1

我正在遵循MSDN 中关于如何列出目录中文件的指南(我正在使用当前目录)。就我而言,我需要将信息放入数据包的消息部分(大小为 1016 的字符数组)以将其发送给客户端。当我在客户端和服务器上打印 packet.message 时,只显示文件名的第一个字符。怎么了?这是相关代码部分的片段:

WIN32_FIND_DATA f;
HANDLE h = FindFirstFile(TEXT("./*.*"), &f);
string file;
int size_needed;
do
{
    sprintf(packet.message,"%s", &f.cFileName);
    //Send packet
} while(FindNextFile(h, &f));
4

3 回答 3

5

这通常是由于宽字符串被错误地视为 ASCII 字符串造成的。该构建针对 UNICODE 并cFileName包含一个宽字符串,但sprintf()假设它是一个 ASCII 字符串。

FindFirstFile()将被映射到FindFirstFileA()FindFirstFileW()取决于构建是否以 UNICODE 为目标。

一种解决方案是显式使用FindFirstFileA()ASCII 字符串。

请注意,在&中不需要sprintf()

sprintf(packet.message, "%s", f.cFileName);

由于应用程序正在使用超出其控制范围的字符串(即文件名),我建议使用更安全_snprintf()的方法来避免缓冲区溢出:

/* From your comment on the question 'packet.message' is a 'char[1016]'
   so 'sizeof()' will function correctly. */
if (_snprintf(packet.message, sizeof(packet.message), "%s", f.cFileName) > 0)
{
}
于 2012-11-19T09:05:04.593 回答
4

您使用的是 Unicode 版本的 FindFirstFile,几乎可以保证,调用窄版本或更改打印的格式说明符。我个人会做前者:

WIN32_FIND_DATAA f;
HANDLE h = FindFirstFileA("./*.*", &f);
string file;
int size_needed;
do
{
    sprintf(packet.message,"%s", f.cFileName);
    //Send packet
} while(FindNextFileA(h, &f));
FindClose(h);

或者,您可以使用 MBCS 或常规字符进行编译。

于 2012-11-19T09:04:00.170 回答
2

正如其他人所提到的,您正在调用 Unicode 版本FindFirstFile()并将 Unicode 数据传递给 Ansisprintf()函数。说明%s符需要 Ansi 输入。您有几种选择来解决代码中的问题:

  1. 继续使用sprintf(),但将%s说明符更改为,%ls以便在写入消息缓冲区时接受 Unicode 输入并将其转换为 Ansi:

    sprintf(packet.message, "%ls", f.cFileName);
    

    但是,这并不理想,因为它将使用本地机器的 Ansi 编码,这可能与接收机器使用的 Ansi 编码不同。

  2. 将您的消息缓冲区更改为使用TCHAR而不是char,然后切换到其中一个wsprintf()_stprintf()代替sprintf()。就像FindFirstFile(),它们将匹配TCHARTEXT()使用的任何字符格式:

    TCHAR message[1016];
    wsprintf(packet.message, TEXT("%s"), f.cFileName);
    

    或者:

    #include <tchar.h>
    
    _TCHAR message[1016];
    _stprintf(packet.message, _T("%s"), f.cFileName);
    
  3. 如果您必须使用char缓冲区,那么您应该从 API 接受 Unicode 数据并将其转换为 UTF-8 进行传输,然后接收方可以将其转换回 Unicode 并根据需要使用它。

    WIN32_FIND_DATAW f;
    HANDLE h = FindFirstFileW(L"./*.*", &f);
    if (h)
    {
        do
        {
            WideCharToMultiByte(CP_UTF8, 0, f.cFileName, lstrlenW(f.cFileName), packet.message, sizeof(packet.message), NULL, NULL);
           //Send packet
        } while(FindNextFile(h, &f));
        FindClose(h);
    }
    
于 2012-11-19T19:44:11.280 回答