Archive: Using external DLL's


Using external DLL's
  I'm developing a Palm app & conduit. As part of the installation, the conduit has to be 'registered' with the Palm Hotsync manager using functions in the palm supplied "CondMgr.dll".

How do I call/use functions in an external DLL? I've looked in the "System.dll" add on by brainsucker, but I'm not a Windows programmer and things aren't making much sense to me....

All help/pointers/links gratefully accepted.


For this you will first have to know how exactly that function that you want to call was defined. If it's a regular registration function (DllRegisterServer) then you can just use RegDLL. If it's anything else you'll have to know the exact prototype (how the function was defined) and use System.dll to call it. If you get me the prototype I can help you write the line you need to use with System.dll.


KiCHiK, he's not a Windows programmer. With all you definition, regular registration and prototype talk, I think that you made him even more confused than he already is.


Virtlink, I think he can answer by himself... If he could have typed the first post he must have a keyboard or at least a voice recognition application and a microphone... ;)


To be fair KiCHiK not only posted helpful information but offered to help further if needed. I don't think there is a non techy answer to the original question so I think KiCHiK did the only thing anyone can for a non-programmer. I'm sure given more time KiCHiK would gladly write the solution to this particular problem but he can't do that *and* try to perfect NSIS *and* be a forum moderator all at the same time!


Thank you Sunjammer :D


Hi kichik,

According to the DLL doco, the function I need to us is defined as:

int CmGetHotSyncExecPath(TCHAR *pPath, int *piSize);

where
pPath is a pointer to a character buffer. Upon return, this is the path & file name of the installed HotSync manager.

