Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support more sophisticated proxy settings #52

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/TinyXml/tinyxml.h
Original file line number Diff line number Diff line change
Expand Up @@ -995,6 +995,8 @@ class TiXmlDocument : public TiXmlNode
{
value = documentName;
error = false;
errorId = 0;
tabsize = 4;
}
#endif

Expand Down
21 changes: 13 additions & 8 deletions src/gup.rc
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,23 @@ BEGIN
PUSHBUTTON "Cancel",IDCANCEL,227,11,50,14
END

IDD_PROXY_DLG DIALOGEX 0, 0, 224, 84
IDD_PROXY_DLG DIALOGEX 0, 0, 225, 143
STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION
CAPTION "Proxy Settings"
FONT 8, "MS Shell Dlg", 0, 0, 0x1
BEGIN
RTEXT "Proxy server : ",IDC_PROXYSERVER_STATIC,11,18,61,8
EDITTEXT IDC_PROXYSERVER_EDIT,77,15,86,14,ES_AUTOHSCROLL
RTEXT "Port : ",IDC_PORT_STATIC,11,41,61,8
EDITTEXT IDC_PORT_EDIT,77,39,34,14,ES_NUMBER
PUSHBUTTON "OK",IDOK,55,66,50,14
PUSHBUTTON "Cancel",IDCANCEL,134,66,50,14
END
EDITTEXT IDC_PROXYSERVER_EDIT,87,16,86,14,ES_AUTOHSCROLL
EDITTEXT IDC_PORT_EDIT,87,40,34,14,ES_NUMBER
COMBOBOX IDC_PROXY_AUTH,87,70,78,30,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP
EDITTEXT IDC_PROXY_USER_PASS,87,92,86,14,ES_AUTOHSCROLL
PUSHBUTTON "OK",IDOK,43,121,50,14
PUSHBUTTON "Cancel",IDCANCEL,122,121,50,14
RTEXT "Proxy server : ",IDC_PROXYSERVER_STATIC,21,19,61,8
RTEXT "Port : ",IDC_PORT_STATIC,21,42,61,8
RTEXT "Proxy Auth Type:",IDC_PROXY_AUTH_STATIC,19,68,61,8
RTEXT "Proxy UserPass String:", IDC_PROXY_USERPASS_STATIC, 2, 96, 77, 8
RTEXT "For Kerberos just colon!", IDC_PROXY_USERPASS_HELP_STATIC, 87, 108, 77, 8
END

IDD_YESNONEVERDLG DIALOGEX 0, 0, 270, 94
STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
Expand Down
6 changes: 5 additions & 1 deletion src/resource.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,8 @@
#define IDC_YESNONEVERMSG 1008
#define IDD_UPDATE_DLG 1009
#define IDC_DOWNLOAD_LINK 1011

#define IDC_PROXY_AUTH 1012
#define IDC_PROXY_USER_PASS 1013
#define IDC_PROXY_AUTH_STATIC 1014
#define IDC_PROXY_USERPASS_STATIC 1015
#define IDC_PROXY_USERPASS_HELP_STATIC 1016
117 changes: 96 additions & 21 deletions src/winmain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
along with GUP. If not, see <http://www.gnu.org/licenses/>.
*/


#include "../ZipLib/ZipFile.h"
#include "../ZipLib/utils/stream_utils.h"

Expand Down Expand Up @@ -51,6 +52,8 @@ static bool stopDL = false;
static wstring msgBoxTitle = L"";
static wstring abortOrNot = L"";
static wstring proxySrv = L"0.0.0.0";
static wstring proxyAuth = L"ANY";
static wstring proxyUserPass = L":";
static long proxyPort = 0;
static wstring winGupUserAgent = L"WinGup/";
static wstring dlFileName = L"";
Expand Down Expand Up @@ -80,6 +83,7 @@ gup -unzipTo [-clean] FOLDER_TO_ACTION ZIP_URL\r\
\r\
--help : Show this help message (and quit program).\r\
-options : Show the proxy configuration dialog (and quit program).\r\
You may need to run in administrator console to store the options.\r\
-v : Launch GUP with VERSION_VALUE.\r\
VERSION_VALUE is the current version number of program to update.\r\
If you pass the version number as the argument,\r\
Expand All @@ -95,6 +99,50 @@ gup -unzipTo [-clean] FOLDER_TO_ACTION ZIP_URL\r\
";
std::wstring thirdDoUpdateDlgButtonLabel;

