Page 1 of 1

Cum pot trimite un CString prin PostMessage ?

Posted: 26 Nov 2010, 10:16
by mesajflaviu
Cum se poate trimite un CString prin ::PostMessage(...) ? Si apoi cum se poate "recupera" ? Eu l-am trimis ca lParam , dar nu am reusit sa-l recuperez pentru a-l folosi ...

Nu cred ca are rost sa pun codul pe care l-am incercat eu de vreme ce nu functioneaza ...

Re: Cum pot trimite un CString prin PostMessage ?

Posted: 26 Nov 2010, 10:25
by Marius Bancila
Atentie, PostMessage pune mesajul in coada ferestrei si revine. Apelantul continua ruleze, nu e cu blocare ca la SendMessage. Din aceasta cauza, nu sti cand este tratat mesajul trimis. Probabil tu folosesti o variabila locala, care iese din scop si se distruge inainte ca destinatarul sa trateze mesajul tau. Ar fi mai multe optiuni. Prima ar fi sa folosesti SendMessage, dar asta depinde de ce faci tu exact. Alta optiune e sa folosesti o variabila CString care nu e distrusa in momentul in care se trateaza mesajul; poate fi de exemplu membra a unei clase, stiu eu. Si o a treia ar fi sa aloci variabila CString pe heap, sa pasezi pointerul la ea odata cu PostMessage, iar in handlerul mesajului dupa ce ai folosit-o sa o stergi. Atentie, aici ai o problema daca trimiti acelasi mesaj la mai multe ferestre si fiecare vrea sa stearga acelasi obiect de pe heap.

Re: Cum pot trimite un CString prin PostMessage ?

Posted: 26 Nov 2010, 10:43
by mesajflaviu
Acel mesaj il trimit dintr-un thread , deci nu pot folosi SendMessage ... asta inseamna ca nu am nici o solutie sigura ? ( Ultima solutie propusa de tine are o rezerva )

Re: Cum pot trimite un CString prin PostMessage ?

Posted: 26 Nov 2010, 11:37
by Silviu Ardelean
Cum sa nu poti?
O faci ca si cu PostMessage() si in plus ai avantajul ca sti cand mesajul a fost trata in thread-ul destinatie... spre deosebire de situatia in care folosesti PostMessage(). In threadul curent se opreste executia pana iti vine raspunsul ca s-a tratat mesajul tau.

Re: Cum pot trimite un CString prin PostMessage ?

Posted: 26 Nov 2010, 12:58
by Silviu Ardelean
Iti recomand ideea sa folosesti SendMessage() si alocarea temporara pe heap.

Iata un exemplu:

Code: Select all

// in threadul tau de unde vrei sa trimiti mesajul
CString* sOutMsg = new CString();
*sOutLog = _T("your message");		

pThis->SendMessage(MYMSG_UpdateData,  0, (LPARAM) sOutMsg);	
Iar in threadul principal ai o metoda de tratare a mesajului tau:

Code: Select all

LRESULT CYourMainThreadClass::OnYourMessagehandler(WPARAM wParam, LPARAM lParam)
{
	CString* pobject = (CString*)lParam;

	if(pobject != NULL)
	{
		UpdateData(TRUE);

		m_sData += *pobject;
		m_sData += L" \r\n";
		delete pobject;

		UpdateData(FALSE);
	}
		
	return 0;
}
Daca vrei sa trimiti mesajul intre mai multe thread-uri secundare (nu thread-ul principal) atunci trebuie sa intrii la sincronizari.

Re: Cum pot trimite un CString prin PostMessage ?

Posted: 26 Nov 2010, 14:08
by cristianamarie
mesajflaviu wrote:Cum se poate trimite un CString prin ::PostMessage(...) ? Si apoi cum se poate "recupera" ? Eu l-am trimis ca lParam , dar nu am reusit sa-l recuperez pentru a-l folosi ...

Nu cred ca are rost sa pun codul pe care l-am incercat eu de vreme ce nu functioneaza ...
Nu ai cum sa trimiti nici un pointer direct prin PostMessage.

1. Poti sa il aloci cu un new CString si faci post (dar mai bine LPTSTR alocat decit CString), dar exista riscul sa nu fie procesat si ramine leak.
2. Poti sa il pui intr-o tabela globala de CString, il inserezi, iei indexul, si trimiti indexul in LPARAM in PostMessage. Trebuie sa rezolvi concurenta aici, dar fiind doar insert de unde faci post si read de unde vine mesajul, nu prea sint mari probleme.
3. IPC (dar WM_COPYDATA nu merge cu post, doar send) - ce mecanism vrei tu, dar e o variatiune a punctului 2.

