Calling a static C# method from a managed C++/CLI thread - c#

I seem to be having issue with calling static C# methods.
I currently have 2 DLLs that I inject into an ancient legacy app and then execute a static method as seen in the code below:
Module.cs
using System;
namespace Debugger
{
public static class Module
{
public static void Initialize()
{
Console.WriteLine("YES");
}
}
}
dllmain.cpp
#include "stdafx.h"
#include <windows.h>
#pragma once
#pragma managed
using namespace System;
using namespace System::Reflection;
using namespace Debugger;
DWORD WINAPI MainThread(LPVOID param)
{
AllocConsole();
Console::WriteLine("Test");
Debugger::Module::Initialize();
FreeLibraryAndExitThread((HMODULE)param, 0);
return 0;
}
#pragma unmanaged
HMODULE hModule;
BOOL APIENTRY DllMain(HINSTANCE hInstance, DWORD reason, LPVOID reserved)
{
switch (reason)
{
case DLL_PROCESS_ATTACH:
CreateThread(0, 0, MainThread, hModule, 0, 0);
break;
case DLL_PROCESS_DETACH:
FreeLibrary(hModule);
break;
}
return true;
}
As a result: I get the console open, the 'Test' message pops up but 'YES' doesn't - instead, the app crashes.

Moving the DLL to the same folder as executable I'm injecting into fixed the issue.

Related

c++ CLR to bridge a c++ dll with a c# application

I am trying to follow this example: http://blogs.artinsoft.net/Mrojas/archive/2008/06/19/Log4NET-for-C++.aspx
to get Log4Net running in a c++ dll.
I created an empty CLR project, changed the output type to lib, and added the following code:
//Bridge.cpp
#include <atlstr.h>
using namespace System;
/// <summary>
/// Example of how to simply configure and use log4net
/// </summary>
ref class LoggingExample
{
private:
// Create a logger for use in this class
static log4net::ILog^ log = log4net::LogManager::GetLogger("LoggingExample"); static LoggingExample()
{
log4net::Config::BasicConfigurator::Configure();
}
public:static void ReportMessageWarning(char* msg)
{
String^ data = gcnew String(msg);
log->Warn(data);
}
static void ReportMessageError(char* msg)
{
String^ data = gcnew String(msg);
log->Error(data);
}
static void ReportMessageInfo(char* msg)
{
String^ data = gcnew String(msg);
log->Info(data);
}static void ReportMessageDebug(char* msg)
{
String^ data = gcnew String(msg);
log->Debug(data);
}
};
extern "C"
{
_declspec(dllexport) void ReportMessageWarning(char* msg)
{
LoggingExample::ReportMessageWarning(msg);
}
_declspec(dllexport) void ReportMessageError(char* msg)
{
LoggingExample::ReportMessageError(msg);
}
_declspec(dllexport) void ReportMessageInfo(char* msg)
{
LoggingExample::ReportMessageInfo(msg);
}
_declspec(dllexport) void ReportMessageDebug(char* msg)
{
LoggingExample::ReportMessageDebug(msg);
}
}
I have created a c++ console application project, and added this code:
#include "stdafx.h"
#include <iostream>
#include <atlstr.h>
extern "C"
{
//log4net from the wrapper lib
_declspec(dllimport) void ReportMessageWarning(char* msg);
__declspec(dllexport) void RunTest()
{
std::string message = "hey it seems it is working";
ReportMessageWarning(_strdup(message.c_str()));
}
}
This will be a c++ dll that is called from another C# application.
I have compiled the clr lib, and linked it in the dependencies of the c++ application.
However, the c++ dll will not compile as is, giving me:
Error LNK2001 unresolved external symbol __imp_ReportMessageWarning
What have i missed here?

Calling function of Csharp Application using a injected dll

