2008-11-25 7 views
30

Mam zasobu wersji w moich zasobach w projekcie C++, który zawiera numer wersji, prawa autorskie i szczegóły kompilacji. Czy istnieje prosty sposób, aby uzyskać dostęp do tego w czasie wykonywania, aby wypełnić moje okno dialogowe help/about, ponieważ obecnie utrzymuję oddzielne wartości stałych tych informacji. Idealnie, rozwiązanie powinno działać dla Windows/CE mobile i wcześniejszych wersji Visual C++ (6.0 w górę).Jak odczytać z zasobu wersji w Visual C++

+0

Należy zauważyć, że użycie '_get_pgmptr()' lub '_get_wpgmptr()' jest lepsze niż 'GetModuleFileName (NULL, szFilename, MAX_PATH)'; ratuje cię od niepotrzebnej alokacji i wyjaśnia twoją intencję. – q12

Odpowiedz

30

Jest to edytowany wersja mojego oryginalnego odpowiedź.

bool GetProductAndVersion(CStringA & strProductName, CStringA & strProductVersion) 
{ 
    // get the filename of the executable containing the version resource 
    TCHAR szFilename[MAX_PATH + 1] = {0}; 
    if (GetModuleFileName(NULL, szFilename, MAX_PATH) == 0) 
    { 
     TRACE("GetModuleFileName failed with error %d\n", GetLastError()); 
     return false; 
    } 

    // allocate a block of memory for the version info 
    DWORD dummy; 
    DWORD dwSize = GetFileVersionInfoSize(szFilename, &dummy); 
    if (dwSize == 0) 
    { 
     TRACE("GetFileVersionInfoSize failed with error %d\n", GetLastError()); 
     return false; 
    } 
    std::vector<BYTE> data(dwSize); 

    // load the version info 
    if (!GetFileVersionInfo(szFilename, NULL, dwSize, &data[0])) 
    { 
     TRACE("GetFileVersionInfo failed with error %d\n", GetLastError()); 
     return false; 
    } 

    // get the name and version strings 
    LPVOID pvProductName = NULL; 
    unsigned int iProductNameLen = 0; 
    LPVOID pvProductVersion = NULL; 
    unsigned int iProductVersionLen = 0; 

    // replace "040904e4" with the language ID of your resources 
    if (!VerQueryValue(&data[0], _T("\\StringFileInfo\\040904e4\\ProductName"), &pvProductName, &iProductNameLen) || 
     !VerQueryValue(&data[0], _T("\\StringFileInfo\\040904e4\\ProductVersion"), &pvProductVersion, &iProductVersionLen)) 
    { 
     TRACE("Can't obtain ProductName and ProductVersion from resources\n"); 
     return false; 
    } 

    strProductName.SetString((LPCSTR)pvProductName, iProductNameLen); 
    strProductVersion.SetString((LPCSTR)pvProductVersion, iProductVersionLen); 

    return true; 
} 
+0

Gdzie znajduje się identyfikator języka? –

+0

@JeffB Zacznę od strony MSDN [Stałe identyfikatora języka i ciągi znaków] (https://msdn.microsoft.com/en-us/library/windows/desktop/dd318693 (v = vs.85) .aspx) . –

+0

Obie twoje ostatnie dwie linie dają mi '' void ATL :: CSimpleStringT :: SetString (const char *, int) ': nie można przekonwertować argumentu 1 z' LPCTSTR 'na' const char * '. '. Mam '#include ' –

5

Coś takiego daje surowy dostęp do danych zasobów i możesz zacząć:

HRSRC res = ::FindResource(NULL, MAKEINTRESOURCE(MY_VERSION_ID), RT_VERSION); 
DWORD size = ::SizeofResource(NULL, res); 
HGLOBAL mem = ::LoadResource(NULL, res); 
LPVOID raw_data = ::LockResource(mem); 
... 
::FreeResource(mem); 
0

Ok, nieco bardziej googleing znalazł following na CodeGuru. Zasadniczo to podejście używa obiektu , aby uzyskać dostęp do dowolnego pliku. Warto sprawdzić, czy działa na aktualnie uruchomionym pliku .EXE i Windows CE.

7

Coś może Ci zacząć, może:

TCHAR moduleName[MAX_PATH+1]; 
(void)GetModuleFileName(AfxGetInstanceHandle(), moduleName, MAX_PATH); 
DWORD dummyZero; 
DWORD versionSize = GetFileVersionInfoSize(moduleName, &dummyZero); 
if(versionSize == 0) 
{ 
    return NULL; 
} 
void* pVersion = malloc(versionSize); 
if(pVersion == NULL) 
{ 
    return NULL; 
} 
if(!GetFileVersionInfo(moduleName, NULL, versionSize, pVersion)) 
{ 
    free(pVersion); 
    return NULL; 
} 

UINT length; 
VS_FIXEDFILEINFO* pFixInfo; 
VERIFY(VerQueryValue(pVersionInfo, const_cast<LPTSTR>("\\"), (LPVOID*)&pFixInfo, &length)); 
4

Uwaga! Korzystanie z FindResource..LockResource nie jest poprawne. Czasami będzie działać (tak jak w moim małym programie demonstracyjnym), a czasami powoduje naruszenia zasad dostępu (np. Kod produkcyjny, dla którego robiłem demo).

Dokumentacja VerQueryValue() stwierdza, że ​​należy wywołać metody GetFileVersionInfoSize i GetFileVersionInfo. Raymond Chen wyjaśnia, zobacz http://blogs.msdn.com/oldnewthing/archive/2006/12/26/1365215.aspx

13

Aby uzyskać język niezależny wynik zmian odpowiedź Marka:

// replace "040904e4" with the language ID of your resources 
    !VerQueryValue(&data[0], _T("\\StringFileInfo\\040904e4\\ProductVersion"), &pvProductVersion, &iProductVersionLen)) 
{ 
    TRACE("Can't obtain ProductName and ProductVersion from resources\n"); 
    return false; 
} 

Aby

UINT    uiVerLen = 0; 
VS_FIXEDFILEINFO* pFixedInfo = 0;  // pointer to fixed file info structure 
// get the fixed file info (language-independent) 
if(VerQueryValue(&data[0], TEXT("\\"), (void**)&pFixedInfo, (UINT *)&uiVerLen) == 0) 
{ 
    return false; 
} 

strProductVersion.Format("%u.%u.%u.%u", 
    HIWORD (pFixedInfo->dwProductVersionMS), 
    LOWORD (pFixedInfo->dwProductVersionMS), 
    HIWORD (pFixedInfo->dwProductVersionLS), 
    LOWORD (pFixedInfo->dwProductVersionLS)); 
+0

dzięki, to jest bardzo interesujące, świetne rozwiązanie! – ghiboz

+0

Otrzymuje różne informacje od odpowiedzi Marka Ransoma. Pobrane wartości to cztery liczby całkowite z wiersza najwyższego poziomu PRODUCTVERSION w pliku zasobów; jednak odpowiedź Marks pobiera łańcuch "ProductVersion" spod bloku "StringFileInfo". –

0

Czasami otrzymać dostęp naruszenie gdy użycie VerQueryValueA. Ale nigdy nie dostałem tego błędu podczas używania VerQueryValueW. Myślę, że coś nie tak z VerQueryValueA w wersji.dll. Dlatego używam VerQueryValueW zamiast VerQueryValueA nawet w projektach Wielobajtowe kodowanie znaków. Here is my code of ReadVersion function

Powiązane problemy