How to force the unmanaged to managed calls to use the default appdomain? - appdomain

I have been trying to fix this issue for quite sometime now. I have a C# user control wrapping an activex control (through wrappers created by RCW); This particular activex control loads MFC extension dll which has got C# WPF assembly dependant. This MFC extension dll calls C# WPF assembly through classes compiled as managed (using /clr compiler option).
The problem here is that - when my C# user control gets loaded in C#; It gets into the default app domain and everything seems to be working fine; but whenever a call is made from unmanaged part of MFC extension dll to the managed portion of it, it cramps to find the C# WPF assembly. I googled to find that there seems another appdomain getting created when a call is made from unmanaged portion of MFC extension dll to the managed portion. Right now, I am clueless about this one - How to force the unmanaged to managed calls to use the default appdomain?

Related

Replace COM DLL with new managed COM Callable assembly

Is there a smart way to scaffold a COM callable .NET class library from an existing native COM DLL?
Scenario
Suppose you have a COM based C++ Win32 application and you want to replace one of the COM DLLs with something written from scratch.
Constraints
The new library shall be written in C#, targeting the .NET Framework (4.x)
No modifications to the rest of the existing unmanaged application shall be required.
No recompilation of the unmanaged code shall be required.
What I already know
You can create .NET assemblies which are COM callable.
You can import the type library IDL from an existing COM DLL.
Based on this question, what I want should be possible, even if arduous.
Question
Is there a smart / efficient way to generate the scaffolding code for a COM callable .NET class library with the exact same signature as an existing unmanaged COM DLL so I can replace the DLLs?
There does not need to be any implementation at first, every method could just throw a NotImplementedException for example.

Out-of-process Classic COM EXE using Windows Runtime Template Library (WRL)

