Wm_copydata

Thomasio

Erfahrenes Mitglied
Kennt ihr diese Fehler vom Typ "das kanns ja gar nicht geben?"

Ich habe 2 Fenster, wo eines Daten an das Andere schicken soll.
Für einen ersten Test ganz einfach

Fenster 1:

Code:
COPYDATASTRUCT cd;
char tosend[] = "Test";
cd.dwData = 0;
cd.cbData = sizeof(tosend);
cd.lpData = &tosend;
SendMessage(FindWindow("My2ndWindow",NULL), WM_COPYDATA, (WPARAM)hwnd, (LPARAM)&cd);

Fenster 2:

Code:
case WM_COPYDATA:
{

PCOPYDATASTRUCT cd = (PCOPYDATASTRUCT) lParam;

char * received = (LPSTR)cd->lpData;
MessageBox(NULL,received,"receiving",MB_OK);

return 0;

}
break;

Alles prima, was immer in tosend steht kommt prima in meiner MessageBox an und auch der Absender bekommt die Bestätigung korrekt zurück.
Also statt "Test" jetzt mal echte Daten senden, die hat mein erstes Fenster in einem std::string, den muss ich also kopieren, ganz einfach mit std::copy (dachte ich)

Fenster 1:

Code:
TempString = "Irgendwas";

COPYDATASTRUCT cd;
char tosend[TempString.length()];
std::copy(TempString.begin(),TempString.end(),tosend);
tosend[TempString.length()] = '\0';
cd.dwData = 0;
cd.cbData = sizeof(tosend);
cd.lpData = &tosend;
SendMessage(FindWindow("My2ndWindow",NULL), WM_COPYDATA, (WPARAM)hwnd, (LPARAM)&cd);

Und dann verstehe ich nur noch Bahnhof.
Er sendet immer noch brav den Inhalt von tosend,
aber ausserdem kommen noch zusätzlich ein paar Zeichen Müll an, als ob die \0 hinten im string fehlt oder der string länger geworden ist.

Ich habe mit einem Dutzend MessageBox alles überprüft, aber ich finde den Fehler nicht.
Wenn ich mir vorm senden den Inhalt von tosend ausgeben lasse stimmt alles, auch sizeof(tosend) stimmt, trotzdem geht auf dem Weg zum anderen Fenster irgendwo die \0 verloren, oder sonstwas schief.

Bin ich blind oder doof, oder beides?
 
Hallo,

mich wundert's, das diese Zeile
Code:
char tosend[TempString.length()];
überhaupt kompiliert wird, da für die Festlegung der Arraygröße eigentlich nur konstante Werte erlaubt sind.

Ansonsten brauchst du den std::string nicht unbedingt in ein char-Array kopieren. Versuch's doch mal so:
C++:
COPYDATASTRUCT cd;
cd.cbData = static_cast<DWORD>(TempString.length()) + 1;
cd.lpData = const_cast<char *>((TempString.c_str()));
cd.dwData = 0;
Gruß
MCoder
 
Heissa, das geht, Problem also mal gelöst.

Wenn ich jetzt nur noch verstehen würde, warum meine Version nicht ging.
Ich hatte schon experimentiert mit

const char * tosend = TempString.c_str();

hat aber auch nicht funktioniert.
 
Anschlussfrage, weil ich es schon wieder nicht geregelt bekomme:

Die Funktion CreateThread() bietet genau wie WM_COPYDATA die Möglichkeit als Argument 4 dem Thread einen Pointer auf eine Variable zu übergeben.

Wie sieht der Aufruf von CreateThread() aus, bzw. was kommt an die Stelle der ?

Code:
std::string tosend = "Irgendwas";

HANDLE hThread;
DWORD  dwThreadID;
hThread = CreateThread(NULL,0,ThreadFunc, ? ,0,&dwThreadID);
CloseHandle(hThread);

und wenn wir schon dabei sind, gleich noch die Sicherheitsprobleme:
- wie lange lebt tosend
- kann man den thread mehrfach, mit jeweils anderem Text starten, oder muss man immer warten, bis er durch ist?
 