class ProxyAuthType {
#define MAX_AUTH_TYPE 8
private:
typedef struct { const unsigned long num; const wchar_t* text; } auth_t;
static const auth_t auth_conv[MAX_AUTH_TYPE];
public:
static unsigned long getAuthNum(const wstring& text) {
// BASIC, DIGEST, NEGOTIATE, NTLM, AWS_SIGV4, ANY, ANYSAFE
for (int i = 0; i < MAX_AUTH_TYPE; ++i) {
if (text == auth_conv[i].text) {
return auth_conv[i].num;
}
}
return CURLAUTH_NONE;
}

static bool getAuthStr(unsigned long lAuth, wstring& text) {
// BASIC, DIGEST, NEGOTIATE, NTLM, AWS_SIGV4, ANY, ANYSAFE
for (int i = 0; i < MAX_AUTH_TYPE; ++i) {
if (lAuth == auth_conv[i].num) {
text = auth_conv[i].text;
return true;
}
}
return false;
}
static void fillComboBox(HWND hWnd) {
for (int i = 0; i < MAX_AUTH_TYPE; ++i) {
SendMessage(hWnd, (UINT)CB_ADDSTRING, (WPARAM)0, (LPARAM)auth_conv[i].text);
}
}
};

const ProxyAuthType::auth_t ProxyAuthType::auth_conv[MAX_AUTH_TYPE] = {
{ CURLAUTH_NONE, L"NONE" },
{ CURLAUTH_NTLM, L"NTLM" },
{ CURLAUTH_BASIC, L"BASIC" },
{ CURLAUTH_DIGEST, L"DIGEST" },
{ CURLAUTH_NEGOTIATE, L"NEGOTIATE" },
{ CURLAUTH_AWS_SIGV4, L"AWS_SIGV4" },
{ CURLAUTH_ANYSAFE, L"ANYSAFE" },
{ CURLAUTH_ANY, L"ANY" }
};

