【问题标题】:Win32 - Appending text to an Edit ControlWin32 - 将文本附加到编辑控件
【发布时间】:2013-05-02 01:32:44
【问题描述】:

试图将文本附加到对话框内的编辑控件。我无法让 _tcscat_s 正确附加。它崩溃并说明缓冲区太小或以空字符结尾的字符串。

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
    return DialogBox( hInstance, MAKEINTRESOURCE( IDD_MAIN ), NULL, DlgProc );
}

BOOL CALLBACK DlgProc( HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam ) 
{
    switch( Message )
    {
        case WM_INITDIALOG:
            OpenAndReadFile( hwnd );
            return TRUE;
        case WM_COMMAND:
            switch( LOWORD( wParam ) )
            {
                case IDSTART:
                    EndDialog( hwnd, IDSTART );
                    break;
                case IDQUIT:
                    EndDialog( hwnd, IDQUIT );
                    break;
            }
            break;
        case WM_CLOSE:
            EndDialog( hwnd, 0 );
            break;
        default:
            return FALSE;
    }
    return TRUE;
}

BOOL OpenAndReadFile( const HWND &hwnd ) 
{   
    // Open the file

    HANDLE hFile;
    hFile = CreateFile( TEXT( "sites.txt" ),    // file to open
                        GENERIC_READ,           // open for reading
                        FILE_SHARE_READ,        // share for reading
                        NULL,                   // default security
                        OPEN_EXISTING,          // existing file only
                        FILE_ATTRIBUTE_NORMAL,  // normal file
                        NULL );                 // no attr. template

    if ( hFile == INVALID_HANDLE_VALUE )
    {
        SetDlgItemText( hwnd, IDC_OUTPUT, TEXT( "Error: File could not be opened\r\n" ) );
        return FALSE;
    }
    else
        SetDlgItemText( hwnd, IDC_OUTPUT, TEXT( "sites.txt opened\r\n" ) );

    AppendText( hwnd, TEXT("TEXT") );

    // Read data from file

    const DWORD BUFFERSIZE = GetFileSize( hFile, NULL );
    char *ReadBuffer = new char [BUFFERSIZE]();
    DWORD dwBytesRead = 0;

    // read one character less than the buffer size to save room for the
    // terminate NULL character.
    //if ( FALSE == ReadFile( hFile, ReadBuffer, BUFFERSIZE - 1, &dwBytesRead, NULL ) )
    {

    }

    return TRUE;
}

void AppendText( const HWND &hwnd, TCHAR *newText )
{
    // get size to determine buffer size
    int outLength = GetWindowTextLength( GetDlgItem( hwnd, IDC_OUTPUT ) );

    // create buffer to hold current text in edit control
    TCHAR * buf = ( TCHAR * ) GlobalAlloc( GPTR, outLength + 1 );

    // get existing text from edit control and put into buffer
    GetDlgItemText( hwnd, IDC_OUTPUT, buf, outLength + 1 );

    // append the newText to the buffer
    _tcscat_s( buf, outLength + 1, newText );

    // Set the text in the dialog
    SetDlgItemText( hwnd, IDC_OUTPUT, buf );
}

【问题讨论】:

  • 我一直假设 _tcscat_s 在进行连接时会添加必要的空间。这是错的吗?如果是这样,我是否需要在 GlobalAlloc 期间为 newText 腾出额外的空间?
  • 为什么要使用它?要使用相同的算法,只需将文本加载到std::string,附加到它,然后保存回来。至少在 C++11 中,数据保证是连续的。如果不使用 C++11,std::vector 几乎同样可以加载文本。或者(可能更好),使用this technique。没有为它管理内存。不用担心追加。同样易于使用。
  • @ShrimpCrackers: _tcscat_s() 如果附加文本超出缓冲区的范围,则不会增加缓冲区。 _tcscat_s() 有一个参数来指定缓冲区大小,因此如果它变得太长,它将截断连接的文本。因此,您需要先将缓冲区分配到所需的最终大小,然后再开始将文本放入其中。

标签: c++ c winapi windows-controls


【解决方案1】:

GetWindowTextLength() 返回文本中TCHAR 元素的数量,但GlobalAlloc() 需要一个字节数。如果您正在为 Unicode 编译,TCHAR 是 2 个字节,而不是 1 个字节,但您没有考虑到这一点。您也没有分配足够大的缓冲区来容纳现有文本和要附加的新文本。您还泄漏了您分配的内存。

