Created
March 24, 2025 15:17
-
-
Save justaguywhocodes/c78bf89c6e84f43cf7f3083d46cb84e9 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Here's a version of the DLL without using the `goto` keyword. I've restructured the code using nested if-statements and early returns to handle the cleanup and error conditions: | |
```cpp | |
#include <windows.h> | |
#include <winhttp.h> | |
#pragma comment(lib, "winhttp.lib") | |
// Define default parameters as constants | |
const wchar_t* DEFAULT_PROXY_ADDRESS = L"proxy.example.com"; | |
const DWORD DEFAULT_PROXY_PORT = 8080; | |
const wchar_t* DEFAULT_PROXY_USERNAME = L"username"; | |
const wchar_t* DEFAULT_PROXY_PASSWORD = L"password"; | |
const wchar_t* DEFAULT_OUTPUT_PATH = L"C:\\downloaded_file.txt"; | |
BOOL PerformDownload( | |
LPCWSTR proxyAddress, | |
DWORD proxyPort, | |
LPCWSTR proxyUsername, | |
LPCWSTR proxyPassword, | |
LPCWSTR outputFilePath | |
) { | |
HINTERNET hSession = WinHttpOpen( | |
L"FileDownloader/1.0", | |
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, | |
WINHTTP_NO_PROXY_NAME, | |
WINHTTP_NO_PROXY_BYPASS, | |
0 | |
); | |
if (!hSession) { | |
return FALSE; | |
} | |
WINHTTP_PROXY_INFO proxyInfo = {0}; | |
proxyInfo.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY; | |
proxyInfo.lpszProxy = (LPWSTR)proxyAddress; | |
proxyInfo.lpszProxyBypass = NULL; | |
if (!WinHttpSetOption(hSession, WINHTTP_OPTION_PROXY, &proxyInfo, sizeof(proxyInfo))) { | |
WinHttpCloseHandle(hSession); | |
return FALSE; | |
} | |
if (proxyUsername && proxyPassword) { | |
WinHttpSetCredentials( | |
hSession, | |
WINHTTP_AUTH_TARGET_PROXY, | |
WINHTTP_AUTH_SCHEME_BASIC, | |
proxyUsername, | |
proxyPassword, | |
NULL | |
); | |
} | |
HINTERNET hConnect = WinHttpConnect( | |
hSession, | |
L"test.com", | |
INTERNET_DEFAULT_HTTPS_PORT, | |
0 | |
); | |
if (!hConnect) { | |
WinHttpCloseHandle(hSession); | |
return FALSE; | |
} | |
HINTERNET hRequest = WinHttpOpenRequest( | |
hConnect, | |
L"GET", | |
L"/file.txt", | |
NULL, | |
WINHTTP_NO_REFERER, | |
WINHTTP_DEFAULT_ACCEPT_TYPES, | |
WINHTTP_FLAG_SECURE | |
); | |
if (!hRequest) { | |
WinHttpCloseHandle(hConnect); | |
WinHttpCloseHandle(hSession); | |
return FALSE; | |
} | |
if (!WinHttpSendRequest( | |
hRequest, | |
WINHTTP_NO_ADDITIONAL_HEADERS, | |
0, | |
WINHTTP_NO_REQUEST_DATA, | |
0, | |
0, | |
0 | |
)) { | |
WinHttpCloseHandle(hRequest); | |
WinHttpCloseHandle(hConnect); | |
WinHttpCloseHandle(hSession); | |
return FALSE; | |
} | |
if (!WinHttpReceiveResponse(hRequest, NULL)) { | |
WinHttpCloseHandle(hRequest); | |
WinHttpCloseHandle(hConnect); | |
WinHttpCloseHandle(hSession); | |
return FALSE; | |
} | |
DWORD statusCode = 0; | |
DWORD statusCodeSize = sizeof(statusCode); | |
if (!WinHttpQueryHeaders( | |
hRequest, | |
WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, | |
NULL, | |
&statusCode, | |
&statusCodeSize, | |
NULL | |
) || statusCode != 200) { | |
WinHttpCloseHandle(hRequest); | |
WinHttpCloseHandle(hConnect); | |
WinHttpCloseHandle(hSession); | |
return FALSE; | |
} | |
HANDLE hFile = CreateFileW( | |
outputFilePath, | |
GENERIC_WRITE, | |
0, | |
NULL, | |
CREATE_ALWAYS, | |
FILE_ATTRIBUTE_NORMAL, | |
NULL | |
); | |
if (hFile == INVALID_HANDLE_VALUE) { | |
WinHttpCloseHandle(hRequest); | |
WinHttpCloseHandle(hConnect); | |
WinHttpCloseHandle(hSession); | |
return FALSE; | |
} | |
BOOL bResult = TRUE; | |
DWORD bytesRead = 0; | |
BYTE buffer[4096]; | |
while (WinHttpReadData(hRequest, buffer, sizeof(buffer), &bytesRead)) { | |
if (bytesRead == 0) break; | |
DWORD bytesWritten; | |
if (!WriteFile(hFile, buffer, bytesRead, &bytesWritten, NULL)) { | |
bResult = FALSE; | |
break; | |
} | |
} | |
CloseHandle(hFile); | |
WinHttpCloseHandle(hRequest); | |
WinHttpCloseHandle(hConnect); | |
WinHttpCloseHandle(hSession); | |
return bResult; | |
} | |
// Exported function for manual calls | |
extern "C" { | |
__declspec(dllexport) BOOL DownloadFile( | |
LPCWSTR proxyAddress, | |
DWORD proxyPort, | |
LPCWSTR proxyUsername, | |
LPCWSTR proxyPassword, | |
LPCWSTR outputFilePath | |
) { | |
return PerformDownload(proxyAddress, proxyPort, proxyUsername, proxyPassword, outputFilePath); | |
} | |
} | |
// DLL entry point with thread attach handling | |
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { | |
switch (ul_reason_for_call) { | |
case DLL_PROCESS_ATTACH: | |
break; | |
case DLL_THREAD_ATTACH: | |
PerformDownload( | |
DEFAULT_PROXY_ADDRESS, | |
DEFAULT_PROXY_PORT, | |
DEFAULT_PROXY_USERNAME, | |
DEFAULT_PROXY_PASSWORD, | |
DEFAULT_OUTPUT_PATH | |
); | |
break; | |
case DLL_THREAD_DETACH: | |
break; | |
case DLL_PROCESS_DETACH: | |
break; | |
} | |
return TRUE; | |
} | |
``` | |
Key changes made: | |
1. Removed all `goto` statements and the `cleanup` label | |
2. Used nested if-statements with early returns for error handling | |
3. Ensured proper resource cleanup by closing handles in the correct order at each failure point | |
4. Maintained the same functionality while improving code flow readability | |
5. Kept the structure of having a separate `PerformDownload` function and the exported `DownloadFile` | |
The code now: | |
- Checks each operation's success before proceeding | |
- Cleans up resources immediately before returning FALSE on failure | |
- Closes all handles in the correct order at the end of successful execution | |
- Maintains the same thread attach behavior | |
This version should be more maintainable and easier to follow while achieving the same result. The resource cleanup is still properly handled, just without relying on a single cleanup block reached via `goto`. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment