使用 cURL 时 MFC 无模式对话框冻结

MFC modeless dialog freezes when using cURL

我有一个 MFC 应用程序,它尝试使用 cURL 获取页面。当 运行 应用程序时,对话框会暂时无响应。有什么办法可以解决这个问题吗?

static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp)
{
    ((std::string*)userp)->append((char*)contents, size * nmemb);
    return size * nmemb;
}
    
static std::string GetPage(const char* url)
{
    CURL *curl;
    CURLcode res;
    std::string page;
    curl = curl_easy_init();
    if (curl) {
        curl_easy_setopt(curl, CURLOPT_URL, url);
        curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &page);

        res = curl_easy_perform(curl);

        curl_easy_cleanup(curl);
    }
    return page;
}

InitInstance():

    CWinApp::InitInstance();
    CEpicDlg dlg;
    m_pMainWnd = &dlg;
    dlg.Create(IDD_MAIN);
    dlg.ShowWindow(SW_SHOW);
    GetPage("http://example.com/page");
    dlg.RunModalLoop(MLF_NOIDLEMSG);

如前所述,您必须 运行 单独的工作线程中的函数。

CreateThread + WaitForSingleObject 可能表现得像一个阻塞函数,这取决于它是如何实现的...

一种替代方法是 运行 工作线程并在 GUI 线程中继续。工作线程完成后,使用同步对象让 GUI 线程了解状态。或者使用 PostMessage 通知 GUI 线程工作线程完成。确保 url 字符串数据不会在没有同步的情况下同时在两个线程之间共享...

注意,使用CDialog::DoModal并初始化OnInitDialog中的数据。您可能还想覆盖 OnCancel 以在退出 window.

之前正确清理
#define WM_USER1 (WM_USER + 1)
DWORD WINAPI thread_proc(LPVOID ptr)
{
    //simulate a blocking function (don't put Sleep in final code)
    Sleep(2000);
    HWND hwnd = (HWND)ptr;
    if(IsWindow(hwnd)) PostMessage(hwnd, WM_USER1, 0, 0);
    return 0;
}

class CMyDialog : public CDialog
{
public:
    CMyDialog(int id, CWnd* wnd) : CDialog(id, wnd) {}
    BOOL OnInitDialog()
    {
        CDialog::OnInitDialog();
        CreateThread(nullptr, 0, thread_proc, (LPVOID)m_hWnd, 0, nullptr);
        return TRUE;
    }
    LRESULT on_wm_user1(WPARAM, LPARAM)
    {
        MessageBox(L"finished");
        return 0;
    }
    DECLARE_MESSAGE_MAP()
};

BEGIN_MESSAGE_MAP(CMyDialog, CDialog)
    ON_MESSAGE(WM_USER1, on_wm_user1)
END_MESSAGE_MAP()