I want call the ConsoleAppTwo.Program::PrintMessage the application...
i create a csharp test software with a function to call me:
using System;
namespace ConsoleAppTwo
{
class Program
{
static void PrintMessage(string str)
{
Console.WriteLine(str);
}
static void Main(string[] args)
{
while (true)
{
if(Console.ReadKey().Key == ConsoleKey.NumPad0)
{
PrintMessage("[Whatever string]");
}
}
}
}
}
and i use the IDA pro to found the functions:
IDA PRO
after i use the cheat engine and add the 'address' "ConsoleAppTwo.Program::PrintMessage" and get the address pointer and i create the dll:
#include <string>
#include <Windows.h>
#include "main.h">
using namespace std;
typedef void(__cdecl *_FuncA)(string str);
DWORD WINAPI MainThread(LPVOID param) {
_FuncA func = (_FuncA)(0x3504F0);
while (!GetAsyncKeyState(VK_HOME))
{
if (GetAsyncKeyState(VK_INSERT) & 1)
{
func("What is your name");
}
Sleep(10);
}
FreeLibraryAndExitThread((HMODULE) param, 0);
return 0;
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD fdwReason, LPVOID lpvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hModule);
CreateThread(0, 0, MainThread, GetModuleHandle(NULL), 0, 0);
default:
break;
}
return true;
}
and after i inject the dll in software and the code not work..., i get the output error: "EXCEPTION_ACCESS_VIOLATION"

c++ native code DLL using an abstract class into a wrapper to be used in C# module

