In C++, calling this function is just as simple as:
CertEnumSystemStore(CERT_SYSTEM_STORE_CURRENT_USER, NULL, NULL, (PFN_CERT_ENUM_SYSTEM_STORE)addr);
Addr would just be the base address of where the function resides
In C#, you can't just pass in an address, and will have to pass in a function, which is not what I want in this case. Below is a snippet of my code
public delegate bool CertEnumSystemStoreCallback([In, MarshalAs(UnmanagedType.LPWStr)] String pvSystemStore, uint dwFlags, ref CERT_SYSTEM_STORE_INFO pStoreInfo, uint pvReserved, [In, MarshalAs(UnmanagedType.LPWStr)] String pvArg);
[DllImport("crypt32.dll", CharSet = CharSet.Unicode)]
public static extern uint CertEnumSystemStore(uint dwFlags, uint pvSystemStoreLocationPara, String pvArg, CertEnumSystemStoreCallback pfnEnum);
[StructLayout(LayoutKind.Sequential)]
public struct CERT_SYSTEM_STORE_INFO
{
uint cbSize;
}
CertEnumSystemStore(CERT_SYSTEM_STORE_CURRENT_USER, 0, null, (CertEnumSystemStoreCallback)addr);
I get a type conversion error that tells me it can't cast type InPtr to type CertEnumSystemStoreCallback.
What can I do to just pass an address containing the function instead of having to supply the function name itself?
Related
I'm trying to build a struct for LDAP in C#, but I if I try to convert the InPtr to the struct I defined it throws the following exception:
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
[DllImport("wldap32.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_sslinitW",
SetLastError = true, CharSet = CharSet.Unicode)]
private static extern IntPtr ldap_sslinit(string hostName, uint portNumber, int secure);
//https://learn.microsoft.com/en-us/windows/win32/api/winldap/ns-winldap-ldap
[StructLayout(LayoutKind.Sequential)]
public struct LDAP
{
[StructLayout(LayoutKind.Sequential)]
struct ld_sb
{
System.UIntPtr sb_sd;
byte Reserved1;
System.UIntPtr sb_naddr;
byte Reserved2;
}
string ld_host;
UInt32 ld_version;
byte ld_lberoptions;
UInt32 ld_deref;
UInt32 ld_timelimit;
UInt32 ld_sizelimit;
UInt32 ld_errno;
string ld_matched;
string ld_error;
ulong ld_msgid;
string Reserved3;
UInt32 ld_cldaptries;
UInt32 ld_cldaptimeout;
UInt32 ld_refhoplimit;
UInt32 ld_options;
}
private const uint LDAP_SSL_PORT = 636;
static void Main(string[] args)
{
IntPtr ld = ldap_sslinit("test", LDAP_SSL_PORT, 1);
var ldap = Marshal.PtrToStructure(ld, typeof(LDAP));
}
Before this I tried to declare the ldapsslinit method with private static extern LDAP ldap_sslinit(string hostName, uint portNumber, int secure); However, it returns the following error:
'Method's type signature is not PInvoke compatible.'
I think the problem is caused by the LDAP struct I defined, but I don't known which type from unmanged to managed was wrong.
unmanaged
managed
UINT_PTR
UIntPtr
UCHAR*
byte[]
ULONG_PTR
UIntPtr
PCHAR
string
ULONG
UInt32
UCHAR
byte
Did I use the wrong mapping in this table?
What specifically are you trying to accomplish. There are managed types in C# for connecting to and using LDAP that don't require native implementations like you are trying to use.
If for some reason you need the native implementation (Note: since you are stuck on step one of a complex handshake I would recommend using a managed implemtation), Instead of the c++ definition of the nested ldap_sslinit struct declare it outside of LDAP
struct ld_sb
{
System.UIntPtr sb_sd;
byte Reserved1;
System.UIntPtr sb_naddr;
byte Reserved2;
}
public struct LDAP
{
ld_sb ld_sb;
string ld_host;
//...
}```
First: I'm sorry if the title is wrong. I'm not sure how to name my problem.
In my C API I have a function:
MYAPI_STATUS SetParam(void *hInst, unsigned long param, void *value);
This function accepts different types of pointers depending on param type. Like this:
SetParam(hInst, 1, (void*)"somevalue");
int x = 55;
SetParam(hInst, 2, &x);
I'm just writing a wrapper/binding in C# and I have a problem.
[DllImport("myapi", CallingConvention = CallingConvention.Cdecl]
public static extern uint SetParam(IntPtr hInst, uint paramCode, IntPtr paramValue);
What's the best way to replicate behaviour from C? So the function would look like:
public static uint SetParam(IntPtr hInst, uint paramCode, ref object paramValue);
or possibly:
public static uint SetParam(IntPtr hInst, uint paramCode, object paramValue);
I solved it by marshalling manually first checking type of object if the object is string then I use Marshal.StringToHGlobalAnsi if it's something else then I marshall differently based on what I need.
If someone has any better solution feel free to write :)
The * sign in C programming means give parameter by reference, so this code is not match:
public static uint SetParam(IntPtr hInst, uint paramCode, object paramValue);
Because it gives parameter by value.
This code is very similar to what you want:
public static uint SetParam(IntPtr hInst, uint paramCode, ref object paramValue);
But there is a bit difference. When you using ref before a parameter you have to initialize it before sending to the method, but by using out you don't have this limitation for passing it. So I think the best possible match will be this code:
public static uint SetParam(IntPtr hInst, uint paramCode, out object paramValue);
I'm taking my first steps in COM but I keep getting System.AccessViolationException which is one of those exceptions which tells you nothing of value. I'm trying to create an IShellItem with SHCreateItemFromParsingName. I copied the definition of the interface from another project so I know there is nothing wrong with it, the problem is most likely in my function definition/call, which I wrote myself for learning purposes.
I want to call the unmanaged function without it returning the IShellItem interface but instead passing a reference of it to the last argument in the call.
The function declaration:
[DllImport("shell32.dll", CharSet = CharSet.Unicode)]
internal static extern uint SHCreateItemFromParsingName([MarshalAs(UnmanagedType.LPWStr)] string pszPath, IBindCtx pbc, Guid riid, out IShellItem ppv);
The function call:
IShellItem file;
SHCreateItemFromParsingName(#"C:\file.txt", null, typeof(IShellItem).GUID, out file);
I find IDL to be rather cryptic, but my reasoning is:
HRESULT = uint
[in] PCWSTR = [MarshalAs(UnmanagedType.LPWStr)] string
[in, optional] IBindCtx = IBindCtx
[in] REFIID = Guid
[out] void = out IShellItem
SHCreateItemFromParsingName function
The problem comes from the REFIID type parameter. It's not a GUID (a 16 bytes struct), but a GUID reference (REFIID), a pointer (so 4 or 8 bytes depending on process bitness).
So you could define the method like this, with a ref keyword (so the struct would be passed by reference, as a pointer):
internal static extern uint SHCreateItemFromParsingName(
[MarshalAs(UnmanagedType.LPWStr)] string pszPath,
IBindCtx pbc,
ref Guid riid,
out IShellItem ppv);
But I recommend this way which is easier to use and avoids creating/copying GUIDs all around (you will call it the same way as you do):
internal static extern uint SHCreateItemFromParsingName(
[MarshalAs(UnmanagedType.LPWStr)] string pszPath,
IBindCtx pbc,
[MarshalAs(UnmanagedType.LPStruct)] Guid riid,
out IShellItem ppv);
I created a C# application which use 2 C++ Dll, the first one work very well, but i have some trouble with the second.
I'm flashing a CPU :
My dll :
[DllImport(#"st10flasher.dll")]
public static extern long SetCom(string PortName, long comspeed);
[DllImport(#"st10flasher.dll")]
public static extern long LoadFile(string FileName, ref long Fsize);
[DllImport(#"st10flasher.dll")]
public static extern long InitMonitor(string device);
[DllImport(#"st10flasher.dll")]
public static extern long ProgramFlash();
[DllImport(#"st10flasher.dll")]
public static extern long EraseFlash(long Block);
[DllImport(#"st10flasher.dll")]
public static extern long CloseCom();
[DllImport(#"st10flasher.dll")]
public static extern long BlockNBToErase(bool EraseBlockError);
It usually work but sometime it crash with.
-I checked the event log and found the exception code : 0xc0000409
-It ask me if i want to debug it with VS then i have this stack :
The Error message isn't in english i'll try to translate :
unmanaged exception 0x71E2CF1B (clr.dll). the instrumentation code stack cookie detected exceeding the stack buffer
What could it be ? thanks !
As you asked i added the VB declaration :
Declare Function SetCom Lib "st10flasher.dll" (ByVal PortName$, ByVal comspeed As Long) As Long
Declare Function LoadFile Lib "st10flasher.dll" (ByVal FileName$, ByRef Fsize As Long) As Long
Declare Function InitMonitor Lib "st10flasher.dll" (ByVal device As Any) As Long
Declare Function ProgramFlash Lib "st10flasher.dll" () As Long
Declare Function GetError Lib "st10flasher.dll" (ByVal BufferForStatus As Any) As Long
Declare Function EraseFlash Lib "st10flasher.dll" (ByVal Block As Long) As Long
Declare Function CloseCom Lib "st10flasher.dll" () As Long
/************************************************** EDIT **************************************************/
So i updated my functions declaration like that :
[DllImport(#"st10flasher.dll")]
public static extern uint SetCom([MarshalAs(UnmanagedType.LPStr)] string PortName, uint comspeed);
[DllImport(#"st10flasher.dll")]
public static extern uint LoadFile([MarshalAs(UnmanagedType.LPStr)] string FileName, ref uint Fsize);
[DllImport(#"st10flasher.dll")]
public static extern uint InitMonitor([MarshalAs(UnmanagedType.LPStr)] string device);
[DllImport(#"st10flasher.dll")]
public static extern uint ProgramFlash();
[DllImport(#"st10flasher.dll")]
public static extern uint EraseFlash(uint Block);
[DllImport(#"st10flasher.dll")]
public static extern uint CloseCom();
[DllImport(#"st10flasher.dll")]
public static extern uint BlockNBToErase(bool EraseBlockError);
and i found the dll's documentation :
unsigned int SetCom(char *PortName, unsigned int ComSpeed)
unsigned int CloseCom(void)
unsigned int LoadFile(char *filename)
unsigned int InitMonitor(char *target)
unsigned int EraseFlash(unsigned int BlockMask)
unsigned int ProgramFlash(void)
i tried to update my prototype using this post : post StackOverflow But i still have the same error. Did i misunderstood something from the link ?
/******************************SOLVED****************************/
I solved my problem by creating an other C++ DLL which load and unload the st10flasher.dll
[DllImport(#"st10flasher.dll")]
public static extern uint LoadFile([MarshalAs(UnmanagedType.LPStr)] string FileName, ref uint Fsize);
seems wrong:
unsigned int LoadFile(char *filename)
remove the ref uint Fsize
You didn't have a signature for this:
[DllImport(#"st10flasher.dll")]
public static extern uint BlockNBToErase(bool EraseBlockError);
Everything else should be correct.
I have a dll which accepts a struct that contains a pointer to a function to do a callback.
How can I get an IntPtr to a function of my application to build the struct?
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class OPERATION {
public uint OperationID;
public IntPtr Context;
public IntPtr Callback; -> How to pass this?
}
Here is the delegate accepting the OPERATION struct
public delegate void MY_CALLBACK([In] OPERATION operation, [In] uint msgId, [In] IntPtr msgDataPtr);
use Marshal.GetFunctionPointerForDelegate
Maybe the Marshal.GetFunctionPointerForDelegate method may help you.