PDA

View Full Version : Dll Custom Action Fails to find Entry Point, but other programs do not (Basic MSI)



PickyPG
06-25-2004, 09:14 AM
This very urgent. I have been struggling to enable a Product Key (CD Key) activation process for the past week, and finally I have given up and I am now hoping an expert can help me.

As far as the Dll and Installer goes:

Everything compiles and builds correctly.

As far as the Dll goes:

It simply verifies the key is valid (returns 1 (TRUE)) or invalid (returns 0 (FALSE)). The code is written using C++, but externed to C to stop the decorating of the Dll names. Only one function is exposed, and it works perfectly under another program that I have written in C#.

// Working C# declaration:
[DllImport("VerifyKey.dll")]
private static extern int ValidateKey ( string szKey );

// C++ declaration:
extern "C" VALIDKEY_API BOOL ValidateKey ( const char *szProductKey );

As far as the installer goes:

// Installer declaration:
[Custom Action Name = ValidateProductKey]
Location: <bin>/ValidKey.dll
Function Signature: BOOL=[_IsValidKey] ValidKey::ValidateKey(in STRING=[PRODUCTKEY])
Return Processing: Synchronous (Ignores exit code)
In-Script Execution: Immediate Execution
Execution Scheduling: Always Execute
Silent Mode: No

// Called by:
CustomerInfo::Next::Event
([Event] [Argument] [Condition])
DoAction ValidateProductKey 1

It runs to the point that I ask it to run the Custom Action (upon clicking the Next button in the customer info dialog), but then it spits out an error (nonfatal because I use the return value as opposed to getting InstallShield to watch it): "Can not find the entry point of function 'ValidateKey', make sure it is exported." (by the way, Can not is really spelled Cannot).

Does anyone know why the one works (C#), but not the other (InstallShield)?

*Edited because I have also posted this on a newsgroup and copy/pasting messed with the spacing*

huntant
06-25-2004, 02:34 PM
MSI expects the function signature to be as follows:

DWORD __stdcall CustomAction( MSIHANDLE hInstall )

I don't think you can call a function without that type of signature (at least I have never tried).

You would need to use MsiGetProperty() inside your function to get the value of PRODUCTKEY.

Also, have you tried running dumpbin /exports on your dll to make sure that the signature is as you expect it?



Anthony

PickyPG
06-25-2004, 02:43 PM
The decorations don't occur when you extern to C.

As for the MSIHANDLE, are there any libraries that I must include to get access to the object?

Also, the function signature dialog that appears when I try to change the function signature does not list MSIHANDLE or DWORD as a return type, instead it lists the types that I was expecting to write the code using: BOOL and STRING (also HANDLE, I guess this would probably cover MSIHANDLE).

I should probably mention that I am not using any scripting to call this DLL, I am simply using the EVENTS in the dialog behaviour menu.

_doog_
06-28-2004, 07:00 AM
msiquery.h should give that to you
you should verify that the file covers version2 of the windows installer...

huntant
06-28-2004, 07:10 AM
You will need to include the msi.h file, and there is also a link dependency on msi.lib.

What type of action are you using? Usually a type 1 is used for api calls.



Anthony

PickyPG
06-28-2004, 08:51 AM
I have created a function that accepts an MSIHANDLE in hopes of fixing the problems. Function declaration:

extern "C" VALIDKEY_API uint __stdcall VerifyKey ( MSIHANDLE hInstaller );

[Note: uint is typedefed: "typedef UINT uint;" because I use uint throughout C# and wanted the similarity.]

UINT was used instead of DWORD because of an MSDN article that I read.

However, the same error occurs.

Anyone have any ideas?

Here is a picture of what I am doing:

_doog_
06-28-2004, 09:02 AM
to include your dll as CA, you should choose

- new MSI DLL (not new Standard DLL)
- the signature property of the CA should be only the function name. (not all params or stuff)
- your function should not be part of a class, it should be only the function
- if it does not work, you might consider to take a prog like depends and check the dll entry points so that your function is really exported and it is not decorated

PickyPG
06-28-2004, 10:17 AM
Thanks for the quick responses.

Is there anyway to use the return code? I return whether the key is valid or not and if it's not I do not want to allow the user to continue (but I don't want the program to close).

_doog_
06-28-2004, 10:20 AM
no, the return code is to indicate to msi that the ca has failed

if you want to return something, you should:
- set a property with the return value (MsiSetProperty)
- or modify the UI directly, if thats possible with your needs.

PickyPG
06-28-2004, 10:43 AM
You're awesome, thanks, the MsiSetProperty was exactly what I was looking for!

Now hopefully when this is compiled I can get it running.

PickyPG
06-28-2004, 11:48 AM
The Dll is failing to be connected for whatever reason (it no longer says that it cannot find entry point).

It's my understanding that the code is not even being run because the MessageBox at the top is not being displayed. However, if it's not an entry point issue then what could it be?

I've included the code that should be run (excluding the product key verifcation, which has no interaction with the window) with the relevant activation content. The Dll is definitely in the specified path. I had attempted to change the return type to be of type DWORD (unsigned long...), but to no avail, so I have since changed it back to the documented UINT.

Documentation Source: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/msigetproperty.asp

Thanks for your help.

[Note: uint is typedefed: "typedef UINT uint;" because I use uint throughout C# and wanted the similarity.]

_doog_
06-28-2004, 12:07 PM
i can't see an error
perhaps you forgot something to rebuild, so i would start rebuilding everything and checking everything is the latest version.

after that, i would create a verbose log file and see if there are any hints in there

PickyPG
06-28-2004, 02:41 PM
Well it seems that my InstallShield Developer 7 is dead or my system is corrupted (probably the former).

I just started a brand new project and loaded up the MSI DLL as a brand new custom action in hopes that it would refresh the MSI DB, or something to get it to work.

As my luck would have it, that was not the case; it's still broken, and yet I can get the exact same DLL to work in other projects (not InstallShield related).

Signs that it is infact InstallShield that is dead is that the "uninstaller" leaves the majority of the files on the system. Now, maybe this was a feature in InstallShield Developer 7, but I can only hope this is not the case, or that at the very least it is corrected in InstallShield X because otherwise that completely goes against my understanding of a user friendly install and uninstall process.

So right now I am pitying myself, but hopefully my time will not be wasted under InstallShield X, which I assume is a much more feature-complete product and I am looking forward to completing the installation process with it.

I would like to deeply thank you two for helping me and bearing with me on my probably stupid questions.