Marshalling PDouble (C# -> Delphi) - c#

I've got an unmanaged DLL file written in Delphi, containing a function with the following definition:
function F(tgran: integer; inputs: PDouble; goutp, outputs, toutp: PDouble): integer; stdcall; external 'mydll.dll';
I've written an Adapter in C# that should help me consume it.
[UnmanagedFunctionPointer(APIAdapter.Convention)]
public delegate int FDelegate(int tgran, IntPtr inputs, IntPtr goutp, IntPtr outputs, IntPtr toutp);
public class APIAdapter : IDisposable
{
public const string DllName = "mydll.dll";
public const CallingConvention Convention = CallingConvention.StdCall;
public FDelegate F;
[DllImport("kernel32")]
private static extern IntPtr LoadLibrary(string lpLibFileName);
[DllImport("kernel32")]
private static extern bool FreeLibrary(IntPtr hModule);
[DllImport("kernel32.dll")]
private static extern IntPtr GetProcAddress(IntPtr hModule, String procname);
private IntPtr _dllHandle;
public APIAdapter()
{
_dllHandle = LoadLibrary(DllName);
F = (FDelegate)GetFunction<CalcCavSpDelegate>("F");
}
private Delegate GetFunction<T>(string procName)
{
IntPtr procAddress = GetProcAddress(_dllHandle, procName);
return Marshal.GetDelegateForFunctionPointer(procAddress, typeof(T));
}
~APIAdapter()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (disposing)
{
}
while (FreeLibrary(_dllHandle))
{
}
}
}
The usage is pretty straightforward:
using(var api = new APIAdapter())
{
// Call API functions
}
The problem is an AccessViolationException that happens within the DLL file.
I've tried to pass the PDouble variables as double[], double* (unsafe code), IntPtr. It's the same story regardless of the method I choose. I've tried to substantially increase the size of the arrays passed in to exclude errors with array indexing - AccessViolation exception again.
What is the proper way of passing a PDouble into an unmanaged Delphi DLL file?

I think you can do away with all the LoadLibrary, GetProcAddress and FreeLibrary complexity by simply using DllImport attribute. Though, I can say that I am not aware about any specific reason of why you chose to go this way.
Anyway, you can simply include ref double doubleArg in your declaration to pass PDouble. There should be no need of IntPtr here.

Related

OpenGL loading fails at seemingly random points

I am loading OpenGL in C# using LoadLibrary/GetProcAddress/wglGetProcAddress. For some reason, it fails to load the pointer for glBlendFunc, and other random ones after that point. I have been looking through my code for the better part of an hour now, and all these failing parts look completely fine and normal?
The code to load the function pointers and cast it to a delegate.
public override T GetFunction<T>(string name)
{
IntPtr pointer = wglGetProcAddress(name);
if (pointer == IntPtr.Zero)
pointer = GetProcAddress(Handle, name);
return Marshal.GetDelegateForFunctionPointer<T>(pointer);
}
A sample of the code that calls GetFunction.
BlendEquationSeparate = Loader.GetFunction<glBlendEquationSeparate>("glBlendEquationSeparate");
BlendEquationSeparatei = Loader.GetFunction<glBlendEquationSeparatei>("glBlendEquationSeparatei");
BlendFunc = Loader.GetFunction<glBlendFunc>("glBlendFunc");
BlendFunci = Loader.GetFunction<glBlendFunci>("glBlendFunci");
BlendFuncSeparate = Loader.GetFunction<glBlendFuncSeparate>("glBlendFuncSeparate");
BlendFuncSeparatei = Loader.GetFunction<glBlendFuncSeparatei>("glBlendFuncSeparatei");
A sample of the delegate code.
public delegate void glBlendEquationSeparate(BlendEquationMode modeRGB, BlendEquationMode modeAlpha);
public static glBlendEquationSeparate BlendEquationSeparate;
public delegate void glBlendEquationSeparatei(UInt32 buf, BlendEquationMode modeRGB, BlendEquationMode modeAlpha);
public static glBlendEquationSeparatei BlendEquationSeparatei;
public delegate void glBlendFunc(BlendingFactorSrc sfactor, BlendingFactorDest dfactor);
public static glBlendFunc BlendFunc;
public delegate void glBlendFunci(UInt32 buf, BlendingFactorSrc sfactor, BlendingFactorDest dfactor);
public static glBlendFunci BlendFunci;
public delegate void glBlendFuncSeparate(BlendingFactorSrc srcRGB, BlendingFactorDest dstRGB, BlendingFactorSrc srcAlpha, BlendingFactorDest dstAlpha);
public static glBlendFuncSeparate BlendFuncSeparate;
public delegate void glBlendFuncSeparatei(UInt32 buf, BlendingFactorSrc srcRGB, BlendingFactorDest dstRGB, BlendingFactorSrc srcAlpha, BlendingFactorDest dstAlpha);
public static glBlendFuncSeparatei BlendFuncSeparatei;
The DllImports I am using
[DllImport("kernel32")]
public static extern IntPtr LoadLibrary(string fileName);
[DllImport("kernel32")]
public static extern IntPtr GetProcAddress(IntPtr module, string procName);
[DllImport("opengl32.dll", EntryPoint = "wglGetProcAddress", ExactSpelling = true)]
public static extern IntPtr wglGetProcAddress(string lpszProc);
All the enums are pretty standard, and need no context. I load the library like usual: LoadLibrary(opengl32.dll);. Can anyone explain to me where I am going wrong?
I have found a somewhat strange solution. If I move the code to a static constructor so that it runs at the beginning of the program, it suddenly works. I have no idea why my first approach didn't work.

