client.c 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425
  1. /* -*- tab-width: 8; c-basic-offset: 4 -*- */
  2. /*
  3. * DDEML library
  4. *
  5. * Copyright 1997 Alexandre Julliard
  6. * Copyright 1997 Len White
  7. * Copyright 1999 Keith Matthews
  8. * Copyright 2000 Corel
  9. * Copyright 2001 Eric Pouech
  10. *
  11. * This library is free software; you can redistribute it and/or
  12. * modify it under the terms of the GNU Lesser General Public
  13. * License as published by the Free Software Foundation; either
  14. * version 2.1 of the License, or (at your option) any later version.
  15. *
  16. * This library is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  19. * Lesser General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU Lesser General Public
  22. * License along with this library; if not, write to the Free Software
  23. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  24. */
  25. #include <stdarg.h>
  26. #include <string.h>
  27. #include "windef.h"
  28. #include "winbase.h"
  29. #include "wingdi.h"
  30. #include "winuser.h"
  31. #include "winerror.h"
  32. #include "winnls.h"
  33. #include "dde.h"
  34. #include "ddeml.h"
  35. #include "win.h"
  36. #include "wine/debug.h"
  37. #include "dde/dde_private.h"
  38. WINE_DEFAULT_DEBUG_CHANNEL(ddeml);
  39. static LRESULT CALLBACK WDML_ClientProc(HWND, UINT, WPARAM, LPARAM); /* only for one client, not conv list */
  40. const char WDML_szClientConvClassA[] = "DdeClientAnsi";
  41. const WCHAR WDML_szClientConvClassW[] = {'D','d','e','C','l','i','e','n','t','U','n','i','c','o','d','e',0};
  42. /******************************************************************************
  43. * DdeConnectList [USER32.@] Establishes conversation with DDE servers
  44. *
  45. * PARAMS
  46. * idInst [I] Instance identifier
  47. * hszService [I] Handle to service name string
  48. * hszTopic [I] Handle to topic name string
  49. * hConvList [I] Handle to conversation list
  50. * pCC [I] Pointer to structure with context data
  51. *
  52. * RETURNS
  53. * Success: Handle to new conversation list
  54. * Failure: 0
  55. */
  56. HCONVLIST WINAPI DdeConnectList(DWORD idInst, HSZ hszService, HSZ hszTopic,
  57. HCONVLIST hConvList, PCONVCONTEXT pCC)
  58. {
  59. FIXME("(%ld,%p,%p,%p,%p): stub\n", idInst, hszService, hszTopic, hConvList, pCC);
  60. return (HCONVLIST)1;
  61. }
  62. /*****************************************************************
  63. * DdeQueryNextServer [USER32.@]
  64. */
  65. HCONV WINAPI DdeQueryNextServer(HCONVLIST hConvList, HCONV hConvPrev)
  66. {
  67. FIXME("(%p,%p): stub\n", hConvList, hConvPrev);
  68. return 0;
  69. }
  70. /******************************************************************************
  71. * DdeDisconnectList [USER32.@] Destroys list and terminates conversations
  72. *
  73. *
  74. * PARAMS
  75. * hConvList [I] Handle to conversation list
  76. *
  77. * RETURNS
  78. * Success: TRUE
  79. * Failure: FALSE
  80. */
  81. BOOL WINAPI DdeDisconnectList(HCONVLIST hConvList)
  82. {
  83. FIXME("(%p): stub\n", hConvList);
  84. return TRUE;
  85. }
  86. /*****************************************************************
  87. * DdeConnect (USER32.@)
  88. */
  89. HCONV WINAPI DdeConnect(DWORD idInst, HSZ hszService, HSZ hszTopic,
  90. PCONVCONTEXT pCC)
  91. {
  92. HWND hwndClient;
  93. WDML_INSTANCE* pInstance;
  94. WDML_CONV* pConv = NULL;
  95. ATOM aSrv = 0, aTpc = 0;
  96. TRACE("(0x%lx,%p,%p,%p)\n", idInst, hszService, hszTopic, pCC);
  97. EnterCriticalSection(&WDML_CritSect);
  98. pInstance = WDML_GetInstance(idInst);
  99. if (!pInstance)
  100. {
  101. goto theEnd;
  102. }
  103. /* make sure this conv is never created */
  104. pConv = WDML_FindConv(pInstance, WDML_CLIENT_SIDE, hszService, hszTopic);
  105. if (pConv != NULL)
  106. {
  107. ERR("This Conv already exists: (%p)\n", pConv);
  108. goto theEnd;
  109. }
  110. /* we need to establish a conversation with
  111. server, so create a window for it */
  112. if (pInstance->unicode)
  113. {
  114. WNDCLASSEXW wndclass;
  115. wndclass.cbSize = sizeof(wndclass);
  116. wndclass.style = 0;
  117. wndclass.lpfnWndProc = WDML_ClientProc;
  118. wndclass.cbClsExtra = 0;
  119. wndclass.cbWndExtra = 2 * sizeof(DWORD);
  120. wndclass.hInstance = 0;
  121. wndclass.hIcon = 0;
  122. wndclass.hCursor = 0;
  123. wndclass.hbrBackground = 0;
  124. wndclass.lpszMenuName = NULL;
  125. wndclass.lpszClassName = WDML_szClientConvClassW;
  126. wndclass.hIconSm = 0;
  127. RegisterClassExW(&wndclass);
  128. hwndClient = CreateWindowW(WDML_szClientConvClassW, NULL, WS_POPUP, 0, 0, 0, 0, 0, 0, 0, 0);
  129. }
  130. else
  131. {
  132. WNDCLASSEXA wndclass;
  133. wndclass.cbSize = sizeof(wndclass);
  134. wndclass.style = 0;
  135. wndclass.lpfnWndProc = WDML_ClientProc;
  136. wndclass.cbClsExtra = 0;
  137. wndclass.cbWndExtra = 2 * sizeof(DWORD);
  138. wndclass.hInstance = 0;
  139. wndclass.hIcon = 0;
  140. wndclass.hCursor = 0;
  141. wndclass.hbrBackground = 0;
  142. wndclass.lpszMenuName = NULL;
  143. wndclass.lpszClassName = WDML_szClientConvClassA;
  144. wndclass.hIconSm = 0;
  145. RegisterClassExA(&wndclass);
  146. hwndClient = CreateWindowA(WDML_szClientConvClassA, NULL, WS_POPUP, 0, 0, 0, 0, 0, 0, 0, 0);
  147. }
  148. SetWindowLongPtrW(hwndClient, GWL_WDML_INSTANCE, (LONG_PTR)pInstance);
  149. if (hszService)
  150. {
  151. aSrv = WDML_MakeAtomFromHsz(hszService);
  152. if (!aSrv) goto theEnd;
  153. }
  154. if (hszTopic)
  155. {
  156. aTpc = WDML_MakeAtomFromHsz(hszTopic);
  157. if (!aTpc) goto theEnd;
  158. }
  159. LeaveCriticalSection(&WDML_CritSect);
  160. /* note: sent messages shall not use packing */
  161. SendMessageTimeoutW( HWND_BROADCAST, WM_DDE_INITIATE, (WPARAM)hwndClient, MAKELPARAM(aSrv, aTpc),
  162. SMTO_ABORTIFHUNG, 2000, NULL );
  163. EnterCriticalSection(&WDML_CritSect);
  164. pInstance = WDML_GetInstance(idInst);
  165. if (!pInstance)
  166. {
  167. goto theEnd;
  168. }
  169. /* At this point, Client WM_DDE_ACK should have saved hwndServer
  170. for this instance id and hwndClient if server responds.
  171. So get HCONV and return it. And add it to conv list */
  172. pConv = WDML_GetConvFromWnd(hwndClient);
  173. if (pConv == NULL || pConv->hwndServer == 0)
  174. {
  175. ERR("Done with INITIATE, but no Server window available\n");
  176. pConv = NULL;
  177. goto theEnd;
  178. }
  179. TRACE("Connected to Server window (%p)\n", pConv->hwndServer);
  180. pConv->wConvst = XST_CONNECTED;
  181. /* finish init of pConv */
  182. if (pCC != NULL)
  183. {
  184. pConv->convContext = *pCC;
  185. }
  186. else
  187. {
  188. memset(&pConv->convContext, 0, sizeof(pConv->convContext));
  189. pConv->convContext.cb = sizeof(pConv->convContext);
  190. pConv->convContext.iCodePage = (pInstance->unicode) ? CP_WINUNICODE : CP_WINANSI;
  191. }
  192. theEnd:
  193. LeaveCriticalSection(&WDML_CritSect);
  194. if (aSrv) GlobalDeleteAtom(aSrv);
  195. if (aTpc) GlobalDeleteAtom(aTpc);
  196. return (HCONV)pConv;
  197. }
  198. /*****************************************************************
  199. * DdeReconnect (DDEML.37)
  200. * DdeReconnect (USER32.@)
  201. */
  202. HCONV WINAPI DdeReconnect(HCONV hConv)
  203. {
  204. WDML_CONV* pConv;
  205. WDML_CONV* pNewConv = NULL;
  206. ATOM aSrv = 0, aTpc = 0;
  207. TRACE("(%p)\n", hConv);
  208. EnterCriticalSection(&WDML_CritSect);
  209. pConv = WDML_GetConv(hConv, FALSE);
  210. if (pConv != NULL && (pConv->wStatus & ST_CLIENT))
  211. {
  212. BOOL ret;
  213. /* to reestablist a connection, we have to make sure that:
  214. * 1/ pConv is the converstation attached to the client window (it wouldn't be
  215. * if a call to DdeReconnect would have already been done...)
  216. * FIXME: is this really an error ???
  217. * 2/ the pConv conversation had really been deconnected
  218. */
  219. if (pConv == WDML_GetConvFromWnd(pConv->hwndClient) &&
  220. (pConv->wStatus & ST_TERMINATED) && !(pConv->wStatus & ST_CONNECTED))
  221. {
  222. HWND hwndClient = pConv->hwndClient;
  223. HWND hwndServer = pConv->hwndServer;
  224. ATOM aSrv, aTpc;
  225. SetWindowLongA(pConv->hwndClient, GWL_WDML_CONVERSATION, 0);
  226. aSrv = WDML_MakeAtomFromHsz(pConv->hszService);
  227. aTpc = WDML_MakeAtomFromHsz(pConv->hszTopic);
  228. if (!aSrv || !aTpc) goto theEnd;
  229. LeaveCriticalSection(&WDML_CritSect);
  230. /* note: sent messages shall not use packing */
  231. ret = SendMessageA(hwndServer, WM_DDE_INITIATE, (WPARAM)hwndClient,
  232. MAKELPARAM(aSrv, aTpc));
  233. EnterCriticalSection(&WDML_CritSect);
  234. pConv = WDML_GetConv(hConv, FALSE);
  235. if (pConv == NULL)
  236. {
  237. FIXME("Should fail reconnection\n");
  238. goto theEnd;
  239. }
  240. if (ret && (pNewConv = WDML_GetConvFromWnd(pConv->hwndClient)) != NULL)
  241. {
  242. /* re-establish all links... */
  243. WDML_LINK* pLink;
  244. for (pLink = pConv->instance->links[WDML_CLIENT_SIDE]; pLink; pLink = pLink->next)
  245. {
  246. if (pLink->hConv == hConv)
  247. {
  248. /* try to reestablish the links... */
  249. DdeClientTransaction(NULL, 0, (HCONV)pNewConv, pLink->hszItem, pLink->uFmt,
  250. pLink->transactionType, 1000, NULL);
  251. }
  252. }
  253. }
  254. else
  255. {
  256. /* reset the conversation as it was */
  257. SetWindowLongA(pConv->hwndClient, GWL_WDML_CONVERSATION, (DWORD)pConv);
  258. }
  259. }
  260. }
  261. theEnd:
  262. LeaveCriticalSection(&WDML_CritSect);
  263. if (aSrv) GlobalDeleteAtom(aSrv);
  264. if (aTpc) GlobalDeleteAtom(aTpc);
  265. return (HCONV)pNewConv;
  266. }
  267. /******************************************************************
  268. * WDML_ClientQueueAdvise
  269. *
  270. * Creates and queue an WM_DDE_ADVISE transaction
  271. */
  272. static WDML_XACT* WDML_ClientQueueAdvise(WDML_CONV* pConv, UINT wType, UINT wFmt, HSZ hszItem)
  273. {
  274. DDEADVISE* pDdeAdvise;
  275. WDML_XACT* pXAct;
  276. ATOM atom;
  277. TRACE("XTYP_ADVSTART (with%s data) transaction\n", (wType & XTYPF_NODATA) ? "out" : "");
  278. atom = WDML_MakeAtomFromHsz(hszItem);
  279. if (!atom) return NULL;
  280. pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_ADVISE, wFmt, hszItem);
  281. if (!pXAct)
  282. {
  283. GlobalDeleteAtom(atom);
  284. return NULL;
  285. }
  286. pXAct->wType = wType & ~0x0F;
  287. pXAct->hMem = GlobalAlloc(GHND | GMEM_DDESHARE, sizeof(DDEADVISE));
  288. /* FIXME: hMem is unfreed for now... should be deleted in server */
  289. /* pack DdeAdvise */
  290. pDdeAdvise = (DDEADVISE*)GlobalLock(pXAct->hMem);
  291. pDdeAdvise->fAckReq = (wType & XTYPF_ACKREQ) ? TRUE : FALSE;
  292. pDdeAdvise->fDeferUpd = (wType & XTYPF_NODATA) ? TRUE : FALSE;
  293. pDdeAdvise->cfFormat = wFmt;
  294. GlobalUnlock(pXAct->hMem);
  295. pXAct->lParam = PackDDElParam(WM_DDE_ADVISE, (UINT_PTR)pXAct->hMem, atom);
  296. return pXAct;
  297. }
  298. /******************************************************************
  299. * WDML_HandleAdviseReply
  300. *
  301. * handles the reply to an advise request
  302. */
  303. static WDML_QUEUE_STATE WDML_HandleAdviseReply(WDML_CONV* pConv, MSG* msg, WDML_XACT* pXAct)
  304. {
  305. DDEACK ddeAck;
  306. UINT_PTR uiLo, uiHi;
  307. HSZ hsz;
  308. if (msg->message != WM_DDE_ACK || WIN_GetFullHandle((HWND)msg->wParam) != pConv->hwndServer)
  309. {
  310. return WDML_QS_PASS;
  311. }
  312. UnpackDDElParam(WM_DDE_ACK, msg->lParam, &uiLo, &uiHi);
  313. hsz = WDML_MakeHszFromAtom(pConv->instance, uiHi);
  314. if (DdeCmpStringHandles(hsz, pXAct->hszItem) != 0)
  315. return WDML_QS_PASS;
  316. GlobalDeleteAtom(uiHi);
  317. FreeDDElParam(WM_DDE_ACK, msg->lParam);
  318. WDML_ExtractAck(uiLo, &ddeAck);
  319. if (ddeAck.fAck)
  320. {
  321. WDML_LINK* pLink;
  322. /* billx: first to see if the link is already created. */
  323. pLink = WDML_FindLink(pConv->instance, (HCONV)pConv, WDML_CLIENT_SIDE,
  324. pXAct->hszItem, TRUE, pXAct->wFmt);
  325. if (pLink != NULL)
  326. {
  327. /* we found a link, and only need to modify it in case it changes */
  328. pLink->transactionType = pXAct->wType;
  329. }
  330. else
  331. {
  332. WDML_AddLink(pConv->instance, (HCONV)pConv, WDML_CLIENT_SIDE,
  333. pXAct->wType, pXAct->hszItem, pXAct->wFmt);
  334. }
  335. pXAct->hDdeData = (HDDEDATA)1;
  336. }
  337. else
  338. {
  339. TRACE("Returning FALSE on XTYP_ADVSTART - fAck was FALSE\n");
  340. GlobalFree(pXAct->hMem);
  341. pXAct->hDdeData = NULL;
  342. }
  343. return WDML_QS_HANDLED;
  344. }
  345. /******************************************************************
  346. * WDML_ClientQueueUnadvise
  347. *
  348. * queues an unadvise transaction
  349. */
  350. static WDML_XACT* WDML_ClientQueueUnadvise(WDML_CONV* pConv, UINT wFmt, HSZ hszItem)
  351. {
  352. WDML_XACT* pXAct;
  353. ATOM atom;
  354. TRACE("XTYP_ADVSTOP transaction\n");
  355. atom = WDML_MakeAtomFromHsz(hszItem);
  356. if (!atom) return NULL;
  357. pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_UNADVISE, wFmt, hszItem);
  358. if (!pXAct)
  359. {
  360. GlobalDeleteAtom(atom);
  361. return NULL;
  362. }
  363. /* end advise loop: post WM_DDE_UNADVISE to server to terminate link
  364. * on the specified item.
  365. */
  366. pXAct->lParam = PackDDElParam(WM_DDE_UNADVISE, wFmt, atom);
  367. return pXAct;
  368. }
  369. /******************************************************************
  370. * WDML_HandleUnadviseReply
  371. *
  372. *
  373. */
  374. static WDML_QUEUE_STATE WDML_HandleUnadviseReply(WDML_CONV* pConv, MSG* msg, WDML_XACT* pXAct)
  375. {
  376. DDEACK ddeAck;
  377. UINT_PTR uiLo, uiHi;
  378. HSZ hsz;
  379. if (msg->message != WM_DDE_ACK || WIN_GetFullHandle((HWND)msg->wParam) != pConv->hwndServer)
  380. {
  381. return WDML_QS_PASS;
  382. }
  383. UnpackDDElParam(WM_DDE_ACK, msg->lParam, &uiLo, &uiHi);
  384. hsz = WDML_MakeHszFromAtom(pConv->instance, uiHi);
  385. if (DdeCmpStringHandles(hsz, pXAct->hszItem) != 0)
  386. return WDML_QS_PASS;
  387. FreeDDElParam(WM_DDE_ACK, msg->lParam);
  388. GlobalDeleteAtom(uiHi);
  389. WDML_ExtractAck(uiLo, &ddeAck);
  390. TRACE("WM_DDE_ACK received while waiting for a timeout\n");
  391. if (!ddeAck.fAck)
  392. {
  393. TRACE("Returning FALSE on XTYP_ADVSTOP - fAck was FALSE\n");
  394. pXAct->hDdeData = NULL;
  395. }
  396. else
  397. {
  398. /* billx: remove the link */
  399. WDML_RemoveLink(pConv->instance, (HCONV)pConv, WDML_CLIENT_SIDE,
  400. pXAct->hszItem, pXAct->wFmt);
  401. pXAct->hDdeData = (HDDEDATA)1;
  402. }
  403. return WDML_QS_HANDLED;
  404. }
  405. /******************************************************************
  406. * WDML_ClientQueueRequest
  407. *
  408. *
  409. */
  410. static WDML_XACT* WDML_ClientQueueRequest(WDML_CONV* pConv, UINT wFmt, HSZ hszItem)
  411. {
  412. WDML_XACT* pXAct;
  413. ATOM atom;
  414. TRACE("XTYP_REQUEST transaction\n");
  415. atom = WDML_MakeAtomFromHsz(hszItem);
  416. if (!atom) return NULL;
  417. pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_REQUEST, wFmt, hszItem);
  418. if (!pXAct)
  419. {
  420. GlobalDeleteAtom(atom);
  421. return NULL;
  422. }
  423. pXAct->lParam = PackDDElParam(WM_DDE_REQUEST, wFmt, atom);
  424. return pXAct;
  425. }
  426. /******************************************************************
  427. * WDML_HandleRequestReply
  428. *
  429. *
  430. */
  431. static WDML_QUEUE_STATE WDML_HandleRequestReply(WDML_CONV* pConv, MSG* msg, WDML_XACT* pXAct)
  432. {
  433. DDEACK ddeAck;
  434. WINE_DDEHEAD wdh;
  435. UINT_PTR uiLo, uiHi;
  436. HSZ hsz;
  437. if (WIN_GetFullHandle((HWND)msg->wParam) != pConv->hwndServer)
  438. return WDML_QS_PASS;
  439. switch (msg->message)
  440. {
  441. case WM_DDE_ACK:
  442. UnpackDDElParam(WM_DDE_ACK, msg->lParam, &uiLo, &uiHi);
  443. FreeDDElParam(WM_DDE_ACK, msg->lParam);
  444. GlobalDeleteAtom(uiHi);
  445. WDML_ExtractAck(uiLo, &ddeAck);
  446. pXAct->hDdeData = 0;
  447. if (ddeAck.fAck)
  448. ERR("Positive answer should appear in NACK for a request, assuming negative\n");
  449. TRACE("Negative answer...\n");
  450. break;
  451. case WM_DDE_DATA:
  452. UnpackDDElParam(WM_DDE_DATA, msg->lParam, &uiLo, &uiHi);
  453. TRACE("Got the result (%08x)\n", uiLo);
  454. hsz = WDML_MakeHszFromAtom(pConv->instance, uiHi);
  455. if (DdeCmpStringHandles(hsz, pXAct->hszItem) != 0)
  456. return WDML_QS_PASS;
  457. pXAct->hDdeData = WDML_Global2DataHandle((HGLOBAL)uiLo, &wdh);
  458. if (wdh.fRelease)
  459. {
  460. GlobalFree((HGLOBAL)uiLo);
  461. }
  462. if (wdh.fAckReq)
  463. {
  464. WDML_PostAck(pConv, WDML_CLIENT_SIDE, 0, FALSE, TRUE, uiHi, msg->lParam, WM_DDE_DATA);
  465. }
  466. else
  467. {
  468. GlobalDeleteAtom(uiHi);
  469. FreeDDElParam(WM_DDE_ACK, msg->lParam);
  470. }
  471. break;
  472. default:
  473. FreeDDElParam(msg->message, msg->lParam);
  474. return WDML_QS_PASS;
  475. }
  476. return WDML_QS_HANDLED;
  477. }
  478. /******************************************************************
  479. * WDML_BuildExecuteCommand
  480. *
  481. * Creates a DDE block suitable for sending in WM_DDE_COMMAND
  482. * It also takes care of string conversion between the two window procedures
  483. */
  484. static HGLOBAL WDML_BuildExecuteCommand(WDML_CONV* pConv, LPCVOID pData, DWORD cbData)
  485. {
  486. HGLOBAL hMem;
  487. BOOL clientUnicode, serverUnicode;
  488. DWORD memSize;
  489. clientUnicode = IsWindowUnicode(pConv->hwndClient);
  490. serverUnicode = IsWindowUnicode(pConv->hwndServer);
  491. if (clientUnicode == serverUnicode)
  492. {
  493. memSize = cbData;
  494. }
  495. else
  496. {
  497. if (clientUnicode)
  498. {
  499. memSize = WideCharToMultiByte( CP_ACP, 0, pData, cbData, NULL, 0, NULL, NULL);
  500. }
  501. else
  502. {
  503. memSize = MultiByteToWideChar( CP_ACP, 0, pData, cbData, NULL, 0) * sizeof(WCHAR);
  504. }
  505. }
  506. hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, memSize);
  507. if (hMem)
  508. {
  509. LPBYTE pDst;
  510. pDst = GlobalLock(hMem);
  511. if (pDst)
  512. {
  513. if (clientUnicode == serverUnicode)
  514. {
  515. memcpy(pDst, pData, cbData);
  516. }
  517. else
  518. {
  519. if (clientUnicode)
  520. {
  521. WideCharToMultiByte( CP_ACP, 0, pData, cbData, pDst, memSize, NULL, NULL);
  522. }
  523. else
  524. {
  525. MultiByteToWideChar( CP_ACP, 0, pData, cbData, (LPWSTR)pDst, memSize/sizeof(WCHAR));
  526. }
  527. }
  528. GlobalUnlock(hMem);
  529. }
  530. else
  531. {
  532. GlobalFree(hMem);
  533. hMem = 0;
  534. }
  535. }
  536. return hMem;
  537. }
  538. /******************************************************************
  539. * WDML_ClientQueueExecute
  540. *
  541. *
  542. */
  543. static WDML_XACT* WDML_ClientQueueExecute(WDML_CONV* pConv, LPCVOID pData, DWORD cbData)
  544. {
  545. WDML_XACT* pXAct;
  546. TRACE("XTYP_EXECUTE transaction\n");
  547. pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_EXECUTE, 0, 0);
  548. if (!pXAct)
  549. return NULL;
  550. if (cbData == (DWORD)-1)
  551. {
  552. HDDEDATA hDdeData = (HDDEDATA)pData;
  553. pData = DdeAccessData(hDdeData, &cbData);
  554. if (pData)
  555. {
  556. pXAct->hMem = WDML_BuildExecuteCommand(pConv, pData, cbData);
  557. DdeUnaccessData(hDdeData);
  558. }
  559. }
  560. else
  561. {
  562. pXAct->hMem = WDML_BuildExecuteCommand(pConv, pData, cbData);
  563. }
  564. pXAct->lParam = (LPARAM)pXAct->hMem;
  565. return pXAct;
  566. }
  567. /******************************************************************
  568. * WDML_HandleExecuteReply
  569. *
  570. *
  571. */
  572. static WDML_QUEUE_STATE WDML_HandleExecuteReply(WDML_CONV* pConv, MSG* msg, WDML_XACT* pXAct)
  573. {
  574. DDEACK ddeAck;
  575. UINT_PTR uiLo, uiHi;
  576. if (msg->message != WM_DDE_ACK || WIN_GetFullHandle((HWND)msg->wParam) != pConv->hwndServer)
  577. {
  578. return WDML_QS_PASS;
  579. }
  580. UnpackDDElParam(WM_DDE_ACK, msg->lParam, &uiLo, &uiHi);
  581. FreeDDElParam(WM_DDE_ACK, msg->lParam);
  582. if ((HANDLE)uiHi != pXAct->hMem)
  583. {
  584. return WDML_QS_PASS;
  585. }
  586. WDML_ExtractAck(uiLo, &ddeAck);
  587. pXAct->hDdeData = (HDDEDATA)(UINT_PTR)ddeAck.fAck;
  588. TRACE("hDdeData = %p\n", pXAct->hDdeData);
  589. pConv->instance->lastError = (pXAct->hDdeData != 0) ? DMLERR_NO_ERROR : DMLERR_NOTPROCESSED;
  590. return WDML_QS_HANDLED;
  591. }
  592. /******************************************************************
  593. * WDML_ClientQueuePoke
  594. *
  595. *
  596. */
  597. static WDML_XACT* WDML_ClientQueuePoke(WDML_CONV* pConv, LPCVOID pData, DWORD cbData,
  598. UINT wFmt, HSZ hszItem)
  599. {
  600. WDML_XACT* pXAct;
  601. ATOM atom;
  602. TRACE("XTYP_POKE transaction\n");
  603. atom = WDML_MakeAtomFromHsz(hszItem);
  604. if (!atom) return NULL;
  605. pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_POKE, wFmt, hszItem);
  606. if (!pXAct)
  607. {
  608. GlobalDeleteAtom(atom);
  609. return NULL;
  610. }
  611. if (cbData == (DWORD)-1)
  612. {
  613. pXAct->hMem = (HDDEDATA)pData;
  614. }
  615. else
  616. {
  617. DDEPOKE* ddePoke;
  618. pXAct->hMem = GlobalAlloc(GHND | GMEM_DDESHARE, sizeof(DDEPOKE) + cbData);
  619. ddePoke = GlobalLock(pXAct->hMem);
  620. if (ddePoke)
  621. {
  622. memcpy(ddePoke->Value, pData, cbData);
  623. ddePoke->fRelease = FALSE; /* FIXME: app owned ? */
  624. ddePoke->cfFormat = wFmt;
  625. GlobalUnlock(pXAct->hMem);
  626. }
  627. }
  628. pXAct->lParam = PackDDElParam(WM_DDE_POKE, (UINT_PTR)pXAct->hMem, atom);
  629. return pXAct;
  630. }
  631. /******************************************************************
  632. * WDML_HandlePokeReply
  633. *
  634. *
  635. */
  636. static WDML_QUEUE_STATE WDML_HandlePokeReply(WDML_CONV* pConv, MSG* msg, WDML_XACT* pXAct)
  637. {
  638. DDEACK ddeAck;
  639. UINT_PTR uiLo, uiHi;
  640. HSZ hsz;
  641. if (msg->message != WM_DDE_ACK && WIN_GetFullHandle((HWND)msg->wParam) != pConv->hwndServer)
  642. {
  643. return WDML_QS_PASS;
  644. }
  645. UnpackDDElParam(WM_DDE_ACK, msg->lParam, &uiLo, &uiHi);
  646. hsz = WDML_MakeHszFromAtom(pConv->instance, uiHi);
  647. if (DdeCmpStringHandles(hsz, pXAct->hszItem) != 0)
  648. {
  649. return WDML_QS_PASS;
  650. }
  651. FreeDDElParam(WM_DDE_ACK, msg->lParam);
  652. GlobalDeleteAtom(uiHi);
  653. WDML_ExtractAck(uiLo, &ddeAck);
  654. GlobalFree(pXAct->hMem);
  655. pXAct->hDdeData = (HDDEDATA)TRUE;
  656. return TRUE;
  657. }
  658. /******************************************************************
  659. * WDML_ClientQueueTerminate
  660. *
  661. * Creates and queue an WM_DDE_TERMINATE transaction
  662. */
  663. static WDML_XACT* WDML_ClientQueueTerminate(WDML_CONV* pConv)
  664. {
  665. WDML_XACT* pXAct;
  666. pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_TERMINATE, 0, 0);
  667. if (!pXAct)
  668. return NULL;
  669. pXAct->lParam = 0;
  670. pConv->wStatus &= ~ST_CONNECTED;
  671. return pXAct;
  672. }
  673. /******************************************************************
  674. * WDML_HandleTerminateReply
  675. *
  676. * handles the reply to a terminate request
  677. */
  678. static WDML_QUEUE_STATE WDML_HandleTerminateReply(WDML_CONV* pConv, MSG* msg, WDML_XACT* pXAct)
  679. {
  680. if (msg->message != WM_DDE_TERMINATE)
  681. {
  682. /* FIXME: should delete data passed here */
  683. return WDML_QS_SWALLOWED;
  684. }
  685. if (WIN_GetFullHandle((HWND)msg->wParam) != pConv->hwndServer)
  686. {
  687. FIXME("hmmm shouldn't happen\n");
  688. return WDML_QS_PASS;
  689. }
  690. if (!pConv->instance->CBFflags & CBF_SKIP_DISCONNECTS)
  691. {
  692. WDML_InvokeCallback(pConv->instance, XTYP_DISCONNECT, 0, (HCONV)pConv,
  693. 0, 0, 0, 0, (pConv->wStatus & ST_ISSELF) ? 1 : 0);
  694. }
  695. WDML_RemoveConv(pConv, WDML_CLIENT_SIDE);
  696. return WDML_QS_HANDLED;
  697. }
  698. /******************************************************************
  699. * WDML_HandleReplyData
  700. *
  701. *
  702. */
  703. static WDML_QUEUE_STATE WDML_HandleIncomingData(WDML_CONV* pConv, MSG* msg, HDDEDATA* hdd)
  704. {
  705. UINT_PTR uiLo, uiHi;
  706. HDDEDATA hDdeDataIn, hDdeDataOut;
  707. WDML_LINK* pLink;
  708. WINE_DDEHEAD wdh;
  709. HSZ hsz;
  710. TRACE("WM_DDE_DATA message received in the Client Proc!\n");
  711. /* wParam -- sending window handle */
  712. /* lParam -- hDdeData & item HSZ */
  713. UnpackDDElParam(WM_DDE_DATA, msg->lParam, &uiLo, &uiHi);
  714. hsz = WDML_MakeHszFromAtom(pConv->instance, uiHi);
  715. hDdeDataIn = WDML_Global2DataHandle((HGLOBAL)uiLo, &wdh);
  716. /* billx:
  717. * For hot link, data should be passed to its callback with
  718. * XTYP_ADVDATA and callback should return the proper status.
  719. */
  720. pLink = WDML_FindLink(pConv->instance, (HCONV)pConv, WDML_CLIENT_SIDE, hsz,
  721. uiLo ? TRUE : FALSE, wdh.cfFormat);
  722. if (!pLink)
  723. {
  724. WDML_DecHSZ(pConv->instance, hsz);
  725. DdeFreeDataHandle(hDdeDataIn);
  726. return WDML_QS_PASS;
  727. }
  728. if (hDdeDataIn != 0 && wdh.fAckReq)
  729. {
  730. WDML_PostAck(pConv, WDML_CLIENT_SIDE, 0, FALSE, TRUE, uiHi, msg->lParam, WM_DDE_DATA);
  731. if (msg->lParam)
  732. msg->lParam = 0;
  733. }
  734. else
  735. {
  736. GlobalDeleteAtom(uiHi);
  737. }
  738. hDdeDataOut = WDML_InvokeCallback(pConv->instance, XTYP_ADVDATA, pLink->uFmt, pLink->hConv,
  739. pConv->hszTopic, pLink->hszItem, hDdeDataIn, 0, 0);
  740. if (hDdeDataOut != (HDDEDATA)DDE_FACK || wdh.fRelease)
  741. {
  742. if (uiLo) GlobalFree((HANDLE)uiLo);
  743. }
  744. DdeFreeDataHandle(hDdeDataIn);
  745. WDML_DecHSZ(pConv->instance, hsz);
  746. if (msg->lParam)
  747. FreeDDElParam(WM_DDE_DATA, msg->lParam);
  748. return WDML_QS_HANDLED;
  749. }
  750. /******************************************************************
  751. * WDML_HandleIncomingTerminate
  752. *
  753. *
  754. */
  755. static WDML_QUEUE_STATE WDML_HandleIncomingTerminate(WDML_CONV* pConv, MSG* msg, HDDEDATA* hdd)
  756. {
  757. if (pConv->hwndServer != WIN_GetFullHandle((HWND)msg->wParam))
  758. return WDML_QS_PASS;
  759. pConv->wStatus |= ST_TERMINATED;
  760. if (!pConv->instance->CBFflags & CBF_SKIP_DISCONNECTS)
  761. {
  762. WDML_InvokeCallback(pConv->instance, XTYP_DISCONNECT, 0, (HCONV)pConv,
  763. 0, 0, 0, 0, (pConv->wStatus & ST_ISSELF) ? 1 : 0);
  764. }
  765. if (pConv->wStatus & ST_CONNECTED)
  766. {
  767. /* don't care about result code (if server exists or not) */
  768. PostMessageA(pConv->hwndServer, WM_DDE_TERMINATE, (WPARAM)pConv->hwndClient, 0L);
  769. pConv->wStatus &= ~ST_CONNECTED;
  770. }
  771. /* have to keep connection around to allow reconnection */
  772. return WDML_QS_HANDLED;
  773. }
  774. /******************************************************************
  775. * WDML_HandleReply
  776. *
  777. * handles any incoming reply, and try to match to an already sent request
  778. */
  779. static WDML_QUEUE_STATE WDML_HandleReply(WDML_CONV* pConv, MSG* msg, HDDEDATA* hdd)
  780. {
  781. WDML_XACT* pXAct = pConv->transactions;
  782. WDML_QUEUE_STATE qs;
  783. if (pConv->transactions)
  784. {
  785. /* first check message against a pending transaction, if any */
  786. switch (pXAct->ddeMsg)
  787. {
  788. case WM_DDE_ADVISE:
  789. qs = WDML_HandleAdviseReply(pConv, msg, pXAct);
  790. break;
  791. case WM_DDE_UNADVISE:
  792. qs = WDML_HandleUnadviseReply(pConv, msg, pXAct);
  793. break;
  794. case WM_DDE_EXECUTE:
  795. qs = WDML_HandleExecuteReply(pConv, msg, pXAct);
  796. break;
  797. case WM_DDE_REQUEST:
  798. qs = WDML_HandleRequestReply(pConv, msg, pXAct);
  799. break;
  800. case WM_DDE_POKE:
  801. qs = WDML_HandlePokeReply(pConv, msg, pXAct);
  802. break;
  803. case WM_DDE_TERMINATE:
  804. qs = WDML_HandleTerminateReply(pConv, msg, pXAct);
  805. break;
  806. default:
  807. qs = WDML_QS_ERROR;
  808. FIXME("oooch\n");
  809. }
  810. }
  811. else
  812. {
  813. qs = WDML_QS_PASS;
  814. }
  815. /* now check the results */
  816. switch (qs)
  817. {
  818. case WDML_QS_ERROR:
  819. case WDML_QS_SWALLOWED:
  820. *hdd = 0;
  821. break;
  822. case WDML_QS_HANDLED:
  823. /* ok, we have resolved a pending transaction
  824. * notify callback if asynchronous, and remove it in any case
  825. */
  826. WDML_UnQueueTransaction(pConv, pXAct);
  827. if (pXAct->dwTimeout == TIMEOUT_ASYNC && pXAct->ddeMsg != WM_DDE_TERMINATE)
  828. {
  829. WDML_InvokeCallback(pConv->instance, XTYP_XACT_COMPLETE, pXAct->wFmt,
  830. (HCONV)pConv, pConv->hszTopic, pXAct->hszItem,
  831. pXAct->hDdeData, MAKELONG(0, pXAct->xActID), 0 /* FIXME */);
  832. qs = WDML_QS_PASS;
  833. }
  834. else
  835. {
  836. *hdd = pXAct->hDdeData;
  837. }
  838. WDML_FreeTransaction(pConv->instance, pXAct, TRUE);
  839. break;
  840. case WDML_QS_PASS:
  841. /* no pending transaction found, try a warm/hot link or a termination request */
  842. switch (msg->message)
  843. {
  844. case WM_DDE_DATA:
  845. qs = WDML_HandleIncomingData(pConv, msg, hdd);
  846. break;
  847. case WM_DDE_TERMINATE:
  848. qs = WDML_HandleIncomingTerminate(pConv, msg, hdd);
  849. break;
  850. }
  851. break;
  852. case WDML_QS_BLOCK:
  853. FIXME("shouldn't be used on client side\n");
  854. break;
  855. }
  856. return qs;
  857. }
  858. /******************************************************************
  859. * WDML_SyncWaitTransactionReply
  860. *
  861. * waits until an answer for a sent request is received
  862. * time out is also handled. only used for synchronous transactions
  863. */
  864. static HDDEDATA WDML_SyncWaitTransactionReply(HCONV hConv, DWORD dwTimeout, WDML_XACT* pXAct)
  865. {
  866. DWORD dwTime;
  867. DWORD err;
  868. WDML_CONV* pConv;
  869. TRACE("Starting wait for a timeout of %ld ms\n", dwTimeout);
  870. /* FIXME: time 32 bit wrap around */
  871. dwTimeout += GetCurrentTime();
  872. while ((dwTime = GetCurrentTime()) < dwTimeout)
  873. {
  874. /* we cannot be in the crit sect all the time because when client and server run in a
  875. * single process they need to share the access to the internal data
  876. */
  877. if (MsgWaitForMultipleObjects(0, NULL, FALSE,
  878. dwTimeout - dwTime, QS_POSTMESSAGE) == WAIT_OBJECT_0)
  879. {
  880. BOOL ret = FALSE;
  881. MSG msg;
  882. WDML_CONV* pConv;
  883. HDDEDATA hdd;
  884. EnterCriticalSection(&WDML_CritSect);
  885. pConv = WDML_GetConv(hConv, FALSE);
  886. if (pConv == NULL)
  887. {
  888. LeaveCriticalSection(&WDML_CritSect);
  889. /* conversation no longer available... return failure */
  890. break;
  891. }
  892. while (PeekMessageA(&msg, pConv->hwndClient, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE))
  893. {
  894. /* check that either pXAct has been processed or no more xActions are pending */
  895. ret = (pConv->transactions == pXAct);
  896. ret = WDML_HandleReply(pConv, &msg, &hdd) == WDML_QS_HANDLED &&
  897. (pConv->transactions == NULL || ret);
  898. if (ret) break;
  899. }
  900. LeaveCriticalSection(&WDML_CritSect);
  901. if (ret)
  902. {
  903. return hdd;
  904. }
  905. }
  906. }
  907. TRACE("Timeout !!\n");
  908. EnterCriticalSection(&WDML_CritSect);
  909. pConv = WDML_GetConv(hConv, FALSE);
  910. if (pConv != NULL)
  911. {
  912. if (pConv->transactions)
  913. {
  914. switch (pConv->transactions->ddeMsg)
  915. {
  916. case WM_DDE_ADVISE: err = DMLERR_ADVACKTIMEOUT; break;
  917. case WM_DDE_REQUEST: err = DMLERR_DATAACKTIMEOUT; break;
  918. case WM_DDE_EXECUTE: err = DMLERR_EXECACKTIMEOUT; break;
  919. case WM_DDE_POKE: err = DMLERR_POKEACKTIMEOUT; break;
  920. case WM_DDE_UNADVISE: err = DMLERR_UNADVACKTIMEOUT; break;
  921. default: err = DMLERR_INVALIDPARAMETER; break;
  922. }
  923. pConv->instance->lastError = err;
  924. }
  925. }
  926. LeaveCriticalSection(&WDML_CritSect);
  927. return 0;
  928. }
  929. /*****************************************************************
  930. * DdeClientTransaction (USER32.@)
  931. */
  932. HDDEDATA WINAPI DdeClientTransaction(LPBYTE pData, DWORD cbData, HCONV hConv, HSZ hszItem, UINT wFmt,
  933. UINT wType, DWORD dwTimeout, LPDWORD pdwResult)
  934. {
  935. WDML_CONV* pConv;
  936. WDML_XACT* pXAct;
  937. HDDEDATA hDdeData = 0;
  938. TRACE("(%p,%ld,%p,%p,%x,%x,%ld,%p)\n",
  939. pData, cbData, hConv, hszItem, wFmt, wType, dwTimeout, pdwResult);
  940. if (hConv == 0)
  941. {
  942. ERR("Invalid conversation handle\n");
  943. return 0;
  944. }
  945. EnterCriticalSection(&WDML_CritSect);
  946. pConv = WDML_GetConv(hConv, TRUE);
  947. if (pConv == NULL)
  948. {
  949. /* cannot set error... cannot get back to DDE instance */
  950. goto theError;
  951. }
  952. switch (wType)
  953. {
  954. case XTYP_EXECUTE:
  955. if (hszItem != 0 || wFmt != 0)
  956. {
  957. pConv->instance->lastError = DMLERR_INVALIDPARAMETER;
  958. goto theError;
  959. }
  960. pXAct = WDML_ClientQueueExecute(pConv, pData, cbData);
  961. break;
  962. case XTYP_POKE:
  963. pXAct = WDML_ClientQueuePoke(pConv, pData, cbData, wFmt, hszItem);
  964. break;
  965. case XTYP_ADVSTART|XTYPF_NODATA:
  966. case XTYP_ADVSTART|XTYPF_NODATA|XTYPF_ACKREQ:
  967. case XTYP_ADVSTART:
  968. case XTYP_ADVSTART|XTYPF_ACKREQ:
  969. if (pData)
  970. {
  971. pConv->instance->lastError = DMLERR_INVALIDPARAMETER;
  972. goto theError;
  973. }
  974. pXAct = WDML_ClientQueueAdvise(pConv, wType, wFmt, hszItem);
  975. break;
  976. case XTYP_ADVSTOP:
  977. if (pData)
  978. {
  979. pConv->instance->lastError = DMLERR_INVALIDPARAMETER;
  980. goto theError;
  981. }
  982. pXAct = WDML_ClientQueueUnadvise(pConv, wFmt, hszItem);
  983. break;
  984. case XTYP_REQUEST:
  985. if (pData)
  986. {
  987. pConv->instance->lastError = DMLERR_INVALIDPARAMETER;
  988. goto theError;
  989. }
  990. pXAct = WDML_ClientQueueRequest(pConv, wFmt, hszItem);
  991. break;
  992. default:
  993. FIXME("Unknown transation\n");
  994. /* unknown transaction type */
  995. pConv->instance->lastError = DMLERR_INVALIDPARAMETER;
  996. goto theError;
  997. }
  998. if (pXAct == NULL)
  999. {
  1000. pConv->instance->lastError = DMLERR_MEMORY_ERROR;
  1001. goto theError;
  1002. }
  1003. WDML_QueueTransaction(pConv, pXAct);
  1004. if (!PostMessageA(pConv->hwndServer, pXAct->ddeMsg, (WPARAM)pConv->hwndClient, pXAct->lParam))
  1005. {
  1006. WARN("Failed posting message %x to %p (error=0x%lx)\n",
  1007. pXAct->ddeMsg, pConv->hwndServer, GetLastError());
  1008. pConv->wStatus &= ~ST_CONNECTED;
  1009. WDML_UnQueueTransaction(pConv, pXAct);
  1010. WDML_FreeTransaction(pConv->instance, pXAct, TRUE);
  1011. goto theError;
  1012. }
  1013. pXAct->dwTimeout = dwTimeout;
  1014. /* FIXME: should set the app bits on *pdwResult */
  1015. if (dwTimeout == TIMEOUT_ASYNC)
  1016. {
  1017. if (pdwResult)
  1018. {
  1019. *pdwResult = MAKELONG(0, pXAct->xActID);
  1020. }
  1021. hDdeData = (HDDEDATA)1;
  1022. }
  1023. else
  1024. {
  1025. DWORD count, i;
  1026. if (pdwResult)
  1027. {
  1028. *pdwResult = 0L;
  1029. }
  1030. count = WDML_CritSect.RecursionCount;
  1031. for (i = 0; i < count; i++)
  1032. LeaveCriticalSection(&WDML_CritSect);
  1033. hDdeData = WDML_SyncWaitTransactionReply((HCONV)pConv, dwTimeout, pXAct);
  1034. for (i = 0; i < count; i++)
  1035. EnterCriticalSection(&WDML_CritSect);
  1036. }
  1037. LeaveCriticalSection(&WDML_CritSect);
  1038. return hDdeData;
  1039. theError:
  1040. LeaveCriticalSection(&WDML_CritSect);
  1041. return 0;
  1042. }
  1043. /*****************************************************************
  1044. * DdeAbandonTransaction (USER32.@)
  1045. */
  1046. BOOL WINAPI DdeAbandonTransaction(DWORD idInst, HCONV hConv, DWORD idTransaction)
  1047. {
  1048. WDML_INSTANCE* pInstance;
  1049. WDML_CONV* pConv;
  1050. WDML_XACT* pXAct;
  1051. TRACE("(%08lx,%p,%08ld);\n", idInst, hConv, idTransaction);
  1052. EnterCriticalSection(&WDML_CritSect);
  1053. if ((pInstance = WDML_GetInstance(idInst)))
  1054. {
  1055. if (hConv)
  1056. {
  1057. if ((pConv = WDML_GetConv(hConv, TRUE)) && pConv->instance == pInstance)
  1058. {
  1059. for (pXAct = pConv->transactions; pXAct; pXAct = pXAct->next)
  1060. {
  1061. if (pXAct->dwTimeout == TIMEOUT_ASYNC &&
  1062. (idTransaction == 0 || pXAct->xActID == idTransaction))
  1063. {
  1064. WDML_UnQueueTransaction(pConv, pXAct);
  1065. WDML_FreeTransaction(pInstance, pXAct, TRUE);
  1066. }
  1067. }
  1068. }
  1069. }
  1070. else
  1071. {
  1072. for (pConv = pInstance->convs[WDML_CLIENT_SIDE]; pConv; pConv = pConv->next)
  1073. {
  1074. if (!(pConv->wStatus & ST_CONNECTED)) continue;
  1075. for (pXAct = pConv->transactions; pXAct; pXAct = pXAct->next)
  1076. {
  1077. if (pXAct->dwTimeout == TIMEOUT_ASYNC)
  1078. {
  1079. WDML_UnQueueTransaction(pConv, pXAct);
  1080. WDML_FreeTransaction(pInstance, pXAct, TRUE);
  1081. }
  1082. }
  1083. }
  1084. }
  1085. }
  1086. LeaveCriticalSection(&WDML_CritSect);
  1087. return TRUE;
  1088. }
  1089. /******************************************************************
  1090. * WDML_ClientProc
  1091. *
  1092. * Window Proc created on client side for each conversation
  1093. */
  1094. static LRESULT CALLBACK WDML_ClientProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
  1095. {
  1096. UINT uiLo, uiHi;
  1097. WDML_CONV* pConv = NULL;
  1098. HSZ hszSrv, hszTpc;
  1099. TRACE("%p %04x %08x %08lx\n", hwnd, iMsg, wParam , lParam);
  1100. if (iMsg == WM_DDE_ACK &&
  1101. /* in the initial WM_INITIATE sendmessage */
  1102. ((pConv = WDML_GetConvFromWnd(hwnd)) == NULL || pConv->wStatus == XST_INIT1))
  1103. {
  1104. /* In response to WM_DDE_INITIATE, save server window */
  1105. char buf[256];
  1106. WDML_INSTANCE* pInstance;
  1107. /* note: sent messages do not need packing */
  1108. uiLo = LOWORD(lParam);
  1109. uiHi = HIWORD(lParam);
  1110. /* FIXME: convlist should be handled here */
  1111. if (pConv)
  1112. {
  1113. /* we already have started the conv with a server, drop other replies */
  1114. GlobalDeleteAtom(uiLo);
  1115. GlobalDeleteAtom(uiHi);
  1116. PostMessageA((HWND)wParam, WM_DDE_TERMINATE, (WPARAM)hwnd, 0);
  1117. return 0;
  1118. }
  1119. pInstance = WDML_GetInstanceFromWnd(hwnd);
  1120. hszSrv = WDML_MakeHszFromAtom(pInstance, uiLo);
  1121. hszTpc = WDML_MakeHszFromAtom(pInstance, uiHi);
  1122. pConv = WDML_AddConv(pInstance, WDML_CLIENT_SIDE, hszSrv, hszTpc, hwnd, (HWND)wParam);
  1123. SetWindowLongA(hwnd, GWL_WDML_CONVERSATION, (DWORD)pConv);
  1124. pConv->wStatus |= ST_CONNECTED;
  1125. pConv->wConvst = XST_INIT1;
  1126. /* check if server is handled by DDEML */
  1127. if ((GetClassNameA((HWND)wParam, buf, sizeof(buf)) &&
  1128. strcmp(buf, WDML_szServerConvClassA) == 0) ||
  1129. (GetClassNameW((HWND)wParam, (LPWSTR)buf, sizeof(buf)/sizeof(WCHAR)) &&
  1130. lstrcmpW((LPWSTR)buf, WDML_szServerConvClassW) == 0))
  1131. {
  1132. pConv->wStatus |= ST_ISLOCAL;
  1133. }
  1134. WDML_BroadcastDDEWindows(WDML_szEventClass, WM_WDML_CONNECT_CONFIRM, (WPARAM)hwnd, wParam);
  1135. GlobalDeleteAtom(uiLo);
  1136. GlobalDeleteAtom(uiHi);
  1137. /* accept conversation */
  1138. return 1;
  1139. }
  1140. if (iMsg >= WM_DDE_FIRST && iMsg <= WM_DDE_LAST)
  1141. {
  1142. EnterCriticalSection(&WDML_CritSect);
  1143. pConv = WDML_GetConvFromWnd(hwnd);
  1144. if (pConv)
  1145. {
  1146. MSG msg;
  1147. HDDEDATA hdd;
  1148. msg.hwnd = hwnd;
  1149. msg.message = iMsg;
  1150. msg.wParam = wParam;
  1151. msg.lParam = lParam;
  1152. WDML_HandleReply(pConv, &msg, &hdd);
  1153. }
  1154. LeaveCriticalSection(&WDML_CritSect);
  1155. return 0;
  1156. }
  1157. return (IsWindowUnicode(hwnd)) ?
  1158. DefWindowProcW(hwnd, iMsg, wParam, lParam) : DefWindowProcA(hwnd, iMsg, wParam, lParam);
  1159. }
  1160. /*****************************************************************
  1161. * DdeDisconnect (USER32.@)
  1162. */
  1163. BOOL WINAPI DdeDisconnect(HCONV hConv)
  1164. {
  1165. WDML_CONV* pConv = NULL;
  1166. WDML_XACT* pXAct;
  1167. DWORD count, i;
  1168. BOOL ret = FALSE;
  1169. TRACE("(%p)\n", hConv);
  1170. if (hConv == 0)
  1171. {
  1172. ERR("DdeDisconnect(): hConv = 0\n");
  1173. return FALSE;
  1174. }
  1175. EnterCriticalSection(&WDML_CritSect);
  1176. pConv = WDML_GetConv(hConv, TRUE);
  1177. if (pConv != NULL)
  1178. {
  1179. if (pConv->wStatus & ST_CLIENT)
  1180. {
  1181. /* FIXME: should abandon all pending transactions */
  1182. pXAct = WDML_ClientQueueTerminate(pConv);
  1183. if (pXAct != NULL)
  1184. {
  1185. count = WDML_CritSect.RecursionCount;
  1186. for (i = 0; i < count; i++)
  1187. LeaveCriticalSection(&WDML_CritSect);
  1188. if (PostMessageA(pConv->hwndServer, pXAct->ddeMsg,
  1189. (WPARAM)pConv->hwndClient, pXAct->lParam))
  1190. WDML_SyncWaitTransactionReply(hConv, 10000, pXAct);
  1191. for (i = 0; i < count; i++)
  1192. EnterCriticalSection(&WDML_CritSect);
  1193. ret = TRUE;
  1194. WDML_FreeTransaction(pConv->instance, pXAct, TRUE);
  1195. /* still have to destroy data assosiated with conversation */
  1196. WDML_RemoveConv(pConv, WDML_CLIENT_SIDE);
  1197. }
  1198. else
  1199. {
  1200. FIXME("Not implemented yet for a server side conversation\n");
  1201. }
  1202. }
  1203. }
  1204. LeaveCriticalSection(&WDML_CritSect);
  1205. return ret;
  1206. }
  1207. /*****************************************************************
  1208. * DdeImpersonateClient (USER32.@)
  1209. */
  1210. BOOL WINAPI DdeImpersonateClient(HCONV hConv)
  1211. {
  1212. WDML_CONV* pConv;
  1213. BOOL ret = FALSE;
  1214. TRACE("(%p)\n", hConv);
  1215. EnterCriticalSection(&WDML_CritSect);
  1216. pConv = WDML_GetConv(hConv, TRUE);
  1217. if (pConv)
  1218. {
  1219. ret = ImpersonateDdeClientWindow(pConv->hwndClient, pConv->hwndServer);
  1220. }
  1221. LeaveCriticalSection(&WDML_CritSect);
  1222. return ret;
  1223. }