-
Mar 21st, 2013, 06:20 AM
#1
Thread Starter
Junior Member
Marshal.GetDelegateForFunctionPointer() Problem w/ Function returning Struct
Hello -
I used to use DllImport to call an external/unmanaged function as follows ...
Private Declare Function Function_Delegate_A Lib "C:\Program Files\ABC\XYZ.dll" Alias "External_Function" _
(ByRef ArgumentA As TypeA, _
ByVal ArgumentB As Byte) As Return_Type
This worked fine but I had to make the location of the *.dll dynamic so I changed it to ...
Private Delegate Function Function_Delegate_B(ByRef ArgumentA as TypeA, _
ByVal ArgumentB as Byte) As Return_Type
mFunctionPointer = NativeMethods.GetProcAddress(mExternalLibraryPath, "External_Function")
mFunctionPointerDelegate = DirectCast(Marshal.GetDelegateForFunctionPointer(mFunctionPointer, GetType(Function_Delegate_B)), Function_Delegate_B)
Dim XYZ As Return_Type = mFunctionPointerDelegate.Invoke(A, B)
This returns complete garbage for XYZ.
I read in several related posts that you cannot return a struct from a function but where in the .NET documentation does it state that … and why did this work with DllImport?
Thanks,
Joe
-
Mar 21st, 2013, 11:51 AM
#2
Re: Marshal.GetDelegateForFunctionPointer() Problem w/ Function returning Struct
I'm sorry but I don't understand "had to make the location of the *.dll dynamic". As you've kinda proved that that way madness lies it seems to be time to rethink that!
I don't really see much hope of the second method working. It seems to reference all kinds of undeclared and undefined stuff. There is certainly no injunction on returning a structure from a function. Windows would be dead in the water if you couldn't!
As the 6-dimensional mathematics professor said to the brain surgeon, "It ain't Rocket Science!"
Reviews: "dunfiddlin likes his DataTables" - jmcilhinney
Please be aware that whilst I will read private messages (one day!) I am unlikely to reply to anything that does not contain offers of cash, fame or marriage!
-
Mar 21st, 2013, 08:45 PM
#3
Thread Starter
Junior Member
Re: Marshal.GetDelegateForFunctionPointer() Problem w/ Function returning Struct
The problem is that the *.dll is in a location that is determined at run-time ... hence "dynamic". The mechanism I used is well-documented and works for everything else ... except when a function returns a Structure. Here is what that looks like ...
<StructLayout(LayoutKind.Explicit)> _
Public Structure Return_Type
<FieldOffset(0)> Dim ValueA As Single
<FieldOffset(4)> Dim ValueB As Single
End Structure
The other variables are ...
mFunctionPointer As IntPtr = IntPtr.Zero
mFunctionPointerDelegate As Function_Delegate_B = Nothing
Thanks,
Joe
-
Mar 21st, 2013, 09:36 PM
#4
Re: Marshal.GetDelegateForFunctionPointer() Problem w/ Function returning Struct
I'm not 100% sure but I think you need to use the MarshalAsAttribute on the return type.
Code:
Private Delegate Function Function_Delegate_B(ByRef ArgumentA As TypeA, _
ByVal ArgumentB As Byte) As <MarshalAs(UnmanagedType.Struct)> Return_Type
Or possibly use UnmanagedType.LPStruct.
I don't think I ever used any p/invoke on any function that have returned a struct.
Last edited by Joacim Andersson; Mar 21st, 2013 at 09:47 PM.
-
Mar 21st, 2013, 11:13 PM
#5
Re: Marshal.GetDelegateForFunctionPointer() Problem w/ Function returning Struct
Originally Posted by Joacim Andersson
I don't think I ever used any p/invoke on any function that have returned a struct.
Well certainly not a Win32 API function. MS prefers passing back structures through parameters and reserving the return value as a means to determine success or failure of the function itself. However, the OP may be trying to call an exported function that is not of the Win32 API in which case all bets are off. While on that topic, I would expect it to return a pointer to a structure. It would be nice if the OP could post the C signature of the function he is trying to call.
-
Mar 22nd, 2013, 04:55 AM
#6
Re: Marshal.GetDelegateForFunctionPointer() Problem w/ Function returning Struct
I actually doubt that the function returns a pointer to a struct since it has to use malloc to be able to get the struct onto the heap, who is responsible for releasing that memory? There is no way you can construct a local struct in a C/C++ function and then return a pointer to that since then you would get a pointer to a location on the stack that has been popped when the function returns. Nasty things will happen in either case.
-
Mar 22nd, 2013, 05:56 AM
#7
Thread Starter
Junior Member
Re: Marshal.GetDelegateForFunctionPointer() Problem w/ Function returning Struct
@Joacim
Thanks a lot ... I just tried the UnmanagedType.Struct but nothing changed. I also tried the UnmanagedType.LPStruct but that just caused a crash.
Thanks,
Joe
-
Mar 22nd, 2013, 06:10 AM
#8
Re: Marshal.GetDelegateForFunctionPointer() Problem w/ Function returning Struct
LPStruct should crash if the function doesn't return a pointer to the struct, which I doubted to begin with.
Do you have the signature for the C function?
-
Mar 22nd, 2013, 06:13 AM
#9
Thread Starter
Junior Member
Re: Marshal.GetDelegateForFunctionPointer() Problem w/ Function returning Struct
@Niya
The *.dll is actually in Ada so I didn't want to "scare" folks with the interface but here we go ...
type Type_A
is record
A : Float;
...
end record;
type Return_Type
is record
A : Float;
B : Float;
end record;
function External_Function()
( ArgumentA : in Type_A;
ArgumentB : in Boolean := False
) return Return_Type;
pragma Export (C, External_Function, "External_Function");
The problem is that I don't have much control over that interface. There are also other (working) functions that use an "out" in the Ada interface to return a structure by reference through an argument.
I also forgot to mention that I use the following for the Private Delegate Function ...
<UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet:=CharSet.Ansi)> _
and (unsuccessfully) tried the CallingConvention.Cdecl as well.
I saw that I could use Marshal.PtrToStructure if the function returned a pointer but unfortunately I don't have much control over the interface.
Thanks,
Joe
-
Mar 22nd, 2013, 06:40 AM
#10
Re: Marshal.GetDelegateForFunctionPointer() Problem w/ Function returning Struct
Have you tried using Marshal.PtrToStructure? In which case you must change the signature for your delegate to accept an IntPtr as the return type.
-
Mar 22nd, 2013, 07:06 AM
#11
Thread Starter
Junior Member
Re: Marshal.GetDelegateForFunctionPointer() Problem w/ Function returning Struct
Originally Posted by Joacim Andersson
LPStruct should crash if the function doesn't return a pointer to the struct, which I doubted to begin with.
Do you have the signature for the C function?
Makes sense. See below for the Ada interface.
-
Mar 22nd, 2013, 07:10 AM
#12
Thread Starter
Junior Member
Re: Marshal.GetDelegateForFunctionPointer() Problem w/ Function returning Struct
Originally Posted by Joacim Andersson
Have you tried using Marshal.PtrToStructure? In which case you must change the signature for your delegate to accept an IntPtr as the return type.
Yes ... I already tried that but it resulted in a crash. Probably because the Ada code isn't returning a pointer.
Thanks,
Joe
-
Mar 22nd, 2013, 07:55 AM
#13
Re: Marshal.GetDelegateForFunctionPointer() Problem w/ Function returning Struct
Alright, I'm out of ideas unless you can create a wrapper function in another DLL that will call this function and return the struct as an out parameter.
-
Mar 22nd, 2013, 09:31 AM
#14
Thread Starter
Junior Member
Re: Marshal.GetDelegateForFunctionPointer() Problem w/ Function returning Struct
Originally Posted by Joacim Andersson
Alright, I'm out of ideas unless you can create a wrapper function in another DLL that will call this function and return the struct as an out parameter.
That might be something to look into but maybe I can get an updated version of the *.dll too. I certainly appreciate your help!
Thanks,
Joe
-
Mar 25th, 2013, 06:33 PM
#15
Re: Marshal.GetDelegateForFunctionPointer() Problem w/ Function returning Struct
I've had a play with this with some success.
Seeing as we already have some ADA posted in this thread, I'm going to post the C# I used. I did translate it using this translator but it looked awful, so I'll leave that to someone else.
Code:
using System;
using System.Runtime.InteropServices;
using System.Drawing;
Helper class wrapping LoadLibrary API
Code:
class NativeLibrary
{
[DllImport("kernel32.dll")]
static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string libraryName);
[DllImport("kernel32.dll")]
static extern int FreeLibrary(IntPtr hModule);
IntPtr handle;
public NativeLibrary(string libraryName)
{
handle = LoadLibrary(libraryName);
if (handle == IntPtr.Zero)
throw new ArgumentException(string.Format("Failed to load \"{0}\"", libraryName));
}
public void Free()
{
FreeLibrary(handle);
handle = IntPtr.Zero;
}
public object CreateDelegate(string procedureName, Type type)
{
var func = GetProcAddress(handle, procedureName);
if (func == IntPtr.Zero)
throw new ArgumentException(string.Format("Failed to find procedure \"{0}\"", procedureName));
return Marshal.GetDelegateForFunctionPointer(func, type);
}
}
Example use of class above to wrap test API.
Code:
class LibXWrapper
{
public delegate float PassVal_(PointF pt);
public delegate float PassRef_(ref PointF pt);
public delegate float PassPtr_(ref PointF pt);
public delegate PointF RetVal_(float n);
public delegate IntPtr RetRef_(ref PointF pt);
public delegate IntPtr RetPtr_(ref PointF pt);
NativeLibrary lib;
public LibXWrapper( string libraryPath )
{
lib = new NativeLibrary(libraryPath);
PassVal = (PassVal_)lib.CreateDelegate("ByVal_", typeof(PassVal_));
PassRef = (PassRef_)lib.CreateDelegate("ByRef_", typeof(PassRef_));
PassPtr = (PassPtr_)lib.CreateDelegate("ByPtr_", typeof(PassPtr_));
RetVal = (RetVal_)lib.CreateDelegate("RetVal_", typeof(RetVal_));
RetRef = (RetRef_)lib.CreateDelegate("RetRef_", typeof(RetRef_));
RetPtr = (RetPtr_)lib.CreateDelegate("RetPtr_", typeof(RetPtr_));
}
public PassVal_ PassVal { get; private set; }
public PassRef_ PassRef { get; private set; }
public PassPtr_ PassPtr { get; private set; }
public RetVal_ RetVal { get; private set; }
public RetRef_ RetRef { get; private set; }
public RetPtr_ RetPtr { get; private set; }
}
The DLL header for the test API
Code:
#pragma once
extern "C"
{
struct pointF
{
float x, y;
};
__declspec( dllexport ) float ByVal_(pointF);
__declspec( dllexport ) float ByRef_(pointF&);
__declspec( dllexport ) float ByPtr_(pointF*);
__declspec( dllexport ) pointF RetVal_(float);
__declspec( dllexport ) pointF& RetRef_(pointF*);
__declspec( dllexport ) pointF* RetPtr_(pointF*);
}
-
Mar 25th, 2013, 07:08 PM
#16
Thread Starter
Junior Member
Re: Marshal.GetDelegateForFunctionPointer() Problem w/ Function returning Struct
Wow ... thanks for taking the time to play with this. I'll give ita try using my Ada *.dll as soon as I get a chance ...
Thanks,
Joe
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|