C++ wxWidgets应用程序在运行文件下载功能时关闭。

huangapple go评论66阅读模式
英文:

C++ wxWidgets application closes when running file download function

问题

我正在编写一个需要下载文件并显示下载进度对话框的C++应用程序。我正在使用cURL来完成下载请求,但由于某种原因,当我通过单击安装按钮来启动下载时,应用程序立即关闭,没有错误或其他指示。以下是我目前的代码:

#include <wx/wx.h>
#include <iostream>
#include <fstream>
#include <curl/curl.h>
#include <thread>

class FileDownloader {
public:
    FileDownloader() = default;
    ~FileDownloader() = default;

    static size_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userp)
    {
        size_t totalSize = size * nmemb;
        wxThreadEvent* event = static_cast<wxThreadEvent*>(userp);
        wxString data(static_cast<const char*>(contents), wxConvUTF8, totalSize);
        event->SetString(data);
        wxQueueEvent(wxTheApp->GetTopWindow(), event);
        return totalSize;
    }

    bool DownloadFile(const std::string& url, const std::string& destination)
    {
        CURL* curl = curl_easy_init();
        if (!curl)
            return false;

        FILE* file = fopen(destination.c_str(), "wb");
        if (!file)
        {
            curl_easy_cleanup(curl);
            return false;
        }

        curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, file);

        CURLcode res = curl_easy_perform(curl);

        fclose(file);
        curl_easy_cleanup(curl);

        return res == CURLE_OK;
    }
};

class WindowsInstaller : public wxApp
{
public:
    bool OnInit() override;
};

// This defines the equivalent of main() for the current platform.
wxIMPLEMENT_APP(WindowsInstaller);

class NewFrame : public wxFrame
{
public:
   NewFrame();

private:
    void OnHello(wxCommandEvent& event);
    void OnExit(wxCommandEvent& event);
    void OnAbout(wxCommandEvent& event);
    void OnInstallButtonClick(wxCommandEvent& event);
    void OnSetButtonClick(wxCommandEvent& event);
    void OnCheckBoxClicked(wxCommandEvent& event);
    
    wxButton* install_button;
    wxButton* set_location;
    wxTextCtrl* textCtrl;
    wxCheckBox* accept_checkbox;
    wxGauge* gauge;
};

bool WindowsInstaller::OnInit()
{
    NewFrame* frame = new NewFrame();
    frame->Show();
    return true;
}

enum
{
    ID_Hello = 1,
    ID_Install_Button = 2,
    ID_Set_Location = 3,
    ID_Accept_CheckBox = 4,
    ID_UPDATE_PROGRESS = 5,
    ID_DOWNLOAD_COMPLETE = 6,
    ID_DOWNLOAD_ERROR = 7,
    ID_ENABLE_INSTALL_BUTTON = 8
};

NewFrame::NewFrame()
    : wxFrame(nullptr, wxID_ANY, "Hello World", wxDefaultPosition, wxSize(700, 500), wxDEFAULT_FRAME_STYLE & ~(wxRESIZE_BORDER | wxMAXIMIZE_BOX))
{
    // ...(其余代码保持不变)
}

void NewFrame::OnExit(wxCommandEvent& event)
{
    Close(true);
}

void NewFrame::OnAbout(wxCommandEvent& event)
{
    wxMessageBox("This is a wxWidgets Hello World example",
        "About Hello World", wxOK | wxICON_INFORMATION);
}

void NewFrame::OnHello(wxCommandEvent& event)
{
    wxLogMessage("Hello world from wxWidgets!");
}

void NewFrame::OnInstallButtonClick(wxCommandEvent& event)
{
    // ...(其余代码保持不变)
}

void NewFrame::OnSetButtonClick(wxCommandEvent& event)
{
    wxMessageBox("Button clicked!", "Button", wxOK | wxICON_INFORMATION);
}

void NewFrame::OnCheckBoxClicked(wxCommandEvent& event)
{
    if (accept_checkbox->IsChecked())
        install_button->Enable(true);
    else
        install_button->Enable(false);
}

这是调试器捕获的异常信息:

Exception thrown at 0x00007FFC285301E8 (wxbase32ud_vc_custom.dll) in WindowsInstaller.exe: 0xC0000005: Access violation writing location 0x00000080FDFDFDFD.

