static void test_extra_block(void) { WORD extra_block[] = { 72, 0, 0, 'W', 'i', 'n', 'e', 'T', 'e', 's', 't', '\0', 24, 4, 0, 'B', 'i', 'n', 'a', 'r', 'y', '\0', 0xbeef, 0xdead, 24, 4, 1, 'T', 'e', 'x', 't', '\0', 'B', '-', ')', '\0', }; char buf[MAX_PATH]; UINT len, ret; ULONG w; char *ver, *p; WORD *length; ret = GetModuleFileNameA(NULL, buf, sizeof(buf)); ok(ret, "GetModuleFileNameA failed\n"); len = GetFileVersionInfoSizeA(buf, NULL); ok(len, "GetFileVersionInfoSizeA(%s) error %u\n", buf, GetLastError()); ver = HeapAlloc(GetProcessHeap(), 0, len + sizeof(extra_block) * 2); ok(ver != NULL, "Can't allocate memory\n"); ret = GetFileVersionInfoA(buf, 0, len, ver); ok(ret, "GetFileVersionInfoA error %u\n", GetLastError()); /* forge the string table, as windres dislike an extra block */ length = (WORD *)ver; /* see VS_VERSION_INFO_STRUCT32 for details */ memcpy(ver + *length, extra_block, sizeof(extra_block)); *length += sizeof(extra_block); p = (char *)0xdeadbeef; len = 0xdeadbeef; w = 0xdeadbeef; ret = VerQueryValueA(ver, "WineTest\\Binary", (LPVOID*)&p, &len); ok(ret, "VerQueryValue error %u\n", GetLastError()); ok(len == 4, "VerQueryValue returned %u, expected 4\n", len); ok(p != (char *)0xdeadbeef, "not expected 0xdeadbeef\n"); ok(memcmp(p, &w, sizeof(w)) == 0, "got 0x%08x, expected 0x%08x\n", *(PULONG)p, w); p = (char *)0xdeadbeef; len = 0xdeadbeef; ret = VerQueryValueA(ver, "WineTest\\Text", (LPVOID*)&p, &len); ok(ret, "VerQueryValue error %u\n", GetLastError()); ok(len == 4, "VerQueryValue returned %u, expected 4\n", len); ok(p != (char *)0xdeadbeef, "not expected 0xdeadbeef\n"); ok(strcmp(p, "B-)") == 0, "got '%s', expected '%s'\n", p, "B-)"); HeapFree(GetProcessHeap(), 0, ver); }
bool getFileVersion(const char* filePath, DWORD& fileVersionMS, DWORD& fileVersionLS) { DWORD verSize = GetFileVersionInfoSizeA(filePath, NULL); if (verSize == 0) { DWORD gle = GetLastError(); warning() << "GetFileVersionInfoSizeA on " << filePath << " failed with " << errnoWithDescription(gle); return false; } std::unique_ptr<char[]> verData(new char[verSize]); if (GetFileVersionInfoA(filePath, NULL, verSize, verData.get()) == 0) { DWORD gle = GetLastError(); warning() << "GetFileVersionInfoSizeA on " << filePath << " failed with " << errnoWithDescription(gle); return false; } UINT size; VS_FIXEDFILEINFO* verInfo; if (VerQueryValueA(verData.get(), "\\", (LPVOID*)&verInfo, &size) == 0) { DWORD gle = GetLastError(); warning() << "VerQueryValueA on " << filePath << " failed with " << errnoWithDescription(gle); return false; } if (size != sizeof(VS_FIXEDFILEINFO)) { warning() << "VerQueryValueA on " << filePath << " returned structure with unexpected size"; return false; } fileVersionMS = verInfo->dwFileVersionMS; fileVersionLS = verInfo->dwFileVersionLS; return true; }
/************************************************************************* * VerQueryValue [VER.11] */ DWORD WINAPI VerQueryValue16( SEGPTR spvBlock, LPCSTR lpszSubBlock, SEGPTR *lpspBuffer, UINT16 *lpcb ) { LPVOID lpvBlock = MapSL( spvBlock ); LPVOID buffer = lpvBlock; UINT buflen; DWORD retv; TRACE("(%p, %s, %p, %p)\n", lpvBlock, debugstr_a(lpszSubBlock), lpspBuffer, lpcb ); retv = VerQueryValueA( lpvBlock, lpszSubBlock, &buffer, &buflen ); if ( !retv ) return FALSE; if ( OFFSETOF( spvBlock ) + ((char *) buffer - (char *) lpvBlock) >= 0x10000 ) { FIXME("offset %08X too large relative to %04X:%04X\n", (char *) buffer - (char *) lpvBlock, SELECTOROF( spvBlock ), OFFSETOF( spvBlock ) ); return FALSE; } if (lpcb) *lpcb = buflen; *lpspBuffer = (SEGPTR) ((char *) spvBlock + ((char *) buffer - (char *) lpvBlock)); return retv; }
int __declspec(dllexport) Load(PLUGINLINK *link) { BOOL bFlag = FALSE; HINSTANCE hDll; #ifndef NDEBUG //mem leak detector :-) Thanks Tornado! int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); // Get current flag flag |= _CRTDBG_LEAK_CHECK_DF; // Turn on leak-checking bit _CrtSetDbgFlag(flag); // Set flag to the new value #endif pluginLink = link; // set the memory & utf8 managers mir_getMMI( &memoryManagerInterface ); mir_getUTFI( &utfi ); mir_getLP( &pluginInfo ); hDll = LoadLibraryA("riched20.dll"); if ( hDll ) { char modulePath[MAX_PATH]; if (GetModuleFileNameA(hDll, modulePath, MAX_PATH)) { DWORD dummy; VS_FIXEDFILEINFO* vsInfo; UINT vsInfoSize; DWORD size = GetFileVersionInfoSizeA(modulePath, &dummy); BYTE* buffer = (BYTE*) mir_alloc(size); if (GetFileVersionInfoA(modulePath, 0, size, buffer)) if (VerQueryValueA(buffer, "\\", (LPVOID*) &vsInfo, &vsInfoSize)) if (LOWORD(vsInfo->dwFileVersionMS) != 0) bFlag= TRUE; mir_free(buffer); } } if ( !bFlag ) { if (IDYES == MessageBox(0, TranslateT("Miranda could not load the Chat plugin because Microsoft Rich Edit v 3 is missing.\nIf you are using Windows 95/98/NT or WINE please upgrade your Rich Edit control.\n\nDo you want to download an update now?."),TranslateT("Information"),MB_YESNO|MB_ICONINFORMATION)) CallService(MS_UTILS_OPENURL, 1, (LPARAM) "http://members.chello.se/matrix/re3/richupd.exe"); FreeLibrary(GetModuleHandleA("riched20.dll")); return 1; } UpgradeCheck(); g_hMenu = LoadMenu(g_hInst, MAKEINTRESOURCE(IDR_MENU)); InitREOleCallback(); HookEvents(); CreateServiceFunctions(); CreateHookableEvents(); OptionsInit(); TabsInit(); return 0; }
//------------------------------------------------------------------ DWORD getVer() { HRSRC r; HGLOBAL h; void *s; VS_FIXEDFILEINFO *v; UINT i; r=FindResource(0, (TCHAR*)VS_VERSION_INFO, RT_VERSION); h=LoadResource(0, r); s=LockResource(h); if(!s || !VerQueryValueA(s, "\\", (void**)&v, &i)) return 0; return v->dwFileVersionMS; }
/** * Helper for VBoxServiceGetFileVersion and attempts to read and parse * FileVersion. * * @returns Success indicator. */ static bool VBoxServiceGetFileVersionOwn(LPSTR pVerData, PDWORD pdwMajor, PDWORD pdwMinor, PDWORD pdwBuildNumber, PDWORD pdwRevisionNumber) { UINT cchStrValue = 0; LPTSTR pStrValue = NULL; if (!VerQueryValueA(pVerData, "\\StringFileInfo\\040904b0\\FileVersion", (LPVOID *)&pStrValue, &cchStrValue)) return false; /** @todo r=bird: get rid of this. Avoid sscanf like the plague! */ if (sscanf(pStrValue, "%ld.%ld.%ld.%ld", pdwMajor, pdwMinor, pdwBuildNumber, pdwRevisionNumber) != 4) return false; return true; }
std::string get_sysinfo() { #ifdef _WIN32 std::ostringstream oss; LPSTR filePath = new char[MAX_PATH]; UINT blockSize; VS_FIXEDFILEINFO *fixedFileInfo; GetSystemDirectoryA(filePath, MAX_PATH); PathAppendA(filePath, "kernel32.dll"); DWORD dwVersionSize = GetFileVersionInfoSizeA(filePath, NULL); LPBYTE lpVersionInfo = new BYTE[dwVersionSize]; GetFileVersionInfoA(filePath, 0, dwVersionSize, lpVersionInfo); VerQueryValueA(lpVersionInfo, "\\", (LPVOID *)&fixedFileInfo, &blockSize); oss << "Windows/" << HIWORD(fixedFileInfo->dwProductVersionMS) << '.' // Major << LOWORD(fixedFileInfo->dwProductVersionMS) << '.' // Minor << HIWORD(fixedFileInfo->dwProductVersionLS) << ' '; // Build #ifdef _WIN64 oss << "x86_64"; #else BOOL is64 = FALSE; if (IsWow64Process(GetCurrentProcess(), &is64) && is64) oss << "x86_64"; // 32-bit app on 64-bit OS else oss << "x86"; #endif delete[] lpVersionInfo; delete[] filePath; return oss.str(); #else struct utsname osinfo; uname(&osinfo); return std::string(osinfo.sysname) + "/" + osinfo.release + " " + osinfo.machine; #endif }
std::string DynamicLibrary::getVersionStr() { std::string ret = "missing"; DWORD infoHandle; LONG sz = GetFileVersionInfoSizeA(name.c_str(),&infoHandle); if (!sz) return ret; VS_FIXEDFILEINFO * fileInf; std::vector<BYTE> buf(sz*2); if (!GetFileVersionInfoA(name.c_str(),0,sz,&buf[0])) return ret; UINT len; if (!VerQueryValueA(&buf[0],"\\",(LPVOID *) &fileInf,&len)) return ret; std::ostringstream strb; strb << HIWORD(fileInf->dwFileVersionMS) << "." << LOWORD(fileInf->dwFileVersionMS) << "." << HIWORD(fileInf->dwFileVersionLS) << "." << LOWORD(fileInf->dwFileVersionLS); return strb.str(); }
/*********************************************************************** * GetVersionFromFileEx (ADVPACK.@) */ HRESULT WINAPI GetVersionFromFileEx( LPSTR lpszFilename, LPDWORD pdwMSVer, LPDWORD pdwLSVer, BOOL bVersion ) { DWORD hdl, retval; LPVOID pVersionInfo; BOOL boolret; VS_FIXEDFILEINFO *pFixedVersionInfo; UINT uiLength; TRACE("(%s, %p, %p, %d)\n", lpszFilename, pdwMSVer, pdwLSVer, bVersion); if (bVersion) { retval = GetFileVersionInfoSizeA(lpszFilename, &hdl); if (retval == 0 || hdl != 0) return E_FAIL; pVersionInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, retval); if (pVersionInfo == NULL) return E_FAIL; GetFileVersionInfoA( lpszFilename, 0, retval, pVersionInfo); boolret = VerQueryValueA(pVersionInfo, "\\", (LPVOID) &pFixedVersionInfo, &uiLength); HeapFree(GetProcessHeap(), 0, pVersionInfo); if (boolret) { *pdwMSVer = pFixedVersionInfo->dwFileVersionMS; *pdwLSVer = pFixedVersionInfo->dwFileVersionLS; } else return E_FAIL; } else { *pdwMSVer = LOCALE_NEUTRAL; /* GetUserDefaultUILanguage(); */ *pdwLSVer = GetACP(); } return S_OK; }
const char * get_file_version(const char * file_name) { static char version[32]; DWORD size; DWORD handle; size = GetFileVersionInfoSizeA("dsound.dll", &handle); if (size) { char * data = HeapAlloc(GetProcessHeap(), 0, size); if (data) { if (GetFileVersionInfoA("dsound.dll", handle, size, data)) { VS_FIXEDFILEINFO *pFixedVersionInfo; UINT len; if (VerQueryValueA(data, "\\", (LPVOID *)&pFixedVersionInfo, &len)) { sprintf(version, "%ld.%ld.%ld.%ld", pFixedVersionInfo->dwFileVersionMS >> 16, pFixedVersionInfo->dwFileVersionMS & 0xffff, pFixedVersionInfo->dwFileVersionLS >> 16, pFixedVersionInfo->dwFileVersionLS & 0xffff); } else sprintf(version, "not available"); } else
static char * get_file_version(char * file_name) { static char version[32]; DWORD size; DWORD handle; size = GetFileVersionInfoSizeA(file_name, &handle); if (size) { char * data = xmalloc(size); if (data) { if (GetFileVersionInfoA(file_name, handle, size, data)) { static char backslash[] = "\\"; VS_FIXEDFILEINFO *pFixedVersionInfo; UINT len; if (VerQueryValueA(data, backslash, (LPVOID *)&pFixedVersionInfo, &len)) { sprintf(version, "%d.%d.%d.%d", pFixedVersionInfo->dwFileVersionMS >> 16, pFixedVersionInfo->dwFileVersionMS & 0xffff, pFixedVersionInfo->dwFileVersionLS >> 16, pFixedVersionInfo->dwFileVersionLS & 0xffff); } else sprintf(version, "version not available"); } else
MEXP(int) getExeInfo(const char* file_name, char* exe_info, size_t exe_info_size, uint32_t* version, int platform) { const char* base = (char*) 0; unsigned long file_size; FILE* f = (FILE*) 0; int ret; #ifdef MOS_WINDOWS HANDLE hFile; FILETIME ft; SYSTEMTIME st; LPBYTE buf; VS_FIXEDFILEINFO* ffi; DWORD infoSize, bytesRead; #else cm_pe_t pe; cm_pe_resdir_t* root; cm_pe_resdir_t* dir; cm_pe_version_t ffi; size_t i; struct stat st; struct tm* time; #endif if (!file_name || !exe_info || !exe_info_size || !version) return 0; base = get_basename(file_name); switch (platform) { case BNCSUTIL_PLATFORM_X86: #ifdef MOS_WINDOWS infoSize = GetFileVersionInfoSizeA(file_name, &bytesRead); if (infoSize == 0) return 0; buf = (LPBYTE) VirtualAlloc(NULL, infoSize, MEM_COMMIT, PAGE_READWRITE); if (buf == NULL) return 0; if (GetFileVersionInfoA(file_name, NULL, infoSize, buf) == FALSE) return 0; if (!VerQueryValueA(buf, "\\", (LPVOID*) &ffi, (PUINT) &infoSize)) return 0; *version = ((HIWORD(ffi->dwProductVersionMS) & 0xFF) << 24) | ((LOWORD(ffi->dwProductVersionMS) & 0xFF) << 16) | ((HIWORD(ffi->dwProductVersionLS) & 0xFF) << 8) | (LOWORD(ffi->dwProductVersionLS) & 0xFF); #if DEBUG bncsutil_debug_message_a("%s version = %d.%d.%d.%d (0x%08X)", base, (HIWORD(ffi->dwProductVersionMS) & 0xFF), (LOWORD(ffi->dwProductVersionMS) & 0xFF), (HIWORD(ffi->dwProductVersionLS) & 0xFF), (LOWORD(ffi->dwProductVersionLS) & 0xFF), *version); #endif VirtualFree(buf, 0lu, MEM_RELEASE); #else pe = cm_pe_load(file_name); if (!pe) return 0; root = cm_pe_load_resources(pe); if (!root) { cm_pe_unload(pe); return 0; } for (i = 0; i < root->subdir_count; i++) { dir = (root->subdirs + i); if (dir->name == 16) { if (!cm_pe_fixed_version(pe, dir->subdirs->resources, &ffi)) { cm_pe_unload_resources(root); cm_pe_unload(pe); return 0; } break; } } *version = ((HIWORD(ffi.dwProductVersionMS) & 0xFF) << 24) | ((LOWORD(ffi.dwProductVersionMS) & 0xFF) << 16) | ((HIWORD(ffi.dwProductVersionLS) & 0xFF) << 8) | (LOWORD(ffi.dwProductVersionLS) & 0xFF); #if DEBUG bncsutil_debug_message_a("%s version = %d.%d.%d.%d (0x%08X)", base, (HIWORD(ffi.dwProductVersionMS) & 0xFF), (LOWORD(ffi.dwProductVersionMS) & 0xFF), (HIWORD(ffi.dwProductVersionLS) & 0xFF), (LOWORD(ffi.dwProductVersionLS) & 0xFF), *version); #endif cm_pe_unload_resources(root); cm_pe_unload(pe); #endif break; case BNCSUTIL_PLATFORM_MAC: case BNCSUTIL_PLATFORM_OSX: f = fopen(file_name, "r"); if (!f) return 0; if (fseek(f, -4, SEEK_END) != 0) { fclose(f); return 0; } if (fread(version, 4, 1, f) != 1) { fclose(f); return 0; } #ifdef MOS_WINDOWS fclose(f); #endif } #ifdef MOS_WINDOWS hFile = CreateFileA(file_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) return 0; file_size = GetFileSize(hFile, NULL); if (!GetFileTime(hFile, &ft, NULL, NULL)) { CloseHandle(hFile); return 0; } if (!FileTimeToSystemTime(&ft, &st)) { CloseHandle(hFile); return 0; } CloseHandle(hFile); ret = snprintf(exe_info, exe_info_size, "%s %02u/%02u/%02u %02u:%02u:%02u %lu", base, st.wMonth, st.wDay, (st.wYear % 100), st.wHour, st.wMinute, st.wSecond, file_size); #else if (!f) f = fopen(file_name, "r"); if (!f) return 0; if (fseek(f, 0, SEEK_END) == -1) { fclose(f); return 0; } file_size = ftell(f); fclose(f); if (stat(file_name, &st) != 0) return 0; time = gmtime(&st.st_mtime); if (!time) return 0; switch (platform) { case BNCSUTIL_PLATFORM_MAC: case BNCSUTIL_PLATFORM_OSX: if (time->tm_year >= 100) // y2k time->tm_year -= 100; break; } ret = (int) snprintf(exe_info, exe_info_size, "%s %02u/%02u/%02u %02u:%02u:%02u %lu", base, (time->tm_mon+1), time->tm_mday, time->tm_year, time->tm_hour, time->tm_min, time->tm_sec, file_size); #endif #if DEBUG bncsutil_debug_message(exe_info); #endif return ret; }
static void test_info(void) { DWORD hdl, retval; PVOID pVersionInfo = NULL; BOOL boolret; VS_FIXEDFILEINFO *pFixedVersionInfo; UINT uiLength; char VersionString[MAX_PATH]; static const char backslash[] = "\\"; DWORDLONG dwlVersion; hdl = 0x55555555; SetLastError(MY_LAST_ERROR); retval = GetFileVersionInfoSizeA( "kernel32.dll", &hdl); ok( retval, "GetFileVersionInfoSizeA result wrong! <> 0L expected, got 0x%08x\n", retval); ok((NO_ERROR == GetLastError()) || (MY_LAST_ERROR == GetLastError()), "Last error wrong! NO_ERROR/0x%08x (NT4) expected, got %u\n", MY_LAST_ERROR, GetLastError()); ok( hdl == 0L, "Handle wrong! 0L expected, got 0x%08x\n", hdl); if ( retval == 0 || hdl != 0) return; pVersionInfo = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, retval ); ok(pVersionInfo != 0, "HeapAlloc failed\n" ); if (pVersionInfo == 0) return; if (0) { /* this test crashes on WinNT4 */ boolret = GetFileVersionInfoA( "kernel32.dll", 0, retval, 0); ok (!boolret, "GetFileVersionInfoA should have failed: GetLastError = %u\n", GetLastError()); ok ((GetLastError() == ERROR_INVALID_DATA) || (GetLastError() == ERROR_BAD_PATHNAME) || (GetLastError() == NO_ERROR), "Last error wrong! ERROR_INVALID_DATA/ERROR_BAD_PATHNAME (ME)/" "NO_ERROR (95) expected, got %u\n", GetLastError()); } boolret = GetFileVersionInfoA( "kernel32.dll", 0, retval, pVersionInfo ); ok (boolret, "GetFileVersionInfoA failed: GetLastError = %u\n", GetLastError()); if (!boolret) goto cleanup; boolret = VerQueryValueA( pVersionInfo, NULL, (LPVOID *)&pFixedVersionInfo, &uiLength ); ok (boolret || GetLastError() == NO_ERROR /* Win98 */, "VerQueryValueA failed: GetLastError = %u\n", GetLastError()); boolret = VerQueryValueA( pVersionInfo, "", (LPVOID *)&pFixedVersionInfo, &uiLength ); ok (boolret, "VerQueryValueA failed: GetLastError = %u\n", GetLastError()); boolret = VerQueryValueA( pVersionInfo, backslash, (LPVOID *)&pFixedVersionInfo, &uiLength ); ok (boolret, "VerQueryValueA failed: GetLastError = %u\n", GetLastError()); if (!boolret) goto cleanup; dwlVersion = (((DWORDLONG)pFixedVersionInfo->dwFileVersionMS) << 32) + pFixedVersionInfo->dwFileVersionLS; VersionDwordLong2String(dwlVersion, VersionString); trace("kernel32.dll version: %s\n", VersionString); if (0) { /* this test crashes on WinNT4 */ boolret = VerQueryValueA( pVersionInfo, backslash, (LPVOID *)&pFixedVersionInfo, 0); ok (boolret, "VerQueryValue failed: GetLastError = %u\n", GetLastError()); } cleanup: HeapFree( GetProcessHeap(), 0, pVersionInfo); }
void GetVersionInfo(const char * name, VersionInfo * pInfo) { HMODULE hVersion = LoadLibraryA("version.dll"); memset(pInfo, 0, sizeof(VersionInfo)); if (NULL != hVersion) { pfnGetFileVersionInfoA GetFileVersionInfoA = (pfnGetFileVersionInfoA) GetProcAddress(hVersion, "GetFileVersionInfoA"); pfnGetFileVersionInfoSizeA GetFileVersionInfoSizeA = (pfnGetFileVersionInfoSizeA) GetProcAddress(hVersion, "GetFileVersionInfoSizeA"); pfnVerQueryValueA VerQueryValueA = (pfnVerQueryValueA) GetProcAddress(hVersion, "VerQueryValueA"); if (NULL != GetFileVersionInfoA && NULL != GetFileVersionInfoSizeA && NULL != VerQueryValueA) { DWORD dummy = 0; DWORD size = GetFileVersionInfoSize(name, &dummy); if (size > 0 && size <= 8192) { char block[8192]; if (GetFileVersionInfo(name, dummy, size, block)) { struct LANGANDCODEPAGE { WORD language; WORD codepage; } * pTranslate; UINT blocksize; if (VerQueryValueA(block, "\\VarFileInfo\\Translation", (LPVOID*)&pTranslate, &blocksize)) { uint32_t i; for (i = 0; i < blocksize / sizeof(struct LANGANDCODEPAGE); ++i) { UINT dummy; char * value = NULL; char subblock[50]; char * tokens[] = { "Comments", "CompanyName", "FileDescription", "FileVersion", "InternalName", "LegalCopyright", "LegalTrademarks", "OriginalFilename", "ProductName", "ProductVersion", "PrivateBuild", "SpecialBuild" }; size_t j; for (j = 0; j < sizeof(tokens) / sizeof(tokens[0]); ++j) { ConsoleIOFormat(subblock, 50, "\\StringFileInfo\\%04x%04x\\%s", pTranslate[i].language, pTranslate[i].codepage, tokens[j]); if (VerQueryValueA(block, subblock, &value, &dummy)) { xstrcat((char*)pInfo + kMaxVersionString * j, kMaxVersionString, value); } } } } } } } FreeLibrary(hVersion); } }
static void test_VerQueryValue_InvalidLength(void) { /* this buffer is created with the reactos resource compiler from this resource: #include "winver.h" VS_VERSION_INFO VERSIONINFO FILEVERSION 1,0,0,0 PRODUCTVERSION 1,0,0,0 FILEFLAGSMASK 63 FILEFLAGS 0 FILEOS VOS_UNKNOWN FILETYPE VFT_APP FILESUBTYPE VFT2_UNKNOWN { BLOCK "StringFileInfo" { } } */ char preparedbuffer[] = { /* VS_VERSION_INFO_STRUCT32 */ 0x80, 0x00, /* wLength */ 0x34, 0x00, /* wValueLength */ 0x00, 0x00, /* wType */ /* L"VS_VERSION_INFO" + DWORD alignment */ 0x56, 0x00, 0x53, 0x00, 0x5f, 0x00, 0x56, 0x00, 0x45, 0x00, 0x52, 0x00, 0x53, 0x00, 0x49, 0x00, 0x4f, 0x00, 0x4e, 0x00, 0x5f, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x46, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, /* VS_FIXEDFILEINFO */ 0xbd, 0x04, 0xef, 0xfe, /* dwSignature */ 0x00, 0x00, 0x01, 0x00, /* dwStrucVersion */ 0x00, 0x00, 0x01, 0x00, /* dwFileVersionMS */ 0x00, 0x00, 0x00, 0x00, /* dwFileVersionLS */ 0x00, 0x00, 0x01, 0x00, /* dwProductVersionMS */ 0x00, 0x00, 0x00, 0x00, /* dwProductVersionLS */ 0x3f, 0x00, 0x00, 0x00, /* dwFileFlagsMask */ 0x00, 0x00, 0x00, 0x00, /* dwFileFlags */ 0x00, 0x00, 0x00, 0x00, /* dwFileOS */ 0x01, 0x00, 0x00, 0x00, /* dwFileType */ 0x00, 0x00, 0x00, 0x00, /* dwFileSubtype */ 0x00, 0x00, 0x00, 0x00, /* dwFileDateMS */ 0x00, 0x00, 0x00, 0x00, /* dwFileDateLS */ /* first child: */ 0x24, 0x00, /* wLength */ 0x00, 0x00, /* wValueLength */ 0x01, 0x00, /* wType */ /* L"StringFileInfo" + DWORD alignment */ 0x53, 0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x46, 0x00, 0x69, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x66, 0x00, 0x6f, 0x00, 0x00, 0x00, /* "FE2X" */ 0x46, 0x45, 0x32, 0x58, /* Extra bytes allocated for W->A conversions. */ 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, }; char *p; UINT len, ret; WCHAR FileDescriptionW[] = { '\\', '\\', 'S', 't', 'r', 'i', 'n', 'g', 'F', 'i', 'l', 'e', 'I', 'n', 'f', 'o', 0 }; p = (char *)0xdeadbeef; len = 0xdeadbeef; SetLastError(0xdeadbeef); ret = VerQueryValueA(preparedbuffer, "StringFileInfo", (LPVOID *)&p, &len); ok(ret, "VerQueryValueA error %u\n", GetLastError()); todo_wine ok(len == 0, "VerQueryValueA returned %u, expected 0\n", len); todo_wine ok(p == preparedbuffer + 0x7e, "p was %p, expected %p\n", p, preparedbuffer + 0x7e); p = (char *)0xdeadbeef; len = 0xdeadbeef; SetLastError(0xdeadbeef); ret = VerQueryValueA(preparedbuffer, "\\StringFileInfo", (LPVOID *)&p, &len); ok(ret, "VerQueryValueA error %u\n", GetLastError()); todo_wine ok(len == 0, "VerQueryValueA returned %u, expected 0\n", len); todo_wine ok(p == preparedbuffer + 0x7e, "p was %p, expected %p\n", p, preparedbuffer + 0x7e); p = (char *)0xdeadbeef; len = 0xdeadbeef; SetLastError(0xdeadbeef); ret = VerQueryValueA(preparedbuffer, "\\\\StringFileInfo", (LPVOID *)&p, &len); ok(ret, "VerQueryValueA error %u\n", GetLastError()); todo_wine ok(len == 0, "VerQueryValueA returned %u, expected 0\n", len); todo_wine ok(p == preparedbuffer + 0x7e, "p was %p, expected %p\n", p, preparedbuffer + 0x7e); /* also test the W versions. */ p = (char *)0xdeadbeef; len = 0xdeadbeef; SetLastError(0xdeadbeef); ret = VerQueryValueW(preparedbuffer, FileDescriptionW + 2, (LPVOID *)&p, &len); ok(ret, "VerQueryValueW error %u\n", GetLastError()); ok(len == 0, "VerQueryValueW returned %u, expected 0\n", len); todo_wine ok(p == preparedbuffer + 0x7e, "p was %p, expected %p\n", p, preparedbuffer + 0x7e); p = (char *)0xdeadbeef; len = 0xdeadbeef; SetLastError(0xdeadbeef); ret = VerQueryValueW(preparedbuffer, FileDescriptionW + 1, (LPVOID *)&p, &len); ok(ret, "VerQueryValueW error %u\n", GetLastError()); ok(len == 0, "VerQueryValueW returned %u, expected 0\n", len); todo_wine ok(p == preparedbuffer + 0x7e, "p was %p, expected %p\n", p, preparedbuffer + 0x7e); p = (char *)0xdeadbeef; len = 0xdeadbeef; SetLastError(0xdeadbeef); ret = VerQueryValueW(preparedbuffer, FileDescriptionW, (LPVOID *)&p, &len); ok(ret, "VerQueryValueW error %u\n", GetLastError()); ok(len == 0, "VerQueryValueW returned %u, expected 0\n", len); todo_wine ok(p == preparedbuffer + 0x7e, "p was %p, expected %p\n", p, preparedbuffer + 0x7e); }
static void test_VerQueryValueA(void) { static const char * const value_name[] = { "Product", "CompanyName", "FileDescription", "Internal", "ProductVersion", "InternalName", "File", "LegalCopyright", "FileVersion", "Legal", "OriginalFilename", "ProductName", "Company", "Original" }; char *ver, *p; UINT len, ret, translation, i; char buf[MAX_PATH]; ret = GetModuleFileNameA(NULL, buf, sizeof(buf)); assert(ret); SetLastError(0xdeadbeef); len = GetFileVersionInfoSizeA(buf, NULL); ok(len, "GetFileVersionInfoSizeA(%s) error %u\n", buf, GetLastError()); ver = HeapAlloc(GetProcessHeap(), 0, len); assert(ver); SetLastError(0xdeadbeef); ret = GetFileVersionInfoA(buf, 0, len, ver); ok(ret, "GetFileVersionInfoA error %u\n", GetLastError()); p = (char *)0xdeadbeef; len = 0xdeadbeef; SetLastError(0xdeadbeef); ret = VerQueryValueA(ver, "\\VarFileInfo\\Translation", (LPVOID*)&p, &len); ok(ret, "VerQueryValue error %u\n", GetLastError()); ok(len == 4, "VerQueryValue returned %u, expected 4\n", len); translation = *(UINT *)p; translation = MAKELONG(HIWORD(translation), LOWORD(translation)); p = (char *)0xdeadbeef; len = 0xdeadbeef; SetLastError(0xdeadbeef); ret = VerQueryValueA(ver, "String", (LPVOID*)&p, &len); ok(!ret, "VerQueryValue should fail\n"); ok(GetLastError() == ERROR_RESOURCE_TYPE_NOT_FOUND || GetLastError() == 0xdeadbeef /* NT4, W2K */, "VerQueryValue returned %u\n", GetLastError()); ok(p == (char *)0xdeadbeef, "expected 0xdeadbeef got %p\n", p); ok(len == 0, "expected 0 got %x\n", len); p = (char *)0xdeadbeef; len = 0xdeadbeef; SetLastError(0xdeadbeef); ret = VerQueryValueA(ver, "StringFileInfo", (LPVOID*)&p, &len); ok(ret, "VerQueryValue error %u\n", GetLastError()); ok(len == 0, "VerQueryValue returned %u, expected 0\n", len); ok(p != (char *)0xdeadbeef, "not expected 0xdeadbeef\n"); p = (char *)0xdeadbeef; len = 0xdeadbeef; SetLastError(0xdeadbeef); ret = VerQueryValueA(ver, "\\StringFileInfo", (LPVOID*)&p, &len); ok(ret, "VerQueryValue error %u\n", GetLastError()); ok(len == 0, "VerQueryValue returned %u, expected 0\n", len); ok(p != (char *)0xdeadbeef, "not expected 0xdeadbeef\n"); p = (char *)0xdeadbeef; len = 0xdeadbeef; SetLastError(0xdeadbeef); ret = VerQueryValueA(ver, "\\\\StringFileInfo", (LPVOID*)&p, &len); ok(ret, "VerQueryValue error %u\n", GetLastError()); ok(len == 0, "VerQueryValue returned %u, expected 0\n", len); ok(p != (char *)0xdeadbeef, "not expected 0xdeadbeef\n"); p = (char *)0xdeadbeef; len = 0xdeadbeef; SetLastError(0xdeadbeef); ret = VerQueryValueA(ver, "\\StringFileInfo\\\\", (LPVOID*)&p, &len); ok(ret, "VerQueryValue error %u\n", GetLastError()); ok(len == 0, "VerQueryValue returned %u, expected 0\n", len); ok(p != (char *)0xdeadbeef, "not expected 0xdeadbeef\n"); sprintf(buf, "\\StringFileInfo\\%08x", translation); p = (char *)0xdeadbeef; len = 0xdeadbeef; SetLastError(0xdeadbeef); ret = VerQueryValueA(ver, buf, (LPVOID*)&p, &len); ok(ret, "VerQueryValue error %u\n", GetLastError()); ok(len == 0, "VerQueryValue returned %u, expected 0\n", len); ok(p != (char *)0xdeadbeef, "not expected 0xdeadbeef\n"); for (i = 0; i < sizeof(value_name)/sizeof(value_name[0]); i++) { sprintf(buf, "\\StringFileInfo\\%08x\\%s", translation, value_name[i]); p = (char *)0xdeadbeef; len = 0xdeadbeef; SetLastError(0xdeadbeef); ret = VerQueryValueA(ver, buf, (LPVOID*)&p, &len); ok(ret, "VerQueryValueA(%s) error %u\n", buf, GetLastError()); ok(len == strlen(value_name[i]) + 1, "VerQueryValue returned %u\n", len); ok(!strcmp(value_name[i], p), "expected \"%s\", got \"%s\"\n", value_name[i], p); /* test partial value names */ len = lstrlenA(buf); buf[len - 2] = 0; p = (char *)0xdeadbeef; len = 0xdeadbeef; SetLastError(0xdeadbeef); ret = VerQueryValueA(ver, buf, (LPVOID*)&p, &len); ok(!ret, "VerQueryValueA(%s) succeeded\n", buf); ok(GetLastError() == ERROR_RESOURCE_TYPE_NOT_FOUND || GetLastError() == 0xdeadbeef /* NT4, W2K */, "VerQueryValue returned %u\n", GetLastError()); ok(p == (char *)0xdeadbeef, "expected 0xdeadbeef got %p\n", p); ok(len == 0, "expected 0 or 0xbeef, got %x\n", len); } HeapFree(GetProcessHeap(), 0, ver); }
static void test_32bit_win(void) { DWORD hdlA, retvalA; DWORD hdlW, retvalW = 0; BOOL retA,retW; PVOID pVersionInfoA = NULL; PVOID pVersionInfoW = NULL; char *pBufA; WCHAR *pBufW; UINT uiLengthA, uiLengthW; char mypathA[MAX_PATH]; WCHAR mypathW[MAX_PATH]; char rootA[] = "\\"; WCHAR rootW[] = { '\\', 0 }; WCHAR emptyW[] = { 0 }; char varfileinfoA[] = "\\VarFileInfo\\Translation"; WCHAR varfileinfoW[] = { '\\','V','a','r','F','i','l','e','I','n','f','o', '\\','T','r','a','n','s','l','a','t','i','o','n', 0 }; char WineVarFileInfoA[] = { 0x09, 0x04, 0xE4, 0x04 }; char FileDescriptionA[] = "\\StringFileInfo\\040904E4\\FileDescription"; WCHAR FileDescriptionW[] = { '\\','S','t','r','i','n','g','F','i','l','e','I','n','f','o', '\\','0','4','0','9','0','4','E','4', '\\','F','i','l','e','D','e','s','c','r','i','p','t','i','o','n', 0 }; char WineFileDescriptionA[] = "FileDescription"; WCHAR WineFileDescriptionW[] = { 'F','i','l','e','D','e','s','c','r','i','p','t','i','o','n', 0 }; BOOL is_unicode_enabled = TRUE; /* A copy from dlls/version/info.c */ typedef struct { WORD wLength; WORD wValueLength; WORD wType; WCHAR szKey[1]; #if 0 /* variable length structure */ /* DWORD aligned */ BYTE Value[]; /* DWORD aligned */ VS_VERSION_INFO_STRUCT32 Children[]; #endif } VS_VERSION_INFO_STRUCT32; /* If we call GetFileVersionInfoA on a system that supports Unicode, NT/W2K/XP/W2K3 (by default) and Wine, * the versioninfo will contain Unicode strings. * Part of the test is to call both the A and W versions, which should have the same Version Information * for some requests, on systems that support both calls. */ /* First get the versioninfo via the W versions */ SetLastError(0xdeadbeef); GetModuleFileNameW(NULL, mypathW, MAX_PATH); if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { win_skip("GetModuleFileNameW not existing on this platform, skipping comparison between A- and W-calls\n"); is_unicode_enabled = FALSE; } if (is_unicode_enabled) { retvalW = GetFileVersionInfoSizeW( mypathW, &hdlW); pVersionInfoW = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, retvalW ); retW = GetFileVersionInfoW( mypathW, 0, retvalW, pVersionInfoW ); ok(retW, "GetFileVersionInfo failed: GetLastError = %u\n", GetLastError()); } GetModuleFileNameA(NULL, mypathA, MAX_PATH); retvalA = GetFileVersionInfoSizeA( mypathA, &hdlA); pVersionInfoA = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, retvalA ); retA = GetFileVersionInfoA( mypathA, 0, retvalA, pVersionInfoA ); ok(retA, "GetFileVersionInfo failed: GetLastError = %u\n", GetLastError()); if (is_unicode_enabled) { ok( retvalA == retvalW, "The size of the struct should be the same for both A/W calls, it is (%d) vs. (%d)\n", retvalA, retvalW); ok( !memcmp(pVersionInfoA, pVersionInfoW, retvalA), "Both structs should be the same, they aren't\n"); } /* The structs on Windows are bigger than just the struct for the basic information. The total struct * contains also an empty part, which is used for converted strings. The converted strings are a result * of calling VerQueryValueA on a 32bit resource and calling VerQueryValueW on a 16bit resource. * The first WORD of the structure (wLength) shows the size of the base struct. The total struct size depends * on the Windows version: * * 16bits resource (numbers are from a sample app): * * Windows Version Retrieved with A/W wLength StructSize * ==================================================================================== * Win98 A 0x01B4 (436) 436 * NT4 A/W 0x01B4 (436) 2048 ??? * W2K/XP/W2K3 A/W 0x01B4 (436) 1536 which is (436 - sizeof(VS_FIXEDFILEINFO)) * 4 * * 32bits resource (numbers are from this test executable version_crosstest.exe): * Windows Version Retrieved with A/W wLength StructSize * ============================================================= * Win98 A 0x01E0 (480) 848 (structure data doesn't seem correct) * NT4 A/W 0x0350 (848) 1272 (848 * 1.5) * W2K/XP/W2K3 A/W 0x0350 (848) 1700 which is (848 * 2) + 4 * * Wine will follow the implementation (eventually) of W2K/XP/W2K3 */ /* Now some tests for the above (only if we are unicode enabled) */ if (is_unicode_enabled) { VS_VERSION_INFO_STRUCT32 *vvis = pVersionInfoW; ok ( retvalW == ((vvis->wLength * 2) + 4) || retvalW == (vvis->wLength * 1.5), "Structure is not of the correct size\n"); } /* Although the 32bit resource structures contain Unicode strings, VerQueryValueA will always return normal strings, * VerQueryValueW will always return Unicode ones. (That means everything returned for StringFileInfo requests). */ /* Get the VS_FIXEDFILEINFO information, this must be the same for both A- and W-Calls */ retA = VerQueryValueA( pVersionInfoA, rootA, (LPVOID *)&pBufA, &uiLengthA ); ok (retA, "VerQueryValueA failed: GetLastError = %u\n", GetLastError()); ok ( uiLengthA == sizeof(VS_FIXEDFILEINFO), "Size (%d) doesn't match the size of the VS_FIXEDFILEINFO struct\n", uiLengthA); if (is_unicode_enabled) { if(0) { /* This causes Vista and w2k8 to crash */ retW = VerQueryValueW( pVersionInfoW, NULL, (LPVOID *)&pBufW, &uiLengthW ); ok (retW, "VerQueryValueW failed: GetLastError = %u\n", GetLastError()); } retW = VerQueryValueW( pVersionInfoW, emptyW, (LPVOID *)&pBufW, &uiLengthW ); ok (retW, "VerQueryValueW failed: GetLastError = %u\n", GetLastError()); retW = VerQueryValueW( pVersionInfoW, rootW, (LPVOID *)&pBufW, &uiLengthW ); ok (retW, "VerQueryValueW failed: GetLastError = %u\n", GetLastError()); ok ( uiLengthW == sizeof(VS_FIXEDFILEINFO), "Size (%d) doesn't match the size of the VS_FIXEDFILEINFO struct\n", uiLengthW ); ok( uiLengthA == uiLengthW, "The size of VS_FIXEDFILEINFO should be the same for both A/W calls, it is (%d) vs. (%d)\n", uiLengthA, uiLengthW); ok( !memcmp(pBufA, pBufW, uiLengthA), "Both values should be the same, they aren't\n"); } /* Get some VarFileInfo information, this must be the same for both A- and W-Calls */ retA = VerQueryValueA( pVersionInfoA, varfileinfoA, (LPVOID *)&pBufA, &uiLengthA ); ok (retA, "VerQueryValueA failed: GetLastError = %u\n", GetLastError()); ok( !memcmp(pBufA, WineVarFileInfoA, uiLengthA), "The VarFileInfo should have matched 0904e404 (non case sensitive)\n"); if (is_unicode_enabled) { retW = VerQueryValueW( pVersionInfoW, varfileinfoW, (LPVOID *)&pBufW, &uiLengthW ); ok (retW, "VerQueryValueW failed: GetLastError = %u\n", GetLastError()); ok( uiLengthA == uiLengthW, "The size of the VarFileInfo information should be the same for both A/W calls, it is (%d) vs. (%d)\n", uiLengthA, uiLengthW); ok( !memcmp(pBufA, pBufW, uiLengthA), "Both values should be the same, they aren't\n"); } /* Get some StringFileInfo information, this will be ANSI for A-Calls and Unicode for W-Calls */ retA = VerQueryValueA( pVersionInfoA, FileDescriptionA, (LPVOID *)&pBufA, &uiLengthA ); ok (retA, "VerQueryValueA failed: GetLastError = %u\n", GetLastError()); ok( !lstrcmpA(WineFileDescriptionA, pBufA), "expected '%s' got '%s'\n", WineFileDescriptionA, pBufA); /* Test a second time */ retA = VerQueryValueA( pVersionInfoA, FileDescriptionA, (LPVOID *)&pBufA, &uiLengthA ); ok (retA, "VerQueryValueA failed: GetLastError = %u\n", GetLastError()); ok( !lstrcmpA(WineFileDescriptionA, pBufA), "expected '%s' got '%s'\n", WineFileDescriptionA, pBufA); if (is_unicode_enabled) { retW = VerQueryValueW( pVersionInfoW, FileDescriptionW, (LPVOID *)&pBufW, &uiLengthW ); ok (retW, "VerQueryValueW failed: GetLastError = %u\n", GetLastError()); ok( !lstrcmpW(WineFileDescriptionW, pBufW), "FileDescription should have been '%s'\n", WineFileDescriptionA); } HeapFree( GetProcessHeap(), 0, pVersionInfoA); if (is_unicode_enabled) HeapFree( GetProcessHeap(), 0, pVersionInfoW); }
/*********************************************************************** * VideoCapDriverDescAndVer [MSVIDEO.22] */ DWORD WINAPI VideoCapDriverDescAndVer16(WORD nr, LPSTR buf1, WORD buf1len, LPSTR buf2, WORD buf2len) { static const char version_info_spec[] = "\\StringFileInfo\\040904E4\\FileDescription"; DWORD verhandle; DWORD infosize; UINT subblocklen; char *s, buf[2048], fn[260]; LPBYTE infobuf; LPVOID subblock; DWORD i, cnt = 0, lRet; DWORD bufLen, fnLen; FILETIME lastWrite; HKEY hKey; BOOL found = FALSE; TRACE("(%d,%p,%d,%p,%d)\n", nr, buf1, buf1len, buf2, buf2len); lRet = RegOpenKeyExA(HKEY_LOCAL_MACHINE, HKLM_DRIVERS32, 0, KEY_QUERY_VALUE, &hKey); if (lRet == ERROR_SUCCESS) { RegQueryInfoKeyA( hKey, 0, 0, 0, &cnt, 0, 0, 0, 0, 0, 0, 0); for (i = 0; i < cnt; i++) { bufLen = sizeof(buf) / sizeof(buf[0]); lRet = RegEnumKeyExA(hKey, i, buf, &bufLen, 0, 0, 0, &lastWrite); if (lRet != ERROR_SUCCESS) continue; if (strncasecmp(buf, "vid", 3)) continue; if (nr--) continue; fnLen = sizeof(fn); lRet = RegQueryValueExA(hKey, buf, 0, 0, (LPBYTE)fn, &fnLen); if (lRet == ERROR_SUCCESS) found = TRUE; break; } RegCloseKey( hKey ); } /* search system.ini if not found in the registry */ if (!found && GetPrivateProfileStringA("drivers32", NULL, NULL, buf, sizeof(buf), "system.ini")) { for (s = buf; *s; s += strlen(s) + 1) { if (strncasecmp(s, "vid", 3)) continue; if (nr--) continue; if (GetPrivateProfileStringA("drivers32", s, NULL, fn, sizeof(fn), "system.ini")) found = TRUE; break; } } if (!found) { TRACE("No more VID* entries found nr=%d\n", nr); return 20; } infosize = GetFileVersionInfoSizeA(fn, &verhandle); if (!infosize) { TRACE("%s has no fileversioninfo.\n", fn); return 18; } infobuf = HeapAlloc(GetProcessHeap(), 0, infosize); if (GetFileVersionInfoA(fn, verhandle, infosize, infobuf)) { /* Yes, two space behind : */ /* FIXME: test for buflen */ snprintf(buf2, buf2len, "Version: %d.%d.%d.%d\n", ((WORD*)infobuf)[0x0f], ((WORD*)infobuf)[0x0e], ((WORD*)infobuf)[0x11], ((WORD*)infobuf)[0x10] ); TRACE("version of %s is %s\n", fn, buf2); } else { TRACE("GetFileVersionInfoA failed for %s.\n", fn); lstrcpynA(buf2, fn, buf2len); /* msvideo.dll appears to copy fn*/ } /* FIXME: language problem? */ if (VerQueryValueA( infobuf, version_info_spec, &subblock, &subblocklen )) { UINT copylen = min(subblocklen,buf1len-1); memcpy(buf1, subblock, copylen); buf1[copylen] = '\0'; TRACE("VQA returned %s\n", (LPCSTR)subblock); } else { TRACE("VQA did not return on query \\StringFileInfo\\040904E4\\FileDescription?\n"); lstrcpynA(buf1, fn, buf1len); /* msvideo.dll appears to copy fn*/ } HeapFree(GetProcessHeap(), 0, infobuf); return 0; }
static void test_GetFileVersionInfoEx(void) { char *ver, *p; BOOL ret; UINT size, translation, i; HMODULE mod; BOOL (WINAPI *pGetFileVersionInfoExW)(DWORD, LPCWSTR, DWORD, DWORD, LPVOID); DWORD (WINAPI *pGetFileVersionInfoSizeExW)(DWORD, LPCWSTR, LPDWORD); const LANGID lang = GetUserDefaultUILanguage(); const LANGID english = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); const WORD unicode = 1200; /* = UNICODE */ const WCHAR kernel32W[] = {'k','e','r','n','e','l','3','2','.','d','l','l',0}; const DWORD test_flags[] = { 0, FILE_VER_GET_LOCALISED, FILE_VER_GET_NEUTRAL, FILE_VER_GET_LOCALISED | FILE_VER_GET_NEUTRAL, 0xdeadbeef, /* invalid value (ignored) */ }; char desc[MAX_PATH]; mod = GetModuleHandleA("kernel32.dll"); assert(mod); if (!FindResourceExA(mod, (LPCSTR)RT_VERSION, (LPCSTR)VS_VERSION_INFO, lang) && !FindResourceExA(mod, (LPCSTR)RT_VERSION, (LPCSTR)VS_VERSION_INFO, MAKELANGID(PRIMARYLANGID(lang),SUBLANG_NEUTRAL))) { skip("Translation is not available\n"); return; } size = GetFileVersionInfoSizeW(kernel32W, NULL); ok(size, "GetFileVersionInfoSize(kernel32) error %u\n", GetLastError()); ver = HeapAlloc(GetProcessHeap(), 0, size); assert(ver); ret = GetFileVersionInfoW(kernel32W, 0, size, ver); ok(ret, "GetFileVersionInfo error %u\n", GetLastError()); ret = VerQueryValueA(ver, "\\VarFileInfo\\Translation", (void **)&p, &size); translation = *(UINT *)p; ok(ret, "VerQueryValue error %u\n", GetLastError()); ok(size == 4, "VerQueryValue returned %u, expected 4\n", size); /* test default version resource */ ok(LOWORD(translation) == lang, "got %u, expected lang is %u\n", LOWORD(translation), lang); ok(HIWORD(translation) == unicode, "got %u, expected codepage is %u\n", HIWORD(translation), unicode); HeapFree(GetProcessHeap(), 0, ver); mod = GetModuleHandleA("version.dll"); assert(mod); /* prefer W-version as A-version is not available on Windows 7 */ pGetFileVersionInfoExW = (void *)GetProcAddress(mod, "GetFileVersionInfoExW"); pGetFileVersionInfoSizeExW = (void *)GetProcAddress(mod, "GetFileVersionInfoSizeExW"); if (!pGetFileVersionInfoExW && !pGetFileVersionInfoSizeExW) { win_skip("GetFileVersionInfoEx family is not available\n"); return; } for (i = 0; i < ARRAY_SIZE(test_flags); i++) { size = pGetFileVersionInfoSizeExW(test_flags[i], kernel32W, NULL); ok(size, "[%u] GetFileVersionInfoSizeEx(kernel32) error %u\n", i, GetLastError()); ver = HeapAlloc(GetProcessHeap(), 0, size); assert(ver); ret = pGetFileVersionInfoExW(test_flags[i], kernel32W, 0, size, ver); ok(ret, "[%u] GetFileVersionInfoEx error %u\n", i, GetLastError()); ret = VerQueryValueA(ver, "\\VarFileInfo\\Translation", (void **)&p, &size); ok(ret, "[%u] VerQueryValue error %u\n", i, GetLastError()); ok(size == 4, "[%u] VerQueryValue returned %u, expected 4\n", i, size); translation = *(UINT *)p; /* test MUI version resource */ if (test_flags[i] & FILE_VER_GET_LOCALISED) ok(LOWORD(translation) == lang, "[%u] got %u, expected lang is %u\n", i, LOWORD(translation), lang); else ok(LOWORD(translation) == english, "[%u] got %u, expected lang is %u\n", i, LOWORD(translation), english); ok(HIWORD(translation) == unicode, "[%u] got %u, expected codepage is %u\n", i, HIWORD(translation), unicode); /* test string info using translation info */ size = 0; sprintf(desc, "\\StringFileInfo\\%04x%04x\\FileDescription", LOWORD(translation), HIWORD(translation)); ret = VerQueryValueA(ver, desc, (void **)&p, &size); ok(ret, "[%u] VerQueryValue error %u\n", i, GetLastError()); ok(size == strlen(p) + 1, "[%u] VerQueryValue returned %u\n", i, size); HeapFree(GetProcessHeap(), 0, ver); } return; }