WINAPI Callback in C# **gelöst**



  • Ja, weils ein Referenztyp ist.
    Simon



  • wenn ich das mapping in die Dll verschiebe

    Da habe ich mich etwas unklar ausgedrückt. Mit mapping meine ich von managed auf unmanaged. D.h. die Zeiger sollen verschwinden und in der DLL so aufbereitet werden, dass sie eben in C# ohne unsafe auskommen.

    Simon



  • und wie mach ich das dann wenn ich meine C funktion rufe (alos ich habe jetzt mal die Referenz auf das Delegate übergeben - das ^ noch gesetzt in der Deklaration)

    static tKSErrorCode KSSetDllResultHandlerGetMode(tKSDllResultHandlerGetMode ^pHandler);
    

    doch wie mache ich das jetzt wenn ich meine C Funktion den Pointer übergeben will?

    tKSErrorCode CTest::KSSetDllResultHandlerGetMode(tKSDllResultHandlerGetMode ^pHandler)
    {
    	return (tKSErrorCode)SetDllResultHandlerGetMode(pHandler);
    }
    

    er meldet jetzt: DllDotNet.cpp(14) : error C2664: 'SetDllResultHandlerGetMode': Konvertierung des Parameters 1 von 'DllDotNet::tKSDllResultHandlerGetMode ^' in 'tDllResultHandlerGetMode (__cdecl *)' nicht möglich

    MfG





  • Ev. hilft dir der folgende Link. Dabei ist auch ein Bsp mit EnumWindows (ähnlich wie das Bsp. von dir).
    http://www.codeproject.com/KB/mcpp/quickcppcli.aspx



  • wenn ich die Funktion jetzt so mache bringt der eine Warnung

    tKSReaderErrorCode CTest::KSSetDllResultHandlerGetMode(tKSDllResultHandlerGetMode ^pHandler)
    {
    	return (tKSErrorCode)SetDllResultHandlerGetMode(System::Runtime::InteropServices::Marshal.GetFunctionPointerForDelegate(pHandler));
    }
    

    Warnungen:
    DllDotNet.cpp(14) : warning C4832: Das Token '.' ist nach UDT 'System::Runtime::InteropServices::Marshal' illegal
    c:\windows\microsoft.net\framework\v2.0.50727\mscorlib.dll: Siehe Deklaration von 'System::Runtime::InteropServices::Marshal'
    DllDotNet.cpp(14) : error C2275: 'System::Runtime::InteropServices::Marshal': Ungültige Verwendung dieses Typs als Ausdruck

    was bedutet diese?

    MfG



  • Ja, da muss ein Doppelpunkt sein, kein Punkt.
    Simon



  • Ok

    tKSReaderErrorCode CTest::KSSetDllResultHandlerGetMode(tKSDllResultHandlerGetMode ^pHandler)
    {
    	return (tKSErrorCode)SetDllResultHandlerGetMode(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(pHandler));
    }
    

    jetzt kommt der Fehler:
    DllDotNet.cpp(14) : error C2664: 'SetDllResultHandlerGetMode': Konvertierung des Parameters 1 von 'System::IntPtr' in 'tDllResultHandlerGetMode (__cdecl *)' nicht möglich

    selbst wenn ich Caste

    tKSReaderErrorCode CTest::KSSetDllResultHandlerGetMode(tKSDllResultHandlerGetMode ^pHandler)
    {
    	return (tKSErrorCode)SetDllResultHandlerGetMode((tDllResultHandlerGetMode)System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(pHandler));
    }
    

    also bin ich wieder da wo ich vorher war. Hast du noch eine Idee?

    MfG



  • gibt es da eine Möglichkeit das zu umgehen?

    MfG



  • Ich habe mal ein kleines Bsp. geschrieben, welches dein Problem anspricht.
    Dabei geht es darum ein C Aufruf mit Callback von managed nach unmanaged und wieder zurück zu bringen.

    Dabei bringt die Klasse WindowEnumerator (native) den C Aufruf mit Callback zusammen. Die Klasse WindowsEnumeratorWrapper (managed) benutzt den WindowsEnumerator (native).

    In deinem Fall ist dann der WindowsEnumeratorWrapper die Bridge zu C#. (WindowsEnumeratorWrapper müsst noch in einen namespace gesteckt werden.)

    WindowsEnumerator.h

    #pragma once
    #include <windows.h>
    #include <vcclr.h>
    
    ref class WindowsEnumeratorWrapper;
    
    class WindowsEnumerator
    {
    public:
    	WindowsEnumerator(WindowsEnumeratorWrapper^ wrapper);
    
    	void Enumerate() const;
    
    private:
    	void OnCallback(const TCHAR* windowText) const;
    	static BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam);
    
    private:
    	gcroot<WindowsEnumeratorWrapper^> _wrapper;
    };
    

    WindowsEnumerator.cpp

    #include "stdafx.h"
    #include "WindowsEnumerator.h"
    #include "WindowsEnumeratorWrapper.h"
    
    using namespace System;
    
    WindowsEnumerator::WindowsEnumerator(WindowsEnumeratorWrapper^ wrapper)
    : _wrapper(wrapper)
    {
    }
    
    void WindowsEnumerator::Enumerate() const
    {
    	EnumWindows(&WindowsEnumerator::EnumWindowsProc, reinterpret_cast<LPARAM>(this));
    }
    
    void WindowsEnumerator::OnCallback(const TCHAR* windowText) const
    {
    	_wrapper->OnCallback(gcnew String(windowText));
    }
    
    BOOL CALLBACK WindowsEnumerator::EnumWindowsProc(HWND hWnd, LPARAM lParam)
    {
    	WindowsEnumerator* instance = reinterpret_cast<WindowsEnumerator*>(lParam);
    
    	const size_t len = 256;
    	TCHAR buf[len] = {};
    	GetWindowText(hWnd, buf, len);
    
    	instance->OnCallback(buf);
    
    	return TRUE;
    }
    

    WindowsEnumeratorWrapper.h

    #pragma once
    #include "WindowsEnumerator.h"
    
    using namespace System;
    
    public delegate void WindowEventHandler(String^ windowText);
    
    public ref class WindowsEnumeratorWrapper
    {
    public:
    	event WindowEventHandler^ OnWindow;
    
    public:
    	WindowsEnumeratorWrapper()
    	{
    		_enumerator = new WindowsEnumerator(this);
    	}
    
    	~WindowsEnumeratorWrapper()
    	{
    		delete _enumerator;
    	}
    
    	void Enumerate()
    	{
    		_enumerator->Enumerate();
    	}
    
    	void OnCallback(String^ windowText)
    	{
    		OnWindow(windowText);
    	}
    
    private:
    	WindowsEnumerator* _enumerator;
    };
    

    Test.cpp

    #include "stdafx.h"
    #include "WindowsEnumeratorWrapper.h"
    
    using namespace System;
    using namespace System::Diagnostics;
    
    ref class EventSink
    {
    public:
    	void OnWindow(String^ windowText)
    	{
    		Debug::WriteLine(windowText);
    	}
    };
    
    int main(array<System::String ^> ^args)
    {
    	EventSink sink;
    
    	WindowsEnumeratorWrapper wrapper;
    	wrapper.OnWindow += gcnew WindowEventHandler(%sink, &EventSink::OnWindow);
    	wrapper.Enumerate();
    
        return 0;
    }
    

    Dieser Code ist nur als simples Bsp. gedacht. Gut möglich dass noch einiges verbessert werden könnte (z.B. könnte ein managed Callback Interface definiert werden anstatt die Klasse direkt zu übergeben).
    Simon



  • ich versuche gerade mal obiges beispiel nachzuprogrammieren

    aber es scheitert schon an der Klassendefinition

    #include "DllDotNetWrapper.h"
    
    ref class CRWrapper;
    
    class CR
    {
    public:	
    	//CR(CRWrapper ^wrapper);
    };
    
    #include "DllDotNet.h" 
    
    using namespace System;
    
    public ref class CRWrapper 
    	{ 
    	private: 
    		CR *pR;
    	};
    

    er meldet bei CR *pR:

    DllDotNetWrapper.h(37) : error C2143: Syntaxfehler: Es fehlt ';' vor '*'
    DllDotNetWrapper.h(37) : error C4430: Fehlender Typspezifizierer - int wird angenommen. Hinweis: "default-int" wird von C++ nicht unterstützt.

    MfG



  • Ich nehme mal an in CRWrapper in CR unbekannt. Binde das Header File ein (Vorwärtsdekl. reicht nicht, weil Du ja nachher ein new machst).
    Simon



  • DllDotNet.h ist der Header wo die CR Klasse drin ist.

    OK nachdem ich #include"DllDotNetWrapper.h" auskommentiert habe ging es

    gcroot<CRWrapper^> RWrapper;
    

    jetzt hat er Probleme mit der anweisung, da er gcroot nicht kennt.

    MfG



  • Ok include vergessen



  • ich habe das Beispiel jetzt für mich angepasst.

    habe aber noch eine Frage zu deinem c++ Code

    Bringt der Commpiler bei dir beim aufruf des Callbacks keine Fehlermeldung?

    void WindowsEnumerator::OnCallback(const TCHAR* windowText) const 
    { 
        _wrapper->OnCallback(gcnew String(windowText)); 
    }
    

    bei mir sagt er:

    1>.\DllDotNet.cpp(30) : error C3767: "DllDotNet::CRWrapper::OnHandler::raise": Auf mögliche Funktion(en) kann nicht zugegriffen werden.

    MfG



  • Nein. Ich rate mal: Du hast OnWindow zu OnCallback umbenannt...
    Simon



  • Ok ich habe mich falsch ausgedrückt.

    Ich habe das beispiel nachgebaut.

    Meine Funktion ist:

    void DllDotNet::CRead::Handler(TByte uwNumberOfDevices, TDWord *pListOfDevices,void *pTag)
    {
    	RWrapper->OnCallbackHandler(uwNumberOfDevices,pListOfDevices,pTag);
    }
    

    deshalb steht da ein anderer Name.

    hier noch die Wrapper Klasse

    public delegate void tKSdelDllHandler(int uwNumberOfDevices, void *pListOfDevices,void *pTag);
    
    public ref class CReadWrapper 
    	{ 
    	private: 
    		CRead *pRead;
    	public: 
    		event tKSdelDllHandler ^OnHandler;
    
    		CReadWrapper() 
    		{ 
    			pRead = new CRead(this); 
    		} 
    
    		~CReadWrapper() 
    		{ 
    			delete pRead; 
    		} 
    
    		void OnCallbackHandler(int uwNumberOfDevices, void *pListOfDevices,void *pTag)
    		{
    			OnHandler(uwNumberOfDevices,pListOfDevices,pTag);
    		}
    	};
    

    und die c++ Klasse:

    class CRead
    	{
    	private:
    		gcroot<CReaderWrapper^> ReadWrapper;
    
    		static void HandlerCallback(TByte uwNumberOfDevices, TDWord *pListOfDevices,void *pTag);
    
    	public:	
    		CRead(CReadWrapper ^wrapper);
    
    		void Handler(TByte uwNumberOfDevices, TDWord *pListOfDevices,void *pTag);
    
    	};
    

    und da bringt er die Fehlermeldung:
    1>.\DllDotNet.cpp(30) : error C3767: "DllDotNet::CReadWrapper::OnHandler::raise": Auf mögliche Funktion(en) kann nicht zugegriffen werden.

    MfG

    Edit: fehlende Funkion hinzugefügt



  • in der MSDN steht irgendwas von friend funktionen, die ich aber doch gar nihct benutze

    komisch



  • Guck nochmals im Bsp. Du rufst in der CRead Klasse direkt den OnHandler event auf, im Bsp. wird der OnHandler aber in der CReadWrapper Klasse aufgerufen.

    Simon



  • ja das wars


Anmelden zum Antworten