希望这有助于解决你的问题。如果你需要进一步的帮助,请随时提问。

英文:

I am writing a C++ app that needd to download a file and show a download progress dialog. I am using cURL to complete the doenlaod request, however, for some reason, when I initiate the download by clicking the install button, the application immediately closes with no errors or other indication. Here is what I have so far:

#include &lt;wx/wx.h&gt;

#include &lt;iostream&gt;
#include &lt;fstream&gt;
#include &lt;curl/curl.h&gt;

#include &lt;thread&gt;

class FileDownloader {
public:
    FileDownloader() = default;
    ~FileDownloader() = default;

    static size_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userp)
    {
        size_t totalSize = size * nmemb;
        wxThreadEvent* event = static_cast&lt;wxThreadEvent*&gt;(userp);
        wxString data(static_cast&lt;const char*&gt;(contents), wxConvUTF8, totalSize);
        event-&gt;SetString(data);
        wxQueueEvent(wxTheApp-&gt;GetTopWindow(), event);
        return totalSize;
    }

    bool DownloadFile(const std::string&amp; url, const std::string&amp; destination)
    {
        CURL* curl = curl_easy_init();
        if (!curl)
            return false;

        FILE* file = fopen(destination.c_str(), &quot;wb&quot;);
        if (!file)
        {
            curl_easy_cleanup(curl);
            return false;
        }

        curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, file);

        CURLcode res = curl_easy_perform(curl);

        fclose(file);
        curl_easy_cleanup(curl);

        return res == CURLE_OK;
    }
};

class WindowsInstaller : public wxApp
{
public:
    bool OnInit() override;
};

// This defines the equivalent of main() for the current platform.
wxIMPLEMENT_APP(WindowsInstaller);


class NewFrame : public wxFrame
{
public:
   NewFrame();

private:
    void OnHello(wxCommandEvent&amp; event);
    void OnExit(wxCommandEvent&amp; event);
    void OnAbout(wxCommandEvent&amp; event);
    void OnInstallButtonClick(wxCommandEvent&amp; event);
    void OnSetButtonClick(wxCommandEvent&amp; event);
    void OnCheckBoxClicked(wxCommandEvent&amp; event);
    


    wxButton* install_button;
    wxButton* set_location;

    wxTextCtrl* textCtrl;

    wxCheckBox* accept_checkbox;

    wxGauge* gauge;
};



bool WindowsInstaller::OnInit()
{
    NewFrame* frame = new NewFrame();
    frame-&gt;Show();
    return true;
}


enum
{
    ID_Hello = 1,
    ID_Install_Button = 2,
    ID_Set_Location = 3,
    ID_Accept_CheckBox = 4,
    ID_UPDATE_PROGRESS = 5,
    ID_DOWNLOAD_COMPLETE = 6,
    ID_DOWNLOAD_ERROR = 7,
    ID_ENABLE_INSTALL_BUTTON = 8

};


NewFrame::NewFrame()
    : wxFrame(nullptr, wxID_ANY, &quot;Hello World&quot;, wxDefaultPosition, wxSize(700, 500), wxDEFAULT_FRAME_STYLE &amp; ~(wxRESIZE_BORDER | wxMAXIMIZE_BOX))

