How to call a function in an unmanaged dll from C# Code?
How can I call the following method from C#, which is in a C++ dll? How Can I recreate the following structure in C#?
Original
Method:
LONG MyMethod (P_HOLO_INFO pInfo, LPVOID pBuffer, LPUSHORT pTracksWritten);
Structure: This method uses the following structure:
typedef struct _HOLO_INFO
{
LONG lHoloType;
LONG lStatus;
HANDLE lThreadHandle;
LONG lErrorCode;
LONG lDriveIndex;
LONG lHeight;
SHORT iFormat;
INT iStartingTrack;
LONG lWrite;
LONG lSkip;
BOOL bSkipZero;
BOOL bInvert;
LONG lMaxConsecutiveErrors;
LONG lMaxTotalErrors;
LONG lMostConsecutiveErrors;
LONG lTotalErrors;
LPBYTE pBuffer;
LPUSHORT pTracksWritten;
LONG bUpsideDown;
} HOLO_INFO, *P_HOLO_INFO;
I worked in C# like this
Method:
[DllImport("My.dll", EntryPoint = "_MyMethod@12")]
public unsafe static extern long MyMethod(ref HOLO_INFO pInfo, Byte[] pBuffer,ref ushort pTracksWritten);
Structure:
This method uses the following structure:
unsafe public struct HOLO_INFO
{
public long lHoloType;
public long lStatus;
public long lThreadHandle;
public ulong lErrorCode;
public long lDriveIndex;
public long lHeight;
public short iFormat;
public int iStartingTrack;
public long lWrite;
public long lSkip;
public bool bSkipZero;
public bool bInvert;
public long lMaxConsecutiveErrors;
public long lMaxTotalErrors;
public long lMostConsecutiveErrors;
public long lTotalErrors;
public Byte* pBuffer;
public long* pTracksWritten;
public long bUpsideDown;
};
I made a call to the method like this:
do
{
result = MyMetho开发者_开发技巧d(ref pInfo,ptrBuf,pTracksWritten);
} while (result ==1 );
Because, it returns 1, if it is Active 0, if it completed successfully 3, if it stopped because of error. if the method is in running state(Active-1). it modifies pInfo and pTracksWritten to update the status information.
Lots of issues:
- LONG should be declared as int in C#
- HANDLE is IntPtr.
- pTracksWritten is missing. You probably need to make it, and pBuffer, an IntPtr and use Marshal.AllocHGlobal to allocate memory for them, depends.
- You need the CallingConvention in the [DllImport] declaration to use Cdecl.
Odds of getting this to work are not great if you can't debug the unmanaged code. One basic sanity test is to make sure that Marshal.SizeOf() returns the same length as sizeof() in the unmanaged code. Next verify that passed arguments look good when debugging the native code. Next triple-check the pointer usage in the native code and verify that they are not getting copied.
See Using a Very C# DLL in C++
You can do a 'simple' trick [this answer](answer Using a Very C# DLL in C++) or you can have a look at fullblown embedding as per my answer
Give this a shot:
[DllImport("My.dll", EntryPoint = "_MyMethod@12")]
int MyMethod (HOLO_INFO pInfo, IntPtr pBuffer, IntPtr pTracksWritten);
public class HOLO_INFO
{
public int lHoloType;
public int lStatus;
public IntPtr lThreadHandle;
public int lErrorCode;
public int lDriveIndex;
public int lHeight;
public short iFormat;
public int iStartingTrack;
public int lWrite;
public int lSkip;
public bool bSkipZero;
public bool bInvert;
public int lMaxConsecutiveErrors;
public int lMaxTotalErrors;
public int lMostConsecutiveErrors;
public int lTotalErrors;
public IntPtr pBuffer;
public IntPtr pTracksWritten;
public int bUpsideDown;
}
Depending on how they're allocated, you may need to use Marshal.Copy
to access HOLO_INFO.pBuffer
and Marshal.PtrToStructure
to access HOLO_INFO.pTracksWritten
(or Marshal.Copy
if it's an array vs. a pointer to a singular value).
精彩评论