Access Violation from DllImport'd Sub

mooman_fl

Centurion
Joined
Nov 3, 2002
Messages
193
Location
Florida, USA
As usual I am having a bit of trouble and I am hoping one of the gurus out there can shed some light. I think I know what the problem is, I just don't know how to fix it even after searching myself half blind.

I am working with a third-party DLL written in unmanaged code. I used DLL import to pull it into my project like so (yes it is a plugin for DarkBasic Pro if you recognized it):

Code:
    <DllImport("Matrix1Util_20.dll", EntryPoint:="CallFunctionPtr", CallingConvention:=CallingConvention.Cdecl)> _
    Friend Shared Sub CallFunctionPtr(ByVal FunctionPointer As Long)
    End Sub
The problem comes when I try to use the function. It works, then crashes immediately with an "System.AccessViolationException: Attempted to read or write protected memory."

If I Try/Catch this and bypass the error, the thing functions as it should, but crashes upon closing with an empty error dialog (no text, just an "Ok" button).

What that DLL does is call a function via a pointer in an unmanaged application. In this case, the application in question lables both Subs and Functions as a "Function" in my test code there was no return value.

I have looked up information on things like this but all I could find were references to similar problems where the imported function had a callback and was solved by making a delegate with the "UnmanagedFunctionPointer" attribute, however this function doesn't have a visible callback.

Any help or advice on how to solve this is appreciated. If you need more info or code just let me know.
 
Do you have any documentation for the dll itself, or more specifically this particular function?

It could possibly be down to the data types you are using for parameters of the calling convention may be something other than cdecl, without the actual documentation though it is pretty difficult to track down this kind of error.
 
Unfortunately, I know for certain it is not a problem with the data types. Between knowing how DarkBasic Pro handles data types, the help file description for this command, and the string table entry (resource hacked to get a peek) for this command in the DLL I am pretty certain (99.9%) that it isn't a problem with mismatched data types. I become 100% certain when you add to that the fact that if I use Try/Catch with an empty Catch section to trap the Access Violation error, the command works as expected until you exit the application at which time it crashes.

To give a little more insight, here is the Help File entry for the command as it is used in DarkBasic Pro:

CALL FUNCTION PTR

Syntax

CALL FUNCTION PTR Function Pointer, ...arguments...
Return Value = CALL FUNCTION POINTER ( Function Pointer, ...arguments... )

Description

Calls the function pointer, passing any arguments you have provided (up to 10) to the function being called. These functions/commands will work for either __cdecl (DBPro or user DLL) or __stdcall (windows DLL) functions safely (... hopefully).
It is an overloaded function, but I am using the first one that takes a Long type with no other arguments.

Here is the string table entry from within the DLL:

Code:
CALL FUNCTION PTR%L%CallFunctionPtr
As you can see the section "%L%" means that it takes a data type of Long with no return value.


You can see in my first post how I load the DLL function for use. Here is how I use it in my code:

Code:
Try
    MatrixFunctionPointers.CallFunctionPtr(currentmessage.Handler)
Catch ex As Exception
    MessageBox.Show(ex.ToString)
End Try
The property "currentmessage.Handler" is of type Long and is poplated with a value from another command within the DLL that holds the "CallFunctionPtr" command. The command that gives the value is one that is intended to pass the correct value for that command. If I remove the MessageBox command from the Catch portion, it doesn't give an error and works as expected... then crashes when you try to exit the program.

If it helps, here is a link to the author's page where you can get the DLLs, it is in a pack of 28 of them.

EDIT: I am using the Matrix1Util_20.dll. The link to download them is the first of two links at the bottom of the first post on the page.

http://forum.thegamecreators.com/?m=forum_view&t=85209&b=18

They are made as plugins for DarkBasic Pro, but plugins can be referenced by other DLLs.

DarkBasic Pro and most of the plugins are written in unmanaged code, however the process for getting a .Net DLL to work as a plugin is well understood by the community.

I hope this helps. I will be willing to zip up my code and attach it if need be. However, without DarkBasic Pro there would be little point. My code compiles just fine... the error is only revealed when you run it within the intended environment. I am as sure as I can be that it is a problem with my managed code calling an unmanaged code function that does something .Net doesn't like.

I have a question up on the author of the DLL's forum entry to match this one... but since I don't believe the problem is with his DLL, I figured this forum might be able to help as well.
 
Last edited:
Try changing the calling convention to stdcall rather than cdecl and see if that works, the fact it returns and then crashes sounds like a corrupt stack - something that is highly likely to happen if calling conventions are mismatched.
 
Ok, I changed it to a stdcall. Unfortunately that had no visible effect.

I did get a reply from the author of the DLL, however he has almost no experience with .Net and his answer just didn't sound right to me. But then that could be just MY inexperience in some areas. Here is the reply that he gave:

"I was wondering if you have any experience with VB.Net or even C#"
Almost none, and absolutely none with regard to calling external DLLs.

I would guess that the low-level stack handling I do within CallFunctionPtr is causing the crash and that the problem is caused by the .NET environment is using it's own stack and that this stack is fairly small (less than 80 bytes).

If this is the case then I don't have a solution for that without slowing the command down for everyone - it's not an issue that occurs with the DBPro stack.

If you want to send me a small example DLL and the code to go with it, I can take a look and see if I get any ideas.
Does this answer sound plausible to you (no pun intended, but certainly enjoyed)?

Here is a post from another forum on the web that talks about a similar sounding problem, unfortunately I have just enough knowledge to see this as a possible cause, and not enough to solve it:

http://www.thescripts.com/forum/thread672441.html
 
It certainly sounds like the kind of problem a corrupt stack could cause, however I'm not convinced it is down to the size of the .Net stack.
Raymond Chen has a good blog posting on the subject (like pretty much all his postings are...) and this error definitely fits the pattern.

Unless the DLL is doing something peculiar then stdcall should be the correct calling convention, however if he is manipulating the stack himself there isn't an awful lot you can do if he isn't following the rules 100% :(
 
Well I got part of the problem solved. My program no longer crashes when you shut it down if you bypass the Access Violation. I don't want to release it with the error bypassed though since that could introduce some nasty bugs later.

Basically the crashing on exit problem was a String issue. Evidently C++ doesn't handle strings the same way and I was unable to get my code to accept or pass strings properly to the host application (not the DLL I was trying to reference). I just changed that parameter to a Long type and the crash-on-exit bug went away.

Unfortunately the Access Violation is still there. I am hoping I can get this solved.
 
I'm just stabbing in the dark here, but it looks like (ByVal FunctionPointer As Long) would be better off as (ByVal FunctionPointer As IntPtr). A long is 64-bits and a pointer is 32-bits or 64-bits (probably 32), depending on the environment. That could be related to unbalanced or other stack issues (I don't know who cleans the stack in an stdcall).

This is a common issue when porting VB6 code that uses unmanaged DLLs since VB6 didn't have a pointer type and a VB6 long is 32-bits. This means that VB6 code had to use a long. In DotNet IntPtr is generally a better representation for a pointer.
 
Back
Top