Archive: Problem with System::Call


Problem with System::Call
Hi,

I'm having a problem with a System::Call to an external DLL.
What I want to do is to port an existing InstallShield installer
for a driver to NSIS.
I've read the Readme, studied several examples but can't found what's wrong.


In a custom action of IS a SetupAPI calls are performed to copy/uninstall
an OEM inffile.

SetupCopyOEMInf/SetupUninstallOEMInf are declared as follows:

BOOL WINAPI SetupCopyOEMInf(
PCTSTR SourceInfFileName,
PCTSTR OEMSourceMediaLocation,
DWORD OEMSourceMediaType,
DWORD CopyStyle,
PTSTR DestinationInfFileName,
DWORD DestinationInfFileNameSize,
PDWORD RequiredSize,
PTSTR DestinationInfFileNameComponent
);


BOOL SetupUninstallOEMInf(
PCWSTR InfFileName,
DWORD Flags,
PVOID Reserved
);


I translated these into:

!define SETUP_COPY_OEM_INFA "SetupAPI::SetupCopyOEMInfA (t, t, i, i, *t, i, i, *t) i"
!define SETUP_UNINSTALL_OEM_INFA "SetupAPI::SetupUninstallOEMInfA (t, i, *i) i"


with the calls being:

System::Call '${SETUP_COPY_OEM_INFA} (r0,,0, 2, .r2, ${NSIS_MAX_STRLEN},, )'
System::Call "${SETUP_UNINSTALL_OEM_INFA} i(r1, 1, 0) .r3"


These calls don't work. :-(
I don't even get a return value except for "error" from GetLastError....

I've added Dumpstate::debug calls and MessageBox output to see stack and variables,
but it seems that the call is aborted before setting any return code.

Can somebody point out what I'm doing wrong?


I do have "SetPluginUnload alwaysoff" and "SetPluginUnload manual" and "System::Free 0"
of course, globally/in the respective section.


If I get this working I can start work on a NSIS module implementing/using
Microsoft DIF (Driver Installation Framework), which would really simplify
driver installations.




Here are the relevant code snippets:

Quote:

Function RegisterInf
;prototype BOOL WINAPI SetupCopyOEMInf(
; PCTSTR SourceInfFileName,
; PCTSTR OEMSourceMediaLocation,
; DWORD OEMSourceMediaType,
; DWORD CopyStyle,
; PTSTR DestinationInfFileName,
; DWORD DestinationInfFileNameSize,
; PDWORD RequiredSize,
; PTSTR DestinationInfFileNameComponent
;);
Exch $0 ; passed path to inf file
Push $1
Push $2
Push $3

SetOutPath $SYSDIR
${GetFileName} $0 $1 ; get filename part of path
Dumpstate::debug
System::Call '${SETUP_COPY_OEM_INFA} (r0,,0, 2, .r2, ${NSIS_MAX_STRLEN},, )'
Dumpstate::debug
Call CheckError

; return code is in $3
MessageBox MB_ICONINFORMATION|MB_OK "SetupCopyOEMInf ($0 / $2) returned $3 "
IntCmp $3 0 WriteToReg
StrCpy $2 ""
WriteToReg:
; result is in $2
WriteRegStr ${NSIS_REGISTRY_ROOT} "Software\${OEM}\${PRODUCT}" "$1" "$2"

Pop $3
Pop $2
Pop $1
Exch $0

FunctionEnd

Function un.RegisterInf
;prototype BOOL SetupUninstallOEMInf(
; PCWSTR InfFileName,
; DWORD Flags,
; PVOID Reserved
;);
Exch $0 ; passed path inf file name
Push $1
Push $2
Push $3

; result is in $1
ReadRegStr $1 ${NSIS_REGISTRY_ROOT} "${NSIS_REGISTRY_PRODUCTPATH}" "$0"
${un.GetFileName} $1 $2 ; get filename part of path

StrCmp $OSVersion 'W2K' Case_W2K

System::Call "${SETUP_UNINSTALL_OEM_INFA} i(r1, 1, 0) .r3"
; return code is in $3
MessageBox MB_ICONINFORMATION|MB_OK "SetupUninstallOEMInfA ($0 / $1) returned $3 "
StrCpy $0 $3
IntCmp $3 0 Done
goto Done

Case_W2K:
StrCpy $0 ""
SetFileAttributes $1 FILE_ATTRIBUTE_NORMAL
Delete $1
IfErrors 0 Done
StrCpy $0 "1"

Done:
Pop $3
Pop $2
Pop $1
Exch $0

FunctionEnd

Function CheckError
Push $0
System::Call "Kernel32::GetLastError ()i ().r0"
Dumpstate::debug
MessageBox MB_ICONINFORMATION|MB_OK "Error code: $0 "
Pop $0
FunctionEnd Call in section:
:
StrCpy $0 "$INSTDIR\${MY_DRIVERNAME}.inf"
Push $0
Call RegisterInf
Pop $R0
IntCmpU $R0 0 InfError InfError
:

Have a look at SetupCopyOEMInf and SetupUninstallOEMInf

I would define the calls as:

System::Call 'Setupapi.dll::SetupCopyOEMInfA(t r1,t r2,i r3, i r4,*t .r5,i r6,*i .r7,*t .r8)i.r9'
System::Call 'Setupapi.dll::SetupUninstallOEMInfA(t R1,i R2,)i.R3'
So in your case it would become
System::Call 'Setupapi.dll::SetupCopyOEMInfA(t r0,t "",i 0, i 2,*t .r2,i ${NSIS_MAX_STRLEN},*i .r3,*t .r4)i.R0'
System::Call 'Setupapi.dll::SetupUninstallOEMInfA(t r1,i 2,)i.R1'
The first one should give you 1 (success) or 0 (fail) on $R0 and the second one should give you 1 (success) or 0 (fail) on $R1 and GetLastError will give you extended info in either case
Hope this helps
CF

PS note that you should have admin privileges to call these functions, so you may want to add the appropriate code to make sure that the user running your app has sufficient privileges.

Hi,

thanks to your example i was able to resolve the problem.

Originally posted by CancerFace
Have a look at SetupCopyOEMInf and SetupUninstallOEMInf
Although the calls do NOT return the values in the variables as described by MS, using Dumpstate::debug I was able to find out which variables to use.

No I'm out for implementing the interface to DIF.

Regards,
Axel