Globaler Speicher

Cromon

Erfahrenes Mitglied
An Moderatoren: Falls möglich/nötig bitte in den .net-Bereich verschieben ;)

Hallo miteinander!

Ich entwickle im Moment gerade eine Bibliothek für die CLR-Sprachen mit gewissen Funktionalitäten.

Allerdings finden die wesentlichen Aktivitäten nicht in der .net-DLL statt sondern sie geschehen über eine in naitivem C++ geschriebenen DLL und die beiden synchronisieren über ein entsprechendes Interface.

Die Sprünge zwischen verwaltetem und unverwaltetem Code funktionieren soweit mit Hilfe von #pragma managed relativ gut, allerdings habe ich an einem Punkt etwas Probleme.

Die Situation:
1. Ein Socketinterface wird gestartet in der C++-DLL von der .net-DLL aus
2. Das Interface feuert Events, wenn zum Beispiel ein Client connectet hat.
3. Die abstrakte Basisklasse IConnectionManager, die sowohl in der C++-DLL als auch in der .net-DLL vorhanden ist fängt diese Events ab und gibt sie über eine unverwaltete Funktion in die .net-DLL

Code:
class IConnectionManager
{
	typedef void (*tOnClient)(IConnectionManager*, IAsyncSocket*);
public:
	tOnClient OnClient;
	virtual bool StartUp(UINT port, const char* listenaddr = 0) = 0;
};

...

// In der Klasse CConnectionManager, die von IConnectionManager erbt

if(OnClient)
{
	OnClient(this, (IAsyncSocket*)&m_clientsocket);
}

Und in der .net-DLL:
Code:
	public ref class CConnectionManager
	{
		IConnectionManager* m_base;
		....
	}

Im folgenden dann die Funktionen, über die ich aus der C++-DLL bei einem Event zurück in die .net-DLL komme
Code:
			void FindManager(IConnectionManager* icm, IAsyncSocket* sock)
			{
				
			}

#pragma unmanaged

			void OnClient(IConnectionManager* icm, IAsyncSocket* sock)
			{
				FindManager(icm, sock);
			}

#pragma managed

Die OnClient-Funktion wird dann auch entsprechend im Konstruktor von CConnectionManager "registriert":
Code:
...
				m_base->OnClient = OnClient;
...

Soweit so gut, wenn ich in FindManager eine verwaltete MessageBox anzeige wird die perfekt angezeigt wenn ein Client eine Verbindung herstellt, die Kette funktioniert bis dahin also einwandfrei. Nun habe ich jedoch ein Problem:

Wie kriege ich in der Funktion FindManager die passende Instanz der verwalteten Klasse CConnectionManager? Mein erster Approach war es eine globale Hashtable zu deklarieren in der dann die entsprechenden Instanzen geordnet nach ihren Hash-Werten (mit GetHashCode()) stehen und ich der Basis (m_base) im Konstruktor den Hashwert meiner Instanz mitgebe, der ja unsigned int ist und somit tiptop in den unverwalteten Bereich mitgenommen werden könnte.

Allerdings scheitert das oben Genannte daran, dass man verwaltete Typen nicht global deklarieren kann.

Daher meine Fragen:
Gibt es irgendwo eine Möglichkeit, wie ich in einem global verfügbaren Speicher meine Instanz inclusive einem Merkmal, das sich in den unverwalteten Bereich mitnehmen lässt hinterlegen, oder sonst eine Möglichkeit wie ich in FindManager an die passende Instanz kommen kann?

Mit besten Grüssen
Cromon
 
Zuletzt bearbeitet:
So, nun finde ich auch noch Zeit hier zu schreiben!

Langsam wird es mir irgendwie peinlich, immer wenn ich Stunden vergeblich gesucht habe und dann hier sozusagen als letze Hoffnung ein Posting mache kommt mir die zündende Idee ;D.

Mir ist in den Sinn gekommen, dass ja die ganze .net-Sache im wesentlichen auf der COM beruht also muss ja meine CConnectionHandler-Klasse, die von System::Object standardmässig erbt auch ein COM-Interface sein und somit irgendwo ganz ganz weit weg von IUnknown erben. Viel Googeln und Probieren verhalf mir dann zu den zwei Funktionen:
Code:
System::IntPtr System::Runtime::InteropServices::Marshal::GetIUnknownForObject(System::Object^)

System::Object^ System::Runtime::InteropServices::Marshal::GetObjectForIUnknown(System::IntPtr)

Damit hat sich dann die Lösung folgendermassen gestaltet:
Code:
#ifndef _ICONNECTION_MANAGER
#define _ICONNECTION_MANAGER

class IConnectionManager
{
	typedef void (*tOnClient)(IConnectionManager*, IAsyncSocket*);
public:
	void* ManagedHandler;
	tOnClient OnClient;
	virtual bool StartUp(UINT port, const char* listenaddr = 0) = 0;
};

#endif

Ausserdem:
Code:
System::IntPtr variant = System::Runtime::InteropServices::Marshal::GetIUnknownForObject(this);
m_base->ManagedHandler = variant.ToPointer();

Und dann in der FindHandler:
Code:
			void FindManager(IConnectionManager* icm, IAsyncSocket* sock)
			{
				try
				{
					CConnectionManager^ mgr = (CConnectionManager^)System::Runtime::InteropServices::Marshal::GetObjectForIUnknown(IntPtr(icm->ManagedHandler));
					System::Windows::Forms::MessageBox::Show(mgr->Message); // Kleiner Test, obs geklappt hat :D
					mgr->OnClientConnected(sock)
				}
				catch(...) // mgr ist nicht gültig, also ist wohl auch icm nicht gültig --> drop
				{
				}
			}

Klappt soweit bis jetzt wunderbar!
 
Zurück