Calling Managed .Net DLL From NSIS: Difference between revisions
Claesabrandt (talk | contribs) No edit summary |
Claesabrandt (talk | contribs) No edit summary |
||
Line 1: | Line 1: | ||
{{PageAuthor|claesabrandt}} | {{PageAuthor|claesabrandt}} | ||
Please note that I have created a new NSIS plug-in, that can call methods in your managed .NET DLL. See the NSIS forum [http://forums.winamp.com/showthread.php?s=&threadid=295881 thread] (it's the second post with an attachment). The plug-in is now fully functional, but still undergoes some development and changes. When the plug-in is completed and tested okay, a new wiki page will be created in the plug-ins section, which more or less replaces this article. | |||
== Introduction == | == Introduction == | ||
Line 50: | Line 53: | ||
2) Create another script that includes your C# DLL and setup1.exe. In .onGUIInit it copies them to $TEMP, then executes setup1.exe. When setup1.exe runs and calls the C++/CLR DLLs, which in turn calls the C# DLLs, the .NET framework can find the C# DLLs. When setup1.exe finishes, you delete both the C# DLL and setup1.exe then call abort. You will never see the first installer. | 2) Create another script that includes your C# DLL and setup1.exe. In .onGUIInit it copies them to $TEMP, then executes setup1.exe. When setup1.exe runs and calls the C++/CLR DLLs, which in turn calls the C# DLLs, the .NET framework can find the C# DLLs. When setup1.exe finishes, you delete both the C# DLL and setup1.exe then call abort. You will never see the first installer. | ||
[[Category:Code Examples]] | [[Category:Code Examples]] |
Revision as of 09:09, 19 August 2008
Author: claesabrandt (talk, contrib) |
Please note that I have created a new NSIS plug-in, that can call methods in your managed .NET DLL. See the NSIS forum thread (it's the second post with an attachment). The plug-in is now fully functional, but still undergoes some development and changes. When the plug-in is completed and tested okay, a new wiki page will be created in the plug-ins section, which more or less replaces this article.
Introduction
This page shows how to call methods in a managed .NET DLL from NSIS using the System::Call function.
If you want to call methods in a C# DLL from NSIS, it is required that you write a wrapper around it. This is VERY simple. Managed C++/CLR allows you to create a DLL with an interface that NSIS understands, and you get all the benefits of having access to both the Win32 library and the .NET library. From your C++/CLR DLL, you can then instantiate any C# class and call it's methods or you can call static methods without instantiating any classes.
One thing you should know is, when you call a .NET DLL from NSIS, your installer will be dependent upon the .NET framework. The NSIS documentation contains information on how to detect the presence of the framework and how to download and install it if nessecary.
Setting up your C++/CLR project
I assume you already have your C# DLL ready with some classes and methods in it you want to call. If you have this in a solution, you can now add a new project to the solution, select C++ CLR, then select Class Library. This will generate a managed C++/CLR DLL and this is the DLL you will be calling from NSIS. Remember to add your C# project as a reference in your C++/CLR project.
The wizard will have created a sample C++ class in a sample namespace. You do not need this and you can delete the h file, empty the cpp file and then you are ready to write your DLL code. On last thing is to remove precompiled headers in the project: Project > Properties > Configuration Properties > C/C++ > Precompiled Headers > Create/Use Precompiles Header > Set to "Not Using Precompiles Headers".
The cpp file
Write a function for each C# method you want to call. The functions should look like this:
extern "C" __declspec(dllexport) char* HelloWorld() { // get a string from your C# method (in this case it is a static method) System::String ^str = MyNamespace::MyClass::HelloWorld(); // convert string to char* (this is one line) char* chp = (char*)(void*)System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi(str); // return the char* to NSIS return chp; }
And now your wrapper is done! To call the function from NSIS:
SetOutPath $PLUGINSDIR System::Call 'DLLName::HelloWorld(v) t .r0'
This will return the string in register $0. You can have parameters too. For more information, see the System::Call documentation.
Make sure to include both the C++/CLR DLL and the C# DLL in your installer and place them in for instance the $PLUGINSDIR. When calling the C++/CLR DLL with System::Call, be sure to make a call to SetOutPath $PLUGINSDIR first, so NSIS can find the DLLs.
[EDIT]:
I found out that the installer cannot find the C# DLL when running the installer. To fix this:
1) Create your script that calls your C++/CLR DLL which then in turn calls your C# DLL. This is what is described above. But do not copy your C# DLL file in this script. Resulting exe could be for instance setup1.exe
2) Create another script that includes your C# DLL and setup1.exe. In .onGUIInit it copies them to $TEMP, then executes setup1.exe. When setup1.exe runs and calls the C++/CLR DLLs, which in turn calls the C# DLLs, the .NET framework can find the C# DLLs. When setup1.exe finishes, you delete both the C# DLL and setup1.exe then call abort. You will never see the first installer.