OpenGL loading fails at seemingly random points - c#

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.

Related

How to use SetProcessMitigationPolicy with C#

I need to implement the following C++ code into C#.
PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY signaturePolicy = { };
signaturePolicy.MicrosoftSignedOnly = true;
SetProcessMitigationPolicy(ProcessSignaturePolicy, &signaturePolicy, sizeof(signaturePolicy));
I have already defined the extern and the struct, but i dont know to use the parameters for the function.
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool SetProcessMitigationPolicy(int policy, PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY lpBuffer, int size);
private struct PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY
{
private uint MicrosoftSignedOnly;
}
public static void Main(string[] args)
{
SetProcessMitigationPolicy(??) // what do do there? how to get the required sizeof?
}
Can anyone explain me how to pass the required parameters in the right way? Thanks.

Passing string from Fortran dll to C#

I am trying to load a Fortran dll dynamically and pass a string back from fortran to C#. Everything looks fine when inside the fortran code, but when returning to C# the value of the string is lost. Instead the initial value, set in C#, is back. I have tried to use the 'ref' keyword to get the string to be passed by reference, but then I get error like below. What am I doing wrong?
The runtime has encountered a fatal error. The address of the error was at 0x709ce248, on thread 0x2ac4. The error code is 0xc0000005. This error may be a bug in the CLR or in the unsafe or non-verifiable portions of user code. Common sources of this bug include user marshaling errors for COM-interop or PInvoke, which may corrupt the stack.
Fortran code:
module FortLibInterface
implicit none
integer, parameter :: STR_LENGTH = 256
contains
subroutine GetString(Str)
!DIR$ ATTRIBUTES DLLEXPORT::GetString
!DIR$ ATTRIBUTES ALIAS: 'GetString' :: GetString
!DIR$ ATTRIBUTES REFERENCE:: Str
character(len=STR_LENGTH), intent(inout) :: Str
Str = 'bcdef...'
end subroutine
end module
C# code:
using System;
using System.Runtime.InteropServices;
namespace FortranCSTest
{
class Program
{
static void Main(string[] args)
{
string dllPath = "C:\\Temp\\FortLib.dll";
FortLibTest lib = new FortLibTest(dllPath);
lib.MakeTestCall();
}
}
public class FortLibTest
{
public const int STR_LENGTH = 256;
public const string FortranFuncName = "GetString";
private string pathToDll = null;
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr LoadLibrary(String DllName);
[DllImport("kernel32.dll")]
private static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
[DllImport("kernel32.dll")]
private static extern bool FreeLibrary(IntPtr hModule);
public FortLibTest(string FullPathToDll)
{
pathToDll = FullPathToDll;
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void TypeGetStrInfo(char[] str);
void GetStrInfo(char[] str)
{
IntPtr pDll = LoadLibrary(pathToDll);
if (pDll != IntPtr.Zero)
{
IntPtr pFunc = GetProcAddress(pDll, FortranFuncName);
if (pFunc != IntPtr.Zero)
{
TypeGetStrInfo func = (TypeGetStrInfo)Marshal.GetDelegateForFunctionPointer(pFunc, typeof(TypeGetStrInfo));
func(str);
}
else
{
//Something
}
FreeLibrary(pDll);
}
else
{
//Something
}
}
public void MakeTestCall()
{
char[] str = new char[STR_LENGTH];
str[0] = 'a';
GetStrInfo(str);
}
}
}
For future reference. I added [In, Out] and everything works.
[DllImport(_dllName, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern void GetString([In, Out] char[] str);

Marshalling PDouble (C# -> Delphi)

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.

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