{
    wxMenu* menuFile = new wxMenu;
    menuFile-&gt;Append(ID_Hello, &quot;&amp;Hello...\tCtrl+H&quot;,
        &quot;Help string shown in status bar for this menu item&quot;);
    menuFile-&gt;AppendSeparator();
    menuFile-&gt;Append(wxID_EXIT);

    wxMenu* menuHelp = new wxMenu;
    menuHelp-&gt;Append(wxID_ABOUT);

    wxMenuBar* menuBar = new wxMenuBar;
    menuBar-&gt;Append(menuFile, &quot;&amp;File&quot;);
    menuBar-&gt;Append(menuHelp, &quot;&amp;Help&quot;);

    SetMenuBar(menuBar);

    CreateStatusBar();
    SetStatusText(&quot;Welcome to wxWidgets!&quot;);

    wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);

    textCtrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY | wxHSCROLL);
    textCtrl-&gt;SetBackgroundColour(*wxWHITE);
    textCtrl-&gt;SetForegroundColour(*wxBLACK);
    textCtrl-&gt;SetFont(wxFont(wxFontInfo(10)));

    wxString licenseText = &quot;Copyright 2023 Author \n\n&quot;
        &quot;Permission is hereby granted, free of charge, to any person obtaining a copy of this software &quot;
        &quot;and \nassociated documentation files(the Software), to deal in the Software without restriction, &quot;
        &quot;\nincluding without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, &quot;
        &quot;\nand/or sell copies of the Software, and to permit persons to whom the Software is furnished to do \n&quot;
        &quot;so, subject to the following conditions : \n&quot;
        &quot;The above copyright notice and this permission notice shall be included in all copies or substantial \n&quot;
        &quot;portions of the Software. \n\n&quot;
        &quot;THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR \n&quot;
        &quot;IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS \n&quot;
        &quot;FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS \n&quot;
        &quot;OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, \n&quot;
        &quot;WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN \n&quot;
        &quot;CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.&quot;;
    textCtrl-&gt;SetValue(licenseText);



    mainSizer-&gt;Add(textCtrl, 1, wxEXPAND | wxALL, 20);

    accept_checkbox = new wxCheckBox(this, ID_Accept_CheckBox, &quot;I accept the license agreement&quot;);
    mainSizer-&gt;Add(accept_checkbox, 0, wxALIGN_LEFT | wxALL, 10);

    gauge = new wxGauge(this, wxID_ANY, 100, wxDefaultPosition, wxDefaultSize, wxGA_HORIZONTAL);
    mainSizer-&gt;Add(gauge, 0, wxEXPAND | wxALL, 20);

    install_button = new wxButton(this, ID_Install_Button, &quot;Install&quot;, wxPoint(20, 20));
    set_location = new wxButton(this, ID_Set_Location, &quot;Set Location&quot;, wxPoint(20, 20));

    install_button-&gt;Enable(false);

    mainSizer-&gt;AddStretchSpacer(); 
    mainSizer-&gt;Add(install_button, 0, wxALIGN_CENTER | wxALL, 10); 
    mainSizer-&gt;Add(set_location, 0, wxALIGN_CENTER | wxALL, 5);


    SetSizerAndFit(mainSizer);



    Bind(wxEVT_MENU, &amp;NewFrame::OnHello, this, ID_Hello);
    Bind(wxEVT_MENU, &amp;NewFrame::OnAbout, this, wxID_ABOUT);
    Bind(wxEVT_MENU, &amp;NewFrame::OnExit, this, wxID_EXIT);
    Bind(wxEVT_BUTTON, &amp;NewFrame::OnInstallButtonClick, this, ID_Install_Button);
    Bind(wxEVT_BUTTON, &amp;NewFrame::OnSetButtonClick, this, ID_Set_Location);
    Bind(wxEVT_CHECKBOX, &amp;NewFrame::OnCheckBoxClicked, this, ID_Accept_CheckBox);


    wxWindow::SetInitialSize(wxSize(700, 500));
}

void NewFrame::OnExit(wxCommandEvent&amp; event)
{
    Close(true);
}

void NewFrame::OnAbout(wxCommandEvent&amp; event)
{
    wxMessageBox(&quot;This is a wxWidgets Hello World example&quot;,
        &quot;About Hello World&quot;, wxOK | wxICON_INFORMATION);
}

void NewFrame::OnHello(wxCommandEvent&amp; event)
{
    wxLogMessage(&quot;Hello world from wxWidgets!&quot;);
}

void NewFrame::OnInstallButtonClick(wxCommandEvent&amp; event)
{
    if (!accept_checkbox-&gt;IsChecked())
    {
        wxMessageBox(&quot;Please accept the license agreement.&quot;, &quot;Error&quot;, wxOK | wxICON_ERROR);
        return;
    }

    // Test file download
    FileDownloader downloader;
    wxString url = &quot;https://releases.ubuntu.com/22.04.2/ubuntu-22.04.2-desktop-amd64.iso&quot;;
    wxString destination = &quot;F:/ubuntu-22.04.2-desktop-amd64.iso&quot;;

    install_button-&gt;Disable();

    std::thread downloadThread([this, &amp;downloader, url, destination]() {
        wxThreadEvent* progressEvent = new wxThreadEvent(wxEVT_THREAD, ID_UPDATE_PROGRESS);
        progressEvent-&gt;SetInt(0);
        wxQueueEvent(wxTheApp-&gt;GetTopWindow(), progressEvent);

        if (downloader.DownloadFile(url.ToStdString(), destination.ToStdString()))
        {
            wxThreadEvent* completeEvent = new wxThreadEvent(wxEVT_THREAD, ID_DOWNLOAD_COMPLETE);
            wxQueueEvent(wxTheApp-&gt;GetTopWindow(), completeEvent);
        }
        else
        {
            wxThreadEvent* errorEvent = new wxThreadEvent(wxEVT_THREAD, ID_DOWNLOAD_ERROR);
            wxQueueEvent(wxTheApp-&gt;GetTopWindow(), errorEvent);
        }

        wxThreadEvent* enableEvent = new wxThreadEvent(wxEVT_THREAD, ID_ENABLE_INSTALL_BUTTON);
        wxQueueEvent(wxTheApp-&gt;GetTopWindow(), enableEvent);
        });

    downloadThread.detach();
}


void NewFrame::OnSetButtonClick(wxCommandEvent&amp; event)
{
    wxMessageBox(&quot;Button clicked!&quot;, &quot;Button&quot;, wxOK | wxICON_INFORMATION);
}

void NewFrame::OnCheckBoxClicked(wxCommandEvent&amp; event)
{
    if (accept_checkbox-&gt;IsChecked())
        install_button-&gt;Enable(true);
    else
        install_button-&gt;Enable(false);
}


This is the exception that the debugger captures:

Exception thrown at 0x00007FFC285301E8 (wxbase32ud_vc_custom.dll) in WindowsInstaller.exe: 0xC0000005: Access violation writing location 0x00000080FDFDFDFD.

答案1

得分: 2

在评论中得到的所有帮助,通过它们的组合,我能够修复崩溃问题、内存泄漏问题和二进制转换问题。以下是更新后的代码:

#include <wx/wx.h>
#include <iostream>
#include <fstream>
#include <curl/curl.h>
#include <thread>
#include <filesystem>
#include <future>

class BinaryFileDownloader
{
public:
    BinaryFileDownloader(wxGauge* progressGauge)
        : progressGauge_(progressGauge)
    {
    }

    bool DownloadFile(const std::string& url, const std::string& destination)
    {
        FILE* file = fopen(destination.c_str(), "wb");
        if (!file)
        {
            std::cerr << "无法打开目标文件:" << destination << std::endl;
            return false;
        }

        CURL* curl = curl_easy_init();
        if (!curl)
        {
            std::cerr << "无法初始化libcurl" << std::endl;
            fclose(file);
            return false;
        }

        curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, file);
        curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
        curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, ProgressCallback);
        curl_easy_setopt(curl, CURLOPT_XFERINFODATA, this);

        CURLcode res = curl_easy_perform(curl);
        fclose(file);
        curl_easy_cleanup(curl);

        if (res != CURLE_OK)
        {
            std::cerr << "下载文件失败:" << curl_easy_strerror(res) << std::endl;
            return false;
        }

        std::cout << "文件下载成功!" << std::endl;
        return true;
    }

    static size_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userdata)
    {
        FILE* file = static_cast<FILE*>(userdata);
        size_t written = fwrite(contents, size, nmemb, file);
        return written;
    }

    static int ProgressCallback(void* clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
    {
        BinaryFileDownloader* downloader = static_cast<BinaryFileDownloader*>(clientp);
        if (downloader->progressGauge_)
        {
            if (dltotal > 0)
            {
                double progress = static_cast<double>(dlnow) / static_cast<double>(dltotal) * 100.0;
                downloader->progressGauge_->SetValue(static_cast<int>(progress));
            }
        }
        return 0;
    }

private:
    wxGauge* progressGauge_;
};

enum
{
    ID_Hello = 1,
    ID_Install_Button = 2,
    ID_Set_Location = 3,
    ID_Accept_CheckBox = 4,
    ID_UPDATE_PROGRESS = 5,
    ID_DOWNLOAD_COMPLETE = 6,
    ID_DOWNLOAD_ERROR = 7,
    ID_ENABLE_INSTALL_BUTTON = 8
};

class NewFrame : public wxFrame
{
public:
    NewFrame();
    void OnHello(wxCommandEvent& event);
    void OnAbout(wxCommandEvent& event);
    void OnInstallButtonClick(wxCommandEvent& event);
    void OnSetButtonClick(wxCommandEvent& event);
    void OnCheckBoxClicked(wxCommandEvent& event);
    void OnExit(wxCommandEvent& event);
    void OnDownloadComplete(wxThreadEvent& event);

private:
    wxButton* install_button;
    wxButton* set_location;
    wxTextCtrl* textCtrl;
    wxTextCtrl* statusCtrl;
    wxCheckBox* accept_checkbox;
    wxGauge* gauge;
    std::thread downloadThread;
};

class WindowsInstallerApp : public wxApp
{
public:
    bool OnInit() override;
    int OnExit() override;

private:
    NewFrame* frame;
};

wxIMPLEMENT_APP(WindowsInstallerApp);

bool WindowsInstallerApp::OnInit()
{
    frame = new NewFrame();
    frame->Show(true);
    return true;
}

NewFrame::NewFrame()
    : wxFrame(nullptr, wxID_ANY, "Hello World", wxDefaultPosition, wxSize(700, 500), wxDEFAULT_FRAME_STYLE & ~(wxRESIZE_BORDER | wxMAXIMIZE_BOX))
{
    // ... 省略部分代码 ...
}

// ... 省略部分代码 ...

void NewFrame::OnDownloadComplete(wxThreadEvent& event)
{
    // 清理下载线程
    if (downloadThread.joinable()) {
        downloadThread.join();
    }
}

// ... 省略部分代码 ...

崩溃问题是由于 curl_easy_setopt(curl, CURLOPT_WRITEDATA, file);wxThreadEvent* event = static_cast<wxThreadEvent*>(userp); 不兼容引起的,感谢 drescherjm 提供的解决方案。

内存泄漏问题是由 Jesper Juhl 发现的,通过在窗口销毁时关闭窗口来修复。

最后,二进制转换问题已经修复,以便与非UTF-8文本文件一起使用,感谢 Retired Ninja 的建议。

英文:

In appreciate all the help I received in the comments, using a combination of them, I was able to fix the crashing problem, memory leak and poor binary transformation problems. Here is the updated code:

