简体   繁体   English

C ++ MFC附加文字以编辑控件会使程序崩溃

[英]C++ MFC Appeding text to edit control crashes the program

这是发生异常时在运行时对程序的反汇编 Class in test.h: test.h中的类:

class CHelixV3Dlg : public CDialogEx
{
   DECLARE_DYNAMIC(CHelixV3Dlg);
friend class CHelixV3DlgAutoProxy;

// Construction
public:
   CHelixV3Dlg(CWnd* pParent = NULL);   // standard constructor

// Dialog Data
   enum { IDD = IDD_HELIXV3_DIALOG };


// Implementation
protected:
   CHelixV3DlgAutoProxy* m_pAutoProxy;
   HICON m_hIcon;
public:
   DWORD WINAPI loop(LPVOID); //thread identifier
   void AppendText(CEdit &edit, LPCTSTR pszText);
};

I have a method defined like so, which is supposed to print a string to editbox, which normally works (in test.cpp): 我有一个这样定义的方法,该方法应该将一个字符串打印到editbox,通常可以正常工作(在test.cpp中):

void TestDlg::AppendText(CEdit &edit, LPCWSTR pszText)
{
   // get the initial text length
   int nLength = edit.GetWindowTextLength();
   // put the selection at the end of text
   edit.SetSel(nLength, nLength);
   // replace the selection
   edit.ReplaceSel(pszText);
 }

Then here is my thread, which listens for key presses(test.cpp) 这是我的线程,它监听按键(test.cpp)

 DWORD WINAPI TestDlg::KeyThread(LPVOID PARAMS)
 {
    TestDlg* Testdlg;
    while (1)
    {
       Sleep(1);
       if (GetAsyncKeyState(VK_F1) & 1)
       {
           Enabled = !Enabled;
           if (Enabled) {
            CEdit* log = (CEdit*)GetDlgItem(IDC_EDIT1);
            log->AppendText(*log, "test"); //causes a crash
       }
    }
   return 0;
  }

Dialog initialization, where the "loop" thread is created: 对话框初始化,其中创建了“循环”线程:

BOOL CHelixV3Dlg::OnInitDialog()
{
TestDlg* Testdlg;
CDialogEx::OnInitDialog();

//creates the thread->
CreateThread(NULL, NULL, &Testdlg->KeyThread, NULL, NULL, NULL);

/* IGNORE THIS */
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
    BOOL bNameValid;
    CString strAboutMenu;
    bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
    ASSERT(bNameValid);
    if (!strAboutMenu.IsEmpty())
    {
        pSysMenu->AppendMenu(MF_SEPARATOR);
        pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
    }
}

// Set the icon for this dialog.  The framework does this automatically
//  when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE);         // Set big icon
SetIcon(m_hIcon, FALSE);        // Set small icon

// TODO: Add extra initialization here

return TRUE;  // return TRUE  unless you set the focus to a control
}

So, the program compiles, but when it's running and i press F1, it crashes. 因此,该程序可以编译,但是当它运行并按F1时,它会崩溃。

You have multiple problems in your code. 您的代码中有多个问题。 The uninitialized Testdlg pointer has been already pointed by others. 其他人已经指出了未初始化的Testdlg指针。

Here is another one: 这是另一个:

log->AppendText(*log, "test");

I'm sure you want to say: 我确定你想说:

Testdlg->AppendText(*log, "test");

However, that won't work, because this is on a worker thread. 但是,那是行不通的,因为它在工作线程上。 What you have to do is post/send a message from the worker thread to the queue of the main thread (that created your test dialog window). 您要做的是将消息从工作线程发布/发送到主线程(创建测试对话框窗口)的队列。 In the handler for the message, you can actually call your AppendText method. 在消息的处理程序中,您实际上可以调用AppendText方法。

Here is how you do that ( notice that I've typed all this in the browser so it may contain errors ): 这是您的操作方法(请注意,我已经在浏览器中输入了所有这些内容,因此可能包含错误 ):

In the header (TestDlg.h) declare a handler: 在标头(TestDlg.h)中声明一个处理程序:

LRESULT OnMessageFromWorker(WPARAM wParam, LPARAM lPARAM);

In the source file (TestDlg.cpp): 在源文件(TestDlg.cpp)中:

Define your message: 定义您的消息:

#define MY_WORKER_THREAD_MSG   WM_APP + 123

Add an entry for the message in the message map 在消息映射中为消息添加条目

ON_MESSAGE(MY_WORKER_THREAD_MSG, &TestDlg::OnMessageFromWorker)

Send the message from the worker thread: 从辅助线程发送消息:

 DWORD WINAPI TestDlg::KeyThread(LPVOID PARAMS)
 {
    HWND dlgWnd = (HWND)PARAMS;
    while (1)
    {
       Sleep(1);
       if (GetAsyncKeyState(VK_F1) & 1)
       {
           Enabled = !Enabled;
           if (Enabled) 
           {
               CString* msg = new CString("test");
               PostMessage(dlgWnd, 0, reinterpret_cast<LPARAM>(msg));
           }
       }
    }
   return 0;
  }

Notice that in this example you need to pass the HWND of the dialog window, not the this pointer to the thread function. 请注意,在此示例中,您需要传递对话框窗口的HWND ,而不是this指针传递给线程函数。 In other words: 换一种说法:

CreateThread(nullptr, nullptr, &Testdlg->KeyThread, this->GetSafeHwnd(), nullptr, nullptr);

Handle the message: 处理消息:

LRESULT TestDlg::OnMessageFromWorker(WPARAM wParam, LPARAM lPARAM)
{
   CString* msg = reinterpret_cast<CString*>(lPARAM);
   CEdit* log = (CEdit*)TestDlg->GetDlgItem(IDC_EDIT1);
   AppendText(*log, *msg);
   delete msg; // you must delete the object

   return 0;
}

First you should define TestDlg::Thread as a static member function. 首先,您应该将TestDlg :: Thread定义为静态成员函数。 When you call CreateThread, the fourth argument should be 'this'. 当您调用CreateThread时,第四个参数应为“ this”。

In your header file (TestDlg.h or whatever): 在头文件(TestDlg.h或其他文件)中:

static DWORD WINAPI TestDlg::KeyThread(LPVOID PARAMS);

In OnInitDialog: 在OnInitDialog中:

//creates the thread-> //创建线程->

CreateThread(NULL, NULL, &Testdlg->KeyThread, this, NULL, NULL);


DWORD WINAPI TestDlg::KeyThread(LPVOID PARAMS)
 {
    TestDlg* Testdlg = (TestDlg*) PARAMS;
    while (1)
    {
       Sleep(1);
       if (GetAsyncKeyState(VK_F1) & 1)
       {
           Enabled = !Enabled;
           if (Enabled) {
            CEdit* log = (CEdit*)TestDlg->GetDlgItem(IDC_EDIT1);
            log->AppendText(*log, "test"); //causes a crash
       }
    }
   return 0;
  }

It still may not work because the CWnd pointers may only be valid in the main thread. 由于CWnd指针可能仅在主线程中有效,因此它可能仍然无法工作。 YMMV 因人而异

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM