I am using C# to run the sqlite3_exec API available in SQLite3.DLL. (care! this link will download)
I import the API as follows:
[DllImport("sqlite3.dll", EntryPoint = "sqlite3_exec", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
static extern int sqlite3_exec(IntPtr dbHandle, string sql, Callback callback, object args, out IntPtr errmsg);
The API signature is found here
I've defined a delegate for the 3rd parameter, the callback as follows:
public delegate int Callback(IntPtr p, int n, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr, SizeParamIndex = 1)]string[] names, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr, SizeParamIndex = 1)]string[] values);
Something is amiss (and I can't see what that is) because I hit this error consistently after retrieving the 3rd record i.e. during the 4th callback
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
I'd appreciate your help in resolving the issue or for any pointers leading thereto.
Related
I've got a COM interface dll, and some documentation about the methods within the dll, however from what I can tell with the documentation, the method requires a custom struct be passed in as an out parameter, but the documentation doesn't provide any information about the struct itself.
The function I'm calling from c# is as follows:
API
UINT OpenRequest ([out] PHCOMS phComs,
[in] PCHAR pEndPointName,
[in] UINT fBlockingMode,
[in] UINT fOpenMode,
[in] UINT fDataType,
[in] HINSTANCE hInstance)
My issue is that PHCOMS is a type described in the documentation as:
The address of a variable of type HCOMS. The communications handle to be used by the other API calls, is returned in this variable. If an error occurs this will be NULL.
This function starts by allocating a comms handle (hComs), if
available, to the application. This handle is used for creating a new
connection object. The parameters of this function are assigned to the
relevant members. For this object, a pointer instance is created for
connecting to the interface, as well as the PC Headerpched
interface
I've had a look at various dll inspectors and other posts on SO but can't find anything that helps with how I can actually create a struct that's going to be validly accepted by the function.
I am also unsure if I'm misinterpreting what I need to do - is it possible that I just need to pass a standard handle through to the function or something similar? Is the PHComs type a non custom type that I just can't find info on in google?
Right now I'm attempting to call the function through c# using the DLLImport attribute over an extern function which seems to be ok except that the handle I get back is never valid, which I'm blindly (I've never done something like this before) trying to do like this
[DllImport("MyDll.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
public static extern uint OpenRequest(ref SafeProcessHandle hComs, string host, uint fBlockingMode, uint fOpenMode, uint fDataType, SafeProcessHandle hInstance);
static void Main(string[] args)
{
IntPtr h = new IntPtr();
var handle = new SafeProcessHandle(h, true);
uint test = 0;
test = OpenRequest(ref handle, "Host01", 0, 0, 0, handle);
handle.Dispose();
}
Any assistance on how to setup my test properly would help too since I'm blindly guessing about the IntPtr and use of whatever Safe*Handle Classes.
Edit
I've changed it to be like this following Hans' comment:
As you said, there are other methods that use that handle, for example the ConnectRequest added below.
Any suggestion as to what the HInstance parameter refers to? I doubt it's correct that I'm just passing the same handle/IntPtr in again?
The documentation says:
hInstance HINSTANCE Windows programs must pass their instance handle.
[DllImport("MyDll.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
public static extern uint OpenRequest(out IntPtr hComs, string host, uint fBlockingMode, uint fOpenMode, uint fDataType, IntPtr hInstance);
[DllImport("MyDll.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
public static extern uint ConnectRequest(IntPtr hComs, uint cTimeOut);
static void Main(string[] args)
{
IntPtr hComs = new IntPtr();
uint test_OpenRequest = 0;
test_OpenRequest = OpenRequest(out hComs, "Host01", 0, 0, 0, hComs);
}
Edit 2
[DllImport("WinCom32.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
public static extern uint OpenRequest(out IntPtr hComs, string host, uint fBlockingMode, uint fOpenMode, uint fDataType, IntPtr hInstance);
static void Main(string[] args)
{
IntPtr hComs = new IntPtr();
uint test_Request = 0;
string hostName = ConfigurationManager.AppSettings["HostName"];
IntPtr hInstance = Marshal.GetHINSTANCE(Assembly.GetEntryAssembly().GetModules()[0]);
test_Request = OpenRequest(out hComs, hostName, 0, 0, 1, hInstance);
Console.WriteLine("Request response value: " + test_Request.ToString());
}
There's a test application I can run that shows that this is supposed to work because it's able to connect to the host, so I've got to be doing something wrong.
I'm trying to PInvoke the following function from GitHub's fork of CMark
char *cmark_markdown_to_html(const char *text, size_t len, int options)
and here's my PInvoke signature:
[DllImport("cmark.dll")]
public static extern IntPtr cmark_markdown_to_html(
[In()] [MarshalAs(UnmanagedType.LPStr)] string text,
[MarshalAs(UnmanagedType.SysUInt)] uint len,
[MarshalAs(UnmanagedType.SysInt)] int options);
I call it as follows:
var retValue = cmark_markdown_to_html(markdown, 0, 0);
However, it throws a Marshaling exception the with the message:
Cannot marshal 'parameter #2':
Invalid managed/unmanaged type combination
(Int32/UInt32 must be paired with I4, U4, or Error).
OK, so I change the signature to:
[DllImport("cmark.dll")]
public static extern IntPtr cmark_markdown_to_html(
[In, MarshalAs(UnmanagedType.LPStr)] string text,
[MarshalAs(UnmanagedType.U4)] uint len,
[MarshalAs(UnmanagedType.I4)] int options);
Now it throws a PInvokeStackImbalance error
The name '$exception' does not exist in the current context
Native stuff is a mystery to me. Can someone help?
Stack imbalance
The reason for stack imbalance is described in Why are Cdecl calls often mismatched in the "standard" P/Invoke Convention?.
Basically you need to specify proper calling convention in the DllImport that will probably be cdecl:
[DllImport("cmark.dll", CallingConvention = CallingConvention.Cdecl)]
Marshalling size_t
That one is discussed in what is equal to the c++ size_t in c# .
Assuming that CMark will always be native (32 bit on x86, 64 bit on x64), you should use (U)IntPtr.
If it is always 32 bit, then Int32 should be used.
PInvokeStackImbalance
Presumably CMark is using the default calling convention. The default calling convention for C code is "Cdecl", while the default used for P/invoke calls is "StdCall". The calling convention specifies how the arguments and return value are placed on the call stack. A mismatch between the used calling convention causes the stack to become imbalanced.
You can specify the calling convention to use from C# code in the DllImport attribute.
[DllImport("cmark.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr cmark_markdown_to_html(
[In, MarshalAs(UnmanagedType.LPStr)] string text,
[MarshalAs(UnmanagedType.U4)] uint len,
[MarshalAs(UnmanagedType.I4)] int options);
Marshalling
In case you want your code to be compatible with architectures other than 32-bit, you would want to marshall size_t with UIntPtr. (Read #Eugene Podskal answer)
[DllImport("cmark.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr cmark_markdown_to_html(
[In, MarshalAs(UnmanagedType.LPStr)] string text,
[MarshalAs(UnmanagedType.U4)] UIntPtr len,
[MarshalAs(UnmanagedType.I4)] int options);
Then you can call the method like so
var retValue = cmark_markdown_to_html(markdown, UIntPtr.Zero, 0);
I'm adding new disk device to system from my C# code, so I want to call
[System.Runtime.InteropServices.DllImport("Shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public extern static void SHChangeNotify(long wEventId, uint uFlags, IntPtr dwItem1, IntPtr dwItem2);
like below
MyWin32Functions.SHChangeNotify(0x00000100/*ADDRIVE*/, 0x0005/*PATHW*/, driveLetter, IntPtr.Zero);
dwItem1 is void* and we should pass a wchar_t* (pointing to null terminated string) containing drive root in this case; so driveLetter above is
string letter = "Z:\\";
byte[] data = Encoding.Default.GetBytes(letter);
byte[] zdata = new byte[data.Length + 1];
data.CopyTo(zdata, 0);
IntPtr p = System.Runtime.InteropServices.Marshal.AllocHGlobal(zdata.Length);
System.Runtime.InteropServices.Marshal.Copy(zdata, 0, p, zdata.Length);
(my code almost same as code in similiar case: How to call SHChangeNotify from C# without error 14007
but I get System.AccessViolationException)
Any suggestions what am I doing wrong?
The first parameter in your interop signature should be an int, not a long. Though the Win32 function is declared as LONG, a LONG in Win32 is 32-bit.
[System.Runtime.InteropServices.DllImport("Shell32.dll")]
public extern static void SHChangeNotify(int wEventId, uint uFlags, IntPtr dwItem1, IntPtr dwItem2);
This MSDN article shows the common mapping between Win32 types an .NET types for Platform Invoke.
Making a function call to .NET 4 to native code is resulting in the following exception:
A call to PInvoke function has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.
Here is my definition in Native Code:
typedef void ( CALLBACK* CB_DOWNLOADING )
(
ULONG, // secs elapsed
LPARAM, // custom callback param
LPBOOL // abort?
);
FETCH_API HttpFetchW
(
LPCWSTR url,
IStream** retval,
LPCWSTR usrname = NULL,
LPCWSTR pwd = NULL,
BOOL unzip = TRUE,
CB_DOWNLOADING cb = NULL,
LPARAM cb_param = 0,
LPWSTR ctype = NULL,
ULONG ctypelen = 0
);
Here is the .NET counterpart:
[DllImport(dllPath, CharSet = CharSet.Unicode, SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
internal static extern FETCH HttpFetchW
(
[MarshalAs(UnmanagedType.LPWStr)]
string url,
out System.Runtime.InteropServices.ComTypes.IStream retval,
[MarshalAs(UnmanagedType.LPWStr)]
string usrname,
[MarshalAs(UnmanagedType.LPWStr)]
string pwd,
bool unzip,
dlgDownloadingCB cb,
IntPtr cb_param,
[MarshalAs(UnmanagedType.LPWStr)]
string ctype,
ulong ctypelen
);
Where FETCH is an enum.
[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
internal delegate void dlgDownloadingCB(ulong elapsedSec, IntPtr lParam, bool abort);
internal static void DownloadingCB(ulong elapsedSec, IntPtr lParam, bool abort)
{
// Console.WriteLine("elapsedSec = " + elapsedSec.ToString());
}
Can anyone suggest an alternative within the .NET 4?
Thank you very much for your help.
The only clear error in HttpFetchW that I can see is that C# ulong is 64 bits wide, by C++ ULONG is 32 bits wide. The C# code for the final parameter should be uint.
Other things to check include the calling convention. Are you sure it is cdecl? Are you sure that SetLastError should be true?
As for the callback, you make the same error with ulong. And the abort parameter is LPBOOL. That is a pointer to BOOL. So you should declare the C# parameter as a ref parameter. And the callback is declared with CALLBACK which is stdcall.
So the delegate should be:
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
internal delegate void dlgDownloadingCB(
uint elapsedSec,
IntPtr lParam,
ref bool abort
);
Or simply delete the UnmanagedFunctionPointer attribute since the default is stdcall.
I think it exceptionally likely that since the callback is stdcall, so will the function. I expect that the FETCH_API macro expands to both the return enum and the calling convention. Since you did not supply those details, I can only guess. You'll need to check.
The other thing that we cannot check is CB_DOWNLOADING.
Anyway, with those assumptions, the function becomes:
[DllImport(dllPath, CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern FETCH HttpFetchW(
string url,
out System.Runtime.InteropServices.ComTypes.IStream retval,
string usrname,
string pwd,
bool unzip,
dlgDownloadingCB cb,
IntPtr cb_param,
string ctype,
uint ctypelen
);
Source : MSDN
In the .NET Framework version 3.5, the pInvokeStackImbalance MDA is disabled by default. When you use the .NET Framework version 3.5 with Visual Studio 2005, the pInvokeStackImbalance MDA will appear in the Managed Debugging Assistants list in the Exceptions dialog box (which is displayed when you click Exceptions on the Debug menu). However, selecting or clearing the Thrown check box for pInvokeStackImbalance does not enable or disable the MDA; it only controls whether Visual Studio throws an exception when the MDA is activated.
https://msdn.microsoft.com/en-us/library/0htdy0k3(v=vs.110).aspx
I have following method in my C++ dll and I am trying to call it in my C# application by means p/invoke.
void Graphics::Create(char* Project, char* Connection, int Count, char *_Source[], char *_Destination[], char *_Search[], char *_Replace[], int _Block[])
Signature I use in C# is:
[DllImport("Wincc.dll", CharSet = CharSet.Unicode, SetLastError = true)]
static public extern void Create(IntPtr Project, IntPtr Connection, int Count, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr)] string[] _Source, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr)] string[] _Destination, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr)] string[] _Search, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr)] string[] _Replace, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.I4)] int[] _Block);
I get unknown method in C#. Seems my signature is wrong. However I cannot figure it out what is wrong.
You can not call a C++ function as C++ does not have C linkage. To achieve this add extern "C" before your function.
extern "C" {
int foo();
}
But it wont work on C++ methods. There is an uglier solution though. But I dont recommend it.
Best approach is to write down a wrapper. Wrap your tasks (only what you need) in C++ only using function. In the function you can call those methods. And then compile it with C linkage. Then you'll be able to call it from C#.
Check your DLL with dependency walker, see if you have proper export in your DLL. Try to define your export in YOURDLLNAME.DEF file. Like this:
YOURLLNAME.DEF
EXPORTS
Create