Leaked source code of windows server 2003
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.

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