WideCharToMultiByte 随机失败并出现错误 122/ERROR_INSUFFICIENT_BUFFER

WideCharToMultiByte fails randomly with error 122/ERROR_INSUFFICIENT_BUFFER

我用 C 语言创建了一个小应用程序,它使用凯撒密码对字符串进行加密和解密。字符串 (unicode) 解密后,使用 WideCharToMultiByte 将其转换为 UTF8。它在大约 90% 的时间内工作,但有时 WideCharToMultiByte 似乎失败并且 GetLastError 函数打印 122,这意味着 ERROR_INSUFFICIENT_BUFFER.

我将 unicode 字符串转换为 UTF8 的函数如下所示:

LPSTR convert(LPWSTR wideStringToDecryptAndConvertUTF) {

   LPWSTR res = shift(wideStringToDecryptAndConvertUTF, -6); //Decrypting the string by shifting -6 letters.

   MessageBoxW(NULL, res, L"Decrypted output", MB_OK); //Check if the string was successfully decrypted - judging by the output of the messagebox this is always the case, the decrypted string looks as expected.

   LPSTR retVal = 0;
   ULONG cb = 0, cch = (ULONG)strl(res);
   cb = WideCharToMultiByte(CP_UTF8, 0, res, cch * sizeof(WCHAR), retVal, cb, 0, 0);
   retVal = GlobalAlloc(GMEM_FIXED, cb);
   WideCharToMultiByte(CP_UTF8, 0, res, cch * sizeof(WCHAR), retVal, cb, 0, 0);

   if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {            //Check for debugging purposes. At random times (even with the same string) this specific error occurs.
       MessageBoxW(NULL, L"Error", L"Debug", MB_OK);
   }
   GlobalFree(res);
   return retVal;
}

我对 decrypt/encrypt 字符串的转换函数如下所示(在本例中它被解密):

LPWSTR shift(LPWSTR shift, int param) {

    LPWSTR allc = L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz[]<>()[]";
    LPWSTR encrypted = (LPWSTR)GlobalAlloc(GMEM_FIXED, strl(shift) * sizeof(WCHAR) + 1);
    int r = 0;
    if (encrypted != NULL) {
        for (size_t i = 0; i < strl(shift); i++) {
            r++;
            if (strchr42a((LPWSTR)allc, shift[i]) != NULL) {

                LPWSTR e = strchr42a((LPWSTR)allc, shift[i]);
                int index = (int)(e - allc);
                encrypted[i] = allc[index + param];

            }
            else {
                encrypted[i] = shift[i];
            }
        }
    }

    if (encrypted != NULL) {
        encrypted[r] = 0;
    }
    return encrypted;

}

虽然这很简单,但这里是上面两个函数中使用的strl函数:

size_t strl(LPWSTR s) {
    size_t i = 0;
    while (s && *s != '[=13=]') {
        s++;
        i++;
    }
    return i;
}

我尝试加密的所有字符串都使用相同的程序加密,并且只包含字母。 我知道加密本身有局限性(例如加密时不能移动超过 8 个字母),但这不是我的问题。 我不明白为什么 WideCharToMultiByte 函数在我的情况下似乎工作不稳定。任何建议表示赞赏!

你打错了WideCharToMultiByte。第 4 个参数是 字符数 ,而不是 字节数 。您也没有以 null 终止 retVal 缓冲区,并且根本没有进行任何错误处理。

此外,shift() 正在为其 encrypted 缓冲区计算错误的字节大小。更糟糕的是,如果输入 shift 字符串包含任何字符 A..F,找到的索引被 -6 偏移将超出 allc.

的范围

试试像这样的东西:

LPCWSTR strchr42a(LPCWSTR str, int ch)
{
    do {
        if (*str == ch) return str;
    } while (*str++);
    return NULL;
}

LPWSTR shift(LPCWSTR shift, int param) {

    LPCWSTR allc = L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz[]<>()[]";
    ULONG shift_len = strl(shift);

    LPWSTR encrypted = (LPWSTR) GlobalAlloc(GMEM_FIXED, (shift_len + 1) * sizeof(WCHAR));
    if (!encrypted) return NULL;

    int r = 0;
    for (size_t i = 0; i < shift_len; ++i) {
        ++r;
        LPCWSTR e = strchr42a(allc, shift[i]);
        if (e != NULL) {
            int index = (int)(e - allc) + param;
            if (index < 0) {
                // OUT OF BOUNDS! Need to wrap the index, or fail the function...
            }
            encrypted[i] = allc[index];
        }
        else {
            encrypted[i] = shift[i];
        }
    }

    encrypted[r] = 0;
    return encrypted;
}

LPSTR convert(LPWSTR wideStringToDecryptAndConvertUTF) {

   LPWSTR res = shift(wideStringToDecryptAndConvertUTF, -6); //Decrypting the string by shifting -6 letters.
   if (!res) {
       MessageBoxW(NULL, L"Error", L"Debug", MB_OK);
       return NULL;
   }

   MessageBoxW(NULL, res, L"Decrypted output", MB_OK); //Check if the string was successfully decrypted - judging by the output of the messagebox this is always the case, the decrypted string looks as expected.

   ULONG cch = (ULONG) strl(res);
   ULONG cb = WideCharToMultiByte(CP_UTF8, 0, res, cch, retVal, 0, NULL, NULL);
   if (cb == 0) {
       DWORD errCode = GetLastError();
       MessageBoxW(NULL, L"Error", L"Debug", MB_OK);
       return NULL;
   }

   LPSTR retVal = GlobalAlloc(GMEM_FIXED, cb + 1);
   if (!retVal) {
       DWORD errCode = GetLastError();
       MessageBoxW(NULL, L"Error", L"Debug", MB_OK);
       return NULL;
   }

   WideCharToMultiByte(CP_UTF8, 0, res, cch, retVal, cb, NULL, NULL);
   retVal[cb] = 0;

   GlobalFree(res);
   return retVal;
}