【问题标题】:Cannot convert Argument 1 from WCHAR to const char * [duplicate]无法将参数 1 从 WCHAR 转换为 const char * [重复]
【发布时间】:2020-09-08 07:22:13
【问题描述】:

我需要帮助:Visual Studio 2019 说它Cannot convert Argument 1 from WCHAR to const char *

uintptr_t GetModuleBaseAddress(const char* modName) {
    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, procId);
    if (hSnap != INVALID_HANDLE_VALUE) {
        MODULEENTRY32 modEntry;
        modEntry.dwSize = sizeof(modEntry);
        if (Module32First(hSnap, &modEntry)) {
            do {
                if (!strcmp(modEntry.szModule, modName)) {
                    CloseHandle(hSnap);
                    return (uintptr_t)modEntry.modBaseAddr;
                }
            } while (Module32Next(hSnap, &modEntry));
        }
    }

这是什么意思?代码有明显错误吗?

【问题讨论】:

  • 哪一行出现此错误?
  • 如果你处理的是wchar_t*,你应该使用std::wcscmp
  • 我觉得你问这个问题很好,而不是用演员来消除警告的做法,许多新程序员后来才发现它要么崩溃要么不起作用。
  • 您似乎正在使用为项目选择的“使用 UNICODE 字符集”选项编译文件:这会将MODULEENTRY32 类型重新定义为MODULEENTRY32W 结构,其中@ 987654328@ 成员是一个WCHAR 数组。您是否可以将项目设置切换为“使用多字节字符集”?如果没有,您将不得不处理您的代码,以便您的函数的参数也是 WCHAR 字符串,或者提供代码来转换它,因为您无法(直接)比较 char* 字符串和 @ 987654332@字符串。
  • @CoryKramer 但是modName 也需要是wchar_t* 字符串。

标签: c++ string winapi unicode


【解决方案1】:

从您的代码 sn-p 中考虑这一行:

if (!strcmp(modEntry.szModule, modName)) {

modEntryMODULEENTRY32 结构的一个实例。在 Unicode 版本中(这是自 VS2005 以来 Visual Studio 中的默认设置),此结构在 Windows SDK 标头中为 #define'd 为 MODULEENTRY32W(注意结尾 W)。

如果您阅读the MSDN documentation on MODULEENTRY32W,您会发现它的szModule 字段是一个WCHAR 数组。这意味着模块名称使用 Unicode UTF-16 编码字符串表示,它遵循我上面提到的 Unicode 构建设置。 WCHAR 基本上是一个typedef 意思是wchar_t

另一方面,您调用的strcmp 函数将两个基于char (const char*) 的字符串作为输入进行比较,而不是基于WCHAR 的字符串和基于char 的字符串。因此,由于这种类型不匹配,编译器正确地抱怨。

要解决此问题,我建议您将代码移动到 Unicode。基本上,您可以传递 const wchar_t* 字符串作为输入,而不是 const char*

uintptr_t GetModuleBaseAddress(const wchar_t* modName) {

您可以使用基于 Unicode 的 wcscmp 函数来比较字符串,而不是 strcmp

if (!wcscmp(modEntry.szModule, modName)) {

另一种方法是更改​​您的项目设置并切换到 ANSI/MBCS 构建(在 VS2019 IDE 中选择您的项目 Properties | Advanced | Character Set 并选择 Use Multi-Byte Character Set),但我更愿意修复您的代码以使其基于 Unicode。

请注意,您需要在代码中为基于wchar_t 的字符串文字使用L 前缀,例如L"Some Unicode UTF-16 string".


另一种选择是在strcmp 调用站点使用ATL conversion helper like CW2A 将Unicode MODULEENTRY32::szModule 字符串转换为ANSI:

#include <atlconv.h> // for CW2A
...

// CW2A converts from wchar_t-string to char-string
if (!strcmp(CW2A(modEntry.szModule), modName)) {

但请注意,这种 Unicode 到 ANSI 的转换很容易出错,因为 Unicode 是 ANSI 的超集。

【讨论】:

    【解决方案2】:

    您正在为 Unicode 编译项目,并且您正在使用 MODULEENTRY32Module32First()Module32Next()TCHAR 变体,因此它们将映射到它们的 Unicode 变体,而不是它们的 ANSI 变体。因此,modEntry.szModule 将是 WCHAR[],您不能将其传递给 strcmp()

    您正在寻找使用 ANSI 字符串的模块,因此您应该使用 Win32 API 函数的 ANSI 变体。

    如果找不到匹配的模块,您也会泄露CreateToolhelp32Snapshot() 返回的HANDLE

    试试这个:

    uintptr_t GetModuleBaseAddress(const char* modName) {
        HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, procId);
        if (hSnap != INVALID_HANDLE_VALUE) {
            MODULEENTRY32A modEntry; // <-- note the trailing A !
            modEntry.dwSize = sizeof(modEntry);
            if (Module32FirstA(hSnap, &modEntry)) { // <-- note the trailing A !
                do {
                    if (strcmp(modEntry.szModule, modName) == 0) {
                        CloseHandle(hSnap);
                        return (uintptr_t)modEntry.modBaseAddr;
                    }
                } while (Module32NextA(hSnap, &modEntry)); // <-- note the trailing A !
            }
            CloseHandle(hSnap); // <-- add this !
         }
    

    【讨论】:

    • 如何将我的代码放入 Unicode
    • modName 更改为使用wchar_t 而不是char,将API 引用更改为使用它们的W 版本而不是它们的A 版本,并将strcmp() 更改为@987654337 @。如果您无法将modName 更改为wchar_t,您至少可以在运行时使用MultiByteToWideChar() 或等效项将其数据转换为wchar_t,然后再将转换后的数据与modEntry.szModule 进行比较
    猜你喜欢
    • 2012-01-28
    • 2014-11-22
    • 2013-08-11
    • 1970-01-01
    • 1970-01-01
    • 2023-03-11
    • 1970-01-01
    • 1970-01-01
    • 2012-09-25
    相关资源
    最近更新 更多