class DlgIconHelper
{
public:
Expand Down Expand Up @@ -646,20 +694,26 @@ LRESULT CALLBACK proxyDlgProc(HWND hWndDlg, UINT Msg, WPARAM wParam, LPARAM)

switch(Msg)
{
case WM_INITDIALOG:
case WM_INITDIALOG: {
HWND hCmb = GetDlgItem(hWndDlg, IDC_PROXY_AUTH);
ProxyAuthType::fillComboBox(hCmb);
::SetDlgItemText(hWndDlg, IDC_PROXYSERVER_EDIT, proxySrv.c_str());
::SetDlgItemInt(hWndDlg, IDC_PORT_EDIT, proxyPort, FALSE);
goToScreenCenter(hWndDlg);
return TRUE;
::SetDlgItemText(hWndDlg, IDC_PROXY_AUTH, proxyAuth.c_str());
::SetDlgItemText(hWndDlg, IDC_PROXY_USER_PASS, proxyUserPass.c_str());

goToScreenCenter(hWndDlg);
return TRUE;
}
case WM_COMMAND:
switch(wParam)
{
case IDOK:
{
wchar_t proxyServer[MAX_PATH];
::GetDlgItemText(hWndDlg, IDC_PROXYSERVER_EDIT, proxyServer, MAX_PATH);
proxySrv = proxyServer;
wchar_t text[MAX_PATH];
::GetDlgItemText(hWndDlg, IDC_PROXYSERVER_EDIT, text, MAX_PATH); proxySrv = text;
::GetDlgItemText(hWndDlg, IDC_PROXY_AUTH, text, MAX_PATH); proxyAuth = text;
::GetDlgItemText(hWndDlg, IDC_PROXY_USER_PASS, text, MAX_PATH); proxyUserPass = text;
proxyPort = ::GetDlgItemInt(hWndDlg, IDC_PORT_EDIT, NULL, FALSE);
EndDialog(hWndDlg, 1);
return TRUE;
Expand Down Expand Up @@ -765,7 +819,7 @@ static DWORD WINAPI launchProgressBar(void *)
return 0;
}

bool downloadBinary(const wstring& urlFrom, const wstring& destTo, const wstring& sha2HashToCheck, pair<wstring, int> proxyServerInfo, bool isSilentMode, const pair<wstring, wstring>& stoppedMessage)
bool downloadBinary(const wstring& urlFrom, const wstring& destTo, const wstring& sha2HashToCheck, const GupExtraOptions& extraOptions, bool isSilentMode, const pair<wstring, wstring>& stoppedMessage)
{
FILE* pFile = _wfopen(destTo.c_str(), L"wb");
if (!pFile)
Expand All @@ -792,11 +846,19 @@ bool downloadBinary(const wstring& urlFrom, const wstring& destTo, const wstring
curl_easy_setopt(curl, CURLOPT_USERAGENT, ws2s(winGupUserAgent).c_str());
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorBuffer);

if (!proxyServerInfo.first.empty() && proxyServerInfo.second != -1)

if (extraOptions.hasProxySettings())
{
curl_easy_setopt(curl, CURLOPT_PROXY, ws2s(proxyServerInfo.first).c_str());
curl_easy_setopt(curl, CURLOPT_PROXYPORT, proxyServerInfo.second);
curl_easy_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
if (!extraOptions.getAuth().empty()) {
long lAuth = ProxyAuthType::getAuthNum(extraOptions.getAuth());

curl_easy_setopt(curl, CURLOPT_PROXYAUTH, lAuth); // any method as proposed by proxy
}
if (!extraOptions.getUserPass().empty()) {
curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, ws2s(extraOptions.getUserPass()).c_str());
}
curl_easy_setopt(curl, CURLOPT_PROXY, ws2s(extraOptions.getProxyServer()).c_str());
curl_easy_setopt(curl, CURLOPT_PROXYPORT, extraOptions.getPort());
}
curl_easy_setopt(curl, CURLOPT_SSL_OPTIONS, CURLSSLOPT_ALLOW_BEAST | CURLSSLOPT_NO_REVOKE);

Expand Down Expand Up @@ -874,7 +936,7 @@ bool downloadBinary(const wstring& urlFrom, const wstring& destTo, const wstring
return true;
}

bool getUpdateInfo(const string& info2get, const GupParameters& gupParams, const GupExtraOptions& proxyServer, const wstring& customParam, const wstring& version)
bool getUpdateInfo(const string& info2get, const GupParameters& gupParams, const GupExtraOptions& extraOptions, const wstring& customParam, const wstring& version)
{
char errorBuffer[CURL_ERROR_SIZE] = { 0 };

Expand Down Expand Up @@ -930,13 +992,19 @@ bool getUpdateInfo(const string& info2get, const GupParameters& gupParams, const
curl_easy_setopt(curl, CURLOPT_USERAGENT, ws2s(winGupUserAgent).c_str());
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorBuffer);

if (proxyServer.hasProxySettings())
if (extraOptions.hasProxySettings())
{
curl_easy_setopt(curl, CURLOPT_PROXY, ws2s(proxyServer.getProxyServer()).c_str());
curl_easy_setopt(curl, CURLOPT_PROXYPORT, proxyServer.getPort());
curl_easy_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
}
if (!extraOptions.getAuth().empty()) {
long lAuth = ProxyAuthType::getAuthNum(extraOptions.getAuth());

curl_easy_setopt(curl, CURLOPT_PROXYAUTH, lAuth); // any method as proposed by proxy
}
if (!extraOptions.getUserPass().empty()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coding convention is not respected.

curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, ws2s(extraOptions.getUserPass()).c_str());
}
curl_easy_setopt(curl, CURLOPT_PROXY, ws2s(extraOptions.getProxyServer()).c_str());
curl_easy_setopt(curl, CURLOPT_PROXYPORT, extraOptions.getPort());
}
curl_easy_setopt(curl, CURLOPT_SSL_OPTIONS, CURLSSLOPT_ALLOW_BEAST | CURLSSLOPT_NO_REVOKE);

res = curl_easy_perform(curl);
Expand Down Expand Up @@ -1255,7 +1323,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR lpszCmdLine, int)
if (dlStopped == L"")
dlStopped = MSGID_DOWNLOADSTOPPED;

bool isSuccessful = downloadBinary(dlUrl, dlDest, sha256ToCheck, pair<wstring, int>(extraOptions.getProxyServer(), extraOptions.getPort()), true, pair<wstring, wstring>(dlStopped, gupParams.getMessageBoxTitle()));
bool isSuccessful = downloadBinary(dlUrl, dlDest, sha256ToCheck, extraOptions , true, pair<wstring, wstring>(dlStopped, gupParams.getMessageBoxTitle()));
if (isSuccessful)
{
isSuccessful = decompress(dlDest, destPath);
Expand Down Expand Up @@ -1314,10 +1382,17 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR lpszCmdLine, int)
{
proxySrv = extraOptions.getProxyServer();
proxyPort = extraOptions.getPort();
proxyAuth = extraOptions.getAuth();
proxyUserPass = extraOptions.getUserPass();
}
if (::DialogBox(hInst, MAKEINTRESOURCE(IDD_PROXY_DLG), NULL, reinterpret_cast<DLGPROC>(proxyDlgProc)))
extraOptions.writeProxyInfo(L"gupOptions.xml", proxySrv.c_str(), proxyPort);

{
extraOptions.setProxyServer(proxySrv);
extraOptions.setPort(proxyPort);
extraOptions.setAuth(proxyAuth);
extraOptions.setUserPass(proxyUserPass);
extraOptions.write();
}
return 0;
}

Expand Down Expand Up @@ -1427,7 +1502,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR lpszCmdLine, int)
if (dlStopped == L"")
dlStopped = MSGID_DOWNLOADSTOPPED;

bool dlSuccessful = downloadBinary(gupDlInfo.getDownloadLocation(), dlDest, L"", pair<wstring, int>(extraOptions.getProxyServer(), extraOptions.getPort()), isSilentMode, pair<wstring, wstring>(dlStopped, gupParams.getMessageBoxTitle()));
bool dlSuccessful = downloadBinary(gupDlInfo.getDownloadLocation(), dlDest, L"", extraOptions , isSilentMode, pair<wstring, wstring>(dlStopped, gupParams.getMessageBoxTitle()));

if (!dlSuccessful)
{
Expand Down
41 changes: 34 additions & 7 deletions src/xmlTools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,30 @@ GupExtraOptions::GupExtraOptions(const wchar_t * xmlFileName)
}
}

TiXmlNode *authNode = proxyNode->FirstChildElement("auth");
if (authNode)
{
TiXmlNode *auth = authNode->FirstChild();
if (auth)
{
const char *val = auth->Value();
if (val)
_proxyAuth = s2ws(val);
}
}

TiXmlNode *userpwdNode = proxyNode->FirstChildElement("userpwd");
if (userpwdNode)
{
TiXmlNode *userpwd = userpwdNode->FirstChild();
if (userpwd)
{
const char *val = userpwd->Value();
if (val)
_proxyUserPass = s2ws(val);
}
}

TiXmlNode *portNode = proxyNode->FirstChildElement("port");
if (portNode)
{
Expand All @@ -303,19 +327,22 @@ GupExtraOptions::GupExtraOptions(const wchar_t * xmlFileName)
}
}

void GupExtraOptions::writeProxyInfo(const wchar_t* fn, const wchar_t* proxySrv, long port)
void GupExtraOptions::write()
{
TiXmlDocument newProxySettings(ws2s(fn).c_str());
TiXmlNode *root = newProxySettings.InsertEndChild(TiXmlElement("GUPOptions"));
_xmlDoc.Clear();
TiXmlNode *root = _xmlDoc.InsertEndChild(TiXmlElement("GUPOptions"));
TiXmlNode *proxy = root->InsertEndChild(TiXmlElement("Proxy"));
TiXmlNode *auth = proxy->InsertEndChild(TiXmlElement("auth"));
auth->InsertEndChild(TiXmlText(ws2s(_proxyAuth).c_str()));
TiXmlNode *userpwd = proxy->InsertEndChild(TiXmlElement("userpwd"));
userpwd->InsertEndChild(TiXmlText(ws2s(_proxyUserPass).c_str()));
TiXmlNode *server = proxy->InsertEndChild(TiXmlElement("server"));
server->InsertEndChild(TiXmlText(ws2s(proxySrv).c_str()));
server->InsertEndChild(TiXmlText(ws2s(_proxyServer).c_str()));
TiXmlNode *portNode = proxy->InsertEndChild(TiXmlElement("port"));
char portStr[10];
sprintf(portStr, "%d", port);
sprintf(portStr, "%d", _port);
portNode->InsertEndChild(TiXmlText(portStr));

newProxySettings.SaveFile();
_xmlDoc.SaveFile();
}

