C++ 在缓冲区溢出时自动截断和null终止字符串缓冲区

C++ 在缓冲区溢出时自动截断和null终止字符串缓冲区,c++,winapi,truncate,buffer-overflow,C++,Winapi,Truncate,Buffer Overflow,我有以下代码,可以从指定父窗口的所有子窗口加载文本。它运行良好,但有时,有一些父窗口(例如打开了记事本,使用了很长的C++源文件),这些文件有大量的文本并导致缓冲区溢出。 BOOL CALLBACK EnumChildProc(__in HWND hWnd, __in LPARAM lParam) { LRESULT TEXT_LENGTH = NULL; WCHAR szText[32767]; LPWSTR szWindowText; UINT nBuffe

我有以下代码,可以从指定父窗口的所有子窗口加载文本。它运行良好,但有时,有一些父窗口(例如打开了记事本,使用了很长的C++源文件),这些文件有大量的文本并导致缓冲区溢出。
BOOL CALLBACK EnumChildProc(__in HWND hWnd, __in LPARAM lParam) {

    LRESULT TEXT_LENGTH = NULL;
    WCHAR szText[32767];
    LPWSTR szWindowText;
    UINT nBuffer = NULL, nText = NULL;

    szWindowText = reinterpret_cast<LPWSTR>(lParam); szText[0] = L'\0';
    nBuffer = (UINT)wcslen(szWindowText);
    TEXT_LENGTH = SendMessage(hWnd, WM_GETTEXTLENGTH, NULL, NULL);

    if (TEXT_LENGTH > NULL)
    {
        SendMessage(hWnd, WM_GETTEXT, (WPARAM)32767, reinterpret_cast<LPARAM>(&szText));
        szText[TEXT_LENGTH] = L'\n'; szText[TEXT_LENGTH + 1] = L'\0';

        while ((nBuffer < 32766) && (szText[nText] != L'\0'))
        { szWindowText[nBuffer++] = szText[nText++]; }

        szWindowText[nBuffer] = L'\0';
    }
    return TRUE;
}
BOOL回调EnumChildProc(\uuu在HWND-HWND中,\uu在LPARAM中){
LRESULT TEXT_LENGTH=NULL;
WCHAR szText[32767];
LPWSTR文本;
UINT nBuffer=NULL,nText=NULL;
szWindowText=reinterpret_cast(LPRAM);szText[0]=L'\0';
nBuffer=(UINT)wcslen(szWindowText);
TEXT_LENGTH=SendMessage(hWnd,WM_GETTEXTLENGTH,NULL,NULL);
如果(文本长度>NULL)
{
SendMessage(hWnd,WM_GETTEXT,(WPARAM)32767,reinterpret_cast(&szText));
szText[TEXT_LENGTH]=L'\n';szText[TEXT_LENGTH+1]=L'\0';
而((nBuffer<32766)和&(szText[nText]!=L'\0'))
{szWindowText[nBuffer++]=szText[nText++];}
szWindowText[nBuffer]=L'\0';
}
返回TRUE;
}
SendMessage(hWnd,WM_GETTEXT,(WPARAM)32767,reinterpret_cast(&szText))有时会导致缓冲区溢出和我的应用程序崩溃

我知道如何检测这种溢出,比如
if(TEXT_LENGTH>32767)
,但我无法动态增加缓冲区的大小
szText

正如问题标题所提到的,我不想增加其大小,我只想将返回文本截断并空终止为最大缓冲区大小
32767
(如果
text\u LENGTH
超过
32767
),并将其分配给
szWindowText
,以用于其他目的

非常感谢您的帮助。

有几件事:

  • 最好将缓冲区动态分配到文本长度。(“\0”的+1)
  • 在WM_GETTEXT中删除szText的&运算符,您只需要包含的地址,而不是指针的地址
  • 当您显式使用字符时,请使用SendMessageA,否则VisualStudio将默认使用带有SendMessageW的wchar\u t。SendMessage是一个宏,可根据项目设置扩展为wchar\u t或char。或者将TCHAR类型与SendMessage一起使用,也可以将其扩展为正确的类型

  • DWORD l=SendMessage(hWnd,WM_GETTEXTLENGTH,NULL,NULL);
    如果(l>0){
    TCHAR*szText=新的TCHAR[l+1];
    SendMessage(hWnd,WM_GETTEXT,(WPARAM)l+1,reinterpret_cast(szText));
    //使用szText
    删除文本;
    }
    
    基本上,您需要为
    \n
    腾出空间,无论插入什么,方法是在
    WM\u GETTEXT
    调用中使用szText-1的
    sizeof
    而不是32767

    注意:如果您必须使用Simonyi符号,请不要在不适用的地方使用它。关于
    szText
    ,没有以null结尾的内容,您仅将其用于
    WM_GETTEXT
    发送消息(hWnd,WM_GETTEXT,(WPARAM)32767,reinterpret_cast(&szText))不应导致缓冲区溢出,因为提供了正确大小的缓冲区。实际上,根本不需要这个临时缓冲区


    真正的问题是,在不知道目标缓冲区大小的情况下,将字符追加到作为
    lParam
    提供的指针中。您应该提供目标缓冲区大小。

    不要将整数与
    NULL
    进行比较,也不要初始化整数
    NULL
    应该是空指针。即使定义为
    0
    使用
    NULL
    在语义上也是错误的,并且会误导阅读您代码的人。
    WCHAR szText[32767]
    !!!知道长度后,为什么不使用std::wstring并动态调整其大小?
    SendMessage(hWnd,WM_GETTEXT,(WPARAM)32767,reinterpret_cast(&szText))不应导致缓冲区溢出,因为提供了正确大小的缓冲区。实际上,根本不需要这个临时缓冲区。您真正的问题是,您正在写入作为
    lParam
    提供的指针,而不知道目标缓冲区的大小。@VTT是的,您可以使用
    &some\u string\u object[0]
    获取指向字符串中第一个元素的指针(一旦大小正确调整)。@Blueeyes789我不知道。那么呢?这个答案确实会影响OP提到的缓冲区溢出问题。它还建议做错误的事情:使用chars或TCHAR,而不是显式使用宽chars和W版本的函数。并且发布的代码片段包含错误:
    WPARAM
    SendMessage
    应该包含目标缓冲区容量,即应该是
    l+1
    ,并且还应该检查第二次
    SendMessage
    调用返回的值,以确定实际复制到缓冲区的字符数(虽然不太可能与
    l
    )不同。好的,修复了缓冲区容量问题。但是,我不同意“使用宽字符和W版本”的观点。在我看来,您应该始终使用TCHAR、LPTSTR等以及win32 API函数的宏版本(因此不是“W”或“A”)因此,程序将适应项目设置中配置的任何内容
    DWORD l = SendMessage(hWnd, WM_GETTEXTLENGTH, NULL, NULL);
    
    if (l > 0){
       TCHAR *szText = new TCHAR[l + 1];
       SendMessage(hWnd, WM_GETTEXT, (WPARAM)l + 1, reinterpret_cast<LPARAM>(szText));
    
      // use szText
    
       delete[] szText;
    }