Quantcast
Channel: AutoIt v3 - General Help and Support
Viewing all articles
Browse latest Browse all 12506

C structures and AutoIt [MT DLL]

$
0
0

So some time ago I created a project, a DLL to create background requests in separate threads using WinHTTP and pass around data using C structures. It all worked out wonderfully with the exception of a crash every now and then, but it got the job done.

 

Now I have need to make my dll return data in binary instead of doing the conversions internally, I want to be able to receive any kind of data, from text, binary all the way to gzip data. 

 

I basically make a copy of the structure in my dll on the AutoIt side.

AutoIt         
Global $INT_BUFFERSIZE = 1048576 Global $tagTHREAD_PARAMETERS = _         "WCHAR UserAgent[1024];" & _                            ;   user agent         "WCHAR HTTPVerb[1024];" & _                             ;   POST/GET/HEAD etc         "WCHAR Host[1024];" & _                                 ;   ex: google.com         "WCHAR Resource[1024];" & _                             ;   ex: /somescript.php         "int Port;" & _                                         ;   80/443         "WCHAR Referer[1024];" & _                              ;   optional referer         "WCHAR Headers[1024];" & _                              ;   null terminated request headers         "ptr ExtraData;" & _                                    ;   pointer to structure with arguments ex: a=1&b=2&page=45         "DWORD Length;" & _                                     ;   lenght of the arguents         "DWORD TotalLength;" & _                                ;   same as above         "int dwResolveTimeout;" & _                             ;   Resolve timout         "int dwConnectTimeout;" & _                             ;   Connection timout         "int dwSendTimeout;" & _                                ;   Send timeout         "int dwReceiveTimeout;" & _                             ;   Recieve timeout         "WCHAR Proxy[1024];" & _                                ;   proxy string         "DWORD ProxyFlags;" & _                                 ;   WinHTTP open flags         "DWORD SendFlags;" & _                                  ;   WinHttpOpenRequest flags         "BYTE ResponceHTML[" & $INT_BUFFERSIZE & "];" & _       ;   HTML returned         "WCHAR ResponceHeaders[" & $INT_BUFFERSIZE & "];" & _   ;   Responce Headers         "DOUBLE Latency;" & _                                   ;   Responce Latency         "int RetryTimes;" & _                                   ;   Times to retry request with server         "int MaxTestTime;" & _                                  ;   max amount of time the request can run for         "ptr httpSession;" & _         "ptr httpConnect;" & _         "ptr httpRequest"

And I have this copy in my dll which I later initialize with my AutoIt copy so I can use all the info in it and subsequently return data as well.

C++         
// AutoIt thread parameters static const int INT_BUFFERSIZE = 1048576;    // Had to increase to 1MB because I was getting very big pages with some tests and it wouldn't work // AutoIt thread parameters, AutoIt will create a version of this and pass it as a thread paramater struct THREAD_PARAM_COMPONENTS {     WCHAR UserAgent[1024];                      // user agent     WCHAR HTTPVerb[1024];                       // POST/GET/HEAD etc     WCHAR Host[1024];                           // Domain name for target request     WCHAR Resource[1024];                       // resource at target     int Port;                                   // port on target     WCHAR Referer[1024];                        // referer     WCHAR Headers[1024];                        // headers string     LPVOID ExtraData;                           // additional data/paramaters to send     DWORD Length;                               // lenght of additional data     DWORD TotalLenght;                          // same as above for some reason     int dwResolveTimeout;                       // max time for resolving     int dwConnectTimeout;                       // max time for connection     int dwSendTimeout;                          // max time to wait while sending     int dwReceiveTimeout;                       // max time to wait for recieving responce     WCHAR Proxy[1024];                          // proxy for request     DWORD ProxyFlags;                           // flags for proxy     DWORD SendFlags;                            // send flags     BYTE ResponceHTML[INT_BUFFERSIZE];          // HTML from responce     WCHAR ResponceHeaders[INT_BUFFERSIZE];      // headers from responce     double Latency;                             // return indicating total time spent in request     int RetryTimes;                             // maximum times to retry request if failures happen     int MaxTestTime;                            // maximum time to spend in request     LPVOID httpSession;                         // Session handles returned to AutoIt     LPVOID httpConnect;                         // Session handles returned to AutoIt     LPVOID httpRequest;                         // Session handles returned to AutoIt };

I then pass the structure I created AutoIt side to the dll and it creates a thread and initializes the structure.

THREAD_PARAM_COMPONENTS* tData = (THREAD_PARAM_COMPONENTS*)threadData; // threadData is passed as an LPVOID to the thread

