# Text in Textfeld ausgeben



## CopWorker (21. September 2020)

Hallo zusammen, 

ich habe eine RPC - Schnittstelle für eine IPC (inter process communication) erstellt. 
Dazu habe ich eine RPC Server und einen RPC Client erstellt. 
Der Server sendet an den Client einen Text. Ganz einfach. 
Das funktioniert auch.

Die Methode "ReceiveMessage" ist eine Auszug aus dem RPC Client. 
Beim Erhalt einer Message (Text) möchte ich diesen in einer Textbox in einem Dialog ausgeben. 
Die Klasse in dem die Methode "ReceiveMessage" sitzt besitzt eine Instanz der Dialogklasse in dem der Text ausgegeben werden soll.

Alles noch gut. 
Aber beim Schreiben auf die Textbox wird das Programm nicht weiter ausgeführt. 
Das Schreiben auf die Textbox erfolgt nicht direkt, sondern über eine Methode ".ShowReceiveData(string Message);
Die Aktion führt nicht zu einem Absturz, es scheint irgendwie blockiert zu sein. 

Hier der Auszug des RPC Clients:


```
public int ReceiveMessage(ref string strMsg)
{
    int iRet = 0;
    string strMessage = string.Empty;

    //When a call comes, do the following:
    server.OnExecute += delegate (IRpcClientInfo iclient, byte[] arg)
    {
        strMessage = str.ByteArrayToString(arg);

        using (iclient.Impersonate())
        {
            //Eingehende Meldungen auf Oberfläche
            //clParent.ShowReceivedData(strMessage);

            return new byte[0];
        }
    };

    return iRet;
}
```
Das interface "IRpcClientInfo" stammt aus einer DLL.

Hier die Methode in der auf die Textbox zugegriffen wird:

```
public bool ShowReceivedData(string strMsg)
{
    bool BRet = false;

    tbReceiveMsg.Text = strMsg;
    Application.DoEvents();

    return BRet;
}
```
Der Debugger führt mich bis an die Stelle auf der auf die Textbox geschrieben wird.
tbReceiveMsg.Text = strMsg;
Dann steigt der Debugger aus.

Gibt es in C# so etwas wie C++ wie "SENDMESSAGE("Text");


Vielen Dank.
Grüße von CopWorker


----------



## Spyke (22. September 2020)

Vorweg, das Application.DoEvents rausnehmen.
Sollte man eigentlich nie verwenden, kann auch unschöne Seiteneffekte produzieren.

Und ich vermute mal das die Daten über einen extra Thread kommen und wahrscheinlich das Programm intern wegen einer ThreadException aussteigt.

