How to release DotNet Assembly loaded in C++ - c++

I have the following code in a C++ DLL. It loads and invokes a method in a DotNet DLL built with C#.
Assembly^ a = Assembly::LoadFrom(gcnew String("MyDotNet.dll"));
Type^ type = a->GetType("MyAssemply.Assembly");
MethodInfo^ method = type->GetMethod("MyMethod");
Object^ obj = Activator::CreateInstance(type);
array<Object^>^ params = gcnew array<Object^>(0) { };
Object^ ret = method->Invoke(obj, params);
The problem is that it does not appear to release the resources or DLL even when I do a FreeLibrary on the C++ DLL. Is there a API or Method I need to call to release the DLLs/resources?
I am using Visual Studio 2010.
Thanks.

You can't unload a managed assembly from an app pool. You can create another app pool and unload that.
This post is related: How to unload an assembly from the primary AppDomain?

Related

Compiling an MFC GUI application as a DLL in VS2012

Is it possible to compile an MFC GUI EXE project into a DLL and then execute this DLL application from another application?
My progress so far is:
I changed "Configuration properties | General | Configuration type" to DLL
I added an exported function creating and running the application using this code:
theApp.m_hInstance = pModuleState->m_hCurrentInstanceHandle;
theApp.InitInstance();
theApp.Run();
I added code to DLLMain to initialize module state:
if (dwReason == DLL_PROCESS_ATTACH)
{
AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
pModuleState->m_hCurrentInstanceHandle = hInstance;
pModuleState->m_hCurrentResourceHandle = hInstance;
I created a console application that loads the DLL and calls the function creating and running the DLL application.
Yet, I'm still getting various debug assertions as, for example, AfxGetThread returns NULL, etc. And the application fails to run.
Can someone tell me if my idea of making DLL from EXE is realistic?
Thanks in advance.

Call Java code from C

I use the JNI interface to invoke Java code from C code.
While compiling I use the following command:
gcc -g -I/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/include/ -I/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/include/linux/ -L/usr/bin/java -L/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/jre/lib/amd64/server/ -ljvm calljava.c
And I use the following code to create the JVM:
JNIEnv* create_vm()
{
JavaVM* jvm;
JNIEnv* env;
JavaVMInitArgs args;
JavaVMOption options[1];
args.version = JNI_VERSION_1_2;
args.nOptions = 1;
options[0].optionString = "-Djava.class.path=<classpath>";
args.options = options;
args.ignoreUnrecognized = JNI_FALSE;
JNI_CreateJavaVM(&jvm, (void **)&env, &args);
return env;
}
My question is:
Is the path to the JVM hardcoded in the binary?
Can we specify the path to the java executable at runtime?
If there is a way to do that can anyone help me with the compile time flags that can be used for that?
Thanks in advance!
The "java executable" is not used at all. When you compile and link your code, you link against a shared library, the location of which is determined by the system at runtime when you launch your executable.
Unless you dynamically load the jvm shared library yourself from a known location (and subsequently look up and call the functions therein), the system is going to determine the "path to the JVM".
Usually if you want to run against a specific version, you would include that version in your application's distribution, and configure the launch of your application to ensure that the proper shared library is used (either via scripts which set the environment appropriately, dynamically loading it, or other system-specific methods).

Problems with de-registering of COM (advanced installer)

Definition of problem:
Hangs up for sometime during COM de-registering and says The setup was unable to automatically close all requested applications. Please ensure that the applications holding files in use are closed before continuing with the installation. But actually my extension is successfully unloaded and uninstalled.
Definition of environment:
I created some kind of dummy shell namespace extension for tests. It implements IContextMenu and all methods returnS_OK and do nothing else and rgs file is
HKCR
{
xxx.sergz.dummyShellExt.1 = s 'DummyNSE Class'
{
CLSID = s '{6C0FBE00-9898-4BB0-806F-3ED7D2F1170D}'
}
xxx.sergz.dummyShellExt = s 'DummyNSE Class'
{
CurVer = s 'xxx.sergz.dummyShellExt.1'
}
NoRemove CLSID
{
ForceRemove {6C0FBE00-9898-4BB0-806F-3ED7D2F1170D} = s 'DummyNSE Class'
{
ProgID = s 'xxx.sergz.dummyShellExt.1'
VersionIndependentProgID = s 'xxx.sergz.dummyShellExt'
ForceRemove Programmable
InprocServer32 = s '%MODULE%'
{
val ThreadingModel = s 'Apartment'
}
TypeLib = s '{3DC947F0-6691-4043-B414-29F749209905}'
Version = s '1.0'
}
}
NoRemove Directory
{
NoRemove Background
{
NoRemove ShellEx
{
NoRemove ContextMenuHandlers
{
ForceRemove DummyShellExt = s '{6C0FBE00-9898-4BB0-806F-3ED7D2F1170D}'
}
}
}
}
}
HKLM
{
NoRemove Software
{
NoRemove Microsoft
{
NoRemove Windows
{
NoRemove CurrentVersion
{
NoRemove Shell Extensions
{
NoRemove Approved
{
val '{6C0FBE00-9898-4BB0-806F-3ED7D2F1170D}' = s 'xxx.sergz Dummy shell extension.'
}
}
}
}
}
}
}
I choose Professional installer and added only my dll file. On file properties Registration tab I choose Auto register file..., Extract registration info... and Synchronization is Enabled. In Product Information->Install Parameters->PackageType I choose 64-bit package for x64....
Now I build the MSI and install the extension.
Launch explorer and do right click somewhere on folder background. According to my log my extension is loaded and is DLL_PROCESS_ATTACH and a few times DLL_THREAD_ATTACH.
I launch the MSI again and choose Remove. It says that you have to close ... applications are using files... and there is only Windows Explorer in the list. I choose Automatically close ... and press OK.
All Explorer windows are closed but it seems that Explorer was not shutdown.
The status is "Shutting down applications", according to my log the dll is already unloaded. The problem is here. The dll is already unloaded but the MSI is still waiting for something and then it says The setup was unable to automatically close all requested applications. Please ensure that the applications holding files in use are closed before continuing with the installation.
I click OK and the process continues and my DLL is successfully removed in the end.
I use windows 8 64bit.
What are the reasons of this waiting and the message that applications can not be closed. How can I figure it out?
Right, this isn't going to work, the shell extension is very likely to be loaded and MSI isn't going to kill Explorer.exe. Nor would you want it to, it is rather a ghastly sight to the user.
You'll need to use an alternative way to un/register the extension. It isn't clear what "Professional installer" might mean. But you can always un/register a COM server by modifying the registry yourself rather than leaving it up to the DLL to do so. It is in fact the recommended way. You already know the registry keys from your .rgs file. You can also use the Heat.exe harvester from the WiX toolset. The DLL needs to be removed by delay-deleting it at the next user login, done by adding it to the PendingFileRenameOperations registry key. Check your installer creator tool for the proper procedure.

HRESULT "Class Not Registered" Implementing simple COM server DLL

I'm following this sites tutorial:
http://progtutorials.tripod.com/COM.htm
Preliminary evidence: Visual Studio 2010, Windows 7 64 bit.
and I'm coding the examples in section 3. (Implementing a server DLL). I've typed out the code exactly as shown and I'm getting a "Class not registered" exception when executing this code on line 12 of the code outlined in section 4.1 (where the tutorial shows you how to access the DLL and I have followed 3.1 to the letter):
hresult hr = CoGetClassObject(CLSID_Car, CLSCTX_SERVER, NULL, IID_IClassFactory, (void **) &pClassFactory);
I tried running:
regsvr32 xyz.dll
with xyz.dll being the path to my dll in order to register the DLL. This resulted in an error trying to find DLLRegisterServer:
I have already run
REGEDIT
HKEY_CLASSES_ROOT\CarDLL.Car\CLSID = {d969084c-b758-43ea-a218-a48763167abd}
HKEY_CLASSES_ROOT\CLSID\{d969084c-b758-43ea-a218-a48763167abd} = CarDLL.Car
HKEY_CLASSES_ROOT\CLSID\{d969084c-b758-43ea-a218-a48763167abd}\InProcServer32 = C:\Users\wiocl2\Documents\Visual Studio 2010\Projects\CarDLL\debug\CarDLL.dll
that I assumed put all the GUIDS I needed in the registry (The GUIDS were generated by me).
I'm assuming that a function is needed to be added to the class that allows it to be registered but I don't know how to do this and how to go about figuring it out. I'm kind of lost, as I haven't been working with COM for very long. If someone could give me a shove in the right direction that would be helpful.
Edit: Oh yes, I moved
#include // contains definition of DEFINE_GUID
to the iid.h file from iid.cpp, otherwise I was getting unresolved external errors on the build.
The most likely explanation: you are building your COM object as a 32-bit DLL, but the registration has been performed as a 64-bit DLL.
The treatment: open an admin privileged command window and navigate to the location of your DLL (C:\Users\wiocl2\Documents\Visual Studio 2010\Projects\CarDLL\debug). Once there, type:
c:\windows\sysWOW64\regedit <filename of .reg file whose contents are displayed above>
This will run the 32-bit version of REGEDIT, ensuring that the registry entries are created in the correct part of the hive. To verify this, you should see an entry for {d969084c-b758-43ea-a218-a48763167abd} in HKLM\Software\Wow6432Node\Classes\CLSID, not HKLM\Software\Classes\CLSID.
DllRegisterServer is a method you can implement in your COM server DLL, and is required if you want to use regsvr32 to perform the same operation you are currently using the .REG approach for. The same caveat applies: for a 32-bit DLL, you'll need to invoke c:\windows\sysWOW64\regsvr32.exe.
And Yes! COM is still mostly alive and well :) At least there is still standard support for it in VS 2012.
Hope that helps.