And then I start accessing the stuff I sent from my AutoIt script from inside the DLL...

...     hSession = ::WinHttpOpen(tData->UserAgent,                             tData->ProxyFlags,                             tData->Proxy,                             WINHTTP_NO_PROXY_BYPASS,                             0); ...

So far all that stuff works, requests are made and data was returned, up until I attempted to change my program from returning WCHAR data to a BYTE array. And now I get nothing but a ridiculous amount of zeros like "0x0000.... to infinity".

 

so far this is the problem var in both sides.

    BYTE ResponceHTML[INT_BUFFERSIZE];          // HTML from responce

This is my DLL codebase, unicode.

C++         
////////////////////////////////////////////////////////////////////////////////////////// // DLL to create multiple background WinHTTP requests. // Why? since AutoIt is single threaded, I need a nonblocking function to make requests. // Project is Unicode ////////////////////////////////////////////////////////////////////////////////////////// #include <Windows.h> #include <WinHTTP.h> #include <string> #include <time.h> #pragma comment(lib, "winhttp.lib") // need to link to lib using namespace std; // AutoIt thread parameters static const int INT_BUFFERSIZE = 1048576;    // Had to increase to 1MB because I was getting very big pages with some tests and it wouldn't work // AutoIt thread parameters, AutoIt will create a version of this and pass it as a thread paramater struct THREAD_PARAM_COMPONENTS {     WCHAR UserAgent[1024];                      // user agent     WCHAR HTTPVerb[1024];                       // POST/GET/HEAD etc     WCHAR Host[1024];                           // Domain name for target request     WCHAR Resource[1024];                       // resource at target     int Port;                                   // port on target     WCHAR Referer[1024];                        // referer     WCHAR Headers[1024];                        // headers string     LPVOID ExtraData;                           // additional data/paramaters to send     DWORD Length;                               // lenght of additional data     DWORD TotalLenght;                          // same as above for some reason     int dwResolveTimeout;                       // max time for resolving     int dwConnectTimeout;                       // max time for connection     int dwSendTimeout;                          // max time to wait while sending     int dwReceiveTimeout;                       // max time to wait for recieving responce     WCHAR Proxy[1024];                          // proxy for request     DWORD ProxyFlags;                           // flags for proxy     DWORD SendFlags;                            // send flags     BYTE ResponceHTML[INT_BUFFERSIZE];          // HTML from responce     WCHAR ResponceHeaders[INT_BUFFERSIZE];      // headers from responce     double Latency;                             // return indicating total time spent in request     int RetryTimes;                             // maximum times to retry request if failures happen     int MaxTestTime;                            // maximum time to spend in request     LPVOID httpSession;                         // Session handles returned to AutoIt     LPVOID httpConnect;                         // Session handles returned to AutoIt     LPVOID httpRequest;                         // Session handles returned to AutoIt }; DWORD WINAPI _WinHTTP_Process(LPVOID threadData); ////////////////////////////////////////////////////////////////////////////////////////// // Dll entry point ////////////////////////////////////////////////////////////////////////////////////////// BOOLEAN APIENTRY DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved) {     switch ( fdwReason )     {     case DLL_PROCESS_ATTACH:         DisableThreadLibraryCalls( hinstDLL );// disable callbacks on new threads, we don't need them.         break;     case DLL_PROCESS_DETACH:         break;     }     return TRUE; } // End of DllMain ////////////////////////////////////////////////////////////////////////////////////////// // The exported function of our DLL ////////////////////////////////////////////////////////////////////////////////////////// HANDLE WINAPI WinHTTP_Action(LPVOID threadData) {     return CreateThread(NULL,                         0,              // SIZE_T dwStackSize                         &_WinHTTP_Process,                         threadData,     // LPVOID threadData                         0,              // DWORD dwCreationFlag                         NULL);          // LPDWORD lpThreadId } // End of WinHTTP_Action ////////////////////////////////////////////////////////////////////////////////////////// // "The Thread" ////////////////////////////////////////////////////////////////////////////////////////// DWORD WINAPI _WinHTTP_Process(LPVOID threadData) {     // Initialize the structure that AutoIt sent us, threadData with internal equivalent THREAD_PARAM_COMPONENTS     THREAD_PARAM_COMPONENTS* tData = (THREAD_PARAM_COMPONENTS*)threadData;     // Timer     clock_t init, final;     wstring m_charset;     //DWORD dError;     const unsigned int INT_RETRYTIMES = tData->RetryTimes;     bool bRetVal = true;     HINTERNET hSession = NULL;     hSession = ::WinHttpOpen(tData->UserAgent,                             tData->ProxyFlags,                             tData->Proxy,                             WINHTTP_NO_PROXY_BYPASS,                             0); //Note: do not use async...     if (!hSession)         return false;     tData->httpSession = hSession;     WinHttpSetTimeouts(hSession,                         tData->dwResolveTimeout,                         tData->dwConnectTimeout,                         tData->dwSendTimeout,                         tData->dwReceiveTimeout);     HINTERNET hConnect = NULL;     hConnect = ::WinHttpConnect(hSession,                                 tData->Host,                                 tData->Port,                                 0 );     if (hConnect != NULL)     {         tData->httpConnect = hConnect;         HINTERNET hRequest = NULL;         hRequest = ::WinHttpOpenRequest(hConnect,                                         tData->HTTPVerb,                                         tData->Resource,                                         L"HTTP/1.1",                                         tData->Referer,                                         WINHTTP_DEFAULT_ACCEPT_TYPES,                                         tData->SendFlags);         if (hRequest != NULL)         {             tData->httpRequest = hRequest;             bool bGetReponseSucceed = false;             init = clock(); // start timer             double TotalTime;             if (!::WinHttpSendRequest(hRequest,                                     tData->Headers,                                     -1L, //<-- using wcslen()+1 seems to cause an invalid param error here so will stick with -1L                                     tData->ExtraData,                                     (DWORD) tData->Length,                                     (DWORD) tData->TotalLenght,                                     (DWORD) 0))             {                 // This is just here in case I need to refrence back to how to get and view the last error of a function                 //dError = GetLastError();                 //WCHAR temp[100];                 //swprintf_s(temp, 100, L"Error: %d" , dError);                 //MessageBox(0 , temp, L"Error!", 0);             }             else             {                 // Call was successfull, continue accepting whatever                 if (::WinHttpReceiveResponse(hRequest, NULL))                 {                     DWORD dwSize = 0;                     // Get the buffer size of the HTTP response header.                     BOOL bResult = ::WinHttpQueryHeaders(hRequest,                                                         WINHTTP_QUERY_RAW_HEADERS_CRLF,                                                         WINHTTP_HEADER_NAME_BY_INDEX,                                                         NULL,                                                         &dwSize,                                                         WINHTTP_NO_HEADER_INDEX);                     if (bResult || (!bResult && (::GetLastError() == ERROR_INSUFFICIENT_BUFFER)))                     {                         wchar_t *szHeader = new wchar_t[dwSize];                         if (szHeader != NULL)                         {                             memset(szHeader, 0, dwSize* sizeof(wchar_t));                             // Get HTTP response header.                             if (::WinHttpQueryHeaders(hRequest,                                 WINHTTP_QUERY_RAW_HEADERS_CRLF,                                 WINHTTP_HEADER_NAME_BY_INDEX,                                 szHeader,                                 &dwSize,                                 WINHTTP_NO_HEADER_INDEX))                             {                                 _wcslwr_s(szHeader, wcslen(szHeader)+1);                                 wstring lwrHeader = szHeader;                                 // get headers to our structure later                                 unsigned int iMaxBufferSize = INT_BUFFERSIZE; // Should proabbly be setting buffer size autoit side somehow                                 unsigned int iCurrentBufferSize = 0;                                 BYTE* m_pResponse = NULL;                                 m_pResponse = new BYTE[iMaxBufferSize];                                 memset(m_pResponse, 0, iMaxBufferSize);                                 do                                 {                                     dwSize = 0;                                     if (::WinHttpQueryDataAvailable(hRequest, &dwSize))                                     {                                         BYTE *pResponse = new BYTE[dwSize + 1];                                         if (pResponse != NULL)                                         {                                             memset(pResponse, 0, dwSize);                                             DWORD dwRead = 0;                                             if (::WinHttpReadData(hRequest,                                                 pResponse,                                                 dwSize,                                                 &dwRead))                                             {                                                 if (dwRead + iCurrentBufferSize > iMaxBufferSize)                                                 {                                                     BYTE *pOldBuffer = m_pResponse;                                                     m_pResponse = new BYTE[iMaxBufferSize * 2];                                                     if (m_pResponse == NULL)                                                     {                                                         m_pResponse = pOldBuffer;                                                         bRetVal = false;                                                         break;                                                     }                                                     iMaxBufferSize *= 2;                                                     memset(m_pResponse, 0, iMaxBufferSize);                                                     memcpy(m_pResponse, pOldBuffer, iCurrentBufferSize);                                                     delete[] pOldBuffer;                                                 }                                                 memcpy(m_pResponse + iCurrentBufferSize, pResponse, dwRead);                                                 iCurrentBufferSize += dwRead;                                             }                                             delete[] pResponse;                                         }                                     }                                 }                                 while (dwSize > 0);                                 final=clock()-init;                                 TotalTime = (double)final / ((double)CLOCKS_PER_SEC);                                 // Return anything regardless, unless it took too long                                 if (TotalTime < tData->MaxTestTime)                                 {                                     bGetReponseSucceed = true;                                     int p=0;                                     while (p < sizeof(m_pResponse)) {                                         if(m_pResponse[p] != NULL)                                             tData->ResponceHTML[p]=m_pResponse[p]; // write chars to our autoit char array so we can process it over at scriptside                                         p++;                                     }                                     swprintf(tData->ResponceHeaders, INT_BUFFERSIZE, L"%s" ,lwrHeader);                                     tData->Latency = TotalTime;                                 }                             }                         }                     }                 }             }             ::WinHttpCloseHandle(hRequest);         }         ::WinHttpCloseHandle(hConnect);     }     ::WinHttpCloseHandle(hSession);     return 1; } // End of _WinHTTP_Process

