Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1377 lines
34 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: DDE.C (Extensible Compound Documents -DDE)
  3. *
  4. * Copyright (c) 1985 - 1991 Microsoft Corporation
  5. *
  6. * PURPOSE: Handles all API routines for the dde sub-dll of the ole dll.
  7. *
  8. * History:
  9. * Raor,Srinik (../../90,91) Designed and coded
  10. * curts created portable version for WIN16/32
  11. *
  12. \***************************************************************************/
  13. #include <windows.h>
  14. #include "dde.h"
  15. #include "dll.h"
  16. /* #define GRAPHBUG */
  17. // ### may not need seperate wndproc for system topic!
  18. HANDLE GetDDEDataHandle (DDEDATA FAR *, UINT, HANDLE);
  19. extern ATOM aSystem;
  20. extern ATOM aOle;
  21. extern HANDLE hInstDLL;
  22. // DocWndProc: Window procedure used to document DDE conversations
  23. LRESULT FAR PASCAL DocWndProc(
  24. HWND hwnd,
  25. UINT message,
  26. WPARAM wParam,
  27. LPARAM lParam
  28. ){
  29. PEDIT_DDE pedit = NULL;
  30. LPOBJECT_LE lpobj = NULL;
  31. Puts("DocWndProc");
  32. if (lpobj = (LPOBJECT_LE) GetWindowLongPtr (hwnd, 0))
  33. {
  34. pedit = lpobj->pDocEdit;
  35. }
  36. else
  37. {
  38. // Can't cope so just pass this message on
  39. DEBUG_OUT ("SYS: doc conv block missing",0);
  40. return DefWindowProc (hwnd, message, wParam, lParam);
  41. }
  42. switch (message){
  43. case WM_DDE_ACK:
  44. #ifdef FIREWALLS
  45. ASSERT (pedit, "Doc conv channel missing");
  46. #endif
  47. DEBUG_OUT ("WM_DDE_ACK ", 0);
  48. if (pedit->bTerminating){
  49. // ### this error recovery may not be correct.
  50. DEBUG_OUT ("No action due to termination process",0)
  51. break;
  52. }
  53. switch(pedit->awaitAck){
  54. case AA_INITIATE:
  55. HandleAckInitMsg (pedit, (HWND)wParam);
  56. if (LOWORD(lParam))
  57. GlobalDeleteAtom (LOWORD(lParam));
  58. if (HIWORD(lParam))
  59. GlobalDeleteAtom (HIWORD(lParam));
  60. break;
  61. case AA_REQUEST:
  62. Puts("Request");
  63. HandleAck (lpobj, pedit, wParam, lParam);
  64. break;
  65. case AA_UNADVISE:
  66. Puts("Unadvise");
  67. HandleAck (lpobj, pedit, wParam, lParam);
  68. break;
  69. case AA_EXECUTE:
  70. Puts("Execute");
  71. HandleAck (lpobj, pedit, wParam, lParam);
  72. break;
  73. case AA_ADVISE:
  74. Puts("Advise");
  75. HandleAck (lpobj, pedit, wParam, lParam);
  76. break;
  77. case AA_POKE:
  78. // freeing pokedata is done in handleack
  79. Puts("Poke");
  80. HandleAck (lpobj, pedit, wParam, lParam);
  81. break;
  82. default:
  83. DEBUG_OUT ("received ACK We don't know how to handle ",0)
  84. break;
  85. } // end of switch
  86. break;
  87. case WM_TIMER:
  88. #ifdef FIREWALLS
  89. ASSERT (pedit, "Doc conv channel missing");
  90. #endif
  91. HandleTimerMsg (lpobj, pedit);
  92. break;
  93. case WM_DDE_DATA:
  94. #ifdef FIREWALLS
  95. ASSERT (pedit, "Doc conv channel missing");
  96. #endif
  97. DEBUG_OUT ("WM_DDE_DATA",0);
  98. HandleDataMsg (lpobj, GET_WM_DDE_DATA_HDATA(wParam,lParam),
  99. GET_WM_DDE_DATA_ITEM(wParam,lParam));
  100. DDEFREE(message, lParam);
  101. break;
  102. case WM_DDE_TERMINATE:
  103. #ifdef FIREWALLS
  104. ASSERT (pedit, "Doc conv channel missing");
  105. #endif
  106. DEBUG_OUT ("WM_DDE_TERMINATE",0);
  107. HandleTermMsg (lpobj, pedit, (HWND)wParam, TRUE);
  108. break;
  109. case WM_DESTROY:
  110. #ifdef FIREWALLS
  111. ASSERT (pedit, "Doc conv channel missing");
  112. #endif
  113. DEBUG_OUT ("Client window being destroyed", 0)
  114. pedit->hClient = NULL;
  115. break;
  116. default:
  117. return DefWindowProc (hwnd, message, wParam, lParam);
  118. }
  119. return 0L;
  120. }
  121. // SrvrWndProc: Window Procedure for System Topic DDE conversations
  122. // wndproc for system topic
  123. LRESULT FAR PASCAL SrvrWndProc(
  124. HWND hwnd,
  125. UINT message,
  126. WPARAM wParam,
  127. LPARAM lParam
  128. ){
  129. PEDIT_DDE pedit = NULL;
  130. LPOBJECT_LE lpobj = NULL;
  131. Puts("SysWndProc");
  132. if (lpobj = (LPOBJECT_LE) GetWindowLongPtr (hwnd, 0))
  133. {
  134. pedit = lpobj->pSysEdit;
  135. }
  136. else
  137. {
  138. // Can't cope so just pass this message on
  139. DEBUG_OUT ("SYS: conv edit block missing",0);
  140. return DefWindowProc (hwnd, message, wParam, lParam);
  141. }
  142. switch (message){
  143. case WM_DDE_ACK:
  144. #ifdef FIREWALLS
  145. ASSERT (pedit, "sys conv edit block missing");
  146. #endif
  147. DEBUG_OUT ("SYS: WM_DDE_ACK",0);
  148. if(pedit->bTerminating){
  149. //### Error recovery may not be OK.
  150. DEBUG_OUT ("No action due to termination process",0)
  151. break;
  152. }
  153. switch (pedit->awaitAck) {
  154. case AA_INITIATE:
  155. #ifdef HISTORY
  156. if (GETWINDOWUINT((HWND)wParam, GWW_HINSTANCE) == pedit->hInst ||
  157. IsSrvrDLLwnd ((HWND)wParam, pedit->hInst)) {
  158. // For exact instance match or for
  159. // DLL instance match, keep the new one
  160. #ifdef FIREWALLS
  161. ASSERT (!pedit->hServer, "Two instances are matching");
  162. #endif
  163. pedit->hServer = (HWND)wParam;
  164. } else {
  165. ++pedit->extraTerm;
  166. // This post directly is alright since we are
  167. // terminating extra initiates.
  168. PostMessage ((HWND)wParam,
  169. WM_DDE_TERMINATE, hwnd, 0);
  170. }
  171. #else
  172. HandleAckInitMsg (pedit, (HWND)wParam);
  173. #endif
  174. if (LOWORD(lParam))
  175. GlobalDeleteAtom (LOWORD(lParam));
  176. if (HIWORD(lParam))
  177. GlobalDeleteAtom (HIWORD(lParam));
  178. break;
  179. case AA_EXECUTE:
  180. HandleAck(lpobj, pedit, wParam, lParam);
  181. break;
  182. default:
  183. DEBUG_OUT ("received ACK We don't know how to handle ",0)
  184. break;
  185. }
  186. break;
  187. case WM_TIMER:
  188. #ifdef FIREWALLS
  189. ASSERT (pedit, "sys conv edit block missing");
  190. #endif
  191. HandleTimerMsg (lpobj, pedit);
  192. break;
  193. case WM_DDE_TERMINATE:
  194. #ifdef FIREWALLS
  195. ASSERT (pedit, "sys conv edit block missing");
  196. #endif
  197. HandleTermMsg (lpobj, pedit, (HWND)wParam, FALSE);
  198. break;
  199. case WM_DESTROY:
  200. #ifdef FIREWALLS
  201. ASSERT (pedit, "sys conv edit block missing");
  202. #endif
  203. DEBUG_OUT ("destroy window for the sys connection", 0);
  204. pedit->hClient = NULL;
  205. break;
  206. default:
  207. return DefWindowProc (hwnd, message, wParam, lParam);
  208. }
  209. return 0L;
  210. }
  211. void INTERNAL HandleTimerMsg (
  212. LPOBJECT_LE lpobj,
  213. PEDIT_DDE pedit
  214. ){
  215. // Since there is only one timer for each client, just
  216. // repost the message and delete the timer.
  217. KillTimer (pedit->hClient, 1);
  218. pedit->wTimer = 0;
  219. if (PostMessageToServer(pedit, pedit->msg, pedit->lParam))
  220. return ; // return something.
  221. // Postmessage failed. We need to getback to the main stream of
  222. // commands for the object.
  223. HandleAck (lpobj, pedit, (WPARAM)NULL, pedit->lParam);
  224. return ;
  225. }
  226. void INTERNAL HandleTermMsg (lpobj, pedit, hwndPost, bDoc)
  227. LPOBJECT_LE lpobj;
  228. PEDIT_DDE pedit;
  229. HWND hwndPost;
  230. BOOL bDoc;
  231. {
  232. UINT asyncCmd;
  233. BOOL bBusy;
  234. if (pedit->hServer != hwndPost){
  235. DEBUG_OUT ("Got terminate for extra conversation",0)
  236. if (--pedit->extraTerm == 0 && pedit->bTerminating)
  237. ScheduleAsyncCmd (lpobj);
  238. return;
  239. }
  240. if (!pedit->bTerminating){
  241. // If we are waiting for any ack, then goto next step with error
  242. // delete any data if we were in busy mode.
  243. bBusy = DeleteBusyData (lpobj, pedit);
  244. asyncCmd = lpobj->asyncCmd;
  245. PostMessageToServer(pedit, WM_DDE_TERMINATE, 0);
  246. pedit->hServer = NULL;
  247. if (pedit->awaitAck || bBusy) {
  248. // Set error and goto next step.
  249. lpobj->subErr = OLE_ERROR_COMM;
  250. pedit->awaitAck = 0;
  251. ScheduleAsyncCmd (lpobj);
  252. }
  253. // If the command is delete, do not delete
  254. // the edit blocks. It will be deleted
  255. // in the OleLnkDelete routine and for delete it is
  256. // possible that by the time we come here, the object
  257. // may not exist at all.
  258. if (asyncCmd != OLE_DELETE){
  259. // QueryOpen() is done because excel is sending WM_DDE_TERMINATE
  260. // for system without sending for doc in case of failure.
  261. if (bDoc || QueryOpen (lpobj)) {
  262. // if the termination is for document and no async command
  263. // terminate the server conversation also.
  264. if ((asyncCmd == OLE_NONE) || (asyncCmd == OLE_REQUESTDATA)
  265. || (asyncCmd == OLE_OTHER) || (asyncCmd == OLE_SETDATA)
  266. || (asyncCmd == OLE_RUN) || (asyncCmd == OLE_SHOW)
  267. || (asyncCmd == OLE_SETUPDATEOPTIONS)) {
  268. if (lpobj->pDocEdit && lpobj->pDocEdit->awaitAck)
  269. // we are waiting for an ack on Doc channel. So start
  270. // the unlaunch process after we get the ack.
  271. lpobj->bUnlaunchLater = TRUE;
  272. else
  273. CallEmbLnkDelete (lpobj);
  274. } else {
  275. if (bDoc)
  276. DeleteDocEdit (lpobj);
  277. }
  278. }else
  279. DeleteSrvrEdit (lpobj);
  280. }
  281. } else {
  282. pedit->hServer = NULL;
  283. if (pedit->extraTerm == 0)
  284. ScheduleAsyncCmd (lpobj);
  285. }
  286. }
  287. #ifdef FIREWALLS
  288. BOOL INTERNAL CheckAtomValid (ATOM aItem)
  289. {
  290. char buffer[MAX_ATOM];
  291. int len, val;
  292. Puts("CheckAtomValid");
  293. if (aItem == NULL)
  294. return TRUE;
  295. val = GlobalGetAtomName (aItem, buffer, MAX_ATOM);
  296. len = lstrlen (buffer);
  297. return ((val != 0) && (val == len));
  298. }
  299. #endif
  300. // HandleAckInitMsg: Handles WM_DDE_ACKs received while in initiate state. If
  301. // this is the first reply, save its window handle. If multiple replies
  302. // are received, take the one with the prefered instance, if there is
  303. // one. Keep a count of WM_DDE_TERMINATEs we send so that we don't shut
  304. // the window until we get all of the responses for WM_DDE_TERMINATEs.
  305. void INTERNAL HandleAckInitMsg (
  306. PEDIT_DDE pedit,
  307. HWND hserver
  308. ){
  309. Puts("HandleAckInitMsg");
  310. if (pedit->hServer){
  311. // just take the very first one. Direct post is OK
  312. PostMessage (hserver, WM_DDE_TERMINATE, (WPARAM)pedit->hClient, 0);
  313. ++pedit->extraTerm;
  314. } else
  315. pedit->hServer = hserver;
  316. }
  317. // HandleAck: returns 0 if <ack> is not positive, else non-0. Should probably be
  318. // a macro.
  319. BOOL INTERNAL HandleAck (
  320. LPOBJECT_LE lpobj,
  321. PEDIT_DDE pedit,
  322. WPARAM wParam,
  323. LPARAM lParam
  324. ){
  325. WORD wStatus = GET_WM_DDE_ACK_STATUS(wParam,lParam);
  326. HANDLE hData = NULL;
  327. BOOL retval = TRUE;
  328. UNREFERENCED_PARAMETER(wParam);
  329. // check for busy bit
  330. if ((wStatus & 0x4000) && ContextCallBack ((LPOLEOBJECT)lpobj, OLE_QUERY_RETRY)){
  331. // we got busy from the server. create a timer and wait for time out.
  332. // We do not need makeprocinstance since, DLLs are single insance, all
  333. // we need to do is export for this function.
  334. if ((pedit->wTimer = SetTimer (pedit->hClient, 1, 3000, NULL)))
  335. return TRUE;
  336. }
  337. // even if the client got terminate we have to go thru this path.
  338. if (pedit->wTimer) {
  339. KillTimer (pedit->hClient, 1);
  340. pedit->wTimer = 0;
  341. }
  342. if (pedit->awaitAck == AA_POKE)
  343. // We have to free the data first. Handleack can trigger
  344. // another Poke (like pokehostnames)
  345. FreePokeData (lpobj, pedit);
  346. if (pedit->awaitAck == AA_EXECUTE) {
  347. hData = GET_WM_DDE_EXECACK_HDATA(wParam,lParam);
  348. if (hData) GlobalFree (hData);
  349. } else {
  350. ATOM aItem = GET_WM_DDE_ACK_ITEM(wParam,lParam);
  351. ASSERT (CheckAtomValid(aItem),"Invalid atom in ACK")
  352. if (aItem)
  353. GlobalDeleteAtom (aItem);
  354. }
  355. if (!(wStatus & 0x8000)) {
  356. // error case. set the error
  357. DEBUG_OUT ("DDE ACK with failure", 0)
  358. if (lpobj->errHint){
  359. lpobj->subErr = lpobj->errHint;
  360. lpobj->errHint = OLE_OK;
  361. } else
  362. lpobj->subErr = OLE_ERROR_COMM;
  363. retval = FALSE;
  364. if (pedit->awaitAck == AA_ADVISE) {
  365. #ifdef ASSERT
  366. ASSERT (pedit->hopt, "failed advise, options block missing");
  367. #endif
  368. GlobalFree (pedit->hopt);
  369. }
  370. }
  371. pedit->hopt = NULL;
  372. pedit->awaitAck = 0;
  373. ScheduleAsyncCmd (lpobj);
  374. return retval;
  375. }
  376. // HandleDataMsg: Called for WM_DDE_DATA message. If data is from an
  377. // ADVISE-ON-CLOSE and this is there are no more outstanding
  378. // ADVISE-ON-CLOSE requests, close the document and end the
  379. // conversation.
  380. void INTERNAL HandleDataMsg (
  381. LPOBJECT_LE lpobj,
  382. HANDLE hdata,
  383. ATOM aItem
  384. ){
  385. DDEDATA far *lpdata = NULL;
  386. BOOL fAck;
  387. BOOL fRelease;
  388. int options;
  389. PEDIT_DDE pedit;
  390. Puts("HandleDataMsg");
  391. if (ScanItemOptions (aItem, (int far *)&options) != OLE_OK) {
  392. DEBUG_OUT (FALSE, "Improper item options");
  393. return;
  394. }
  395. pedit = lpobj->pDocEdit;
  396. if (hdata) {
  397. if (!(lpdata = (DDEDATA FAR *) GlobalLock(hdata)))
  398. return;
  399. fAck = lpdata->fAckReq;
  400. fRelease = lpdata->fRelease;
  401. if (pedit->bTerminating) {
  402. DEBUG_OUT ("Got DDE_DATA in terminate sequence",0)
  403. fRelease = TRUE;
  404. }
  405. else {
  406. if ((OLECLIPFORMAT)lpdata->cfFormat == cfBinary && aItem == aStdDocName) {
  407. ChangeDocName (lpobj, (LPSTR)lpdata->Value);
  408. }
  409. else
  410. SetData (lpobj, hdata, options);
  411. #ifdef FIREWALLS
  412. ASSERT (IsWindowValid(pedit->hServer),
  413. "Server window missing in HandleDataMsg")
  414. ASSERT (CheckAtomValid(aItem),"HandleDataMsg invalid atom")
  415. #endif
  416. // important that we post the acknowledge first. Otherwist the
  417. // messages are not in sync.
  418. if (fAck)
  419. {
  420. LPARAM lparamNew = MAKE_DDE_LPARAM(WM_DDE_ACK,POSITIVE_ACK,aItem);
  421. PostMessageToServer (pedit, WM_DDE_ACK, lparamNew);
  422. }
  423. else if (aItem)
  424. GlobalDeleteAtom (aItem);
  425. if ((lpdata->fResponse) && (pedit->awaitAck == AA_REQUEST)) {
  426. // we sent the request. So, schedule next step.
  427. pedit->awaitAck = 0;
  428. ScheduleAsyncCmd (lpobj);
  429. }
  430. }
  431. GlobalUnlock (hdata);
  432. if (fRelease)
  433. GlobalFree (hdata);
  434. }
  435. else {
  436. if (CanCallback (lpobj, options)) {
  437. if (options != OLE_CLOSED)
  438. ContextCallBack ((LPOLEOBJECT)lpobj, options);
  439. else
  440. lpobj->bSvrClosing = FALSE;
  441. }
  442. }
  443. if (options == OLE_CLOSED && (lpobj->pDocEdit->nAdviseClose <= 2)
  444. && (lpobj->asyncCmd == OLE_NONE)) {
  445. InitAsyncCmd (lpobj, OLE_SERVERUNLAUNCH, EMBLNKDELETE);
  446. EmbLnkDelete (lpobj);
  447. }
  448. }
  449. HANDLE GetDDEDataHandle (
  450. DDEDATA far *lpdata,
  451. UINT cfFormat,
  452. HANDLE hdata
  453. ){
  454. if (cfFormat == CF_METAFILEPICT) {
  455. #ifdef _WIN64
  456. return (*(void* _unaligned*)lpdata->Value);
  457. #else
  458. return LongToHandle(*(LONG*)lpdata->Value);
  459. #endif
  460. }
  461. if (cfFormat == CF_BITMAP || cfFormat == CF_ENHMETAFILE)
  462. return LongToHandle(*(LONG*)lpdata->Value);
  463. if (cfFormat == CF_DIB)
  464. return GlobalReAlloc (LongToHandle(*(LONG*)lpdata->Value), 0L,
  465. GMEM_MODIFY|GMEM_SHARE);
  466. return CopyData (((LPSTR)lpdata)+4, (DWORD)(GlobalSize (hdata) - 4));
  467. }
  468. // SetData: Given the DDEDATA structure from a WM_DDE_DATA message, set up the
  469. // appropriate data in lpobj. If the native is in native format, add
  470. // that field, otherwise, if it is in picture format, ask the picture
  471. // to add it itself.
  472. void INTERNAL SetData (
  473. LPOBJECT_LE lpobj,
  474. HANDLE hdata,
  475. int options
  476. ){
  477. DDEDATA far *lpdata = NULL;
  478. OLESTATUS retVal = OLE_ERROR_MEMORY;
  479. HANDLE hdataDDE;
  480. Puts("SetData");
  481. if (!(lpdata = (DDEDATA far *) (GlobalLock (hdata))))
  482. goto errrtn;
  483. if (!(hdataDDE = GetDDEDataHandle (lpdata, lpdata->cfFormat, hdata)))
  484. goto errrtn;
  485. if ((OLECLIPFORMAT)lpdata->cfFormat == cfNative) {
  486. retVal = (*lpobj->head.lpvtbl->ChangeData) ( (LPOLEOBJECT)lpobj,
  487. hdataDDE,
  488. lpobj->head.lpclient,
  489. TRUE); // use this data, don't copy
  490. }
  491. else if ((BOOL)lpdata->cfFormat && (lpdata->cfFormat == (int)GetPictType (lpobj))) {
  492. retVal = (*lpobj->lpobjPict->lpvtbl->ChangeData) (lpobj->lpobjPict,
  493. hdataDDE,
  494. lpobj->head.lpclient,
  495. lpdata->fRelease);
  496. } else {
  497. // case of extra data in the object.
  498. DeleteExtraData (lpobj);
  499. lpobj->cfExtra = lpdata->cfFormat;
  500. lpobj->hextraData = hdataDDE;
  501. goto end;
  502. }
  503. if (retVal == OLE_OK) {
  504. SetExtents (lpobj);
  505. if (CanCallback (lpobj, options)) {
  506. if (options == OLE_CLOSED) {
  507. ContextCallBack ((LPOLEOBJECT)lpobj, OLE_CHANGED);
  508. ContextCallBack ((LPOLEOBJECT)lpobj, OLE_CLOSED);
  509. lpobj->bSvrClosing = FALSE;
  510. }
  511. else
  512. ContextCallBack ((LPOLEOBJECT)lpobj, options);
  513. }
  514. }
  515. end:
  516. errrtn:
  517. if (lpdata)
  518. GlobalUnlock (hdata);
  519. return;
  520. }
  521. // SysStartConvDDE: Starts a system conversation. Returns a handle to that
  522. // conversation, or NULL.
  523. BOOL INTERNAL InitSrvrConv (
  524. LPOBJECT_LE lpobj,
  525. HANDLE hInst
  526. ){
  527. HANDLE hedit = NULL;
  528. PEDIT_DDE pedit = NULL;
  529. Puts("InitSrvrConv");
  530. if (!lpobj->hSysEdit) {
  531. hedit = LocalAlloc (LMEM_MOVEABLE | LMEM_ZEROINIT, sizeof (EDIT_DDE));
  532. if (hedit == NULL || ((pedit = (PEDIT_DDE) LocalLock (hedit)) == NULL))
  533. goto errRtn;
  534. } else {
  535. #ifdef FIREWALLS
  536. ASSERT (!lpobj->pSysEdit->hClient, "Sys conv lptr is present");
  537. #endif
  538. hedit = lpobj->hSysEdit;
  539. pedit = lpobj->pSysEdit;
  540. UtilMemClr ((PSTR) pedit, sizeof (EDIT_DDE));
  541. }
  542. if((pedit->hClient = CreateWindow ("OleSrvrWndClass", "",
  543. WS_OVERLAPPED,0,0,0,0,NULL,NULL, hInstDLL, NULL)) == NULL)
  544. goto errRtn;
  545. lpobj->hSysEdit = hedit;
  546. lpobj->pSysEdit = pedit;
  547. pedit->hInst = hInst;
  548. pedit->awaitAck = AA_INITIATE;
  549. SetWindowLongPtr (pedit->hClient, 0, (LONG_PTR)lpobj);
  550. SendMessage ((HWND)-1, WM_DDE_INITIATE, (WPARAM)pedit->hClient,
  551. MAKELPARAM (lpobj->app, aOle));
  552. ASSERT (CheckAtomValid(aOle),"systopic invalid atom")
  553. pedit->awaitAck = 0;
  554. if (pedit->hServer == NULL) {
  555. pedit->awaitAck = AA_INITIATE;
  556. // Now try the System topic
  557. SendMessage ((HWND)-1, WM_DDE_INITIATE, (WPARAM)pedit->hClient,
  558. MAKELPARAM (lpobj->app, aSystem));
  559. ASSERT (CheckAtomValid(aSystem),"systopic invalid atom")
  560. pedit->awaitAck = 0;
  561. if (pedit->hServer == NULL) {
  562. DEBUG_OUT ("Srver connection failed", 0);
  563. goto errRtn;
  564. }
  565. }
  566. // Put the long ptr handle in the object.
  567. return TRUE;
  568. errRtn:
  569. if (pedit) {
  570. if (pedit->hClient)
  571. DestroyWindow (pedit->hClient);
  572. LocalUnlock (hedit);
  573. }
  574. if (hedit)
  575. LocalFree (hedit);
  576. lpobj->hSysEdit = NULL;
  577. lpobj->pSysEdit = NULL;
  578. return FALSE;
  579. }
  580. // TermSrvrConv: Ends conversation indicated by hedit.
  581. void INTERNAL TermSrvrConv (LPOBJECT_LE lpobj)
  582. {
  583. PEDIT_DDE pedit;
  584. Puts("TermSrvrConv");
  585. if (!(pedit = lpobj->pSysEdit))
  586. return;
  587. if (PostMessageToServer (pedit, WM_DDE_TERMINATE, 0)){
  588. lpobj->bAsync = TRUE;
  589. pedit->bTerminating = TRUE;
  590. } else {
  591. pedit->bTerminating = FALSE;
  592. lpobj->subErr = OLE_ERROR_TERMINATE;
  593. }
  594. return;
  595. }
  596. void INTERNAL DeleteAbortData (
  597. LPOBJECT_LE lpobj,
  598. PEDIT_DDE pedit
  599. ){
  600. UNREFERENCED_PARAMETER(lpobj);
  601. // kill if any timer active.
  602. if (pedit->wTimer) {
  603. KillTimer (pedit->hClient, 1);
  604. pedit->wTimer = 0;
  605. }
  606. return;
  607. }
  608. BOOL INTERNAL DeleteBusyData (
  609. LPOBJECT_LE lpobj,
  610. PEDIT_DDE pedit
  611. ){
  612. UNREFERENCED_PARAMETER(lpobj);
  613. // kill if any timer active.
  614. if (pedit->wTimer) {
  615. KillTimer (pedit->hClient, 1);
  616. pedit->wTimer = 0;
  617. if (pedit->hData) {
  618. GlobalFree (pedit->hData);
  619. pedit->hData = NULL;
  620. }
  621. if (pedit->hopt) {
  622. GlobalFree (pedit->hopt);
  623. pedit->hopt = NULL;
  624. }
  625. if (pedit->awaitAck && (HIWORD(pedit->lParam))) {
  626. if (pedit->awaitAck == AA_EXECUTE) {
  627. HANDLE hData = GET_WM_DDE_EXECACK_HDATA(pedit->wParam, pedit->lParam);
  628. if (hData) GlobalFree (hData);
  629. } else {
  630. ASSERT (CheckAtomValid(HIWORD(pedit->lParam)),
  631. "Invalid atom in ACK")
  632. if (HIWORD(pedit->lParam))
  633. GlobalDeleteAtom (HIWORD(pedit->lParam));
  634. }
  635. // we want to wipe out the HIWORD of lParam
  636. pedit->lParam &= 0x0000FFFF;
  637. }
  638. return TRUE;
  639. }
  640. return FALSE;
  641. }
  642. void INTERNAL DeleteSrvrEdit (
  643. LPOBJECT_LE lpobj
  644. ){
  645. PEDIT_DDE pedit;
  646. Puts("deleteSrvrEdit");
  647. if (!(pedit = lpobj->pSysEdit))
  648. return;
  649. // delete any data if we were in busy mode.
  650. DeleteBusyData (lpobj, pedit);
  651. if (pedit->hClient)
  652. DestroyWindow (pedit->hClient);
  653. if (lpobj->pSysEdit)
  654. LocalUnlock (lpobj->hSysEdit);
  655. if (lpobj->hSysEdit)
  656. LocalFree (lpobj->hSysEdit);
  657. lpobj->hSysEdit = NULL;
  658. lpobj->pSysEdit = NULL;
  659. return;
  660. }
  661. void INTERNAL SendStdExit (
  662. LPOBJECT_LE lpobj
  663. ){
  664. Puts("SendSrvrExit");
  665. if (!lpobj->pSysEdit)
  666. return;
  667. SrvrExecute (lpobj, MapStrToH ("[StdExit]"));
  668. }
  669. void INTERNAL SendStdClose (
  670. LPOBJECT_LE lpobj
  671. ){
  672. Puts("SendDocClose");
  673. if (!lpobj->pDocEdit)
  674. return;
  675. DocExecute (lpobj, MapStrToH ("[StdCloseDocument]"));
  676. }
  677. // SrvrExecute: Sends execute command to system conversation.
  678. BOOL INTERNAL SrvrExecute (
  679. LPOBJECT_LE lpobj,
  680. HANDLE hdata
  681. ){
  682. PEDIT_DDE pedit = NULL;
  683. int retval = FALSE;
  684. Puts("SrvrExecute");
  685. #ifdef FIREWALLS
  686. ASSERT (lpobj->hSysEdit, "Sys conv handle missing");
  687. ASSERT (lpobj->pSysEdit, "sys conv lptr is missing");
  688. #endif
  689. pedit = lpobj->pSysEdit;
  690. if (hdata == NULL || pedit == NULL) {
  691. lpobj->subErr = OLE_ERROR_MEMORY;
  692. return FALSE;
  693. }
  694. #ifdef FIREWALLS
  695. ASSERT (!pedit->bTerminating, "In terminate state")
  696. ASSERT (pedit->awaitAck == 0, "trying to Post msg while waiting for ack")
  697. #endif
  698. if (lpobj->bOldLink) {
  699. GlobalFree (hdata);
  700. return TRUE;
  701. }
  702. if (PostMessageToServer (pedit, WM_DDE_EXECUTE, (LPARAM)hdata)) {
  703. // data is being freed in the acknowledge
  704. lpobj->bAsync = TRUE;
  705. pedit->awaitAck = AA_EXECUTE;
  706. return TRUE;
  707. } else {
  708. lpobj->subErr = OLE_ERROR_COMMAND;
  709. GlobalFree (hdata);
  710. return FALSE;
  711. }
  712. }
  713. // StartConvDDE: Starts the document conversation for an object based on
  714. // .app and .topic atoms.
  715. BOOL FARINTERNAL InitDocConv (
  716. LPOBJECT_LE lpobj,
  717. BOOL fNetDlg
  718. ){
  719. // ### This routine looks very similar to IitSrvrConv
  720. // combine with the it
  721. HANDLE hedit = NULL;
  722. PEDIT_DDE pedit = NULL;
  723. char buf[MAX_NET_NAME];
  724. int nDrive = 2; // drive C
  725. char cOldDrive;
  726. Puts("InitDocConv");
  727. if (QueryOpen (lpobj)){
  728. DEBUG_OUT ("Attempt to start already existing conversation",0);
  729. return FALSE;
  730. }
  731. cOldDrive = lpobj->cDrive;
  732. if (CheckNetDrive (lpobj, fNetDlg) != OLE_OK)
  733. return FALSE;
  734. if (!lpobj->pDocEdit) {
  735. hedit = LocalAlloc (LMEM_MOVEABLE | LMEM_ZEROINIT, sizeof (EDIT_DDE));
  736. if (hedit == NULL || ((pedit = (PEDIT_DDE) LocalLock (hedit)) == NULL)){
  737. lpobj->subErr = OLE_ERROR_MEMORY;
  738. goto errRtn;
  739. }
  740. } else {
  741. #ifdef FIREWALLS
  742. ASSERT (!lpobj->pDocEdit->hClient, "Doc conv lptr is present");
  743. #endif
  744. hedit = lpobj->hDocEdit;
  745. pedit = lpobj->pDocEdit;
  746. UtilMemClr ((PSTR) pedit, sizeof (EDIT_DDE));
  747. }
  748. if ((pedit->hClient = CreateWindow ("OleDocWndClass", "Window Name",
  749. WS_OVERLAPPED,0,0,0,0,NULL,NULL, hInstDLL, NULL)) == NULL) {
  750. lpobj->subErr = OLE_ERROR_MEMORY;
  751. goto errRtn;
  752. }
  753. lpobj->hDocEdit = hedit;
  754. lpobj->pDocEdit = pedit;
  755. SetWindowLongPtr (pedit->hClient, 0, (LONG_PTR)lpobj);
  756. // buf will filled by netname in the first call to SetNextNetDrive()
  757. buf[0] = '\0';
  758. do {
  759. pedit->awaitAck = AA_INITIATE;
  760. // !!! Where are the atom counts bumped?
  761. SendMessage ((HWND)-1, WM_DDE_INITIATE, (WPARAM)pedit->hClient,
  762. MAKELPARAM (lpobj->app, lpobj->topic));
  763. pedit->awaitAck = 0;
  764. if (pedit->hServer) {
  765. if ((cOldDrive != lpobj->cDrive)
  766. && (lpobj->asyncCmd != OLE_CREATEFROMFILE))
  767. ContextCallBack ((LPOLEOBJECT)lpobj, OLE_RENAMED);
  768. return TRUE;
  769. }
  770. } while ((lpobj->head.ctype == CT_LINK) && (lpobj->aNetName)
  771. && SetNextNetDrive (lpobj, &nDrive, buf)) ;
  772. errRtn:
  773. if (cOldDrive != lpobj->cDrive) {
  774. // put back the old drive
  775. lpobj->cDrive = cOldDrive;
  776. ChangeTopic (lpobj);
  777. }
  778. if (pedit && pedit->hClient)
  779. DestroyWindow (pedit->hClient);
  780. if (pedit)
  781. LocalUnlock (hedit);
  782. if (hedit)
  783. LocalFree (hedit);
  784. lpobj->hDocEdit = NULL;
  785. lpobj->pDocEdit = NULL;
  786. return FALSE;
  787. }
  788. // Execute: Sends an execute string WM_DDE_EXECUTE to the document conversation.
  789. BOOL INTERNAL DocExecute(
  790. LPOBJECT_LE lpobj,
  791. HANDLE hdata
  792. ){
  793. PEDIT_DDE pedit;
  794. Puts("DocExecute");
  795. pedit = lpobj->pDocEdit;
  796. if (hdata == NULL || pedit == NULL)
  797. return FALSE;
  798. #ifdef FIREWALLS
  799. ASSERT (!pedit->bTerminating, "Execute: terminating")
  800. ASSERT (pedit->hClient, "Client null")
  801. ASSERT (IsWindowValid(pedit->hClient),"Invalid client")
  802. ASSERT (pedit->awaitAck == 0, "trying to Post msg while waiting for ack")
  803. #endif
  804. if (lpobj->bOldLink) {
  805. GlobalFree (hdata);
  806. return TRUE;
  807. }
  808. if (PostMessageToServer (pedit, WM_DDE_EXECUTE, (LPARAM)hdata)) {
  809. // data is being freed in the execute command
  810. pedit->awaitAck = AA_EXECUTE;
  811. lpobj->bAsync = TRUE;
  812. return TRUE;
  813. } else {
  814. lpobj->subErr = OLE_ERROR_COMMAND;
  815. GlobalFree (hdata);
  816. return FALSE;
  817. }
  818. }
  819. // EndConvDDE: terminates the doc level conversation.
  820. void INTERNAL TermDocConv (
  821. LPOBJECT_LE lpobj
  822. ){
  823. PEDIT_DDE pedit;
  824. Puts ("TermDocConv");
  825. DEBUG_OUT ("About to terminate convs from destroy",0)
  826. if (!(pedit = lpobj->pDocEdit))
  827. return;
  828. if (PostMessageToServer (pedit, WM_DDE_TERMINATE, 0)) {
  829. pedit->bTerminating = TRUE;
  830. lpobj->bAsync = TRUE;
  831. } else
  832. lpobj->subErr = OLE_ERROR_TERMINATE;
  833. return;
  834. }
  835. // Deletes the document conversdation memory.
  836. void INTERNAL DeleteDocEdit (lpobj)
  837. LPOBJECT_LE lpobj;
  838. {
  839. PEDIT_DDE pedit;
  840. Puts ("DeleteDocEdit");
  841. if (!(pedit = lpobj->pDocEdit))
  842. return;
  843. // delete any data if we were in busy mode.
  844. DeleteBusyData (lpobj, pedit);
  845. // Delete if any data blocks.
  846. if (pedit->hClient)
  847. DestroyWindow (pedit->hClient);
  848. if (lpobj->pDocEdit)
  849. LocalUnlock (lpobj->hDocEdit);
  850. if (lpobj->hDocEdit)
  851. LocalFree (lpobj->hDocEdit);
  852. lpobj->hDocEdit = NULL;
  853. lpobj->pDocEdit = NULL;
  854. return;
  855. }
  856. // LeLauchApp: Launches app based on the ClassName in lpobj.
  857. // History:
  858. // curts changed LoadModule calls to WinExec
  859. //
  860. HANDLE INTERNAL LeLaunchApp (LPOBJECT_LE lpobj)
  861. {
  862. // struct CMDSHOW
  863. // {
  864. // WORD first;
  865. // WORD second;
  866. // } cmdShow = {2, SW_SHOWNORMAL};
  867. //
  868. // struct
  869. // {
  870. // WORD wEnvSeg;
  871. // LPSTR lpcmdline;
  872. // struct CMDSHOW FAR *lpCmdShow;
  873. // DWORD dwReserved;
  874. // } paramBlock;
  875. WORD cmdShow = SW_SHOWNORMAL;
  876. char cmdline[MAX_STR];
  877. char exeName[MAX_STR];
  878. char lpstr[2*MAX_STR];
  879. HANDLE hInst;
  880. #define EMB_STR " -Embedding "
  881. Puts("LeLaunchApp");
  882. GlobalGetAtomName (lpobj->aServer, exeName, MAX_STR);
  883. cmdline[0] = ' ';
  884. if (lpobj->bOldLink) {
  885. cmdShow = SW_SHOWMINIMIZED;
  886. GlobalGetAtomName (lpobj->topic, cmdline + 1, MAX_STR);
  887. } else {
  888. lstrcpy ((LPSTR)cmdline+1, (LPSTR) EMB_STR);
  889. // For all link servers we want to give the filename on the command
  890. // line. But Excel is not registering the document before returning
  891. // from WinMain, if it has auto load macros. So, we want send StdOpen
  892. // for the old servers, instead of giving the file name on the command
  893. // line.
  894. if (lpobj->bOleServer && (lpobj->fCmd & LN_MASK) == LN_LNKACT)
  895. GlobalGetAtomName (lpobj->topic, cmdline+sizeof(EMB_STR),
  896. MAX_STR-sizeof(EMB_STR));
  897. if (lpobj->fCmd & ACT_MINIMIZE)
  898. cmdShow = SW_SHOWMINIMIZED;
  899. else if (!(lpobj->fCmd & (ACT_SHOW | ACT_DOVERB))
  900. // we want to launch with show in create invisible case
  901. // even though ACT_SHOW flag will be false
  902. && ((lpobj->fCmd & LN_MASK) != LN_NEW))
  903. cmdShow = SW_HIDE;
  904. }
  905. // paramBlock.wEnvSeg = NULL;
  906. // paramBlock.lpcmdline = (LPSTR)cmdline;
  907. // paramBlock.lpCmdShow = &cmdShow;
  908. // paramBlock.dwReserved = NULL;
  909. lstrcpy(lpstr,exeName);
  910. lstrcat(lpstr,cmdline);
  911. if ((hInst = (HANDLE)ULongToPtr(WinExec(lpstr, cmdShow))) < (HANDLE)32)
  912. hInst = NULL;
  913. if (!hInst) {
  914. LPSTR lptmp;
  915. char ch;
  916. // strip off the path and try again
  917. lptmp = (LPSTR)exeName;
  918. lptmp += lstrlen ((LPSTR) exeName);
  919. ch = *lptmp;
  920. while (ch != '\\' && ch != ':') {
  921. if (lptmp == (LPSTR) exeName) {
  922. // exe did not have path in it's name. we already tried
  923. // loading and it failed, no point trying again.
  924. return NULL;
  925. }
  926. else
  927. ch = *--lptmp;
  928. }
  929. lstrcpy(lpstr,++lptmp);
  930. lstrcat(lpstr,cmdline);
  931. if ((hInst = (HANDLE)ULongToPtr(WinExec(lpstr,cmdShow))) < (HANDLE)32)
  932. hInst = NULL;
  933. }
  934. return hInst;
  935. }
  936. //ScanItemOptions: Scan for the item options like Close/Save etc.
  937. int INTERNAL ScanItemOptions (
  938. ATOM aItem,
  939. int far *lpoptions
  940. ){
  941. ATOM aModifier;
  942. LPSTR lpbuf;
  943. char buf[MAX_STR];
  944. *lpoptions = OLE_CHANGED;
  945. if (!aItem) {
  946. // NULL item with no modifier means OLE_CHANGED for NULL item
  947. return OLE_OK;
  948. }
  949. GlobalGetAtomName (aItem, (LPSTR)buf, MAX_STR);
  950. lpbuf = (LPSTR)buf;
  951. while ( *lpbuf && *lpbuf != '/')
  952. lpbuf++;
  953. // no modifier same as /change
  954. if (*lpbuf == '\0')
  955. return OLE_OK;
  956. *lpbuf++ = '\0'; // seperate out the item string
  957. // We are using this in the caller.
  958. if (!(aModifier = GlobalFindAtom (lpbuf)))
  959. return OLE_ERROR_SYNTAX;
  960. if (aModifier == aChange)
  961. return OLE_OK;
  962. // Is it a save?
  963. if (aModifier == aSave){
  964. *lpoptions = OLE_SAVED;
  965. return OLE_OK;
  966. }
  967. // Is it a Close?
  968. if (aModifier == aClose){
  969. *lpoptions = OLE_CLOSED;
  970. return OLE_OK;
  971. }
  972. // unknown modifier
  973. return OLE_ERROR_SYNTAX;
  974. }
  975. void INTERNAL ChangeDocName (
  976. LPOBJECT_LE lpobj,
  977. LPSTR lpdata
  978. ){
  979. ATOM aOldTopic;
  980. OLESTATUS retVal;
  981. aOldTopic = lpobj->topic;
  982. lpobj->topic = GlobalAddAtom (lpdata);
  983. if ((retVal = SetNetName (lpobj)) != OLE_OK) {
  984. if (lpobj->topic)
  985. GlobalDeleteAtom (lpobj->topic);
  986. lpobj->topic = aOldTopic;
  987. return;
  988. // !!! what should we do in case of error? Currently, we will not
  989. // change the topic if SetNetName fails.
  990. }
  991. if (aOldTopic)
  992. GlobalDeleteAtom (aOldTopic);
  993. // Delete the link data block
  994. if (lpobj->hLink) {
  995. GlobalFree (lpobj->hLink);
  996. lpobj->hLink = NULL;
  997. }
  998. ContextCallBack ((LPOLEOBJECT)lpobj, OLE_RENAMED);
  999. }
  1000. BOOL INTERNAL CanCallback (
  1001. LPOBJECT_LE lpobj,
  1002. int options
  1003. ){
  1004. LPINT lpCount;
  1005. if (options == OLE_CLOSED) {
  1006. lpobj->bSvrClosing = TRUE;
  1007. lpCount = &(lpobj->pDocEdit->nAdviseClose);
  1008. }
  1009. else if (options == OLE_SAVED) {
  1010. if (lpobj->head.ctype == CT_LINK)
  1011. return TRUE;
  1012. lpCount = &(lpobj->pDocEdit->nAdviseSave);
  1013. }
  1014. else {
  1015. // it must be due to request
  1016. if ((lpobj->pDocEdit->awaitAck == AA_REQUEST)
  1017. && lpobj->pDocEdit->bCallLater)
  1018. return FALSE;
  1019. return TRUE;
  1020. }
  1021. switch (*lpCount) {
  1022. case 1:
  1023. break;
  1024. case 2:
  1025. ++(*lpCount);
  1026. return FALSE;
  1027. case 3:
  1028. --(*lpCount);
  1029. break;
  1030. default:
  1031. return FALSE;
  1032. }
  1033. return TRUE;
  1034. }
  1035. void FARINTERNAL CallEmbLnkDelete (
  1036. LPOBJECT_LE lpobj
  1037. ){
  1038. InitAsyncCmd (lpobj, OLE_SERVERUNLAUNCH,EMBLNKDELETE);
  1039. EmbLnkDelete (lpobj);
  1040. if (lpobj->head.ctype == CT_EMBEDDED) {
  1041. lpobj->bSvrClosing = TRUE;
  1042. ContextCallBack ((LPOLEOBJECT)lpobj, OLE_CLOSED);
  1043. if (FarCheckObject ((LPOLEOBJECT)lpobj))
  1044. lpobj->bSvrClosing = FALSE;
  1045. }
  1046. }