Hi i am having the same problem with abstract class.i am trying to wrap my cpp Dll calls to use in the C# module.
Dll is using the Factory pattern.which contain a class Factory,MiddileWare ,And their costrong textrresponding child class.Could any one help me to start the wrapper. i am stuck in between this.Your help will be appreciated. i am giving the flow here:
MiddleWareFactory.h
#pragma once
#include "MiddleWareConnection.h"
#include "std afx.h"
#ifdef MIDDLEWAREFACTORY_EXPORTS
#define MIDDLEWAREFACTORY_API __declspec(dllexport)
#else
#define MIDDLEWAREFACTORY_API __declspec(dllimport)
#endif
MIDDLEWAREFACTORY_API enum eMiddleWareEngine
{
eRabitMQ = 0,
eZeroMQ,
eActiveMQ
};
// This class is exported from the MiddleWareFactory.dll
class MIDDLEWAREFACTORY_API CMiddleWareFactory
{
public:
CMiddleWareFactory(void);
~CMiddleWareFactory();
// TODO: add your methods here.
//Function to Create the object of Broker module:implemnted the Factory concept.
BOOL CreateInstance(CMiddleWareConnection** pMObj);
int m_eMomEngine;//To define which MOM need to enable.
};
extern MIDDLEWAREFACTORY_API int nMiddleWareFactory;
MIDDLEWAREFACTORY_API int fnMiddleWareFactory(void);
MiddleWareConnection.h
#pragma once
class CMiddleWareConnection
{
public:
virtual ~CMiddleWareConnection(void)
{
}
//Pure virtual fuctions for interfacing
virtual BOOL Connect(int nServerType)=0;
virtual BOOL CreateSessionExchange() = 0;
virtual BOOL CreateQueue(LPCTSTR lpszQueueName) = 0;
virtual BOOL Disconnect() = 0;
virtual BOOL Send(void *MomItem,LPCTSTR lpszKey, int &nSendCount)=0;
virtual BOOL Receive() = 0;
virtual void StopReceiver() = 0;
virtual void GetData(void* pMsg, int &nMsgLen,int nMsgType,int &nReceiveCount)=0;
};
RabbitMQ.h
#pragma once
#include "MiddleWareConnection.h"
#include "Amqp.h"
#pragma comment(lib, "rabbitmq.4.lib")
#define GET_DATA(a){memcpy(&a, pDataPtr, sizeof(a));pDataPtr+=sizeof(a);}
#define GET_DATA_EX(s,n){memcpy(s, pDataPtr, n);pDataPtr+=n;}
typedef struct _ROUTINE_KEY
{
CString RoutingKey;
}ROUTEKEY, *LPROUTEKEY;
class CRabbitMQ :
public CMiddleWareConnection
{
public:
CRabbitMQ(CAppConfig &rConfig);
~CRabbitMQ();
void InitializeRBMQ(CAppConfig &rConfig);//Initialize RBMQ Config;
BOOL Connect(int nServerType);
BOOL Disconnect(void);
BOOL Send(void *MomItem, LPCTSTR lpszKey, int &nSendCount);
BOOL Receive(void);
BOOL CreateQueue(LPCTSTR lpszQueueName);
BOOL CreateSessionExchange();
BOOL BindQueue(LPCTSTR lpszQueue, LPCTSTR lpszExchangeName, LPCTSTR lpszKey);
bool IsConnected(){return m_bConnected;}
void SetKeyQueueCombination( TCHAR *pszQueueName, TCHAR *pszRoutingKey);
void StopReceiver();
bool ReEstablishRMQMWConnection();
void GetData(LPBYTE &pMsg, int &nMsgLen,int &nReceiveCount);
void GetData(void* pMsg, int &nMsgLen,int nMsgType,int &nReceiveCount);
BOOL GetNext_JasonListItem(LPJASON_ITEM pItem);
LPRABBIT_MQ_ITEM GetNextItem();
};
Here i want to expose the rabbitMq class functions[Connect,send,Recieve ete from MiddleWareConnection.h to C# module.
Thanks
below I posted a small code example of a wrapping C++/CLI class. You could create a new C++/CLI project which links your native library and create a class following the example below. This will produce a managed assembly that you could reference from C# side. Hope it helps!
#include <Windows.h>
#include <vcclr.h>
using namespace System;
using namespace System::Text;
using namespace System::Collections::Generic;
using namespace System::Runtime::InteropServices;
public ref class CMiddleWareConnection_Net
{
public:
CMiddleWareConnection_Net()
{
pMiddleWareConnection = NULL;
}
~CMiddleWareConnection_Net()
{
//Release pMiddleWareConnection
if (pMiddleWareConnection)
delete pMiddleWareConnection;
}
void InitializeRBMQ(CAppConfig_Net config)
{
// CAppConfig_Net is another ref class
// which provides a toNative method
// returning a plain C++ CAppConfig object
CAppConfig rConfig = config.toNative();
pMiddleWareConnection = CRabbitMQ(rConfig);
}
bool Connect(int nServerType)
{
return (pMiddleWareConnection->Connect(nServerType) == TRUE);
}
bool Disconnect(void)
{
return (pMiddleWareConnection->Disconnect() == TRUE);
}
bool Send(array<Byte>^ MomItem, String^ lpszKey, int% nSendCount)
{
//Assuming MomItem is a byte array...
unsigned char *pData = new unsigned char[MomItem->Length];
Marshal::Copy(MomItem, 0, IntPtr(pData), MomItem->Length);
//Marshal String^ to LPCSTR
IntPtr ip = Marshal::StringToHGlobalAnsi(lpszKey);
LPCSTR str = static_cast<LPCSTR>(ip.ToPointer());
bool bRet = (pMiddleWareConnection->Send(pData, str, nSendCount) == TRUE);
//Freeing memory
delete[] pData;
Marshal::FreeHGlobal(ip);
return bRet;
}
bool Receive(void)
{
return (pMiddleWareConnection->Receive() == TRUE);
}
/* Other methods */
...
private:
CMiddleWareConnection *pMiddleWareConnection;
};
****MiddleWareFactory.h****
BOOL CreateInstance(CMiddleWareConnection** pMObj)
{
//if( some config value)
*pMObj = new RabbitMq();
// esle
/***other MOm like OBCS,OSCS etec...**/
}
****MiddlewareConnection.h****
have the basic abstract functions....
**Rabbitmq.h**
it is one of the child class.
****Wrapper****
CLRWrapper::CppMathWrapper::CppMathWrapper()
{
cppMath = new cCppMath();
oFact->createInstance(&cppMath);'// here i want to pass the reference & wanna get back the child class type:now i am stuck here..how can we pass/marshal the object:im getting the error
}
BOOL CLRWrapper::CppMathWrapper::connect(type)
{
return (cppMath->Connect(nServerType) == TRUE);
}
..........And so On............
CLR Wrapper.cpp(11) : error C2664: 'Factory::createInstance' : cannot convert parameter 1 from 'cli::interior_ptr' to 'Base **'
1> with
1> [
1> Type=cCppMath *
1> ]
1> Cannot convert a managed type to an unmanaged type
}
instead of this we are using createinstance()[InitializeRBMQ() is inside connect(),so it will be handled inside i think]
void InitializeRBMQ(CAppConfig_Net config)
{
// CAppConfig_Net is another ref class
// which provides a toNative method
// returning a plain C++ CAppConfig object
CAppConfig rConfig = config.toNative();
pMiddleWareConnection = CRabbitMQ(rConfig);
}
C# side
i want to expose :
private static void Main(string[] args)
{
CppMathWrapper wrapper = new CppMathWrapper();
wrapper.connect(0);
}
i tried one example with CPPMath class.In real i am attaching the code below:
CLRWrapper::CppMathWrapper::CppMathWrapper()
{
middlewareConnection *oConn;// MiddleConnection.h pointer
middleWareFactory oFact= new middleWareFactory ();// MiddleWareFactory.h object
oFact->createInstance(&oConn);'// here i want to pass the reference & wanna get back the child class type:now i am stuck here..how can we pass/marshal the object:im getting the error.How could i wrap the object....the same like
}
BOOL CLRWrapper::CppMathWrapper::connect(type)
{
return (oConn->Connect(nServerType) == TRUE);
}
..........And so On............