unity3d EntryPointNotFoundException yet entryPoint exists

I have a C/C++ unmanaged DLL that is working with the exception of a single method which causes an EntryPointNotFoundException
i'm setting up the DLL in c#
private const string dllname = "mydllname";
[DllImport(dllname)]
private static extern IntPtr CreateBridge();
[DllImport(dllname)]
private static extern void DestroyBridge(IntPtr context);
[DllImport(dllname)]
private static extern int getChannels(IntPtr context);
[DllImport(dllname)]
private static extern void setUpdate(IntPtr context, IntPtr values);
and then calling the method
IntPtr updatePtr = Marshal.AllocHGlobal(Marshal.SizeOf(update));
Marshal.StructureToPtr(update, updatePtr, true);
setUpdate(context, updatePtr);
Before I'm calling setUpdate(context, updatePtr) I'm sucessfully calling CreateBridge() and getChannels(IntPtr context) so we know the DLL is present, that it is loaded and that other entryPoints can be called
But setUpdate(context, updatePtr) causes the exception EntryPointNotFoundException
the C definition is as follows
#define DLL_EXPORT __declspec(dllexport)
...
extern "C" {
DLL_EXPORT UnityBridge* CreateBridge();
DLL_EXPORT void DestroyBridge(const UnityBridge* _unitybridge);
DLL_EXPORT int getChannels(UnityBridge* _unitybridge);
DLL_EXPORT void setUpdate(UnityBridge* _unitybridge, Update* update);
}
What else can cause this exception?
EDIT #1
I checked with Dependency it is not being exported... this makes the question different, but any clues?

How to fix 'EntryPointNotFoundException'

