web-dev-qa-db-ja.com

Visual C ++でバージョンリソースから読み取る方法

バージョン番号、著作権、ビルドの詳細を含むC++プロジェクトのリソースにバージョンリソースがあります。現在この情報の個別のconst値を維持しているので、実行時にこれにアクセスしてhelp/aboutダイアログに入力する簡単な方法はありますか?理想的には、このソリューションはWindows/CEモバイルおよび以前のバージョンのVisual C++(6.0以上)で機能する必要があります。

30
SmacL

これは私の元の回答を編集したものです。

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;
}
33
Mark Ransom

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));
14
EdM

次のようなものがあなたを始めるかもしれません、おそらく:

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));
7
Will Dean

このようなものは、リソースデータへの生のアクセスを提供し、あなたを始めるでしょう:

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);
5
Rob

注意してください! FindResource..LockResourceの使用は正しくありません。 (私の小さなデモプログラムと同じように)動作することもあれば、アクセス違反を引き起こすこともあります(例:デモを作成していた製品コード)。

VerQueryValue()のドキュメントには、代わりにGetFileVersionInfoSizeおよびGetFileVersionInfoを呼び出す必要があると記載されています。 Raymond Chenが説明します http://blogs.msdn.com/oldnewthing/archive/2006/12/26/1365215.aspx を参照してください

4
Leo

VerQueryValueAを使用すると、アクセス違反が発生することがあります。しかし、VerQueryValueWを使用しても、このエラーは発生しませんでした。 version.dllのVerQueryValueAに問題があると思います。そのため、マルチバイト文字エンコーディングのプロジェクトでも、VerQueryValueWではなくVerQueryValueAを使用しています。 これがReadVersion関数の私のコードです

0
Vitaly

OK、もう少しグーグルで、CodeGuruに following が見つかりました。基本的にこのアプローチでは、CFileVersionInfoオブジェクトを使用して、任意のファイルを取得します。現在実行中の.EXEファイルとWindows CEで動作するかどうかを確認することは興味深いはずです。

0
SmacL