VC++ DLL throws error when call it from C#[EntryPointNotFound]

Here i created in DLL project in vc++ 2008. Following are two code files lib.h and lib.cpp.
lib.h
#include "stdafx.h";
class __declspec(dllexport) test
{
public:
test();
static void hello();
static void hello1();
};
class __declspec(dllexport) test1
{
public:
test1();
void hello_test1();
void hello1_test1();
};
lib.cpp
#include "stdafx.h"
#include "lib.h"
#include <stdio.h>
void test::hello()
{
printf("Hello");
}
void test::hello1()
{
printf("Hello1");
}
void test1::hello_test1()
{
printf("Hello_test1");
}
void test1::hello1_test1()
{
printf("Hello1_test1");
}
stdafx.h
#include "targetver.h"
#define WIN32_LEAN_AND_MEAN
// Windows Header Files:
#include <windows.h>
dllMain.cpp
#include "stdafx.h"
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
I have written C# code to call the method of test and test1 classes:
ConsoleApp
[DllImport("lib.dll" )]
public static extern void hello();
[DllImport("lib.dll")]
public static extern void hello1();
[DllImport("lib.dll")]
public static extern void hello_test1();
[DllImport("lib.dll")]
public static extern void hello1_test1();
static void Main()
{
hello();
hello1();
hello_test1();
hello1_test1();
Console.ReadKey();
}
when i run above code i have got following error:
EntryPointNotFoundException: Unable to find an entry point named 'hello' in DLL 'lib.dll'
I know about how to call function only(without using Class) of vc++ DLL from C# but i don't know how to call method of any class and how to code that in proper way in vc++.
I know somewhere is mistake in my above code, please experts guide me about my mistake because i tried all from my side.
If anyone has full example like above then suggest me.
Thanks in advance..
As far as I'm aware there is no way to directly call a native class method from c#. The typical way to get around this is to make non-member functions that call the class methods and interact with those. Please refer to the following link for more specifics. It includes a direct example of what you are trying to do.
using a class defined in a c++ dll in c# code
After reading more of the answers it might be possible but it appears that the link shows the examples you are looking for.
#Jarrett Thanks for moving me towards to Marshal concept.
I added testClass.h and testClass.cpp in this project to marshal C++ classes
testClass.h
#ifndef __testClass_h__
#define __testClass_h__
#include "lib.h"
#ifdef __cplusplus
extern "C" {
#endif
extern LIBDLL_API test* createTestClass();
extern LIBDLL_API void disposeTestClass(test* pObject);
extern LIBDLL_API void callHello(test* pObject);
extern LIBDLL_API void callHelloTest1Class(test1* pObject);
#ifdef _cplusplus
#endif
}
#endif
testClass.cpp
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "stdafx.h"
#include "testClass.h"
extern "C" LIBDLL_API test* createTestClass()
{
return new test();
}
extern "C" LIBDLL_API void disposeTestClass(test* pObject)
{
if(pObject!=NULL)
{
delete pObject;
pObject=NULL;
}
}
extern "C" LIBDLL_API void callHello(test* pObject)
{
if(pObject!=NULL)
{
pObject->hello();
}
}
extern "C" LIBDLL_API void callHelloTest1Class(test1* pObject)
{
if(pObject!=NULL)
{
pObject->hello_test1();
}
}
lib.h
#include "stdafx.h";
#ifdef LIB_EXPORTS
#define LIBDLL_API __declspec(dllexport)
#else
#define LIBDLL_API __declspec(dllimport)
#endif
class LIBDLL_API test
{
public:
test();
virtual ~test();
static void hello();
static void hello1();
};
class LIBDLL_API test1
{
public:
test1();
void hello_test1();
void hello1_test1();
};
lib.cpp
#pragma once
#include "stdafx.h"
#include "lib.h"
#include <stdio.h>
#include <iostream>
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#include <windows.h>
test::test()
{}
test::~test()
{}
void test::hello()
{
printf("\nHello");
}
void test::hello1()
{
printf("Hello1");
}
void test1::hello_test1()
{
printf("\nHello_test1");
}
void test1::hello1_test1()
{
printf("Hello1_test1");
}
And now create a console application and add some code in program.cs file
Program.cs
namespace ConsoleApplication1
{
class ConsoleApplication1
{
static void Main()
{
CS_Test_Class testClass = new CS_Test_Class();
testClass.hello();
testClass.hello_test1();
Console.ReadKey();
testClass.Dispose();
}
}
}
program.cs call the method of CS_Test_Class.cs So....
CS_Test_Class.cs
using System;
using System.Runtime.InteropServices;
namespace ConsoleApplication1
{
public class CS_Test_Class:IDisposable
{
[DllImport("lib.dll")]
public static extern IntPtr createTestClass();
[DllImport("lib.dll")]
static private extern void disposeTestClass(IntPtr pTestClassObject);
[DllImport("lib.dll")]
static private extern void callHello(IntPtr pTestClassObject);
[DllImport("lib.dll")]
static private extern void callHelloTest1Class(IntPtr pTestClassObject);
private IntPtr nativeObject;
public CS_Test_Class()
{
this.nativeObject = createTestClass();
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool bDisposing)
{
disposeTestClass(this.nativeObject);
this.nativeObject = IntPtr.Zero;
if (bDisposing)
GC.SuppressFinalize(this);
}
~CS_Test_Class()
{
Dispose(false);
}
public void hello()
{
callHello(this.nativeObject);
}
public void hello_test1()
{
callHelloTest1Class(this.nativeObject);
}
}
}
Marshling allows you to acces the class and method of c++ Dll. Microsoft provides facility to Marshal C-functions and also provides the mechanism to Marshal c++ clases.
Enjoy Marshling...
Thank you.

