问题
I'm P/Invoking out to Graphviz as shown here. When I wrote that blog entry, the code worked just fine. Now, I'm putting together an HttpModule
that renders Graphviz graphs using that code, but I get an AccessViolationException
at agmemread
.
// Native signature
Agraph_t agmemread(char *);
// P/Invoke Signature
[DllImport(LIB_GRAPH)]
private static extern IntPtr agmemread(string data);
// Usage
IntPtr g = agmemread(data);
Like I said, this worked perfectly before. But now, I can't get my code to work in anything. Even my old Graphviz apps based on the same code don't work anymore.
What could I have possibly changed that would cause this? I haven't even downloaded a new version of Graphviz or anything, so the DLLs are all the same.
EDIT: I tried changing string
to StringBuilder
, but that produced the same result. Then, I added a MarshalAs
attribute:
static extern IntPtr agmemread([MarshalAs(UnmanagedType.LPWStr)] string data);
With that, I no longer get an AccessViolationException
, but Graphviz fails to read the string correctly and returns a null pointer.
回答1:
Unmanaged code rarely needs a lot of help from C# to start generating access violations. There's nothing wrong with your P/Invoke signature, that cannot be the cause.
The most common source of AVs in unmanaged code is heap corruption. C/C++ code doesn't have a garbage collector, memory must be managed explicitly. Not only must it take care of releasing memory (or it will leak), it is also responsible for allocating the correct size and making sure that the code that writes to the allocated memory doesn't write past the end of the allocated memory block or writes into memory that was already freed. That last requirement is where C/C++ code often fails.
The trouble with heap corruption is that it is extremely hard to diagnose. It can go unnoticed for quite a while. The typical damage done is that the internal heap structure is compromised, or the data in another heap allocation is overwritten. That doesn't cause a problem until later, when the heap block is released or the overwritten data is used. The code that generates the exception is not actually responsible for the damage that was done earlier. Which sets you off on the wrong track trying to find the source of the problem.
Finding the real trouble maker is very hard, you'd have only a few breadcrumbs to figure out what might have gone wrong. It is very hard when you have the C/C++ source code, but running it in a debug build with a debug allocator helps. It is impossible when you don't have the source code.
Unless you can pin-point a problem with using the API from earlier calls made, you'll need help from the vendor or support group to really solve this problem. Good luck.
回答2:
I had the same issue - the P/Invoke
signatures require adding CallingConvention=CallingConvention.Cdecl.
The Graphviz libraries are C calling convention, not StdCall
.
See this thread.
来源:https://stackoverflow.com/questions/2167263/access-violation-where-there-wasnt-one-before