I have followed the example here: http://msdn.microsoft.com/en-us/library/vstudio/jj822931.aspx to create an In-proc Classic COM DLL using Windows Runtime Template Library (WRL). I am also able to modify to code to run the DLL as COM surrogate (wrapped inside DllHost.exe).
However, I couldn't find the way to create an out-of-process COM EXE using the WRL. There is a simple example using barebone COM API here: http://www.codeproject.com/Articles/3173/A-simple-yet-debuggable-COM-skeleton-code, but I'd like to know how I can utilize WRL to simplify that.
Thanks.
Yes it is possible. I just got one working. Here's the basics that are required, as compared to implementing an in-proc coclass.
Implement your coclass using WRL::RuntimeClass the same way you would for an in-proc class. (https://msdn.microsoft.com/en-us/library/jj822931.aspx)
In your main function, create a module object using WRL::Module<OutOfProc>::Create(), and call module.RegisterObjects() on startup, and module.UnregisterObjects() and module.Terminate() on shutdown.
You need to build a DLL to host the proxies: https://msdn.microsoft.com/en-us/library/windows/desktop/ms688707(v=vs.85).aspx
Static Registrations: DO register the Interface and the CLSID of your proxy stub. DO NOT statically register your coclass.
In the Client, when you call CoCreateInstance, be sure to use the appropriate CLSCTX. (I use CLSCTX_ALL when the hosting model is not important to the client.)
(I know it's been almost 4 years, but I had the same question this week.)

Calling c# code from managed c++ crashes

I have an unmanaged c++ DLL that calls c# code through a managed c++ wrapper. The unmanaged c++ DLL is a plug-in for some application (outside my control). When this application calls the unmanaged c++ DLL everything works fine until the managed c++ code tries to use the c# code. Then it crashes.
I have written a test application that does the same thing as the application, that is, it calls the unmanaged c++ DLL. This works fine.
The code is as simple as it could be:
unmanaged c++:
extern "C" __declspec(dllexport) void UnmanagedMethodCalledUponByApplication()
{
new Bridge();
}
managed c++:
Bridge::Brigde()
{
gcnew Managed(); // This line crashes
}
c#:
public class Managed
{
}
I have tried to add a try-catch (...) block around the problematic line but it doesn't catch the error.
If I replace the gcnew Managed(); line with MessageBox::Show("Alive!"); it works fine. So my guess is that something is wrong with my c# project settings.
I have tried to compile it with different platforms (Any CPU and x86). I have tried to change target framework. I have tried to call a static method in Managed instead of using gcnew. Still crashing.
Any ideas what might be the problem?
Update:
After advise in comments and answer, I attached the debugger. Now I see that I get a System.IO.FileNotFoundException saying that the managed DLL (or one of its dependencies) can't be found.
Here's a guess: The DLLs are placed together, but they are not located in the current directory. The unmanaged c++ DLL is loaded correctly since the main application specifies the path to it. The managed c++ is actually a lib, so that code works fine as well. But when the managed c++ tries to load the c# DLL it looks for it in the wrong directory.
Update:
The way to fix this is to load the c# DLL dynamically, using reflection.
extern "C" __declspec(dllexport)
Yes, that's a cheap and easy way to get the compiler to generate the required stub that loads and initializes the CLR so it can execute managed code. Problem is, it doesn't do anything reasonable to deal with exceptions thrown by managed code. And managed code likes throwing exceptions, they are a terrific trouble-shooting tool. That stops being terrific when there's no way for you to retrieve the exception information.
The best you could possibly do from native code is use the __try/__except keywords to catch the managed exception. Exception code is 0xe0434f4d. But that still doesn't give you access to the information you need, the exception message and the holy stack trace.
You can debug it. Project + Properties, Debugging, change the Debugger Type to "Mixed". Then Debug + Exceptions, tick the Thrown checkbox for CLR Exceptions. The debugger stops when the exception is thrown so you can see what's wrong.
Getting decent diagnostics after you shipped your code requires a better interop mechanism. Like using COM interop or hosting the CLR yourself.

Problems calling a DLL from .NET

I have a VB6 DLL that wraps a call to a 3rd party component. When I call my DLL from VB6, everything works fine, but when I call it from vb.net (2.0 framework targeted - VS2010) I get this error:
AccessViolationException occurred
Attempted to read or write protected memory. This is often an
indication that other memory is corrupt.
This error only occurs on Windows 7 (Windows XP clients work fine).
I've looked this up and all the articles I found talked about the declaration not being correct. I am not declaring any APIs calls though, the 3rd party component is early bound in my VB6 DLL. I can run the DLL, set a breakpoint, and it goes into my VB6 function, but errors calling a function in the 3rd party component.
My VB6 DLL takes 3 string and one 32bit numeric (long in VB6) parameters. The 3rd party's DLL function that I am calling is taking a string (bstrDNSID as string is what Intellisense shows in VB6). This is where it errors.
Does anyone know how this might be resolved?
Update:
None of the marshalling has helped, so I tried creating a test sub in my VB6 DLL. I hardcoded all the values within the DLL's test sub. It works fine when called from VB6, but gives the same error as above when running from .NET. Also of interest, when I have the VB6 DLL running from the VB6 IDE, I do not get the error when calling the DLL from .NET.
This doesn't really answer your question, but I couldn't fit these examples in the comments.
When marshaling strings to unmanaged DLL calls from .NET, I would receive an AccessViolationException on occasion because I wasn't specifying the right charset. I fixed it by explicitly converting an IntPtr to a string in the charset I needed.
[DllImport("MyDLL.dll", CharSet = CharSet.Ansi)]
static extern void do_something(IntPtr str);
void DoSomethingWrapper(string str) {
var ptr = Marshal.StringToHGlobalAnsi(str);
do_something(ptr);
}
You might need Marshal.StringToBSTR. I don't know if you can call the VB6 function with a pointer or if you'll have to create the pointer in the VB6 DLL.
Here's a question you might find useful: How can I get the charset VB6 is using?
Workaround:
I have found one solution that works. I simply created an ActiveX EXE in VB6 that called the 3rd party component. Works like a charm from .NET.
Also of note, I'd never created an ActiveX EXE and didn't know that regsvr32 will not work to register it. Here is the proper way to register ActiveX EXEs.
VB6 probably declares integer as 16 bit. This is a problem with calling DLLs from VBA too. The solution should be to change your integer to long

Can I override _matherr in an C++/CLI dll?

I have an unmanaged c++ application that provides a custom _matherr handler. When this application loads and runs code in unmanaged DLLs, if there is a Math error ( e.g. asin( 100.0 ) ) the custom _matherr function is called and everything works.
However, I'm now trying to create a NUnit Test DLL in C++/CLI that loads the same unmanaged DLL and runs the same code as the application above. What I want to do is add the _matherr function to the C++/CLI dll such that when math errors occur I can perform some custom handler logic.
The C++/CLI dll compiles just fine with the _matherr function defined, but when I force a math error from the unmanaged dll, the _matherr function is not called.
Is this not supported by C++/CLI? The MSDN documentation seems to say _matherr is supported by all C Run times, (with a link to a list of runtimes including the /clr runtime. )
My experience is that defining _matherr does not work if done in a dll. It must be defined in the executable.
I've even seen compilers that when you try to add _matherr in a dll, will not link it in because they don't see anybody making a reference to it.
Maybe you need something like a proxy dll, passing through each function call to the original dll excepting those you want to be handled extra.