C++更新资源文件的问题

int main()
{
    const LPCWSTR lpType = MAKEINTRESOURCE(135);
    const LPCWSTR lpName = L"CPPFILEACCOUNTJSON";

    wchar_t exePath[] = L"I:\\CPP\\project\\test\\bin\\test.exe";
    LPWSTR lpExePath = exePath;
    //GetModuleFileNameW(NULL, exePath, MAX_PATH);
    HANDLE hUpdate = BeginUpdateResourceW(exePath, FALSE);
    if (hUpdate == NULL) {
        MessageBoxW(0, L"BeginUpdateResource failed.", 0, MB_OK | MB_ICONERROR);
        return 1;
    }
    char newStr[] = "123456789";
    wchar_t newStrW[sizeof(newStr)];
    MultiByteToWideChar(CP_UTF8, 0, newStr, sizeof(newStr), newStrW, sizeof(newStrW) / sizeof(wchar_t));
    size_t dataSize = (strlen(newStr)) * sizeof(wchar_t);
    cout << dataSize << endl;

    if (!UpdateResourceW(hUpdate, lpName, lpType, 0, newStrW, dataSize)) {
        MessageBoxW(0, L"UpdateResource failed.", 0, MB_OK | MB_ICONERROR);
        return 1;
    }
    if (!EndUpdateResourceW(hUpdate, FALSE)) {
        DWORD errCode = GetLastError();
        LPWSTR errBuffer = nullptr;
        FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
            nullptr, errCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&errBuffer, 0, nullptr);
        MessageBoxW(nullptr, errBuffer, L"Error", MB_OK | MB_ICONERROR);
        LocalFree(errBuffer);
        return 1;
    }

    system("pause");
    std::cout << "Hello World!\n";
    return  0;
}

在上面的代码中我替换指定的资源文件的字符串内容为:"123456789"
代码执行成功后 test.exe被成功写入的字符只有"1" 这是为什么 我哪里写错了。。。求解答

img

BOOL UpdateResourceW(
  [in]           HANDLE  hUpdate,
  [in]           LPCWSTR lpType,
  [in]           LPCWSTR lpName,
  [in]           WORD    wLanguage,
  [in, optional] LPVOID  lpData,
  [in]           DWORD   cb
);

你参数调用顺序好像有误,type在前面,name在后面,你好像反了

该回答引用ChatGPT
在上述代码中,数据大小 `dataSize` 的计算方法存在问题。因为此处需要更新的资源是 Unicode 字符串,所以 `dataSize` 计算应该是字符串长度加上 1(表示字符串结束符号 '\0')再乘上 `sizeof(wchar_t)` 的值。所以应该改成如下这样:


size_t dataSize = (wcslen(newStrW) + 1) * sizeof(wchar_t);


原来的计算方式仅仅将字符串的字节数作为大小信息,导致实际写入的数据只有第一个字符(低位一个字节)被正确写入,而其它字符都被丢弃了。
cout << dataSize << endl;

这里输出多少

以下答案由GPT-3.5大模型与博主波罗歌共同编写:
这是一个编码问题,具体原因是在使用MultiByteToWideChar将char类型的字符串newStr转换成wchar_t类型的字符串newStrW时出现了问题。

在使用sizeof(newStr)的时候,返回的是字符数组newStr的总长度,而实际上字符数组newStr中的有效字符只有9个,也就是字符串"123456789"的长度。因此,在调用MultiByteToWideChar时,需要传入字符串的实际长度,而不是字符数组的长度。

修改方式如下:

char newStr[] = "123456789";
int newStrLength = strlen(newStr);

// 计算出转换成宽字符后需要的缓冲区大小
int bufferLength = MultiByteToWideChar(CP_UTF8, 0, newStr, newStrLength, nullptr, 0);

// 分配缓冲区
wchar_t *newStrW = new wchar_t[bufferLength + 1];

// 将char类型的字符串转换成wchar_t类型的字符串
MultiByteToWideChar(CP_UTF8, 0, newStr, newStrLength, newStrW, bufferLength);
newStrW[bufferLength] = '\0'; // 最后加上一个结束符

if (!UpdateResourceW(hUpdate, lpName, lpType, 0, newStrW, bufferLength * sizeof(wchar_t))) {
    MessageBoxW(0, L"UpdateResource failed.", 0, MB_OK | MB_ICONERROR);
    return 1;
}

delete[] newStrW;

在这个修改后的代码中,首先计算了需要分配的缓冲区的大小,然后根据这个大小动态分配了一段wchar_t类型的内存。接着,调用了MultiByteToWideChar将char类型的字符串转换成wchar_t类型的字符串,并将结果存入刚才分配的内存中。最后,在调用UpdateResourceW时,需要传入的是实际字符的字节数,因此需要将计算出来的字符数乘以每个字符的字节数(在Windows下,wchar_t类型的字符是2个字节),才能得到需要传入的总字节数。

需要特别注意的是,在使用完分配的内存后需要调用delete[]来释放它,避免内存泄漏。
如果我的回答解决了您的问题,请采纳!

引用chatGPT作答,在这个代码中出现问题的原因是对 newStrW 数组的长度估计错误。

在代码中, newStr 数组的长度为 10 (9 个字符和结尾的 null 字节),然后通过 MultiByteToWideChar 函数将其转换为宽字符集编码,存储到 newStrW 数组中。

newStrW 数组的长度被定义为 sizeof(newStrW),这个值通常是在编译时计算的,它等于数组所占用的内存字节数。在这里,这个值为 20 (10 个 wchar_t 类型,每个占用 2 个字节)。

然而,由于 newStr 数组中只有 9 个字符(8 个数字和结尾的 null 字节),因此调用 MultiByteToWideChar 函数后, newStrW 数组中只包含 9 个宽字符。

