I am not all that familiar with unmanaged code but have been using some of the methods in dnsapi.dll in my C# application. There are lots of examples on how to use DnsQuery, or DnsFlushResolverCache for example, but the method DnsValidateServerStatus seems to be new (requiring Win 7 or Server 2008 R2). I would like to use this method from my C# application but I can't seem to get the Marshaling and structures to work correctly. The documentation for this method can be found at:
http://msdn.microsoft.com/en-us/library/windows/desktop/ee837436(v=VS.85).aspx
Please help!
The difficult part of this Win32 API is the SOCKADDR structure. On PINVOKE.NET there is an implementation of the SOCKADDR structure. The following example is based on this implementation:
[DllImport("Dnsapi.dll")]
private static extern int DnsValidateServerStatus(IntPtr sockaddr, string queryName, ref uint serverStatus);
WinsockSockAddr addr = new WinsockSockAddr(IPAddress.Parse("127.0.0.1"), 0);
uint serverStatus = 0;
int status = DnsValidateServerStatus(addr.PinnedSockAddr, "fqdn server name", ref serverStatus);
Console.Out.WriteLine(status);
Console.Out.WriteLine(serverStatus);
Hope, this helps.
Not sure does it work:
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet=System.Runtime.InteropServices.CharSet.Ansi)]
public struct sockaddr {
/// u_short->unsigned short
public ushort sa_family;
/// char[14]
[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=14)]
public byte[] sa_data;
}
/// Return Type: DWORD->unsigned int
///server: PSOCKADDR->sockaddr*
///queryName: PCWSTR->WCHAR*
///serverStatus: PDWORD->DWORD*
[System.Runtime.InteropServices.DllImportAttribute("dnsapi.dll", EntryPoint="DnsValidateServerStatus")]
public static extern uint DnsValidateServerStatus([System.Runtime.InteropServices.InAttribute()] ref sockaddr server, [System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPWStr)] string queryName, [System.Runtime.InteropServices.OutAttribute()] out uint serverStatus) ;
}
Related
I am working on a project where I need to PInvoke the secur32!AddSecurityPackageA function, but I am still learning the ins and outs of how to do this by hand and could use some help.
Here are a the references I am working with:
https://learn.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-addsecuritypackagea
https://learn.microsoft.com/en-us/windows/desktop/api/sspi/ns-sspi-_security_package_options
And here's a sample of my code where I am trying to define the struct and call the function:
[DllImport("secur32.dll", EntryPoint = "AddSecurityPackageA")]
public static extern void AddSecurityPackageA(
ref string pszPackageName,
ref SECURITY_PACKAGE_OPTIONS[] Options
);
[StructLayout(LayoutKind.Sequential, CharSet =CharSet.Ansi)]
public class SECURITY_PACKAGE_OPTIONS
{
public ulong Size;
public ulong Type;
public ulong Flags;
public ulong SignatureSize;
public IntPtr Signature;
}
string dll = #"c:\temp\test.dll";
SECURITY_PACKAGE_OPTIONS[] pkgOpts = new SECURITY_PACKAGE_OPTIONS();
AddSecurityPackageA(ref dll, ref pkgOpts);
My questions are:
At lines 3 and 4, is this an appropriate use of ref and is this generally correct according to the MSDN docs?
At line 14, the C++ struct on MSDN has this as a void pointer, but while researching I found that the C# equivalent is an IntPtr. Is that correct or do I need to use unsafe?
In general, has anyone found any really good PInvoke tutorials outside of reading other people's code? I'm moving over from Python so it is quite a bit different and much of what I've found is either "draw a circle, draw the rest of the owl" or insanely lengthy MSDN documentation that makes a lot of assumptions.
Thank you!
Some comments:
Use the W function rather than the A function. You don't want to limit yourself to ANSI. This is a Unicode world.
The function has a return value. You must declare the function with a matching return value type. Presumably it is uint or int but you should check in the C++ header file.
ref string is wrong. It should be string.
ref SECURITY_PACKAGE_OPTIONS[] is wrong. It is not an array. It is a pointer to a struct. Since you declared SECURITY_PACKAGE_OPTIONS as a class, a reference type, you can replace ref SECURITY_PACKAGE_OPTIONS[] with SECURITY_PACKAGE_OPTIONS.
C++ unsigned long is 32 bits, so it should be uint in C#.
IntPtr is correct, but that leaves unresolved the question of how to declare the digital signature and obtain a pointer to it. I think it's outside the remit of this question for us to track down an example of how to do that.
This one works for me:
[DllImport("secur32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern uint AddSecurityPackage(
string pszPackageName,
SECURITY_PACKAGE_OPTIONS Options
);
[DllImport("secur32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern uint DeleteSecurityPackage(
string pszPackageName
);
I am going mad trying to call a DLL function for days from a C# application.
Here is the definition of the DLL call:
phStatus_t phbalReg_Rd70xUsbWin_Init
( phbalReg_Rd70xUsbWin_DataParams_t * pDataParams,
uint16_t wSizeOfDataParams )
Here is the definition of phbalReg_Rd70xUsbWin_DataParams_t:
And here is my C# code for calling the DLL:
public static data_params parameters;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct data_params
{
internal ushort wId; //Layer ID for this BAL component, NEVER MODIFY!
internal byte ucTxSeq; //Sequence counter for packets.
[MarshalAs(UnmanagedType.LPStr)]
String pDeviceName;
internal IntPtr pDeviceHandle; //Handle to the USB device.
internal IntPtr pPipeOut; //Handle to Usb Out-pipe.
internal IntPtr pPipeIn; //Handle to Usb In-pipe.
internal ushort wTimeoutWrMs; //TO value for Usb Write pipe transfer.
internal ushort wTimeoutRdMs; //TO value for Usb Read pipe transfer.
}
[DllImport("NxpRdlib.dll", EntryPoint = "phbalReg_Rd70xUsbWin_Init")]
public static extern uint phbalReg_Rd70xUsbWin_Init(ref data_params data_parameters,
public static unsafe uint connectToPegoda()
{
parameters = new data_params();
parameters.wId = 0x05;
parameters.ucTxSeq = 0;
parameters.pDeviceHandle = IntPtr.Zero;
parameters.pPipeOut = IntPtr.Zero;
parameters.pPipeIn = IntPtr.Zero;
parameters.wTimeoutWrMs = 0xFFFF;
parameters.wTimeoutRdMs = 0xFFFF;
return phbalReg_Rd70xUsbWin_Init(ref parameters, (uint)Marshal.SizeOf(parameters));
}
The problem is that I receive a PInvokeStackImbalance exception.
I tried to change type of paramaters with different things and never achieved to get this work. I am sure I am doing something wrong with types, but can't find what. Can someone help me?
The most common explanation is a calling convention mis-match. As written, the unmanaged function declaration uses cdecl. You did not specify a calling convention in your p/invoke and so the default of stdcall is used.
To fix this, specify cdecl in your p/invoke:
[DllImport("NxpRdlib.dll", CallingConvention = CallingConvention.Cdecl)]
You also specified only part of the p/invoke declaration. You missed the second parameter. The full declaration should be:
[DllImport("NxpRdlib.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern uint phbalReg_Rd70xUsbWin_Init(
ref data_params data_parameters,
ushort wSizeOfDataParams
);
The other unknown here is phStatus_t. You've translated that as uint, an unsigned 32 bit integer. We can only take your word that the translation is correct.
Update: From your comment to the question, phStatus_t should be translated as ushort. So, finally, we have:
[DllImport("NxpRdlib.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern ushort phbalReg_Rd70xUsbWin_Init(
ref data_params data_parameters,
ushort wSizeOfDataParams
);
Function description here.
I'm struggling to get it right to call this function from c#.
I'm at a stage where I'm calling it but it's returning E_INVALIDARG.
I've set it up as follows...
[DllImport("p2p.dll", CharSet=CharSet.Unicode)]
internal static extern uint PeerGroupCreateInvitation(IntPtr hGroup, string pwzIdentityInfo, IntPtr pftExpiration, int cRoles, IntPtr pRoles, out string ppwzInvitation);
My best guess is the 5th parameter, "pRoles".
I'm supposed to send it a pointer to one or two GUIDs representing the role type.
PEER_GROUP_ROLE_ADMIN
PEER_GROUP_ROLE_MEMBER
I have no clue presently how to do this from c#.
In C this parameter looks like this when calling the function...
..., (PEER_ROLE_ID*) &PEER_GROUP_ROLE_MEMBER, ...
PEER_ROLE_ID looks like a System.Guid type.
PEER_GROUP_ROLE_MEMBER looks like the actual GUID. (Can I get this from the p2p.dll file?)
Any help would be greatly appreciated... especially since there's close to ZERO info on this function on the internet.
Working solution after everyone's comments.
Declaration:
[DllImport("p2p.dll")]
public static extern uint PeerGroupCreateInvitation(IntPtr hGroup, [MarshalAs(UnmanagedType.BStr)] string pwzIdentityInfo, int pftExpiration, int cRoles, ref Guid pRoles, out IntPtr ppwzInvitation);
Calling:
uint hr = PeerGroupCreateInvitation(hGroup, identityInfo, 0, 1, ref PEER_GROUP_ROLE_MEMBER, out pInvitation);
...where PEER_GROUP_ROLE_MEMBER is the System.Guid for this role.
Getting the invitation:
string invitation = Marshal.PtrToStringAuto(pInvitation);
This is the correct declaration:
[DllImport("p2p.dll")]
public static extern uint PeerGroupCreateInvitation(
IntPtr hGroup, /* Updated with #RedDude's suggestion */
[MarshalAs(UnmanagedType.BStr)] string pwzIdentityInfo,
int pftExpiration, // 32 bit, not 64 bit
int cRoles,
ref Guid pRoles,
out IntPtr ppwzInvitation);
As #strenr has said you should use a ref Guid argument to pass the GUID for the pRoles. However, and you might have already decided against this, have you taken a look at the WCF peer-to-peer support? This would give you most of the peer-to-peer capabilities already wrapped up in a .NET interface?
Take a look here
http://msdn.microsoft.com/en-us/library/system.net.peertopeer.aspx
I am trying to call some legacy C code using interop in C#.
I am not too famliar with how interop works on C# yet but has to work with some confusing structs.
I got part of it working but the address messes up when I try to get the struct into the C layer.
I am trying to pass a struct to C code, it will do something to it, and I need to get a result back
I have these structs in C#
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct RETURNBUFFER
public IntPtr records; //this is the struct RECORD
public IntPtr infoA; // this is the struct INFO
public IntPtr infoB;
public int number;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct INFO
{
public IntPtr doc; //this is a handle in C code
public int cpFirst;
public int cpLim;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct RECORD
{
public int size;
}
Records is actually a pointer to another Struct STATS defined in C# like this,
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct STATS
{
public int size;
public int a;
public int b;
public int c;
public int d;
public int e;
public int f;
public int g;
}
in the C# layer, i create the struct like the following
RETURNBUFFER returnBuffer = new RETURNBUFFER();
returnBuffer.infoA = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(INFO)));
returnBuffer.infoB = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(INFO)));
returnBuffer.records = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(STATS)));
When I run my code, I was only able to retrieve the first item in returnBuffer which is returnBuffer.records,
all the other item including the int value in returnBuffer is messed up.
I try to debug through it and look into the address value,
I found that when the code codes from C# -> C the address is shifted
I am not sure why the address is off,
Here is an example of what happened under a 64bit environment
C#
&ReturnBuffer
0x00000000046f05f8
&ReturnBuffer.records
0x00000000046f05f8
&ReturnBuffer.infoA
0x00000000046f0600
&ReturnBuffer.infoB
0x00000000046f0608
&ReturnBuffer.number
0x00000000046f0610
in C, let say the function I am calling is taking parameter RETURNBUFFER *pReturnBuffer,
i get these address,
pReturnBuffer
0x00000000046F05F8
&pReturnBuffer->records
0x00000000046F05F8
&pReturnBuffer->infoA
0x00000000046F0600
&pReturnBuffer->infoB
0x00000000046F0610 **This address is off by 8**
&pReturnBuffer->number
0x00000000046F0620 **this is off by 16**
So as a result,
when the code moves back to C# function,
I can construct the returnBuffer.records correctly,
but weren't able to construct neither infoA nor infoB nor get the correct value for returnBuffer.number
not sure what I am missing out here.
===============================================
I edited my code with help of, Fun Mun Pieng
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)]
public struct CRB
{
[FieldOffset(0)]
public IntPtr pcstat;//CSTAT
[FieldOffset(8)]
public IntPtr caProc;//NLCA
[FieldOffset(24)]
public IntPtr caSent;//NLCA
[FieldOffset(40)]
public int cnlch;
}
now, the address matches up when it goes to C# -> C++ -> C#
However I am still getting some garbage data back.
I did some investigation and here is the erratic behaviour I found.
in C# code i make the call like this
IntPtr text = Marshal.StringToCoTaskMemUni("I am here");
legacyFunction(text, ref returnBuffer)
in here, when I call the GetHashCode function, i get the following values
returnBuffer.records.GetHashCode() 473881344
returnBuffer.infoA.GetHashCode() 473898944
returnBuffer.infoB.GetHashCode() 473898784
text.GetHashCode() 468770816
upon returning from the function, these hash value changes,
returnBuffer.records.GetHashCode() 543431240
returnBuffer.infoA.GetHashCode() 473799988
returnBuffer.infoB.GetHashCode() 473799988
text.GetHashCode() 473799988
Now, I can actually do,
Marshal.PtrToStringUni(checkReturnBuffer.infoA) and I get "I am here"
C# now thinks, both infoA and infoB are the same as text .
====================================================
2nd edit
The c++ structure is in fact
typedef struct RETURNBUFFER
{
RECORD *precord;
INFO infoA;
INFO infoB;
UINT number;
} CRB;
Thanks for the reply, this was indeed my problem.
I was somehow under the impression,
for every struct/class/object in C++
I have to make an equivalent IntPtr in C#
One last question, while I am here so I dont have to re define all structs in a new question,
for the IntPtr in struct INFO.
in C++, it is of type HANDLE
Am i correct here to define it as IntPtr? It is only a handle, but it is not a *handle thought, or should i just let it be a uint value?
Here's what I read from a msdn site "Remember, any API function that returns or accepts a handle is really working with an opaque pointer. Your code should marshal handles in Windows as System.IntPtr values"
If i defined it as IntPtr,
How should I alloc memory for it? Will the below be correct?
returnBuffer.infoA.doc = Marshal.AllocCoTaskMem(System.IntPtr.Size);
to unmarshal
Marshal.PtrToStructure(returnBuffer.infoA.doc, typeof(IntPtr));
is this the right approach?
Thank you so much
It might be because any of the following:
your C++ is compiled to 16 bytes alignment
your type for infoA is different between C++ and C#, or the size of the types are different
possible solutions include:
[FieldOffset(24)] public IntPtr infoB;
OR
comparing IntPtr.Size against sizeof(infoB) on C++
Edit: It seems infoA is 16 bytes, but your INFO declaration is not 16 bytes. It's very likely that your C# and C++ declarations are different. It would be good if you can include your C++ declarations in the question.
In the meantime, I can only guess the best match to be:
public struct RETURNBUFFER
{
public RECORD records; //this is the struct RECORD
public INFO infoA; // this is the struct INFO
public INFO infoB;
public int number;
}
Your assumption that RETURNBUFFER contains structure pointers has to be wrong. That's the only way that infoA and infoB can take up 16 bytes. The INFO structure certainly is 16 bytes long, I can't see the type of infoB. Thus:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct RETURNBUFFER
public IntPtr records;
public INFO infoA;
public DUNNO infoB;
public int number;
}
Update your question with the C declarations if you still have trouble. It should be easy to see from them.
Try to make sure the win32 struct and c# struct is bit(bit size) mapping. This can be achieved by using exact c# type for win32 type.
Hey, im doing a little app for my smart phone, using Windows Mobile 6. I'm trying to get all currently running processec, but method CreateToolhelp32Snapshot always returns -1. So now im stuck. I tried to get error with invoking GetLastError() method, but that method returns 0 value.
Here is a snippet of my code.
private const int TH32CS_SNAPPROCESS = 0x00000002;
[DllImport("toolhelp.dll")]
public static extern IntPtr CreateToolhelp32Snapshot(uint flags,
uint processid);
public static Process[] GetProcesses()
{
ArrayList procList = new ArrayList();
IntPtr handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if ((int)handle > 0)
{
try
{
PROCESSENTRY32 peCurr;
PROCESSENTRY32 pe32 = new PROCESSENTRY32();
// get byte array to pass to API call
byte[] peBytes = pe32.ToByteArray();
// get the first process
int retval = Process32First(handle, peBytes);
First, your handle check is wrong. It's common for the high bit to be on in a handle, causing it to look like a negative number when cast to a signed int. You should be checking that is isn't NULL (0) or INVALID_HANDLE_VALUE (-1 / 0xffffffff).
You shouldn't be "invoking GetLastError" but calling Marshal.GetLastWin32Error()
You've not set the SetLastError attribute in the P/Invoke declaration. In C# it defaults to false, in VB it defaults to true.
Where's your PROCESS32 implementation? The docs clearly state that the dwLength member must be set before the call and it's not clear here if that's happening.
As a side note, the Smart Device Framework's OpenNETCF.ToolHelp namespace has all of this implemented and working (in case you'd rather not reinvent the wheel).
Instead of
CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
use
private const int TH32CS_SNAPNOHEAPS = 0x40000000;
CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS | TH32CS_SNAPNOHEAPS, 0);
By default CreateToolhelp32Snapshot will try to snapshot the heaps and that can cause an out of memory error.
Found this at https://social.msdn.microsoft.com/Forums/en-US/e91d845d-d51e-45ad-8acf-737e832c20d0/createtoolhelp32snapshot-windows-mobile-5?forum=vssmartdevicesnative and it solved my problem.
If you're not seeing valid "last error" information, perhaps you might need to add the "SetLastError" attribute on the API's DllImport attribute (MSDN reference with code examples). According to the documentation of this attribute, you should set SetLastError to...
...true to indicate that the callee will
call SetLastError; otherwise, false.
The default is false.
The runtime marshaler calls
GetLastError and caches the value
returned to prevent it from being
overwritten by other API calls. You
can retrieve the error code by calling
GetLastWin32Error
As for the API failure you're seeing, I don't spot anything obvious offhand; the code you have seems very similar to the sample code here.
This is the proper implementation based on the MSDN documentation
private const int INVALID_HANDLE_VALUE = -1;
[Flags]
private enum SnapshotFlags : uint
{
HeapList = 0x00000001,
Process = 0x00000002,
Thread = 0x00000004,
Module = 0x00000008,
Module32 = 0x00000010,
Inherit = 0x80000000,
All = 0x0000001F,
NoHeaps = 0x40000000
}
[DllImport("toolhelp.dll"]
private static extern IntPtr CreateToolhelp32Snapshot(SnapshotFlags dwFlags, int th32ProcessID);
[StructLayout(LayoutKind.Sequential)]
public struct PROCESSENTRY32
{
public uint dwSize;
public uint cntUsage;
public uint th32ProcessID;
public IntPtr th32DefaultHeapID;
public uint th32ModuleID;
public uint cntThreads;
public uint th32ParentProcessID;
public int pcPriClassBase;
public uint dwFlags;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string szExeFile;
};
IntPtr hSnap = CreateToolhelp32Snapshot(SnapshotFlags.Process, 0);
if (hSnap.ToInt64() != INVALID_HANDLE_VALUE)
{
PROCESSENTRY32 procEntry = new PROCESSENTRY32();
procEntry.dwSize = (uint)Marshal.SizeOf(typeof(PROCESSENTRY32));
if (Process32First(hSnap, ref procEntry))
{
do
{
//do whatever you want here
} while (Process32Next(hSnap, ref procEntry));
}
}
CloseHandle(hSnap);
Most importantly is this line, because you must set the size of the procEntry:
procEntry.dwSize = (uint)Marshal.SizeOf(typeof(PROCESSENTRY32));