OLE/COM Object Viewer reports STG_E_FILENOTFOUND

I have created simple COM DLL using ATL and have added "ATL Simple Object" after that. To be sure server is registering I have placed messagebox:
STDAPI DllRegisterServer(void)
{
MessageBoxA ( NULL, "Hello World!", "Test", MB_OK );
HRESULT hr = _AtlModule.DllRegisterServer();
return hr;
}
Registering does fine. I decided to look how this object looks with OLE-COM Object Viewer that is part of SDK. Viewer reports error:
"LoadTypelib'(c:\pr\ILight.dll) failed.
<No system message defined> STG_E_FILENOTFOUND ($800300002)
Does it means my COM dll corrupted? How to make VIewer to show my dll information?
P.S.
Project RC file contians:
"REGISTRY"
IDR_ILIGHT
HKCR{}
IDR_LIGHT
HKCR
{
AboutiLight.1 = s 'Light Class'
{
CLSID = s '{DBC53EA8-A51E-4374-B104-06A834273B0C}'
}
AboutiLight = s 'Light Class'
{
CurVer = s 'AboutiLight.1'
}
NoRemove CLSID
{
ForceRemove {DBC53EA8-A51E-4374-B104-06A834273B0C} = s 'Light Class'
{
ProgID = s 'AboutiLight.1'
VersionIndependentProgID = s 'AboutiLight'
ForceRemove Programmable
InprocServer32 = s '%MODULE%'
{
val ThreadingModel = s 'Apartment'
}
TypeLib = s '{1D9F859D-10FF-4827-A341-4A8B8E318A61}'
Version = s '1.0'
}
}
}
String table
String table
ID=IDS_PROJNAME Value=100 Caption ILight
Version
VS_VERSION_INFO
FILEVERSION 1,0,0,1
PRODUCTVERSION 1,0,0,1
FILEMASK 0x3fL
FILEFLAGS 0x0L
FILEOS VOS_NT_WINDOWS32
FILETYPE VFT_DLL
FILESUBTYPE VFT2_UNKNOWN
After having received the same error (STG_E_FILENOTFOUND), and seeing Joe Willcoxson's comment about 64-bit and 32-bit, I was able to find a solution.
If you are using OleView.exe, the OLE/COM Object Viewer, there are actually two versions of it: 32-bit, and 64-bit. Ensure that you are launching with the proper version of OleView. The version in the base "BIN" folder of the SDK will be the 32-bit version. The "x64" folder will have the 64-bit version of the application, which is not fully compatible with older binaries and their typelibs (made in a 32-bit world).
On the other hand, if your new DLL is actively being compiled for x64, then it's highly likely 32-bit OleView will not be able to read the data properly, either.
1) Check to make sure that is the right path to your DLL.
2) Open the DLL itself from Visual Studio and check to be sure that a type library is embedded in the resources. If a typelib isn't found, add one.
3) If all that fails, did you register it under an administrator account/shell. If you call regsvr32.exe on it, make sure you are running with elevated privileges.