I am writing a C# wrapper around a third party C++ library and with a new version a method parameter changed from uint to ulong.
I still need to support the old version preferably without changing the wrapper interface.
Now I would need to know if I can call the new or the old method. I already tested that I can call the new method with the old library without a C# exception but of course the results will be wrong.
Is there a way to check if a native method with specific parameter types exists? Or maybe another way around it?
This would one example of a changed method (notice the value parameter):
[DllImport("Foo.dll")]
public extern static uint Bar(IntPtr ptr, uint value, out IntPtr optr);
[DllImport("Foo.dll")]
public extern static uint Bar(IntPtr ptr, ulong value, out IntPtr optr);
Related
I have a working C# wrapper class for a native library.
Almost all the native methods are expecting a pointer to structure as a parameter, for example:
returntype1 method1(struct1** param1, ...); // yes, there is one method with double reference parameter
returntype2 method2(struct1* param2, ...); // most of the methods expects simple pointer to struct
returntype3 method3(struct1* param3, ...); // most of the methods expects simple pointer to struct
The required structure parameter is defined in the C library header file.
My wrappers are following:
[DllImport(LibraryName, CharSet = Charset.Ansi)]
public static extern int WrapperMethod1(ref IntPtr struct1, ...);
[DllImport(LibraryName, CharSet = Charset.Ansi)]
public static extern int WrapperMethod2(IntPtr struct1, ...);
What is not clear for me, how can the wrapper even work, when I simply do NOT define and use the managed version of the native structure? But it works! Tested all the methods and they work exactly as expected.
I simply call them like:
var ptr = IntPtr.Zero;
WrapperClass.WrapperMethod1(ref ptr, ...);
WrapperClass.WrapperMethod2(ptr, ...);
Why I do not need to allocate memory for the structure using for example Marshal.AllocHGlobal or Marshal.StructureToPtr ? Why it simply works just by specifying a simple IntPtr without any structre defintion and allocation?
I've implemented a very simple custom marshaler for an API:
Custom Marshaler:
private sealed class JuliaWrapperMarshaller : ICustomMarshaler
{
object ICustomMarshaler.MarshalNativeToManaged(IntPtr pNativeData) => (JuliaWrapper)pNativeData;
[other methods removed]
}
API:
[DllImport(#"libjulia.dll", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(JuliaWrapperMarshaller))]
public static extern JuliaWrapper jl_eval_string(string str);
And this works fine when the jl_eval_string method returns a non-zero IntPtr. I can convert it to my return object JuliaWrapper and all is well.
The problem comes when I execute jl_eval_string with invalid parameters and it returns a zero IntPtr.
I want to handle this in my JuliaWrapper object and automatically call 'get last error'. However I don't get the chance to, because the ICustomMarshaler.MarshalNativeToManaged method is never invoked when the jl_eval_string method returns 0x0000
Is there a way of telling the custom marshaler to provide me with 0 IntPtr values?
Are there any hacks to work around this?
Is there a better way of working?
Based on Hans' comment, this isn't possible.
In order to achieve similar functionality, I created public/private shadow functions which return my wrapper class.
The implicit operator function receives the IntPtr which is 0 or otherwise, and calls the constructor of my wrapper class, which I then have code in to handle calling 'GetLastError' if the IntPtr is 0.
RegSetValueEx has the following P/Invoke signature:
[DllImport("advapi32.dll", SetLastError = true)]
static extern uint RegSetValueEx(
UIntPtr hKey,
[MarshalAs(UnmanagedType.LPStr)]
string lpValueName,
int Reserved,
RegistryValueKind dwType,
IntPtr lpData,
int cbData);
The IntPtr lpData parameter can be a pain to work with. To pass a string value, I need to call one of the Marshall.StringToHGlobal functions and then release it when I'm done. My code can be simpler if I change the type of the lpData parameter to [MarshalAs(UnmanagedType.LPStr)]String lpData. This seems to work and I can imagine that behind the scenes the marshalling code is doing exactly what I would do to get an IntPtr. I haven't been able to find any definitive statements if this is legal or not. Can anyone provide one?
[Yes, I know there is managed code to interface with the registry. In my particular case I can't use it, and even if I could I would still be interested in the answer in general]
Yes, this is a perfectly normal and acceptable technique in pinvoke. Just about any winapi function argument of type BYTE*, PVOID, LPARAM lends itself to a customized [DllImport] declaration. A string, array or struct is the usual equivalent C# parameter type. Particularly useful when you declare SendMessage().
Not where it ends, you can also readily take advantage of the C# language allowing method overloads. In other words, you can write any number of RegSetValueEx() declarations with different types for the lpData argument. They all map to the same native function so nothing else you have to do. A practical example is here.
You just have to make sure that the value you pass after marshalling has the expected byte values. Beware that mistakes tend to be hard to debug, you might still want to marshal manually if the call doesn't pan out. One quirk is certainly notable for this question, you always want to use CharSet = CharSet.Unicode in the declaration, calling the ANSI version (RegSetValueExA) is not useful. Now you can also add ExactSpelling = true.
I'm working on a Vulkan wrapper for C# (like I'm sure many people are) and I'm having a bit of a problem with vkGetPhysicalDeviceFeatures it either doesn't return data, or throws Access Violations
Unanaged Side - Signature:
The signature from the spec is this:
void vkGetPhysicalDeviceFeatures(
VkPhysicalDevice physicalDevice,
VkPhysicalDeviceFeatures* pFeatures);
VkPhysicalDevice is a handle object defined as:
#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object;
VK_DEFINE_HANDLE(VkPhysicalDevice)
This is just a pointer and other imports using IntPtr or SafeHandle wrappers for objects of this shape work.
Managed Side - DLL Import:
Expected DLL Import (but failing):
[DllImport("vulkan-1.dll", EntryPoint = "vkGetPhysicalDeviceFeatures")]
internal static extern void GetPhysicalDeviceFeatures(PhysicalDeviceHandle physicalDevice, ref IntPtr features);
This is similar to other working imports. Note: PhysicalDeviceHandle is derived from SafeHandle should be marshalled to IntPtr, I have other imports with this pattern that work. The above throws an access violation when called.
Platform:
Windows 10 (x64)
Nvidia Driver: 356.43-vkonly (latest)
Update
#V. Kravchenko was correct
There was nothing wrong with the import above. My issue was actually with the vkEnumeratePhysicalDevices call.
First off I had the import wrong, the correct import looks like:
[DllImport("vulkan-1.dll", EntryPoint = "vkEnumeratePhysicalDevices ")]
internal static extern Result EnumeratePhysicalDevices (InstanceHandle instance, ref physicalDeviceCount, IntPtr[] physicalDevices);
Second off, I was actually using the function incorrectly. You need to call vkEnumeratePhysicalDevices twice. The first call gets the count of devices, the second call populates the array of devices.:
IntPtr[] devices = new IntPtr[]();
uint deviceCount = 0;
// populates deviceCount with the number of devices
Vk.EnumeratePhysicalDevices(instanceHandle, ref deviceCount, null);
// populates the devices array with the handle to each device, will only populate up to deviceCount devices
Vk.EnumeratePhysicalDevices(instanceHandle, ref deviceCount, devices);
Note: this is outlined in the description/valid usage section of the function's documentation, I just didn't interpret it correctly on the first read through.
Once I finally had the right handle values from EnumeratePhysicalDevices then my final call to GetPhysicalDeviceFeatures worked as expected. The final import for GetPhysicalDeviceFeatures looks like:
[DllImport("vulkan-1.dll", EntryPoint = "vkGetPhysicalDeviceFeatures")]
internal static extern void GetPhysicalDeviceFeatures(PhysicalDeviceHandle physicalDevice, ref VkPhysicalDeviceFeatures features);
Note: any variable with Handle in the name is a subclass of SafeHandle.
You must IntPtr, which actually does point to a valid object, but not just IntPtr. Access violation means that code in dll is trying to access memory, that your IntPtr points and can't, because your IntPtr doesn't point to a valid object.
Overall, you should use your expected variant, but pass pointer to a valid object.
Working variant is working, because ref IntPtr is actually a pointer to IntPtr, and IntPtr object's location, to which ref IntPtr is pointing, is valid memory.
How do I declare in C# a C function that returns a pointer to a structure?
I believe following is one way to do that, followed by Marshal.PtrToStructure to get actual structure value.
// C-function
SimpleStruct * Function(void);
// C# import
[DllImport("MyDll.dll")]
public static extern IntPtr Function();
Am I correct about that?
Are there other ways to accomplish the same? (It would be OK to get struct back by value)
Since the function returns a pointer (hopefully not a locally allocated one?) your best bet is to manually marshal it (via Marshal.PtrToStructure).
If it were a parameter you could create a managed version of the structure using the PInvoke Interop Assistant then pass it via ref or out.
Caveat: this will only work if the pointer returned is to memory already managed by the CLR
I believe what you are looking for is
// C# import
[DllImport("MyDll.dll")]
[return : MarshalAs(UnmanagedType.LPStruct)]
public static extern StructureName Function();
[StructLayout(LayoutKind.Sequential)]
public class StructureName {}
This should eliminate the need for any manual Marshal.PtrToStructure calls. Depending on what your structure contains, you may need to tag some fields with MarshalAs attributes as appropriate. MSDN has a good example of this.
I am not an expert here at all, but I happened to be looking at a piece of code (that i don't understand completely mind you) that is doing this same thing.
Here is what they are doing
[DllImport("")]
private static extern short MethodName([In,Out] ref StructureName variable);
and then on the structure they have the following attribute
[StructLayout(LayoutKind.Sequential, Size = #)]
public struct StructureName {}
I think the part you are looking for is the [In,Out] part, and since it's being passed via ref, you should be getting the same data back.
marked as community wiki so people can fix this if wrong.