NullReferenceException during C++ callback to C# function

developers!
I have very strange problem. My project has DLL writen in C++ and a GUI writen in C#. And I have implemented callback for some interoperability. I planed that C++ dll will call C# code in some circumstances. It works... but not long and I cant understand why. The problem marked in comment in C# part
Here the complete code of simplified sample:
C++ DLL:
#include <SDKDDKVer.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
extern "C"
{
typedef void (*WriteSymbolCallback) (char Symbol);
WriteSymbolCallback Test;
_declspec(dllexport) void InitializeLib()
{
Test = NULL;
}
_declspec(dllexport) void SetDelegate(WriteSymbolCallback Callback)
{
Test = Callback;
}
_declspec(dllexport) void TestCall(const char* Text,int Length)
{
if(Test != NULL)
{
for(int i=0;i<Length;i++)
{
Test(Text[i]);
}
}
}
};
C# part:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace CallBackClient
{
class Program
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void WriteToConsoleCallback(char Symbol);
[DllImport("CallbackSketch.dll",CharSet=CharSet.Ansi,CallingConvention=CallingConvention.Cdecl)]
private static extern void InitializeLib();
[DllImport("CallbackSketch.dll",CharSet=CharSet.Ansi,CallingConvention=CallingConvention.Cdecl)]
private static extern void SetDelegate(WriteToConsoleCallback Callback);
[DllImport("CallbackSketch.dll",CharSet=CharSet.Ansi,CallingConvention=CallingConvention.Cdecl)]
private static extern void TestCall(string Text,int Length);
private static void PrintSymbol(char Symbol)
{
Console.Write(Symbol.ToString());
}
static void Main(string[] args)
{
InitializeLib();
SetDelegate(new WriteToConsoleCallback(PrintSymbol));
string test = "Hello world!";
for (int i = 0; i < 15000; i++)
{
TestCall(test, test.Length);// It crashes when i == 6860!!!! Debugger told me about System.NullReferenceException
}
}
}
}
The problem is that it crashes in 6860th iteration! I believe that the problem is lack of my knowlege in the subject. Could sombody help me?
SetDelegate(new WriteToConsoleCallback(PrintSymbol));
Yes, this cannot work properly. The native code is storing a function pointer for the delegate object but the garbage collector cannot see this reference. As far as it is concerned, there are no references to the object. And the next collection destroys it. Kaboom.
You have to store a reference to the object yourself. Add a field in the class to store it:
private static WriteToConsoleCallback callback;
static void Main(string[] args)
{
InitializeLib();
callback = new WriteToConsoleCallback(PrintSymbol);
SetDelegate(callback);
// etc...
}
The rule is that the class that stores the object must have a lifetime at least as long as native code's opportunity to make the callback. It must be static in this particular case, that's solid.

Categories

Resources