试试这个:

void AppendText( const HWND &hwnd, TCHAR *newText )
{
    // get edit control from dialog
    HWND hwndOutput = GetDlgItem( hwnd, IDC_OUTPUT );

    // get new length to determine buffer size
    int outLength = GetWindowTextLength( hwndOutput ) + lstrlen(newText) + 1;

    // create buffer to hold current and new text
    TCHAR * buf = ( TCHAR * ) GlobalAlloc( GPTR, outLength * sizeof(TCHAR) );
    if (!buf) return;

    // get existing text from edit control and put into buffer
    GetWindowText( hwndOutput, buf, outLength );

    // append the newText to the buffer
    _tcscat_s( buf, outLength, newText );

    // Set the text in the edit control
    SetWindowText( hwndOutput, buf );

    // free the buffer
    GlobalFree( buf );
}

或者:

#include <vector>

void AppendText( const HWND &hwnd, TCHAR *newText )
{
    // get edit control from dialog
    HWND hwndOutput = GetDlgItem( hwnd, IDC_OUTPUT );

    // get new length to determine buffer size
    int outLength = GetWindowTextLength( hwndOutput ) + lstrlen(newText) + 1;

    // create buffer to hold current and new text
    std::vector<TCHAR> buf( outLength );
    TCHAR *pbuf = &buf[0];

    // get existing text from edit control and put into buffer
    GetWindowText( hwndOutput, pbuf, outLength );

    // append the newText to the buffer
    _tcscat_s( pbuf, outLength, newText );

    // Set the text in the edit control
    SetWindowText( hwndOutput, pbuf );
}

话虽如此,将窗口的当前文本放入内存,附加到它,然后替换窗口的文本是一种将文本附加到编辑控件的非常低效的方法。请改用EM_REPLACESEL 消息:

void AppendText( const HWND &hwnd, TCHAR *newText )
{
    // get edit control from dialog
    HWND hwndOutput = GetDlgItem( hwnd, IDC_OUTPUT );

    // get the current selection
    DWORD StartPos, EndPos;
    SendMessage( hwndOutput, EM_GETSEL, reinterpret_cast<WPARAM>(&StartPos), reinterpret_cast<WPARAM>(&EndPos) );

    // move the caret to the end of the text
    int outLength = GetWindowTextLength( hwndOutput );
    SendMessage( hwndOutput, EM_SETSEL, outLength, outLength );

    // insert the text at the new caret position
    SendMessage( hwndOutput, EM_REPLACESEL, TRUE, reinterpret_cast<LPARAM>(newText) );

    // restore the previous selection
    SendMessage( hwndOutput, EM_SETSEL, StartPos, EndPos );
}

【讨论】:

  • 效率低下,只会增加更多搞砸的可能性,这在您指出的所有问题中都很明显。
  • 谢谢,雷米。效果很好。作为 win32 api 的新手,我对最后一个示例有三个问题。 (1) 是否需要 hwndOutput 赋值?我以为我将句柄作为函数参数传递给对话框控件。 DlgProc() 函数中的 hwnd 是其他东西的句柄吗? (2) 为什么要在 WPARAM 和 LPARAM 上使用 reinterpret_cast? (3) 为什么outLength必须同时发送给WPARAM和LPARAM参数?
  • 1) EM_... 消息直接发送到编辑控件,因此一次抓取它的 HWND 并多次使用它是有意义的。 DlgProc() HWND 是父对话框。 2) reinterpret_cast 是 C++ 的类型安全、编译时验证的方式,用于将指针类型转换为整数,反之亦然(除其他外)。 3)read the documentation。 4) OpenAndReadFile() 有内存泄漏。
【解决方案2】:

http://support.microsoft.com/kb/109550

是你的答案:

   string buffer = "append this!"
   HWND hEdit = GetDlgItem (hDlg, ID_EDIT);
   int index = GetWindowTextLength (hEdit);
   SetFocus (hEdit); // set focus
   SendMessageA(hEdit, EM_SETSEL, (WPARAM)index, (LPARAM)index); // set selection - end of text
   SendMessageA(hEdit, EM_REPLACESEL, 0, (LPARAM)buffer.c_str()); // append!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-15
    • 2011-03-27
    • 1970-01-01
    • 2011-04-14
    • 1970-01-01
    • 2010-12-14
    • 1970-01-01
    相关资源
    最近更新 更多