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.
Related
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);
I have an unmanaged function call that is throwing this exception when I try to pass it the path to a file name.
I've read that this is likely caused by the DLL itself but I don't think that is the case since the DLL is used in another application, so the problem is likely in my method calling the function.
The specification:
libvlc_media_new_path (libvlc_instance_t *p_instance, const char *path)
Description:
p_instance the instance
path local filesystem path
And my method:
[DllImport("libvlc", EntryPoint = "libvlc_media_new_path")]
public static extern IntPtr NewMedia(IntPtr instance,
[MarshalAs(UnmanagedType.LPStr)] string path);
I think I'm missing the convention call but what would that likely be? Or would it be something else causing this exception?
EDIT: Based on some comments I did some poking around and found... well, nothing. The struct for the instance is opaque, which means I have no idea in Laymans terms. My guess is that it means you don't need to reconstruct it in the application that is using it?
In a blind guess based on this, I replaced the return value that I had been using with the function responsible for setting the *p_instance value to a long instead of an IntPtr since when it was an IntPtr it was returning 0, and with a long I was seeing a value. Again, what an IntPtr is I don't really know. I was pretty happy to see something not 0 in the instance variable but when I ran it past that, it errored out again.
EDIT: I've expanded the question to here.
Based on the exception you're seeing and the declaration you've provided for the native function,
libvlc_media_new_path (libvlc_instance_t *p_instance, const char *path)
your p/invoke declaration is incorrect. You've mismatched the calling conventions. The default for the .NET p/invoke system is stdcall (to match the Windows API functions), but the default for C and C++ code is cdecl. You have to tell .NET explicitly that your function uses the cdecl calling convention.
So change it to look like this:
[DllImport("libvlc", EntryPoint = "libvlc_media_new_path", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr NewMedia(IntPtr instance,
[MarshalAs(UnmanagedType.LPStr)] string path);
Of course, I'm guessing that you're right about the return value being a pointer. The native function declaration you've shown is missing the return type.
As for your question about the instance parameter, and whether you are correctly using the IntPtr type: The parameter is a pointer to a libvlc_instance_t, so you have two basic ways of making that work using p/invoke. First is to declare the parameter as an IntPtr, which gets it marshalled like a raw pointer value. This is not particularly useful for cases where the pointer needs to be anything other than opaque (i.e. retrieved from one native function, stored, and then passed to another native function). Second is to declare a managed structure that mirrors the native structure, and then write the p/invoke declaration to use this structure so that the marshaller will handle things automatically. This is most useful if you actually need to interact with the values stored in the structure pointed to by the pointer.
In this case, after a Google search, it looks like you're using one of the VLC APIs. Specifically this one. That also tells us what an libvlc_instance_t is: it is an opaque structure that represents a libvlc instance. So declaring a managed structure is not an option here, because the structure is treated as opaque even by the native code. All you really need is the pointer, passed back and forth; a perfect case for the first method I talked about above. So the declaration shown above is your winner.
The only battle now is obtaining a valid pointer to a libvlc instance that you can pass to the function whenever you call it. Chances are good that will come from a prior call to a function like libvlc_new, which is documented as creating and intializing a new libvlc instance. Its return value is exactly what you need here. So unless you've already created a libvlc instance (in which case, use that pointer), you will also need to call this function and store its result.
If the documentation is correct about the required values for the libvlc_new function's parameters, you can declare it very simply:
[DllImport("libvlc", EntryPoint = "libvlc_new", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr NewCore(int argc, IntPtr argv);
And call it thus:
IntPtr pLibVlc = NewCore(0, IntPtr.Zero);
// now pLibVlc should be non-zero
And of course, I know nothing about the VLC APIs, but my general knowledge of API design tells me that you will probably need to call the libvlc_release function with that same pointer to an instance once you're finished with it.
Try without the [MarshalAs(UnmanagedType.LPStr)], usually works for me.
I have this signature in a delphi 2007 function I'm calling (the SomeOtherFile is another DLL that it in turn is calling):
function MyFunction(Place, Name: PChar):_Recordset; stdcall; far; external 'SomeOtherFile.DLL';
I'm trying to call it from C# code like this:
[DllImport("MyFile.dll", CallingConvention = CallingConvention.StdCall,
CharSet = CharSet.Ansi, EntryPoint="MyFunction")]
public static extern DataSet MyFunction(string Place, [MarshalAs(UnmanagedType.LPStr)]string Name);
Whenever I run this and store it into a variable, I get a runtime error about type mismatches. I guess I'm reading the signature wrong, but I can't figure out what it should be.
edit
The actual error is: A call to PInvoke function [...] has unbalanced the stack...I've also tried both params using the MarshalAs attribute, and it throws the same thing.
I've done a bit of digging around and I think you need to marshal the return value as a Recordset interface. I'm sure the P/Invoke marshaller won't magically convert your Delphi _Recordset into a .net DataSet class instance.
So I think you can write it something like this:
[DllImport("MyFile.dll")]
[return: MarshalAs(UnmanagedType.Interface)]
public static extern object MyFunction(string Place, string Name);
Call it like this
Recordset rs = (Recordset) MyFunction(Place, Name);
I'm assuming that the Place and Name parameters are input parameters, in which case the default marshalling for string is just fine.
You don't need to specify ANSI character set because that is the default too. You don't need to name the entry point if it has the same name as the C# function. You don't need to specify the calling convention because stdcall is the default.
The Recordset interface resides in the ADODB namespace.
As an aside, the use of far in your Delphi function import is spurious. The far keyword stopped having any effect once we left the 16 bit world behind.
I'm trying to override the behavior of an external function in user32.dll because I don't want a certain window to show up.
What I'm trying to do is this:
[DllImport("user32.dll")]
public extern override IntPtr GetSystemMenu(IntPtr hMenu, bool bRevert)
{
return new IntPtr();
}
but this won't work because I get the following errors:
... no suitable method found to override
and
... cannot be extern and declare a body
Is there any way to simulate what I'm trying to do?
If the source code that calls GetSystemMenu is within your control then you can provide an alternative GetSystemMenu which delegates to the real one most of the time, but does something different for your special case.
If the source code that calls GetSystemMenu is outside your control then you will need to use hooks. In this situation you need to modify how user32.GetSystemMenu behaves which is entirely outside your codebase.
I think your problem stems from the fact that you're illegally adding an implementation to an external method declaration.
The C# specification (10.6.7 External methods) states that:
Because an external method declaration
provides no actual implementation, the
method-body of an external method
simply consists of a semicolon. An
external method may not be generic.
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.