We ship a DDEX provider with Connector/Net. This provider plugs into Visual Studio and integrates into server explorer allowing a user to create data connections to MySQL from within the IDE. This integration is handled, in large part, by a lengthy series of registry entries. Until 5.2.2, these entries were made by my installer which is written in WiX. Having the registry changes made in the installer has two problems. First, I often need to register the provider during debugging and I don't want to do a full install of the product so I end up hand editing a registry file and manually merging that file. This a awkward at best. Second I plan to ship a stand-alone configuration utility in 5.3 that will allow the user to configure which installed version of Connector/Net should be used for VS integration. Currently you can only have one instance installed at a time.
My approach to solving this was to write an installer class that made the registry changes for me and just use installutil to register the assembly. I was already doing this with my core and web assemblies so this is nothing new. The problem is that installutil will scan the assembly and all referenced assemblies for types looking for installer classes. This fails when some of the Microsoft assemblies are scanned. After much effort I gave up and decided to write my own installutil that I would ship with my installer.
I had no trouble creating this application and then set about executing it from within my installer. I attempted to use the CAQuietExec custom action available with WiX v3 but just couldn't make it work right. So I gave up and decided to write my own execute custom action.
So I cracked open Visual Studio 2008 and read a couple of blogs about custom action writing. One of them mentioned mixing managed and unmanaged code, the unmanaged code being necessary for the proper DLL exports. I decided I had to see this work.
Within minutes I had a DLL project setup with the /clr option and had hacked out the following code:
1: extern "C" __declspec(dllexport) UINT InstallAssembly(MSIHANDLE hMSI)
2: {
3: System::Windows::Forms::MessageBox::Show("boo");
4: TCHAR name[261]={0};
5: DWORD len=261;
6:
7: UINT result = ::MsiGetProperty(hMSI, TEXT("CustomActionData"), name, &len);
8: InstallVSAssembly(name, true);
9: return ERROR_SUCCESS;
10: }
11:
12: bool InstallVSAssembly(char *assemblyName)
13: {
14: String^ str = gcnew String(assemblyName);
15: bool uninstalling = false;
16: IDictionary mySavedState = new Hashtable();
17: int arg = 0;
18:
19: InstallContext context = new InstallContext();
20: while (arg < args.Length)
21: {
22: string[] parts = args[arg++].Split('=');
23: context.Parameters.Add(parts[0], parts[1]);
24: }
25:
26: Installer installer = null;
27: try
28: {
29: Assembly assem = Assembly.LoadFrom(file);
30: installer = (Installer)assem.CreateInstance("MySql.Data.VisualStudio.MyInstaller");
31: if (installer == null)
32: {
33: Console.WriteLine("Unable to find an installer in that assembly.");
34: return;
35: }
36: installer.Context = context;
37: if (uninstalling)
38: installer.Uninstall(mySavedState);
39: else
40: installer.Install(mySavedState);
41: }
42: catch (Exception e)
43: {
44: Console.WriteLine(e.Message);
45: }
46: return true;
47: }
Yes, that is managed code and unmanaged code *in the same function*! Now this code might not compile as it is not what I wound up using and I just grabbed it out of an old folder but you get the idea (and yes I did test a version of this so I know the concept works). I didn't use this approach because the /clr switch requires the dynamic CRT and I didn't feel like bundling that up.
And, in case you were wondering about the "boo" messagebox on line 3, that is my debugging trap. You run the installer until that pops up, attach to the proper msiexec using Visual Studio, set a break point, and go. Yup, that's cool.
this nice code for assembler.. now i notice is still working with it...
ReplyDeletenow i notice is still working with it... wow
ReplyDeletenice code
ReplyDeleteThank you for that very helpful explanation.
ReplyDeletethanks for the code ...
ReplyDeletewhat agreat code, thank you
ReplyDeleteThanks for the code.
ReplyDeleteThis is a great code. Thanks for sharing it.
ReplyDeletenow i notice is still working with it... wow
ReplyDeleteImplementing a DDEX provider requires that you implement certain required procedures. In addition, you can implement optional procedures. The topics included in this section provide guidance on implementing a DDEX provider under various circumstances and in different implementation scenarios.
ReplyDeleteThe Windows Installer XML toolset (WiX, pronounced "wicks"), is a free software toolset that builds Windows Installer (MSI) packages from an XML document. It supports a command-line environment that developers may integrate into their build processes to build MSI and MSM setup packages. This is the first software released by Microsoft under an open-source license called Common Public License.
ReplyDeleteThis post was really great explanation of this issue!
ReplyDeleteRegards Matty
You provided exactly what I was looking for!
ReplyDeletenow i notice is still working with it... wow
ReplyDeleteI cracked open Visual Studio 2008 and read a couple of blogs about custom action writing. One of them mentioned mixing managed and unmanaged code, the unmanaged code being necessary for the proper DLL exports. I decided I had to see this work.
ReplyDeleteMixed mode was always cool :)
ReplyDeletezi jin mian
ReplyDeleteWould you like to post a guest post on my blog?
ReplyDeleteThank you for sharing this blog post. I've bookmarked the page :)
ReplyDeleteNow this is hghly recommeded post for me. I will surely email this to my friend.
ReplyDeleteRegards
paul
cool code
ReplyDeletethanks
Cool, thank you!
ReplyDeleteCreative Biomart www.creativebiomart.net