Deine Version ging nicht, da du die abschliessende Null NACH dem Array reingeschrieben hast (du benutzt TempString.length() als Index, das Array geht aber von 0 bis TempString.length() - 1). Dadurch wird die Null nicht mitgesendet.
Dadurch weiß der Empfänger nicht, wo der String zu Ende war und hat dann alles drangehängt, bis irgendwo im Speicher zufällig eine Null herumgelegen hat.

Denke daran, std::string::length gibt nur die Anzahl der enthaltenen Zeichen an; zählt also die Null hinten dran nicht mit.

Zu 2)
tosend lebt solange, wie der std::string im Scope des aufrufenden Threads bleibt, kann also dem anderen Thread unterm Hintern weggezogen werden.

CreateThread will einen LPVOID, also einen Pointer auf void. Da musst du eigentlich immer casten. Allerdings musst du da aufpassen, du kannst nicht einfach einen Pointer auf etwas temporäres da reinsetzen.

Du kannst nämlich nicht mit Bestimmtheit sagen, dass deine ThreadProc den Pointer noch rechtzeitig zu fassen bekommt, bevor der Pointer im aufrufenden Thread aus dem Scope läuft. Besser entweder etwas immer Greifbares nehmen oder dynamisch alloziieren:

Code:
// durch das New bleibt der std::string auf jeden Fall im Speicher
std::string* pToSend = new std::string( "Irgendwas" );

HANDLE hThread;
DWORD  dwThreadID;
hThread = CreateThread(NULL,0,ThreadFunc, (LPVOID)pToSend ,0,&dwThreadID);
CloseHandle(hThread);

In der Threadproc:
Code:
DWORD ThreadFunc( LPVOID Param )
{

  std::string*  pString = (std::string*)Param;

  // wenn du fertig bist mit dem String
  delete pString;
  return 0;
}

Mit der Variante mit new kannst du den Thread mehrmals aufrufen (musst allerdings auch jedesmal ein eigenes new pro Thread machen).
 
Danke für die ausführliche Antwort.
Allerdings sind mir 2 Dinge nicht ganz klar.

1) Wenn

std::string x = "Test";

dann ist x.length() = 4

Also ergibt

char y[x.length()]

soviel wie

char y[4]

und das sind 5 Zeichen, 0 - 4, also 4 Buchstaben plus \0
Davon abgesehen hatte ich auch length()+1 probiert, geht aber auch nicht.

2) Nur zum Verständnis:
Wenn ich den thread mehrfach starte und jedesmal

std::string* pToSend = new std::string( "Irgendwas" );

mache, wobei "Irgendwas" sich jedesmal ändert, bin ich da noch auf der sicheren Seite, so dass jede Instanz des thread ihr eigenes "Irgendwas" findet?
Vermutlich eine dumme Frage, weil der string ja jedesmal neu erstellt wird, der Pointer also auch bei gleichem Namen immer woanders hin zeigt?
 
Danke für die ausführliche Antwort.
Allerdings sind mir 2 Dinge nicht ganz klar.

1) Wenn

std::string x = "Test";

dann ist x.length() = 4

Also ergibt

char y[x.length()]

soviel wie

char y[4]

und das sind 5 Zeichen, 0 - 4, also 4 Buchstaben plus \0
Nein, das sind 4 Zeichen, 0 - 3. Die 0 passt nicht mehr rein. Mit length() + 1 hätte es eigentlich klappen sollen. Length() + 1 muss aber auch beim Senden verwendet werden.

2) Nur zum Verständnis:
Wenn ich den thread mehrfach starte und jedesmal

std::string* pToSend = new std::string( "Irgendwas" );

mache, wobei "Irgendwas" sich jedesmal ändert, bin ich da noch auf der sicheren Seite, so dass jede Instanz des thread ihr eigenes "Irgendwas" findet?
Vermutlich eine dumme Frage, weil der string ja jedesmal neu erstellt wird, der Pointer also auch bei gleichem Namen immer woanders hin zeigt?

Ganz genau. Es wird jedesmal ein neues Objekt erstellt, mit eigenem Pointer, die haben nichts mehr gemein, können also unabhängig voneinander benutzt werden.
 
Zurück