Skip to content
⌘ NSIS Forum Archive

System::Call and proprietary DLL

11 posts

Re DeL SiLeNziO#

System::Call and proprietary DLL

Hi all,
I've write a simple function (for now a test function) and I've created a DLL..
In order to call my dll (calling httpPost.dll) I'm using System::Call in this way:

System::Call 'httpPost::test'
My DLL is called: httpPost.dll and my function is:
void test (void) {
...
....
.....
}
In this way I don't see my trace, in the DLL, it seems that is not called correctly.
I'm doing something wrong?

Thanks!
Anders#
You have not provided a lot of information here but my guess is that the function export has some decoration (c++, stdcall or both).

Try EXTERN_C void __cdecl test(void)
Re DeL SiLeNziO#
Sorry...

my dll:

#include "stdafx.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

#include <stdio.h>
#include "curl-7.28.0\include\curl/curl.h"

EXTERN_C int __cdecl test(void);

int test( void )
{
CURL *curl;
CURLcode res;
char* jsonObj = "{ \"name\" : \"Carmine\" , \"age\" : \"30\" }";
struct curl_slist *headers = NULL;
FILE *log;

log = fopen ( "C:\\Temp\\CURL.log", "w+" );
if ( !log )
{
MessageBox(NULL, (LPCWSTR)L"NO file opened!\n", (LPCWSTR)L"ALERT!!!", MB_OK);
goto abort;
}
else
MessageBox(NULL, (LPCWSTR)L"Continue...!\n", (LPCWSTR)L"LOG INITIALIZATION", MB_OK);

fprintf ( log, "%d:%s - INIZIO LIBRERIA\n", __LINE__, __FUNCTION__ );

curl = curl_easy_init();
if ( curl )
{
// curl_easy_setopt( curl, CURLOPT_FOLLOWLOCATION, 1L );
curl_slist_append(headers, "Accept: application/json");
curl_slist_append(headers, "Content-Type: application/json");
curl_slist_append(headers, "charsets: utf-8");
curl_easy_setopt( curl, CURLOPT_URL, "http://127.0.0.1:4488" );
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonObj);
res = curl_easy_perform(curl);


/* Perform the request, res will get the return code */
res = curl_easy_perform( curl );
/* Check for errors */
if ( res != CURLE_OK )
fprintf( stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror( res ) );

/* always cleanup */
curl_easy_cleanup( curl );
}
abort:
if (log)
fclose ( log );
return 0;
}
I've added
EXTERN_C int __cdecl test(void);
but my file and my message box don't work!
Re DeL SiLeNziO#
my dll:

#include "stdafx.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

#include <stdio.h>
#include "curl-7.28.0\include\curl/curl.h"

EXTERN_C int __cdecl test(void);

int test( void )
{
CURL *curl;
CURLcode res;
char* jsonObj = "{ \"name\" : \"Carmine\" , \"age\" : \"30\" }";
struct curl_slist *headers = NULL;
FILE *log;

log = fopen ( "C:\\Temp\\CURL.log", "w+" );
if ( !log )
{
MessageBox(NULL, (LPCWSTR)L"NO file opened!\n", (LPCWSTR)L"ALERT!!!", MB_OK);
goto abort;
}
else
MessageBox(NULL, (LPCWSTR)L"Continue...!\n", (LPCWSTR)L"LOG INITIALIZATION", MB_OK);

fprintf ( log, "%d:%s - INIZIO LIBRERIA\n", __LINE__, __FUNCTION__ );

curl = curl_easy_init();
if ( curl )
{
// curl_easy_setopt( curl, CURLOPT_FOLLOWLOCATION, 1L );
curl_slist_append(headers, "Accept: application/json");
curl_slist_append(headers, "Content-Type: application/json");
curl_slist_append(headers, "charsets: utf-8");
curl_easy_setopt( curl, CURLOPT_URL, "http://127.0.0.1:4488" );
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonObj);
res = curl_easy_perform(curl);


/* Perform the request, res will get the return code */
res = curl_easy_perform( curl );
/* Check for errors */
if ( res != CURLE_OK )
fprintf( stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror( res ) );

/* always cleanup */
curl_easy_cleanup( curl );
}
abort:
if (log)
fclose ( log );
return 0;
}
I've added
EXTERN_C int __cdecl test(void);
but my file and my message box don't work!
JasonFriday13#
Just a tip I use: I don't declare exported functions at the top of my source, and I always put them at the bottom of my source (along with the main entry point) so that they are different from the private functions.