#include &lt;wx/wx.h&gt;
#include &lt;iostream&gt;
#include &lt;fstream&gt;
#include &lt;curl/curl.h&gt;
#include &lt;thread&gt;
#include &lt;filesystem&gt;
#include &lt;future&gt;
class BinaryFileDownloader
{
public:
BinaryFileDownloader(wxGauge* progressGauge)
: progressGauge_(progressGauge)
{
}
bool DownloadFile(const std::string&amp; url, const std::string&amp; destination)
{
FILE* file = fopen(destination.c_str(), &quot;wb&quot;);
if (!file)
{
std::cerr &lt;&lt; &quot;Failed to open destination file: &quot; &lt;&lt; destination &lt;&lt; std::endl;
return false;
}
CURL* curl = curl_easy_init();
if (!curl)
{
std::cerr &lt;&lt; &quot;Failed to initialize libcurl&quot; &lt;&lt; std::endl;
fclose(file);
return false;
}
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, file);
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, ProgressCallback);
curl_easy_setopt(curl, CURLOPT_XFERINFODATA, this);
CURLcode res = curl_easy_perform(curl);
fclose(file);
curl_easy_cleanup(curl);
if (res != CURLE_OK)
{
std::cerr &lt;&lt; &quot;Failed to download file: &quot; &lt;&lt; curl_easy_strerror(res) &lt;&lt; std::endl;
return false;
}
std::cout &lt;&lt; &quot;File downloaded successfully!&quot; &lt;&lt; std::endl;
return true;
}
static size_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userdata)
{
FILE* file = static_cast&lt;FILE*&gt;(userdata);
size_t written = fwrite(contents, size, nmemb, file);
return written;
}
static int ProgressCallback(void* clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
{
BinaryFileDownloader* downloader = static_cast&lt;BinaryFileDownloader*&gt;(clientp);
if (downloader-&gt;progressGauge_)
{
if (dltotal &gt; 0)
{
double progress = static_cast&lt;double&gt;(dlnow) / static_cast&lt;double&gt;(dltotal) * 100.0;
downloader-&gt;progressGauge_-&gt;SetValue(static_cast&lt;int&gt;(progress));
}
}
return 0;
}
private:
wxGauge* progressGauge_;
};
enum
{
ID_Hello = 1,
ID_Install_Button = 2,
ID_Set_Location = 3,
ID_Accept_CheckBox = 4,
ID_UPDATE_PROGRESS = 5,
ID_DOWNLOAD_COMPLETE = 6,
ID_DOWNLOAD_ERROR = 7,
ID_ENABLE_INSTALL_BUTTON = 8
};
class NewFrame : public wxFrame
{
public:
NewFrame();
void OnHello(wxCommandEvent&amp; event);
void OnAbout(wxCommandEvent&amp; event);
void OnInstallButtonClick(wxCommandEvent&amp; event);
void OnSetButtonClick(wxCommandEvent&amp; event);
void OnCheckBoxClicked(wxCommandEvent&amp; event);
void OnExit(wxCommandEvent&amp; event);
void OnDownloadComplete(wxThreadEvent&amp; event);
private:
wxButton* install_button;
wxButton* set_location;
wxTextCtrl* textCtrl;
wxTextCtrl* statusCtrl;
wxCheckBox* accept_checkbox;
wxGauge* gauge;
std::thread downloadThread;
};
class WindowsInstallerApp : public wxApp
{
public:
bool OnInit() override;
int OnExit() override;
private:
NewFrame* frame;
};
wxIMPLEMENT_APP(WindowsInstallerApp);
bool WindowsInstallerApp::OnInit()
{
frame = new NewFrame();
frame-&gt;Show(true);
return true;
}
NewFrame::NewFrame()
: wxFrame(nullptr, wxID_ANY, &quot;Hello World&quot;, wxDefaultPosition, wxSize(700, 500), wxDEFAULT_FRAME_STYLE &amp; ~(wxRESIZE_BORDER | wxMAXIMIZE_BOX))
{
wxMenu* menuFile = new wxMenu;
menuFile-&gt;Append(ID_Hello, &quot;&amp;Hello...\tCtrl+H&quot;,
&quot;Help string shown in status bar for this menu item&quot;);
menuFile-&gt;AppendSeparator();
menuFile-&gt;Append(wxID_EXIT);
wxMenu* menuHelp = new wxMenu;
menuHelp-&gt;Append(wxID_ABOUT);
wxMenuBar* menuBar = new wxMenuBar;
menuBar-&gt;Append(menuFile, &quot;&amp;File&quot;);
menuBar-&gt;Append(menuHelp, &quot;&amp;Help&quot;);
SetMenuBar(menuBar);
CreateStatusBar();
SetStatusText(&quot;Installer Ready!&quot;);
wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
textCtrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY | wxHSCROLL);
textCtrl-&gt;SetBackgroundColour(*wxWHITE);
textCtrl-&gt;SetForegroundColour(*wxBLACK);
textCtrl-&gt;SetFont(wxFont(wxFontInfo(10)));
wxString licenseText = &quot;Copyright 2023 Ethan James \n\n&quot;
&quot;Permission is hereby granted, free of charge, to any person obtaining a copy of this software &quot;
&quot;and \nassociated documentation files(the “Software”), to deal in the Software without restriction, &quot;
&quot;\nincluding without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, &quot;
&quot;\nand/or sell copies of the Software, and to permit persons to whom the Software is furnished to do \n&quot;
&quot;so, subject to the following conditions : \n&quot;
&quot;The above copyright notice and this permission notice shall be included in all copies or substantial \n&quot;
&quot;portions of the Software. \n\n&quot;
&quot;THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR \n&quot;
&quot;IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS \n&quot;
&quot;FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS \n&quot;
&quot;OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, \n&quot;
&quot;WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN \n&quot;
&quot;CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.&quot;;
textCtrl-&gt;SetValue(licenseText);
mainSizer-&gt;Add(textCtrl, 1, wxEXPAND | wxALL, 20);
accept_checkbox = new wxCheckBox(this, ID_Accept_CheckBox, &quot;I accept the license agreement&quot;);
mainSizer-&gt;Add(accept_checkbox, 0, wxALIGN_LEFT | wxALL, 10);
gauge = new wxGauge(this, wxID_ANY, 100, wxDefaultPosition, wxDefaultSize, wxGA_HORIZONTAL);
mainSizer-&gt;Add(gauge, 0, wxEXPAND | wxALL, 20);
gauge-&gt;SetValue(0);
install_button = new wxButton(this, ID_Install_Button, &quot;Install&quot;, wxPoint(20, 20));
set_location = new wxButton(this, ID_Set_Location, &quot;Set Location&quot;, wxPoint(20, 20));
install_button-&gt;Enable(false);
mainSizer-&gt;AddStretchSpacer();
mainSizer-&gt;Add(install_button, 0, wxALIGN_CENTER | wxALL, 10);
mainSizer-&gt;Add(set_location, 0, wxALIGN_CENTER | wxALL, 5);
SetSizerAndFit(mainSizer);
Bind(wxEVT_MENU, &amp;NewFrame::OnHello, this, ID_Hello);
Bind(wxEVT_MENU, &amp;NewFrame::OnAbout, this, wxID_ABOUT);
Bind(wxEVT_MENU, &amp;NewFrame::OnExit, this, wxID_EXIT);
Bind(wxEVT_BUTTON, &amp;NewFrame::OnInstallButtonClick, this, ID_Install_Button);
Bind(wxEVT_BUTTON, &amp;NewFrame::OnSetButtonClick, this, ID_Set_Location);
Bind(wxEVT_CHECKBOX, &amp;NewFrame::OnCheckBoxClicked, this, ID_Accept_CheckBox);
Bind(wxEVT_THREAD, &amp;NewFrame::OnDownloadComplete, this, ID_DOWNLOAD_COMPLETE);
wxWindow::SetInitialSize(wxSize(700, 500));
}
void NewFrame::OnAbout(wxCommandEvent&amp; event)
{
wxMessageBox(&quot;This is a simple windows application installer, written by Sadan#9264&quot;,
&quot;About This App&quot;, wxOK | wxICON_INFORMATION);
}
void NewFrame::OnHello(wxCommandEvent&amp; event)
{
}
void NewFrame::OnInstallButtonClick(wxCommandEvent&amp; event)
{
if (!accept_checkbox-&gt;IsChecked())
{
wxMessageBox(&quot;Please accept the license agreement.&quot;, &quot;Error&quot;, wxOK | wxICON_ERROR);
return;
}
install_button-&gt;Enable(false);
accept_checkbox-&gt;Enable(false);
set_location-&gt;Enable(false);
downloadThread = std::thread([this]() {
BinaryFileDownloader downloader(gauge);
std::string url = &quot;https://releases.ubuntu.com/22.04.2/ubuntu-22.04.2-desktop-amd64.iso&quot;;
std::string destination = &quot;F:/ubuntu-22.04.2-desktop-amd64.iso&quot;;
bool success = downloader.DownloadFile(url, destination);
// Notify the main thread when the download is complete.
wxThreadEvent* event = new wxThreadEvent(wxEVT_THREAD, ID_DOWNLOAD_COMPLETE);
event-&gt;SetString(success ? &quot;Download successful&quot; : &quot;Download failed&quot;);
wxQueueEvent(this, event);
});
}
void NewFrame::OnDownloadComplete(wxThreadEvent&amp; event)
{
/*
std::string message = event.GetString();
std::cout &lt;&lt; message &lt;&lt; std::endl;
*/
// Cleanup the download thread
if (downloadThread.joinable()) {
downloadThread.join();
}
}
void NewFrame::OnSetButtonClick(wxCommandEvent&amp; event)
{
wxMessageBox(&quot;Button clicked!&quot;, &quot;Button&quot;, wxOK | wxICON_INFORMATION);
}
void NewFrame::OnCheckBoxClicked(wxCommandEvent&amp; event)
{
if (accept_checkbox-&gt;IsChecked())
install_button-&gt;Enable(true);
else
install_button-&gt;Enable(false);
}
int WindowsInstallerApp::OnExit()
{
delete frame;
return wxApp::OnExit();
}
void NewFrame::OnExit(wxCommandEvent&amp; event)
{
Close(true);
}

The crashing was a problem with curl_easy_setopt(curl, CURLOPT_WRITEDATA, file); and wxThreadEvent* event = static_cast&lt;wxThreadEvent*&gt;(userp);, which are incompatible, thanks to drescherjm.

The memory leak with the frame, which was noticed by Jesper Juhl was fixed by closing it when the window is destroyed.

And finally the binary transformation was replaced in order to work with non utf-8 text files, thanks Retired Ninja.

huangapple
  • 本文由 发表于 2023年5月30日 07:46:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/76360860.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定