I'M browsing through the whole stackoverflow forum but I'm quite unsure if my marshalling solution fits to my problem.
I got a c++ method returning an array of integer via a parameter. The prototype is the following:
method1(uint aId, uint*& aNewIntArray, uint& aNewIntArrayCount);
I marshal the parameters like:
method1(UInt32 aId, ref UIntPtr aNewIntArray, ref UInt64 aNewIntArrayCount);
I marshal uint*& to ref UIntPtr but I'm not very sure if this is correct and while i not found another one having the same problem i'll ask on myself.
Another idea is: Is it possible to marshal int* and int& parameter the same way using
ref UInt32
? Or did I need to use UIntPtr / IntPtr without a "ref" Keyword?
In this case I would prefer to use ref instead of out to avoid the C++ uses a not initialized int reference.
Your C++ method is allocating an array of integers and returning a pointer to the first element in aNewIntArray. Therefore the match C# definition for that parameter is
ref IntPtr aNewIntArray
You used UIntPtr which is basically equivalent. I think you are under the impression that UIntPtr is what you use if the underlying array is unsigned but that is not the case. This is effectively a void* pointer and you will have to use Marshal.Copy to transfer to a C# array, uint[].
Note that since the aNewIntArray really is an out parameter I think you should declare it as such
You also have declared the final parameter incorrectly. It is a 32 bit integer.
I would therefore declare the C# function like this:
method1(uint aId, out IntPtr aNewIntArray, out uint aNewIntArrayCount);
Related
I have this C++ code :
void ReleaseHandle(void* handle){
Machine.motor motor =static_cast<Machine.IMotor*> (handle)
if (motor == 0) throw;
delete motor;
handle = nullptr;
}
so far I can pass a variable into Releasehandle using PInvoke in Managed using uint as data type, problem is the value of passed variable doesn't change. This method is not the whole package, but i think this is enough to illustrate what i want to do. I need the value to change since if the pointer doesn't change in managed side and i decide to call releaseHandle again from managed, it will throw stacktrace since the releaseHandle is called and machine is not found (released).
I have tried a lot of methods of passing datatype as ref from managed including but not limited to :
void*
[In, Out] void*
uint
ref/out uint
ref/out void*
UintPtr
ref/out UintPtr
I expect when i call ReleaseHandle in managed like
uint managedHandle = 123213124;
ReleaseHandle(managedHandle);
Console.WriteLine(managedHandle); // this outputs to 0
Thank you for your help.
Your basic problem is, that you are intending to change the a variable you pass by value.
That having said, as Matthew Watson pointed out in the comment to your question, you have to adjust the interface of the method you are calling in the DLL to take a pointer pointing to the location of the pointer you want to modify.
In your example you need to pass the pointer to managedHandle to ReleaseHandle.
Hence your code should look like this in your DLL:
void ReleaseHandle(void** handle) {
*handle = nullptr; /* Note that here we dereference one level
to modify the content of the location
pointed at */
}
In your C# program on the other hand, you should import the function with something like that:
[DllImport("YourLibrary.dll")]
static extern void ReleaseHandle(ref IntPtr handle);
and invoke it by using the ref keyword:
IntPtr value = IntPtr.Add(IntPtr.Zero, 123456789);
ReleaseHandle(ref managedHandle);
Console.WriteLine(managedHandle); // this outputs to 0
I have a structure:
typedef struct _wfs_bcr_caps
{
WORD wClass;
BOOL bCompound;
BOOL bCanFilterSymbologies;
LPUSHORT lpwSymbologies;
DWORD dwGuidLights[32];
LPSTR lpszExtra;
BOOL bPowerSaveControl;
BOOL bAntiFraudModule;
}
I need to make a correct copy of this structure in C#.
But I have a problem with LPUSHORT type. Could some one help me to set up correct marshal attributes for lpwSymbologies property?
LPUSHORT is just long pointer to ushort value. You can marshal it as IntPtr and than read a value using Marshal.ReadInt16 or Marshal.ReadInt32 (since you are using unsigned short). Another option is described in this article, Unmanaged to Managed type translation table, e.g. marshalling LP<struct> into [In] ref <struct>
This question already has an answer here:
How to pass a nullable type to a P/invoked function [duplicate]
(1 answer)
Closed 5 years ago.
How can i skip the optional parameter (pioRecvPci) in C#?
I think the main problem is that in C the parameter is a pointer so it is possible to supply NULL while in C# the ref keyword on a struct is used which can't be null by definition.
C Code
typedef struct {
DWORD dwProtocol;
DWORD cbPciLength;
} SCARD_IO_REQUEST;
LONG WINAPI SCardTransmit(
__in SCARDHANDLE hCard,
__in LPCSCARD_IO_REQUEST pioSendPci,
__in LPCBYTE pbSendBuffer,
__in DWORD cbSendLength,
__inout_opt LPSCARD_IO_REQUEST pioRecvPci,
__out LPBYTE pbRecvBuffer,
__inout LPDWORD pcbRecvLength
);
C# Code
[StructLayout(LayoutKind.Sequential)]
public struct SCARD_IO_REQUEST
{
public int dwProtocol;
public int cbPciLength;
}
[DllImport("winscard.dll")]
public static extern int SCardTransmit(
int hCard,
ref SCARD_IO_REQUEST pioSendRequest,
ref byte SendBuff,
int SendBuffLen,
ref SCARD_IO_REQUEST pioRecvRequest,
ref byte RecvBuff,
ref int RecvBuffLen);
You can change the struct to a class and then pass null. Remember that a C# struct is quite different from a C++ struct, and here your really want to use a C# class.
Or if you always want to ignore pioRecvRequest change the signature of SCardTransmit so that pioRecvRequest is of type IntPtr. Then pass IntPtr.Zero for the value.
Actually, the SCARD_IO_REQUEST is just a header and if you want to pass it in the call you will have to manage this structure and the additional buffer space yourself anyway so IntPtr is the right choice. You will then have to use the Marshal functions to allocate and fill the structure before the call and unmarshal the data and free it after the call.
C# supports method overloads. Something you can take advantage of here, redeclare the method but now give it an IntPtr argument type (no ref). And pass IntPtr.Zero.
Second way is to marshal the structure yourself. Declare the argument type IntPtr. And use Marshal.AllocHGlobal() to allocate memory for the structure, Marshal.StructureToPtr() to copy the structure into it. Marshal.FreeHGlobal() after the call. Or pass IntPtr.Zero. Clearly the overload trick is much less painful.
How do I pass a pointer to a pointer to a struct as a function parameter in C#?
I am trying to use a function from a DLL which has one of its arguments as a double pointer. For e.g.,
struct mystruct
{
int a;
char b;
};
[DllImport("mydll.dll")]
private static extern int func_name(int a, char b, mystruct** c);
I guess the correct way to use a pointer like int *a is ref int a. Is there anything similar for int **a?
The CLR equivalent for a pointer to a pointer is ref IntPtr.
An IntPtr is a pointer to an integer, and when you pass it by ref, it's transferred by reference, making it a pointer to a pointer.
You may also need to use the Marshal.PtrToStructure method to convert the pointer to your structure object.
See the section entitled "Manual marshalling" near the bottom of this article for more information.
I would work differently.
Any pointer should be used as
System.IntPtr
and I would then use
Marshal.PtrToStructure
for the actual conversion of the pointer to actual structure. Otherwise I would also consider to copy field by field with offsets, which is sometimes easier to debug.
What interop signature would you use for the following COM method? I am interested particularly in the final two parameters, and whether to try to use MarshalAs with a SizeParamIndex or not.
HRESULT GetOutputSetting(
DWORD dwOutputNum,
LPCWSTR pszName,
WMT_ATTR_DATATYPE* pType,
BYTE* pValue,
WORD* pcbLength
);
Documentation states:
pValue [out] Pointer to a byte buffer containing the value. Pass NULL
to retrieve the length of the buffer
required.
pcbLength [in, out] On input, pointer to a variable containing the
length of pValue. On output, the
variable contains the number of bytes
in pValue used.
You could try the PInvoke Signature Toolkit. It's rather useful for getting marshaling right when performing platform interops. It quite possibly won't cover your particular problem, but you may find a comparable one that gives you the information you seek.
I would use the SizeParamIndex, because your scenario is exactly the one this feature is for: To specify the length of a variable sized array.
So the last to parameters would be in C# signature:
byte[] pValue,
ref ushort pcbLength
The byte-Array is passed without ref, because the array corresponds to a pointer in native code.
If you pass NULL (or null in C#) for pValue in order to retrieve the size of the buffer needed. That means also that the caller has to allocate the byte-Array.
The parameter pcbLength is passed by ref, because it is used as an in/out-parameter.