Microsoft Visual Studio .NET 2003 Microsoft DirectX 9.0 SDK (December 2004) |
■ログ出力 | Prev Top Next |
今回はログを出力します。公開してるゲームが実行できないといった問い合わせを受けた後、調査してみるとDirectXランタイムのバージョンが古かったのが原因でした、などということはよくある話です。 こういった調査をスムーズに行うためにログにPCのシステム情報を出力するようにします。
さて、実装方法ですが、COMインターフェースによりDirectX診断ツール(DxDiag)へアクセスし、DirectX診断ツール(DxDiag)から必要な情報を取得する方法を使用します。なんでこんな面倒なことするのかというとDirectXランタイムのバージョン情報を 直接取得する方法がないからです。困ったもので。といってもDirectX SDKにサンプルソースがあるのでそれを改造することで実装できるのでなんとかなります。サンプルソースは次のところにあります。
SDK のルート フォルダの\Samples\C++\Misc\getdxver
---errorlog.cpp---
//**************************************************************** //ログを出力する関数 //**************************************************************** HRESULT OutPutDxDiagLog() { HRESULT hr; FILE* f = NULL; IDxDiagProvider* pDxDiagProvider = NULL; IDxDiagContainer* pDxDiagRoot = NULL; IDxDiagContainer* pDxChild = NULL; char str[100], strDestination[100]; VARIANT var; f = fopen( "log.txt", "a+" ); hr = CoInitialize(NULL); if( FAILED( hr ) ) return hr; hr = CoCreateInstance( CLSID_DxDiagProvider, NULL, CLSCTX_INPROC_SERVER, IID_IDxDiagProvider, (LPVOID*) &pDxDiagProvider ); if( SUCCEEDED(hr) ) { DXDIAG_INIT_PARAMS dxDiagInitParam; ZeroMemory( &dxDiagInitParam, sizeof(DXDIAG_INIT_PARAMS) ); dxDiagInitParam.dwSize = sizeof(DXDIAG_INIT_PARAMS); dxDiagInitParam.dwDxDiagHeaderVersion = DXDIAG_DX9_SDK_VERSION; dxDiagInitParam.bAllowWHQLChecks = false; dxDiagInitParam.pReserved = NULL; hr = pDxDiagProvider->Initialize( &dxDiagInitParam ); if( SUCCEEDED(hr) ) { //ルート コンテナにする IDxDiagContainer オブジェクトを作成し、初期化する。 hr = pDxDiagProvider->GetRootContainer( &pDxDiagRoot ); if( SUCCEEDED(hr) ) { //**************************************************************** //DirectX診断ツールのシステムタブの情報を取得する。 //**************************************************************** hr = pDxDiagRoot->GetChildContainer( L"DxDiag_SystemInfo", &pDxChild ); if( SUCCEEDED(hr) ) { fputs( "--- システム ---\n", f ); //**************************************************************** //OSバージョン //**************************************************************** VariantInit( &var ); hr = pDxChild->GetProp( L"szOSExLocalized", &var ); if( SUCCEEDED(hr) && var.vt == VT_BSTR && SysStringLen( var.bstrVal ) != 0 ) { WideCharToMultiByte( CP_ACP, 0, var.bstrVal, -1, strDestination, 100*sizeof(CHAR), NULL, NULL ); sprintf( str, " OS: %s\n", strDestination ); fputs( str, f ); } VariantClear( &var ); //**************************************************************** //CPU //**************************************************************** VariantInit( &var ); hr = pDxChild->GetProp( L"szProcessorEnglish", &var ); if( SUCCEEDED(hr) && var.vt == VT_BSTR && SysStringLen( var.bstrVal ) != 0 ) { WideCharToMultiByte( CP_ACP, 0, var.bstrVal, -1, strDestination, 100*sizeof(CHAR), NULL, NULL ); sprintf( str, " CPU: %s\n", strDestination ); fputs( str, f ); } VariantClear( &var ); //**************************************************************** //SystemMemoryの容量 //**************************************************************** VariantInit( &var ); hr = pDxChild->GetProp( L"szPhysicalMemoryEnglish", &var ); if( SUCCEEDED(hr) && var.vt == VT_BSTR && SysStringLen( var.bstrVal ) != 0 ) { WideCharToMultiByte( CP_ACP, 0, var.bstrVal, -1, strDestination, 100*sizeof(CHAR), NULL, NULL ); sprintf( str, " SysMemory: %s\n", strDestination ); fputs( str, f ); } VariantClear( &var ); //**************************************************************** //DirectXランタイムのバージョン //**************************************************************** VariantInit( &var ); hr = pDxChild->GetProp( L"szDirectXVersionLongEnglish", &var ); if( SUCCEEDED(hr) && var.vt == VT_BSTR && SysStringLen( var.bstrVal ) != 0 ) { WideCharToMultiByte( CP_ACP, 0, var.bstrVal, -1, strDestination, 100*sizeof(CHAR), NULL, NULL ); sprintf( str, " DirectX: %s\n", strDestination ); fputs( str, f ); } VariantClear( &var ); //**************************************************************** //DirectXMode //**************************************************************** VariantInit( &var ); hr = pDxChild->GetProp( L"bIsD3DDebugRuntime", &var ); if( SUCCEEDED(hr) && var.vt == VT_BOOL ) { if( var.boolVal == TRUE ) sprintf( str, "DirectXMode: DebugRuntime\n" ); else sprintf( str, "DirectXMode: RetailRuntime\n" ); fputs( str, f ); } VariantClear( &var ); pDxChild->Release(); } //**************************************************************** //ディスプレイタブの情報を取得する。 //**************************************************************** hr = pDxDiagRoot->GetChildContainer( L"DxDiag_DisplayDevices", &pDxChild ); if( SUCCEEDED(hr) ) { DWORD DisplayCnt; WCHAR wszContainer[100]; IDxDiagContainer* pDxDisplay = NULL; //ディスプレイアダプタの数を取得する。 pDxChild->GetNumberOfChildContainers( &DisplayCnt ); for( DWORD i=0; i < DisplayCnt; i++ ) { sprintf( str, "--- ディスプレイアダプタ%d ---\n", i ); fputs( str, f ); //ディスプレイの列挙 hr = pDxChild->EnumChildContainerNames( i, wszContainer, 100 ); if( SUCCEEDED( hr ) ) { hr = pDxChild->GetChildContainer( wszContainer, &pDxDisplay ); if( SUCCEEDED( hr ) ) { //**************************************************************** //チップの種類 //**************************************************************** VariantInit( &var ); hr = pDxDisplay->GetProp( L"szChipType", &var ); if( SUCCEEDED(hr) && var.vt == VT_BSTR && SysStringLen( var.bstrVal ) != 0 ) { WideCharToMultiByte( CP_ACP, 0, var.bstrVal, -1, strDestination, 100*sizeof(CHAR), NULL, NULL ); sprintf( str, " Chip: %s\n", strDestination ); fputs( str, f ); } VariantClear( &var ); //**************************************************************** //VRAM //**************************************************************** VariantInit( &var ); hr = pDxDisplay->GetProp( L"szDisplayMemoryEnglish", &var ); if( SUCCEEDED(hr) && var.vt == VT_BSTR && SysStringLen( var.bstrVal ) != 0 ) { WideCharToMultiByte( CP_ACP, 0, var.bstrVal, -1, strDestination, 100*sizeof(CHAR), NULL, NULL ); sprintf( str, " VRAM: %s\n", strDestination ); fputs( str, f ); } VariantClear( &var ); //**************************************************************** //DDI //**************************************************************** VariantInit( &var ); hr = pDxDisplay->GetProp( L"szDDIVersionEnglish", &var ); if( SUCCEEDED(hr) && var.vt == VT_BSTR && SysStringLen( var.bstrVal ) != 0 ) { WideCharToMultiByte( CP_ACP, 0, var.bstrVal, -1, strDestination, 100*sizeof(CHAR), NULL, NULL ); sprintf( str, " DDI: %s\n", strDestination ); fputs( str, f ); } VariantClear( &var ); //**************************************************************** //DirectDrawアクセラレータ //**************************************************************** VariantInit( &var ); hr = pDxDisplay->GetProp( L"bDDAccelerationEnabled", &var ); if( SUCCEEDED(hr) && var.vt == VT_BOOL ) { if( var.boolVal == TRUE ) sprintf( str, " DirectDraw: 使用可能\n" ); else sprintf( str, " DirectDraw: 無効\n" ); fputs( str, f ); } VariantClear( &var ); //**************************************************************** //Direct3Dアクセラレータ //**************************************************************** VariantInit( &var ); hr = pDxDisplay->GetProp( L"b3DAccelerationEnabled", &var ); if( SUCCEEDED(hr) && var.vt == VT_BOOL ) { if( var.boolVal == TRUE ) sprintf( str, " Direct3D: 使用可能\n" ); else sprintf( str, " Direct3D: 無効\n" ); fputs( str, f ); } VariantClear( &var ); //**************************************************************** //AGPアクセラレータ //**************************************************************** VariantInit( &var ); hr = pDxDisplay->GetProp( L"bAGPEnabled", &var ); if( SUCCEEDED(hr) && var.vt == VT_BOOL ) { if( var.boolVal == TRUE ) sprintf( str, " AGP: 使用可能\n" ); else sprintf( str, " AGP: 無効\n" ); fputs( str, f ); } VariantClear( &var ); pDxDisplay->Release(); } } } pDxChild->Release(); } pDxDiagRoot->Release(); } } pDxDiagProvider->Release(); } CoUninitialize(); fputs( "===================================\n", f ); fclose( f ); }
上記の関数を実行すると次のようなログを出力します。
--- システム --- OS: Microsoft Windows XP Professional (5.1, ビルド 2600) CPU: Intel(R) Core(TM)2 CPU T5500 @ 1.66GHz (2 CPUs) SysMemory: 1022MB RAM DirectX: DirectX 9.0c (4.09.0000.0904) DirectXMode: DebugRuntime --- ディスプレイアダプタ0 --- Chip: GeForce Go 7600 VRAM: 256.0 MB DDI: 9 (or higher) DirectDraw: 使用可能 Direct3D: 使用可能 AGP: 使用可能
これは筆者が使用しているPCの環境です。内容に関してはDirectX診断ツール(DxDiag)をみればわかると思いますので省略します。 シェーダーを使用している場合は、シェーダーモデルのバージョンも出力しておくとよいでしょう。
さて、これはテキストファイルで出力していますが、この方法ではひとつ問題があります。ユーザーがテキストの内容を自由に改変できることです。これでは情報に信頼性がなくあまり有効ではありません。 これを防ぐために、アプリケーション側でメール送信する方法があります。今回はそこまではやりませんが。