[C++/CLI] Native Funktion aus Managed-Callback aufrufen

FBIagent

Erfahrenes Mitglied
Guten tag,

ich versuche momentan einen Wrapper um die Logitech Gaming Software SDK für .NET zu schreiben. Allerdings kommt es zu Problemen wenn ich eine native Funktion im Managed-Callback aufrufen möchte der vom nativen Code aufgerufen wurde.

Das gleiche habe ich einmal in C# sowie C++/CLI versucht wobei beides den gleichen Effekt brachte.

Das ganze läuft so ab: Ich verbinde mit hilfe der nativen Lib zum LCD monitor service von Logitech und gebe dieser Funktion den Funktion-Pointer der in .NET definierten delegates. Nun wird irgendwann meine definierte Managed-Methode aufgerufen, in der ich eine weitere native Funktion der Lib aufrufe. Allerdings passiert beim aufruf der nativen Funktion nichts mehr. Genau gesagt weis ich nciht genau was passiert, der debugger spingt einfach auf normale ausführung selbst wenn ich einzellschritt debugge(zeilen code nach dem aufruf der nativen Funktion werden nicht ausgeführt, zumindest erreicht das Programm niemals die gesetzten Haltepunkte).

Die relevanten Methoden sind LGLCDConnection::_Connect(übergibt den Funktionspointer and die native Lib), LGLCDConnection::_NotifyCallback(der callback) und LGLCDConnection::Disconnect(wird von _NotifyCallback aufgerufen und ruft die native Funktion lgLcdDisconnect auf).

Der code der Klassenbibliothek sieht wie folg aus:
C++:
// LGLCDConnection.h
#pragma once

using namespace System;
using namespace System::Collections::Generic;

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN 1
#endif
#include <Windows.h>
#include <lglcd.h>

namespace LGLCDNet
{
	interface class LGLCDConnectionHandler;

	public ref class LGLCDConnection
	{
	private:
		delegate UInt32 ConfigCBDelegate(Int32 connection, IntPtr^ pContext);
		delegate UInt32 NotifyCBDelegate(Int32 connection, IntPtr^ pContext, UInt32 notificationCode, UInt32 notifyParm1, UInt32 notifyParm2, UInt32 notifyParm3, UInt32 notifyParm4);
	public:
		enum class AppletCapabilities : UInt32
		{
			BASIC = LGLCD_APPLET_CAP_BASIC,
			BW = LGLCD_APPLET_CAP_BW,
			QVGA = LGLCD_APPLET_CAP_QVGA
		};

	private:
		static LGLCDConnection();
	public:
		static LGLCDConnection^ LGLCDConnection::Connect(String^ name, Boolean autostartable, AppletCapabilities capabilities, LGLCDConnectionHandler^ handler)
		{
			LGLCDConnection^ con = gcnew LGLCDConnection(handler);
			con->_Connect(name, autostartable, capabilities);
			return con;
		}

	internal:
		volatile Int32 _connection;
	private:
		LGLCDConnectionHandler^ _handler;
		// hold references since we pass function pointers to native code
		ConfigCBDelegate^ _configCallback;
		NotifyCBDelegate^ _notifyCallback;

		LGLCDConnection(LGLCDConnectionHandler^ handler);
		~LGLCDConnection();

		UInt32 _ConfigCallback(Int32 connection, IntPtr^ pContext);
		UInt32 _NotifyCallback(Int32 connection, IntPtr^ pContext, UInt32 notificationCode, UInt32 notifyParm1, UInt32 notifyParm2, UInt32 notifyParm3, UInt32 notifyParm4);

		void _Connect(String^ name, Boolean autostartable, AppletCapabilities capabilities);

	public:
		void Disconnect();
		Boolean IsConnected();
	};
}

C++:
// LGLCDConnection.cpp
#include "LGLCDConnection.h"

#include <msclr\marshal.h>
using namespace msclr::interop;
using namespace System::Runtime::InteropServices;

#include "LGLCDConnectionHandler.h"

namespace LGLCDNet
{
	static LGLCDConnection::LGLCDConnection()
	{
		lgLcdInit();
	}

	LGLCDConnection::LGLCDConnection(LGLCDConnectionHandler^ handler)
	{
		_connection = LGLCD_INVALID_CONNECTION;
		_handler = handler;
	}

	LGLCDConnection::~LGLCDConnection()
	{
		Disconnect();
	}