piSize is a pointer to an integer that specifies the size (in TCHAR's), of the buffer referenced by the pPath parameter.

result: 0 if no error, else error value

Thanks for the offer of help. Sorry to take so long to reply, but I'm in Australia and have only just got out of bed! As Sunjammer notes, there is probably no non-technical answer to this question. As I noted before, I'm not a Windows programmer (certainly not to this level) - embedded micro's are more my area.

Thanks again for the assistance.


Hmm I've just spent half an hour staring at System.txt, System.nsh,SysFunc.nsh and System.nsi. I feel like I'm soo close to being able to tell you how to use the System plugin to do this but I have to be honest, I can't quite work it out.

If anyone else can help the point I got stuck on is this: the function populates a string, fair enough, so I use System::Alloc to alloc some space but then after the call when I've filled that space how on Earth do I get that string from the memory in the System plugin into an NSIS variable? (the variable populated by the System::Alloc call contains a pointer which is no use, I want a variable containing the string itself).

The docs are, ahem, somewhat greek even to someone who regularly uses Windows API calls. It mostly makes sense, but I can't seem to find an example of how to deal with a function that populates a char array, all I can find is how to extract values from structures... so close and yet so far!

I'm off to bed now, good luck!


Thanks for spending the time Sunjammer. I'm glad I'm not the only one who finds the System plugin doco a bit cryptic.

Hopefully someone else has had to do this and can pass on their knowledge....


Everyone has problems with that cryptic documentation, so flizebogen and Dark_boy are going to rewrite the documentation and I (propably some others also) will help.


If I understand you correctly virtlink then it's great that not only the core NSIS documentation will be revised but also that of the plugins, especially System! :D


Sunjammer, you are dreaming. The only one that can rewrite that readme is Brainsucker himself :p

Anyway, back to the original subject... I know Sunjammer has already sent you a little DLL that does this but I still had to give it a go :D

Try:

SetOutPath "C:\\Palm\\DLL\\Path"

>StrCpy $1 ${NSIS_MAX_STRLEN}
>System::Call 'dll_name::CmGetHotSyncExecPath(t, *i) i(.r0, .r1).r2'
>DetailPrint 'Path: "$0"'
>DetailPrint "Path length (I think): $1"
>DetailPrint "Return value: $2"
Use this with the latest CVS version and it should work. Even if Sunjammer's DLL worked, please try this, I am curious :)

I think you're being optimistic KiCHiK, theoretically my DLL should work but whether or not I got it right first time who knows... then again theoretically it should be easily done using System too :)


Optimisem rocks! :p
You'll see... One day, I am telling you! One day I will know how to use System.dll! :D


OK, I tried kichik's code, using the latest CVS Zip file from Sourceforge. Unfortunately, no go. My code:


SetOutPath $TEMP\eInspect ; create temp directory
File bin\CondMgr.dll ; copy dll there

StrCpy $1 " " 1024
System::Call 'CondMgr::CmGetHotSyncExecPath(t, *i) i(.r0, .r1).r2'
DetailPrint 'Path: "$0"'
DetailPrint "Path length (I think): $1"
DetailPrint "Return value: $2"


and the results:


Output folder: c:\windows\TEMP\eInspect
Extract: CondMgr.dll
Path: ""
Path length (I think): 25
Return value: -1010


Do I have to use "RegDll" before I can run this code?

I've attached a zipped version of the DLL in question.

Another question:
Can you please explain the syntax in the System::Call command you are using?


System::Call 'CondMgr::CmGetHotSyncExecPath(t, *i) i(.r0, .r1).r2'


My understanding is:
'CondMgr::CmGetHotSyncExecPath(t, *i) i' is the call to the function where t is a text string, *i is a pointer to an integer and i is an integer return value.
I also understand that r0, r1 & r2 map to the NSIS variables $0, $1, $2 respectively.
What do the '.' (dots) signify? And why is the variable list presented after the function definition?

Thanks for the assistance.

It should be:


StrCpy $1 1024 

>
not:

StrCpy $1 " " 1024 

>
Your code copied the first 1024 chars of the string " ". I will try this myself too now that I have the DLL, and let you know.

It will also be better if you use ${NSIS_MAX_STRLEN} instead of 1024, so you can be sure it's the right number.

Now, for the command itself:
'CondMgr::CmGetHotSyncExecPath(t, *i) i' is indeed the prototype of the function. The last 'i' is the return type. The second list is the actualy parameters that are passed on. The dot "makes no change to source". I have no idea why we need this, but it worked with wsprintf this way. I have tried this DLL on my computer with HotSync running but it returned error -1010 yet again. Can you please find out what that error means from this DLL's docs?

KiCHiK, what does System do about calling conventions? Windows API calls are __stdcall but I have a feeling this dll is __cdecl.


Nope Sunjammer, __stdcall. Just checked that with VC. Can't get it to work with VC either though =/
It returns 0, 1 in the int pointer and nothing in the path.

Try this one please:
System::Call 'CondMgr::CmGetHotSyncExecPath(t, *i) i(.r0, r1).r2'


Morning All.

kichik, I tried the code


StrCpy $1 1024 

>
and my compiler barfed. I'll try to check out the latest CVS build again this morning and try the code again.

Error codes from this function:

0: No error
-1: A non-specific error occurred
ERR_REGISTRY_ACCESS(-1006):Unable to access the Palm configuration entries
ERR_BUFFER_TOO_SMALL(-1010): The buffer is too small to hold the requested information
ERR_INVALID_POINTER(-1013):The specified pointer is not a valid pointer

Also, if the buffer is too small the value in *int is the size (in TCHARs) that the buffer should be.

YeeHa!

We're away. Tried the latest mods that kichik suggested (i.e. remove the '.' from the pointer variable) and we're up.

Calling loadDll
Output folder: c:\windows\TEMP\eInspect
Extract: CondMgr.dll
Path: "C:\Dave\palm\Hotsync.exe"
Path length (I think): 1024
Return value: 0
Sunjammer: I'll try your DLL as well after breakfast.

Thanks **VERY** much everyone for the assistance, and for the excellent installer package.

DJC: Don't bother with the DLL, system is a much better solution.

Could you do me a real favour please, pretty please :) Could you create a page in the Archive showing how to call your DLL function using System. It doesn't matter that others don't have your DLL, it shows a use of System that had to be figured out and that's worth showing to others.


Sunjammer: I've posted up an example in the Archive as you suggested. See

'Calling an external DLL using the System.dll plugin'

in the examples section.

Thanks everyone for your assistance anf forebearance.


Told you optimisem rocks :D