2008-11-25 20 views
30

Tôi có tài nguyên phiên bản trong tài nguyên của mình trong dự án C++ chứa số phiên bản, bản quyền và chi tiết bản dựng. Có cách nào dễ dàng để truy cập vào thời gian chạy này để điền vào hộp thoại trợ giúp của tôi/khoảng vì tôi hiện đang duy trì các giá trị const riêng biệt của thông tin này. Lý tưởng nhất, giải pháp nên hoạt động cho Windows/CE di động và các phiên bản trước của Visual C++ (6.0 trở lên).Làm cách nào để đọc từ tài nguyên phiên bản trong Visual C++

+0

Bạn nên lưu ý rằng việc sử dụng '_get_pgmptr()' hoặc '_get_wpgmptr()' là tốt hơn 'GetModuleFileName (NULL, szFilename, MAX_PATH)'; tiết kiệm cho bạn từ việc phân bổ không cần thiết và làm rõ ý định của bạn. – q12

Trả lời

30

Đây là một phiên bản chỉnh sửa của câu trả lời ban đầu của tôi.

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

Bạn tìm ID ngôn ngữ ở đâu? –

+0

@JeffB Tôi sẽ bắt đầu tại trang MSDN [Các hằng số nhận dạng ngôn ngữ và các chuỗi] (https://msdn.microsoft.com/en-us/library/windows/desktop/dd318693 (v = vs.85) .aspx) . –

+0

Cả hai dòng cuối cùng của bạn cung cấp cho tôi một ''void ATL :: CSimpleStringT :: SetString (const char *, int)': không thể chuyển đổi đối số 1 từ 'LPCTSTR' thành 'const char *'. Tôi đã '#include ' –

5

Something như thế này sẽ cung cấp cho bạn truy cập thô để các dữ liệu tài nguyên và giúp bạn bắt đầu:

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, thêm một chút googleing tìm thấy following trên CodeGuru. Về cơ bản, phương pháp này sử dụng đối tượng CFileVersionInfo để nhận bất kỳ tệp nào đã cho. Sẽ rất thú vị nếu nó hoạt động trên tệp .EXE hiện đang chạy và trên Windows CE.

7

Cái gì đó như có thể giúp bạn bắt đầu, có lẽ:

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

Cẩn thận! Sử dụng FindResource..LockResource không chính xác. Nó đôi khi sẽ làm việc (như nó đã làm trong chương trình demo nhỏ của tôi) và đôi khi gây ra các vi phạm truy cập (ví dụ: mã sản xuất tôi đã tạo bản trình diễn).

Tài liệu VerQueryValue() nêu rõ rằng bạn nên gọi GetFileVersionInfoSize và GetFileVersionInfo để thay thế. Raymond Chen giải thích, xem http://blogs.msdn.com/oldnewthing/archive/2006/12/26/1365215.aspx

13

Để có được một kết quả độc lập ngôn ngữ để thay đổi câu trả lời của Mark:

// 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; 
} 

Để

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

cảm ơn, điều này rất thú vị, giải pháp tuyệt vời! – ghiboz

+0

Điều này nhận được thông tin khác nhau từ câu trả lời của Mark Ransom. Các giá trị bạn truy xuất là bốn số nguyên từ dòng cấp cao nhất PRODUCTVERSION trong tệp tài nguyên; tuy nhiên câu trả lời của Marks lấy chuỗi "ProductVersion" từ dưới khối "StringFileInfo". –

0

Đôi khi tôi nhận được truy cập Vi phạm khi sử dụng VerQueryValueA. Nhưng tôi chưa bao giờ gặp lỗi này khi sử dụng VerQueryValueW. Tôi nghĩ có điều gì đó sai với VerQueryValueA trong version.dll. Do đó, tôi sử dụng VerQueryValueW thay vì VerQueryValueA ngay cả trong các dự án Mã hóa ký tự nhiều byte. Here is my code of ReadVersion function

Các vấn đề liên quan