	UInt32 LGLCDConnection::_ConfigCallback(Int32 connection, IntPtr^ pContext)
	{
		UNREFERENCED_PARAMETER(connection);
		UNREFERENCED_PARAMETER(pContext);
		try
		{
			_handler->OnConfigure(this);
		}
		catch (...)
		{
			Console::WriteLine("_ConfigCallback exception!");
		}
		return 0;
	}

	UInt32 LGLCDConnection::_NotifyCallback(Int32 connection, IntPtr^ pContext, UInt32 notificationCode, UInt32 notifyParm1, UInt32 notifyParm2, UInt32 notifyParm3, UInt32 notifyParm4)
	{
		UNREFERENCED_PARAMETER(connection);
		UNREFERENCED_PARAMETER(pContext);
		UNREFERENCED_PARAMETER(notifyParm1);
		UNREFERENCED_PARAMETER(notifyParm2);
		UNREFERENCED_PARAMETER(notifyParm3);
		UNREFERENCED_PARAMETER(notifyParm4);

		try
		{
			switch (notificationCode)
			{
			case LGLCD_NOTIFICATION_CLOSE_CONNECTION:
				Disconnect();
				_handler->OnDisconnect(this);
				break;
			default:
				break;
			}
		}
		catch (...)
		{
			Console::WriteLine("_NotifyCallback exception!");
		}

		return 0;
	}

	void LGLCDConnection::_Connect(String^ name, Boolean autostartable, AppletCapabilities capabilities)
	{
		_configCallback = gcnew ConfigCBDelegate(this, &LGLCDConnection::_ConfigCallback);
		_notifyCallback = gcnew NotifyCBDelegate(this, &LGLCDConnection::_NotifyCallback);

		marshal_context^ marshalCtx = gcnew marshal_context();
		lgLcdConnectContextExW connectCtx;
		connectCtx.appFriendlyName = marshalCtx->marshal_as<LPCWSTR>(name);
		connectCtx.isPersistent = FALSE;
		connectCtx.isAutostartable = autostartable;
		connectCtx.onConfigure.configCallback = (lgLcdOnConfigureCB)Marshal::GetFunctionPointerForDelegate(_configCallback).ToPointer();
		connectCtx.onConfigure.configContext = nullptr;
		connectCtx.connection = LGLCD_INVALID_CONNECTION;
		connectCtx.dwAppletCapabilitiesSupported = (DWORD)capabilities;
		connectCtx.dwReserved1 = 0;
		connectCtx.onNotify.notificationCallback = (lgLcdOnNotificationCB)Marshal::GetFunctionPointerForDelegate(_notifyCallback).ToPointer();
		connectCtx.onNotify.notifyContext = nullptr;
		DWORD res = lgLcdConnectExW(&connectCtx);
		if (res != 0)
			throw gcnew Exception("Failed to open connection. Code: " + res);
		_connection = connectCtx.connection;
	}

	void LGLCDConnection::Disconnect()
	{
		lgLcdDisconnect(_connection);
		_connection = LGLCD_INVALID_CONNECTION;
	}

	Boolean LGLCDConnection::IsConnected()
	{
		return _connection != LGLCD_INVALID_CONNECTION;
	}
}

C++:
// LGLCDConnectionHandler.h
#pragma once

namespace LGLCDNet
{
	ref class LGLCDConnection;

	public interface class LGLCDConnectionHandler
	{
		void OnConfigure(LGLCDConnection^ con);
		void OnDisconnect(LGLCDConnection^ con);
	};
}

Der Code der Konsolenanwendung zum test sieht so aus:
C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using LGLCDNet;

namespace LGLCD.Net.Test
{
	class Program : LGLCDConnectionHandler
	{
		private static LGLCDConnection _CON;

		static void Main(string[] args)
		{
			try
			{
				_CON = LGLCDConnection.Connect("lglcd.net.test", true, LGLCDConnection.AppletCapabilities.QVGA, new Program());
				Console.WriteLine("Connected to LCDMon.");
				while (_CON != null)
				{
					Thread.Sleep(1);
				}
			}
			catch (Exception e)
			{
				Console.WriteLine("Failed to connect to LCDMon! " + e);
			}

			Console.ReadKey();
		}

		public void OnConfigure(LGLCDConnection con)
		{
			
		}

		public void OnDisconnect(LGLCDConnection con)
		{
			Console.WriteLine("Connection to LCDMon closed.");
			_CON = null;
		}
	}
}

Woran kann das liegen das das Programm nach dem nativen Funktionsaufruf nicht weiter macht?
 
Zuletzt bearbeitet:
Zurück