[Win32 API] OSのバージョン取得

OSVERSIONINFO構造体とGetVersionEx関数を利用すればいいらしい。
ただし、OSVERSIONINFO構造体ではエディション情報(XP Home/Proとか)までは取得できない。エディション情報を取得する場合はOSVERSIONINFOEX構造体を用いる必要があるらしい。

OSVERSIONINFO構造体

DWORD dwOSVersionInfoSize
構造体のサイズ
DWORD dwMajorVersion
OSのメジャーバージョン番号
DWORD dwMinorVersion
OSのマイナーバージョン番号
DWORD dwBuildNumber
OSのビルド番号
DOWRD dwPlatformId
プラットフォームID
TCHAR szCSDVersion[128]
追加情報

各OS毎の組み合わせ*1

OSdwPlatformIddwMajorVersiondwMinorVersiondwBuildNumberszCSDVersion
Windows 951(9x系)40950 
Windows 95 SP1a
Windows 95 OSR2/2.11111B
Windows 95 OSR2.51212C
Windows 98101998 
Windows 98 SE2222A
Windows Me903000 
Windows NT 4.02(NT系)01381 
Windows 2000502195 
Windows XP12600 
Windows XP SP2Service Pack 2
Windows XP x642  
Windows Server 20032  
Windows Server 2003 R2  
Windows Vista60  

*1 : 判明次第順次更新します

使ってみる

OSVERSIONINFO osVer;
//構造体のサイズを求めてdwOSVersionInfoSizeに格納
osVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
::GetVersionEx( &osVer );

参考

[Win32 API] システム時刻の取得

GetLocalTimeで取得できるようです。

SYSTEMTIME構造体

typedef struct _SYSTEMTIME {
 WORD wYear;     // 現在年
 WORD wMonth;     // 現在月
 WORD wDayOfWeek;   // 現在の曜日
 WORD wDay;      // 現在日
 WORD wHour;     // 現在時
 WORD wMinite;    // 現在分
 WORD wSecond;    // 現在秒
 WORD wMilliseconds; // 現在のミリ秒
} SYSTEMTIME;

CString文字列として取得する

SYSTEMTIME st;
::GetLocalTime( &st );
CString sysDate, sysTime;
// yyyy/MM/dd形式の文字列生成
sysDate.Format( _T("%04d/%02d/%02d", st.wYear, st.wMonth, st.wDay) );
// hh:mm:ss形式の文字列生成
sysTime.Format( _T("%02d:%02d:%02d", st.wHour, st.wMinite, st.wSecond) );

[MFC] 文字列変換

Unicodeプロジェクト上の文字列変換について。

CString -> TCHAR(LPTSTR)

_tcscpy_sを使えばいいようです。

CString str = _T("foobar");	// 変換元CString文字列
TCHAR* tcharStr = new TCHAR[ str.GetLength() + 1]; // 変換先TCHAR文字列
_tcscpy_s( tcharStr, str.GetLength() + 1, str );

参考URL

TCHAR文字列 -> CString

そのまま代入できるようです。

TCHAR tcharStr[] = _T("foobar"); // 変換元TCHAR文字列
CString str = tcharStr; // 変換先CString文字列

[MFC/Win32API] ファイル・フォルダの存在チェック

[MFC] CFileFind

指定されたファイル名のファイルが存在する場合にtrueを返す。
ただし、ディレクトリのパスが与えられた場合、ディレクトリが存在してもfalseを返す。

ファイル単体の存在チェック

CFileFind find;
CString filePath = _T("C:\\foo.bar");

if( find.FindFile( filePath ) ){
 // ファイルが存在
}

フォルダ内ファイルの存在チェック

以下の例ではでファイル名の条件を指定。

CFileFind find;
CString dirPath = _T("C:\\foo\\bar");
dirPath += _T("*.txt"); // ファイルの条件

if( find.FindFile( dirPath ) ){
 // while( find.FindNextFile() ) // ※間違い※これだと処理出来るファイルが実際の数より1つ少ない

 bool flag;
 do{
  flag = find.FindNextFile(); 
  // *.txtファイルが存在したときの処理
 }while( flag ); // これなら対象ファイル全てが処理出来る
}

[Win32 API] Path関数

PathFileExists
指定されたパスにファイル、もしくはディレクトリが存在した場合にtrueを返す。
PathIsDirectory
指定されたパスがディレクトリならtrueを返す。

指定されたパスがファイルかディレクトリかで処理を切り分ける場合

CString path = _T("C:\\foo.bar");
if( ::PathFileExists( path ) && !::PathIsDirectory( path ) ){
 // 指定されたパスにファイルが存在、かつディレクトリでない
}else if( ::PathFileExists( path ) ){
 // 指定されたパスがディレクトリである
}

車輪の再発明

FindFirstFileを利用してもファイル・フォルダの存在確認にできるらしい。が、ルートディレクトリは検出できないっぽい。
上記のような関数を知らなかった為こんなものを作ってしまった。PathIsDirectory関数と(たぶんほぼ)等価なはず。

// 引数で与えられたフォルダのパスが存在するかを確認
// param: folderPath(参照渡し): フォルダのパス(最後の\記号はつけない)
// return: true: フォルダが存在 / false: フォルダが存在しない
bool isFolderExist( CString &folderPath ){
 HANDLE hFind;
 WIN32_FIND_DATA FindFileData;

 hFind = ::FindFirstFile( folderPath, &FindFileData );
 if( FindFileData.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY ){
  // 引数のパスが正しい(フォルダが存在)
  return true;
 }

 // フォルダが存在しなかった場合、もしくはルートディレクトリを指定していた場合
 // ルートディレクトリならfolderPathの長さは2になるはず(C:)など
 if( folderPath.GetLength() == 2 ){
  TCHAR szBuff[125];	// 4*26 + 1
  ::GetLogicalDriveStrings( sizeof(szBuff), szBuff );
  for( int i = 0; i < 125 /* szBuffの配列長 */; i = i+4 ){
   if( szBuff[i] == folderPath.MakeUpper().GetAt(0) &&
    ':' == folderPath.GetAt(1) ){
    // 指定されたルートディレクトリのドライブレターが有効なドライブであった場合
    return true;
   }
  }
 }
 return false;
}

参考URL