Everything looked like it should work right but obviously something is not going over as planned...

 

I create the thread like so~

AutoIt         
    Local $ContentType = _         "Connection: keep-alive" & @CRLF & _         "Cache-Control: no-cache" & @CRLF & _         "Pragma: no-cache" & @CRLF & _         "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" & @CRLF & _         "Accept-Language: en-US,en;q=0.8" & @CRLF & _         "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3" & @CRLF     $tURL_COMPONENTS = DllStructCreate($tagTHREAD_PARAMETERS)     DllStructSetData($tURL_COMPONENTS, "UserAgent", "(COMPATABLE; AutoIt/v3)")     DllStructSetData($tURL_COMPONENTS, "HTTPVerb", "GET")     DllStructSetData($tURL_COMPONENTS, "Host", "www.google.com")     DllStructSetData($tURL_COMPONENTS, "Resource", "test")     DllStructSetData($tURL_COMPONENTS, "Port", $INTERNET_DEFAULT_HTTPS_PORT)     DllStructSetData($tURL_COMPONENTS, "Referer", "")     DllStructSetData($tURL_COMPONENTS, "Headers", $ContentType)     DllStructSetData($tURL_COMPONENTS, "ExtraData", 0)     DllStructSetData($tURL_COMPONENTS, "Length", 0)     DllStructSetData($tURL_COMPONENTS, "TotalLength", 0)     DllStructSetData($tURL_COMPONENTS, "dwResolveTimeout", 30000)     DllStructSetData($tURL_COMPONENTS, "dwConnectTimeout", 30000)     DllStructSetData($tURL_COMPONENTS, "dwSendTimeout", 30000) ; 15 seconds     DllStructSetData($tURL_COMPONENTS, "dwReceiveTimeout", 30000)     If $Proxy Then         DllStructSetData($tURL_COMPONENTS, "Proxy", $Proxy)         DllStructSetData($tURL_COMPONENTS, "ProxyFlags", $WINHTTP_ACCESS_TYPE_NAMED_PROXY)     Else         DllStructSetData($tURL_COMPONENTS, "ProxyFlags", $WINHTTP_ACCESS_TYPE_NO_PROXY)     EndIf     DllStructSetData($tURL_COMPONENTS, "SendFlags", BitOR($WINHTTP_FLAG_SECURE, $WINHTTP_FLAG_ESCAPE_DISABLE))     ;DllStructSetData($tURL_COMPONENTS, "RetryTimes", 2); unused now     DllStructSetData($tURL_COMPONENTS, "MaxTestTime", 60)     $hThread = CreateThread(DllStructGetPtr($tURL_COMPONENTS)); dllcall() that will pass the structure pointer to the dll as "ptr"

then after creating the thread, the app idles around and waits for the thread to report it terminated.

Once the thread has finished doing its thing, it will write whatever it got my my BYTE array and return it.

The problem comes when I try to access it now...

DllStructGetData($tURL_COMPONENTS, "ResponceHTML")

DllStructGetData() will return the binary equivalent of "<!Doc" and then the rest will be zeros, garbage and totally not what I was expecting..

 

Any ideas?

 

I have included a ready to compile project with a script to test the DLL in the release directory.

 

Attached File  Full Project.zip   31.86KB   5 downloads


Viewing all articles
Browse latest Browse all 12506

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>