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.

2916 lines
80 KiB

  1. /*****************************************************************************
  2. C L I P B O O K U T I L I T I E S
  3. Name: cvutil.c
  4. Date: 21-Jan-1994
  5. Creator: Unknown
  6. Description:
  7. Utility functions for clipbook viewer.
  8. *****************************************************************************/
  9. #define WIN31
  10. #define STRICT
  11. #include <windows.h>
  12. #include <windowsx.h>
  13. #include <commctrl.h>
  14. #include <assert.h>
  15. #include <memory.h>
  16. #include <stdio.h>
  17. #include <strsafe.h>
  18. #include "common.h"
  19. #include "clipbook.h"
  20. #include "clipbrd.h"
  21. #include "clipdsp.h"
  22. #include "cvinit.h"
  23. #include "cvutil.h"
  24. #include "dib.h"
  25. #include "strtok.h"
  26. #include "initmenu.h"
  27. #include "debugout.h"
  28. DWORD gXERR_Type = 0;
  29. DWORD gXERR_Err = 0;
  30. HSZ hszErrorRequest = 0;
  31. #if DEBUG
  32. static void DumpDataReq (PDATAREQ pdr);
  33. static void DumpDataReq(
  34. PDATAREQ pdr)
  35. {
  36. PINFO(TEXT("Datareq: type %d, to window %lx, \r\nat index %u, fDisc=%u, format=%u\r\n"),
  37. pdr->rqType,
  38. pdr->hwndMDI,
  39. pdr->iListbox,
  40. pdr->fDisconnect,
  41. pdr->wFmt);
  42. }
  43. #else
  44. #define DumpDataReq(x)
  45. #endif
  46. // AdjustControlSizes //////////////////
  47. //
  48. // This function sizes the listbox windows associated
  49. // with an MDI child window when its size changes
  50. VOID AdjustControlSizes (
  51. HWND hwnd)
  52. {
  53. RECT rc1, rc2;
  54. PMDIINFO pMDI;
  55. int cx = GetSystemMetrics ( SM_CXVSCROLL );
  56. int cy = GetSystemMetrics ( SM_CYHSCROLL );
  57. if (!(pMDI = GETMDIINFO(hwnd)))
  58. return;
  59. GetClientRect ( hwnd, &rc1 );
  60. rc2 = rc1;
  61. rc2.right -= cx - 1;
  62. rc2.bottom -= cy - 1;
  63. switch ( pMDI->DisplayMode )
  64. {
  65. case DSP_LIST:
  66. case DSP_PREV:
  67. MoveWindow ( pMDI->hWndListbox, rc1.left - 1, rc1.top - 1,
  68. rc1.right - rc1.left + 2, ( rc1.bottom - rc1.top ) + 2, TRUE );
  69. break;
  70. case DSP_PAGE:
  71. MoveWindow (pMDI->hwndHscroll,
  72. rc1.left - 1,
  73. rc2.bottom,
  74. (rc2.right - rc2.left) +2,
  75. cy,
  76. TRUE );
  77. if ( pMDI->flags & F_CLPBRD ) {
  78. MoveWindow ( pMDI->hwndVscroll, rc2.right, rc1.top - 1,
  79. cx, ( rc2.bottom - rc2.top ) + 2, TRUE );
  80. }
  81. else
  82. {
  83. MoveWindow ( pMDI->hwndVscroll, rc2.right, rc1.top - 1,
  84. cx, ( rc2.bottom - rc2.top ) + 2 - 2*cy, TRUE );
  85. }
  86. MoveWindow ( pMDI->hwndSizeBox, rc2.right, rc2.bottom, cx, cy, TRUE );
  87. if ( ! ( pMDI->flags & F_CLPBRD ) )
  88. {
  89. MoveWindow ( pMDI->hwndPgUp, rc2.right,
  90. rc2.bottom + 1 - 2*cy, cx, cy, TRUE );
  91. MoveWindow ( pMDI->hwndPgDown, rc2.right,
  92. rc2.bottom + 1 - cy, cx, cy, TRUE );
  93. }
  94. // adjust display window
  95. pMDI->rcWindow = rc2;
  96. break;
  97. }
  98. }
  99. VOID ShowHideControls (
  100. HWND hwnd)
  101. {
  102. PMDIINFO pMDI;
  103. int nShowScroll;
  104. int nShowList;
  105. if (!(pMDI = GETMDIINFO(hwnd)))
  106. return;
  107. switch ( pMDI->DisplayMode )
  108. {
  109. case DSP_PREV:
  110. case DSP_LIST:
  111. nShowScroll = SW_HIDE;
  112. nShowList = SW_SHOW;
  113. break;
  114. case DSP_PAGE:
  115. if ( GetBestFormat( hwnd, pMDI->CurSelFormat) != CF_OWNERDISPLAY )
  116. nShowScroll = SW_SHOW;
  117. else
  118. {
  119. nShowScroll = SW_HIDE;
  120. ShowScrollBar ( hwnd, SB_BOTH, TRUE );
  121. }
  122. nShowList = SW_HIDE;
  123. break;
  124. }
  125. ShowWindow ( pMDI->hWndListbox, nShowList );
  126. ShowWindow ( pMDI->hwndVscroll, nShowScroll );
  127. ShowWindow ( pMDI->hwndHscroll, nShowScroll );
  128. ShowWindow ( pMDI->hwndSizeBox, nShowScroll );
  129. ShowWindow ( pMDI->hwndPgUp, (pMDI->flags & F_CLPBRD)? SW_HIDE: nShowScroll );
  130. ShowWindow ( pMDI->hwndPgDown, (pMDI->flags & F_CLPBRD)? SW_HIDE: nShowScroll );
  131. }
  132. // AssertConnection /////////////////
  133. BOOL AssertConnection (
  134. HWND hwnd)
  135. {
  136. PMDIINFO pMDI;
  137. if (!(pMDI = GETMDIINFO(hwnd)))
  138. return FALSE;
  139. if (IsWindow(hwnd))
  140. {
  141. if (pMDI->hExeConv ||
  142. (pMDI->hExeConv = InitSysConv (hwnd,
  143. pMDI->hszConvPartner,
  144. hszClpBookShare,
  145. FALSE))
  146. )
  147. {
  148. return TRUE;
  149. }
  150. }
  151. return FALSE;
  152. }
  153. // InitSysConv ////////////////////////
  154. //
  155. // Purpose: Establishes a conversation with the given app and topic.
  156. //
  157. // Parameters:
  158. // hwnd - MDI child window to own this conversation
  159. // hszApp - App name to connect to
  160. // hszTopic - Topic to connect to
  161. // fLocal - Ignored.
  162. //
  163. // Returns: Handle to the conversation (0L if no conv. could be established).
  164. //
  165. HCONV InitSysConv (
  166. HWND hwnd,
  167. HSZ hszApp,
  168. HSZ hszTopic,
  169. BOOL fLocal )
  170. {
  171. HCONV hConv = 0L;
  172. PDATAREQ pDataReq;
  173. DWORD dwErr;
  174. #if DEBUG
  175. TCHAR atchApp[256];
  176. TCHAR atchTopic[256];
  177. if (DdeQueryString(idInst, hszApp, atchApp,
  178. sizeof(atchApp), CP_WINANSI) &&
  179. DdeQueryString(idInst, hszTopic, atchTopic,
  180. sizeof(atchTopic), CP_WINANSI))
  181. {
  182. PINFO(TEXT("InitSysConv: [%s | %s]\r\n"), atchApp, atchTopic);
  183. }
  184. else
  185. {
  186. PERROR(TEXT("I don't know my app/topic pair!\r\n"));
  187. }
  188. #endif
  189. if (LockApp (TRUE, szEstablishingConn))
  190. {
  191. hConv = DdeConnect ( idInst, hszApp, hszTopic, NULL );
  192. if (!hConv)
  193. {
  194. dwErr = DdeGetLastError(idInst);
  195. PINFO(TEXT("Failed first try at CLIPSRV, #%x\r\n"), dwErr);
  196. if (GetSystemMetrics(SM_REMOTESESSION) )
  197. {
  198. MessageBoxID (hInst, hwnd, IDS_TSNOTSUPPORTED, IDS_APPNAME, MB_OK | MB_ICONHAND);
  199. }
  200. else
  201. {
  202. MessageBoxID (hInst, hwnd, IDS_NOCLPBOOK, IDS_APPNAME, MB_OK | MB_ICONHAND);
  203. }
  204. }
  205. else
  206. {
  207. PINFO(TEXT("Making datareq."));
  208. if ( pDataReq = CreateNewDataReq() )
  209. {
  210. pDataReq->rqType = RQ_EXECONV;
  211. pDataReq->hwndMDI = hwnd;
  212. pDataReq->wFmt = CF_TEXT;
  213. DdeSetUserHandle ( hConv, (DWORD)QID_SYNC, (DWORD_PTR)pDataReq );
  214. Sleep(3000);
  215. PINFO(TEXT("Entering AdvStart transaction "));
  216. if (!MySyncXact ( NULL, 0L, hConv, hszTopics,
  217. CF_TEXT, XTYP_ADVSTART, LONG_SYNC_TIMEOUT, NULL ))
  218. {
  219. XactMessageBox (hInst, hwnd, IDS_APPNAME, MB_OK | MB_ICONEXCLAMATION);
  220. }
  221. }
  222. else
  223. {
  224. PERROR(TEXT("InitSysConv:Could not create data req\r\n"));
  225. }
  226. }
  227. LockApp ( FALSE, szNull );
  228. }
  229. else
  230. {
  231. PERROR(TEXT("app locked in initsysconv\n\r"));
  232. }
  233. return hConv;
  234. }
  235. // UpdateListBox ////////////////////////////
  236. //
  237. // This function updates the contents of a listbox
  238. // given the window handle of the MDI child window
  239. // and the conversation over which the data is to be
  240. // obtained
  241. BOOL UpdateListBox(
  242. HWND hwnd,
  243. HCONV hConv)
  244. {
  245. HDDEDATA hData;
  246. BOOL fOK = TRUE;
  247. if ( hConv == 0L || !IsWindow( hwnd ))
  248. {
  249. PERROR(TEXT("UpdateListBox called with garbage\n\r"));
  250. fOK = FALSE;
  251. }
  252. else
  253. {
  254. if (GETMDIINFO(hwnd) && GETMDIINFO(hwnd)->flags & F_LOCAL)
  255. {
  256. PINFO(TEXT("Getting all topics\r\n"));
  257. }
  258. else
  259. {
  260. PINFO(TEXT("Getting shared topics\r\n"));
  261. }
  262. // ask clipsrv to initialize shares
  263. MySyncXact (SZCMD_INITSHARE,
  264. sizeof (SZCMD_INITSHARE),
  265. hConv,
  266. 0L,
  267. CF_TEXT,
  268. XTYP_EXECUTE,
  269. SHORT_SYNC_TIMEOUT,
  270. NULL);
  271. //get the data
  272. hData = MySyncXact (NULL,
  273. 0L,
  274. hConv,
  275. hszTopics,
  276. CF_TEXT,
  277. XTYP_REQUEST,
  278. SHORT_SYNC_TIMEOUT,
  279. NULL );
  280. if ( !hData )
  281. {
  282. XactMessageBox (hInst,
  283. hwnd,
  284. IDS_APPNAME,
  285. MB_OK | MB_ICONEXCLAMATION);
  286. fOK = FALSE;
  287. }
  288. else
  289. {
  290. fOK = InitListBox ( hwnd, hData );
  291. }
  292. }
  293. return fOK;
  294. }
  295. // GetPreviewBitmap //////////////////////////////
  296. // Informs CLIPSRV via DDE that we need a preview bitmap
  297. // for the given page.
  298. //
  299. // Parameters:
  300. // hwnd - Clipbook window which wants the bitmap
  301. // szName - Name of the clipbook page.
  302. // index - Page's index within the listbox in hwnd
  303. //
  304. // Returns:
  305. // void.
  306. //
  307. BOOL GetPreviewBitmap (
  308. HWND hwnd,
  309. LPTSTR szName,
  310. UINT index)
  311. {
  312. HSZ hszTopic, hszItem = 0L;
  313. HCONV hConv;
  314. HDDEDATA hRet;
  315. PDATAREQ pDataReq;
  316. BOOL fLocked;
  317. TCHAR tchTmp;
  318. if (WAIT_TIMEOUT == WaitForSingleObject (hXacting, 0))
  319. return FALSE;
  320. fLocked = LockApp (TRUE, NULL);
  321. tchTmp = szName[0];
  322. szName[0] = SHR_CHAR;
  323. if (0 == (hszTopic = DdeCreateStringHandle (idInst, szName, 0)))
  324. {
  325. PERROR(TEXT("GetPreviewBitmap: no topic handle\n\r"));
  326. goto done;
  327. }
  328. if (0 == (hszItem = DdeCreateStringHandle (idInst, SZPREVNAME, 0)))
  329. {
  330. PERROR(TEXT("GetPreviewBitmap: no item handle\n\r"));
  331. goto done;
  332. }
  333. if (!GETMDIINFO(hwnd))
  334. {
  335. PERROR(TEXT("GETMDIINFO(hwnd) -> NULL\n\r"));
  336. goto done;
  337. }
  338. if (NULL == (pDataReq = CreateNewDataReq()))
  339. {
  340. PERROR(TEXT("GetPreviewBitmap: no pdatareq\n\r"));
  341. goto done;
  342. }
  343. #if DEBUG
  344. {
  345. TCHAR atch[64];
  346. DdeQueryString(idInst, GETMDIINFO(hwnd)->hszConvPartnerNP,
  347. atch, 64, CP_WINANSI);
  348. PINFO(TEXT("GetPrevBmp: Connecting [%s | %s ! %s]\r\n"),
  349. atch, szName, SZPREVNAME);
  350. }
  351. #endif
  352. //
  353. // Let's try to connect up to ten times. Sometimes when updating
  354. // the thumbnails if the user changes a page, the server will be
  355. // busy doing that and we can't connect here. So, at least try
  356. // a few times.
  357. //
  358. {
  359. INT trycnt = 0;
  360. hConv = 0L;
  361. while (trycnt < 10 && !hConv)
  362. {
  363. hConv = DdeConnect (idInst, GETMDIINFO(hwnd)->hszConvPartnerNP, hszTopic, NULL);
  364. trycnt++;
  365. if (hConv) continue;
  366. PINFO (TEXT("GetPreviewBitmap: trying to connect again\r\n"));
  367. Sleep (200);
  368. }
  369. }
  370. if (hConv)
  371. {
  372. DWORD adwTrust[3];
  373. BOOL fLocal = FALSE;
  374. if (GETMDIINFO(hwnd)->flags & F_LOCAL)
  375. {
  376. fLocal = TRUE;
  377. if (NDDE_NO_ERROR != NDdeGetTrustedShare(NULL, szName,
  378. adwTrust, adwTrust + 1, adwTrust + 2))
  379. {
  380. adwTrust[0] = 0L;
  381. }
  382. NDdeSetTrustedShare (NULL,
  383. szName,
  384. adwTrust[0] | NDDE_TRUST_SHARE_INIT);
  385. }
  386. pDataReq->rqType = RQ_PREVBITMAP;
  387. pDataReq->hwndList = GETMDIINFO(hwnd)->hWndListbox;
  388. pDataReq->iListbox = index;
  389. pDataReq->hwndMDI = hwnd;
  390. pDataReq->fDisconnect = TRUE;
  391. pDataReq->wFmt = (WORD)cf_preview;
  392. pDataReq->wRetryCnt = 3;
  393. {
  394. /**** disable all edit function ****/
  395. /**** will enable in after callback ****/
  396. // If the user does a paste or make some changes to the pages while
  397. // clipbrd is waiting for the xaction to complete, sometimes we get
  398. // a popup says there's a problem with connection (or something similar)
  399. // It seems there's some dirty code is causing this. Below is a temp
  400. // fix which works well on fast machines. On slower machines it may
  401. // still fail at times. A better fix may be not to use async at all.
  402. //
  403. // NOTE: If there's multiple requests, one may complete while we're still
  404. // waitng for another. This will cause the EDIT functions to be enabled
  405. // while we are still waiting.
  406. HANDLE hmenu;
  407. hmenu = GetMenu (hwndApp);
  408. EnableMenuItem (hmenu, IDM_COPY, MF_GRAYED | MF_BYCOMMAND);
  409. EnableMenuItem (hmenu, IDM_KEEP, MF_GRAYED | MF_BYCOMMAND);
  410. EnableMenuItem (hmenu, IDM_PASTE_PAGE, MF_GRAYED | MF_BYCOMMAND);
  411. EnableMenuItem (hmenu, IDM_DELETE, MF_GRAYED | MF_BYCOMMAND);
  412. SendMessage (hwndToolbar, TB_ENABLEBUTTON, IDM_COPY, FALSE);
  413. SendMessage (hwndToolbar, TB_ENABLEBUTTON, IDM_KEEP, FALSE);
  414. SendMessage (hwndToolbar, TB_ENABLEBUTTON, IDM_DELETE, FALSE);
  415. }
  416. hRet = DdeClientTransaction (NULL,
  417. 0L,
  418. hConv,
  419. hszItem,
  420. cf_preview,
  421. XTYP_REQUEST,
  422. (DWORD)TIMEOUT_ASYNC,
  423. NULL);
  424. if ( !hRet )
  425. {
  426. unsigned uiErr;
  427. uiErr = DdeGetLastError (idInst);
  428. PERROR(TEXT("GetPreviewBitmap: Async Transaction for (%s) failed:%x\n\r"),
  429. szName, uiErr);
  430. }
  431. DdeSetUserHandle ( hConv, (DWORD)QID_SYNC, (DWORD_PTR)pDataReq );
  432. }
  433. #if DEBUG
  434. else
  435. {
  436. unsigned uiErr;
  437. uiErr = DdeGetLastError(idInst);
  438. DdeQueryString(idInst, GETMDIINFO(hwnd)->hszConvPartner,
  439. szBuf, 128, CP_WINANSI );
  440. PERROR(TEXT("GetPreviewBitmap: connect to %lx|%lx (%s|%s) failed: %d\n\r"),
  441. GETMDIINFO(hwnd)->hszConvPartner, hszTopic,
  442. (LPTSTR)szBuf, (LPTSTR)szName, uiErr);
  443. }
  444. #endif
  445. done:
  446. if (!hszTopic)
  447. DdeFreeStringHandle (idInst, hszTopic);
  448. if (!hszItem)
  449. DdeFreeStringHandle ( idInst, hszItem );
  450. if (fLocked)
  451. LockApp (FALSE, NULL);
  452. szName[0] = tchTmp;
  453. SetEvent (hXacting);
  454. return TRUE;
  455. }
  456. VOID SetBitmapToListboxEntry (
  457. HDDEDATA hbmp,
  458. HWND hwndList,
  459. UINT index)
  460. {
  461. LPLISTENTRY lpLE;
  462. RECT rc;
  463. HBITMAP hBitmap;
  464. LPBYTE lpBitData;
  465. DWORD cbDataLen;
  466. unsigned uiErr;
  467. #if DEBUG
  468. uiErr = DdeGetLastError(idInst);
  469. if (uiErr)
  470. {
  471. PINFO(TEXT("SBmp2LBEntr: %d\r\n"), uiErr);
  472. }
  473. #endif
  474. if (!IsWindow (hwndList)
  475. || SendMessage (hwndList, LB_GETTEXT, index, (LPARAM)(LPCSTR)&lpLE) == LB_ERR
  476. || SendMessage (hwndList, LB_GETITEMRECT, index, (LPARAM)(LPRECT)&rc) == LB_ERR)
  477. {
  478. DdeFreeDataHandle(hbmp);
  479. PERROR(TEXT("SetBitmapToListboxEntry: bad window: %x\n\r"), hwndList);
  480. }
  481. else
  482. {
  483. if (hbmp)
  484. {
  485. if ( lpBitData = DdeAccessData ( hbmp, &cbDataLen ))
  486. {
  487. // create the preview bitmap
  488. hBitmap = CreateBitmap (PREVBMPSIZ,PREVBMPSIZ,1,1, lpBitData);
  489. DdeUnaccessData ( hbmp );
  490. }
  491. else
  492. {
  493. PERROR(TEXT("SB2LB: Couldn't access data!\r\n"));
  494. hBitmap = NULL;
  495. }
  496. DdeFreeDataHandle ( hbmp );
  497. lpLE->hbmp = hBitmap;
  498. PINFO(TEXT("Successfully set bmp.\r\n"));
  499. }
  500. PINFO(TEXT("Invalidating (%d,%d)-(%d,%d)\r\n"),rc.left, rc.top,
  501. rc.right, rc.bottom);
  502. InvalidateRect ( hwndList, &rc, TRUE );
  503. }
  504. uiErr = DdeGetLastError(idInst);
  505. if (uiErr)
  506. {
  507. PINFO (TEXT("SBmp2LBEntr: exit err %d\r\n"), uiErr);
  508. }
  509. }
  510. /*
  511. * UpdatePage
  512. *
  513. * When user paste into an existing page, the first item
  514. * in szList is the share name of the page pasted. Since
  515. * the name did not change, we need to do some special
  516. * processing to update the display.
  517. *
  518. */
  519. BOOL UpdatePage (HWND hwnd, LPTSTR szList)
  520. {
  521. PMDIINFO pMDI;
  522. PLISTENTRY pLE;
  523. TCHAR szPageBuf[MAX_NDDESHARENAME+1];
  524. LPTSTR szPage = szPageBuf;
  525. RECT Rect;
  526. INT i;
  527. *szPage = TEXT('\0');
  528. // does the first item in szList spcifies
  529. // an updated page?
  530. if (BOGUS_CHAR != *szList)
  531. return FALSE;
  532. // get the share name
  533. szList++;
  534. while (*szList && TEXT('\t') != *szList)
  535. *szPage++ = *szList++;
  536. *szPage = TEXT('\0');
  537. // Find the page, notice the name comparison below does not
  538. // compare the first char. This is because the updated page's
  539. // share state may have changed so the first char won't match.
  540. pMDI = GETMDIINFO(hwnd);
  541. for (i=0;
  542. LB_ERR != SendMessage(pMDI->hWndListbox, LB_GETTEXT, i, (LPARAM)&pLE);
  543. i++)
  544. {
  545. if (pLE)
  546. if (!lstrcmpiA(pLE->name+1, szPageBuf+1))
  547. {
  548. goto update;
  549. }
  550. }
  551. return FALSE;
  552. update:
  553. // invalidate the preview bitmap
  554. SendMessage (pMDI->hWndListbox, LB_GETITEMRECT, i, (LPARAM)&Rect);
  555. if (pLE->hbmp)
  556. DeleteObject (pLE->hbmp);
  557. pLE->fTriedGettingPreview = FALSE;
  558. pLE->hbmp = NULL;
  559. InvalidateRect (pMDI->hWndListbox, &Rect, FALSE);
  560. // if in page view and the page is the one currently
  561. // selected then update the page view
  562. if (DSP_PAGE == pMDI->DisplayMode)
  563. if (SendMessage (pMDI->hWndListbox, LB_GETCURSEL, 0, 0) == i)
  564. PostMessage (hwndApp, WM_COMMAND, IDM_UPDATE_PAGEVIEW, 0L);
  565. return TRUE;
  566. }
  567. // InitListBox //////////////////////////////////
  568. //
  569. // this function initializes the entries of a listbox
  570. // given the handle of the MDI child window that owns
  571. // the list box and a ddeml data handle that contains the
  572. // tab-separated list of items that are to appear in the
  573. // listbox
  574. // Right now, this deletes all entries in the list and
  575. // then recreates them. It would be more efficient to add or
  576. // delete only those items that have changed. This would save
  577. // CONSIDERABLE time in thumbnail mode-- now, we have to
  578. // establish a new DDE conversation with the server for each
  579. // page, just to get the thumbnail bitmap.
  580. BOOL InitListBox (
  581. HWND hwnd,
  582. HDDEDATA hData )
  583. {
  584. PMDIINFO pMDI;
  585. PLISTENTRY pLE;
  586. LPTSTR lpszList, q;
  587. DWORD cbDataLen;
  588. HWND hwndlist;
  589. int OldCount;
  590. int NewCount;
  591. int OldSel;
  592. LPTSTR OldSelString;
  593. BOOL OldStringDeleted;
  594. int i;
  595. BOOL fDel;
  596. if ( hData == 0L || !IsWindow ( hwnd ) )
  597. {
  598. PERROR(TEXT("InitListBox called with garbage\n\r"));
  599. return FALSE;
  600. }
  601. // Get a copy of the data in the handle
  602. lpszList = (LPTSTR)DdeAccessData ( hData, &cbDataLen );
  603. DdeUnaccessData(hData);
  604. lpszList = GlobalAllocPtr(GHND, cbDataLen);
  605. DdeGetData(hData, lpszList, cbDataLen, 0L);
  606. // Sometimes, the data will be longer than the string. This
  607. // would make the 'put tabs back' code below fail if we didn't
  608. // do this.
  609. cbDataLen = lstrlen(lpszList);
  610. PINFO(TEXT("InitLB: %s \r\n"), lpszList);
  611. if (!lpszList)
  612. {
  613. PERROR(TEXT("error accessing data in InitListBox\n\r"));
  614. return FALSE;
  615. }
  616. if (!(pMDI = GETMDIINFO(hwnd)))
  617. return FALSE;
  618. if (!(hwndlist = GETMDIINFO(hwnd)->hWndListbox))
  619. return FALSE;
  620. SendMessage ( hwndlist, WM_SETREDRAW, 0, 0L );
  621. // let's update the page that was pasted into
  622. // an existing page.
  623. UpdatePage (hwnd, lpszList);
  624. OldCount = (int)SendMessage ( hwndlist, LB_GETCOUNT, 0, 0L );
  625. OldSel = (int)SendMessage ( hwndlist, LB_GETCURSEL, 0, 0L );
  626. OldSelString = (LPTSTR)SendMessage (hwndlist, LB_GETITEMDATA, OldSel, 0);
  627. OldStringDeleted = FALSE;
  628. // Delete items in list that don't exist anymore
  629. for (i = 0; i < OldCount; i++)
  630. {
  631. SendMessage (hwndlist, LB_GETTEXT, i, (LPARAM)&pLE);
  632. fDel = TRUE;
  633. if (pLE)
  634. {
  635. for (q = strtokA(lpszList, "\t"); q; q = strtokA(NULL, "\t"))
  636. {
  637. PINFO(TEXT("<%hs>"), q);
  638. if (0 == lstrcmpA(pLE->name, q))
  639. {
  640. fDel = FALSE;
  641. *q = BOGUS_CHAR;
  642. break;
  643. }
  644. }
  645. PINFO(TEXT("\r\n"));
  646. // Put back the tab chars that strtok ripped out
  647. for (q = lpszList;q < lpszList + cbDataLen;q++)
  648. {
  649. if ('\0' == *q)
  650. {
  651. *q = '\t';
  652. }
  653. }
  654. *q = '\0';
  655. PINFO(TEXT("Restored %hs\r\n"), lpszList);
  656. if (fDel)
  657. {
  658. PINFO(TEXT("Deleting item %s at pos %d\r\n"), pLE->name, i);
  659. pLE->fDelete = TRUE;
  660. if (OldSelString == (LPTSTR)pLE)
  661. {
  662. OldStringDeleted = TRUE;
  663. }
  664. SendMessage(hwndlist, LB_DELETESTRING, i, 0L);
  665. i--;
  666. if (OldCount)
  667. {
  668. OldCount--;
  669. }
  670. }
  671. }
  672. else
  673. {
  674. PERROR(TEXT("Got NULL pLE!\r\n"));
  675. }
  676. }
  677. // Add new items to list
  678. for (q = strtokA(lpszList, "\t"); q; q = strtokA(NULL, "\t"))
  679. {
  680. // only add shared items if remote, never re-add existing items
  681. if (BOGUS_CHAR != *q &&
  682. (( GETMDIINFO(hwnd)->flags & F_LOCAL ) || *q == SHR_CHAR ))
  683. {
  684. // allocate a new list entry...
  685. if ( ( pLE = (PLISTENTRY)GlobalAllocPtr ( GHND,
  686. sizeof ( LISTENTRY ))) != NULL )
  687. {
  688. // mark this item to be deleted in WM_DELETEITEM
  689. pLE->fDelete = TRUE;
  690. pLE->fTriedGettingPreview = FALSE;
  691. StringCchCopy(pLE->name, MAX_PAGENAME_LENGTH + 1, q);
  692. PINFO(TEXT("Adding item %s\r\n"), pLE->name);
  693. SendMessage(hwndlist, LB_ADDSTRING, 0, (LPARAM)(LPCSTR)pLE);
  694. }
  695. }
  696. }
  697. // Select the item at the same position we were at
  698. NewCount = (int)SendMessage (hwndlist, LB_GETCOUNT, 0, 0L);
  699. if (NewCount)
  700. if (OldCount == NewCount)
  701. {
  702. SendMessage (hwndlist,
  703. LB_SETCURSEL,
  704. OldSel,
  705. 0L);
  706. }
  707. else if ( (LB_ERR != (LRESULT)OldSelString) && (!OldStringDeleted) )
  708. {
  709. SendMessage (hwndlist,
  710. LB_SELECTSTRING,
  711. OldSel-1, // listbox is sorted
  712. (LPARAM)OldSelString);
  713. }
  714. SendMessage ( hwndlist, WM_SETREDRAW, 1, 0L );
  715. UpdateNofMStatus( hwnd );
  716. if (lpszList)
  717. GlobalFreePtr(lpszList);
  718. return TRUE;
  719. }
  720. // MyGetFormat ////////////////////////////
  721. //
  722. // this function returns the UINT ID of the
  723. // format matching the supplied string. This
  724. // is the reverse of the "getclipboardformatname" function.
  725. //
  726. // Note that the formats &Bitmap, &Picture and Pal&ette exist
  727. // both as predefined windows clipboard formats and as privately
  728. // registered formats. The integer switch passed to this function
  729. // determines whether the instrinsic format or the privately registered
  730. // format ID is returned
  731. //
  732. // GETFORMAT_DONTLIE return instrinsic format i.e. CF_BITMAP
  733. // GETFORMAT_LIE return registered format i.e. cf_bitmap
  734. UINT MyGetFormat(
  735. LPTSTR szFmt,
  736. int mode)
  737. {
  738. TCHAR szBuff[40];
  739. unsigned i;
  740. UINT uiPrivates[] = {CF_BITMAP,
  741. CF_METAFILEPICT,
  742. CF_PALETTE,
  743. CF_ENHMETAFILE,
  744. CF_DIB};
  745. PINFO("\nMyGetFormat [%s] %d:", szFmt, mode);
  746. for (i = 0; i <= CF_ENHMETAFILE; i++)
  747. {
  748. LoadString(hInst, i, szBuff, 40);
  749. if (!lstrcmp( szFmt, szBuff))
  750. {
  751. if (GETFORMAT_DONTLIE == mode)
  752. {
  753. PINFO(TEXT("No-lie fmt %d\r\n"), i);
  754. }
  755. else
  756. {
  757. unsigned j;
  758. for (j = 0;j <sizeof(uiPrivates)/sizeof(uiPrivates[0]);j++)
  759. {
  760. if (i == uiPrivates[j])
  761. {
  762. i = RegisterClipboardFormat(szBuff);
  763. break;
  764. }
  765. }
  766. }
  767. PINFO(TEXT("Format result %d\r\n"), i);
  768. return(i);
  769. }
  770. }
  771. for (i = CF_OWNERDISPLAY;i <= CF_DSPENHMETAFILE ;i++ )
  772. {
  773. LoadString(hInst, i, szBuff, 40);
  774. if (!lstrcmp( szFmt, szBuff))
  775. {
  776. if (GETFORMAT_DONTLIE != mode)
  777. {
  778. i = RegisterClipboardFormat(szBuff);
  779. }
  780. return(i);
  781. }
  782. }
  783. PINFO(TEXT("Registering format %s\n\r"), szFmt );
  784. return RegisterClipboardFormat ( szFmt );
  785. }
  786. // HandleOwnerDraw ////////////////////////////////
  787. //
  788. // This function handles drawing of owner draw buttons
  789. // and listboxes in this app.
  790. VOID HandleOwnerDraw(
  791. HWND hwnd,
  792. UINT msg,
  793. WPARAM wParam,
  794. LPARAM lParam)
  795. {
  796. LPDRAWITEMSTRUCT lpds;
  797. RECT tmprc;
  798. COLORREF OldTextColor;
  799. COLORREF OldBkColor;
  800. COLORREF BackColor;
  801. COLORREF TextColor;
  802. HBRUSH hBkBrush;
  803. DWORD cbData = 0L;
  804. LPLISTENTRY lpLE;
  805. BOOL fSel = FALSE;
  806. lpds = (LPDRAWITEMSTRUCT) lParam;
  807. // this section handles listbox drawing
  808. switch ( lpds->CtlID )
  809. {
  810. case ID_LISTBOX:
  811. if (!GETMDIINFO(hwnd))
  812. break;
  813. if ( GETMDIINFO(hwnd)->DisplayMode == DSP_LIST )
  814. {
  815. if ( lpds->itemAction & (ODA_DRAWENTIRE|ODA_SELECT|ODA_FOCUS))
  816. {
  817. if ( SendMessage ( GETMDIINFO(hwnd)->hWndListbox, LB_GETTEXT,
  818. lpds->itemID, (LPARAM)(LPCSTR)&lpLE ) == LB_ERR )
  819. {
  820. return;
  821. }
  822. hOldBitmap = SelectObject ( hBtnDC, hbmStatus );
  823. tmprc = lpds->rcItem;
  824. if ( lpds->itemState & ODS_SELECTED &&
  825. lpds->itemState & ODS_FOCUS )
  826. {
  827. TextColor = GetSysColor ( COLOR_HIGHLIGHTTEXT );
  828. BackColor = GetSysColor ( COLOR_HIGHLIGHT );
  829. }
  830. else
  831. {
  832. TextColor = GetSysColor ( COLOR_WINDOWTEXT );
  833. BackColor = GetSysColor ( COLOR_WINDOW );
  834. }
  835. OldTextColor = SetTextColor ( lpds->hDC, TextColor );
  836. OldBkColor = SetBkColor ( lpds->hDC, BackColor );
  837. hBkBrush = CreateSolidBrush ( BackColor );
  838. if ( hBkBrush )
  839. FillRect ( lpds->hDC, &tmprc, hBkBrush );
  840. DeleteObject ( hBkBrush );
  841. hOldFont = SelectObject ( lpds->hDC, hFontPreview );
  842. TextOut (lpds->hDC,
  843. lpds->rcItem.left + 2 * LSTBTDX,
  844. lpds->rcItem.top+1,
  845. &(lpLE->name[1]),
  846. lstrlen((lpLE->name)) - 1);
  847. SelectObject ( lpds->hDC, hOldFont );
  848. if ( IsShared( lpLE ) && fShareEnabled )
  849. {
  850. BitBlt ( lpds->hDC, lpds->rcItem.left + ( LSTBTDX / 2 ),
  851. lpds->rcItem.top, LSTBTDX, LSTBTDY,
  852. hBtnDC,
  853. SHR_PICT_X,
  854. SHR_PICT_Y +
  855. (( lpds->itemState & ODS_SELECTED ) &&
  856. ( lpds->itemState & ODS_FOCUS ) ? 0 : LSTBTDY ),
  857. SRCCOPY );
  858. }
  859. else
  860. {
  861. BitBlt ( lpds->hDC, lpds->rcItem.left + ( LSTBTDX / 2 ),
  862. lpds->rcItem.top, LSTBTDX, LSTBTDY,
  863. hBtnDC,
  864. SAV_PICT_X,
  865. SAV_PICT_Y +
  866. (( lpds->itemState & ODS_SELECTED ) &&
  867. ( lpds->itemState & ODS_FOCUS ) ? 0 : LSTBTDY ),
  868. SRCCOPY );
  869. }
  870. SelectObject ( hBtnDC, hOldBitmap );
  871. SetTextColor ( lpds->hDC, OldTextColor );
  872. SetBkColor ( lpds->hDC, OldBkColor );
  873. if ( lpds->itemAction & ODA_FOCUS &&
  874. lpds->itemState & ODS_FOCUS )
  875. {
  876. DrawFocusRect ( lpds->hDC, &(lpds->rcItem) );
  877. }
  878. }
  879. }
  880. else if ( GETMDIINFO(hwnd)->DisplayMode == DSP_PREV )
  881. {
  882. if ( lpds->itemAction & ODA_FOCUS )
  883. {
  884. DrawFocusRect ( lpds->hDC, &(lpds->rcItem) );
  885. }
  886. if ( SendMessage ( GETMDIINFO(hwnd)->hWndListbox, LB_GETTEXT,
  887. lpds->itemID, (LPARAM)(LPCSTR)&lpLE ) == LB_ERR )
  888. {
  889. return;
  890. }
  891. if ( lpds->itemAction & ODA_DRAWENTIRE )
  892. {
  893. // erase any bogus leftover focusrect
  894. if ( hBkBrush = CreateSolidBrush ( GetSysColor(COLOR_WINDOW)))
  895. {
  896. FillRect ( lpds->hDC, &(lpds->rcItem), hBkBrush );
  897. DeleteObject ( hBkBrush );
  898. }
  899. tmprc.top = lpds->rcItem.top + PREVBRD;
  900. tmprc.bottom = lpds->rcItem.top + PREVBRD + PREVBMPSIZ;
  901. tmprc.left = lpds->rcItem.left + 5 * PREVBRD;
  902. tmprc.right = lpds->rcItem.right - 5 * PREVBRD;
  903. Rectangle (lpds->hDC,
  904. tmprc.left,
  905. tmprc.top,
  906. tmprc.right,
  907. tmprc.bottom );
  908. // draw preview bitmap if available
  909. if (lpLE->hbmp == NULL)
  910. {
  911. if (!lpLE->fTriedGettingPreview)
  912. {
  913. if (!GetPreviewBitmap (hwnd,
  914. lpLE->name,
  915. lpds->itemID))
  916. {
  917. lpLE->fTriedGettingPreview = FALSE;
  918. InvalidateRect (lpds->hwndItem,
  919. &(lpds->rcItem),
  920. FALSE);
  921. break;
  922. }
  923. else
  924. {
  925. lpLE->fTriedGettingPreview = TRUE;
  926. }
  927. }
  928. else
  929. {
  930. DrawIcon ( lpds->hDC,
  931. // the magic '19' below is a function of the icon
  932. tmprc.left + PREVBMPSIZ - 19,
  933. tmprc.top,
  934. hicLock);
  935. }
  936. }
  937. else
  938. {
  939. hOldBitmap = SelectObject ( hBtnDC, lpLE->hbmp );
  940. BitBlt ( lpds->hDC, tmprc.left+1, tmprc.top+1,
  941. ( tmprc.right - tmprc.left ) - 2,
  942. ( tmprc.bottom - tmprc.top ) - 2,
  943. hBtnDC, 0, 0, SRCCOPY );
  944. SelectObject ( hBtnDC, hOldBitmap );
  945. }
  946. // draw share icon in corner...
  947. if ( IsShared ( lpLE ) && fShareEnabled )
  948. {
  949. DrawIcon (lpds->hDC,
  950. tmprc.left - 10,
  951. tmprc.top + PREVBMPSIZ - 24,
  952. LoadIcon ( hInst, MAKEINTRESOURCE(IDSHAREICON)));
  953. }
  954. }
  955. if ( lpds->itemAction & ( ODA_SELECT | ODA_DRAWENTIRE | ODA_FOCUS ))
  956. {
  957. tmprc = lpds->rcItem;
  958. tmprc.left += PREVBRD;
  959. tmprc.right -= PREVBRD;
  960. tmprc.top += PREVBMPSIZ + 2 * PREVBRD;
  961. tmprc.bottom--;
  962. if ((lpds->itemState & ODS_SELECTED) &&
  963. (lpds->itemState & ODS_FOCUS))
  964. {
  965. TextColor = GetSysColor ( COLOR_HIGHLIGHTTEXT );
  966. BackColor = GetSysColor ( COLOR_HIGHLIGHT );
  967. }
  968. else
  969. {
  970. TextColor = GetSysColor ( COLOR_WINDOWTEXT );
  971. BackColor = GetSysColor ( COLOR_WINDOW );
  972. }
  973. OldTextColor = SetTextColor ( lpds->hDC, TextColor );
  974. OldBkColor = SetBkColor ( lpds->hDC, BackColor );
  975. hOldFont = SelectObject ( lpds->hDC, hFontPreview );
  976. if ( hBkBrush = CreateSolidBrush ( BackColor ))
  977. {
  978. FillRect ( lpds->hDC, &tmprc, hBkBrush );
  979. DeleteObject ( hBkBrush );
  980. }
  981. DrawText (lpds->hDC,
  982. &(lpLE->name[1]),
  983. lstrlen(lpLE->name) -1,
  984. &tmprc,
  985. DT_CENTER | DT_WORDBREAK | DT_NOPREFIX );
  986. SetTextColor ( lpds->hDC, OldTextColor );
  987. SetBkColor ( lpds->hDC, OldBkColor );
  988. SelectObject ( lpds->hDC, hOldFont );
  989. }
  990. }
  991. break;
  992. case ID_PAGEUP:
  993. case ID_PAGEDOWN:
  994. if (lpds->itemAction & (ODA_SELECT | ODA_DRAWENTIRE))
  995. {
  996. if (lpds->itemState & ODS_SELECTED)
  997. hOldBitmap = SelectObject (hBtnDC,
  998. (lpds->CtlID==ID_PAGEUP)? hPgUpDBmp: hPgDnDBmp);
  999. else
  1000. hOldBitmap = SelectObject (hBtnDC,
  1001. (lpds->CtlID==ID_PAGEUP)? hPgUpBmp: hPgDnBmp);
  1002. StretchBlt (lpds->hDC,
  1003. lpds->rcItem.top,
  1004. lpds->rcItem.left,
  1005. GetSystemMetrics (SM_CXVSCROLL),
  1006. GetSystemMetrics (SM_CYHSCROLL),
  1007. hBtnDC,
  1008. 0,
  1009. 0,
  1010. 17, // x and y of resource bitmaps
  1011. 17,
  1012. SRCCOPY);
  1013. SelectObject (hBtnDC, hOldBitmap);
  1014. }
  1015. break;
  1016. default:
  1017. PERROR(TEXT("spurious WM_DRAWITEM ctlID %x\n\r"), lpds->CtlID );
  1018. break;
  1019. }
  1020. }
  1021. // CreateNewListBox ///////////////////////////////
  1022. //
  1023. // this function creates a new ownerdraw listbox in one of
  1024. // two styles suitable for this app: multicolumn for the
  1025. // preview bitmap display, and single column for the description
  1026. // display preceeded by the little clipboard entry icons
  1027. HWND CreateNewListBox(
  1028. HWND hwnd,
  1029. DWORD style)
  1030. {
  1031. HWND hLB;
  1032. hLB = CreateWindow (TEXT("listbox"),
  1033. szNull,
  1034. WS_CHILD | LBS_STANDARD | LBS_NOINTEGRALHEIGHT | style,
  1035. 0,
  1036. 0,
  1037. 100,
  1038. 100,
  1039. hwnd,
  1040. (HMENU)ID_LISTBOX,
  1041. hInst,
  1042. 0L );
  1043. if ( style & LBS_MULTICOLUMN )
  1044. SendMessage ( hLB, LB_SETCOLUMNWIDTH, PREVBMPSIZ + 10*PREVBRD, 0L );
  1045. return hLB;
  1046. }
  1047. // SetClipboardFormatFromDDE ///////////////////////////
  1048. //
  1049. // This function accepts a ddeml data handle and uses the
  1050. // data contained in it to set the clipboard data in the specified
  1051. // format to the virtual clipboard associated with the supplied MDI
  1052. // child window handle. This could be the real clipboard if the MDI
  1053. // child window handle refers to the clipboard child window.
  1054. BOOL SetClipboardFormatFromDDE(
  1055. HWND hwnd,
  1056. UINT uiFmt,
  1057. HDDEDATA hDDE)
  1058. {
  1059. HANDLE hBitmap;
  1060. HANDLE hData;
  1061. LPBYTE lpData;
  1062. LPBYTE lpSrc;
  1063. BITMAP bitmap;
  1064. HPALETTE hPalette;
  1065. LPLOGPALETTE lpLogPalette;
  1066. DWORD cbData;
  1067. int err;
  1068. BOOL fOK = FALSE;
  1069. PINFO("SetClpFmtDDE: format %d, handle %ld | ", uiFmt, hDDE);
  1070. // Check for existing errors, clear the error flag
  1071. err = DdeGetLastError(idInst);
  1072. if (err != DMLERR_NO_ERROR)
  1073. {
  1074. PERROR(TEXT("Existing err %x\r\n"), err);
  1075. }
  1076. // get size of data
  1077. if (NULL == (lpSrc = DdeAccessData ( hDDE, &cbData )))
  1078. {
  1079. #if DEBUG
  1080. unsigned i;
  1081. i = DdeGetLastError(idInst);
  1082. PERROR(TEXT("DdeAccessData fail %d on handle %ld\r\n"), i, hDDE);
  1083. #endif
  1084. goto done;
  1085. }
  1086. PINFO(TEXT("%d bytes of data. "), cbData);
  1087. if (!(hData = GlobalAlloc(GHND, cbData)))
  1088. {
  1089. PERROR(TEXT("GlobalAlloc failed\n\r"));
  1090. goto done2;
  1091. }
  1092. if (!(lpData = GlobalLock(hData)))
  1093. {
  1094. PERROR(TEXT("GlobalLock failed\n\r"));
  1095. goto done2;
  1096. }
  1097. memcpy(lpData, lpSrc, cbData);
  1098. GlobalUnlock(hData);
  1099. // As when we write these we have to special case a few of
  1100. // these guys. This code and the write code should match in terms
  1101. // of the sizes and positions of data blocks being written out.
  1102. switch ( uiFmt )
  1103. {
  1104. case CF_METAFILEPICT:
  1105. {
  1106. HANDLE hMF;
  1107. HANDLE hMFP;
  1108. HANDLE hDataOut = NULL;
  1109. LPMETAFILEPICT lpMFP;
  1110. // Create the METAFILE with the bits we read in.
  1111. lpData = GlobalLock(hData);
  1112. if (hMF = SetMetaFileBitsEx(cbData - sizeof(WIN31METAFILEPICT),
  1113. lpData + sizeof(WIN31METAFILEPICT)))
  1114. {
  1115. // Alloc a METAFILEPICT header.
  1116. if (hMFP = GlobalAlloc(GHND, (DWORD)sizeof(METAFILEPICT)))
  1117. {
  1118. if (!(lpMFP = (LPMETAFILEPICT)GlobalLock(hMFP)))
  1119. {
  1120. PERROR(TEXT("Set...FromDDE: GlobalLock failed\n\r"));
  1121. GlobalFree(hMFP);
  1122. }
  1123. else
  1124. {
  1125. // Have to set this struct memberwise because it's packed
  1126. // as a WIN31METAFILEPICT in the data we get via DDE
  1127. lpMFP->hMF = hMF;
  1128. lpMFP->xExt =((WIN31METAFILEPICT *)lpData)->xExt;
  1129. lpMFP->yExt =((WIN31METAFILEPICT *)lpData)->yExt;
  1130. lpMFP->mm =((WIN31METAFILEPICT *)lpData)->mm;
  1131. GlobalUnlock(hMFP); /* Unlock the header */
  1132. hDataOut = hMFP; /* Stuff this in the clipboard */
  1133. fOK = TRUE;
  1134. }
  1135. }
  1136. else
  1137. {
  1138. PERROR(TEXT("SCFDDE: GlobalAlloc fail in MFP, %ld\r\n"),
  1139. GetLastError());
  1140. }
  1141. }
  1142. else
  1143. {
  1144. PERROR(TEXT("SClipFDDE: SetMFBitsEx fail %ld\r\n"), GetLastError());
  1145. }
  1146. GlobalUnlock(hData);
  1147. hData = hDataOut;
  1148. break;
  1149. }
  1150. case CF_ENHMETAFILE:
  1151. // We get a block of memory containing enhmetafile bits in this case.
  1152. if (lpData = GlobalLock(hData))
  1153. {
  1154. HENHMETAFILE henh;
  1155. henh = SetEnhMetaFileBits(cbData, lpData);
  1156. if (NULL == henh)
  1157. {
  1158. PERROR(TEXT("SetEnhMFBits fail %d\r\n"), GetLastError());
  1159. }
  1160. else
  1161. {
  1162. fOK = TRUE;
  1163. }
  1164. GlobalUnlock(hData);
  1165. GlobalFree(hData);
  1166. hData = henh;
  1167. }
  1168. else
  1169. {
  1170. GlobalFree(hData);
  1171. hData = NULL;
  1172. }
  1173. break;
  1174. case CF_BITMAP:
  1175. if (!(lpData = GlobalLock(hData)))
  1176. {
  1177. GlobalFree(hData);
  1178. }
  1179. else
  1180. {
  1181. bitmap.bmType = ((WIN31BITMAP *)lpData)->bmType;
  1182. bitmap.bmWidth = ((WIN31BITMAP *)lpData)->bmWidth;
  1183. bitmap.bmHeight = ((WIN31BITMAP *)lpData)->bmHeight;
  1184. bitmap.bmWidthBytes = ((WIN31BITMAP *)lpData)->bmWidthBytes;
  1185. bitmap.bmPlanes = ((WIN31BITMAP *)lpData)->bmPlanes;
  1186. bitmap.bmBitsPixel = ((WIN31BITMAP *)lpData)->bmBitsPixel;
  1187. bitmap.bmBits = lpData + sizeof(WIN31BITMAP);
  1188. // If this fails we should avoid doing the SetClipboardData()
  1189. // below with the hData check.
  1190. hBitmap = CreateBitmapIndirect(&bitmap);
  1191. GlobalUnlock(hData);
  1192. GlobalFree(hData);
  1193. hData = hBitmap; // Stuff this in the clipboard
  1194. if (hBitmap)
  1195. {
  1196. fOK = TRUE;
  1197. }
  1198. }
  1199. break;
  1200. case CF_PALETTE:
  1201. if (!(lpLogPalette = (LPLOGPALETTE)GlobalLock(hData)))
  1202. {
  1203. GlobalFree(hData);
  1204. DdeUnaccessData( hDDE );
  1205. DdeFreeDataHandle ( hDDE );
  1206. fOK = FALSE;
  1207. }
  1208. else
  1209. {
  1210. // Create a logical palette.
  1211. if (!(hPalette = CreatePalette(lpLogPalette)))
  1212. {
  1213. GlobalUnlock(hData);
  1214. GlobalFree(hData);
  1215. }
  1216. else
  1217. {
  1218. GlobalUnlock(hData);
  1219. GlobalFree(hData);
  1220. hData = hPalette; // Stuff this into clipboard
  1221. fOK = TRUE;
  1222. }
  1223. }
  1224. break;
  1225. case DDE_DIB2BITMAP:
  1226. // convert dib to bitmap
  1227. {
  1228. HBITMAP hBmp;
  1229. hBmp = BitmapFromDib (hData,
  1230. VGetClipboardData (GETMDIINFO(hwnd)->pVClpbrd, CF_PALETTE));
  1231. GlobalFree (hData);
  1232. hData = hBmp;
  1233. uiFmt = CF_BITMAP;
  1234. fOK = TRUE;
  1235. break;
  1236. }
  1237. default:
  1238. fOK = TRUE;
  1239. }
  1240. if (!hData)
  1241. {
  1242. PERROR(TEXT("SetClipboardFormatFromDDE returning FALSE\n\r"));
  1243. }
  1244. if (GETMDIINFO(hwnd))
  1245. if (fOK)
  1246. {
  1247. PINFO(TEXT("SCFFDDE: Setting VClpD\r\n"));
  1248. VSetClipboardData( GETMDIINFO(hwnd)->pVClpbrd, uiFmt, hData);
  1249. }
  1250. else if (!(GETMDIINFO(hwnd)->flags & F_CLPBRD))
  1251. {
  1252. VSetClipboardData (GETMDIINFO(hwnd)->pVClpbrd, uiFmt,
  1253. INVALID_HANDLE_VALUE);
  1254. }
  1255. // No GlobalFree() call here, 'cause we've put hData on the clp
  1256. done2:
  1257. DdeUnaccessData(hDDE);
  1258. done:
  1259. DdeFreeDataHandle(hDDE);
  1260. return fOK;
  1261. }
  1262. // NewWindow /////////////////////////////////////////////
  1263. //
  1264. // this function creates a new MDI child window. special
  1265. // case code detects if the window created is the special case
  1266. // clipboard MDI child window or the special case local clipbook
  1267. // window, this information is used to size the initial 2 windows
  1268. // to be tiled side-by-side
  1269. HWND NewWindow(VOID)
  1270. {
  1271. HWND hwnd;
  1272. MDICREATESTRUCT mcs;
  1273. mcs.szTitle = TEXT("");
  1274. mcs.szClass = szChild;
  1275. mcs.hOwner = hInst;
  1276. /* Use the default size for the window */
  1277. if ( !hwndClpbrd )
  1278. {
  1279. mcs.style = WS_MINIMIZE;
  1280. }
  1281. else
  1282. {
  1283. mcs.style = 0;
  1284. }
  1285. mcs.x = mcs.cx = CW_USEDEFAULT;
  1286. mcs.y = mcs.cy = CW_USEDEFAULT;
  1287. /* Set the style DWORD of the window to default */
  1288. // note not visible!
  1289. mcs.style |= ( WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_CAPTION |
  1290. WS_THICKFRAME | WS_MAXIMIZEBOX | WS_MINIMIZEBOX |
  1291. WS_SYSMENU );
  1292. /* tell the MDI Client to create the child */
  1293. hwnd = (HWND)SendMessage (hwndMDIClient,
  1294. WM_MDICREATE,
  1295. 0,
  1296. (LPARAM)(LPMDICREATESTRUCT)&mcs);
  1297. return hwnd;
  1298. }
  1299. // AdjustMDIClientSize //////////////////////////////
  1300. //
  1301. // this function adjusts the size of the MDI client window
  1302. // when the application is resized according to whether the
  1303. // toolbar/status bar is visible, etc.
  1304. VOID AdjustMDIClientSize(VOID)
  1305. {
  1306. RECT rcApp;
  1307. RECT rcMDI;
  1308. if (IsIconic(hwndApp))
  1309. return;
  1310. GetClientRect (hwndApp, &rcApp);
  1311. rcMDI.top = 0;
  1312. rcMDI.bottom = rcApp.bottom - rcApp.top;
  1313. rcMDI.left = 0;
  1314. rcMDI.right = rcApp.right - rcApp.left;
  1315. MoveWindow (hwndMDIClient,
  1316. rcMDI.left - 1,
  1317. rcMDI.top + (fToolBar? (dyButtonBar +1): 0),
  1318. (rcMDI.right - rcMDI.left) + 2,
  1319. ((rcMDI.bottom - rcMDI.top) - (fStatus?dyStatus:0)) -(fToolBar?(dyButtonBar +1):0),
  1320. TRUE);
  1321. if (fNeedToTileWindows )
  1322. {
  1323. SendMessage (hwndMDIClient, WM_MDITILE, 0, 0);
  1324. fNeedToTileWindows = FALSE;
  1325. }
  1326. }
  1327. // GetConvDataItem ///////////////////////////////////
  1328. //
  1329. // this function retrieves the data item associated with the
  1330. // supplied topic and item from whatever local or remote host
  1331. // the MDI child window specified by the supplied handle is
  1332. // communicating with. It is used to get the preview bitmaps and
  1333. // to get individual format data.
  1334. //
  1335. // NOTE: caller should LockApp before calling this!
  1336. HDDEDATA GetConvDataItem(
  1337. HWND hwnd,
  1338. LPTSTR szTopic,
  1339. LPTSTR szItem,
  1340. UINT uiFmt)
  1341. {
  1342. HCONV hConv;
  1343. HSZ hszTopic;
  1344. HSZ hszItem;
  1345. HDDEDATA hRet = 0;
  1346. PMDIINFO pMDI;
  1347. PINFO(TEXT("GConvDI: %s ! %s, %x\r\n"), szTopic, szItem, uiFmt);
  1348. if (!( hszTopic = DdeCreateStringHandle ( idInst, szTopic, 0 )))
  1349. {
  1350. PERROR(TEXT("GetConvDataItem: DdeCreateStringHandle failed\n\r"));
  1351. return 0;
  1352. }
  1353. if (!(hszItem = DdeCreateStringHandle ( idInst, szItem, 0 )))
  1354. {
  1355. DdeFreeStringHandle ( idInst, hszTopic );
  1356. PERROR(TEXT("GetConvDataItem: DdeCreateStringHandle failed\n\r"));
  1357. return 0;
  1358. }
  1359. if (!(pMDI = GETMDIINFO(hwnd)))
  1360. return 0;
  1361. if ( hConv = DdeConnect (idInst,
  1362. (uiFmt == cf_preview && !(pMDI->flags & F_LOCAL))?
  1363. pMDI->hszConvPartnerNP:
  1364. pMDI->hszConvPartner,
  1365. hszTopic,NULL ))
  1366. {
  1367. hRet = MySyncXact (NULL, 0L, hConv,
  1368. hszItem, uiFmt, XTYP_REQUEST, SHORT_SYNC_TIMEOUT, NULL );
  1369. if ( !hRet )
  1370. {
  1371. PERROR(TEXT("Transaction for (%s):(%s) failed: %x\n\r"),
  1372. szTopic, szItem, DdeGetLastError(idInst));
  1373. }
  1374. }
  1375. #if DEBUG
  1376. else
  1377. {
  1378. DdeQueryString ( idInst, GETMDIINFO(hwnd)->hszConvPartner,
  1379. szBuf, 128, CP_WINANSI );
  1380. PERROR(TEXT("GetConvDataItem: connect to %s|%s failed: %d\n\r"),
  1381. (LPTSTR)szBuf,
  1382. (LPTSTR)szTopic, DdeGetLastError(idInst) );
  1383. }
  1384. #endif
  1385. DdeDisconnect ( hConv );
  1386. DdeFreeStringHandle ( idInst, hszTopic );
  1387. return hRet;
  1388. }
  1389. //***************************************************************************
  1390. // FUNCTION : MyMsgFilterProc
  1391. //
  1392. // PURPOSE : This filter proc gets called for each message we handle.
  1393. // This allows our application to properly dispatch messages
  1394. // that we might not otherwise see because of DDEMLs modal
  1395. // loop that is used while processing synchronous transactions.
  1396. //
  1397. // Generally, applications that only do synchronous transactions
  1398. // in response to user input (as this app does) does not need
  1399. // to install such a filter proc because it would be very rare
  1400. // that a user could command the app fast enough to cause
  1401. // problems. However, this is included as an example.
  1402. LRESULT PASCAL MyMsgFilterProc(
  1403. int nCode,
  1404. WPARAM wParam,
  1405. LPARAM lParam)
  1406. {
  1407. if (( nCode == MSGF_DIALOGBOX || nCode == MSGF_MENU ) &&
  1408. ((LPMSG)lParam)->message == WM_KEYDOWN &&
  1409. ((LPMSG)lParam)->wParam == VK_F1 )
  1410. {
  1411. PostMessage ( hwndApp, WM_F1DOWN, nCode, 0L );
  1412. }
  1413. return(0);
  1414. }
  1415. // MySyncXact ///////////////////////////////
  1416. //
  1417. // this function is a wrapper to DdeClientTransaction which
  1418. // performs some checks related to the Locked state of the app
  1419. HDDEDATA MySyncXact(
  1420. LPBYTE lpbData,
  1421. DWORD cbDataLen,
  1422. HCONV hConv,
  1423. HSZ hszItem,
  1424. UINT wFmt,
  1425. UINT wType,
  1426. DWORD dwTimeout,
  1427. LPDWORD lpdwResult)
  1428. {
  1429. HDDEDATA hDDE;
  1430. BOOL fAlreadyLocked;
  1431. UINT uiErr;
  1432. UINT DdeErr = 0;
  1433. DWORD dwTmp = 0;
  1434. #if DEBUG
  1435. if (dwTimeout != TIMEOUT_ASYNC)
  1436. {
  1437. dwTimeout +=10000;
  1438. }
  1439. #endif
  1440. // are we already in transaction?
  1441. if (WAIT_TIMEOUT == WaitForSingleObject (hXacting, 0))
  1442. {
  1443. Sleep (2000);
  1444. ClearInput (hwndApp);
  1445. return 0L;
  1446. }
  1447. fAlreadyLocked = !LockApp(TRUE, NULL);
  1448. gXERR_Type = 0;
  1449. gXERR_Err = 0;
  1450. hDDE = DdeClientTransaction (lpbData,
  1451. cbDataLen,
  1452. hConv,
  1453. hszItem,
  1454. wFmt,
  1455. wType,
  1456. dwTimeout,
  1457. lpdwResult );
  1458. if (!hDDE)
  1459. {
  1460. DWORD size;
  1461. LPBYTE lpByte;
  1462. DdeErr = DdeGetLastError(idInst);
  1463. #if DEBUG
  1464. PERROR("MySyncXact fail err %d.\r\n", uiErr);
  1465. DdeQueryString (idInst, hszItem, lpbItem, 64, CP_WINANSI);
  1466. PINFO(TEXT("Parameters: data at %lx (%s), len %ld, HCONV %lx\r\n"),
  1467. lpbData, (CF_TEXT == wFmt && lpbData) ? lpbData : TEXT("Not text"),
  1468. cbDataLen, hConv);
  1469. PINFO(TEXT("item %lx (%s), fmt %d, type %d, timeout %ld\r\n"),
  1470. hszItem, lpbItem, wFmt, wType, dwTimeout);
  1471. #endif
  1472. //
  1473. // There was an error in the transaction, let's ask
  1474. // the server what was it.
  1475. //
  1476. hDDE = DdeClientTransaction (NULL,
  1477. 0L,
  1478. hConv,
  1479. hszErrorRequest,
  1480. CF_TEXT,
  1481. XTYP_REQUEST,
  1482. SHORT_SYNC_TIMEOUT,
  1483. NULL);
  1484. uiErr = DdeGetLastError (idInst);
  1485. if (lpByte = DdeAccessData (hDDE, &size))
  1486. sscanf (lpByte, XERR_FORMAT, &gXERR_Type, &gXERR_Err);
  1487. DdeUnaccessData (hDDE);
  1488. DdeFreeDataHandle (hDDE);
  1489. hDDE = 0;
  1490. }
  1491. if (!gXERR_Type && DdeErr)
  1492. {
  1493. gXERR_Type = XERRT_DDE;
  1494. gXERR_Err = DdeErr;
  1495. }
  1496. if (!fAlreadyLocked)
  1497. {
  1498. LockApp(FALSE, NULL);
  1499. }
  1500. SetEvent (hXacting);
  1501. return hDDE;
  1502. }
  1503. /*
  1504. * RequestXactError
  1505. *
  1506. * Ask the server for error code.
  1507. */
  1508. void RequestXactError(
  1509. HCONV hConv)
  1510. {
  1511. HDDEDATA hDDE;
  1512. BOOL fAlreadyLocked;
  1513. UINT uiErr;
  1514. UINT DdeErr = 0;
  1515. DWORD size;
  1516. LPBYTE lpByte;
  1517. // Are we already in transaction?
  1518. if (WAIT_TIMEOUT == WaitForSingleObject (hXacting, 0))
  1519. {
  1520. Sleep (2000);
  1521. ClearInput (hwndApp);
  1522. return;
  1523. }
  1524. fAlreadyLocked = !LockApp(TRUE, NULL);
  1525. gXERR_Type = 0;
  1526. gXERR_Err = 0;
  1527. DdeErr = DdeGetLastError(idInst);
  1528. hDDE = DdeClientTransaction (NULL,
  1529. 0L,
  1530. hConv,
  1531. hszErrorRequest,
  1532. CF_TEXT,
  1533. XTYP_REQUEST,
  1534. SHORT_SYNC_TIMEOUT,
  1535. NULL);
  1536. uiErr = DdeGetLastError (idInst);
  1537. if (lpByte = DdeAccessData (hDDE, &size))
  1538. sscanf (lpByte, XERR_FORMAT, &gXERR_Type, &gXERR_Err);
  1539. DdeUnaccessData (hDDE);
  1540. DdeFreeDataHandle (hDDE);
  1541. if (!gXERR_Type && DdeErr)
  1542. {
  1543. gXERR_Type = XERRT_DDE;
  1544. gXERR_Err = DdeErr;
  1545. }
  1546. if (!fAlreadyLocked)
  1547. {
  1548. LockApp(FALSE, NULL);
  1549. }
  1550. SetEvent (hXacting);
  1551. }
  1552. // ResetScrollInfo ///////////////////////////
  1553. //
  1554. // this function resets the scroll information of the
  1555. // MDI child window designated by the supplied handle
  1556. VOID ResetScrollInfo(
  1557. HWND hwnd)
  1558. {
  1559. PMDIINFO pMDI = GETMDIINFO(hwnd);
  1560. if (!pMDI)
  1561. return;
  1562. // Invalidate object info; reset scroll position to 0.
  1563. pMDI->cyScrollLast = -1L;
  1564. pMDI->cyScrollNow = 0L;
  1565. pMDI->cxScrollLast = -1;
  1566. pMDI->cxScrollNow = 0;
  1567. // Range is set in case CF_OWNERDISPLAY owner changed it.
  1568. PINFO(TEXT("SETSCROLLRANGE for window '%s'\n\r"),
  1569. (LPTSTR)(pMDI->szBaseName) );
  1570. SetScrollRange (pMDI->hwndVscroll, SB_CTL, 0, VPOSLAST, FALSE);
  1571. SetScrollRange (pMDI->hwndHscroll, SB_CTL, 0, HPOSLAST, FALSE);
  1572. SetScrollPos (pMDI->hwndVscroll, SB_CTL, (int)(pMDI->cyScrollNow), TRUE);
  1573. SetScrollPos (pMDI->hwndHscroll, SB_CTL, pMDI->cxScrollNow, TRUE);
  1574. }
  1575. // IsShared ///////////////////////////////////
  1576. //
  1577. // this function checks the shared state of the ownerdraw
  1578. // listbox entry denoted by the supplied pointer. Shared/nonshared
  1579. // status is expressed as a 1 character prefix to the description string
  1580. //
  1581. // return TRUE if shared, false otherwise
  1582. BOOL IsShared(
  1583. LPLISTENTRY lpLE)
  1584. {
  1585. if (!lpLE)
  1586. return FALSE;
  1587. if ( lpLE->name[0] == SHR_CHAR )
  1588. return TRUE;
  1589. #if DEBUG
  1590. if ( lpLE->name[0] != UNSHR_CHAR )
  1591. PERROR(TEXT("bad prefix char in share name: %s\n\r"),
  1592. (LPTSTR)lpLE->name );
  1593. #endif
  1594. return FALSE;
  1595. }
  1596. // SetShared //////////////////////////////////////////
  1597. //
  1598. // sets shared state to fShared, returns previous state
  1599. BOOL SetShared(
  1600. LPLISTENTRY lpLE,
  1601. BOOL fShared)
  1602. {
  1603. BOOL fSave;
  1604. fSave = lpLE->name[0] == SHR_CHAR ? TRUE : FALSE;
  1605. lpLE->name[0] = ( fShared ? SHR_CHAR : UNSHR_CHAR );
  1606. return fSave;
  1607. }
  1608. // LockApp ////////////////////////////////////////////
  1609. //
  1610. // this function effectively disables the windows UI during
  1611. // synchronous ddeml transactions to prevent the user from initiating
  1612. // another transaction or causing the window procedure of this app
  1613. // or another application to be re-entered in a way that could cause
  1614. // failures... A primary example is that sometimes we are forced to
  1615. // go into a ddeml transaction with the clipboard open... this app
  1616. // and other apps must not be caused to access the clipboard during that
  1617. // time, so this mechanism emulates the hourglass...
  1618. //
  1619. // NOTE: do not call LockApp in a section of code where the
  1620. // cursor is already captured, such as in response to a scroll
  1621. // message, or the releasecapture during unlock will cause strange and
  1622. // bad things to happen.
  1623. BOOL LockApp(
  1624. BOOL fLock,
  1625. LPTSTR lpszComment)
  1626. {
  1627. static HCURSOR hOldCursor;
  1628. BOOL fOK = FALSE;
  1629. if (lpszComment)
  1630. {
  1631. SetStatusBarText( lpszComment );
  1632. }
  1633. if ( fLock == TRUE )
  1634. {
  1635. if ( fAppLockedState )
  1636. {
  1637. PERROR(TEXT("LockApp(TRUE): already locked\n\r"));
  1638. }
  1639. else
  1640. {
  1641. hOldCursor = SetCursor ( LoadCursor ( NULL, IDC_WAIT ));
  1642. SetCapture ( hwndDummy );
  1643. EnableWindow ( hwndApp, FALSE );
  1644. fOK = TRUE;
  1645. fAppLockedState = TRUE;
  1646. }
  1647. }
  1648. else
  1649. {
  1650. if ( !fAppLockedState )
  1651. {
  1652. PERROR(TEXT("LockApp(FALSE): not locked\n\r"));
  1653. }
  1654. else
  1655. {
  1656. ClearInput (hwndApp);
  1657. EnableWindow ( hwndApp, TRUE );
  1658. ReleaseCapture ();
  1659. SetCursor ( hOldCursor );
  1660. fOK = TRUE;
  1661. // take care of any deferred clipboard update requests
  1662. if ( fClipboardNeedsPainting )
  1663. {
  1664. PostMessage ( hwndApp, WM_DRAWCLIPBOARD, 0, 0L );
  1665. }
  1666. fAppLockedState = FALSE;
  1667. }
  1668. }
  1669. return fOK;
  1670. }
  1671. // ForceRenderAll ///////////////////////////////////
  1672. //
  1673. // this function forces a complete rendering of any delayed
  1674. // render clipboard formats
  1675. BOOL ForceRenderAll(
  1676. HWND hwnd,
  1677. PVCLPBRD pVclp)
  1678. {
  1679. HANDLE h;
  1680. UINT uiFmt;
  1681. if ( !VOpenClipboard ( pVclp, hwnd ))
  1682. {
  1683. PERROR(TEXT("Can't open clipboard in ForceRenderAll\n\r"));
  1684. return FALSE;
  1685. }
  1686. for ( uiFmt = VEnumClipboardFormats( pVclp, 0); uiFmt;
  1687. uiFmt = VEnumClipboardFormats( pVclp, uiFmt))
  1688. {
  1689. PINFO(TEXT("ForceRenderAll: force rendering %x\n\r"), uiFmt );
  1690. h = VGetClipboardData ( pVclp, uiFmt );
  1691. }
  1692. VCloseClipboard ( pVclp );
  1693. return TRUE;
  1694. }
  1695. BOOL UpdateNofMStatus(
  1696. HWND hwnd)
  1697. {
  1698. HWND hwndlistbox;
  1699. int total = 0;
  1700. int sel = LB_ERR;
  1701. if (hwnd == NULL)
  1702. {
  1703. SendMessage ( hwndStatus, SB_SETTEXT, 0, (LPARAM)NULL );
  1704. return TRUE;
  1705. }
  1706. if (!GETMDIINFO(hwnd))
  1707. return FALSE;
  1708. if (GETMDIINFO(hwnd)->flags & F_CLPBRD)
  1709. {
  1710. SendMessage ( hwndStatus, SB_SETTEXT, 0, (LPARAM)(LPTSTR) szSysClpBrd );
  1711. return TRUE;
  1712. }
  1713. if ( IsWindow( hwndlistbox = GETMDIINFO(hwnd)->hWndListbox ) )
  1714. {
  1715. total = (int)SendMessage ( hwndlistbox, LB_GETCOUNT, (WPARAM)0, 0L );
  1716. sel = (int)SendMessage ( hwndlistbox, LB_GETCURSEL, 0, 0L);
  1717. }
  1718. if ( sel == (int)LB_ERR )
  1719. {
  1720. if ( total == 1 )
  1721. SendMessage (hwndStatus, SB_SETTEXT, 0, (LPARAM)(LPCSTR)szPageFmt);
  1722. else
  1723. {
  1724. StringCchPrintf( szBuf, SZBUFSIZ, szPageFmtPl, total );
  1725. SendMessage (hwndStatus, SB_SETTEXT, 0, (LPARAM)(LPCSTR)szBuf );
  1726. }
  1727. }
  1728. else
  1729. {
  1730. StringCchPrintf(szBuf, SZBUFSIZ, szPageOfPageFmt, sel+1, total );
  1731. SendMessage ( hwndStatus, SB_SETTEXT, 0, (LPARAM)(LPCSTR)szBuf );
  1732. }
  1733. return TRUE;
  1734. }
  1735. BOOL RestoreAllSavedConnections(void)
  1736. {
  1737. TCHAR szName[80];
  1738. BOOL ret = TRUE;
  1739. unsigned i;
  1740. i = lstrlen(szConn);
  1741. if (NULL != hkeyRoot)
  1742. {
  1743. DWORD dwSize = 80;
  1744. DWORD iSubkey = 0;
  1745. while (ERROR_SUCCESS == RegEnumKeyEx(hkeyRoot, iSubkey,
  1746. szName, &dwSize, NULL, NULL, NULL, NULL) )
  1747. {
  1748. if (0 == memcmp(szName, szConn, i))
  1749. {
  1750. PINFO(TEXT("Restoring connection to '%s'\n\r"), szName + i);
  1751. if ( !CreateNewRemoteWindow ( szName + i, FALSE ) )
  1752. {
  1753. TCHAR szWindowName[80];
  1754. // remove re-connect entry
  1755. RegDeleteKey(hkeyRoot, szName);
  1756. StringCchCopy(szWindowName, 80, szWindows);
  1757. StringCchCat( szWindowName, 80, szName + i);
  1758. RegDeleteKey(hkeyRoot, szWindowName);
  1759. ret = 0;
  1760. }
  1761. }
  1762. dwSize = 80;
  1763. iSubkey++;
  1764. }
  1765. }
  1766. return ret;
  1767. }
  1768. BOOL CreateNewRemoteWindow(
  1769. LPTSTR szMachineName,
  1770. BOOL fReconnect)
  1771. {
  1772. WINDOWPLACEMENT wpl;
  1773. HWND hwndc;
  1774. PMDIINFO pMDIc;
  1775. // make new window active
  1776. hwndc = NewWindow();
  1777. if (NULL == hwndc)
  1778. {
  1779. return FALSE;
  1780. }
  1781. if (!(pMDIc = GETMDIINFO(hwndc)))
  1782. return FALSE;
  1783. // save base name for window
  1784. StringCchCopy( pMDIc->szBaseName, (MAX_COMPUTERNAME_LENGTH+1)*2, szMachineName);
  1785. StringCchCopy( pMDIc->szComputerName, MAX_COMPUTERNAME_LENGTH + 1, szMachineName);
  1786. StringCchPrintf ( szBuf, SZBUFSIZ, TEXT("%s\\%s"), (LPTSTR)szMachineName, (LPTSTR)szNDDEcode);
  1787. pMDIc->hszConvPartner = DdeCreateStringHandle ( idInst, szBuf, 0 );
  1788. PINFO(TEXT("Trying to talk to %s\r\n"),szBuf);
  1789. StringCchPrintf ( szBuf, SZBUFSIZ, TEXT("%s\\%s"), (LPTSTR)szMachineName, (LPTSTR)szNDDEcode1 );
  1790. pMDIc->hszConvPartnerNP = DdeCreateStringHandle ( idInst, szBuf, 0 );
  1791. PINFO(TEXT("NP = %s\r\n"),szBuf);
  1792. #if DEBUG
  1793. DdeQueryString(idInst, hszSystem, szBuf, 128, CP_WINANSI);
  1794. PINFO(TEXT("Topic = %s\r\n"), szBuf);
  1795. PINFO(TEXT("Existing err = %lx\r\n"), DdeGetLastError(idInst));
  1796. #endif
  1797. pMDIc->hExeConv = InitSysConv (hwndc, pMDIc->hszConvPartner, hszClpBookShare, FALSE);
  1798. if ( pMDIc->hExeConv )
  1799. {
  1800. if ( UpdateListBox ( hwndc, pMDIc->hExeConv ))
  1801. {
  1802. StringCchPrintf(szBuf, SZBUFSIZ, szClipBookOnFmt, (LPTSTR)(pMDIc->szBaseName) );
  1803. SetWindowText ( hwndc, szBuf );
  1804. if ( ReadWindowPlacement ( pMDIc->szBaseName, &wpl ))
  1805. {
  1806. wpl.length = sizeof(WINDOWPLACEMENT);
  1807. wpl.flags = WPF_SETMINPOSITION;
  1808. SetWindowPlacement ( hwndc, &wpl );
  1809. UpdateWindow ( hwndc );
  1810. }
  1811. else
  1812. {
  1813. ShowWindow ( hwndc, SW_SHOWNORMAL );
  1814. }
  1815. ShowWindow ( pMDIc->hWndListbox, SW_SHOW );
  1816. SendMessage ( hwndMDIClient, WM_MDIACTIVATE, (WPARAM)hwndc, 0L );
  1817. SendMessage ( hwndMDIClient, WM_MDISETMENU, (WPARAM) TRUE, 0L );
  1818. hwndActiveChild = hwndc;
  1819. pActiveMDI = GETMDIINFO(hwndc);
  1820. if ( fReconnect )
  1821. {
  1822. TCHAR szName[80];
  1823. DWORD dwData;
  1824. StringCchCopy(szName, 80, szConn);
  1825. StringCchCat( szName, 80, szBuf);
  1826. dwData = pMDIc->DisplayMode == DSP_LIST ? 1 : 2;
  1827. RegSetValueEx(hkeyRoot, szName, 0L, REG_DWORD,
  1828. (LPBYTE)&dwData, sizeof(dwData));
  1829. PINFO(TEXT("saving connection: '%s'\n\r"), (LPTSTR)szBuf );
  1830. }
  1831. else
  1832. {
  1833. TCHAR szName[80];
  1834. DWORD dwData;
  1835. DWORD dwDataSize = sizeof(dwData);
  1836. StringCchCopy(szName, 80, szConn);
  1837. StringCchCat( szName, 80, pMDIc->szBaseName);
  1838. RegQueryValueEx(hkeyRoot, szName, NULL, NULL,
  1839. (LPBYTE)&dwData, &dwDataSize);
  1840. if (2 == dwData)
  1841. {
  1842. SendMessage ( hwndApp, WM_COMMAND, IDM_PREVIEWS, 0L );
  1843. }
  1844. }
  1845. return TRUE;
  1846. }
  1847. else
  1848. {
  1849. PERROR(TEXT("UpdateListBox failed\n\r"));
  1850. return FALSE;
  1851. }
  1852. }
  1853. else
  1854. {
  1855. unsigned uiErr;
  1856. #if DEBUG
  1857. DdeQueryString(idInst, pMDIc->hszConvPartner, szBuf, 128, CP_WINANSI);
  1858. #endif
  1859. uiErr = DdeGetLastError(idInst);
  1860. PERROR(TEXT("Can't find %s|System. Error #%x\n\r"),(LPTSTR)szBuf, uiErr );
  1861. }
  1862. return FALSE;
  1863. }
  1864. #define MB_SNDMASK (MB_ICONHAND|MB_ICONQUESTION|MB_ICONASTERISK|MB_ICONEXCLAMATION)
  1865. /*
  1866. * MessageBoxID
  1867. *
  1868. * Display a message box with strings specified by
  1869. * TextID and TitleID.
  1870. */
  1871. int MessageBoxID(
  1872. HANDLE hInstance,
  1873. HWND hwndParent,
  1874. UINT TextID,
  1875. UINT TitleID,
  1876. UINT fuStyle)
  1877. {
  1878. LoadString (hInstance, TextID, szBuf, SZBUFSIZ);
  1879. LoadString (hInstance, TitleID, szBuf2, SZBUFSIZ);
  1880. MessageBeep (fuStyle & MB_SNDMASK);
  1881. return MessageBox (hwndParent, szBuf, szBuf2, fuStyle);
  1882. }
  1883. /*
  1884. * NDdeMessageBox
  1885. *
  1886. * Display a message box with NDde error
  1887. * string specified by errCode and title
  1888. * string specified by TitleID.
  1889. */
  1890. int NDdeMessageBox(
  1891. HANDLE hInstance,
  1892. HWND hwnd,
  1893. UINT errCode,
  1894. UINT TitleID,
  1895. UINT fuStyle)
  1896. {
  1897. if (!errCode)
  1898. return IDOK;
  1899. NDdeGetErrorString (errCode, szBuf, SZBUFSIZ);
  1900. LoadString (hInstance, TitleID, szBuf2, SZBUFSIZ);
  1901. MessageBeep (fuStyle & MB_SNDMASK);
  1902. return MessageBox (hwnd, szBuf, szBuf2, fuStyle);
  1903. }
  1904. /*
  1905. * SysMessageBox
  1906. *
  1907. * Display a messag box for system message
  1908. * strings specified by dwErr and titl string
  1909. * specified by TitleID.
  1910. */
  1911. int SysMessageBox(
  1912. HANDLE hInstance,
  1913. HWND hwnd,
  1914. DWORD dwErr,
  1915. UINT TitleID,
  1916. UINT fuStyle)
  1917. {
  1918. DWORD dwR;
  1919. LPTSTR lpBuffer = NULL;
  1920. DWORD dwSize = 20;
  1921. if (dwErr == NO_ERROR)
  1922. return IDOK;
  1923. dwR = FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER|
  1924. FORMAT_MESSAGE_FROM_SYSTEM,
  1925. NULL,
  1926. dwErr,
  1927. 0,
  1928. (LPTSTR)&lpBuffer,
  1929. dwSize,
  1930. NULL);
  1931. if (0 < dwR)
  1932. {
  1933. LoadString (hInstance, TitleID, szBuf2, SZBUFSIZ);
  1934. MessageBeep (fuStyle & MB_SNDMASK);
  1935. dwR = MessageBox (hwnd, lpBuffer, szBuf2, fuStyle);
  1936. LocalFree (lpBuffer);
  1937. }
  1938. return dwR;
  1939. }
  1940. /*
  1941. * XactMessageBox
  1942. *
  1943. * Display a message box for error
  1944. * occured in an transaction. MySyncXact
  1945. * must be called to do the transaction
  1946. * before calling this function.
  1947. */
  1948. int XactMessageBox(
  1949. HANDLE hInstance,
  1950. HWND hwnd,
  1951. UINT TitleID,
  1952. UINT fuStyle)
  1953. {
  1954. switch (gXERR_Type)
  1955. {
  1956. case XERRT_NDDE:
  1957. return NDdeMessageBox (hInstance, hwnd, gXERR_Err, TitleID, fuStyle);
  1958. case XERRT_DDE:
  1959. return DdeMessageBox (hInstance, hwnd, gXERR_Err, TitleID, fuStyle);
  1960. case XERRT_SYS:
  1961. return SysMessageBox (hInstance, hwnd, gXERR_Err, TitleID, fuStyle);
  1962. default:
  1963. return IDOK;
  1964. }
  1965. }
  1966. /*
  1967. * DdeNessageBox
  1968. *
  1969. * Displays a message box for DDE
  1970. * error strings specified by errCode
  1971. * and title string spcified by TitleID.
  1972. */
  1973. int DdeMessageBox(
  1974. HANDLE hInstance,
  1975. HWND hwnd,
  1976. UINT errCode,
  1977. UINT TitleID,
  1978. UINT fuStyle)
  1979. {
  1980. TCHAR szErr[1024];
  1981. switch (errCode)
  1982. {
  1983. case DMLERR_ADVACKTIMEOUT:
  1984. case DMLERR_DATAACKTIMEOUT:
  1985. case DMLERR_EXECACKTIMEOUT:
  1986. case DMLERR_POKEACKTIMEOUT:
  1987. case DMLERR_UNADVACKTIMEOUT:
  1988. case DMLERR_NO_CONV_ESTABLISHED:
  1989. if (hwnd == hwndLocal)
  1990. LoadString (hInstance, IDS_NOCLPBOOK, szBuf, SZBUFSIZ);
  1991. else
  1992. LoadString (hInstance, IDS_DATAUNAVAIL, szBuf, SZBUFSIZ);
  1993. break;
  1994. case DMLERR_NOTPROCESSED:
  1995. case DMLERR_BUSY:
  1996. case DMLERR_DLL_NOT_INITIALIZED:
  1997. case DMLERR_DLL_USAGE:
  1998. case DMLERR_INVALIDPARAMETER:
  1999. case DMLERR_LOW_MEMORY:
  2000. case DMLERR_MEMORY_ERROR:
  2001. case DMLERR_POSTMSG_FAILED:
  2002. case DMLERR_REENTRANCY:
  2003. case DMLERR_SERVER_DIED:
  2004. case DMLERR_SYS_ERROR:
  2005. case DMLERR_UNFOUND_QUEUE_ID:
  2006. LoadString (hInstance, IDS_INTERNALERR, szBuf, SZBUFSIZ);
  2007. break;
  2008. default:
  2009. return IDOK;
  2010. }
  2011. LoadString (hInstance, TitleID, szBuf2, SZBUFSIZ);
  2012. StringCchPrintf (szErr, 1024, "%s (%#x)", szBuf, errCode);
  2013. MessageBeep (fuStyle & MB_SNDMASK);
  2014. return MessageBox (hwnd, szErr, szBuf2, fuStyle);
  2015. }
  2016. /*
  2017. * ClearInput
  2018. *
  2019. * Removes all keyboard and mouse messages
  2020. * from message queue
  2021. */
  2022. void ClearInput (HWND hWnd)
  2023. {
  2024. MSG Msg;
  2025. while (PeekMessage (&Msg, hWnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE));
  2026. while (PeekMessage (&Msg, hWnd, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE));
  2027. }
  2028. PDATAREQ CreateNewDataReq (void)
  2029. {
  2030. return (PDATAREQ) GlobalAlloc (GPTR, sizeof(DATAREQ));
  2031. }
  2032. BOOL DeleteDataReq(
  2033. PDATAREQ pDataReq)
  2034. {
  2035. return ((HGLOBAL)pDataReq == GlobalFree (pDataReq));
  2036. }
  2037. //
  2038. // Purpose: Handle data returned from CLIPSRV via DDE.
  2039. //
  2040. // Parameters:
  2041. // hData - The data handle the XTYP_XACT_COMPLETE message gave us,
  2042. // or 0L if we got XTYP_DISCONNECT instead.
  2043. //
  2044. // pDataReq - Pointer to a DATAREQ struct containing info about what
  2045. // we wanted the data for. This is gotten via DdeGetUserHandle.
  2046. //
  2047. // Returns:
  2048. // TRUE on success, FALSE on failure.
  2049. //
  2050. //////////////////////////////////////////////////////////////////////////
  2051. BOOL ProcessDataReq(
  2052. HDDEDATA hData,
  2053. PDATAREQ pDataReq)
  2054. {
  2055. LPLISTENTRY lpLE;
  2056. LPSTR lpwszList;
  2057. LPSTR q;
  2058. HCURSOR hSaveCursor;
  2059. DWORD cbDataLen;
  2060. UINT tmp;
  2061. PMDIINFO pMDI;
  2062. UINT uiErr;
  2063. BOOL bRet = FALSE;
  2064. hSaveCursor = SetCursor (LoadCursor (NULL, IDC_WAIT));
  2065. PINFO("PDR:");
  2066. if ( !pDataReq || !IsWindow(pDataReq->hwndMDI) )
  2067. {
  2068. PERROR(TEXT("ProcessDataReq: bogus DATAREQ\n\r"));
  2069. goto done;
  2070. }
  2071. if (!hData)
  2072. {
  2073. PERROR("ProcessDataReq: Woe, woe, we have gotten null data!\r\n");
  2074. DumpDataReq(pDataReq);
  2075. switch (pDataReq->rqType)
  2076. {
  2077. case RQ_COPY:
  2078. MessageBoxID (hInst, hwndApp, IDS_DATAUNAVAIL, IDS_APPNAME,
  2079. MB_OK | MB_ICONHAND);
  2080. break;
  2081. case RQ_PREVBITMAP:
  2082. // We still have to display the lock icon.
  2083. SetBitmapToListboxEntry (hData, pDataReq->hwndList, pDataReq->iListbox);
  2084. break;
  2085. }
  2086. goto done;;
  2087. }
  2088. if (!(pMDI = GETMDIINFO(pDataReq->hwndMDI)))
  2089. goto done;
  2090. switch ( pDataReq->rqType )
  2091. {
  2092. case RQ_PREVBITMAP:
  2093. PINFO("Got bitmap for item %d in %x\r\n",pDataReq->iListbox,
  2094. pDataReq->hwndList);
  2095. SetBitmapToListboxEntry( hData, pDataReq->hwndList, pDataReq->iListbox);
  2096. InitializeMenu (GetMenu (hwndApp));
  2097. bRet = TRUE;
  2098. break;
  2099. case RQ_EXECONV:
  2100. // must be from disconnect
  2101. GETMDIINFO(pDataReq->hwndMDI)->hExeConv = 0L;
  2102. PINFO(TEXT("setting hExeConv NULL!\n\r"));
  2103. break;
  2104. case RQ_COPY:
  2105. PINFO("RQ_COPY:");
  2106. if ( hData == FALSE )
  2107. {
  2108. uiErr = DdeGetLastError (idInst);
  2109. PERROR(TEXT("REQUEST for format list failed: %x\n\r"), uiErr);
  2110. DdeMessageBox (hInst, pDataReq->hwndMDI, uiErr, IDS_APPNAME, MB_OK|MB_ICONEXCLAMATION);
  2111. break;
  2112. }
  2113. lpwszList = DdeAccessData ( hData, &cbDataLen );
  2114. if ( !lpwszList )
  2115. {
  2116. uiErr = DdeGetLastError (idInst);
  2117. DdeMessageBox (hInst, pDataReq->hwndMDI, uiErr, IDS_APPNAME, MB_OK|MB_ICONEXCLAMATION);
  2118. break;
  2119. }
  2120. PINFO(TEXT("formatlist:>%ws<\n\r"), lpwszList );
  2121. // this client now becomes the clipboard owner!!!
  2122. if (SyncOpenClipboard (hwndApp) == TRUE)
  2123. {
  2124. BOOL bHasBitmap = FALSE;
  2125. BOOL bLocked;
  2126. // Need to lock app while we fill the clipboard with formats,
  2127. // else hwndClpbrd will try to frantically try to redraw while
  2128. // we're doing it. Since hwndClpbrd needs to openclipboard() to
  2129. // do that, we don't want it to.
  2130. bLocked = LockApp(TRUE, szNull);
  2131. // reset clipboard view format to auto
  2132. pMDI->CurSelFormat = CBM_AUTO;
  2133. EmptyClipboard();
  2134. hwndClpOwner = pDataReq->hwndMDI;
  2135. PINFO(TEXT("Formats:"));
  2136. if (pDataReq->wFmt != CF_TEXT)
  2137. {
  2138. PERROR(TEXT("Format %d, expected CF_TEXT!\r\n"), pDataReq->wFmt);
  2139. }
  2140. for (q = strtokA(lpwszList, "\t");q;q = strtokA(NULL, "\t"))
  2141. {
  2142. PINFO(TEXT("[%s] "),q);
  2143. tmp = MyGetFormat(q, GETFORMAT_DONTLIE);
  2144. if (0 == tmp)
  2145. {
  2146. PERROR(TEXT("MyGetFormat failure!\r\n"));
  2147. }
  2148. else
  2149. {
  2150. switch (tmp)
  2151. {
  2152. case CF_DIB:
  2153. // DDBitmap can be converted from Dib.
  2154. SetClipboardData (CF_BITMAP, NULL);
  2155. default:
  2156. SetClipboardData (tmp, NULL);
  2157. }
  2158. }
  2159. }
  2160. PINFO("\r\n");
  2161. SyncCloseClipboard();
  2162. if (bLocked)
  2163. LockApp (FALSE, szNull);
  2164. // Redraw clipboard window.
  2165. if (hwndClpbrd)
  2166. {
  2167. InvalidateRect(hwndClpbrd, NULL, TRUE);
  2168. }
  2169. }
  2170. else
  2171. {
  2172. PERROR(TEXT("ProcessDataReq: unable to open clipboard\n\r"));
  2173. }
  2174. DdeUnaccessData ( hData );
  2175. DdeFreeDataHandle ( hData );
  2176. bRet = TRUE;
  2177. break;
  2178. case RQ_SETPAGE:
  2179. PINFO(TEXT("RQ_SETPAGE:"));
  2180. if ( hData == FALSE )
  2181. {
  2182. uiErr = DdeGetLastError (idInst);
  2183. PERROR(TEXT("vclip: REQUEST for format list failed: %x\n\r"), idInst);
  2184. DdeMessageBox (hInst, pDataReq->hwndMDI, idInst, IDS_APPNAME, MB_OK|MB_ICONEXCLAMATION);
  2185. break;
  2186. }
  2187. if ( SendMessage ( pMDI->hWndListbox,
  2188. LB_GETTEXT, pDataReq->iListbox,
  2189. (LPARAM)(LPCSTR)&lpLE) == LB_ERR )
  2190. {
  2191. PERROR(TEXT("IDM_COPY: bad listbox index: %d\n\r"), pDataReq->iListbox );
  2192. break;
  2193. }
  2194. lpwszList = DdeAccessData ( hData, &cbDataLen );
  2195. if ( !lpwszList )
  2196. {
  2197. uiErr = DdeGetLastError (idInst);
  2198. DdeMessageBox (hInst, pDataReq->hwndMDI, uiErr, IDS_APPNAME, MB_OK | MB_ICONEXCLAMATION );
  2199. break;
  2200. }
  2201. if ( VOpenClipboard ( pMDI->pVClpbrd, pDataReq->hwndMDI ) == TRUE )
  2202. {
  2203. BOOL bHasBitmap = FALSE;
  2204. VEmptyClipboard( pMDI->pVClpbrd );
  2205. for (q = strtokA(lpwszList, "\t");q;q = strtokA(NULL,"\t"))
  2206. {
  2207. tmp = MyGetFormat(q, GETFORMAT_DONTLIE);
  2208. switch (tmp)
  2209. {
  2210. case CF_DIB:
  2211. // DDBitmap can be converted from Dib.
  2212. VSetClipboardData (pMDI->pVClpbrd, CF_BITMAP, NULL);
  2213. default:
  2214. VSetClipboardData (pMDI->pVClpbrd, tmp, NULL);
  2215. }
  2216. }
  2217. VCloseClipboard( pMDI->pVClpbrd );
  2218. }
  2219. else
  2220. {
  2221. PERROR(TEXT("ProcessDataReq: unable to open Vclipboard\n\r"));
  2222. }
  2223. DdeUnaccessData ( hData );
  2224. DdeFreeDataHandle ( hData );
  2225. // set proper window text
  2226. if ( pMDI->flags & F_LOCAL )
  2227. {
  2228. StringCchPrintf( szBuf, SZBUFSIZ, TEXT("%s - %s"), szLocalClpBk, &(lpLE->name[1]) );
  2229. }
  2230. else
  2231. {
  2232. StringCchPrintf( szBuf, SZBUFSIZ, TEXT("%s - %s"), (pMDI->szBaseName), &(lpLE->name[1]) );
  2233. }
  2234. SetWindowText ( pDataReq->hwndMDI, szBuf );
  2235. SetFocus ( pDataReq->hwndMDI );
  2236. pMDI->CurSelFormat = CBM_AUTO;
  2237. pMDI->fDisplayFormatChanged = TRUE;
  2238. ResetScrollInfo ( pDataReq->hwndMDI );
  2239. // means data is for going into page mode
  2240. if ( pMDI->DisplayMode != DSP_PAGE )
  2241. {
  2242. pMDI->OldDisplayMode = pMDI->DisplayMode;
  2243. pMDI->DisplayMode = DSP_PAGE;
  2244. AdjustControlSizes ( pDataReq->hwndMDI );
  2245. ShowHideControls ( pDataReq->hwndMDI );
  2246. InitializeMenu ( GetMenu(hwndApp) );
  2247. }
  2248. else // data is for scrolling up or down one page
  2249. {
  2250. SendMessage ( pMDI->hWndListbox, LB_SETCURSEL,
  2251. pDataReq->iListbox, 0L );
  2252. }
  2253. UpdateNofMStatus ( pDataReq->hwndMDI );
  2254. InvalidateRect ( pDataReq->hwndMDI, NULL, TRUE );
  2255. // refresh preview bitmap?
  2256. if ( !lpLE->hbmp )
  2257. {
  2258. GetPreviewBitmap ( pDataReq->hwndMDI, lpLE->name,
  2259. pDataReq->iListbox );
  2260. }
  2261. // PINFO("\r\n");
  2262. bRet = TRUE;
  2263. break;
  2264. default:
  2265. PERROR (TEXT("unknown type %d in ProcessDataReq\n\r"),
  2266. pDataReq->rqType );
  2267. break;
  2268. }
  2269. done:
  2270. SetCursor (hSaveCursor);
  2271. return bRet;
  2272. }