I'm trying to import external c++ methods into my C# code.
I have modified a Windows driver which I'm using to access memory. To invoke the driver, I'm using c++ interface. Finally, to invoke the the interface connecting me to the driver, I use C# code.
The problem I'm facing is that during the runtime, I get following error System.EntryPointNotFoundException: Unable to find an entry point named 'GetTargetPid' in DLL 'API.dll'.
Now, The interface itself consists only of single header file. I thought that maybe that is the problem, however from what I've read online, using single header file even for implementation is perfectly fine.
This is my import in C#
[DllImport("API.dll")]
public static extern IntPtr GetTargetPid();
and here I Invoke the method
IntPtr processID = IntPtr.Zero;
...
ProcessID = GetTargetPid();
So my C# code is nothing special.
Now here is my API.dll
extern "C"
{
...
class CDriver
{
public:
//Handle to the driver
HANDLE hDriver;
//Initialization of the handle
CDriver::CDriver(LPCSTR RegistryPath)
{
hDriver = CreateFileA(RegistryPath, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
}
...
__declspec(dllexport)
ULONG_PTR GetTargetPid()
{
if (hDriver == INVALID_HANDLE_VALUE)
return false;
PVOID Id = 0;
ULONG_PTR Result;
DWORD Bytes;
if (DeviceIoControl(hDriver, IO_GET_PROCESS_ID, NULL, NULL,
Id, sizeof(Id), &Bytes, NULL)) {
Result = (ULONG_PTR)Id;
return Result;
}
else
return false;
}
Most of the examples I'v read online are using static methods, is that of any importance? what I need is working import, i think this should be trivial, however I can't figure it out.
You have two problems. First problem __declspec(dllexport) ULONG_PTR GetTargetPid() compiles just fine and exports CDriver::GetTargetPid. You don't want that.
In reading your CDriver code I'm convinced that it's not a singleton. If you really want to P/Invoke:
extern "C" {
__declspec(dllexport)
CDriver *CreateCDriver(LPCSTR RegistryPath)
{
return new CDriver(RegistryPath);
}
__declspec(dllexport)
ULONG_PTR GetTargetPid(CDriver *driver)
{
return driver->GetTargetPid();
}
__declspec(dllexport)
CDriver *DestroyCDriver(CDriver *driver)
{
delete driver;
}
} // extern "C"
Second problem: you are P/Invoking a C function. Need Cdecl declarations in C#:
[DllImport("API.dll", CallingConvention=Cdecl, CharSet=CharSet.????)]
public static extern IntPtr CreateCDriver(string name);
[DllImport("API.dll", CallingConvention=Cdecl)]
public static extern IntPtr GetTargetPid(IntPtr cdriver);
[DllImport("API.dll", CallingConvention=Cdecl)]
public static extern IntPtr DestroyCDriver(IntPtr cdriver);
I can't tell from your code whether you compile ANSI or Unicode; fill in CharSet.???? correctly.
The usage of this stuff is like this:
IntPtr cdriver = null;
try {
cdriver = CreateCDriver("whatever");
var pid = GetTargetPid(cdriver);
// do whatever with pid
} finally {
DestroyCDriver(cdriver);
}
The moment you have to move a cdriver reference off the stack you need Dispose() and Finalize().
internal class CDriver : IDisposable {
private IntPtr cdriver;
public CDriver(string registry)
{
cdriver = CreateCDriver("whatever");
}
public void Dispose()
{
Dispose(true);
GC.SupressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
DestroyCDriver(cdriver);
cdriver = IntPtr.Zero;
}
}

C# Marshalled Callbacks

I am trying to Marshall c call backs that are in a struct. I am pretty sure I have everything correct, but when using my C# example I don't get events, when using c++ I do get events.
Here is the C#
class Program
{
[DllImport("Some.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern int SetCallbacks(Callbacks callBack);
static Callbacks Callback = new Callbacks { DataArrived = DataArrived, SendFailure = SendFailure };
static void Main(string[] args)
{
SetCallbacks(Callback);
Console.ReadLine();
}
static void DataArrived(uint id, IntPtr data)
{
}
static void SendFailure(uint id, uint id2, IntPtr data)
{
}
}
[StructLayout(LayoutKind.Sequential)]
public struct Callbacks
{
public DataArrived DataArrived;
public SendFailure SendFailure;
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void DataArrived(uint id, IntPtr data);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void SendFailure(uint id, uint id2, IntPtr ulpData);
This is from the C header file.
struct callBacks
{
void (*dataArriveNotif) (unsigned int, void*);
void (*sendFailureNotif) (unsigned int, unsigned int, void*);
}
int SetCallbacks(callBacks callBacks);
Here is the working c++.
struct callBacks;
callbacks.dataArriveNotif = &dataArriveNotif;
callbacks.sendFailureNotif = &sendFailureNotif;
SetCallbacks(callBacks);
Everything dealing with the delegate was actually correct. I simplified the senario a little bit in the example.
public static extern int SetCallbacks(Callbacks callBack);
was actually
public static extern int SetCallbacks(String[] array, Callbacks callBack);
The string array had lots of trailing 0's at the end. Which made the callback struct all nulls. I gave up trying to marshal the string[] the correct way and just made it a Intptr and everything started working.
so very similar to this question asked yesterday...
PInvoke C#: Function takes pointer to function as argument

C# Error Finding Method in DLLImport

I have a C++ assembly that I am importing using DLLImport.
I am attempting to call its method:
namespace Testing
{
class Test{
int Run(char* filePath, bool bEntry, double duration){//code}
};
}
by
[DllImport(dllName, CharSet = CharSet.Auto)]
public static extern int Run(string filePath, bool bEntry, double duration)
);
When I call its method, I get the error message:
Unable to find an entry point named Run in dll
The "Run" looks to be a non-static class method. Although, it's possible to call such methods from C# this is not the primary use-case. It would be way easier to consume it from .NET if you expose it via COM, or at-least as a plain C interface:
extern "C" __declspec(dllexport) void* Testing_Test_Create();
extern "C" __declspec(dllexport) void Testing_Test_Destroy(void* self);
extern "C" __declspec(dllexport) int Testing_Test_Run(void* self, char* filePath, bool bEntry, double duration);
And here is a sample how to call C++ class methods from C#:
// Test.cpp in NativeLib.dll
namespace Testing
{
class __declspec(dllexport) Test
{
public:
explicit Test(int data)
: data(data)
{
}
int Run(char const * path)
{
return this->data + strlen(path);
}
private:
int data;
};
}
// Program.cs in CSharpClient.exe
class Program
{
[DllImport(
"NativeLib.dll",
EntryPoint = "??0Test#Testing##QAE#H#Z",
CallingConvention = CallingConvention.ThisCall,
CharSet = CharSet.Ansi)]
public static extern void TestingTestCtor(IntPtr self, int data);
[DllImport(
"NativeLib.dll",
EntryPoint = "?Run#Test#Testing##QAEHPBD#Z",
CallingConvention = CallingConvention.ThisCall,
CharSet = CharSet.Ansi)]
public static extern int TestingTestRun(IntPtr self, string path);
static void Main(string[] args)
{
var test = Marshal.AllocCoTaskMem(4);
TestingTestCtor(test, 10);
var result = TestingTestRun(test, "path");
Console.WriteLine(result);
Marshal.FreeCoTaskMem(test);
}
}
Entry point names might be different for your build configuration/compiler, so use dumpbin utility to obtain them. Again, this is just a proof of concept, in real code it would be better to use COM.
See here: http://dotnetperls.com/dllimport
I'm not sure this will help if the function is a member of a class, but to locate the entry point by name, not ordinal, you'll need a .def file in your dll..
LIBRARY mylib
Run #1

Categories