std::wstring GupNativeLang::getMessageString(const std::string& msgID) const
Expand Down
16 changes: 12 additions & 4 deletions src/xmlTools.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,20 @@ class GupExtraOptions : public XMLTool {
public:
GupExtraOptions(const wchar_t * xmlFileName);
const std::wstring & getProxyServer() const { return _proxyServer;};
long getPort() const { return _port;};
bool hasProxySettings() const {return ((!_proxyServer.empty()) && (_port != -1));};
void writeProxyInfo(const wchar_t *fn, const wchar_t *proxySrv, long port);
void setProxyServer(const std::wstring& s) { _proxyServer = s; };
long getPort() const { return _port; };
void setPort(long l) { _port = l; };
bool hasProxySettings() const {return ((!_proxyServer.empty()) && (_port != -1)); };
void write();
const std::wstring& getAuth() const { return _proxyAuth; };
void setAuth(const std::wstring& s) { _proxyAuth = s; };
const std::wstring& getUserPass() const { return _proxyUserPass; };
void setUserPass(const std::wstring& s) { _proxyUserPass = s; };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

User password shouldn't be stored into the xml file.


private:
std::wstring _proxyServer;
std::wstring _proxyAuth;
std::wstring _proxyUserPass;
long _port = -1;
};

Expand All @@ -94,7 +102,7 @@ class GupDownloadInfo : public XMLTool {
bool doesNeed2BeUpdated() const {return _need2BeUpdated;};

private:
bool _need2BeUpdated;
bool _need2BeUpdated = false;
std::wstring _updateVersion;
std::wstring _updateLocation;
};
Expand Down
8 changes: 4 additions & 4 deletions vcproj/GUP.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\src\TinyXml;..\src\sha2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this file modified?

<AdditionalIncludeDirectories>$(ProjectDir)..\curl\builds\libcurl-vc15-$(LibrariesArchitecture)-$(Configuration)-dll-ipv6-sspi-schannel\include;..\src\TinyXml;..\src\sha2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;TIXML_USE_STL;_DEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
Expand All @@ -158,7 +158,7 @@
</ClCompile>
<Link>
<AdditionalDependencies>libcurl_debug.lib;ZipLib.lib;zlib.lib;lzma.lib;bzip2.lib;comctl32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\curl\builds\libcurl-vc15-x64-debug-dll-ipv6-sspi-schannel\lib;Bin\x64\Debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>$(ProjectDir)..\curl\builds\libcurl-vc15-$(LibrariesArchitecture)-$(Configuration)-dll-ipv6-sspi-schannel\lib;Bin\x64\Debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
</Link>
Expand Down Expand Up @@ -239,7 +239,7 @@ del ..\bin\GUP.ipdb</Command>
</Command>
</PreBuildEvent>
<ClCompile>
<AdditionalIncludeDirectories>..\src\TinyXml;..\src\sha2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(ProjectDir)..\curl\builds\libcurl-vc15-$(LibrariesArchitecture)-$(Configuration)-dll-ipv6-sspi-schannel\include;..\src\TinyXml;..\src\sha2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;TIXML_USE_STL;NDEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<PrecompiledHeader>
Expand All @@ -251,7 +251,7 @@ del ..\bin\GUP.ipdb</Command>
</ClCompile>
<Link>
<AdditionalDependencies>libcurl.lib;ZipLib.lib;zlib.lib;lzma.lib;bzip2.lib;comctl32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\curl\builds\libcurl-vc15-x64-release-dll-ipv6-sspi-schannel\lib;Bin\x64\Release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>$(ProjectDir)..\curl\builds\libcurl-vc15-$(LibrariesArchitecture)-$(Configuration)-dll-ipv6-sspi-schannel\lib;Bin\x64\Release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>false</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
Expand Down
Loading