【问题标题】:Using GUIDFromString requries including Shell32.dll: How do I do that使用 GUIDFromString 请求,包括 Shell32.dll:我该怎么做
【发布时间】:2025-12-01 07:05:01
【问题描述】:

我正在尝试使用 WinAPI 函数GUIDFromString(),但它需要一些技巧才能将其包含在我的项目中。

根据msdn 文档:

此函数未在标头中声明或按名称从 .dll 文件。它必须从 Shell32.dll 作为序号 703 加载 GUIDFromStringA 和 GUIDFromStringW 的序号 704。

它也可以从 Shlwapi.dll 作为序数 269 访问 GUIDFromStringA 和 GUIDFromStringW 的序号 270。

我以前从未加载过 DLL,所以我不确定我应该做什么,我不确定加载 DLL 是否足够,我是否还必须包含一个编号为 703 的“序数”?任何人都可以就我需要做什么来使用这个功能甚至是一个例子提供任何建议吗?

我在下面的尝试不起作用(我使用的是 VC++ 2010 Express):

#pragma comment(lib, "shell32.lib") // if I am including the dll do I need to include the lib aswell?

// I've heard that the dll location differs across versions of windows
// Does anyone know of a Cross-Windows-Version way to include Shell32.dll no matter where it is? Maybe use a keyword like "%SYSTEM%/Shell32.dll"
HINSTANCE shell32DLL = LoadLibary("C:/System/Shell32.dll"); 

// Now do I include 'Ordinal 703' as described in msdn? And how do I do that?

