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.

1786 lines
42 KiB

  1. /*+
  2. * File name:
  3. * clxtshar.c
  4. * Contents:
  5. * Client extension loaded by RDP client
  6. *
  7. * Copyright (C) 1998-1999 Microsoft Corp.
  8. --*/
  9. #include <windows.h>
  10. #include <windowsx.h>
  11. #include <winsock.h>
  12. #include <string.h>
  13. #include <malloc.h>
  14. #include <stdlib.h>
  15. #include <stdio.h>
  16. #include <stdarg.h>
  17. #ifndef OS_WINCE
  18. #include <direct.h>
  19. #endif // OS_WINCE
  20. #ifndef OS_WINCE
  21. #ifdef OS_WIN32
  22. #include <process.h>
  23. #endif // OS_WIN32
  24. #endif // !OS_WINCE
  25. #include "clxtshar.h"
  26. #define WM_CLIPBOARD (WM_USER) // Internal notifcation to send
  27. // our clipboard
  28. #ifdef OS_WIN32
  29. #ifndef OS_WINCE
  30. /*++
  31. * Function:
  32. * DllMain
  33. * Description:
  34. * Dll entry point for win32 (no WinCE)
  35. --*/
  36. int APIENTRY DllMain(HINSTANCE hDllInst,
  37. DWORD dwReason,
  38. LPVOID fImpLoad)
  39. {
  40. if (dwReason == DLL_PROCESS_ATTACH)
  41. {
  42. g_hInstance = hDllInst;
  43. TRACE((INFO_MESSAGE, TEXT("Clx attached\n")));
  44. #if 0
  45. // Check the key "Allow Background Input"
  46. // If not set pop a message for that
  47. if (!_CheckRegistrySettings())
  48. MessageBox(NULL, "CLXTSHAR.DLL: Can't find registry key:\n"
  49. "HKEY_CURRENT_USER\\Software\\Microsoft\\Terminal Server Client\\"
  50. "Allow Background Input.\n"
  51. "In order to work properly "
  52. "CLX needs this key to be set to 1", "Warning",
  53. MB_OK);
  54. #endif
  55. _GetIniSettings();
  56. }
  57. if (dwReason == DLL_PROCESS_DETACH)
  58. {
  59. TRACE((INFO_MESSAGE, TEXT("Clx detached\n")));
  60. }
  61. return TRUE;
  62. }
  63. #endif // !OS_WINCE
  64. #endif // OS_WIN32
  65. #ifdef OS_WINCE
  66. /*++
  67. * Function:
  68. * dllentry
  69. * Description:
  70. * Dll entry point for wince
  71. --*/
  72. BOOL __stdcall dllentry(HINSTANCE hDllInst,
  73. DWORD dwReason,
  74. LPVOID fImpLoad)
  75. {
  76. if (dwReason == DLL_PROCESS_ATTACH)
  77. {
  78. g_hInstance = hDllInst;
  79. TRACE((INFO_MESSAGE, TEXT("Clx attached\n")));
  80. if (!_StartAsyncThread())
  81. TRACE((ERROR_MESSAGE,
  82. TEXT("Can't start AsyncThread. TCP unusable\n")));
  83. _GetIniSettings();
  84. }
  85. if (dwReason == DLL_PROCESS_DETACH)
  86. {
  87. TRACE((INFO_MESSAGE, TEXT("Clx detached\n")));
  88. _CloseAsyncThread();
  89. }
  90. return TRUE;
  91. }
  92. #endif // OS_WIN32
  93. #ifdef OS_WIN16
  94. /*++
  95. * Function:
  96. * LibMain
  97. * Description:
  98. * Dll entry point for win16
  99. --*/
  100. int CALLBACK LibMain(HINSTANCE hInstance,
  101. WORD dataSeg,
  102. WORD heapSize,
  103. LPSTR pCmdLine)
  104. {
  105. // Check if we are already initialized
  106. // Only one client is allowed in Win16 environment
  107. // so, only one dll can be loaded at a time
  108. if (g_hInstance)
  109. goto exitpt;
  110. g_hInstance = hInstance;
  111. // Check the key "Allow Background Input"
  112. // If not set pop a message for that
  113. if (!_CheckIniSettings())
  114. MessageBox(NULL, "CLXTSHAR.DLL: Can't find key: "
  115. "Allow Background Input in mstsc.ini, section \"\"\n"
  116. "In order to work properly "
  117. "CLX needs this key to be set to 1", "Warning",
  118. MB_OK);
  119. _GetIniSettings();
  120. exitpt:
  121. return TRUE;
  122. }
  123. #endif // OS_WIN16
  124. /*++
  125. * Function:
  126. * ClxInitialize
  127. * Description:
  128. * Initilizes a context for the current session
  129. * reads the command line paramters and determines
  130. * the mode wich will run the extension
  131. * Win32/Win16/WinCE
  132. * Arguments:
  133. * pClInfo - RDP client info
  134. * ppClx - context info
  135. * Return value:
  136. * TRUE on success
  137. * Called by:
  138. * !mstsc after the dll is loaded
  139. --*/
  140. BOOL
  141. CLXAPI
  142. ClxInitialize(PCLINFO pClInfo, PCLXINFO *ppClx)
  143. {
  144. BOOL rv = FALSE;
  145. HWND hwndSMC;
  146. TCHAR szTempBuf[_MAX_PATH];
  147. PCLXINFO pClx = NULL;
  148. #ifdef OS_WIN32
  149. #ifndef OS_WINCE
  150. // We have enough problems in stress with early unloaded
  151. // dll, reference it now and keep it up until the process
  152. // dies
  153. LoadLibrary("clxtshar.dll");
  154. #endif // !OS_WINCE
  155. #endif // OS_WIN32
  156. if ( NULL == ppClx )
  157. {
  158. TRACE((ERROR_MESSAGE, TEXT("ppClx is NULL\n")));
  159. goto exitpt;
  160. }
  161. pClx = (PCLXINFO)_CLXALLOC(sizeof(**ppClx));
  162. if (!pClx)
  163. {
  164. TRACE((ERROR_MESSAGE, TEXT("Can't allocate CLX context\n")));
  165. goto exitpt;
  166. }
  167. // Clear the structure
  168. memset(pClx, 0, sizeof(*pClx));
  169. if ( !_ClxInitSendMessageThread( pClx ))
  170. {
  171. TRACE(( ERROR_MESSAGE, TEXT("Failed to init SendMessageThread\n" )));
  172. goto exitpt;
  173. }
  174. hwndSMC = _ParseCmdLine(pClInfo->pszCmdLine, pClx);
  175. #if 0
  176. if (g_pClx)
  177. // Should not be called twice
  178. {
  179. TRACE((WARNING_MESSAGE, TEXT("g_pClx is not null. Reentered ?!\n")));
  180. goto exitpt;
  181. }
  182. #endif
  183. g_pClx = (pClx);
  184. // Remember client's input window
  185. szTempBuf[0] = 0;
  186. GetClassName( pClInfo->hwndMain, szTempBuf, sizeof( szTempBuf )/sizeof( szTempBuf[0] ));
  187. if (!_CLX_strcmp(g_strMainWindowClass, szTempBuf))
  188. // not our window
  189. //
  190. pClx->hwndMain = NULL;
  191. else
  192. pClx->hwndMain = pClInfo->hwndMain;
  193. if (pClInfo->hwndMain)
  194. #ifdef OS_WINCE
  195. g_hRDPInst = GetCurrentProcessId();
  196. #else // !OS_WINCE
  197. #ifdef _WIN64
  198. g_hRDPInst = (HINSTANCE)GetWindowLongPtr(pClx->hwndMain, GWLP_HINSTANCE);
  199. #else // !_WIN64
  200. #ifdef OS_WIN32
  201. g_hRDPInst = (HINSTANCE)GetWindowLong(pClx->hwndMain, GWL_HINSTANCE);
  202. #endif // OS_WIN32
  203. #endif // _WIN64
  204. #ifdef OS_WIN16
  205. g_hRDPInst = (HINSTANCE)GetWindowWord(pClx->hwndMain, GWW_HINSTANCE);
  206. #endif // OS_WIN16
  207. #endif // !OS_WINCE
  208. #ifndef OS_WINCE
  209. #ifdef OS_WIN32
  210. // and dwProcessId
  211. if ( 0 == pClx->dwProcessId )
  212. pClx->dwProcessId = GetCurrentProcessId();
  213. #endif // OS_WIN32
  214. #endif // !OS_WINCE
  215. #ifdef OS_WIN32
  216. #ifndef OS_WINCE
  217. else {
  218. if (!(pClx->hwndSMC = hwndSMC))
  219. pClx->hwndSMC = _FindSMCWindow(pClx, 0);
  220. }
  221. #endif // !OS_WINCE
  222. #endif // OS_WIN32
  223. rv = TRUE;
  224. exitpt:
  225. if ( !rv && NULL != pClx )
  226. {
  227. _CLXFREE( pClx );
  228. g_pClx = NULL;
  229. pClx = NULL;
  230. }
  231. if ( NULL != ppClx )
  232. {
  233. *ppClx = pClx;
  234. }
  235. if ( !rv )
  236. TRACE((ERROR_MESSAGE, TEXT("ClxInitialzie failed\n")));
  237. return rv;
  238. }
  239. /*++
  240. * Function:
  241. * ClxEvent
  242. * Description:
  243. * Notifies tclient.dll that some event happend.
  244. * Connect/disconnect.
  245. * Win32/Win16/WinCE
  246. * Arguments:
  247. * pClx - context
  248. * Event - can be one of the following:
  249. * CLX_EVENT_CONNECT
  250. * CLX_EVENT_DISCONNECT
  251. * CLX_EVENT_LOGON
  252. * Called by:
  253. * !mstsc on event
  254. * alse some of the internal functions call this, especialy
  255. * to notify that the client can't connect:
  256. * ClxTerminate
  257. * _GarbageCollecting when an error box is popped
  258. --*/
  259. VOID
  260. CLXAPI
  261. ClxEvent(PCLXINFO pClx, CLXEVENT Event, WPARAM wResult)
  262. {
  263. UINT uiMessage = 0;
  264. if (!pClx)
  265. goto exitpt;
  266. #ifdef VLADIMIS_NEW_CHANGE
  267. if (Event == CLX_EVENT_SHADOWBITMAPDC)
  268. {
  269. pClx->hdcShadowBitmap = (HDC)wResult;
  270. goto exitpt;
  271. } else if (Event == CLX_EVENT_SHADOWBITMAP)
  272. {
  273. pClx->hShadowBitmap = (HBITMAP)wResult;
  274. goto exitpt;
  275. } else if (Event == CLX_EVENT_PALETTE)
  276. {
  277. pClx->hShadowPalette = (HPALETTE)wResult;
  278. }
  279. #endif // VLADIMIS
  280. #ifndef OS_WINCE
  281. {
  282. if (!_CheckWindow(pClx))
  283. goto exitpt;
  284. if (Event == CLX_EVENT_DISCONNECT)
  285. uiMessage = WM_FB_DISCONNECT;
  286. else if (Event == CLX_EVENT_CONNECT)
  287. {
  288. uiMessage = WM_FB_CONNECT;
  289. wResult = (WPARAM)pClx->hwndMain;
  290. }
  291. else if (Event == CLX_EVENT_LOGON)
  292. // wResult contains the session ID
  293. uiMessage = WM_FB_LOGON;
  294. if (uiMessage)
  295. {
  296. #ifdef OS_WIN32
  297. if (!_ClxAcquireSendMessageThread(pClx))
  298. goto exitpt;
  299. _ClxSendMessage(
  300. pClx,
  301. pClx->hwndSMC,
  302. uiMessage,
  303. wResult,
  304. pClx->dwProcessId);
  305. _ClxReleaseSendMessageThread(pClx);
  306. #endif // OS_WIN32
  307. #ifdef OS_WIN16
  308. if (g_hRDPInst)
  309. SendMessage(pClx->hwndSMC,
  310. uiMessage,
  311. g_hRDPInst,
  312. (LRESULT)wResult);
  313. #endif // OS_WIN16
  314. }
  315. }
  316. #endif // !OS_WINCE
  317. exitpt:
  318. ;
  319. }
  320. /*++
  321. * Function:
  322. * ClxTextOut
  323. * Description:
  324. * Notifies tclient.dll that TEXTOUT order is recieved.
  325. * Passes the string to the dll. Supported only in Win32
  326. * Win32/Win16/WinCE
  327. * Arguments:
  328. * pClx - context
  329. * pText - buffer containing the string
  330. * textLength - string length
  331. * Called by:
  332. * !mstsc on receiving textout order
  333. --*/
  334. VOID
  335. CLXAPI
  336. ClxTextOut(PCLXINFO pClx, PVOID pText, INT textLength)
  337. {
  338. BOOL bMsgThreadAcquired = FALSE;
  339. if (!pClx || !(*((UINT16 *)pText)))
  340. goto exitpt;
  341. #ifdef OS_WIN32
  342. #ifndef OS_WINCE
  343. if (!_CheckWindow(pClx))
  344. goto exitpt;
  345. if (!_ClxAcquireSendMessageThread(pClx))
  346. goto exitpt;
  347. bMsgThreadAcquired = TRUE;
  348. if (!pClx->hMapF)
  349. if (!_OpenMapFile(0, &(pClx->hMapF), &(pClx->nMapSize)))
  350. goto exitpt;
  351. if (_SaveInMapFile(pClx->hMapF, pText, textLength, pClx->dwProcessId))
  352. _ClxSendMessage(
  353. pClx,
  354. pClx->hwndSMC,
  355. WM_FB_TEXTOUT,
  356. (WPARAM)pClx->dwProcessId,
  357. (LPARAM)pClx->hMapF);
  358. #endif // !OS_WINCE
  359. #endif // OS_WIN32
  360. exitpt:
  361. if ( bMsgThreadAcquired )
  362. _ClxReleaseSendMessageThread(pClx);
  363. }
  364. /*++
  365. * Function:
  366. * ClxTerminate
  367. * Description:
  368. * Frees all alocations from ClxInitialize
  369. * Win32/Win16/WinCE
  370. * Arguments:
  371. * pClx - context
  372. * Called by:
  373. * !mstsc before the dll is unloaded and client exit
  374. --*/
  375. VOID
  376. CLXAPI
  377. ClxTerminate(PCLXINFO pClx)
  378. {
  379. if (!pClx)
  380. goto exitpt;
  381. ClxEvent(pClx, CLX_EVENT_DISCONNECT, 0);
  382. #ifdef OS_WIN32
  383. #ifndef OS_WINCE
  384. {
  385. if(pClx->hMapF)
  386. CloseHandle(pClx->hMapF);
  387. if(pClx->hBMPMapF)
  388. CloseHandle(pClx->hBMPMapF);
  389. _ClxDestroySendMsgThread(pClx);
  390. }
  391. #endif // !OS_WINCE
  392. #endif // OS_WIN32
  393. _CLXFREE(pClx);
  394. g_pClx = NULL;
  395. exitpt:
  396. ;
  397. }
  398. /*
  399. * Void functions exported to the RDP client
  400. */
  401. VOID
  402. CLXAPI
  403. ClxConnect(PCLXINFO pClx, LPTSTR lpsz)
  404. {
  405. }
  406. VOID
  407. CLXAPI
  408. ClxDisconnect(PCLXINFO pClx)
  409. {
  410. }
  411. /*++
  412. * Function:
  413. * ClxDialog
  414. * Description:
  415. * The RDP client is ready with the connect dialog.
  416. * Win32/Win16/WinCE
  417. * Arguments:
  418. * pClx - connection context
  419. * hwnd - handle to the dialog window
  420. * Called by:
  421. * !mstsc when the connect dialog is ready
  422. --*/
  423. VOID
  424. CLXAPI
  425. ClxDialog(PCLXINFO pClx, HWND hwnd)
  426. {
  427. if (!pClx)
  428. goto exitpt;
  429. pClx->hwndDialog = hwnd;
  430. if (hwnd == NULL)
  431. // Dialog disappears
  432. goto exitpt;
  433. exitpt:
  434. ;
  435. }
  436. /*++
  437. * Function:
  438. * ClxBitmap
  439. * Description:
  440. * Send a received bitmap to tclient.dll
  441. * Works on Win16/Win32/WinCE
  442. * and on Win32 for local mode
  443. * Arguments:
  444. * pClx - context
  445. * cxSize, cySize - size of the bitmap
  446. * pBuffer - bitmap bits
  447. * nBmiSize - size of BITMAPINFO
  448. * pBmi - BITMAPINFO
  449. * Called by:
  450. * UHDrawMemBltOrder!mstsc
  451. * ClxGlyphOut
  452. --*/
  453. VOID
  454. CLXAPI
  455. ClxBitmap(
  456. PCLXINFO pClx,
  457. UINT cxSize,
  458. UINT cySize,
  459. PVOID pBuffer,
  460. UINT nBmiSize,
  461. PVOID pBmi)
  462. {
  463. #ifndef OS_WINCE
  464. #ifdef OS_WIN32
  465. UINT nSize, nBmpSize;
  466. PBMPFEEDBACK pView;
  467. #endif // OS_WIN32
  468. #endif // !OS_WINCE
  469. BOOL bMsgThreadAcquired = FALSE;
  470. if (!g_GlyphEnable)
  471. goto exitpt;
  472. if (!pClx)
  473. goto exitpt;
  474. if (nBmiSize && !pBmi)
  475. goto exitpt;
  476. #ifdef OS_WIN32
  477. #ifndef OS_WINCE
  478. if (!_CheckWindow(pClx))
  479. goto exitpt;
  480. if (!nBmiSize)
  481. nBmpSize = (cxSize * cySize ) >> 3;
  482. else
  483. {
  484. nBmpSize = ((PBITMAPINFO)pBmi)->bmiHeader.biSizeImage;
  485. if (!nBmpSize)
  486. nBmpSize = (cxSize * cySize *
  487. ((PBITMAPINFO)pBmi)->bmiHeader.biBitCount) >> 3;
  488. }
  489. nSize = nBmpSize + nBmiSize + sizeof(*pView);
  490. if (!nSize)
  491. goto exitpt;
  492. if (!_ClxAcquireSendMessageThread(pClx))
  493. goto exitpt;
  494. bMsgThreadAcquired = TRUE;
  495. if (!pClx->hBMPMapF)
  496. if (!_OpenMapFile(nSize, &(pClx->hBMPMapF), &(pClx->nBMPMapSize)))
  497. goto exitpt;
  498. if (nSize > pClx->nBMPMapSize)
  499. if (!_ReOpenMapFile( nSize, &(pClx->hBMPMapF), &(pClx->nBMPMapSize) ))
  500. goto exitpt;
  501. pView = (PBMPFEEDBACK)MapViewOfFile(pClx->hBMPMapF,
  502. FILE_MAP_ALL_ACCESS,
  503. 0,
  504. 0,
  505. nSize);
  506. if (!pView)
  507. goto exitpt;
  508. pView->lProcessId = pClx->dwProcessId;
  509. pView->bmpsize = nBmpSize;
  510. pView->bmiSize = nBmiSize;
  511. pView->xSize = cxSize;
  512. pView->ySize = cySize;
  513. if (pBmi)
  514. CopyMemory(&(pView->BitmapInfo), pBmi, nBmiSize);
  515. CopyMemory((BYTE *)(&(pView->BitmapInfo)) + nBmiSize, pBuffer, nBmpSize);
  516. if (!nBmiSize)
  517. {
  518. // This is glyph, strip it to the skin
  519. _StripGlyph((BYTE *)(&pView->BitmapInfo), &cxSize, cySize);
  520. nBmpSize = (cxSize * cySize ) >> 3;
  521. pView->bmpsize = nBmpSize;
  522. pView->xSize = cxSize;
  523. }
  524. UnmapViewOfFile(pView);
  525. _ClxSendMessage(
  526. pClx,
  527. pClx->hwndSMC,
  528. WM_FB_BITMAP,
  529. (WPARAM)pClx->dwProcessId,
  530. (LPARAM)pClx->hBMPMapF);
  531. #endif // !OS_WINCE
  532. #endif // OS_WIN32
  533. exitpt:
  534. if ( bMsgThreadAcquired )
  535. _ClxReleaseSendMessageThread(pClx);
  536. }
  537. /*++
  538. * Function:
  539. * ClxGlyphOut
  540. * Description:
  541. * Send a glyph to tclient.dll
  542. * Win32/Win16/WinCE
  543. * Arguments:
  544. * pClx - context
  545. * cxBits,cyBits - glyph size
  546. * pBuffer - the glyph
  547. * Called by:
  548. * GHOutputBuffer!mstsc
  549. --*/
  550. VOID
  551. CLXAPI
  552. ClxGlyphOut(
  553. PCLXINFO pClx,
  554. UINT cxBits,
  555. UINT cyBits,
  556. PVOID pBuffer)
  557. {
  558. if (g_GlyphEnable)
  559. ClxBitmap(pClx, cxBits, cyBits, pBuffer, 0, NULL);
  560. }
  561. /*++
  562. * Function:
  563. * ClxGlyphOut
  564. * Description:
  565. * Send a glyph to tclient.dll
  566. * Win32/Win16/WinCE
  567. * Arguments:
  568. * pClx - context
  569. * cxBits,cyBits - glyph size
  570. * pBuffer - the glyph
  571. * Called by:
  572. * GHOutputBuffer!mstsc
  573. --*/
  574. BOOL
  575. CLXAPI
  576. ClxGetClientData(
  577. PCLX_CLIENT_DATA pClntData
  578. )
  579. {
  580. BOOL rv = FALSE;
  581. if (!pClntData)
  582. {
  583. TRACE((ERROR_MESSAGE, TEXT("ClxGetClientData: parameter is NULL\n")));
  584. goto exitpt;
  585. }
  586. memset(pClntData, 0, sizeof(*pClntData));
  587. if (!g_pClx)
  588. {
  589. TRACE((ERROR_MESSAGE, TEXT("ClxGetClientData: Clx has no context\n")));
  590. goto exitpt;
  591. }
  592. pClntData->hScreenDC = g_pClx->hdcShadowBitmap;
  593. pClntData->hScreenBitmap = g_pClx->hShadowBitmap;
  594. pClntData->hScreenPalette = g_pClx->hShadowPalette;
  595. rv = TRUE;
  596. exitpt:
  597. return rv;
  598. }
  599. /*++
  600. * Function:
  601. * _ParseCmdLine
  602. * Description:
  603. * Retreives WHND of tclient.dll feedback window
  604. * passed by the command line
  605. * Win32/Win16/WinCE
  606. * Arguments:
  607. * szCmdLine - command line
  608. * Return value:
  609. * The window handle
  610. * Called by:
  611. * ClxInitialize
  612. --*/
  613. HWND _ParseCmdLine(LPCTSTR szCmdLine, PCLXINFO pClx)
  614. {
  615. HWND hwnd = NULL;
  616. LPCTSTR pszwnd, pszdot, pszend;
  617. INT nCounter;
  618. if (!szCmdLine)
  619. goto exitpt;
  620. TRACE((INFO_MESSAGE, TEXT("Command line: %s\n"), szCmdLine));
  621. pszwnd = _CLX_strstr(szCmdLine, TEXT(_COOKIE));
  622. if (!pszwnd)
  623. goto skip_cookie;
  624. pszwnd += _CLX_strlen(TEXT(_COOKIE));
  625. pClx->dwProcessId = (DWORD_PTR)_atoi64( pszwnd );
  626. skip_cookie:
  627. // Check for _HWNDOPT(hSMC) option
  628. pszwnd = _CLX_strstr(szCmdLine, TEXT(_HWNDOPT));
  629. if (!pszwnd)
  630. goto findnext;
  631. // Goto the parameter
  632. pszwnd += _CLX_strlen(TEXT(_HWNDOPT));
  633. // Find the end of the paramter
  634. pszend = _CLX_strchr(pszwnd, TEXT(' '));
  635. if (!pszend)
  636. pszend = pszwnd + _CLX_strlen(pszwnd);
  637. // Check if paramter is valid host name, i.e. not a number
  638. pszdot = _CLX_strchr(pszwnd, TEXT('.'));
  639. {
  640. // local execution, hwnd passed
  641. #ifdef _WIN64
  642. hwnd = (HWND) _atoi64(pszwnd);
  643. #else // !_WIN64
  644. hwnd = (HWND) _CLX_atol(pszwnd);
  645. #endif // !_WIN64
  646. TRACE((INFO_MESSAGE,
  647. TEXT("Local mode. Sending messages to smclient. HWND=0x%x\n"),
  648. hwnd));
  649. }
  650. findnext:
  651. #ifdef OS_WIN32
  652. // check for replace pid command
  653. pszwnd = szCmdLine;
  654. pszwnd = _CLX_strstr(szCmdLine, TEXT("pid="));
  655. if ( NULL != pszwnd )
  656. {
  657. WPARAM wParam;
  658. LPARAM lParam;
  659. HWND hClxWnd = hwnd;
  660. pszwnd += 4 * sizeof(pszwnd[0]);
  661. #ifdef _WIN64
  662. wParam = _atoi64( pszwnd );
  663. #else // !_WIN64
  664. wParam = _CLX_atol( pszwnd );
  665. #endif
  666. lParam = GetCurrentProcessId();
  667. if ( NULL == hClxWnd )
  668. hClxWnd = _FindSMCWindow( pClx, (LPARAM)wParam );
  669. if ( NULL != hClxWnd )
  670. {
  671. PostMessage(hClxWnd,
  672. WM_FB_REPLACEPID,
  673. wParam, lParam);
  674. pClx->hwndSMC = hClxWnd;
  675. }
  676. }
  677. #endif // OS_WIN32
  678. exitpt:
  679. return hwnd;
  680. }
  681. #ifndef OS_WINCE
  682. /*++
  683. * Function:
  684. * _EnumWindowsProcForSMC
  685. * Description:
  686. * Searches for the feedback window by class name
  687. * When found, sends a WM_FB_ACCEPTME to ensure that
  688. * this is the right window handle
  689. * Win32/Win16/!WinCE
  690. * Arguments:
  691. * hWnd - current window
  692. * lParam - unused
  693. * Return value:
  694. * FALSE if found
  695. * Called by:
  696. * _FindSMCWindow thru EnumWindows
  697. --*/
  698. BOOL CALLBACK LOADDS _EnumWindowsProcForSMC( HWND hWnd, LPARAM lParam )
  699. {
  700. TCHAR classname[128];
  701. BOOL bCont = TRUE;
  702. if (GetClassName(hWnd, classname, sizeof(classname)))
  703. {
  704. if (!
  705. _CLX_strcmp(classname, TEXT(_TSTNAMEOFCLAS)) &&
  706. #ifdef OS_WIN32
  707. SendMessage(hWnd, WM_FB_ACCEPTME, 0, *(LPARAM *)lParam))
  708. #endif
  709. #ifdef OS_WIN16
  710. SendMessage(hWnd, WM_FB_ACCEPTME, (WPARAM)g_hRDPInst, 0))
  711. #endif
  712. {
  713. *((HWND*)lParam) = hWnd;
  714. bCont = FALSE;
  715. }
  716. }
  717. return bCont;
  718. }
  719. /*++
  720. * Function:
  721. * _FindSMCWindow
  722. * Description:
  723. * Finds the tclient feedback window
  724. * Win32/Win16/!WinCE
  725. * Arguments:
  726. * pClx - context
  727. * lParam - if non zero override current process id
  728. * in the query
  729. * Return value:
  730. * The window handle
  731. * Called by:
  732. * ClxInitialize, _CheckWindow
  733. --*/
  734. HWND _FindSMCWindow(PCLXINFO pClx, LPARAM lParam)
  735. {
  736. HWND hwndFound = NULL;
  737. #ifdef OS_WIN32
  738. if ( 0 == lParam )
  739. lParam = pClx->dwProcessId;
  740. #endif // OS_WIN32
  741. if (!EnumWindows(_EnumWindowsProcForSMC, (LPARAM)&lParam))
  742. hwndFound = (HWND)lParam;
  743. return hwndFound;
  744. }
  745. /*++
  746. * Function:
  747. * _CheckWindow
  748. * Description:
  749. * Checks the feedback window and if neccessary finds it
  750. * Win32/Win16/!WinCE
  751. * Arguments:
  752. * pClx - context
  753. * Return value:
  754. * Feedback window handle
  755. * Called by:
  756. * ClxEvetm ClxTextOut, ClxBitmap
  757. --*/
  758. HWND _CheckWindow(PCLXINFO pClx)
  759. {
  760. if (!pClx->hwndSMC)
  761. {
  762. pClx->hwndSMC = _FindSMCWindow(pClx, 0);
  763. if (pClx->hwndSMC)
  764. {
  765. TRACE((INFO_MESSAGE,
  766. TEXT("SMC window found:0x%x\n"),
  767. pClx->hwndSMC));
  768. }
  769. } else {
  770. #ifdef _WIN64
  771. if (!GetWindowLongPtr(pClx->hwndSMC, GWLP_HINSTANCE))
  772. #else // !_WIN64
  773. #ifdef OS_WIN32
  774. if (!GetWindowLong(pClx->hwndSMC, GWL_HINSTANCE))
  775. #endif
  776. #ifdef OS_WIN16
  777. if (!GetWindowWord(pClx->hwndSMC, GWW_HINSTANCE))
  778. #endif
  779. #endif // _WIN64
  780. {
  781. TRACE((WARNING_MESSAGE, TEXT("SMC window lost\n")));
  782. pClx->hwndSMC = NULL;
  783. }
  784. }
  785. return (pClx->hwndSMC);
  786. }
  787. #endif // !OS_WINCE
  788. #ifdef OS_WIN32
  789. #ifndef OS_WINCE
  790. /*++
  791. * Function:
  792. * _OpenMapFile
  793. * Description:
  794. * Opens a shared memeory for passing feedback to tclient.dll
  795. * Win32/!Win16/!WinCE
  796. * Return value:
  797. * TRUE if handle is allocated successfully
  798. * Called by:
  799. * ClxTextOut, ClxBitmap
  800. --*/
  801. BOOL _OpenMapFile(
  802. UINT nSize,
  803. HANDLE *phNewMapF,
  804. UINT *pnMapSize
  805. )
  806. {
  807. HANDLE hMapF;
  808. UINT nPageAligned;
  809. if (!nSize)
  810. nPageAligned = ((sizeof(FEEDBACKINFO) / CLX_ONE_PAGE) + 1) *
  811. CLX_ONE_PAGE;
  812. else
  813. nPageAligned = ((nSize / CLX_ONE_PAGE) + 1) * CLX_ONE_PAGE;
  814. hMapF = CreateFileMapping(INVALID_HANDLE_VALUE, //PG.SYS
  815. NULL, // no security
  816. PAGE_READWRITE,
  817. 0, // Size high
  818. nPageAligned, // Size low (1 page)
  819. NULL);
  820. *pnMapSize = (hMapF)?nPageAligned:0;
  821. *phNewMapF = hMapF;
  822. return (hMapF != NULL);
  823. }
  824. /*++
  825. * Function:
  826. * _ReOpenMapFile
  827. * Description:
  828. * Closes and opens a new shared memory with larger size
  829. * Win32/!Win16/!WinCE
  830. * Arguments:
  831. * pClx - context
  832. * newSize - size of the new memory
  833. * Return value:
  834. * TRUE on success
  835. * Called by:
  836. * ClxBitmap
  837. --*/
  838. BOOL _ReOpenMapFile(
  839. UINT newSize,
  840. HANDLE *phNewMapF,
  841. UINT *pnMapSize
  842. )
  843. {
  844. HANDLE hNewMapF;
  845. UINT nPageAligned;
  846. nPageAligned = ((newSize / CLX_ONE_PAGE) + 1) * CLX_ONE_PAGE;
  847. if (*phNewMapF)
  848. CloseHandle(*phNewMapF);
  849. hNewMapF = CreateFileMapping(INVALID_HANDLE_VALUE, //PG.SYS
  850. NULL, // no security
  851. PAGE_READWRITE,
  852. 0, // Size high
  853. nPageAligned, // Size low
  854. NULL);
  855. *pnMapSize = (hNewMapF)?nPageAligned:0;
  856. *phNewMapF = hNewMapF;
  857. return (hNewMapF != NULL);
  858. }
  859. /*++
  860. * Function:
  861. * _SaveinMapFile
  862. * Description:
  863. * Saves a string into the shared memory
  864. * Win32/!Win16/!WinCE
  865. * Arguments:
  866. * hMapF - handle to the map file
  867. * str - the string
  868. * strsize - size of the string
  869. * dwProcessId - our process Id
  870. * Return value:
  871. * TRUE on success
  872. * Called by:
  873. * ClxTextOut
  874. --*/
  875. BOOL _SaveInMapFile(HANDLE hMapF, LPVOID str, int strsize, DWORD_PTR dwProcessId)
  876. {
  877. BOOL rv = FALSE, count = 0;
  878. PFEEDBACKINFO pView;
  879. DWORD laste;
  880. pView = (PFEEDBACKINFO)MapViewOfFile(hMapF,
  881. FILE_MAP_ALL_ACCESS,
  882. 0,
  883. 0,
  884. sizeof(*pView));
  885. if (!pView)
  886. goto exitpt;
  887. pView->dwProcessId = dwProcessId;
  888. strsize = (strsize > sizeof(pView->string)/sizeof(WCHAR) - 1)?
  889. PtrToInt( (PVOID)(sizeof(pView->string)/sizeof(WCHAR) - 1)):
  890. strsize;
  891. CopyMemory(pView->string, str, strsize*sizeof(WCHAR));
  892. ((WCHAR *)(pView->string))[strsize] = 0;
  893. pView->strsize = strsize;
  894. UnmapViewOfFile(pView);
  895. rv = TRUE;
  896. exitpt:
  897. return rv;
  898. }
  899. /*++
  900. * Function:
  901. * _CheckRegistrySettings
  902. * Description:
  903. * Checks if the registry settings are OK for running clxtshar
  904. * "Allow Background Input" must be set to 1 for proper work
  905. * Win32/!Win16/!WinCE
  906. * Return value:
  907. * TRUE if the settings are OK
  908. * Called by:
  909. * DllMain
  910. --*/
  911. BOOL _CheckRegistrySettings(VOID)
  912. {
  913. HKEY key = NULL;
  914. DWORD disposition;
  915. DWORD keyType;
  916. DWORD value;
  917. DWORD cbData;
  918. BOOL rv = FALSE;
  919. LONG sysrc;
  920. sysrc = RegCreateKeyExW(HKEY_CURRENT_USER,
  921. REG_BASE,
  922. 0, /* reserved */
  923. NULL, /* class */
  924. REG_OPTION_NON_VOLATILE,
  925. KEY_ALL_ACCESS,
  926. NULL, /* security attributes */
  927. &key,
  928. &disposition);
  929. if (sysrc != ERROR_SUCCESS)
  930. {
  931. TRACE((WARNING_MESSAGE,
  932. TEXT("RegCreateKeyEx failed, status = %d\n"), sysrc));
  933. goto exitpt;
  934. }
  935. cbData = sizeof(value);
  936. sysrc = RegQueryValueExW(key,
  937. ALLOW_BACKGROUND_INPUT,
  938. 0, // reserved
  939. &keyType, // returned type
  940. (LPBYTE)&value, // data pointer
  941. &cbData);
  942. if (sysrc != ERROR_SUCCESS)
  943. {
  944. TRACE((WARNING_MESSAGE,
  945. TEXT("RegQueryValueEx failed, status = %d\n"), sysrc));
  946. goto exitpt;
  947. }
  948. if (keyType != REG_DWORD || cbData != sizeof(value))
  949. {
  950. TRACE((WARNING_MESSAGE,
  951. TEXT("Mismatch in type/size of registry entry\n")));
  952. goto exitpt;
  953. }
  954. rv = (value == 1);
  955. exitpt:
  956. return rv;
  957. }
  958. #endif // !OS_WINCE
  959. #endif // OS_WIN32
  960. #ifdef OS_WIN16
  961. /*++
  962. * Function:
  963. * _CheckRegistrySettings
  964. * Description:
  965. * Checks if the ini settings are OK for running clxtshar
  966. * "Allow Background Input" must be set to 1 for proper work
  967. * !Win32/Win16/!WinCE
  968. * Return value:
  969. * TRUE if the settings are OK
  970. * Called by:
  971. * DllMain
  972. --*/
  973. BOOL _CheckIniSettings(VOID)
  974. {
  975. UINT nABI;
  976. nABI = GetPrivateProfileInt("",
  977. ALLOW_BACKGROUND_INPUT,
  978. 0,
  979. "mstsc.ini");
  980. return (nABI == 1);
  981. }
  982. #endif // OS_WIN16
  983. /*++
  984. * Function:
  985. * _GetIniSettings
  986. * Description:
  987. * Gets the verbose level for printing debug messages
  988. * ini file: smclient.ini
  989. * section : clx
  990. * key : verbose, value: 0-4 (0-(default) no debug spew, 4 all debug)
  991. * key : GlyphEnable, value: 0(default), 1 - Enables/Disables glyph sending
  992. * Win32/Win16/WinCE
  993. * Called by:
  994. * DllMain, dllentry, LibMain
  995. --*/
  996. VOID _GetIniSettings(VOID)
  997. {
  998. #ifdef OS_WINCE
  999. g_VerboseLevel = 4;
  1000. g_GlyphEnable = 1;
  1001. #else // !OS_WINCE
  1002. CHAR szIniFileName[_MAX_PATH];
  1003. const CHAR smclient_ini[] = "\\smclient.ini";
  1004. const CHAR clx_ini_section[] = "clx";
  1005. memset( szIniFileName, 0, sizeof( szIniFileName ));
  1006. if (!_getcwd (
  1007. szIniFileName,
  1008. sizeof(szIniFileName) - strlen(smclient_ini) - 1)
  1009. )
  1010. {
  1011. TRACE((ERROR_MESSAGE, TEXT("Current directory length too long.\n")));
  1012. }
  1013. strcat(szIniFileName, smclient_ini);
  1014. // Get the timeout value
  1015. g_VerboseLevel = GetPrivateProfileInt(
  1016. clx_ini_section,
  1017. "verbose",
  1018. g_VerboseLevel,
  1019. szIniFileName);
  1020. g_GlyphEnable = GetPrivateProfileInt(
  1021. clx_ini_section,
  1022. "GlyphEnable",
  1023. g_GlyphEnable,
  1024. szIniFileName);
  1025. #endif // !OS_WINCE
  1026. GetPrivateProfileString(
  1027. TEXT("tclient"),
  1028. TEXT("UIYesNoDisconnect"),
  1029. TEXT(YES_NO_SHUTDOWN),
  1030. g_strYesNoShutdown,
  1031. sizeof(g_strYesNoShutdown),
  1032. szIniFileName
  1033. );
  1034. GetPrivateProfileString(
  1035. TEXT("tclient"),
  1036. TEXT("UIDisconnectDialogBox"),
  1037. TEXT(DISCONNECT_DIALOG_BOX),
  1038. g_strDisconnectDialogBox,
  1039. sizeof(g_strDisconnectDialogBox),
  1040. szIniFileName
  1041. );
  1042. GetPrivateProfileString(
  1043. TEXT("tclient"),
  1044. TEXT("UIClientCaption"),
  1045. TEXT(CLIENT_CAPTION),
  1046. g_strClientCaption,
  1047. sizeof(g_strClientCaption),
  1048. szIniFileName
  1049. );
  1050. GetPrivateProfileString(
  1051. TEXT("tclient"),
  1052. TEXT("UIMainWindowClass"),
  1053. TEXT("UIMainClass"),
  1054. g_strMainWindowClass,
  1055. sizeof(g_strMainWindowClass),
  1056. szIniFileName
  1057. );
  1058. }
  1059. /*++
  1060. * Function:
  1061. * _StripGlyph
  1062. * Description:
  1063. * Strips leading and trailing blank ... BITS
  1064. * Yes, bits. The glyph must be aligned from left and right on bit
  1065. * And glyph width must be aligned on word
  1066. * Win32/Win16/WinCE
  1067. * Arguments:
  1068. * pData - the glyph bits
  1069. * pxSize - glyph width
  1070. * ySize - glyph height
  1071. * Called by:
  1072. * ClxBitmap
  1073. --*/
  1074. VOID _StripGlyph(LPBYTE pData, UINT *pxSize, UINT ySize)
  1075. {
  1076. UINT xSize = *pxSize;
  1077. UINT leftBytes, leftBits;
  1078. UINT riteBytes, riteBits;
  1079. UINT xBytes = xSize >> 3;
  1080. UINT xScan, yScan, xFinal;
  1081. BOOL bScan, bAddByte;
  1082. BYTE mask;
  1083. BYTE *pSrc, *pDst;
  1084. if (!pData || !xBytes || !ySize)
  1085. goto exitpt;
  1086. leftBytes = riteBytes = 0;
  1087. leftBits = riteBits = 0;
  1088. *pxSize = 0; // Insurance for bad exit
  1089. // Scan from left for first nonzero byte
  1090. bScan = TRUE;
  1091. while(bScan)
  1092. {
  1093. for (yScan = 0; yScan < ySize && bScan; yScan ++)
  1094. bScan = (pData[yScan*xBytes + leftBytes] == 0);
  1095. if (bScan)
  1096. {
  1097. leftBytes++;
  1098. bScan = (leftBytes < xBytes);
  1099. }
  1100. }
  1101. // Trash if blank
  1102. if (leftBytes == xBytes)
  1103. goto exitpt;
  1104. // Scan from left for most left nonzero bit
  1105. for(yScan = 0; yScan < ySize; yScan ++)
  1106. {
  1107. UINT bitc = 0;
  1108. BYTE b = pData[yScan*xBytes + leftBytes];
  1109. while (b)
  1110. {
  1111. b >>= 1;
  1112. bitc ++;
  1113. }
  1114. if (bitc > leftBits)
  1115. leftBits = bitc;
  1116. }
  1117. if (!leftBits)
  1118. // There's something wrong
  1119. goto exitpt;
  1120. leftBits = 8 - leftBits;
  1121. // So far so good. Check the ri(gh)te side
  1122. bScan = TRUE;
  1123. while(bScan)
  1124. {
  1125. for(yScan = 0 ; yScan < ySize && bScan; yScan ++)
  1126. bScan = (pData[(yScan + 1)*xBytes - 1 - riteBytes] == 0);
  1127. if (bScan)
  1128. {
  1129. riteBytes ++;
  1130. bScan = (riteBytes < xBytes);
  1131. }
  1132. }
  1133. // Scan from rite for most rite nonzero bit
  1134. for(yScan = 0; yScan < ySize; yScan ++)
  1135. {
  1136. UINT bitc = 0;
  1137. BYTE b = pData[(yScan+1)*xBytes - 1 - riteBytes];
  1138. while(b)
  1139. {
  1140. b <<= 1;
  1141. bitc ++;
  1142. }
  1143. if (bitc > riteBits)
  1144. riteBits = bitc;
  1145. }
  1146. riteBits = 8 - riteBits;
  1147. // Cool, now get the final width
  1148. xFinal = xSize - riteBits - leftBits - ((leftBytes + riteBytes) << 3);
  1149. // align it and get bytes
  1150. xFinal = (xFinal + 8) >> 3;
  1151. // Now smoothly move the bitmap to the new location
  1152. pDst = pData;
  1153. mask = BitMask[leftBits];
  1154. bAddByte = xFinal & 1;
  1155. for (yScan = 0; yScan < ySize; yScan ++)
  1156. {
  1157. pSrc = pData + yScan*xBytes + leftBytes;
  1158. for(xScan = 0; xScan < xFinal; xScan ++, pDst++, pSrc++)
  1159. {
  1160. BYTE b = *pSrc;
  1161. BYTE r;
  1162. r = (pSrc[1] & mask) >> (8 - leftBits);
  1163. b <<= leftBits;
  1164. b |= r;
  1165. (*pDst) = b;
  1166. }
  1167. pDst[-1] &= BitMask[8 - (riteBits + leftBits) % 8];
  1168. if (bAddByte)
  1169. {
  1170. (*pDst) = 0;
  1171. pDst++;
  1172. }
  1173. }
  1174. // BUG: Yes, this is a real bug. But removing it means to
  1175. // rerecord all glyph database and the impact for
  1176. // glyph recognition is not so bad
  1177. //if (bAddByte)
  1178. // xFinal++;
  1179. *pxSize = xFinal << 3;
  1180. exitpt:
  1181. ;
  1182. }
  1183. /*++
  1184. * Function:
  1185. * LocalPrintMessage
  1186. * Description:
  1187. * Prints debugging and warning/error messages
  1188. * Win32/Win16/WinCE
  1189. * Arguments:
  1190. * errlevel - level of the message to print
  1191. * format - print format
  1192. * Called by:
  1193. * every TRACE line
  1194. --*/
  1195. VOID __cdecl LocalPrintMessage(INT errlevel, LPCTSTR format, ...)
  1196. {
  1197. TCHAR szBuffer[256];
  1198. TCHAR *type;
  1199. va_list arglist;
  1200. int nchr;
  1201. if (errlevel >= g_VerboseLevel)
  1202. goto exitpt;
  1203. va_start (arglist, format);
  1204. nchr = _CLX_vsnprintf (szBuffer, sizeof(szBuffer)/sizeof( szBuffer[0] ), format, arglist);
  1205. va_end (arglist);
  1206. szBuffer[sizeof( szBuffer )/sizeof( szBuffer[0] ) - 1] = 0;
  1207. switch(errlevel)
  1208. {
  1209. case INFO_MESSAGE: type = TEXT("CLX INF:"); break;
  1210. case ALIVE_MESSAGE: type = TEXT("CLX ALV:"); break;
  1211. case WARNING_MESSAGE: type = TEXT("CLX WRN:"); break;
  1212. case ERROR_MESSAGE: type = TEXT("CLX ERR:"); break;
  1213. default: type = TEXT("UNKNOWN:");
  1214. }
  1215. OutputDebugString(type);
  1216. OutputDebugString(szBuffer);
  1217. exitpt:
  1218. ;
  1219. }
  1220. /*++
  1221. * Function:
  1222. * _ClxAssert
  1223. * Description:
  1224. * Asserts boolean expression
  1225. * Win32/Win16/WinCE
  1226. * Arguments:
  1227. * bCond - boolean condition
  1228. * filename - source file of the assertion
  1229. * line - line of the assertion
  1230. * Called by:
  1231. * every ASSERT line
  1232. --*/
  1233. VOID _ClxAssert(BOOL bCond, LPCTSTR filename, INT line)
  1234. {
  1235. if (!bCond)
  1236. {
  1237. TRACE((ERROR_MESSAGE,
  1238. TEXT("ASSERT: %s line %d\n"), filename, line));
  1239. DebugBreak();
  1240. }
  1241. }
  1242. /*++
  1243. * Function:
  1244. * _EnumWindowsProc
  1245. * Description:
  1246. * Used to find a specific window
  1247. * Win32/Win16/WinCE
  1248. * Arguments:
  1249. * hWnd - current enumerated window handle
  1250. * lParam - pointer to SEARCHWND passed from
  1251. * _FindTopWindow
  1252. * Return value:
  1253. * TRUE on success but window is not found
  1254. * FALSE if the window is found
  1255. * Called by:
  1256. * _FindTopWindow thru EnumWindows
  1257. --*/
  1258. BOOL CALLBACK LOADDS _EnumWindowsProc( HWND hWnd, LPARAM lParam )
  1259. {
  1260. TCHAR classname[128];
  1261. TCHAR caption[128];
  1262. BOOL rv = TRUE;
  1263. _CLXWINDOWOWNER hInst;
  1264. PSEARCHWND pSearch = (PSEARCHWND)lParam;
  1265. if (pSearch->szClassName &&
  1266. !GetClassName(hWnd, classname, sizeof(classname)/sizeof(TCHAR)))
  1267. {
  1268. goto exitpt;
  1269. }
  1270. if (pSearch->szCaption && !GetWindowText(hWnd, caption, sizeof(caption)/sizeof(TCHAR)))
  1271. {
  1272. goto exitpt;
  1273. }
  1274. #ifdef OS_WINCE
  1275. {
  1276. DWORD procId = 0;
  1277. GetWindowThreadProcessId(hWnd, &procId);
  1278. hInst = procId;
  1279. }
  1280. #else // !OS_WINCE
  1281. #ifdef _WIN64
  1282. hInst = (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE);
  1283. #else // !_WIN64
  1284. #ifdef OS_WIN32
  1285. hInst = (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE);
  1286. #endif // OS_WIN32
  1287. #endif // !OS_WINCE
  1288. #ifdef OS_WIN16
  1289. hInst = (HINSTANCE)GetWindowWord(hWnd, GWW_HINSTANCE);
  1290. #endif
  1291. #endif // _WIN64
  1292. if (
  1293. (!pSearch->szClassName || ! // Check for classname
  1294. _CLX_strcmp(classname, pSearch->szClassName))
  1295. &&
  1296. (!pSearch->szCaption || !
  1297. _CLX_strcmp(caption, pSearch->szCaption))
  1298. &&
  1299. hInst == pSearch->hInstance)
  1300. {
  1301. ((PSEARCHWND)lParam)->hWnd = hWnd;
  1302. rv = FALSE;
  1303. }
  1304. exitpt:
  1305. return rv;
  1306. }
  1307. /*++
  1308. * Function:
  1309. * _FindTopWindow
  1310. * Description:
  1311. * Find specific window by classname and/or caption and/or process Id
  1312. * Win32/Win16/WinCE
  1313. * Arguments:
  1314. * classname - class name to search for, NULL ignore
  1315. * caption - caption to search for, NULL ignore
  1316. * hInst - instance handle, NULL ignore
  1317. * Return value:
  1318. * window handle found, NULL otherwise
  1319. * Called by:
  1320. * SCConnect, SCDisconnect, GetDisconnectResult
  1321. --*/
  1322. HWND _FindTopWindow(LPCTSTR classname, LPCTSTR caption, _CLXWINDOWOWNER hInst)
  1323. {
  1324. SEARCHWND search;
  1325. search.szClassName = classname;
  1326. search.szCaption = caption;
  1327. search.hWnd = NULL;
  1328. search.hInstance = hInst;
  1329. EnumWindows(_EnumWindowsProc, (LPARAM)&search);
  1330. return search.hWnd;
  1331. }
  1332. /*++
  1333. * Function:
  1334. * _FindWindow
  1335. * Description:
  1336. * Find child window by classname
  1337. * Win32/Win16/WinCE
  1338. * Arguments:
  1339. * hwndParent - the parent window handle
  1340. * srchclass - class name to search for, NULL - ignore
  1341. * Return value:
  1342. * window handle found, NULL otherwise
  1343. * Called by:
  1344. *
  1345. --*/
  1346. HWND _FindWindow(HWND hwndParent, LPCTSTR srchclass)
  1347. {
  1348. HWND hWnd, hwndTop, hwndNext;
  1349. BOOL bFound;
  1350. TCHAR classname[128];
  1351. hWnd = NULL;
  1352. hwndTop = GetWindow(hwndParent, GW_CHILD);
  1353. if (!hwndTop)
  1354. {
  1355. TRACE((INFO_MESSAGE, TEXT("GetWindow failed. hwnd=0x%x\n"), hwndParent));
  1356. goto exiterr;
  1357. }
  1358. bFound = FALSE;
  1359. hwndNext = hwndTop;
  1360. do {
  1361. hWnd = hwndNext;
  1362. if (srchclass && !GetClassName(hWnd, classname, sizeof(classname)/sizeof(TCHAR)))
  1363. {
  1364. TRACE((INFO_MESSAGE, TEXT("GetClassName failed. hwnd=0x%x\n")));
  1365. goto nextwindow;
  1366. }
  1367. if (!srchclass || !_CLX_strcmp(classname, srchclass))
  1368. bFound = TRUE;
  1369. nextwindow:
  1370. #ifndef OS_WINCE
  1371. hwndNext = GetNextWindow(hWnd, GW_HWNDNEXT);
  1372. #else // OS_WINCE
  1373. hwndNext = GetWindow(hWnd, GW_HWNDNEXT);
  1374. #endif // OS_WINCE
  1375. } while (hWnd && hwndNext != hwndTop && !bFound);
  1376. if (!bFound) goto exiterr;
  1377. return hWnd;
  1378. exiterr:
  1379. return NULL;
  1380. }
  1381. #ifndef OS_WINCE
  1382. #ifdef OS_WIN32
  1383. DWORD
  1384. __stdcall
  1385. _ClxSendMsgThread(VOID *param)
  1386. {
  1387. PCLXINFO pClx = (PCLXINFO)param;
  1388. while(1)
  1389. {
  1390. if (!pClx || WaitForSingleObject(pClx->semSendReady, INFINITE) !=
  1391. WAIT_OBJECT_0)
  1392. goto exitpt;
  1393. if (!pClx || pClx->bSendMsgThreadExit)
  1394. goto exitpt;
  1395. SendMessage(pClx->msg.hwnd,
  1396. pClx->msg.message,
  1397. pClx->msg.wParam,
  1398. pClx->msg.lParam);
  1399. // release next waiting worker
  1400. ReleaseSemaphore(pClx->semSendDone, 1, NULL);
  1401. }
  1402. exitpt:
  1403. return 0;
  1404. }
  1405. BOOL
  1406. _ClxInitSendMessageThread( PCLXINFO pClx )
  1407. {
  1408. BOOL rv = FALSE;
  1409. DWORD dwThreadId;
  1410. if (!pClx)
  1411. goto exitpt;
  1412. if (!pClx->semSendDone)
  1413. pClx->semSendDone = CreateSemaphore(NULL, 1, 10, NULL);
  1414. if (!pClx->semSendReady)
  1415. pClx->semSendReady = CreateSemaphore(NULL, 0, 10, NULL);
  1416. if (!pClx->semSendDone || !pClx->semSendReady)
  1417. goto exitpt;
  1418. if (!pClx->hSendMsgThread)
  1419. {
  1420. pClx->hSendMsgThread = CreateThread(
  1421. NULL,
  1422. 0,
  1423. _ClxSendMsgThread,
  1424. pClx,
  1425. 0,
  1426. &dwThreadId);
  1427. }
  1428. if (!pClx->hSendMsgThread)
  1429. goto exitpt;
  1430. rv = TRUE;
  1431. exitpt:
  1432. if ( !rv )
  1433. {
  1434. _ClxDestroySendMsgThread( pClx );
  1435. }
  1436. return rv;
  1437. }
  1438. BOOL
  1439. _ClxAcquireSendMessageThread( PCLXINFO pClx )
  1440. {
  1441. BOOL rv = FALSE;
  1442. if (!pClx)
  1443. goto exitpt;
  1444. if (!pClx->hSendMsgThread)
  1445. goto exitpt;
  1446. // Wait 10 mins send to complete
  1447. if (WaitForSingleObject(pClx->semSendDone, 600000) !=
  1448. WAIT_OBJECT_0)
  1449. goto exitpt;
  1450. rv = TRUE;
  1451. exitpt:
  1452. return rv;
  1453. }
  1454. VOID
  1455. _ClxReleaseSendMessageThread( PCLXINFO pClx )
  1456. {
  1457. ASSERT( pClx->semSendReady );
  1458. // Signal the thread for available message
  1459. ReleaseSemaphore(pClx->semSendReady, 1, NULL);
  1460. }
  1461. /*++
  1462. * Function:
  1463. * _ClxSendMessage
  1464. * Description:
  1465. * Calls SendMessage from separate thread
  1466. * prevents deadlock on SendMessage (#319816)
  1467. *
  1468. * Arguments:
  1469. * hBitmap - the main bitmap
  1470. * ppDIB - pointer to DIB data
  1471. * left, top, right, bottom - describes the rectangle
  1472. * - if all are == -1, returns the whole bitmap
  1473. * Return value:
  1474. * TRUE on success
  1475. * Called by:
  1476. * _ClxWndProc on WM_TIMER message
  1477. --*/
  1478. LRESULT
  1479. _ClxSendMessage(
  1480. PCLXINFO pClx,
  1481. HWND hWnd, // handle of destination window
  1482. UINT Msg, // message to send
  1483. WPARAM wParam, // first message parameter
  1484. LPARAM lParam // second message parameter
  1485. )
  1486. {
  1487. LRESULT rv = 0;
  1488. ASSERT(pClx->semSendDone);
  1489. ASSERT(pClx->semSendReady);
  1490. ASSERT(pClx->hSendMsgThread);
  1491. pClx->msg.hwnd = hWnd;
  1492. pClx->msg.message = Msg;
  1493. pClx->msg.wParam = wParam;
  1494. pClx->msg.lParam = lParam;
  1495. exitpt:
  1496. return rv;
  1497. }
  1498. VOID
  1499. _ClxDestroySendMsgThread(PCLXINFO pClx)
  1500. {
  1501. if (!pClx)
  1502. goto exitpt1;
  1503. if (!pClx->semSendDone || !pClx->semSendReady || !pClx->hSendMsgThread)
  1504. goto exitpt;
  1505. // Wait 10 mins send to complete
  1506. WaitForSingleObject(pClx->semSendDone, 600000);
  1507. pClx->bSendMsgThreadExit = TRUE;
  1508. // signal the thread to exit
  1509. ReleaseSemaphore(pClx->semSendReady, 1, NULL);
  1510. // wait for the thread to exit
  1511. if (WaitForSingleObject(pClx->hSendMsgThread, 1200000) != WAIT_OBJECT_0)
  1512. {
  1513. TRACE((ERROR_MESSAGE, TEXT("SendThread can't exit, calling TerminateThread\n")));
  1514. TerminateThread(pClx->hSendMsgThread, 0);
  1515. }
  1516. CloseHandle(pClx->hSendMsgThread);
  1517. exitpt:
  1518. if (pClx->semSendDone)
  1519. {
  1520. CloseHandle(pClx->semSendDone);
  1521. pClx->semSendDone = NULL;
  1522. }
  1523. if (pClx->semSendReady)
  1524. {
  1525. CloseHandle(pClx->semSendReady);
  1526. pClx->semSendReady = NULL;
  1527. }
  1528. pClx->hSendMsgThread = 0;
  1529. exitpt1:
  1530. ;
  1531. }
  1532. #endif // OS_WIN32
  1533. #endif // !OS_WINCE