在调用 UpdateResourceW 函数时, dataSize 的值被计算为 strlen(newStr) * sizeof(wchar_t),也就是 18 个字节。这个值假设了 newStrW 数组中有 9 个宽字符,而实际上它包含了 10 个宽字符。

因此,UpdateResourceW 函数仅写入了 newStrW 数组中的前两个字节,即字符 "1",因为它们是存储在 newStrW 数组的前两个位置上。

要解决这个问题,可以使用 wcslen 函数计算 newStrW 数组中的宽字符数,然后将它乘以 sizeof(wchar_t),计算出正确的 dataSize 值,如下所示:

size_t dataSize = wcslen(newStrW) * sizeof(wchar_t);

这将确保 dataSize 的值正确反映了 newStrW 数组中实际存储的数据量,从而保证所有数据都被写入到资源中。

解决了。。。

    const std::string jsonContent = R"(abcdefg)";
    const char* jsonBuffer = jsonContent.c_str();
    const std::streamsize len = jsonContent.length();
```c++


```

朋友你好,以下是我把你的问题和相关观点都看了一遍分析出来的,望采纳谢谢啦
首先我理解的你代码的逻辑
使用宏 MAKEINTRESOURCE(135) 定义了一个指向整数资源 ID 的 LPCWSTR 类型指针。这个整数即为资源类型,本例中为 135。

同理,使用 LPCWSTR lpName = L"CPPFILEACCOUNTJSON" 定义指向资源名称的字符串指针。

调用 BeginUpdateResourceW 函数开始更新资源。此函数接受一个包含资源的可执行文件路径,以及一个布尔值,指示是否将资源写入当前进程的内存中。本例中使用 FALSE 表示不将资源写入当前进程的内存中。

将需要添加到资源中的数据从 char 类型转换为 wchar_t 类型,并将其保存在 newStrW 数组中。然后计算出需要添加的资源数据的大小。

使用 UpdateResourceW 函数将资源添加到可执行文件中。该函数接受句柄 hUpdate,表示要更新资源的可执行文件;lpName,表示新资源的名称;lpType,表示新资源的类型;0,表示资源的标记;newStrW,表示资源数据的指针;dataSize,表示资源数据的大小。

如果 UpdateResourceW 函数执行失败,则会调用 MessageBoxW 函数显示错误消息。

最后,使用 EndUpdateResourceW 函数结束资源更新。如果函数执行失败,则使用 GetLastError 函数获取错误代码,并使用 FormatMessageW 函数获取详细的错误描述。

在代码的最后,使用 system("pause") 以及 cout 和 return 语句输出一些信息和退出程序。

然后我发现修改了这段后,运行通过了欧

 const std::string jsonContent = R"(abcdefg)";
    const char* jsonBuffer = jsonContent.c_str();
    const std::streamsize len = jsonContent.length();

不知道

不知道你这个问题是否已经解决, 如果还没有解决的话:

如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^

回答引用ChatGPT:
在代码中,您使用了sizeof(newStr)来计算新字符串的大小,这是错误的。因为sizeof操作符返回的是数组的大小,而不是字符串的长度。数组的大小包括了最后一个元素的空间,即使它是一个空字符。这可能导致您的字符串被截断,并且只有第一个字符被写入到资源中。

为了获取字符串的长度,您应该使用strlen函数。它返回字符串的长度,不包括最后一个空字符。您还应该在新字符串中添加一个空字符,以确保它以正确的方式终止。

下面是修正后的代码:

int main()
{
    const LPCWSTR lpType = MAKEINTRESOURCE(135);
    const LPCWSTR lpName = L"CPPFILEACCOUNTJSON";

    wchar_t exePath[] = L"I:\\CPP\\project\\test\\bin\\test.exe";
    LPWSTR lpExePath = exePath;
    HANDLE hUpdate = BeginUpdateResourceW(exePath, FALSE);
    if (hUpdate == NULL) {
        MessageBoxW(0, L"BeginUpdateResource 失败。", 0, MB_OK | MB_ICONERROR);
        return 1;
    }

    char newStr[] = "123456789";
    int newStrLen = strlen(newStr);
    std::vector<wchar_t> newStrW(newStrLen + 1);
    if (!MultiByteToWideChar(CP_UTF8, 0, newStr, newStrLen, &newStrW[0], newStrLen)) {
        MessageBoxW(0, L"MultiByteToWideChar 失败。", 0, MB_OK | MB_ICONERROR);
        return 1;
    }
    newStrW[newStrLen] = L'\0'; // add null terminator

    size_t dataSize = (newStrLen + 1) * sizeof(wchar_t); // add one for null terminator
    if (!UpdateResourceW(hUpdate, lpType, lpName, 0, &newStrW[0], dataSize)) {
        MessageBoxW(0, L"UpdateResource 失败。", 0, MB_OK | MB_ICONERROR);
        return 1;
    }

    if (!EndUpdateResourceW(hUpdate, FALSE)) {
        DWORD errCode = GetLastError();
        LPWSTR errBuffer = nullptr;
        FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
            nullptr, errCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&errBuffer, 0, nullptr);
        MessageBoxW(nullptr, errBuffer, L"错误", MB_OK | MB_ICONERROR);
        LocalFree(errBuffer);
        return 1;
    }

    MessageBoxW(0, L"资源更新成功。", 0, MB_OK);
    return 0;
}

这个代码中,我们使用strlen函数来获取新字符串的长度。我们还使用了一个std::vector对象来存储新字符串的宽字符表示,并在新字符串的末尾添加了一个空字符。最后,我们使用正确的顺序调用了UpdateResourceW函数,并在结束时关闭了资源更新句柄。

希望这个修改后的代码可以解决您的问题!