Re: Cum pot trimite un CString prin PostMessage ?

Posted: 27 Nov 2010, 00:23
by Marius Bancila
Nu ai cum sa trimiti nici un pointer direct prin PostMessage.
Ce vrei sa zici? Poti sa trimiti un pointer, dar trebuie sa fie clar ca obiectul pointat nu poate sa fie distrus inaintea tratarii mesajului. Daca conditia asta se indeplineste nu sunt probleme. Altfel da, sigur ca nu merge.

Silviu, in cazul folosirii lui SendMessage nu vad de ce ai mai aloca obiectul CString pe heap, si cu atat mai putin de ce handlerul distruge obiectul, ar putea s-o faca cel care trimite mesajul.

Re: Cum pot trimite un CString prin PostMessage ?

Posted: 27 Nov 2010, 01:00
by Silviu Ardelean
Marius Bancila wrote:Silviu, in cazul folosirii lui SendMessage nu vad de ce ai mai aloca obiectul CString pe heap, si cu atat mai putin de ce handlerul distruge obiectul, ar putea s-o faca cel care trimite mesajul.
Intr-adevar , aceasta abordare se preteaza obligatoriu pentru PostMessage(). Pentru SendMessage() nu mai e neaparat necesara alocarea pe heap.

Re: Cum pot trimite un CString prin PostMessage ?

Posted: 27 Nov 2010, 01:12
by cristianamarie
Marius Bancila wrote:
Nu ai cum sa trimiti nici un pointer direct prin PostMessage.
Ce vrei sa zici? Poti sa trimiti un pointer, dar trebuie sa fie clar ca obiectul pointat nu poate sa fie distrus inaintea tratarii mesajului.
Da, evident. Nu m-am exprimat fericit - normal ca se poate, dar trebuie rezolvate lifetime+owner+access, da.

Re: Cum pot trimite un CString prin PostMessage ?

Posted: 27 Nov 2010, 16:21
by Ovidiu Cucu
  1. Daca mesajul este postat la un singur thread aflat in acelasi proces, de obicei schema aloca si posteaza -> proceseaza si elibereaza, merge fara prea multe batai cap, sincronizari, si alte briz-brizuri; se poate spune: coada de mesaje asigura "sincronizrea".
    La cazul asta ar mai trebui totusi adaugat: string-ul / bufferul este transmis cu o frecventa rezonabila si este procesat intr-un timp rezonabl in asa fel incat sa nu "dea-n foc" :) coada de mesaje.
  2. Daca mesajul este postat la mai multe threaduri, atunci da, trebuie sa ma asigur ca nu se sterge pointerul pasat inainte ca mesajul sa fie procesat in toate thread-urile.
  3. Daca mesajul este pentru un thread din alt proces, atunci Post(Thread)Message sare din schema si trebuie folosita o alta metoda de IPC.

Pun pariu ca probema lui mesajflaviu se incadreaza in cazul 1. :)
Am atasat un exemplu in care se posteaza un pointer la CString din N thread-uri worker la fereastra principala a aplicatiei.
E totusi o mica sincronizare acolo, nu pentru a nu se incurca thread-urile intre ele, ci pentru a a asigura ca fiecare thread isi termina treaba si a evita astfel problema memory leaks de care amintea Cristian.

Re: Cum pot trimite un CString prin PostMessage ?

Posted: 29 Nov 2010, 12:09
by mesajflaviu
Va multumesc tuturor pentru solutii , ( Ovidiu , e didactic exemplul , multumesc ) .
Si eu am rezolvat intr-un mod similar problema :

In thread am :

Code: Select all

CString sTemp = "Unknown error";			
CString* sError = new CString(sTemp);
::PostMessage(m_hwndView,WM_USER_WORK_ERROR,(WPARAM)0,(LPARAM)(LPCSTR)sError);
iar in evenimentul care trateaza mesajul :

Code: Select all

LRESULT CRegistruCoView::OnWorkError(WPARAM wParam, LPARAM lParam)
{
	CString* sError = (CString*)lParam;
	CString& sTemp = *sError;
	GetDocument()->DoSomething(sTemp);
	delete sError;

	return 0;
}

Re: Cum pot trimite un CString prin PostMessage ?

Posted: 29 Nov 2010, 12:52
by Ovidiu Cucu
O mica observatie: acel sTemp n-are nici un rost. Mai mult incurca decat ajuta. ;)

Este suficient:

Code: Select all

   CString* pError = new CString(_T("Unknown error"));
   ::PostMessage(...(LPARAM)pError);
respectiv

Code: Select all

   CString* pError = (CString*)lParam;
   GetDocument()->DoSomething(*pError);
   delete pError;