Example in C:
__declspec(dllexport) void Show(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop, extra_parameters* xp)
{
Initialize(xp);
privatefunctioncall(hwndParent, string_size, variables, stacktop); // example call that passes the exported variables
}

UINT_PTR __cdecl NSISPluginCallback(enum NSPIM Event)
{
if (Event == NSPIM_GUIUNLOAD) {
// unload and cleanup code goes here
}
return 0;
}

BOOL WINAPI DllMain(HINSTANCE hInst, DWORD ul_reason_for_call, LPVOID lpReserved)
{
if (ul_reason_for_call == DLL_PROCESS_DETACH) {
// unload and cleanup code goes here
}
return TRUE;
}
Example in C++:
extern "C" __declspec(dllexport) void Show(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop, extra_parameters* xp)
{
Initialize(xp);
privatefunctioncall(hwndParent, string_size, variables, stacktop); // example call that passes the exported variables
}

UINT_PTR __cdecl NSISPluginCallback(enum NSPIM Event)
{
if (Event == NSPIM_GUIUNLOAD) {
// unload and cleanup code goes here
}
return 0;
}

extern "C" BOOL WINAPI DllMain(HINSTANCE hInst, DWORD ul_reason_for_call, LPVOID lpReserved)
{
if (ul_reason_for_call == DLL_PROCESS_DETACH) {
// unload and cleanup code goes here
}
return TRUE;
}
Anders#
I did not put declspec in my example because I assumed a .def file was used but I guess we don't really know.

With these export issues we need as much information as possible. Compiler switches can change the default calling convention from cdecl to stdcall and gcc has several options related to how functions are exported...
Re DeL SiLeNziO#
mmm I don't understand... where is my error?!
I simplified my code, for test the call, in:


//httpNSI.h

#ifdef HTTPNSI_EXPORTS
#define HTTPNSI_API __declspec(dllexport)
#else
#define HTTPNSI_API __declspec(dllimport)
#endif

namespace HttpOp
{
class Operation
{
public:
static HTTPNSI_API void Test( void );
};
}

/* EoF */
// httpNSI.cpp : Defines the exported functions for the DLL application.
//

#include "stdafx.h"
#include "httpNSI.h"
#include <stdexcept>
#include <stdio.h>

using namespace std;

namespace HttpOp
{
void Operation::Test()
{
FILE *log;

log = fopen ( "C:\\Temp\\CURL.log", "a+" );
if ( !log )
{
MessageBox ( NULL, (LPCWSTR)L"NO file opened!\n", (LPCWSTR)L"ALERT!!!", MB_OK );
goto abort;
}
else
MessageBox( NULL, (LPCWSTR)L"Continue...!\n", (LPCWSTR)L"LOG INITIALIZATION", MB_OK );

fprintf ( log, "%d:%s - INIZIO LIBRERIA\n", __LINE__, __FUNCTION__ );
abort:
if (log)
fclose ( log );
return;
}
}

/* EoF */
and in my nsis installer I use to call Test():
CLR::Call /NOUNLOAD "httpNSI.dll" "HttpOp.Operation" "Test"
In dllmain.cpp I did understand what I have to add and so, it's already wrote like the wizard do.
Now the error is from CLR plugin:

Error calling .NET DLL method
Impossibile caricare il file o l'assembly '29184 bytes loaded from NSIS CLR Loader,
Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' o una delle relative
dipendenze. Tentativo di caricare un programma con un formato non corretto.
Sorry... part of error message is in italian.. 😢
Re DeL SiLeNziO#
OK,
I fixed a step in the stone: I'm now able to call the dllmain.cpp with System::Call 'httpNSI::Test' I see my trace log in dllmain.

Now... There's a parameter in dllmain that tell me that I want to call Test() function?
I Suppose that I will have to create a case in my DLL_PROCESS_ATTACH in dllmain that says if is "Test" parameter from NSIS call, calls Test() function... is ok!?
Anders#
No, you are not supposed to do much work in dllmain, you can save the hinstance in a global if you need it later, other than that, just return true.

After dllmain has been called your test function will be called if it is exported with the correct name, if not, take a look at your dll in dependencywalker.com!
Re DeL SiLeNziO#
Ok, the problem was the header C++ file...
I'm rewrote the file in C with the extern C and it works fine!
Now I've another problem calling an exe file, but I'm going to open a new thread!

Thanks so much!!!!