I have an older app (ca. 2005) which accepts dll plugins. The app was originally designed for Win32 C plugins, but I have a working C# dll template. My problem: I need to do some one-time initialization, which in a Win32 C dll would be done in DllMain:
BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
[one-time stuff here...]
}
Is there a C# equivalent of this? There is no "DllMain" in the C# template I have. I tried a literal C# interpretation, but no go: the dll works but it won't trigger the DllMain function.
public static bool DllMain(int hModule, int reason, IntPtr lpReserved) {
[one time stuff here...]
}
Give your class a static constructor and do your initialization there. It will run the first time anybody calls a static method or property of your class or constructs an instance of your class.
I've had to interact with a legacy application probably in the same situation as you have. I've found a hacky way to get DllMain functionality in a CLR assembly. Luckily it isn't too hard. It requires an additional DLL but it doesn't require you to deploy an additional DLL so you can still have the "put a DLL in that directory and the app will load it" paradigm.
First, you make a simple regular C++ DLL that looks like the following:
dllmain.cpp:
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "resource.h"
extern void LaunchDll(
unsigned char *dll, size_t dllLength,
char const *className, char const *methodName);
static DWORD WINAPI launcher(void* h)
{
HRSRC res = ::FindResourceA(static_cast<HMODULE>(h),
MAKEINTRESOURCEA(IDR_DLLENCLOSED), "DLL");
if (res)
{
HGLOBAL dat = ::LoadResource(static_cast<HMODULE>(h), res);
if (dat)
{
unsigned char *dll =
static_cast<unsigned char*>(::LockResource(dat));
if (dll)
{
size_t len = SizeofResource(static_cast<HMODULE>(h), res);
LaunchDll(dll, len, "MyNamespace.MyClass", "DllMain");
}
}
}
return 0;
}
extern "C" BOOL APIENTRY DllMain(HMODULE h, DWORD reasonForCall, void* resv)
{
if (reasonForCall == DLL_PROCESS_ATTACH)
{
CreateThread(0, 0, launcher, h, 0, 0);
}
return TRUE;
}
Note the thread creation. This is to keep Windows happy because calling managed code within a DLL entrypoint is a no-no.
Next, you have to create that LaunchDll function the code above references. This goes in a separate file because it will be compiled as a managed C++ unit of code. To do this, first create the .cpp file (I called it LaunchDll.cpp). Then right click on that file in your project and in Configuration Properties-->C/C++-->General change the Common Language RunTime Support entry to Common Language RunTime Support (/clr). You can't have exceptions, minimal rebuild, runtime checks and probably some other things I forgot about but the compiler will tell you about. When the compiler complains, track down what settings you much change from the default and change them on the LaunchDll.cpp file only.
LaunchDll.cpp:
#using <mscorlib.dll>
// Load a managed DLL from a byte array and call a static method in the DLL.
// dll - the byte array containing the DLL
// dllLength - the length of 'dll'
// className - the name of the class with a static method to call.
// methodName - the static method to call. Must expect no parameters.
void LaunchDll(
unsigned char *dll, size_t dllLength,
char const *className, char const *methodName)
{
// convert passed in parameter to managed values
cli::array<unsigned char>^ mdll = gcnew cli::array<unsigned char>(dllLength);
System::Runtime::InteropServices::Marshal::Copy(
(System::IntPtr)dll, mdll, 0, mdll->Length);
System::String^ cn =
System::Runtime::InteropServices::Marshal::PtrToStringAnsi(
(System::IntPtr)(char*)className);
System::String^ mn =
System::Runtime::InteropServices::Marshal::PtrToStringAnsi(
(System::IntPtr)(char*)methodName);
// used the converted parameters to load the DLL, find, and call the method.
System::Reflection::Assembly^ a = System::Reflection::Assembly::Load(mdll);
a->GetType(cn)->GetMethod(mn)->Invoke(nullptr, nullptr);
}
Now for the really tricky part. You probably noticed the resource loading in dllmain.cpp:launcher(). What this does is retrieve a second DLL that has been inserted as a resource into the DLL getting created here. To do this, create a resource file by doing the
right click-->Add-->New Item-->Visual C++-->Resource-->Resource File (.rc) thing. Then, you need to make sure there is a line like:
resource.rc:
IDR_DLLENCLOSED DLL "C:\\Path\\to\\Inner.dll"
in the file. (Tricky, huh?)
The only thing left to do is to create that Inner.dll assembly. But, you already have it! This is what you were trying to launch with your legacy app in the first place. Just make sure to include a MyNamespace.MyClass class with a public void DllMain() method (of course you can call these functions whatever you want to, these are just the values hardcoded into dllmain.cpp:launcher() above.
So, in conclusion, the code above takes an existing managed DLL, inserts it into a resource of an unmanaged DLL which, upon getting attached to a process, will load the managed DLL from the resource and call a method in it.
Left as an exercise to the reader is better error checking, loading different DLLs for Debug and Release, etc. mode, calling the DllMain substitute with the same arguments passed to the real DllMain (the example only does it for DLL_PROCESS_ATTACH), and hardcoding other methods of the inner DLL in the outer DLL as pass through methods.
Also not easy to do from C# you can have a per module initializers
Modules may contain special methods called module initializers to initialize the module itself.
All modules may have a module initializer. This method shall be static, a member of the module, take no parameters, return no value, be marked with rtspecialname and specialname, and be named .cctor.
There are no limitations on what code is permitted in a module initializer. Module initializers are permitted to run and call both managed and unmanaged code.
Even though C# doesn't directly support module initialization we can implement it using reflection and static constructors. To do this we can define a custom attribute and use it find classes that need to be initialized on module loading:
public class InitOnLoadAttribute : Attribute {}
private void InitAssembly(Assembly assembly)
{
foreach (var type in GetLoadOnInitTypes(assembly)){
var prop = type.GetProperty("loaded", BindingFlags.Static | BindingFlags.NonPublic); //note that this only exists by convention
if(prop != null){
prop.GetValue(null, null); //causes the static ctor to be called if it hasn't already
}
}
}
static IEnumerable<Type> GetLoadOnInitTypes(Assembly assembly)
{
foreach (Type type in assembly.GetTypes())
{
if (type.GetCustomAttributes(typeof(InitOnLoadAttribute), true).Length > 0){
yield return type;
}
}
}
public MyMainClass()
{
//init newly loaded assemblies
AppDomain.CurrentDomain.AssemblyLoad += (s, o) => InitAssembly(o.LoadedAssembly);
//and all the ones we currently have loaded
foreach(var assembly in AppDomain.CurrentDomain.GetAssemblies()){
InitAssembly(assembly);
}
}
on classes that we need to initialize immediately we add that code to their static constructor (which will be run once even if the property getter is accessed multiple times) and add the custom attribute we added to expose this functionality.
[InitOnLoad]
class foo
{
private static bool loaded { get { return true; } }
static foo()
{
int i = 42;
}
}
Related
i am currently trying to port some piece of code from C# to go where dll's are involved (not sure if this makes any difference).
the actual "code" is not the problem but i run into some "feature" problems
i have the following line:
Marshal.AllocHGlobal(Marshal.SizeOf(typeof(WINMSG)));
i know that i can transform
Marshal.SizeOf => unsafe.Sizeof also typeof is not a problem
but how can i implement the AllocHGlobal?
or is this not even needed - just create the instance of a struct and assign a pointer to it?
why do i need this:
there is need for communicating directly with dll's and i have to communicate/exchange data with them.
fully working code is available which needs to be turned into go
Done - but untested yet:
Marshal.AllocHGlobal
Marshal.FreeHGlobal
implementation of the stuff already done
import (
...
"github.com/kbinani/win"
...
)
type IntPtr int16
type UIntPtr uint64
const uint64 HIWORDMASK = 0xffffffffffff0000
// AllocHGlobal like Marshal.AllocHGlobal from c#
func MarshalAllocHGlobal(numBytes int) (tw.IntPtr, error) {
pNewMem := win.LocalAlloc( /*LMEM_FIXED*/ 0x0000, numBytes)
if pNewMem == 0 /*IntPtr.Zero*/ {
return nil, fmt.Errorf("OutOfMemoryException")
}
return pNewMem
}
func MarshalFreeHGlobal(hglobal IntPtr) error {
if IsNotWin32Atom(hglobal) {
if 0 /*IntPtr.Zero*/ != win.LocalFree(hglobal) {
return fmt.Errorf("failed to FreeHGlobal")
}
}
return nil
}
func IsNotWin32Atom(IntPtr ptr) bool {
return 0 != uint64(ptr)&HIWORDMASK
}
i also need
Marshal.StructureToPtr
#see https://referencesource.microsoft.com/#mscorlib/system/runtime/interopservices/marshal.cs,48a38ffe8a227f92
Marshal.PtrToStructure
#see https://referencesource.microsoft.com/#mscorlib/system/runtime/interopservices/marshal.cs,931fc84766e0e8cb
Updated information.
If you just want to call a Win32 api function, you don't need to .NET specific wrapper for memory management.
There is a pattern to call windows dll functions.
You can see example in windows specific code from the standard library, or at some libs that interact with windows API :
in https://github.com/gofrs/flock, for example, they grouped that code in the flock_winapi.go file
This post makes a decent job at explaining how to write code to call a specific function :
Breaking all the rules: Using Go to call Windows API
Have a good day!
For portability reasons, i have created a C++ DLL with almost novice C++ knowledge just by searching thousands of pages, hundreds of compiling error corrections and couple of stackoverflow questions.
It is far beyond being stable but it is working most of the time :)
Just for curiosity and modularity reasons without importing the header and the cpp file to my application, i would like to ask your advice and help:
C++ Win32 Console Application
int main()
{
HMODULE lib = LoadLibrary(L"Serial.dll");
typedef void(*void_Connect)(UINT Port, UINT Baud);
void_Connect Connect = (void_Connect)GetProcAddress(lib, "Connect");
Connect(1, 9600);
}
I want to add an event into above C++ Win32 Console application, which will be triggered or hosted by the DLL
For example, a Received_Event(const char* data) or Connected_Event(BOOL status) with parameters.
Part from the DLL
typedef void(*fpCALLBACK) (const char* aParam);
static fpCALLBACK s_pCallback = NULL;
extern "C"
{
#define DLL __declspec(dllexport)
DLL void ReceivedEventRegister(fpCALLBACK p_pCallback)
{
s_pCallback = p_pCallback;
}
DLL void evntReceived(const char *receivedData);
}
DLL void evntReceived(const char *received)
{
s_pCallback(received);
}
I want to achive something similar to this C# version, with Standard C++
private static ManagedCallbackDelegate MessageCallbackDelegate;
public delegate void ManagedCallbackDelegate(string aParam);
[DllImport("Serial.dll", EntryPoint = "ReceivedEventRegister", CallingConvention = CallingConvention.Cdecl)]
private static extern void ReceivedEventRegister(ManagedCallbackDelegate callback);
static private void serialRecieved(string data)
{
Console.WriteLine(data);
}
static void Main(string[] args)
{
MessageCallbackDelegate = new ManagedCallbackDelegate(serialRecieved);
ReceivedEventRegister(MessageCallbackDelegate);
}
With C# code above, any data received by the DLL, the serialRecieved function is called in realtime. I want to achive this with Standard C++
I want to be informed or be aware of with the DLL process in realtime, in my Win32 C++ Console Application. ( Without blocking the Win32 Console application )
No MFC. if it is possible, no Component Object Model (It is possible with C# without need to convert the DLL into a COM). if it is possible, I want to do it with Standard C++.
I am compiling things with Visual Studio 2017 Community
Please go easy with me. It is a hobby for me and i just do it in my spare time.
Questions
Can you reference me some code examples written for this purpose, you are aware of?
Is there any specific name for this kind of communication that i can Google?
Is there any approach, you can suggest?
Thank you!
Once again, thanks to #dxiv's comment; helped me a lot, to sort things out! Even, when someone tells you that it should work, you resolve 90% of the problem.
At the DLL side
DLL void evntReceived(const char *received)
{
s_pCallback(received);
}
The DLL is calling the above function all the time as soon as it receives any data. To get that data realtime in your Win32 C++ Application, you need to import the DLL function which is calling the above callback function. Which is this
DLL void ReceivedEventRegister(fpCALLBACK p_pCallback)
part of the DLL.
As the DLL function's parameter type name fpCALLBACK suggests, our function parameter has to be as it is defind in the DLL:
typedef void(*fpCALLBACK) (const char* aParam);
At the Application side
//Callback Function: A function that is passed to another function as an argument
void Event_Received(const char *recvd)
{
std::cout << recvd << std::endl;
}
int main()
{
HMODULE lib = LoadLibrary(L"Serial.dll");
typedef void(*void_Connect)(UINT Port, UINT Baud);
void_Connect Connect = (void_Connect)GetProcAddress(lib, "Connect");
// Type definition of the function pointer.
// In our case: a Void type, which takes in a
// void type function pointer with a parameter (const char *aParam)
// dllCALLBACK is just a type name; you can name it whatever you want.
typedef void(*dllCALLBACK) (void(*fpCALLBACK) (const char* aParam));
// Now we will import the function from our DLL which takes
// the same parameters as we defined above, to call
// our callback function
dllCALLBACK ReceivedEventRegister = (dllCALLBACK)GetProcAddress(lib, "ReceivedEventRegister");
// Call the callback function with the imported function above.
// And that is all there is to it. As soon as any data received
// by our DLL - our Event_Received callback function
// fires in our C++ Win32 Console Application
ReceivedEventRegister(Event_Received);
Connect(1, 9600);
}
If you are a novice like me this video may help you to understand about Callback functions.
Thank you #dxiv again, taking time to read and answer my question!
I have a win32 API library .dll file for some hardware that I need to access in c#. I believe using DllImport to create a wrapper class for the .dll that makes it usable in my C# uwp application.
The first function I believe have done correctly
(C code)
ADIOLIB_API
aDIO_Error WINAPI aDIO_General_Enum(aDIO_Enum_Info* DeviceList,
uint8 ListSize)
(C# code)
[DllImport("aDIOLib.dll")] static extern aDIO_Error aDIO_General_Enum(ref aDIO_Enum_Info DeviceList, Byte ListSize);
public static aDIO_Error aDIOGeneralEnum(ref aDIO_Enum_Info DeviceList, Byte ListSize)
{
return aDIO_General_Enum(ref DeviceList, ListSize);
}
public struct aDIO_Enum_Info
{
UInt32 dev_num;
aDIO_Intrfc_Avail availability;
UInt32 base_address;
UInt32 irq;
bool has_wake;
}
aDIO_Error is just a UInt32 error code, so that part has been handled as well.
When I moved on to the next function to create a wrapper for it I ran into this issue. So the function header is like this:
ADIOLIB_API
aDIO_Error WINAPI aDIO_General_Open(aDIO_Enum_Info DeviceInfo,
aDIO_Handle* Handle)
After thinking the aDIO_Handle is probably another struct that I have to replicate in C#, I looked at the declaration for it and found this:
typedef struct
{
/**
Holds a critical section object used to control access to all library
state and functionality.
*/
CRITICAL_SECTION global_lock;
/**
Holds a handle to the aDIO device file. (Used to send IOCTLs to the
driver.)
*/
HANDLE dev_file;
/**
Holds device/board information retrieved from the driver.
*/
aDIO_Intrfc_Board_Info dev_info;
/**
Holds a critical section object used to control access to the error
logging function and the last error message.
*/
CRITICAL_SECTION log_section;
/**
Holds the last un-retrieved error message.
*/
char last_error_msg[ADIO_ERROR_MAX_MSG_LENGTH];
/**
Holds a pointer to the structure holding the state of the Interrupt
module.
*/
void* int_state;
} aDIO_Descriptor, *aDIO_Handle;
Both the HANDLE and CRITICAL_SECTION types are from external dependencies (minwinbase.h and winnt.h) in which this dll has like 100s of external header files. How am i supposed to make a DllImport for this aDIO_General_Open function without recreating all the header files in the process.
Any help would be much appreciated.
Please ask me questions to clarify if you have any! I am new to this DllImport stuff
I have made a plugin system that uses reflection to call functions in a plugin. A plugin has to implement the IPlugin interface to be used.
In the application which uses the plugins the plugin instance is created with the following code:
Assembly currentAssembly = Assembly.LoadFrom(startInfo.PluginAssemblyPath);
Type[] types = currentAssembly.GetTypes();
IPlugin pluginInstance = null;
foreach (Type type in types)
{
if (type.FullName == startInfo.PluginTypeName)
{
pluginInstance = (IPlugin)Activator.CreateInstance(type);
}
}
if (pluginInstance == null)
{
throw new Exception("Plugin loader error: Could not instantiate plugin: " + startInfo.ToString()); }
return pluginInstance;
I have made a plugin that uses some unmannaged dll's. When I call the IPlugin interface functions in a test project in the plugin solution everything works fine. But when I call the plugin via the plugin instance made in the code shown above I get the System.AccessViolationException: Attempted to read or write protected memory error when calling functions in the unmannaged dll's.
The unmannaged dll's are c++ dll's made by a third party. I tried enabling native code debugging but i do not have the .pdb files.
I am not sure why this is happening, is this because of the reflection? Or can there be other causes?
Edit:
In the stack I can see the unmannaged function being called:
[MarshalAs(UnmanagedType.LPStr)]
private readonly StringBuilder sb = new StringBuilder(256);
[DllImport("x.dll", EntryPoint = "xLib")]
static extern int _xLib(int a1, int a2, int a3, int a4, int a5, int a6, [Out]StringBuilder str);
The exception is thrown when calling the _xLib function.
Edit: Somewhere in this _xLib function the following function is called:
handle = x_Open();
which is in an other dll and is defined as:
DllExport x_Handle *x_Open();
As soon as anything in the handle is used like:
"%s", handle->x.string
The exception is thrown.
I still do not understand why this is working in the test project and not when I am using it in the app as a plugin.
Maybe you have to pin the StringBuilder to allow unmanaged code to interact with it.
Pinned object is one that is not allowed to move. The garbage collector is normally compacting the memory in that it moves all objects to "one or more clusters". This is to create large chunks of free space.
This basically means if someone else (outside) has a pointer to the memory address of an object, this may point to random content - as the object has moved.
Pinning an object tells the GC to NOT MOVE IT. This is normally useless and ONLY makes sense when working with pointers - like when using PInvoke... and I can see a pointer to a StringBuilder instance in _xlib function
Well after some intensive debugging I found the problem was the handle having some wrong address which caused the violation. The cause of the address being wrong was the x_open function loaded yet another dll with the LoadLibraryA function. This dll was not in the same directory as the executable file so it was not found.
I solved it by adding the directory of this last dll to the environment path.
First, I know that it doesn't make sense to compare the dllimport attribute and the getProcAddress function directly. Rather, I am interested in comparing two pieces of code, that achieve basically the same thing - calling a function in a dll - by either importing the function with the dllimport attribute or with the getProcAddress function. Specifically, I am writing a C# application that uses some function in a dll that I have written. At first I accessed my dll function with the following piece of code:
class DllAccess
{
[DllImport("kernel32.dll", SetLastError = true)]
private extern IntPtr LoadLibrary(String DllName);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate Bool BarType(Byte arg); // return value indicates whether function call went well or not.
Bool Bar(Byte arg)
{
Bool ok = false;
IntPtr pDll= LoadLibrary("foo.dll");
if (pDll != IntPtr.Zero)
{
IntPtr pfunc = GetProcAddress(pDll, "bar");
if (pFunc != IntPtr.Zero)
{
BarType bar = (BarType)Marshal.GetDelegateForFunctionPointer(pFunc, typeof(BarType));
ok = bar(arg);
}
FreeLibrary(pDll);
}
return ok;
}
}
However, I later needed to get at the lastError value, if it had been set during the dll call, so I changed my code into this:
class DllAccess
{
[DllImport("foo.dll", EntryPoint = "bar", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
private extern Bool DllBar(Byte arg); // return value indicates whether function call went well or not.
Bool Bar(Byte arg)
{
return DllBar(arg);
}
}
This is of course much tidier, and as mentioned, it sets the lastError code. Obviously, my first piece of code gives me the possibility of changing dll and function call at runtime, but at the moment this is not required. So my question is: Are there any reasons for using the first formulation, if I am certain, that I will not be using another dll or another function?
The only real advantages of using GetProcAddress are that you can unload the DLL manually as well as call a function, and that you can change the naming easily at runtime.
However, the second option provides you with a huge number of benefits. In addition to being "tidier", it also handles much of the marshaling of data types for you - which becomes very important with certain APIs.
That being said, if you do the method you have listed as first, you should make sure to unload everything, as well. Right now, you're basically leaking addresses each time you call Bar()... For details, look at FreeLibrary.
Probably the biggest advantage of GetProcAddress is that it lets you control the search path of the DLL. For example, you could load either 32-bit or 64-bit version of a native DLL automatically. With DllImportAttribute, this isn't possible.