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.

698 lines
18 KiB

  1. #include <windows.h>
  2. #include <windowsx.h>
  3. #include <stdarg.h>
  4. #include "common.h"
  5. #include "clipsrv.h"
  6. #include "clipfile.h"
  7. #include "callback.h"
  8. #include "debugout.h"
  9. static HANDLE hmutexClp; // for syncing open and close of clipboard
  10. static BOOL fAnythingToRender = FALSE;
  11. static BOOL fService = TRUE;
  12. static BOOL fServiceStopped = FALSE;
  13. static TCHAR szClass[] = TEXT("ClipSrvWClass");
  14. static TCHAR szServiceName[] = TEXT("Clipbook Service");
  15. static TCHAR wsbuf[128];
  16. DWORD idInst = 0;
  17. HINSTANCE hInst;
  18. HWND hwndApp;
  19. HSZ hszAppName = 0L;
  20. TCHAR szTopic[MAX_TOPIC] = TEXT("ClipData");
  21. TCHAR szServer[MAX_TOPIC] = TEXT("ClipSrv");
  22. TCHAR szExec[MAX_EXEC] = TEXT("");
  23. TCHAR szUpdateName[MAX_CLPSHRNAME+1] = TEXT("");
  24. UINT cf_preview;
  25. ShrInfo *SIHead = NULL;
  26. static SERVICE_STATUS_HANDLE hService;
  27. static SERVICE_STATUS srvstatus =
  28. {
  29. SERVICE_WIN32_OWN_PROCESS,
  30. SERVICE_START_PENDING,
  31. SERVICE_ACCEPT_STOP,
  32. NO_ERROR,
  33. 0L,
  34. 1,
  35. 200
  36. };
  37. #if DEBUG
  38. HKEY hkeyRoot;
  39. HKEY hkeyClp;
  40. #endif
  41. void ClipSrvHandler (DWORD);
  42. /////////////////////////////////////////////////////////////////////////
  43. //
  44. // "main" function... just calls StartServiceCtrlDispatcher.
  45. //
  46. /////////////////////////////////////////////////////////////////////////
  47. void _cdecl main(
  48. int argc,
  49. char **argv)
  50. {
  51. SERVICE_TABLE_ENTRY srvtabl[] = {{szServiceName, ClipSrvMain},
  52. {NULL, NULL}};
  53. #if DEBUG
  54. DeleteFile("C:\\CLIPSRV.OUT");
  55. #endif
  56. if (argv[1] && !lstrcmpi(argv[1], "-debug"))
  57. {
  58. fService = FALSE;
  59. ClipSrvMain(argc, argv);
  60. }
  61. else
  62. {
  63. StartServiceCtrlDispatcher(srvtabl);
  64. }
  65. }
  66. /*
  67. * ClipSrvMain
  68. */
  69. void ClipSrvMain(
  70. DWORD argc,
  71. LPSTR *argv)
  72. {
  73. MSG msg;
  74. if (fService)
  75. {
  76. hService = RegisterServiceCtrlHandler(szServiceName, ClipSrvHandler);
  77. }
  78. if (0L != hService || FALSE == fService)
  79. {
  80. if (fService)
  81. {
  82. // Tell SCM that we're starting
  83. SetServiceStatus(hService, &srvstatus);
  84. }
  85. hInst = GetModuleHandle(TEXT("CLIPSRV.EXE"));
  86. // Perform initializations
  87. if (InitApplication(hInst, &srvstatus))
  88. {
  89. if (fService)
  90. {
  91. // Tell SCM we've started OK
  92. srvstatus.dwCurrentState = SERVICE_RUNNING;
  93. SetServiceStatus(hService, &srvstatus);
  94. PINFO(TEXT("Told system we're running\r\n"));
  95. }
  96. // Process messages
  97. while (GetMessage(&msg, NULL, 0, 0))
  98. {
  99. TranslateMessage(&msg);
  100. DispatchMessage(&msg);
  101. }
  102. UnregisterClass(szClass, hInst);
  103. if (fService && !fServiceStopped)
  104. {
  105. fServiceStopped = TRUE;
  106. srvstatus.dwCurrentState = SERVICE_STOPPED;
  107. SetServiceStatus(hService, &srvstatus);
  108. }
  109. if (NULL != hmutexClp)
  110. {
  111. CloseHandle(hmutexClp);
  112. }
  113. }
  114. else
  115. {
  116. PERROR(TEXT("ClSrv: InitApplication failed!\r\n"));
  117. if (fService && !fServiceStopped)
  118. {
  119. fServiceStopped = TRUE;
  120. srvstatus.dwCurrentState = SERVICE_STOPPED;
  121. SetServiceStatus(hService, &srvstatus);
  122. }
  123. }
  124. }
  125. }
  126. /*
  127. * ReportStatusToSCMgr
  128. *
  129. * This function is called by the ServMainFunc() and
  130. * by the ServCtrlHandler() to update the service's status
  131. * to the Service Control Manager.
  132. */
  133. BOOL ReportStatusToSCMgr (
  134. DWORD dwCurrentState,
  135. DWORD dwWin32ExitCode,
  136. DWORD dwCheckPoint,
  137. DWORD dwWaitHint)
  138. {
  139. BOOL fResult;
  140. /* disable control requests until service is started */
  141. if (dwCurrentState == SERVICE_START_PENDING)
  142. {
  143. srvstatus.dwControlsAccepted = 0;
  144. }
  145. else
  146. {
  147. srvstatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
  148. }
  149. /* These SERVICE_STATUS members set from parameters */
  150. srvstatus.dwCurrentState = dwCurrentState;
  151. srvstatus.dwWin32ExitCode = dwWin32ExitCode;
  152. srvstatus.dwCheckPoint = dwCheckPoint;
  153. srvstatus.dwWaitHint = dwWaitHint;
  154. /* Report status of service to Service Control Manager */
  155. if (!(fResult = SetServiceStatus(hService,&srvstatus)))
  156. {
  157. /* if error occurs, stop service */
  158. }
  159. return fResult;
  160. }
  161. /*
  162. * ClipSrvHandler
  163. *
  164. *
  165. * Purpose: Acts as the HANDLER_FUNCTION for the Clipbook service.
  166. *
  167. * Parameters:
  168. * fdwControl = Flags saying what action to take
  169. *
  170. * Returns: Void (SetServiceStatus is used to set status)
  171. */
  172. void ClipSrvHandler(
  173. DWORD fdwControl)
  174. {
  175. if (SERVICE_CONTROL_STOP == fdwControl)
  176. {
  177. PINFO(TEXT("Handler: stopping service\r\n"));
  178. srvstatus.dwCheckPoint = 0;
  179. srvstatus.dwCurrentState = SERVICE_STOP_PENDING;
  180. SetServiceStatus(hService, &srvstatus);
  181. SendMessage(hwndApp, WM_CLOSE, 0, 0);
  182. if (!fServiceStopped) {
  183. fServiceStopped = TRUE;
  184. srvstatus.dwCurrentState = SERVICE_STOPPED;
  185. SetServiceStatus(hService, &srvstatus);
  186. }
  187. PINFO(TEXT("Handler: Service stopped\r\n"));
  188. }
  189. else
  190. {
  191. // Unhandled control request.. just keep running.
  192. srvstatus.dwCurrentState = SERVICE_RUNNING;
  193. srvstatus.dwWin32ExitCode = NO_ERROR;
  194. SetServiceStatus(hService, &srvstatus);
  195. }
  196. return;
  197. }
  198. /*
  199. * InitApplication
  200. *
  201. *
  202. * Purpose: Application initialization, including creation of a window
  203. * to do DDE with, getting settings out of the registry, and starting
  204. * up DDE.
  205. *
  206. * Parameters:
  207. * hInstance - Application instance.
  208. * psrvstatus - Pointer to a SERVICE_STATUS struct. We update the
  209. * dwCheckPoint member of this struct and call SetServiceStatus,
  210. * so the system knows that we didn't die.
  211. *
  212. * Returns: True on OK, false on fail.
  213. */
  214. BOOL InitApplication(
  215. HINSTANCE hInstance,
  216. SERVICE_STATUS *psrvstatus)
  217. {
  218. WNDCLASS wc;
  219. #if DEBUG
  220. DWORD dwKeyStatus;
  221. #endif
  222. HWINSTA hwinsta;
  223. wc.style = 0L;
  224. wc.lpfnWndProc = MainWndProc;
  225. wc.cbClsExtra = 0;
  226. wc.cbWndExtra = 0;
  227. wc.hInstance = hInstance;
  228. wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_CLIPSRV));
  229. wc.hCursor = NULL;
  230. wc.hbrBackground = NULL;
  231. wc.lpszMenuName = NULL;
  232. wc.lpszClassName = TEXT("ClipSrvWClass");
  233. if (!RegisterClass(&wc))
  234. {
  235. PERROR(TEXT("Couldn't register wclass\r\n"));
  236. return FALSE;
  237. }
  238. /*
  239. * We are now connected to the appropriate service windowstation
  240. * and desktop. In order to get stuff from clipbook, we need to
  241. * switch our process over to use the interactive user's
  242. * clipboard. Verify that we have access to do this.
  243. */
  244. hwinsta = OpenWindowStation("WinSta0", FALSE,
  245. WINSTA_ACCESSCLIPBOARD | WINSTA_ACCESSGLOBALATOMS);
  246. if (hwinsta == NULL) {
  247. PERROR(TEXT("Couldn't open windowstation WinSta0\r\n"));
  248. return FALSE;
  249. }
  250. SetProcessWindowStation(hwinsta);
  251. psrvstatus->dwCheckPoint++;
  252. hmutexClp = CreateMutex(NULL, FALSE, SZMUTEXCLP);
  253. hwndApp = CreateWindow(TEXT("ClipSrvWClass"),
  254. TEXT("Hidden Data Server"),
  255. WS_POPUP,
  256. CW_USEDEFAULT,
  257. CW_USEDEFAULT,
  258. 400,
  259. 200,
  260. NULL,
  261. NULL,
  262. hInstance,
  263. NULL
  264. );
  265. if (!hwndApp)
  266. {
  267. PERROR(TEXT("No window created\r\n"));
  268. return FALSE;
  269. }
  270. psrvstatus->dwCheckPoint++;
  271. #if DEBUG
  272. if (ERROR_SUCCESS != RegCreateKeyEx (HKEY_CURRENT_USER,
  273. szClipviewRoot,
  274. 0L,
  275. szRegClass,
  276. REG_OPTION_NON_VOLATILE,
  277. KEY_QUERY_VALUE, NULL,
  278. &hkeyClp,
  279. &dwKeyStatus)
  280. &&
  281. ERROR_SUCCESS != RegOpenKeyEx (HKEY_CURRENT_USER,
  282. szClipviewRoot,
  283. 0,
  284. KEY_QUERY_VALUE,
  285. &hkeyClp))
  286. {
  287. DebugLevel = 2;
  288. PINFO(TEXT("Clipsrv: Could not get root key\r\n"));
  289. }
  290. else
  291. {
  292. DWORD iSize = sizeof(DebugLevel);
  293. RegQueryValueEx (hkeyClp,
  294. szDebug,
  295. NULL,
  296. NULL,
  297. (LPBYTE)&DebugLevel,
  298. &iSize);
  299. RegCloseKey (hkeyClp);
  300. }
  301. if (DebugLevel > 0)
  302. {
  303. ShowWindow(hwndApp, SW_SHOWMINNOACTIVE );
  304. }
  305. #endif
  306. if (DdeInitialize ((LPDWORD)&idInst,
  307. (PFNCALLBACK)DdeCallback,
  308. APPCMD_FILTERINITS,
  309. 0L))
  310. {
  311. PERROR(TEXT("Couldn't initialize DDE\r\n"));
  312. return FALSE;
  313. }
  314. PINFO(TEXT("DdeInit OK...\r\n"));
  315. psrvstatus->dwCheckPoint++;
  316. if (fService)
  317. {
  318. SetServiceStatus(hService, psrvstatus);
  319. }
  320. Hszize();
  321. DdeNameService(idInst, hszAppName, 0L, DNS_REGISTER);
  322. InitShares();
  323. return TRUE;
  324. }
  325. /*
  326. * MainWndProc
  327. */
  328. LRESULT CALLBACK MainWndProc(
  329. HWND hwnd,
  330. UINT message,
  331. WPARAM wParam,
  332. LPARAM lParam)
  333. {
  334. switch (message)
  335. {
  336. case WM_CREATE:
  337. fAnythingToRender = FALSE;
  338. cf_preview = RegisterClipboardFormat (SZPREVNAME);
  339. if (fService)
  340. {
  341. // Let the SCP that started us know that we're making progress
  342. srvstatus.dwCheckPoint++;
  343. SetServiceStatus(hService, &srvstatus);
  344. }
  345. PINFO(TEXT("Creating ClSrv window\r\n"));
  346. break;
  347. case WM_DESTROYCLIPBOARD:
  348. /* Prevent unnecessary file I/O when getting a WM_RENDERALLFORMATS */
  349. fAnythingToRender = FALSE;
  350. break;
  351. case WM_RENDERALLFORMATS:
  352. PINFO(TEXT("ClSrv\\WM_RNDRALL rcvd\r\n"));
  353. return (LRESULT)RenderAllFromFile(szSaveFileName);
  354. break;
  355. case WM_RENDERFORMAT:
  356. SetClipboardData((UINT)wParam, RenderFormatFromFile(szSaveFileName, (WORD)wParam));
  357. break;
  358. case WM_QUERYOPEN:
  359. return FALSE;
  360. case WM_DESTROY:
  361. PINFO(TEXT("sTOPPING...\r\n"));
  362. CleanUpShares();
  363. DdeNameService(idInst, 0L, 0L, DNS_UNREGISTER);
  364. UnHszize();
  365. DdeUninitialize(idInst);
  366. if (fService)
  367. {
  368. // Tell SCP we're stopping
  369. srvstatus.dwCheckPoint++;
  370. SetServiceStatus(hService, &srvstatus);
  371. }
  372. PostQuitMessage(0);
  373. break;
  374. default:
  375. return (DefWindowProc(hwnd, message, wParam, lParam));
  376. }
  377. return 0L;
  378. }
  379. /*
  380. * RenderRawFormatToDDE
  381. */
  382. HDDEDATA RenderRawFormatToDDE(
  383. FORMATHEADER *pfmthdr,
  384. HANDLE fh )
  385. {
  386. HDDEDATA hDDE;
  387. LPBYTE lpDDE;
  388. DWORD cbData;
  389. DWORD dwBytesRead;
  390. BOOL fPrivate = FALSE, fMetafile = FALSE, fBitmap = FALSE;
  391. PINFO(TEXT("ClSrv\\RndrRawFmtToDDE:"));
  392. // Note that complex-data formats are sent under a private
  393. // format instead.
  394. if (PRIVATE_FORMAT(pfmthdr->FormatID )
  395. || pfmthdr->FormatID == CF_BITMAP
  396. || pfmthdr->FormatID == CF_METAFILEPICT
  397. || pfmthdr->FormatID == CF_PALETTE
  398. || pfmthdr->FormatID == CF_DIB
  399. || pfmthdr->FormatID == CF_ENHMETAFILE
  400. )
  401. {
  402. fPrivate = TRUE;
  403. if (pfmthdr->FormatID == CF_BITMAP)
  404. {
  405. fBitmap = TRUE;
  406. }
  407. else if (pfmthdr->FormatID == CF_METAFILEPICT)
  408. {
  409. fMetafile = TRUE;
  410. }
  411. pfmthdr->FormatID = RegisterClipboardFormatW(pfmthdr->Name);
  412. }
  413. PINFO(TEXT("rendering format %ws as %x\n\r"), (LPTSTR)pfmthdr->Name, pfmthdr->FormatID );
  414. #ifdef CACHEPREVIEWS
  415. if ( pfmthdr->FormatID == cf_preview )
  416. PINFO(TEXT("making APPOWNED data\n\r"));
  417. #endif
  418. if (!(hDDE = DdeCreateDataHandle (idInst,
  419. NULL,
  420. pfmthdr->DataLen,
  421. 0L,
  422. hszAppName,
  423. pfmthdr->FormatID,
  424. #ifdef CACHEPREVIEWS
  425. pfmthdr->FormatID == cf_preview ? HDATA_APPOWNED : 0
  426. #else
  427. 0
  428. #endif
  429. )))
  430. {
  431. PERROR(TEXT("Couldn't createdata handle\r\n"));
  432. goto done;
  433. }
  434. if ( !(lpDDE = DdeAccessData ( hDDE, &cbData )) )
  435. {
  436. PERROR(TEXT("Couldn't access handle\r\n"));
  437. DdeFreeDataHandle(hDDE);
  438. hDDE = 0L;
  439. goto done;
  440. }
  441. if (~0 == SetFilePointer(fh, pfmthdr->DataOffset, NULL, FILE_BEGIN))
  442. {
  443. PERROR(TEXT("Couldn't set file pointer\r\n"));
  444. DdeUnaccessData(hDDE);
  445. DdeFreeDataHandle(hDDE);
  446. hDDE = 0L;
  447. goto done;
  448. }
  449. ReadFile(fh, lpDDE, pfmthdr->DataLen, &dwBytesRead, NULL);
  450. if (dwBytesRead != pfmthdr->DataLen)
  451. {
  452. // Error in reading the file
  453. DdeUnaccessData(hDDE);
  454. DdeFreeDataHandle(hDDE);
  455. PERROR(TEXT("Error reading file: %ld from lread\n\r"),
  456. dwBytesRead);
  457. hDDE = 0L;
  458. goto done;
  459. }
  460. // This code packs CF_METAFILEPICT and CF_BITMAP structs to WFW-type
  461. // structs. It may lose extents for very large bitmaps and metafiles
  462. // when going from NT to NT. Main symptom would be "Moved a metafile
  463. // across clipbook and it suddenly grew way outside its bounds".
  464. if (fMetafile)
  465. {
  466. WIN31METAFILEPICT w31mfp;
  467. unsigned uNewSize;
  468. HDDEDATA hDDETmp;
  469. uNewSize = pfmthdr->DataLen + sizeof(WIN31METAFILEPICT) -
  470. sizeof(METAFILEPICT);
  471. // Have to make a smaller data handle now
  472. hDDETmp = hDDE;
  473. hDDE = DdeCreateDataHandle(idInst, NULL, uNewSize, 0L,
  474. hszAppName, pfmthdr->FormatID, 0);
  475. w31mfp.mm = (WORD)((METAFILEPICT *)lpDDE)->mm;
  476. w31mfp.xExt = (WORD)((METAFILEPICT *)lpDDE)->xExt;
  477. w31mfp.yExt = (WORD)((METAFILEPICT *)lpDDE)->yExt;
  478. // Place oldmetafilepict and data in new DDE block
  479. DdeAddData(hDDE, (LPTSTR)&w31mfp, sizeof(WIN31METAFILEPICT), 0L);
  480. DdeAddData(hDDE, lpDDE + sizeof(METAFILEPICT),
  481. uNewSize - sizeof(WIN31METAFILEPICT),
  482. sizeof(WIN31METAFILEPICT));
  483. // Drop old handle
  484. DdeUnaccessData(hDDETmp);
  485. DdeFreeDataHandle(hDDETmp);
  486. // We came in with hDDE accessed
  487. lpDDE = DdeAccessData(hDDE, &cbData);
  488. }
  489. else if (fBitmap)
  490. {
  491. WIN31BITMAP w31bm;
  492. unsigned uNewSize;
  493. HDDEDATA hDDETmp;
  494. uNewSize = pfmthdr->DataLen + sizeof(WIN31BITMAP) -
  495. sizeof(BITMAP);
  496. // Have to make a smaller data handle now
  497. hDDETmp = hDDE;
  498. hDDE = DdeCreateDataHandle(idInst, NULL, uNewSize, 0L,
  499. hszAppName, pfmthdr->FormatID, 0);
  500. w31bm.bmType = (WORD)((BITMAP *)lpDDE)->bmType;
  501. w31bm.bmWidth = (WORD)((BITMAP *)lpDDE)->bmWidth;
  502. w31bm.bmHeight = (WORD)((BITMAP *)lpDDE)->bmHeight;
  503. w31bm.bmWidthBytes = (WORD)((BITMAP *)lpDDE)->bmWidthBytes;
  504. w31bm.bmPlanes = (BYTE)((BITMAP *)lpDDE)->bmPlanes;
  505. w31bm.bmBitsPixel = (BYTE)((BITMAP *)lpDDE)->bmBitsPixel;
  506. // Place old-style bitmap header and data in DDE block
  507. DdeAddData(hDDE, (LPTSTR)&w31bm, sizeof(WIN31BITMAP), 0L);
  508. DdeAddData(hDDE, lpDDE + sizeof(BITMAP),
  509. uNewSize - sizeof(WIN31BITMAP),
  510. sizeof(WIN31BITMAP));
  511. // Drop old handle
  512. DdeUnaccessData(hDDETmp);
  513. DdeFreeDataHandle(hDDETmp);
  514. // We came in with hDDE accessed
  515. lpDDE = DdeAccessData(hDDE, &cbData);
  516. }
  517. DdeUnaccessData(hDDE);
  518. done:
  519. PINFO("Ret %lx\r\n", hDDE);
  520. return(hDDE);
  521. }
  522. /*
  523. * SyncOpenClipboard
  524. */
  525. BOOL SyncOpenClipboard(
  526. HWND hwnd)
  527. {
  528. BOOL fOK;
  529. PINFO(TEXT("\r\nClipSrv: Opening Clipboard\r\n"));
  530. WaitForSingleObject (hmutexClp, INFINITE);
  531. fOK = OpenClipboard (hwnd);
  532. if (!fOK)
  533. {
  534. ReleaseMutex (hmutexClp);
  535. }
  536. return fOK;
  537. }
  538. /*
  539. * SyncCloseClipboard
  540. */
  541. BOOL SyncCloseClipboard(void)
  542. {
  543. BOOL fOK;
  544. PINFO(TEXT("\r\nClipSrv: Closing Clipboard\r\n"));
  545. fOK = CloseClipboard ();
  546. ReleaseMutex (hmutexClp);
  547. return fOK;
  548. }