Problems calling a DLL from .NET - vb.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

Related

registering a dll on various OS

I have looked through countless threads on the error message
"the module was loaded but the entry-point dllregisterserver was not found make sure that is a valid DLL or OCX file"
I also tried regsvr32, and regsvr32 from syswow64...
I also tried registering it as name.ocx (per another threads suggestion).
Option Explicit On
Imports System
Public Class GenThis
Public Function rtnStr(Optional ByVal o As Object = Nothing) As String
Try
'do stuff
rtnStr = strTmp
Catch ex As Exception
Return "ERROR"
End Try
End Function
End Class
That is the class, being built on 2.0. When I add the dll as a reference in VS everything works fine. When I try to go in (same machine, Win7) to Excel Dev tab to try and add it there it does not exist. Also need to be bale to register it for our VB6 application.
I can't find any definitive answers or explanations on "what" this means. Can someone elaborate what is going on and what I am doing wrong?
Not all COM dlls are registerable. Sometimes the registration info sits in another dll. Programming languages use type libraries that may or may not be in the dll. Type libraries and registration is two seperate things.
.NET COM dlls aren't registerable in the normal way (it's the .NET framework that gets registered and it recieves calls and passes them to the .NET COM dll). For .NET use RegAsm, part of the .NET framework, which sets it up.

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.

Debugging VB6 dll from VB6 exe

I have a VB6 program that calls a VB6 DLL which in turn calls another VB6 DLL. When I execute the calling program there is an application error which I am unable to pinpoint so I researched how if it was possible to "see" the error in the dll.
I read Stackoverflow entry question about debugging VB6 dll
and followed the directions of Booji Boy to create a vbg. I also followed his directions and removed the two DLLs from he Reference list. The calling program takes a .txt file as input. When I executed the exe I received this error:
Error Number: 13Description: Type mismatch
The error isn't being generated by the application.
What does this mean? How can I debug this issue?
You must have all the source code for the EXE and the two DLLs. You add all the projects into single group file i.e. the VBG. You must have a reference in the EXE project to the first DLL. I have no idea why you have been told you have to remove them. You must have a reference in the first DLL project to the second DLL project. VB is clever enough to silently replace the DLL reference with the project reference. It is also clever enough to silently replace the project reference with the DLL reference if you remove a DLL project from the project group.
Make sure you have error handling set to "Break on All Errors" or "Break in Class".
The type mismatch error can occur from simple things like assign a non-numeric string to an numeric variable. It gets more complicated if you are passing object references around. If you see this error occurs on something like:
Set myObject = someOtherObject
... and it looks as if they should be the same type, this might get very complicated. But first, I'll let you do the debug.
You can use an open source project made in Visual Basic 6.0. It is called "Debuggy v2".This project has multiple roles:
-debugger
-disassembler
-Windows resource extractor
-file hex editor
-window sniffer
-API spy
all rolled into one. I may be useful for what you need.
When starting to work in a VBG a type mismatch can arise if the library references are inconsistent. One library may be referencing another IN the VBG; a second may be referencing the compiled version. Passing objects between them can result in this error.
Concrete example:
VBG contains code for: A.DLL, B.DLL, C.DLL
A references B in the VBG
C references B which is compiled
Code in A calls code in C passing an object defined by a class in B.
Type mismatch
C should have referenced B in the VBG.

How to force the unmanaged to managed calls to use the default 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?

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.