Hi SlyW. From your .NET dll, are you calling further into other .NET dlls?
Calling managed .NET DLL from NSIS - this works :-)
112 posts
None of my writing...
It is calling the System.Cryptography classes, but no other .NET DLLs of my creation.
I have attached complete source code to this message including the source of my encryption library.
Thanks!
-SlyW
It is calling the System.Cryptography classes, but no other .NET DLLs of my creation.
I have attached complete source code to this message including the source of my encryption library.
Thanks!
-SlyW
SlyW, I am looking into it, but at the moment I am a bit clueless about it, as it sounds like NSIS can't load the plugin. I guess you don't have problems with other plugins on those machines? I am thinking of if you could try installing the Visual C++ 2005 redist on those machines. That should not be needed, but maybe you have found a scenario where it is needed. It is the CLR.dll it cannot find, right? Not your crypto dll.
I will try...
I will install the VC++ redist on one of the machines upon which the installer fails and let you know the progress. I would have done it already had I not been required to attend parent-teacher conferences.
Thanks for your excellent responses so far!
I will install the VC++ redist on one of the machines upon which the installer fails and let you know the progress. I would have done it already had I not been required to attend parent-teacher conferences.
Thanks for your excellent responses so far!
No luck. Installed the VC++ 2005 Redist on one of the XP machines with the same results. Could not load CLR.dll and the value popped was the name of the encryption DLL.
Thanks for the testing. This sounds like a problem rbchasetfb encountered back in the beginning of september. Back then we fixed it by making sure the DLL was compiled using Visual Studio 2005 and not 2008, as it seems it fixed it then. But I will have to look further into why NSIS fails to load the DLL in some cases. My first tasks is to reproduce the error myself. I might ask additional questions of you, to reproduce your scenario.
Ask away! And I will see if I can get VS.NET C++ installed locally. I might try installing VS.NET C++ on one of the machines where it fails and see if it helps. I know that VS.NET is installed on all three failing machines, however, only the VB.NET and Web Developer components are installed.
If there are debug flags you want me to use, please do not hesitate to ask.
If there are debug flags you want me to use, please do not hesitate to ask.
My CLR.exe based DLL works on some machines and not others.
What I know:
Win XP SP2 w/.NET 2/3/3.5 works
Vista SP1 w/.NET 2/3/3.5 works
Win 2003 w/.NET 2/3/3.5 works
Win 2003 w/.NET 2 DOES NOT WORK
What I know:
Win XP SP2 w/.NET 2/3/3.5 works
Vista SP1 w/.NET 2/3/3.5 works
Win 2003 w/.NET 2/3/3.5 works
Win 2003 w/.NET 2 DOES NOT WORK
I'll add some other successful test environments:
Win 2003 w/SP1 or SP2 and a minimum of .NET 2.0 SP1
Win XP SP2 with a minimum of .NET 2.0 SP1
The catch is the SP1 version of .NET 2.0. The CLR plugin on DotNET 2.0 without SP1 will not work on any of these environments. The reason your .NET 2/3/3.5 works is the .NET 3 and 3.5 installers install the .NET 2.0 SP1 patches. claesabrandt, that's why the VS2005 compiled CLR only works on this .NET 2.0 SP1 setup...because you have installed .NET 3 and/3.5.
To overcome this, I've added a prerequisites custom page to my installers, right after my license page, that checks for and downloads, installs/upgrades .NET 2.0 SP1 before any calls to the CLR plugin. I use the CLR plugin in custom pages after the components selection page. If this sequence doesn't work for you, you can put a .NET check-download-and-install into the .onInit. A recommended .onInit would do some conformance checks anyway, so here's a good order:
1. Check if installer is already running, if so abort
2. Check for local admin rights, if not, abort
3. Check for and Install IIS (if installing a web site on IIS)
4. Check for and Install .NET 2.0 SP1
It took me some time to figure this one out - and lots of VirtualMachine undo drive wipes - so I hope this saves you all some time.
Win 2003 w/SP1 or SP2 and a minimum of .NET 2.0 SP1
Win XP SP2 with a minimum of .NET 2.0 SP1
The catch is the SP1 version of .NET 2.0. The CLR plugin on DotNET 2.0 without SP1 will not work on any of these environments. The reason your .NET 2/3/3.5 works is the .NET 3 and 3.5 installers install the .NET 2.0 SP1 patches. claesabrandt, that's why the VS2005 compiled CLR only works on this .NET 2.0 SP1 setup...because you have installed .NET 3 and/3.5.
To overcome this, I've added a prerequisites custom page to my installers, right after my license page, that checks for and downloads, installs/upgrades .NET 2.0 SP1 before any calls to the CLR plugin. I use the CLR plugin in custom pages after the components selection page. If this sequence doesn't work for you, you can put a .NET check-download-and-install into the .onInit. A recommended .onInit would do some conformance checks anyway, so here's a good order:
1. Check if installer is already running, if so abort
2. Check for local admin rights, if not, abort
3. Check for and Install IIS (if installing a web site on IIS)
4. Check for and Install .NET 2.0 SP1
It took me some time to figure this one out - and lots of VirtualMachine undo drive wipes - so I hope this saves you all some time.
rbchasetfb, very very good. SlyW, could you please try installing .NET 2.0 SP1 on the machines that fail?
I just installed the .NET 2.0 SP1 on the Win 2003 .NET 2.0 that was failing.
CLR.exe now WORKS!!!
Thanks --- Ted
CLR.exe now WORKS!!!
Thanks --- Ted
Great! Thanks for the excellent testing SlyW and teiles. rbchasetfb, you are my hero again 🙂 I have updated the wiki with the SP1 prerequisite. I assume that this is the solution to the problem. Let me know if not.
I will install SP1 on one or more of the failing machines and let you know the success/failure of each.
Thank you _all_ for making this a useful forum and an even more useful plugin!
Thank you _all_ for making this a useful forum and an even more useful plugin!
Now that we are at the issues. I have encountered an annoying thing and have a workaround for it. If you call a second custom .NET DLL from your first custom .NET DLL, you will run into an issue about the .NET framework cannot find the second DLL, even if you have placed both DLLs in the $PLUGINSDIR. Your second DLL is referenced in your first DLLs Visual Studio project.
The reason the second DLL cannot be found is that .NET looks for the DLL in the same directory as the calling process, which in this is case is the installer exe. You can make .NET look in a subdirectory of the calling process, but here comes the issue. Your installer will run from some location, and then it unpacks everything into a temp directory. From that directory it loads the first DLL by loading it into memory and then using reflection to scan the methods and properties, so the process does not have to look for the DLL. The second DLL is not loaded this way as it is referenced from the first DLL's project. Here I rely on that the .NET framework can find it, and as it was not unpacked in the installer's directory or subdirectory, I have not found a way to make .NET find it.
My workaround has been to make a second NSIS script that wraps my installer script and wraps the .NET DLLs needed in my installer script. These are unpacked to the temp directory together and when the second script is executed using Exec, the second installer will be the executing process and thus it can find the DLLs. When the second installer finishes, I delete the files again.
Although this works, it would be nice to have a "real" solution, where the .NET framework can actually find the second DLL. I have tried all kinds of things, googled for it etc. I have not yet found a solution to make .NET look for a DLL in another directory other than where the calling process is run from or subdirectories of that. If anyone have ideas, let's see if we can find a better solution.
A note: One should not unpack the DLLs in the same directory as the installer, as the installer might be run from a CD-Rom or other readonly media.
A second note: One could use reflection, like how the first DLL is loaded, to load the second DLL. But this as two drawbacks: 1) Using reflection, there will be a weak binding between your DLLs and you will not have code completion in your project when trying to call things in the second DLL. 2) You would have to use reflection again if trying to call a third or fourth DLL.
Regards Claes
The reason the second DLL cannot be found is that .NET looks for the DLL in the same directory as the calling process, which in this is case is the installer exe. You can make .NET look in a subdirectory of the calling process, but here comes the issue. Your installer will run from some location, and then it unpacks everything into a temp directory. From that directory it loads the first DLL by loading it into memory and then using reflection to scan the methods and properties, so the process does not have to look for the DLL. The second DLL is not loaded this way as it is referenced from the first DLL's project. Here I rely on that the .NET framework can find it, and as it was not unpacked in the installer's directory or subdirectory, I have not found a way to make .NET find it.
My workaround has been to make a second NSIS script that wraps my installer script and wraps the .NET DLLs needed in my installer script. These are unpacked to the temp directory together and when the second script is executed using Exec, the second installer will be the executing process and thus it can find the DLLs. When the second installer finishes, I delete the files again.
Although this works, it would be nice to have a "real" solution, where the .NET framework can actually find the second DLL. I have tried all kinds of things, googled for it etc. I have not yet found a solution to make .NET look for a DLL in another directory other than where the calling process is run from or subdirectories of that. If anyone have ideas, let's see if we can find a better solution.
A note: One should not unpack the DLLs in the same directory as the installer, as the installer might be run from a CD-Rom or other readonly media.
A second note: One could use reflection, like how the first DLL is loaded, to load the second DLL. But this as two drawbacks: 1) Using reflection, there will be a weak binding between your DLLs and you will not have code completion in your project when trying to call things in the second DLL. 2) You would have to use reflection again if trying to call a third or fourth DLL.
Regards Claes
Success! I have successfully run the sample installer on a machine _after_ installing SP1. Now, to make SP1 a pre-req for installing our app.
Thanks again for all your help (to everyone)!
BTW: Do we dare ask what SP1 brings to the table that suddenly enables this functionality?
Thanks again for all your help (to everyone)!
BTW: Do we dare ask what SP1 brings to the table that suddenly enables this functionality?
Found additional error messages
I just happened to be perusing the Event Viewer on a machine where the CLR.dll failed to load and discovered the following three entries:
Dependent Assembly Microsoft.VC80.CRT could not be found and Last Error was The referenced assembly is not installed on your system.
Resolve Partial Assembly failed for Microsoft.VC80.CRT. Reference error message: The referenced assembly is not installed on your system.
Generate Activation Context failed for C:\DOCUME~1\USERSL~1\LOCALS~1\Temp\nsy57D.tmp\CLR.dll. Reference error message: The operation completed successfully.
So, apparently SP1 somehow brings Microsoft.VB80.CRT into the fold?
I just happened to be perusing the Event Viewer on a machine where the CLR.dll failed to load and discovered the following three entries:
Dependent Assembly Microsoft.VC80.CRT could not be found and Last Error was The referenced assembly is not installed on your system.
Resolve Partial Assembly failed for Microsoft.VC80.CRT. Reference error message: The referenced assembly is not installed on your system.
Generate Activation Context failed for C:\DOCUME~1\USERSL~1\LOCALS~1\Temp\nsy57D.tmp\CLR.dll. Reference error message: The operation completed successfully.
So, apparently SP1 somehow brings Microsoft.VB80.CRT into the fold?
Class Property
Hi and thx for watching this:
Calling the method "SayHi" from my c# dll works fine, but the set_MyProperty method to setting the public property "name" dont work for me, here is my simple C# class:
Thx for replays 😉
Hi and thx for watching this:
Calling the method "SayHi" from my c# dll works fine, but the set_MyProperty method to setting the public property "name" dont work for me, here is my simple C# class:
using System;
using System.Collections.Generic;
using System.Text;
namespace DllTest{
public class greeting{
private string m_strname;
public greeting() {
}
public string SayHi(){
return "hi " + name;
}
public string name{
get { return m_strname; }
set { m_strname = value; }
}
}
} And this is my nsis source:Section
SetOutPath $PLUGINSDIR
File "DllTest.dll"
CLR::Call /NOUNLOAD DllTest.dll DllTest.greeting set_name 1 "augus666"
CLR::Call /NOUNLOAD DllTest.dll DllTest.greeting SayHi 0
pop $0
detailprint $0
CLR:: Destroy
SectionEnd I did compilated my DllTest.dll on DEBUG, RELEASE, with Framework 2 SP1, i did try with VS Net 2005 and VS Net 2008 classes, Windows Xp SP3 Pc's and nothing yet (btw the get_ method works).Thx for replays 😉
What error do you experience?
Re: Class Property
I cant change the value of the property with the _setMyProperty method
I cant change the value of the property with the _setMyProperty method
Sry for the delay. I have to look into this. I suspect it could have something to do with the internal variable not keeping the value between the calls. I am not sure how NSIS manages the memory when using NOUNLOAD on the calls. I thought the variables would keep their values. However, for now you must keep values in the NSIS script and pass them to the methods when needed.
SlyW: Sorry for the delay. I honestly don't know why .NET Framework SP1 makes things work, but your findings sound resonable.
Dependency Assemblies
This may be old news, but I believe I have found a fix for the dependent assemblies problem using the AssemblyResolve event. I hope it will be of use to you.
My managed C++ skills are not the greatest, but please find attached my modified source file.
Thank you for creating the CLR NSIS plug in. It has proven very valuable - we use it often.
Best Regards,
David
This may be old news, but I believe I have found a fix for the dependent assemblies problem using the AssemblyResolve event. I hope it will be of use to you.
My managed C++ skills are not the greatest, but please find attached my modified source file.
Thank you for creating the CLR NSIS plug in. It has proven very valuable - we use it often.
Best Regards,
David
Re: Dependency Assemblies
David, that looks interesting! That is really something I want to fix in the plugin. I will take a look at your code. I don't think this is old news, at least not for me, because I still had no solution to it. If I understand it right, will it then be possible to place the dependant assemblies anywhere and not necessarily in the same folder hierachy as the calling exe/dll?
David, that looks interesting! That is really something I want to fix in the plugin. I will take a look at your code. I don't think this is old news, at least not for me, because I still had no solution to it. If I understand it right, will it then be possible to place the dependant assemblies anywhere and not necessarily in the same folder hierachy as the calling exe/dll?
What are the requirements for building this plug-in? Can I build it using VC6?
No. It has to be at least Visual Studio 2005 as .NET 2.0 must be supported.
Too bad... Will just have to wait for the day I finally switch to 2008 I guess. But keep 'em coming. It's a useful plug-in.
The free express editions of VS works too, and can be installed alongside with VC6. Anyway, I will most likely implement Davids modification in the CLR.dll, so the dependant assembly problem will be solved for everyone, without having to recompile the source.
Hi Claes,
The default assembly resolution mechanism should be called first, so assemblies registered in the GAC should still work. However, if the default assembly resolution fails it will attempt to load the assembly from the directory containing the assembly that was explicitly executed using CallCLR. I suppose it could be modified without a great deal of effort to accept a Java-like class path of directories to search for dependency assemblies.
Again, thank you for creating this plug in. We used it to replace a very clunky XML-driven solution that we used to use for performing install tasks from .NET DLLs.
Best Regards,
David
The default assembly resolution mechanism should be called first, so assemblies registered in the GAC should still work. However, if the default assembly resolution fails it will attempt to load the assembly from the directory containing the assembly that was explicitly executed using CallCLR. I suppose it could be modified without a great deal of effort to accept a Java-like class path of directories to search for dependency assemblies.
Again, thank you for creating this plug in. We used it to replace a very clunky XML-driven solution that we used to use for performing install tasks from .NET DLLs.
Best Regards,
David
I notice it has been quite some time since talk of changing the way dependent assemblies are located. Is this no longer likely to happen?
Also, is there any particular reason why the plugin requires the assembly being called to have a .dll extension? I tried making calls to an exe (eg. foo.exe) and received a message indicating that the file (eg. foo.exe.dll) could not be found.
Also, is there any particular reason why the plugin requires the assembly being called to have a .dll extension? I tried making calls to an exe (eg. foo.exe) and received a message indicating that the file (eg. foo.exe.dll) could not be found.
Has anyone tested with Windows 7? I am trying to recompile my NSIS installer that was built on XP but now it will not work on Windows 7.
I have .NET 2.0 SP1 framework installed and download the newest CLR.zip form
nsi file
I have .NET 2.0 SP1 framework installed and download the newest CLR.zip form
nsi file
OutFile "setup.exe"
Section
InitPluginsDir
SetOutPath $PLUGINSDIR
File "AccessClass.dll"
File CLR.dll
CLR::Call /NOUNLOAD AccessClass.dll AccessClass.Access removeData 1 "dataTable"
pop $0
MessageBox MB_OK $0
CLR::Destroy
SectionEnd From the MakeNSISWInitPluginsDir
SetOutPath: "$PLUGINSDIR"
File: "AccessClass.dll" [compress] 4493/24576 bytes
File: "CLR.dll" [compress] 31773/95744 bytes
Invalid command: CLR::Call
Error in script "C:\testscript.nsi" on line 9 -- aborting creation process