Virtual PCで利用されている拡張子VHDのハードディスクイメージファイルのヘッダー情報を読み込む。このファイルのフォーマットはMicrosoftが公開しているのでそれを参考にした。
ここでは前回作成した「Virtual Hard Disk Image (VHD)の基本情報を取得する」にヘッダー情報読み込み用のソースコードを追加して、可変容量VHDファイルと差分VHDファイルのみに含まれるヘッダー情報を読み込む。
ヘッダー情報はファイル先頭512bytesの位置から512bytesのサイズ書き込まれている。ただし固定容量VHDの場合はヘッダー情報がない。そのため、先にフッター情報を参照して固定容量VHDではないことを確認する必要がある。
ここでは前回からの追加部分のみを掲載する。ダウンロード可能なプロジェクトには全ソースコードを含んでいる。
依存環境:ATLclass CDnpVHDHeader { // // VHDのヘッダー内で利用される構造体 // #pragma pack(push,1) struct PARENT_LOCATOR_ENTRY { DWORD dwPlatformCode; DWORD dwPlatformDataSpace; DWORD dwPlatformDataLength; BYTE pcbReserved[4]; LONGLONG nPlatformDataOffset; }; #pragma pack(pop) // // VHDのヘッダー構造体 // //容量可変VHD、差分VHDでのみ使われる // #pragma pack(push,1) struct VHD_HEADER_DYNAMIC { BYTE pcbCookie[8]; LONGLONG nDataOffset; LONGLONG nTableOffset; DWORD dwHeaderVersion; DWORD dwMaxTableEntries; DWORD dwBlockSize; DWORD dwChecksum; BYTE pcbParentUniqueId[16]; DWORD dwParentTimeStamp; BYTE pcbReserved1[4]; WCHAR pwszParentUnicodeName[512/2]; PARENT_LOCATOR_ENTRY psParentLocatorEntry[8]; BYTE pcbReserved2[256]; }; #pragma pack(pop) public: public: //ヘッダー情報 VHD_HEADER_DYNAMIC _sHeader; CDnpVHDHeader() { ::ZeroMemory(&_sHeader,sizeof(VHD_HEADER_DYNAMIC)); } // // 指定されたファイルハンドルからVirtual Hard Driveのヘッダー情報を読み込む // bool LoadHeader(HANDLE hFile) { int j; BOOL ret; DWORD dwRead; ::SetFilePointer(hFile,512,NULL,FILE_BEGIN); ret = ::ReadFile(hFile,&_sHeader,sizeof(VHD_HEADER_DYNAMIC),&dwRead,NULL); if(ret == FALSE || dwRead != sizeof(VHD_HEADER_DYNAMIC)) { ::ZeroMemory(&_sHeader,sizeof(VHD_HEADER_DYNAMIC)); return false; } //バイト配列をintel形式に変更 SWAP_BYTE_ALIGNMENT(_sHeader.dwBlockSize); SWAP_BYTE_ALIGNMENT(_sHeader.dwChecksum); SWAP_BYTE_ALIGNMENT(_sHeader.dwHeaderVersion); SWAP_BYTE_ALIGNMENT(_sHeader.dwMaxTableEntries); SWAP_BYTE_ALIGNMENT(_sHeader.dwParentTimeStamp); SWAP_BYTE_ALIGNMENT(_sHeader.nDataOffset); SWAP_BYTE_ALIGNMENT(_sHeader.nTableOffset); for(j = 0; j < 8; j++) { SWAP_BYTE_ALIGNMENT(_sHeader.psParentLocatorEntry[j].dwPlatformCode); SWAP_BYTE_ALIGNMENT(_sHeader.psParentLocatorEntry[j].dwPlatformDataLength); SWAP_BYTE_ALIGNMENT(_sHeader.psParentLocatorEntry[j].dwPlatformDataSpace); SWAP_BYTE_ALIGNMENT(_sHeader.psParentLocatorEntry[j].nPlatformDataOffset); } return IsValidHeader(); } // // ヘッダー情報が正しいかのチェック // //完全にはチェックしていない! // bool IsValidHeader(void) { //cookieは"conectix" if(::memcmp(_sHeader.pcbCookie,"cxsparse",8)) { ::ZeroMemory(&_sHeader,sizeof(VHD_HEADER_DYNAMIC)); return false; } if(_sHeader.nDataOffset != -1) { ::ZeroMemory(&_sHeader,sizeof(VHD_HEADER_DYNAMIC)); return false; } //作成OSはWindowsかMac if(_sHeader.dwHeaderVersion != 0x00010000) { ::ZeroMemory(&_sHeader,sizeof(VHD_HEADER_DYNAMIC)); return false; } //チェックサムのチェック DWORD i; DWORD dwChecksum; DWORD dwCurrent; dwCurrent = _sHeader.dwChecksum; _sHeader.dwChecksum = 0; dwChecksum = 0; for(i = 0; i < sizeof(VHD_HEADER_DYNAMIC); i++) dwChecksum += ((BYTE*)&_sHeader)[i]; _sHeader.dwChecksum = dwCurrent; if(dwCurrent != ~dwChecksum) { ::ZeroMemory(&_sHeader,sizeof(VHD_HEADER_DYNAMIC)); return false; } return true; } }; bool LoadFooterAndHeader(LPCTSTR pszVHDFile) { bool ret; bool bHasHeader; HANDLE hFile; CDnpVHDFooter cFooter; CDnpVHDHeader cHeader; CAtlString strTmp; CAtlString strMessage; hFile = ::CreateFile(pszVHDFile,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); if(hFile == INVALID_HANDLE_VALUE) return false; ret = cFooter.LoadFooter(hFile); if(ret == false) { ::CloseHandle(hFile); return false; } bHasHeader = true; if(cFooter.IsDifferencingVHD()) strMessage = _T("差分VHD\n"); else if(cFooter.IsDynamicVHD()) strMessage = _T("可変容量VHD\n"); else if(cFooter.IsFixedVHD()) { strMessage = _T("固定容量VHD\n"); bHasHeader = false; } if(bHasHeader) { bHasHeader = cHeader.LoadHeader(hFile); if(bHasHeader == false) strMessage += _T("(ヘッダー情報の取得に失敗しました)\n"); } ::CloseHandle(hFile); strTmp.Format(_T("シリンダー数:%d\nヘッダー数:%d\nセクター数/シリンダー:%d\n容量:%dbytes"),cFooter._sFooter.sDiskGeometry.nCylinder,cFooter._sFooter.sDiskGeometry.nHeads,cFooter._sFooter.sDiskGeometry.nSectorsPerTrackCylinder,cFooter._sFooter.nOriginalSize); strMessage += strTmp; ::MessageBox(NULL,strMessage,_T(""),MB_OK); return true; } void Test(void) { bool ret; ret = LoadFooterAndHeader(_T("Fixed3MB.vhd")); if(ret == false) ::MessageBox(NULL,_T("取得に失敗しました"),_T(""),MB_OK); ret = LoadFooterAndHeader(_T("Dynamic3MB.vhd")); if(ret == false) ::MessageBox(NULL,_T("取得に失敗しました"),_T(""),MB_OK); ret = LoadFooterAndHeader(_T("Differncial.vhd")); if(ret == false) ::MessageBox(NULL,_T("取得に失敗しました"),_T(""),MB_OK); }