2016-06-29 8 views
0

Ich entwickle eine Windows 8-Telefonanwendung, in der ich Callback-Ereignisnachrichten von C++ - Code an den UI-Code in C# senden muss. Unten ist der C# -Code, in dem ich die Callback-Funktion erstelle und den Zeiger auf den C++ - Code sende. Der C++ - Code kann mit diesem Funktionszeiger asynchrone Ereignismeldungen an die Benutzerschnittstelle senden.Zugriffsverletzung Leseort 0x00000004 beim Senden von Callback von C++ - Code an C# -Code

C# -Code

public partial class MainPage 
{ 
     public MainPage() 
     { 
      InitializeComponent(); 
     } 
     public delegate void CallBack([In][MarshalAs(UnmanagedType.LPStr)] string strParam); 
     [DllImport("Test.dll", CallingConvention = CallingConvention.StdCall)] 
     public static extern void PerformActionWithCallBack(int x); 

     void DemonstrateCallBack() 
     { 
      int x; 
      CallBack callback_delegate = new CallBack(CallBackFunction); 
      // Converting callback_delegate into a function pointer that can be 
      // used in unmanaged code. 
      IntPtr intptr_delegate = Marshal.GetFunctionPointerForDelegate(callback_delegate); 

      //Getting the pointer into integer value and sending it to C++ 

      x = (int)intptr_delegate; 

      testApp.PerformActionWithCallBack(x); 
     } 

     //CallBack function in which event messages will be received 
     void CallBackFunction([In][MarshalAs(UnmanagedType.LPStr)] string strParam) 
     { 
      if (Dispatcher.CheckAccess() == false) 
      { 
       //Updating the text block with the received message 
       Dispatcher.BeginInvoke(() => MyTextBlock.Text = strParam); 
      } 
      else 
      { 
       MyTextBlock.Text = "Update directly"; 
      } 
     } 
} 

Unten ist die C++ Code, der Ereignismeldungen an C#

//Callback function prototype 
typedef void(__stdcall *PCallBack)(LPSTR s); 
LPSTR cbMsg = NULL; 

//Global instance callback function 
PCallBack gUICallback; 

void TestApp::PerformActionWithCallBack(int x) 
{ 
    //Assigning the received calllback function pointer from C# to global function pointer 
    gUICallback = (PCallBack)x; 
} 

//This function will send event messages to C# 
void SendCallbackMsg() 
{ 
    while(1) 
    { 
     cbMsg = "Hello"; 
     Sleep(100); 
     gUICallback(cbMsg); 
     cbMsg = "Hi"; 
     Sleep(100); 
     gUICallback(cbMsg); 
    } 
} 

Mit diesem Code senden werde ich bin in die Ereignismeldungen erhalten C# erfolgreich, aber nach dem Senden von 650-700 Callbacks gibt meine Anwendung Zugriffsverletzung Ausnahme und danach funktioniert nichts. Ich vermute die Art, wie ich den Funktionszeiger von C# nach C++ übergebe, aber nicht lösen kann.

Antwort

2

Ihr Problem ist, Callback_Delegate wird Müll gesammelt.

MSDN sagt

Sie manuell die Delegierten werden gesammelt vom Garbage Collector von verwalteten Code halten müssen. Der Garbage Collector verfolgt den Verweis auf nicht verwalteten Code nicht.

Versuchen Sie, diese

public partial class MainPage 
{ 
    private CallBack _callBackDelegate = null; 
    public MainPage() 
    { 
     InitializeComponent(); 
    } 
    public delegate void CallBack([In][MarshalAs(UnmanagedType.LPStr)] string strParam); 
    [DllImport("Test.dll", CallingConvention = CallingConvention.StdCall)] 
    public static extern void PerformActionWithCallBack(int x); 

    void DemonstrateCallBack() 
    { 
     _callBackDelegate = new CallBack(CallBackFunction); 
     int x; 

     // Converting _callBackDelegate into a function pointer that can be 
     // used in unmanaged code. 
     IntPtr intptr_delegate = Marshal.GetFunctionPointerForDelegate(_callBackDelegate); 

     //Getting the pointer into integer value and sending it to C++ 

     x = (int)intptr_delegate; 

     testApp.PerformActionWithCallBack(x); 
    } 

    //CallBack function in which event messages will be received 
    void CallBackFunction([In][MarshalAs(UnmanagedType.LPStr)] string strParam) 
    { 
     if (Dispatcher.CheckAccess() == false) 
     { 
      //Updating the text block with the received message 
      Dispatcher.BeginInvoke(() => MyTextBlock.Text = strParam); 
     } 
     else 
     { 
      MyTextBlock.Text = "Update directly"; 
     } 
    } 
} 
+0

Wenn ich so muss ich die Callbackfunction statisch machen. Sonst die Initialisierung von CallBackDelegate durch "new CallBack (CallBackFunction);" gibt Fehler zurück, da "Feldinitialisierer das nicht statische Feld/Methode nicht referenzieren kann". Und wenn ich die CallbackFunction statisch mache, dann kann ich nicht auf das Dispatcher-Objekt innerhalb von CallbackFunction zugreifen, es tritt ein Fehler auf wie "Eine Objektreferenz wird für nicht-statisches Feld/Methot benötigt". Es sieht aus wie Sackgasse. Vielen Dank. –

+0

@SanjeevKumar Sorry, ich bin kein C# -Programmierer, also habe ich mich geirrt. Sie müssen diese Variable nur im Konstruktor oder in der Methode 'void DemonstrateCallback()' initialisieren, damit sie in der Klasse bleibt und nicht statisch ist. Ich habe meine Antwort bearbeitet und behoben –

+0

Hut ab V. Kravchenko, Sie haben mein Problem gelöst. Es funktioniert perfekt. Ein großes Dankeschön an dich. –