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.

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