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.

1645 lines
45 KiB

  1. #include <windows.h>
  2. #include <nddeapi.h>
  3. #include <nddesec.h>
  4. #include <string.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <memory.h>
  8. #include <assert.h>
  9. #include <ddeml.h>
  10. #include <strsafe.h>
  11. #include "common.h"
  12. #include "clipsrv.h"
  13. #include "clipfile.h"
  14. #include "ddeutil.h"
  15. #include "callback.h"
  16. #include "debugout.h"
  17. #define AUTOUPDATE
  18. #define ASKED_FOR_LINK 1
  19. #define ASKED_FOR_OBJECTLINK 2
  20. #define MAX_XERR 128 // maximum number of XERRs we'll store
  21. #define XERR_INUSE 1
  22. typedef struct _XERR // struct for Xaction ERRor
  23. {
  24. HCONV hConv; // the conversation handle
  25. DWORD dwErr; // the error code
  26. DWORD dwUse; // usage, when & with XERR_MASK gives type,
  27. } // bit 1 is set when if struct is in use.
  28. XERR, *PXERR;
  29. XERR gXactErr[MAX_XERR];
  30. TCHAR gszXactErrStr[30];
  31. TCHAR szInitShareCmd[] = SZCMD_INITSHARE;
  32. TCHAR szExitCmd[] = SZCMD_EXIT;
  33. TCHAR szPasteShareCmd[] = SZCMD_PASTESHARE;
  34. TCHAR szDelShareCmd[] = SZCMD_DELETE;
  35. TCHAR szMarkSharedCmd[] = SZCMD_SHARE;
  36. TCHAR szMarkUnSharedCmd[] = SZCMD_UNSHARE;
  37. TCHAR szKeepCmd[] = SZCMD_PASTE;
  38. TCHAR szSaveAsCmd[] = SZCMD_SAVEAS;
  39. TCHAR szSaveAsOldCmd[] = SZCMD_SAVEASOLD;
  40. TCHAR szOpenCmd[] = SZCMD_OPEN;
  41. TCHAR szDebugCmd[] = SZCMD_DEBUG;
  42. TCHAR szVersionCmd[] = SZCMD_VERSION;
  43. TCHAR szSecurityCmd[] = SZCMD_SECURITY;
  44. TCHAR szDebug[] = TEXT("Debug");
  45. TCHAR szVer[] = TEXT("1.1"); // need to be able to
  46. // handle Uni or Ansi req's for this
  47. TCHAR szSection[] = TEXT("Software\\Microsoft\\Clipbook Server");
  48. TCHAR szClipviewRoot[] = TEXT("Software\\Microsoft\\Clipbook");
  49. TCHAR szRegClass[] = TEXT("Config");
  50. HSZ hszSysTopic;
  51. HSZ hszTopicList;
  52. HSZ hszFormatList;
  53. HSZ hszErrorRequest;
  54. /*
  55. * MakeTheRegKey
  56. *
  57. * Purpose: Open the usual key (the one named by szSection) with the
  58. * specified access.
  59. *
  60. * Parameters:
  61. * phkey - Pointer to the HKEY to fill
  62. * regsam - The access types, same as RegCreateKeyEx
  63. *
  64. * Returns:
  65. * ERROR_SUCCESS on success, whatever RegOpenKeyEx returns on fail.
  66. */
  67. LONG MakeTheRegKey(
  68. PHKEY phkey,
  69. REGSAM regsam)
  70. {
  71. DWORD dwR;
  72. DWORD dwIck;
  73. dwR = RegCreateKeyEx (HKEY_LOCAL_MACHINE,
  74. szSection,
  75. 0,
  76. szRegClass,
  77. REG_OPTION_NON_VOLATILE,
  78. regsam,
  79. NULL,
  80. phkey,
  81. &dwIck);
  82. if (dwR == ERROR_SUCCESS)
  83. {
  84. return ERROR_SUCCESS;
  85. }
  86. dwR = RegOpenKeyEx (HKEY_LOCAL_MACHINE, szSection, 0, regsam, phkey);
  87. if (dwR == ERROR_SUCCESS)
  88. {
  89. return ERROR_SUCCESS;
  90. }
  91. PERROR(TEXT("Couldn't regopen %s with %lx access - #%lx\r\n"), szSection, (long)regsam, dwR);
  92. return dwR;
  93. }
  94. /*
  95. * lstrncmp
  96. */
  97. int lstrncmp(
  98. LPTSTR s1,
  99. LPTSTR s2,
  100. WORD count )
  101. {
  102. unsigned i;
  103. register TCHAR tch1;
  104. register TCHAR tch2;
  105. for (i = 0; i < (unsigned)count; i++)
  106. {
  107. if ( (tch1 = *s1++) != (tch2 = *s2++) )
  108. {
  109. if (tch1 < tch2)
  110. return -1;
  111. else
  112. return 1;
  113. }
  114. }
  115. return 0;
  116. }
  117. /*
  118. * AddXactErr
  119. *
  120. * To add a XERR record for hConv. Called
  121. * when XTYP_CONNECT_CONFIRM.
  122. */
  123. static VOID AddXactErr(
  124. HCONV hConv)
  125. {
  126. INT i;
  127. for (i=0; i<MAX_XERR; i++)
  128. if (!(gXactErr[i].dwUse & XERR_INUSE))
  129. {
  130. gXactErr[i].hConv = hConv;
  131. gXactErr[i].dwErr = 0;
  132. gXactErr[i].dwUse = XERR_INUSE;
  133. return;
  134. }
  135. }
  136. /*
  137. * DelXactErr
  138. *
  139. * To delete a XERR record for hConv.
  140. * Called at XTYP_DISCONNECT.
  141. */
  142. static VOID DelXactErr(
  143. HCONV hConv)
  144. {
  145. INT i;
  146. for (i=0; i<MAX_XERR; i++)
  147. if ((gXactErr[i].dwUse & XERR_INUSE) && gXactErr[i].hConv == hConv)
  148. {
  149. gXactErr[i].dwUse = 0;
  150. return;
  151. }
  152. }
  153. /*
  154. * GetXactErr
  155. *
  156. * Returns the XERR error code associated with hConv.
  157. */
  158. DWORD GetXactErr(
  159. HCONV hConv)
  160. {
  161. INT i;
  162. for (i=0; i<MAX_XERR; i++)
  163. if ((gXactErr[i].dwUse & XERR_INUSE) && gXactErr[i].hConv == hConv)
  164. return gXactErr[i].dwErr;
  165. return 0L;
  166. }
  167. /*
  168. * GetXactErrType
  169. *
  170. * Returns the XERR error type associated with hConv.
  171. */
  172. DWORD GetXactErrType(
  173. HCONV hConv)
  174. {
  175. INT i;
  176. for (i=0; i<MAX_XERR; i++)
  177. if ((gXactErr[i].dwUse & XERR_INUSE) && gXactErr[i].hConv == hConv)
  178. return gXactErr[i].dwUse & XERRT_MASK;
  179. return 0L;
  180. }
  181. /*
  182. * SetXactErr
  183. *
  184. * Sets XERR for hConv.
  185. * dwType specifies type, this should be one of the XERRT_ defines.
  186. * dwErr specifies error code.
  187. */
  188. VOID SetXactErr(
  189. HCONV hConv,
  190. DWORD dwType,
  191. DWORD dwErr)
  192. {
  193. INT i;
  194. for (i=0; i<MAX_XERR; i++)
  195. if ((gXactErr[i].dwUse & XERR_INUSE) && gXactErr[i].hConv == hConv)
  196. {
  197. gXactErr[i].dwErr = dwErr;
  198. gXactErr[i].dwUse = (gXactErr[i].dwUse & ~XERRT_MASK) | dwType;
  199. return;
  200. }
  201. }
  202. /*
  203. * DdeCallback
  204. */
  205. HDDEDATA EXPENTRY DdeCallback(
  206. WORD wType,
  207. WORD wFmt,
  208. HCONV hConv,
  209. HSZ hszTopic,
  210. HSZ hszItem,
  211. HDDEDATA hData,
  212. DWORD lData1,
  213. DWORD lData2)
  214. {
  215. HDDEDATA hDDEtmp = 0L;
  216. UINT uiErr;
  217. PINFO(TEXT("\n>>>> DdeCallback\n"));
  218. if (!(wType & XCLASS_NOTIFICATION))
  219. {
  220. PINFO(TEXT("Impersonating\n"));
  221. DdeImpersonateClient(hConv);
  222. }
  223. switch ( wType )
  224. {
  225. case XTYP_CONNECT_CONFIRM:
  226. PINFO (TEXT("XTYP_CONNECT_CONFIRM\n"));
  227. AddXactErr (hConv);
  228. PINFO(TEXT("Confirming connect\r\n"));
  229. hDDEtmp = (HDDEDATA)TRUE;
  230. break;
  231. case XTYP_EXECUTE:
  232. PINFO (TEXT("XTYP_EXECUTE\n"));
  233. // no error yet
  234. SetXactErr (hConv, 0, 0);
  235. // We only take executes on the System topic.
  236. // And only in Unicode or CF_TEXT format.
  237. if ((wFmt == CF_TEXT || wFmt == CF_UNICODETEXT) &&
  238. DdeCmpStringHandles ( hszTopic, hszSysTopic ) )
  239. {
  240. PERROR(TEXT("XTYP_EXECUTE received on non-system topic\n\r"));
  241. hDDEtmp = (HDDEDATA)DDE_FNOTPROCESSED;
  242. break;
  243. }
  244. DdeGetData(hData, (LPBYTE)szExec, MAX_EXEC, 0);
  245. szExec[MAX_EXEC - 1] = '\0';
  246. hDDEtmp = DDE_FNOTPROCESSED;
  247. if (!lstrcmp (szExec, szInitShareCmd))
  248. {
  249. InitShares();
  250. hDDEtmp = (HDDEDATA)DDE_FACK;
  251. }
  252. else if (!lstrncmp (szExec, szKeepCmd, (WORD)lstrlen(szKeepCmd)))
  253. {
  254. DWORD dwErr;
  255. dwErr = AddShare ( szExec + lstrlen(szKeepCmd ), 0);
  256. if (dwErr != NO_ERROR)
  257. SetXactErr (hConv, XERRT_SYS, dwErr);
  258. else
  259. hDDEtmp = (HDDEDATA)DDE_FACK;
  260. }
  261. else if (!lstrncmp (szExec, szVersionCmd, (WORD)lstrlen(szVersionCmd)))
  262. {
  263. hDDEtmp = DdeCreateDataHandle(idInst, szVer, sizeof(szVer) + 1, 0, 0L, wFmt, 0L);
  264. }
  265. else if (!lstrncmp( szExec, szSaveAsCmd, (WORD)lstrlen(szSaveAsCmd)))
  266. {
  267. DWORD dwErr;
  268. fNTSaveFileFormat = TRUE;
  269. dwErr = SaveClipboardToFile (hwndApp, NULL, szExec + lstrlen(szSaveAsCmd ), FALSE);
  270. if (dwErr != NO_ERROR)
  271. SetXactErr (hConv, XERRT_SYS, dwErr);
  272. else
  273. hDDEtmp = (HDDEDATA)DDE_FACK;
  274. }
  275. else if (!lstrncmp (szExec, szSaveAsOldCmd, (WORD)lstrlen(szSaveAsOldCmd)))
  276. {
  277. DWORD dwErr;
  278. fNTSaveFileFormat = FALSE;
  279. dwErr = SaveClipboardToFile(hwndApp, NULL, szExec + lstrlen(szSaveAsOldCmd), FALSE);
  280. if (dwErr != NO_ERROR)
  281. SetXactErr (hConv, XERRT_SYS, dwErr);
  282. else
  283. hDDEtmp = (HDDEDATA)DDE_FACK;
  284. }
  285. else if (!lstrncmp (szExec, szOpenCmd, (WORD)lstrlen(szOpenCmd )) )
  286. {
  287. DWORD dwErr;
  288. dwErr = OpenClipboardFile(hwndApp, szExec + lstrlen(szOpenCmd));
  289. if (dwErr != NO_ERROR)
  290. SetXactErr (hConv, XERRT_SYS, dwErr);
  291. else
  292. hDDEtmp = (HDDEDATA)DDE_FACK;
  293. }
  294. else if (!lstrncmp (szExec, szDelShareCmd, (WORD)lstrlen(szDelShareCmd)))
  295. {
  296. PINFO(TEXT("Deleting %s\n\r"), (LPSTR)szExec + lstrlen(szDelShareCmd));
  297. if (DelShare ( hConv, szExec + lstrlen(szDelShareCmd) ))
  298. {
  299. hDDEtmp = (HDDEDATA)DDE_FACK;
  300. }
  301. }
  302. else if (!lstrncmp (szExec,szMarkSharedCmd, (WORD)lstrlen(szMarkSharedCmd)))
  303. {
  304. PINFO(TEXT("Marking %s as shared\n\r"), (LPSTR)szExec + lstrlen(szMarkSharedCmd));
  305. if ( MarkShare (szExec + lstrlen(szMarkSharedCmd), SIF_SHARED ))
  306. {
  307. hDDEtmp = (HDDEDATA)DDE_FACK;
  308. }
  309. }
  310. else if (!lstrncmp(szExec,szMarkUnSharedCmd, (WORD)lstrlen(szMarkUnSharedCmd)))
  311. {
  312. if ( MarkShare ( szExec + lstrlen(szMarkUnSharedCmd ), 0 ))
  313. {
  314. hDDEtmp = (HDDEDATA)DDE_FACK;
  315. }
  316. }
  317. #if DEBUG
  318. else if (!lstrncmp(szExec,szDebugCmd, (WORD)lstrlen(szDebugCmd)))
  319. {
  320. DumpShares();
  321. hDDEtmp = (HDDEDATA)DDE_FACK;
  322. }
  323. #endif
  324. else
  325. {
  326. PERROR(TEXT("Invalid execute\r\n"));
  327. hDDEtmp = (HDDEDATA)DDE_FNOTPROCESSED;
  328. }
  329. break;
  330. case XTYP_DISCONNECT:
  331. PINFO (TEXT("XTYP_DISCONNECT\n"));
  332. DelXactErr (hConv);
  333. break;
  334. case XTYP_CONNECT:
  335. PINFO (TEXT("XTYP_CONNECT\n"));
  336. hDDEtmp = (HDDEDATA)FALSE;
  337. if ( IsSupportedTopic( hszTopic ) )
  338. {
  339. if (!DdeKeepStringHandle (idInst, hszAppName))
  340. {
  341. PERROR(TEXT("DdeKSHandle fail in DdeCB\r\n"));
  342. }
  343. hDDEtmp = (HDDEDATA)TRUE;
  344. }
  345. #if DEBUG
  346. else
  347. {
  348. TCHAR buf[128];
  349. DdeQueryString ( idInst, hszTopic, buf, 128, CP_WINANSI );
  350. PERROR(TEXT("ClipSRV: Unsupported topic %s requested\n\r"), (LPSTR)buf );
  351. }
  352. #endif
  353. break;
  354. case XTYP_ADVREQ:
  355. case XTYP_REQUEST:
  356. // must be a valid topic
  357. {
  358. TCHAR atch[128];
  359. PINFO (wType==XTYP_ADVREQ?
  360. TEXT("XTYP_ADVREQ\n"): TEXT("XTYP_REQUEST\n"));
  361. DdeQueryString(idInst, hszTopic, atch, 128, CP_WINANSI);
  362. PINFO(TEXT("Topic = %s, "), atch);
  363. DdeQueryString(idInst, hszItem, atch, 128, CP_WINANSI);
  364. PINFO(TEXT("item = %s\r\n"), atch);
  365. }
  366. if (!IsSupportedTopic ( hszTopic ))
  367. {
  368. #if DEBUG
  369. TCHAR buf[128];
  370. DdeQueryString ( idInst, hszTopic, buf, 128, CP_WINANSI );
  371. PERROR(TEXT("Topic %s unsupported!\n\r"), (LPTSTR)buf );
  372. #endif
  373. hDDEtmp = (HDDEDATA)0;
  374. }
  375. else
  376. {
  377. PINFO("System topic request\r\n");
  378. if (!DdeCmpStringHandles (hszTopic, hszSysTopic))
  379. {
  380. if (!DdeCmpStringHandles (hszItem, hszErrorRequest))
  381. {
  382. StringCchPrintf (gszXactErrStr, 30,
  383. XERR_FORMAT,
  384. GetXactErrType (hConv),
  385. GetXactErr (hConv));
  386. hDDEtmp = DdeCreateDataHandle (idInst,
  387. gszXactErrStr,
  388. lstrlen(gszXactErrStr)+sizeof(CHAR),
  389. 0,
  390. hszErrorRequest,
  391. wFmt,
  392. 0);
  393. uiErr = DdeGetLastError (idInst);
  394. }
  395. else if (!DdeCmpStringHandles (hszItem, hszTopicList))
  396. {
  397. PINFO(TEXT("Topic list requested\r\n"));
  398. SetXactErr (hConv, 0, 0);
  399. if (CF_TEXT == wFmt)
  400. {
  401. hDDEtmp = (HDDEDATA)GetTopicListA(hConv, TRUE);
  402. }
  403. else if (CF_UNICODETEXT == wFmt)
  404. {
  405. hDDEtmp = (HDDEDATA)GetTopicListW(hConv, TRUE);
  406. }
  407. else // Can't get the topiclist in anything but CF_TEXT or UNICODE
  408. {
  409. PERROR(TEXT("ClSrv\\DdeCB: Client asked for topics in bad fmt\r\n"));
  410. hDDEtmp = (HDDEDATA)0;
  411. }
  412. }
  413. else
  414. {
  415. #if DEBUG
  416. TCHAR rgtch[128];
  417. DdeQueryString(idInst, hszItem,rgtch, 128, CP_WINANSI);
  418. PERROR(TEXT("item %s requested under system\n\r"), rgtch);
  419. #endif
  420. hDDEtmp = (HDDEDATA)0;
  421. }
  422. }
  423. else
  424. {
  425. // all other topics are assumed clipboard shares!!!
  426. // Is format list the requested item?
  427. if (!DdeCmpStringHandles (hszItem, hszErrorRequest))
  428. {
  429. StringCchPrintf (gszXactErrStr, 30,
  430. XERR_FORMAT,
  431. GetXactErrType (hConv),
  432. GetXactErr (hConv));
  433. hDDEtmp = DdeCreateDataHandle (idInst,
  434. gszXactErrStr,
  435. lstrlen(gszXactErrStr)+sizeof(CHAR),
  436. 0,
  437. hszErrorRequest,
  438. wFmt,
  439. 0);
  440. uiErr = DdeGetLastError (idInst);
  441. }
  442. else if (!DdeCmpStringHandles (hszItem, hszFormatList))
  443. {
  444. PINFO(TEXT("Getting format list\r\n"));
  445. SetXactErr (hConv, 0, 0);
  446. if (CF_TEXT == wFmt)
  447. {
  448. hDDEtmp = (HDDEDATA)GetFormatListA(hConv, hszTopic);
  449. }
  450. else
  451. {
  452. hDDEtmp = (HDDEDATA)GetFormatListW(hConv, hszTopic);
  453. }
  454. }
  455. else
  456. { // request for specific format, or invalid
  457. SetXactErr (hConv, 0, 0);
  458. hDDEtmp = GetFormat ( hConv, hszTopic, hszItem );
  459. }
  460. }
  461. }
  462. break;
  463. case XTYP_ADVSTART:
  464. PINFO (TEXT("XTYP_ADVSTART\n"));
  465. if (0 == DdeCmpStringHandles(hszItem, hszTopicList) &&
  466. 0 == DdeCmpStringHandles(hszTopic, hszSysTopic))
  467. {
  468. PINFO(TEXT("Advise on topiclist OK\r\n"));
  469. hDDEtmp = (HDDEDATA)TRUE;
  470. }
  471. else
  472. {
  473. PERROR(TEXT("Advise loop requested on item other than topiclist\n\r"));
  474. hDDEtmp = (HDDEDATA)FALSE;
  475. }
  476. break;
  477. default:
  478. PINFO (TEXT("unknown wType %#x\n"), wType);
  479. break;
  480. }
  481. if (!(wType & XCLASS_NOTIFICATION))
  482. {
  483. RevertToSelf();
  484. }
  485. if (0L == hDDEtmp)
  486. {
  487. TCHAR atch[128];
  488. DdeQueryString(idInst, hszTopic, atch, 128, CP_WINANSI);
  489. PINFO(TEXT("Topic was %s, "), atch);
  490. DdeQueryString(idInst, hszItem, atch, 128, CP_WINANSI);
  491. PINFO(TEXT("item was %s\r\n"), atch);
  492. }
  493. PINFO(TEXT("Return %#x\n"), hDDEtmp);
  494. PINFO(TEXT("<<<< DdeCallback\n\n"));
  495. return hDDEtmp;
  496. }
  497. /*
  498. * IsSupportedTopic
  499. */
  500. BOOL IsSupportedTopic ( HSZ hszTopic )
  501. {
  502. pShrInfo p;
  503. if ( !DdeCmpStringHandles (hszTopic, hszSysTopic))
  504. {
  505. DdeKeepStringHandle ( idInst, hszTopic );
  506. return TRUE;
  507. }
  508. for ( p = SIHead; p; p = p->Next )
  509. {
  510. if (!DdeCmpStringHandles (hszTopic, p->hszName))
  511. return TRUE;
  512. }
  513. return FALSE;
  514. }
  515. /*
  516. * CleanUpShares
  517. */
  518. BOOL CleanUpShares ( VOID )
  519. {
  520. pShrInfo p, tmp;
  521. for (p=SIHead; p; p=tmp)
  522. {
  523. DdeFreeStringHandle ( idInst, p->hszName );
  524. #ifdef CACHEFORMATLIST
  525. PINFO(TEXT("freeing cached format list\n\r"));
  526. if ( p->hFormatList )
  527. DdeFreeDataHandle ( p->hFormatList );
  528. #endif
  529. #ifdef CACHEPREVIEWS
  530. PINFO(TEXT("freeing cached preview bitmap\n\r"));
  531. if ( p->hPreviewBmp )
  532. DdeFreeDataHandle ( p->hPreviewBmp );
  533. #endif
  534. tmp = p->Next;
  535. LocalFree ((HLOCAL) p );
  536. }
  537. SIHead = NULL;
  538. return TRUE;
  539. }
  540. /*
  541. * InitShares
  542. */
  543. BOOL InitShares (VOID)
  544. {
  545. TCHAR szComputerName[MAX_COMPUTERNAME_LENGTH+3];
  546. TCHAR rgtchPageName[MAX_CLPSHRNAME+1];
  547. TCHAR rgtchPageFile[MAX_FILEPATH+1];
  548. DWORD dwPageSize;
  549. DWORD dwNameSize;
  550. DWORD dwType;
  551. HKEY hkeyClp;
  552. DWORD dwR;
  553. unsigned iValue = 0;
  554. unsigned iKeys = 0;
  555. CleanUpShares ();
  556. if (ERROR_SUCCESS != MakeTheRegKey(&hkeyClp, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE))
  557. {
  558. PERROR(TEXT("Couldn't get to Clipbook root key\r\n"));
  559. return FALSE;
  560. }
  561. szComputerName[0] = szComputerName[1] = TEXT('\\');
  562. dwNameSize = MAX_COMPUTERNAME_LENGTH+1;
  563. GetComputerName (szComputerName+2, &dwNameSize);
  564. do {
  565. dwNameSize = sizeof (rgtchPageName);
  566. dwPageSize = sizeof (rgtchPageFile);
  567. dwR = RegEnumValue (hkeyClp,
  568. iValue,
  569. rgtchPageName,
  570. &dwNameSize,
  571. NULL,
  572. &dwType,
  573. (LPBYTE)rgtchPageFile,
  574. &dwPageSize);
  575. if (dwR == ERROR_SUCCESS)
  576. {
  577. rgtchPageName[dwNameSize] = 0;
  578. rgtchPageFile[dwPageSize] = 0;
  579. AddRecord (rgtchPageName,
  580. rgtchPageFile,
  581. (SHR_CHAR == rgtchPageName[0]) ? SIF_SHARED : 0);
  582. }
  583. iValue++;
  584. } while (dwR != ERROR_NO_MORE_ITEMS);
  585. RegCloseKey(hkeyClp);
  586. PINFO(TEXT("Read %d pages\r\n"),iKeys);
  587. return TRUE;
  588. }
  589. /*
  590. * GetFormat
  591. */
  592. HDDEDATA GetFormat (
  593. HCONV hConv,
  594. HSZ hszTopic,
  595. HSZ hszItem )
  596. {
  597. HDDEDATA hData = 0l;
  598. HANDLE hClpData = NULL;
  599. DWORD cbData = 0L;
  600. pShrInfo pshrinfo;
  601. HANDLE fh;
  602. FORMATHEADER FormatHeader;
  603. unsigned i;
  604. TCHAR szItemKey[CCHFMTNAMEMAX];
  605. unsigned cFormats;
  606. BOOL fPreviewRequested;
  607. unsigned fLocalAskedForLocal = 0;
  608. #ifndef UNICODE
  609. TCHAR szFormatName[CCHFMTNAMEMAX * 2];
  610. #endif
  611. PINFO(TEXT("Clsrv\\GetFormat:"));
  612. if (!DdeQueryString (idInst,hszItem,szItemKey,CCHFMTNAMEMAX,CP_WINANSI))
  613. {
  614. PERROR(TEXT("invalid item\n\r"));
  615. return 0;
  616. }
  617. // is the asked-for format cf_preview?
  618. fPreviewRequested = !lstrcmpi ( szItemKey, SZPREVNAME );
  619. for ( pshrinfo=SIHead; pshrinfo; pshrinfo = pshrinfo->Next )
  620. {
  621. if ( DdeCmpStringHandles ( hszTopic, pshrinfo->hszName ) == 0 )
  622. {
  623. DdeKeepStringHandle ( idInst, hszTopic );
  624. if ( fPreviewRequested && pshrinfo->hPreviewBmp )
  625. {
  626. return pshrinfo->hPreviewBmp;
  627. }
  628. fh = CreateFileW(pshrinfo->szFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
  629. if ( INVALID_HANDLE_VALUE == fh)
  630. {
  631. PERROR(TEXT("ERROR opening %ls\n\r"), pshrinfo->szFileName );
  632. }
  633. else
  634. {
  635. cFormats = ReadFileHeader(fh);
  636. if (0 == cFormats)
  637. {
  638. PERROR(TEXT("Bad .CLP file\r\n"));
  639. }
  640. for (i=0; i < cFormats; i++)
  641. {
  642. ReadFormatHeader(fh, &FormatHeader, i);
  643. #ifndef UNICODE
  644. WideCharToMultiByte (CP_ACP,
  645. 0,
  646. FormatHeader.Name,
  647. CCHFMTNAMEMAX,
  648. szFormatName,
  649. CCHFMTNAMEMAX * 2,
  650. NULL,
  651. NULL);
  652. if (!lstrcmpi (szItemKey, szFormatName))
  653. #else
  654. if (!lstrcmpi (szItemKey, FormatHeader.Name))
  655. #endif
  656. {
  657. // Put back the format names, if a local client asked
  658. // us for objectlink or link.
  659. if (ASKED_FOR_OBJECTLINK == fLocalAskedForLocal)
  660. {
  661. StringCchCopyW(FormatHeader.Name, CCHFMTNAMEMAX, LSZOBJECTLINK);
  662. }
  663. else if (ASKED_FOR_LINK == fLocalAskedForLocal)
  664. {
  665. StringCchCopyW(FormatHeader.Name, CCHFMTNAMEMAX, LSZLINK);
  666. }
  667. hData = RenderRawFormatToDDE(&FormatHeader, fh);
  668. #ifdef CACHEPREVIEWS
  669. if ( fPreviewRequested )
  670. {
  671. PINFO(TEXT("GetFormat: caching preview\n\r"));
  672. pshrinfo->hPreviewBmp = hData;
  673. }
  674. #endif
  675. #if DEBUG
  676. if (!hData)
  677. {
  678. PERROR(TEXT("RenderRawFormatToDDE resulted in 0 handle\n\r"));
  679. }
  680. #endif
  681. }
  682. }
  683. if (!hData)
  684. {
  685. PERROR(TEXT("GetFormat: requested format %s not found\n\r"),
  686. (LPSTR)szItemKey );
  687. }
  688. CloseHandle(fh);
  689. }
  690. }
  691. }
  692. PINFO("Returning %lx",hData);
  693. return hData;
  694. }
  695. /*
  696. * DelShare
  697. *
  698. * Purpose: Delete a ClipBook page.
  699. *
  700. * Parameters:
  701. * pszName - The name of the page.
  702. *
  703. * Returns:
  704. * TRUE on success, FALSE on failure.
  705. */
  706. BOOL DelShare(
  707. HCONV hConv,
  708. TCHAR *pszName)
  709. {
  710. pShrInfo pshrinfo;
  711. pShrInfo q;
  712. HKEY hkeyClp;
  713. TCHAR atch[MAX_COMPUTERNAME_LENGTH + 3];
  714. DWORD dwLen = MAX_COMPUTERNAME_LENGTH + 1;
  715. BOOL fOK = FALSE;
  716. DWORD ret;
  717. WCHAR rgwchT[MAX_CLPSHRNAME + 1];
  718. TCHAR tch;
  719. assert(pszName);
  720. assert(*pszName);
  721. #ifndef UNICODE
  722. MultiByteToWideChar(CP_ACP, 0, pszName, -1, rgwchT, MAX_CLPSHRNAME + 1);
  723. #else
  724. StringCchCopy(rgwchT, MAX_CLPSHRNAME + 1, pszName);
  725. #endif
  726. PINFO(TEXT("Looking for %ls\r\n"), rgwchT);
  727. q = NULL;
  728. for (pshrinfo = SIHead; pshrinfo; pshrinfo = (q = pshrinfo)->Next)
  729. {
  730. assert(pshrinfo->szName);
  731. PINFO(TEXT("Comparing to %ls\r\n"), pshrinfo->szName);
  732. if (!lstrcmpW(pshrinfo->szName, rgwchT))
  733. {
  734. // Delete the Network DDE share for this item
  735. atch[0] = atch[1] = TEXT('\\');
  736. dwLen = MAX_COMPUTERNAME_LENGTH +1;
  737. GetComputerName(atch+2, &dwLen);
  738. tch = pszName[0];
  739. pszName[0] = SHR_CHAR;
  740. PINFO(TEXT("Deleting share %s on %s\r\n"), pszName, atch);
  741. ret = NDdeShareDel(atch, pszName, 0);
  742. pszName[0] = tch;
  743. if (NDDE_NO_ERROR == ret)
  744. {
  745. // Delete the key in the registry
  746. RevertToSelf();
  747. if (ERROR_SUCCESS == MakeTheRegKey(&hkeyClp, KEY_SET_VALUE))
  748. {
  749. RegDeleteValue(hkeyClp, pszName);
  750. RegCloseKey(hkeyClp);
  751. }
  752. else
  753. {
  754. PERROR(TEXT("Couldn't delete key! #%ld\r\n"), GetLastError());
  755. }
  756. DdeImpersonateClient(hConv);
  757. // force render all if applicable!
  758. SendMessage (hwndApp, WM_RENDERALLFORMATS, 0, 0L);
  759. // unlink file!
  760. DeleteFileW(pshrinfo->szFileName);
  761. // Take this page out of the linked list of pages.
  762. if (q == NULL)
  763. {
  764. SIHead = pshrinfo->Next;
  765. }
  766. else
  767. {
  768. q->Next = pshrinfo->Next;
  769. }
  770. DdeFreeStringHandle ( idInst, pshrinfo->hszName );
  771. if ( pshrinfo->hFormatList )
  772. DdeFreeDataHandle ( pshrinfo->hFormatList );
  773. if ( pshrinfo->hPreviewBmp )
  774. DdeFreeDataHandle ( pshrinfo->hPreviewBmp );
  775. LocalFree ( (HLOCAL)pshrinfo );
  776. #ifdef AUTOUPDATE
  777. DdePostAdvise ( idInst, hszSysTopic, hszTopicList );
  778. #endif
  779. fOK = TRUE;
  780. }
  781. else
  782. {
  783. PERROR(TEXT("Csrv: NDde err %ld on delshare\r\n"), ret);
  784. SetXactErr (hConv, XERRT_NDDE, ret);
  785. }
  786. break; // Don't loop thru additional pages if you found the right one
  787. }
  788. }
  789. if (!fOK)
  790. {
  791. PERROR(TEXT("Clipsrv: item to delete '%s' not found\n\r"), pszName );
  792. }
  793. return fOK;
  794. }
  795. /*
  796. * AddRecord
  797. *
  798. * Purpose:
  799. * Add a record to the linked list of Clipbook pages in memory.
  800. *
  801. * Parameters:
  802. * lpszName - Name of the page.
  803. * lpszFileName - Name of the .CLP file containing the page's data.
  804. * siflags - Flags for the page.
  805. *
  806. * Returns:
  807. * TRUE on success, FALSE on failure
  808. */
  809. BOOL AddRecord (
  810. LPTSTR lpszName,
  811. LPTSTR lpszFileName,
  812. ULONG siflags)
  813. {
  814. pShrInfo pshrinfo;
  815. PINFO(TEXT("Making page %s with file %s\r\n"), lpszName, lpszFileName);
  816. pshrinfo = (pShrInfo) LocalAlloc ( LPTR, sizeof ( ShrInfo ) );
  817. if ( !pshrinfo )
  818. {
  819. PERROR(TEXT("AddRecord: LocalAlloc failed\n\r"));
  820. return FALSE;
  821. }
  822. if ( !( pshrinfo->hszName = DdeCreateStringHandle ( idInst, lpszName, 0 )))
  823. {
  824. PERROR(TEXT("AddRecord: DdeCHSZ fail\r\n"));
  825. LocalFree (pshrinfo);
  826. return(FALSE);
  827. }
  828. #ifdef UNICODE
  829. StringCchCopy( pshrinfo->szFileName, MAX_FILEPATH, lpszFileName );
  830. StringCchCopy( pshrinfo->szName, MAX_CLPSHRNAME+1, lpszName );
  831. #else
  832. MultiByteToWideChar(CP_ACP, 0L, lpszFileName, -1, pshrinfo->szFileName, MAX_FILEPATH - 1);
  833. MultiByteToWideChar(CP_ACP, 0L, lpszName, -1, pshrinfo->szName, MAX_CLPSHRNAME);
  834. #endif
  835. PINFO(TEXT("Made page %ls with file %ls\r\n"), pshrinfo->szName, pshrinfo->szFileName);
  836. #ifdef CACHEFORMATLIST
  837. pshrinfo->hFormatList = 0L;
  838. #endif
  839. #ifdef CACHEPREVIEWS
  840. pshrinfo->hPreviewBmp = 0L;
  841. #endif
  842. pshrinfo->Next = SIHead;
  843. SIHead = pshrinfo;
  844. pshrinfo->flags = (WORD) siflags;
  845. return TRUE;
  846. }
  847. /*
  848. * ResetRecord
  849. *
  850. * When paste into an existing page, we need to clear the cached
  851. * stuff for the old data.
  852. */
  853. void ResetRecord (pShrInfo pInfo)
  854. {
  855. // clear the format list
  856. if (pInfo->hFormatList)
  857. {
  858. DdeFreeDataHandle (pInfo->hFormatList);
  859. pInfo->hFormatList = NULL;
  860. }
  861. // clear the preview bitmap
  862. if (pInfo->hPreviewBmp)
  863. {
  864. DdeFreeDataHandle (pInfo->hPreviewBmp);
  865. pInfo->hPreviewBmp = NULL;
  866. }
  867. }
  868. /*
  869. * GetShareFileName
  870. *
  871. */
  872. pShrInfo GetShareFileName (LPTSTR szSName, LPTSTR szFName)
  873. {
  874. BOOL bRet = FALSE;
  875. HSZ hS;
  876. CHAR cSave;
  877. pShrInfo pInfo;
  878. cSave = *szSName;
  879. hS = DdeCreateStringHandle (idInst, szSName, 0);
  880. if (!hS)
  881. goto done;
  882. for (pInfo = SIHead; pInfo; pInfo = pInfo->Next)
  883. if (!DdeCmpStringHandles (pInfo->hszName, hS))
  884. {
  885. #ifndef UNICODE
  886. WideCharToMultiByte (CP_ACP,
  887. 0,
  888. pInfo->szFileName,
  889. -1,
  890. szFName,
  891. MAX_PATH+1,
  892. NULL,
  893. NULL);
  894. #else
  895. StringCchCopy (szFName, MAX_PATH+1, pInfo->szFileName);
  896. #endif
  897. bRet = TRUE;
  898. goto done;
  899. }
  900. DdeFreeStringHandle (idInst, hS);
  901. // not found, change share name to shared or unshared
  902. if (UNSHR_CHAR == cSave)
  903. *szSName = SHR_CHAR;
  904. else
  905. *szSName = UNSHR_CHAR;
  906. // try again with new share name
  907. hS = DdeCreateStringHandle (idInst, szSName, 0);
  908. if (!hS)
  909. goto done;
  910. for (pInfo = SIHead; pInfo; pInfo = pInfo->Next)
  911. if (!DdeCmpStringHandles (pInfo->hszName, hS))
  912. {
  913. #ifndef UNICODE
  914. WideCharToMultiByte (CP_ACP,
  915. 0,
  916. pInfo->szFileName,
  917. -1,
  918. szFName,
  919. MAX_PATH+1,
  920. NULL,
  921. NULL);
  922. #else
  923. StringCchCopy (szFName, MAX_PATH+1, pInfo->szFileName);
  924. #endif
  925. bRet = TRUE;
  926. goto done;
  927. }
  928. done:
  929. if (hS)
  930. DdeFreeStringHandle (idInst, hS);
  931. *szSName = cSave;
  932. if (bRet)
  933. return pInfo;
  934. else
  935. return NULL;
  936. }
  937. /*
  938. * AddShare
  939. *
  940. * Purpose:
  941. * Creates a new Clipbook page by doing this:
  942. * - Save the current clipboard with some random file name.
  943. * - Add the Clipbook page to the list in memory
  944. * - Record the existence of the page in the Clipbook Server
  945. * section of the registry. The value name is the page name,
  946. * and the value is the filename.
  947. *
  948. * Parameters:
  949. * pszName - Name of the page.
  950. * flags - Flags to store with the page.
  951. *
  952. * Returns:
  953. * TRUE on success, FALSE on failure.
  954. */
  955. DWORD AddShare(
  956. LPTSTR pszName,
  957. WORD flags)
  958. {
  959. TCHAR szFName[MAX_PATH+1];
  960. HKEY hkeyClp;
  961. DWORD dwR = NO_ERROR;
  962. pShrInfo pInfo;
  963. fNTSaveFileFormat = TRUE;
  964. if (pInfo = GetShareFileName (pszName, szFName))
  965. {
  966. dwR = SaveClipboardToFile (hwndApp, pszName, szFName, TRUE);
  967. ResetRecord (pInfo);
  968. StringCchCopy (szUpdateName, MAX_CLPSHRNAME+1, pszName);
  969. }
  970. else
  971. {
  972. dwR = GetRandShareFileName (szFName);
  973. if (dwR != NO_ERROR)
  974. return dwR;
  975. dwR = SaveClipboardToFile (hwndApp, pszName, szFName, TRUE);
  976. if (dwR != NO_ERROR)
  977. return dwR;
  978. if (!AddRecord ( pszName, szFName, flags ))
  979. return ERROR_NOT_ENOUGH_MEMORY;
  980. if (ERROR_SUCCESS == MakeTheRegKey(&hkeyClp, KEY_SET_VALUE))
  981. {
  982. RegSetValueEx(hkeyClp, pszName, 0, REG_SZ, szFName, lstrlen(szFName));
  983. RegCloseKey(hkeyClp);
  984. PINFO(TEXT("%s is being written...\n\r"), pszName);
  985. }
  986. }
  987. #ifdef AUTOUPDATE
  988. DdePostAdvise ( idInst, hszSysTopic, hszTopicList );
  989. #endif
  990. return dwR;
  991. }
  992. #if DEBUG
  993. /*
  994. * DumpShares
  995. */
  996. VOID DumpShares (void)
  997. {
  998. char buf[65];
  999. pShrInfo pshrinfo;
  1000. int i;
  1001. DWORD cbRet;
  1002. for ( i=0, pshrinfo = SIHead; pshrinfo; pshrinfo = pshrinfo->Next, i++ )
  1003. {
  1004. PINFO(TEXT("---------- Share %d flags:%x-------------\n\r"), i, pshrinfo->flags );
  1005. cbRet = DdeQueryString ( idInst, pshrinfo->hszName, buf, 128L, CP_WINANSI );
  1006. PINFO(TEXT("name: >%s<\n\r"), (LPSTR)pshrinfo->szName );
  1007. PINFO(TEXT("hsz: >%s<\n\r"), cbRet? (LPSTR)buf : (LPSTR)TEXT("ERROR") );
  1008. }
  1009. }
  1010. #else
  1011. VOID DumpShares (void)
  1012. {
  1013. }
  1014. #endif
  1015. /*
  1016. * MarkShare
  1017. *
  1018. * Purpose: Mark a Clipbook page as shared or unshared.
  1019. *
  1020. * Parameters:
  1021. * pszName - Name of the page.
  1022. * flags - 0 for "unshared", SIF_SHARED for "shared."
  1023. *
  1024. * Returns:
  1025. * TRUE on success, FALSE on failure.
  1026. *
  1027. */
  1028. BOOL MarkShare(
  1029. TCHAR *pszName,
  1030. WORD flags)
  1031. {
  1032. PSECURITY_DESCRIPTOR pSDShare;
  1033. pShrInfo pshrinfo;
  1034. HKEY hkeyClp;
  1035. INT iTmp;
  1036. ACCESS_ALLOWED_ACE *pace;
  1037. WCHAR rgwchT[MAX_CLPSHRNAME+1];
  1038. UINT ret;
  1039. DWORD dwBytes = sizeof(pSDShare);
  1040. WORD wItems = 0;
  1041. PACL Acl;
  1042. BOOL fDacl;
  1043. BOOL fDefault;
  1044. DWORD i;
  1045. #ifndef UNICODE
  1046. MultiByteToWideChar(CP_ACP, 0, pszName, -1, rgwchT, MAX_CLPSHRNAME);
  1047. #endif
  1048. PINFO(TEXT("Entering MarkShare\r\n"));
  1049. for (pshrinfo = SIHead; pshrinfo; pshrinfo = pshrinfo->Next)
  1050. {
  1051. #ifdef UNICODE
  1052. iTmp = lstrcmpW (pshrinfo->szName+1, pszName+1);
  1053. #else
  1054. iTmp = lstrcmpW (pshrinfo->szName+1, rgwchT+1);
  1055. #endif
  1056. if (!iTmp)
  1057. {
  1058. PINFO(TEXT("MarkShare: marking %s %d\n\r"), (LPSTR)pszName, flags );
  1059. // If the name's changing, need to delete old reg key.
  1060. // (We make the new one after hitting the file security.)
  1061. if ((pshrinfo->flags & SIF_SHARED) != (flags & SIF_SHARED))
  1062. {
  1063. PINFO(TEXT("Changing shared status\r\n"));
  1064. // Delete the registry item with the old name
  1065. if (ERROR_SUCCESS == MakeTheRegKey(&hkeyClp, KEY_SET_VALUE))
  1066. {
  1067. PINFO(TEXT("Deleting old name %ws\r\n"),pshrinfo->szName);
  1068. RegDeleteValueW(hkeyClp, pshrinfo->szName);
  1069. RegCloseKey(hkeyClp);
  1070. }
  1071. else
  1072. {
  1073. PERROR(TEXT("MarkShare: Couldn't open registry!\r\n"));
  1074. }
  1075. }
  1076. // Set name to reflect shared/unshared status
  1077. pshrinfo->szName[0] = (flags & SIF_SHARED) ? SHR_CHAR : UNSHR_CHAR;
  1078. pshrinfo->flags = flags;
  1079. // Sync the security on the Clipbook page file to be
  1080. // analogous to the security set on the NetDDE share.
  1081. pszName[0] = SHR_CHAR;
  1082. NDdeGetShareSecurity(NULL, pszName, DACL_SECURITY_INFORMATION, NULL, 0, &i);
  1083. PINFO(TEXT("Getting security %ld bytes\r\n"), i);
  1084. if (!(pSDShare = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, i)))
  1085. {
  1086. PERROR(TEXT("LocalAlloc fail\r\n"));
  1087. }
  1088. else
  1089. {
  1090. ret = NDdeGetShareSecurity (NULL,
  1091. pszName,
  1092. DACL_SECURITY_INFORMATION,
  1093. pSDShare,
  1094. i,
  1095. &i);
  1096. if (NDDE_NO_ERROR != ret)
  1097. {
  1098. PERROR(TEXT("Couldn't get sec #%ld\r\n"), ret);
  1099. }
  1100. else if (!GetSecurityDescriptorDacl(pSDShare, &fDacl, &Acl, &fDefault))
  1101. {
  1102. PERROR(TEXT("GetDACL fail %ld\r\n"), GetLastError());
  1103. }
  1104. else
  1105. {
  1106. DWORD dwGeneric;
  1107. for (i = 0; GetAce(Acl, i, &pace); i++)
  1108. {
  1109. dwGeneric = 0L;
  1110. // Convert NDDE access mask types to generic access
  1111. // mask types
  1112. if (ACCESS_ALLOWED_ACE_TYPE == pace->Header.AceType ||
  1113. ACCESS_DENIED_ACE_TYPE == pace->Header.AceType)
  1114. {
  1115. if ((pace->Mask & NDDE_SHARE_READ) == NDDE_SHARE_READ)
  1116. {
  1117. PINFO(TEXT("R"));
  1118. dwGeneric |= GENERIC_READ;
  1119. }
  1120. if ((pace->Mask & NDDE_SHARE_WRITE) == NDDE_SHARE_WRITE)
  1121. {
  1122. PINFO(TEXT("R"));
  1123. dwGeneric |= GENERIC_WRITE;
  1124. }
  1125. if ((pace->Mask & NDDE_GUI_CHANGE) == NDDE_GUI_CHANGE)
  1126. {
  1127. PINFO(TEXT("D"));
  1128. dwGeneric |= GENERIC_WRITE|GENERIC_READ|DELETE;
  1129. }
  1130. if ((pace->Mask & NDDE_GUI_FULL_CONTROL) ==
  1131. NDDE_GUI_FULL_CONTROL)
  1132. {
  1133. PINFO(TEXT("A"));
  1134. dwGeneric |= GENERIC_ALL;
  1135. }
  1136. PINFO(TEXT(" = %ld\r\n"), dwGeneric);
  1137. pace->Mask = dwGeneric;
  1138. }
  1139. else
  1140. {
  1141. PERROR(TEXT("Invalid ACE type!!!\r\n"));
  1142. }
  1143. }
  1144. ret = SetFileSecurityW (pshrinfo->szFileName,
  1145. DACL_SECURITY_INFORMATION,
  1146. pSDShare);
  1147. if (FALSE == ret)
  1148. {
  1149. PERROR(TEXT("SetFSec err %ld\r\n"), GetLastError());
  1150. }
  1151. }
  1152. LocalFree(pSDShare);
  1153. }
  1154. DdeFreeStringHandle ( idInst, pshrinfo->hszName );
  1155. pshrinfo->hszName = DdeCreateStringHandleW( idInst, pshrinfo->szName,
  1156. CP_WINUNICODE);
  1157. if ( !pshrinfo->hszName )
  1158. {
  1159. PERROR(TEXT("DdeCreateStringHandle failed\n\r"));
  1160. }
  1161. else
  1162. {
  1163. // update the registry to show shared/unshared status
  1164. if (ERROR_SUCCESS == MakeTheRegKey(&hkeyClp, KEY_SET_VALUE))
  1165. {
  1166. PINFO(TEXT("Making registry key %ls from %ls, %d\r\n"),
  1167. pshrinfo->szName, pshrinfo->szFileName,
  1168. lstrlenW(pshrinfo->szFileName));
  1169. RegSetValueExW (hkeyClp,
  1170. pshrinfo->szName,
  1171. 0,
  1172. REG_SZ,
  1173. (LPBYTE)pshrinfo->szFileName,
  1174. lstrlenW (pshrinfo->szFileName) *sizeof(WCHAR) +sizeof(WCHAR));
  1175. RegCloseKey(hkeyClp);
  1176. DdePostAdvise ( idInst, hszSysTopic, hszTopicList );
  1177. return TRUE;
  1178. }
  1179. else
  1180. {
  1181. PERROR(TEXT("Could not make registry key to record %s"),
  1182. pshrinfo->szName);
  1183. }
  1184. }
  1185. }
  1186. }
  1187. PERROR(TEXT("Item to mark '%s' not found\n\r"), pszName );
  1188. return FALSE;
  1189. }
  1190. /*
  1191. * Hszize
  1192. * This creates often used global hszs from standard global strings.
  1193. * It also fills the hsz fields of the topic and item tables.
  1194. *
  1195. */
  1196. void Hszize(void)
  1197. {
  1198. hszAppName = DdeCreateStringHandle (idInst, szServer, 0L);
  1199. hszSysTopic = DdeCreateStringHandle (idInst, SZDDESYS_TOPIC, 0L);
  1200. hszTopicList = DdeCreateStringHandle (idInst, SZDDESYS_ITEM_TOPICS, 0L);
  1201. hszFormatList = DdeCreateStringHandle (idInst, SZ_FORMAT_LIST, 0L);
  1202. hszErrorRequest = DdeCreateStringHandle (idInst, SZ_ERR_REQUEST, 0L);
  1203. #ifdef DEBUG
  1204. if ( !hszAppName || !hszSysTopic || !hszTopicList || !hszFormatList )
  1205. {
  1206. PERROR(TEXT("error creating HSZ constants\n\r"));
  1207. }
  1208. #endif
  1209. }
  1210. /*
  1211. * UnHszize
  1212. */
  1213. void UnHszize(void)
  1214. {
  1215. DdeFreeStringHandle (idInst, hszAppName);
  1216. DdeFreeStringHandle (idInst, hszSysTopic);
  1217. DdeFreeStringHandle (idInst, hszTopicList);
  1218. DdeFreeStringHandle (idInst, hszFormatList);
  1219. DdeFreeStringHandle (idInst, hszErrorRequest);
  1220. }
  1221. /*
  1222. * GetRandShareFileName
  1223. *
  1224. * Purpose:
  1225. * Generate a random share file name in the Windows directory.
  1226. *
  1227. * Parameters:
  1228. * buf - Buffer to place the file name in.
  1229. *
  1230. * Returns:
  1231. * TRUE if a valid filename was found, or FALSE if all of the random
  1232. * filenames are taken up.
  1233. */
  1234. DWORD GetRandShareFileName (
  1235. LPTSTR buf)
  1236. {
  1237. TCHAR szWinDir[144];
  1238. BOOL IsUnique = FALSE;
  1239. WORD rand;
  1240. WORD cTry = 0;
  1241. HANDLE hFile;
  1242. if (!GetWindowsDirectory( szWinDir, 144))
  1243. {
  1244. return GetLastError();
  1245. }
  1246. rand = (WORD)GetTickCount() % 10000;
  1247. do {
  1248. StringCchPrintf ( buf, MAX_PATH+1, TEXT("%s\\CBK%04d.CLP"), szWinDir, rand++ );
  1249. hFile = CreateFile (buf,
  1250. GENERIC_WRITE,
  1251. 0,
  1252. NULL,
  1253. CREATE_NEW,
  1254. FILE_ATTRIBUTE_NORMAL,
  1255. NULL);
  1256. }while (INVALID_HANDLE_VALUE == hFile && cTry++ < 10000);
  1257. if (INVALID_HANDLE_VALUE == hFile)
  1258. {
  1259. PERROR(TEXT("GetRandShareFileName: More than 10000 clipbook file exist!\r\n"));
  1260. return GetLastError();
  1261. }
  1262. else
  1263. {
  1264. CloseHandle(hFile);
  1265. return NO_ERROR;
  1266. }
  1267. }