【问题讨论】:

  • 我没有用序数代替名字做任何类似的事情,但我猜你在GetProcAddress中指定"703"作为名字。
  • 你也可以使用UuidFromString按名称导出的函数(msdn.microsoft.com/en-us/library/windows/desktop/…
  • @chris:使用MAKEINTRESOURCE() 将序数传递给GetProcAddress()
  • @RemyLebeau,哦,我明白了。有一天知道这一点会很高兴,谢谢。
  • 很好奇,您是否事先知道 GUID(这是您在运行时发现的字符串?) - 如果是这样,您可以跳过字符串解析并在编译时将其声明为 GUID myGuid = { 0x00000000, 0x0000, 0x0000, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } 或类似。

标签: c++ winapi dll


【解决方案1】:

如果您将read the documentation 换成GUIDFromString(),它会说:

GUIDFromString 可通过带有 Service Pack 2 (SP2) 的 Windows XP 或 Windows Vista 使用。在后续版本中可能会更改或不可用。应用程序应使用 CLSIDFromString 或 IIDFromString 代替此函数。

CLSIDFromString()IIDFromString() 都是从 Ole32.dll 中按名称导出的,因此您可以像使用任何其他 DLL 函数一样使用它们。

话虽如此,如果您仍想使用GUIDFromString(),请使用LoadLibrary() 加载shell32.dll,然后使用GetProcAddress() 访问该功能。 MSDN documentation 演示了如何做到这一点。要按序号加载函数,可以在调用GetProcAddress()时使用MAKEINTRESOURCE()宏。

所以,例如:

// MAKEINTRESOURCE() returns an LPTSTR, but GetProcAddress()
// expects LPSTR even in UNICODE, so using MAKEINTRESOURCEA()...
#ifdef UNICODE
#define MAKEINTRESOURCEA_T(a, u) MAKEINTRESOURCEA(u)
#else
#define MAKEINTRESOURCEA_T(a, u) MAKEINTRESOURCEA(a)
#endif

BOOL myGUIDFromString(LPCTSTR psz, LPGUID pguid)
{
    BOOL bRet = FALSE;

    typedef BOOL (WINAPI *LPFN_GUIDFromString)(LPCTSTR, LPGUID);
    LPFN_GUIDFromString pGUIDFromString = NULL;

    HINSTANCE hInst = LoadLibrary(TEXT("shell32.dll"));
    if (hInst)
    {
        pGUIDFromString = (LPFN_GUIDFromString) GetProcAddress(hInst, MAKEINTRESOURCEA_T(703, 704));
        if (pGUIDFromString)
            bRet = pGUIDFromString(psz, pguid);
        FreeLibrary(hInst);
    }

    if (!pGUIDFromString)
    {
        hInst = LoadLibrary(TEXT("Shlwapi.dll"));
        if (hInst)
        {
            pGUIDFromString = (LPFN_GUIDFromString) GetProcAddress(hInst, MAKEINTRESOURCEA_T(269, 270));
            if (pGUIDFromString)
                bRet = pGUIDFromString(psz, pguid);
            FreeLibrary(hInst);
        }
    }

    return bRet;
}

【讨论】:

  • 是的,我可以在没有 MSVC 的情况下使用 COM 和 OLE。对于IIDFromString,请确保将接口 IID 括在大括号中。
【解决方案2】:

将以下行保存为 SHLWAPIX.DEF:

LIBRARY SHLWAPI
VERSION 6.0
EXPORTS
 GUIDFromStringA @269
 GUIDFromStringW @270

将以下行另存为 SHLWAPIX.C:

// https://msdn.microsoft.com/en-us/library/bb776431.aspx

__declspec(dllexport)
int __stdcall GUIDFromStringA(void *_1, void *_2)
{ return 0; }

__declspec(dllexport)
int __stdcall GUIDFromStringW(void *_1, void *_2)
{ return 0; }

运行 CL.EXE /LD /Zl SHLWAPIX.C /link /DEF:SHLWAPIX.DEF /NOENTRY 创建导入库SHLWAPIX.LIB,然后删除SHLWAPIX.OBJ、SHLWAPIX.EXP和SHLWAPIX.DLL

将以下行保存为 SHLWAPIX.H:

#pragma once
#pragma comment(linker, "/DEFAULTLIB:SHLWAPIX.LIB")

__declspec(dllimport)
BOOL WINAPI GUIDFromStringA(LPCSTR psz, LPGUID pguid);

__declspec(dllimport)
BOOL WINAPI GUIDFromStringW(LPCWSTR psz, LPGUID pguid);

最后将下面几行保存为SHLWAPIX.C:

#pragma comment(lib, "SHLWAPIX.LIB")
#pragma comment(lib, "USER32.LIB")

#pragma comment(linker, "/ENTRY:wWinMainCRTStartup")
#pragma comment(linker, "/SUBSYSTEM:WINDOWS,5.0")
#pragma comment(linker, "/VERSION:1.0")

#define STRICT
#define UNICODE
#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include "shlwapix.h"

VOID wWinMainCRTStartup()
{
    GUID guid = {0};
    WCHAR szBuffer[1025] = L"";

    if (GUIDFromStringA("{00112233-4455-6677-8899-AABBCCDDEEFF}", &guid))
        if (wsprintf(szBuffer, L"GUID = {%08lX-%04hX-%04hX-%02X%02X-%02X%02X%02X%02X%02X%02X}\n",`
                     guid.Data1, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]) > 0)
            MessageBox((HWND) NULL, szBuffer, L"GUIDFromStringA()", MB_OK);

    if (GUIDFromStringW(L"{FFEEDDCC-BBAA-9988-7766-554433221100}", &guid))
        if (wsprintf(szBuffer, L"GUID = {%08lX-%04hX-%04hX-%02X%02X-%02X%02X%02X%02X%02X%02X}\n",
                     guid.Data1, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]) > 0)
            MessageBox((HWND) NULL, szBuffer, L"GUIDFromStringW()", MB_OK);
}

最后运行CL.EXE /GS- SHLWAPIX.C创建SHLWAPIX.EXE,然后运行后者。

【讨论】:

    【解决方案3】:

    这会给你一个错误“语法错误'('”:

    typedef BOOL WINAPI (*LPFN_GUIDFromString)(LPCTSTR, LPGUID);
    

    正确的版本是:

    typedef BOOL (WINAPI *LPFN_GUIDFromString)(LPCTSTR, LPGUID);
    

    【讨论】:

    • 一个答案不是评论另一个答案的合适区域,但无论如何......它很有帮助。