(SendMessage kann man auch unter C# verwenden (entsprechende Api Funktion muss nur mittels DLLImport deklariert werden), wäre aber in diesem Falle overhead pinvoke.net:             SendMessage (user32))

Probier mal folgendes:

```
if (tbReceiveMsg.InvokeRequired) //Prüfung ob aktuell im Hintergrund Thread läuft
    tbReceiveMsg.Invoke((MethodInvoker)(() => tbReceiveMsg.Text = strMsg)); //verkürzte Schreibweise für einen Methodenaufruf (anonyme Methode), diese Methode wird im UI Thread aufgerufen in der wir wieder normalen Zugriff auf die TextBox haben
else  //läuft nicht in einem Hintergrund Thread, normal setzen
    tbReceiveMsg.Text = strMsg;
```

https://docs.microsoft.com/de-de/do...forms.control.invokerequired?view=netcore-3.1
https://docs.microsoft.com/de-de/dotnet/api/system.windows.forms.control.invoke?view=netcore-3.1
P.S.:
Da es sich um einen unbehandelten Fehler handelt, müsstest du in der Ereignisanzeige von Windows etwas zu deinem Absturz finden.


----------



## CopWorker (22. September 2020)

Hallo Spyke, 

vielen Dank für den Tipp.

Leider besteht das Problem weiterhin. Der Debugger verabschiedet sich an folgender Stelle:

```
tbReceiveMsg.Invoke((MethodInvoker)(() => tbReceiveMsg.Text = strMsg));
```


Ich bin jetzt dran, die eingehenden Nachrichten in eine MessageQueue zu schreiben.

```
public int Write(string strEntry)
{
    int iRet = 0;

    if (liBuffer.Count <= liBuffer.Capacity)
    {
        liBuffer.Add(strEntry);
    }
    else
    {
        iRet = 255; //Buffer overrun
        BOverrun = true;
    }
            
    return iRet;
}
```

Parallel dazu starte ich einen Timer mit einer definierten Intervallzeit. 
Der Timer startet wiederum zyklisch einen Backgroundworker, welcher mit 
den ältesten Wert aus der Queue holt und diesen auf die Textbox im Dialog schreibt.


```
public int Read(ref string strEntry)
{
    int iRet = 0;

    //Information über Anzahl der ungelesenen Einträge als Rückgabe ermitteln
    iRet = liBuffer.Count;

    if (iRet > 0)
    {
        //nach dem ersten Index suchen, diesen auslesen und aus Liste entfernen
        strEntry = liBuffer[0];
        liBuffer.RemoveAt(0);

        if(liBuffer.Count <= liBuffer.Capacity)
            BOverrun = false;
    }
    

    return iRet;
}
```


```
private void tmRecaiveData_Tick(object sender, System.EventArgs e)
{
    //Backgroundworker zum Message Queue auslesen einrichten
    if (!bgwReceiveData.IsBusy)
    {
        bgwReceiveData.RunWorkerAsync();
    }
}
```


```
#region Backgroundworker
private void bgwReceiveData_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
    iCount = 0;

    //Meldungsstapel auslesen
    iCount = clTestCom.ReadMsgQueue(ref strReadedMessage);
}


private void bgwReceiveData_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
    
}


private void bgwReceiveData_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
    if (iCount > 0)
    {
        tbReceiveMsg.Text = string.Format(strMessageConter, iMessageCounter++, strReadedMessage);
    }
}
#endregion
```

Das unschöne liegt nur darin, dass ich nicht weiß wie kurz ich die Intervallzeit einstellen soll um 
das restliche Programm lahmzulegen. 
Ziel ist es, so zeitnah an die Meldungen vom Client ranzukommen als irgendwie möglich.

Grüße von CopWorker


----------



## Spyke (23. September 2020)

Es hat einen Grund warum der Debugger abschmiert.
Was sagt die Ereignisanzeige von Windows?

Und probiert mal folgendes zu setzen in deiner Main Methode der Program.cs um die unbehandelten Fehler abzufangen

```
static int Main(string[] args)
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            Application.ThreadException += new ThreadExceptionEventHandler(Program.Application_ThreadException);
            AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(Program.CurrentDomain_UnhandledException);
```

und dann die unbehandelten Fehler entsprechend Anzeigen/Auswerten

```
private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
        {
            //MessageBox zur Anzeige der Exception und hier mal breakpoint setzen
        }

        private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            if (e.ExceptionObject is Exception exp)
            {
                //MessageBox zur Anzeige der Exception und hier mal breakpoint setzen
            }
        }
```


----------



## CopWorker (2. Oktober 2020)

Hallo Spyke, 

endlich hatte ich mal Zeit dies zu testen.

Aber auch hier keine Änderung. 
Das Programm friert ein. 
Die "CurrentDomain_UnhandledException" und
die "Application_ThreadException" wird nicht angesprungen.

Die Lösung mit der Message Queue funktioniert.

Trotzdem vielen Dank.


Dann habe ich noch ein großes Problem.

Jetzt habe ich 2 C# Programme erzeugt.
Programm A und Programm B stellen jeweils einen Rpc Server und einen Rpc Client zur Verfügung. 
Es ist möglich vom Client (Programm A) zum Server (Programm B) Texte zu senden.
Gleichzeitig ist es auch möglich von Client (Programm B) zum Server (Programm A) Texte zu senden. 
Dies funktioniert auch gleichzeitig. Bestens, nicht geht verloren.

Ich habe noch Programme die in C++ geschrieben sind die ebenfalls Rpc Server und Rpc Clients zur Verfügung stellen. Die Kommunikation funktioniert auch unter diesen Programmen bestens.

Was nicht funktioniert ist folgendes:
Eine Rpc Kommunikation zwischen einem Rpc Client (C++ Programm) und einem Server (C# Programm) und zwischen Rpc Client (C# Programm) und Rpc Server (C++ Programm) funktioniert nicht. 
Die Exception sagen aus, dass die Schnittstelle nicht unbekannt sei. 
Läuft der Rpc Server (C++ Programm) nicht, so wirft der Rpc Client (C# Programm) eine Exception die besagt, "Der RPC-Server ist nicht verfügbar. 
Für mich bedeutet dies, dass sich Server und Client begegnen nur aber die Telegramme nicht auflösen können. 

Die Endpunkte stimmen. Die GUID ist für alle Programme die selbe. 
Das Protokoll ist bei allen (Server, Client) auf "ncacn_ip_tcp" definiert. 
Die Authentifizierung ist bei den Servern auf 
"RPC_C_AUTHN_GSS_NEGOTIATE" und 
"RPC_C_AUTHN_WINNT" erfolgt.

Ich habe keine Ahnung was ich noch machen soll.


Gruß CopWorker


----------



## CopWorker (2. Oktober 2020)

CopWorker hat gesagt.:


> Die Exception sagen aus, dass die Schnittstelle nicht unbekannt sei.


Die Exception sagen aus, dass die Schnittstelle nicht bekannt sei.
So ist´s richtig.


----------



## Spyke (5. Oktober 2020)

Sry mit RPC kenn ich mich nicht aus.
Dafür ev. neuen Thread eröffnen und immer komplette Exception (am besten mit StackTrace) posten.
Es ist nicht nur der inhaltliche Text einer Exception wichtig, manchmal brauch man auch den Exception Typ.
Am besten alles was du mit meineException.ToString() bekommst dann immer rein posten.


----------

