Source code of Windows XP (NT5)
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.

4795 lines
122 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 "clxexport.h"
  26. #include "clxtshar.h"
  27. #define WM_CLIPBOARD (WM_USER) // Internal notifcation to send
  28. // our clipboard
  29. #ifdef OS_WIN32
  30. #ifndef OS_WINCE
  31. /*++
  32. * Function:
  33. * DllMain
  34. * Description:
  35. * Dll entry point for win32 (no WinCE)
  36. --*/
  37. int APIENTRY DllMain(HINSTANCE hDllInst,
  38. DWORD dwReason,
  39. LPVOID fImpLoad)
  40. {
  41. if (dwReason == DLL_PROCESS_ATTACH)
  42. {
  43. g_hInstance = hDllInst;
  44. TRACE((INFO_MESSAGE, TEXT("Clx attached\n")));
  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. _GetIniSettings();
  55. }
  56. if (dwReason == DLL_PROCESS_DETACH)
  57. {
  58. TRACE((INFO_MESSAGE, TEXT("Clx detached\n")));
  59. }
  60. return TRUE;
  61. }
  62. #endif // !OS_WINCE
  63. #endif // OS_WIN32
  64. #ifdef OS_WINCE
  65. /*++
  66. * Function:
  67. * dllentry
  68. * Description:
  69. * Dll entry point for wince
  70. --*/
  71. BOOL __stdcall dllentry(HINSTANCE hDllInst,
  72. DWORD dwReason,
  73. LPVOID fImpLoad)
  74. {
  75. if (dwReason == DLL_PROCESS_ATTACH)
  76. {
  77. g_hInstance = hDllInst;
  78. TRACE((INFO_MESSAGE, TEXT("Clx attached\n")));
  79. if (!_StartAsyncThread())
  80. TRACE((ERROR_MESSAGE,
  81. TEXT("Can't start AsyncThread. TCP unusable\n")));
  82. _GetIniSettings();
  83. }
  84. if (dwReason == DLL_PROCESS_DETACH)
  85. {
  86. TRACE((INFO_MESSAGE, TEXT("Clx detached\n")));
  87. _CloseAsyncThread();
  88. }
  89. return TRUE;
  90. }
  91. #endif // OS_WIN32
  92. #ifdef OS_WIN16
  93. /*++
  94. * Function:
  95. * LibMain
  96. * Description:
  97. * Dll entry point for win16
  98. --*/
  99. int CALLBACK LibMain(HINSTANCE hInstance,
  100. WORD dataSeg,
  101. WORD heapSize,
  102. LPSTR pCmdLine)
  103. {
  104. // Check if we are already initialized
  105. // Only one client is allowed in Win16 environment
  106. // so, only one dll can be loaded at a time
  107. if (g_hInstance)
  108. goto exitpt;
  109. g_hInstance = hInstance;
  110. // Check the key "Allow Background Input"
  111. // If not set pop a message for that
  112. if (!_CheckIniSettings())
  113. MessageBox(NULL, "CLXTSHAR.DLL: Can't find key: "
  114. "Allow Background Input in mstsc.ini, section \"\"\n"
  115. "In order to work properly "
  116. "CLX needs this key to be set to 1", "Warning",
  117. MB_OK);
  118. _GetIniSettings();
  119. exitpt:
  120. return TRUE;
  121. }
  122. #endif // OS_WIN16
  123. /*++
  124. * Function:
  125. * ClxInitialize
  126. * Description:
  127. * Initilizes a context for the current session
  128. * reads the command line paramters and determines
  129. * the mode wich will run the extension: local or RCLX (Remote CLient
  130. * eXecution)
  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. #ifdef OS_WIN32
  147. #ifndef OS_WINCE
  148. // We have enough problems in stress with early unloaded
  149. // dll, reference it now and keep it up until the process
  150. // dies
  151. LoadLibrary("clxtshar.dll");
  152. #endif // !OS_WINCE
  153. #endif // OS_WIN32
  154. hwndSMC = _ParseCmdLine(pClInfo->pszCmdLine);
  155. if (IS_RCLX && !WS_Init())
  156. {
  157. TRACE((ERROR_MESSAGE, TEXT("Can't init winsock\n")));
  158. goto exitpt;
  159. }
  160. if (g_pClx)
  161. // Should not be called twice
  162. {
  163. TRACE((WARNING_MESSAGE, TEXT("g_pClx is not null. Reentered ?!\n")));
  164. goto exitpt;
  165. }
  166. *ppClx = (PCLXINFO)_CLXALLOC(sizeof(**ppClx));
  167. g_pClx = (*ppClx);
  168. if (!*ppClx)
  169. goto exitpt;
  170. // Clear the structure
  171. memset(*ppClx, 0, sizeof(**ppClx));
  172. // put init of g_pClx here
  173. g_pClx->bClipboardReenter = (ULONG)-1;
  174. //
  175. // Remember client's input window
  176. (*ppClx)->hwndMain = pClInfo->hwndMain;
  177. if (pClInfo->hwndMain)
  178. #ifdef OS_WINCE
  179. g_hRDPInst = GetCurrentProcessId();
  180. #else // !OS_WINCE
  181. #ifdef _WIN64
  182. g_hRDPInst = (HINSTANCE)GetWindowLongPtr((*ppClx)->hwndMain, GWLP_HINSTANCE);
  183. #else // !_WIN64
  184. #ifdef OS_WIN32
  185. g_hRDPInst = (HINSTANCE)GetWindowLong((*ppClx)->hwndMain, GWL_HINSTANCE);
  186. #endif // OS_WIN32
  187. #endif // _WIN64
  188. #ifdef OS_WIN16
  189. g_hRDPInst = (HINSTANCE)GetWindowWord((*ppClx)->hwndMain, GWW_HINSTANCE);
  190. #endif // OS_WIN16
  191. #endif // !OS_WINCE
  192. #ifndef OS_WINCE
  193. #ifdef OS_WIN32
  194. // and dwProcessId
  195. (*ppClx)->dwProcessId = GetCurrentProcessId();
  196. #endif // OS_WIN32
  197. #endif // !OS_WINCE
  198. if (IS_RCLX)
  199. {
  200. (*ppClx)->hSocket = INVALID_SOCKET;
  201. RClx_CreateWindow(g_hInstance);
  202. }
  203. #ifdef OS_WIN32
  204. #ifndef OS_WINCE
  205. else {
  206. if (!((*ppClx)->hwndSMC = hwndSMC))
  207. (*ppClx)->hwndSMC = _FindSMCWindow(*ppClx);
  208. }
  209. #endif // !OS_WINCE
  210. #endif // OS_WIN32
  211. if (g_hWindow) // REMOVED: && g_nMyReconId)
  212. PostMessage(g_hWindow, WM_TIMER, 0, 0);
  213. rv = TRUE;
  214. exitpt:
  215. return rv;
  216. }
  217. /*++
  218. * Function:
  219. * ClxEvent
  220. * Description:
  221. * Notifies tclient.dll that some event happend.
  222. * Connect/disconnect.
  223. * Win32/Win16/WinCE
  224. * Arguments:
  225. * pClx - context
  226. * Event - can be one of the following:
  227. * CLX_EVENT_CONNECT
  228. * CLX_EVENT_DISCONNECT
  229. * CLX_EVENT_LOGON
  230. * Called by:
  231. * !mstsc on event
  232. * alse some of the internal functions call this, especialy
  233. * to notify that the client can't connect:
  234. * ClxTerminate
  235. * _GarbageCollecting when an error box is popped
  236. --*/
  237. VOID
  238. CLXAPI
  239. ClxEvent(PCLXINFO pClx, CLXEVENT Event, ULONG ulResult)
  240. {
  241. UINT uiMessage = 0;
  242. #ifdef OS_WIN16
  243. ULONG lResult = ulResult;
  244. #else // !OS_WIN16
  245. LONG_PTR lResult = ulResult;
  246. #endif
  247. if (!pClx)
  248. goto exitpt;
  249. #ifdef VLADIMIS
  250. #pragma message("Disable this peace before checkin")
  251. if (Event == CLX_EVENT_SHADOWBITMAPDC)
  252. {
  253. pClx->hdcShadowBitmap = (HDC)lResult;
  254. goto exitpt;
  255. } else if (Event == CLX_EVENT_SHADOWBITMAP)
  256. {
  257. pClx->hShadowBitmap = (HBITMAP)lResult;
  258. goto exitpt;
  259. }
  260. #endif // VLADIMIS
  261. if (IS_RCLX)
  262. {
  263. RClx_SendEvent(pClx, Event, ulResult);
  264. }
  265. #ifndef OS_WINCE
  266. else {
  267. if (!_CheckWindow(pClx))
  268. goto exitpt;
  269. if (Event == CLX_EVENT_DISCONNECT)
  270. uiMessage = WM_FB_DISCONNECT;
  271. else if (Event == CLX_EVENT_CONNECT)
  272. {
  273. uiMessage = WM_FB_CONNECT;
  274. lResult = (LONG_PTR)pClx->hwndMain;
  275. }
  276. else if (Event == CLX_EVENT_LOGON)
  277. // lResult contains the session ID
  278. uiMessage = WM_FB_LOGON;
  279. if (uiMessage)
  280. {
  281. #ifdef OS_WIN32
  282. _ClxSendMessage(pClx->hwndSMC,
  283. uiMessage,
  284. (WPARAM)lResult,
  285. pClx->dwProcessId);
  286. #endif // OS_WIN32
  287. #ifdef OS_WIN16
  288. if (g_hRDPInst)
  289. SendMessage(pClx->hwndSMC,
  290. uiMessage,
  291. g_hRDPInst,
  292. (LPARAM)lResult);
  293. #endif // OS_WIN16
  294. }
  295. }
  296. #endif // !OS_WINCE
  297. exitpt:
  298. ;
  299. }
  300. /*++
  301. * Function:
  302. * ClxTextOut
  303. * Description:
  304. * Notifies tclient.dll that TEXTOUT order is recieved.
  305. * Passes the string to the dll. Supported only in Win32
  306. * Win32/Win16/WinCE
  307. * Arguments:
  308. * pClx - context
  309. * pText - buffer containing the string
  310. * textLength - string length
  311. * Called by:
  312. * !mstsc on receiving textout order
  313. --*/
  314. VOID
  315. CLXAPI
  316. ClxTextOut(PCLXINFO pClx, PVOID pText, INT textLength)
  317. {
  318. if (!pClx || !(*((UINT16 *)pText)))
  319. goto exitpt;
  320. if (IS_RCLX)
  321. {
  322. RClx_SendTextOut(pClx, pText, textLength);
  323. goto exitpt;
  324. }
  325. #ifdef OS_WIN32
  326. #ifndef OS_WINCE
  327. if (!_CheckWindow(pClx))
  328. goto exitpt;
  329. if (!pClx->hMapF)
  330. if (!_OpenMapFile(pClx, 0))
  331. goto exitpt;
  332. if (_SaveInMapFile(pClx->hMapF, pText, textLength, pClx->dwProcessId))
  333. _ClxSendMessage(pClx->hwndSMC,
  334. WM_FB_TEXTOUT,
  335. (WPARAM)pClx->dwProcessId,
  336. (LPARAM)pClx->hMapF);
  337. #endif // !OS_WINCE
  338. #endif // OS_WIN32
  339. exitpt:
  340. ;
  341. }
  342. /*++
  343. * Function:
  344. * ClxTerminate
  345. * Description:
  346. * Frees all alocations from ClxInitialize
  347. * Win32/Win16/WinCE
  348. * Arguments:
  349. * pClx - context
  350. * Called by:
  351. * !mstsc before the dll is unloaded and client exit
  352. --*/
  353. VOID
  354. CLXAPI
  355. ClxTerminate(PCLXINFO pClx)
  356. {
  357. PCLXVCHANNEL pNext;
  358. if (!pClx)
  359. goto exitpt;
  360. ClxEvent(pClx, CLX_EVENT_DISCONNECT, 0);
  361. if (IS_RCLX)
  362. {
  363. pClx->alive = FALSE;
  364. RClx_Disconnect(pClx);
  365. }
  366. #ifdef OS_WIN32
  367. #ifndef OS_WINCE
  368. else {
  369. if(pClx->hMapF)
  370. CloseHandle(pClx->hMapF);
  371. _ClxDestroySendMsgThread(g_pClx);
  372. }
  373. #endif // !OS_WINCE
  374. #endif // OS_WIN32
  375. if (pClx->uiReconnectTimer)
  376. {
  377. KillTimer(g_hWindow, pClx->uiReconnectTimer);
  378. pClx->uiReconnectTimer = 0;
  379. }
  380. if (pClx->pRequest)
  381. _CLXFREE(pClx->pRequest);
  382. _CLXFREE(pClx);
  383. g_pClx = NULL;
  384. // dispose g_pVChannels;
  385. while(g_pVChannels)
  386. {
  387. pNext = g_pVChannels->pNext;
  388. free(g_pVChannels);
  389. g_pVChannels = pNext;
  390. }
  391. RClx_DestroyWindow();
  392. if (IS_RCLX)
  393. WSACleanup();
  394. exitpt:
  395. ;
  396. }
  397. /*
  398. * Void functions exported to the RDP client
  399. */
  400. VOID
  401. CLXAPI
  402. ClxConnect(PCLXINFO pClx, LPTSTR lpsz)
  403. {
  404. }
  405. VOID
  406. CLXAPI
  407. ClxDisconnect(PCLXINFO pClx)
  408. {
  409. }
  410. /*++
  411. * Function:
  412. * ClxDialog
  413. * Description:
  414. * The RDP client is ready with the connect dialog.
  415. * In RCLX mode this means that we can connect to the test controler
  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. if (g_hWindow)
  434. PostMessage(g_hWindow, WM_TIMER, 0, 0);
  435. else
  436. TRACE((ERROR_MESSAGE, TEXT("No g_hWindow in ClxDialog\n")));
  437. exitpt:
  438. ;
  439. }
  440. /*++
  441. * Function:
  442. * ClxBitmap
  443. * Description:
  444. * Send a received bitmap to tclient.dll
  445. * Works on Win16/Win32/WinCE in RCLX mode
  446. * and on Win32 for local mode
  447. * Arguments:
  448. * pClx - context
  449. * cxSize, cySize - size of the bitmap
  450. * pBuffer - bitmap bits
  451. * nBmiSize - size of BITMAPINFO
  452. * pBmi - BITMAPINFO
  453. * Called by:
  454. * UHDrawMemBltOrder!mstsc
  455. * ClxGlyphOut
  456. --*/
  457. VOID
  458. CLXAPI
  459. ClxBitmap(
  460. PCLXINFO pClx,
  461. UINT cxSize,
  462. UINT cySize,
  463. PVOID pBuffer,
  464. UINT nBmiSize,
  465. PVOID pBmi)
  466. {
  467. #ifndef OS_WINCE
  468. #ifdef OS_WIN32
  469. UINT nSize, nBmpSize;
  470. PBMPFEEDBACK pView;
  471. #endif // OS_WIN32
  472. #endif // !OS_WINCE
  473. if (!g_GlyphEnable)
  474. goto exitpt;
  475. if (!pClx)
  476. goto exitpt;
  477. if (nBmiSize && !pBmi)
  478. goto exitpt;
  479. if (IS_RCLX)
  480. {
  481. RClx_SendBitmap(pClx, cxSize, cySize, pBuffer, nBmiSize, pBmi);
  482. goto exitpt;
  483. }
  484. #ifdef OS_WIN32
  485. #ifndef OS_WINCE
  486. if (!_CheckWindow(pClx))
  487. goto exitpt;
  488. if (!nBmiSize)
  489. nBmpSize = (cxSize * cySize ) >> 3;
  490. else
  491. {
  492. nBmpSize = ((PBITMAPINFO)pBmi)->bmiHeader.biSizeImage;
  493. if (!nBmpSize)
  494. nBmpSize = (cxSize * cySize *
  495. ((PBITMAPINFO)pBmi)->bmiHeader.biBitCount) >> 3;
  496. }
  497. nSize = nBmpSize + nBmiSize + sizeof(*pView);
  498. if (!nSize)
  499. goto exitpt;
  500. if (!pClx->hMapF)
  501. if (!_OpenMapFile(pClx, nSize))
  502. goto exitpt;
  503. if (nSize > pClx->nMapSize)
  504. if (!_ReOpenMapFile(pClx, nSize))
  505. goto exitpt;
  506. pView = MapViewOfFile(pClx->hMapF,
  507. FILE_MAP_ALL_ACCESS,
  508. 0,
  509. 0,
  510. nSize);
  511. if (!pView)
  512. goto exitpt;
  513. pView->lProcessId = pClx->dwProcessId;
  514. pView->bmpsize = nBmpSize;
  515. pView->bmiSize = nBmiSize;
  516. pView->xSize = cxSize;
  517. pView->ySize = cySize;
  518. if (pBmi)
  519. CopyMemory(&(pView->BitmapInfo), pBmi, nBmiSize);
  520. CopyMemory((BYTE *)(&(pView->BitmapInfo)) + nBmiSize, pBuffer, nBmpSize);
  521. if (!nBmiSize)
  522. {
  523. // This is glyph, strip it to the skin
  524. _StripGlyph((BYTE *)(&pView->BitmapInfo), &cxSize, cySize);
  525. nBmpSize = (cxSize * cySize ) >> 3;
  526. pView->bmpsize = nBmpSize;
  527. pView->xSize = cxSize;
  528. }
  529. UnmapViewOfFile(pView);
  530. _ClxSendMessage(pClx->hwndSMC,
  531. WM_FB_BITMAP,
  532. (WPARAM)pClx->dwProcessId,
  533. (LPARAM)pClx->hMapF);
  534. #endif // !OS_WINCE
  535. #endif // OS_WIN32
  536. exitpt:
  537. ;
  538. }
  539. /*++
  540. * Function:
  541. * ClxGlyphOut
  542. * Description:
  543. * Send a glyph to tclient.dll
  544. * Win32/Win16/WinCE
  545. * Arguments:
  546. * pClx - context
  547. * cxBits,cyBits - glyph size
  548. * pBuffer - the glyph
  549. * Called by:
  550. * GHOutputBuffer!mstsc
  551. --*/
  552. VOID
  553. CLXAPI
  554. ClxGlyphOut(
  555. PCLXINFO pClx,
  556. UINT cxBits,
  557. UINT cyBits,
  558. PVOID pBuffer)
  559. {
  560. if (g_GlyphEnable)
  561. ClxBitmap(pClx, cxBits, cyBits, pBuffer, 0, NULL);
  562. }
  563. /*++
  564. * Function:
  565. * ClxGlyphOut
  566. * Description:
  567. * Send a glyph to tclient.dll
  568. * Win32/Win16/WinCE
  569. * Arguments:
  570. * pClx - context
  571. * cxBits,cyBits - glyph size
  572. * pBuffer - the glyph
  573. * Called by:
  574. * GHOutputBuffer!mstsc
  575. --*/
  576. BOOL
  577. CLXAPI
  578. ClxGetClientData(
  579. PCLX_CLIENT_DATA pClntData
  580. )
  581. {
  582. BOOL rv = FALSE;
  583. if (!pClntData)
  584. {
  585. TRACE((ERROR_MESSAGE, TEXT("ClxGetClientData: parameter is NULL\n")));
  586. goto exitpt;
  587. }
  588. memset(pClntData, 0, sizeof(*pClntData));
  589. if (!g_pClx)
  590. {
  591. TRACE((ERROR_MESSAGE, TEXT("ClxGetClientData: Clx has no context\n")));
  592. goto exitpt;
  593. }
  594. pClntData->hScreenDC = g_pClx->hdcShadowBitmap;
  595. pClntData->hScreenBitmap = g_pClx->hShadowBitmap;
  596. pClntData->hwndMain = g_pClx->hwndMain;
  597. pClntData->hwndDialog = g_pClx->hwndDialog;
  598. pClntData->hwndInput = g_pClx->hwndInput;
  599. rv = TRUE;
  600. exitpt:
  601. return rv;
  602. }
  603. /*++
  604. * Function:
  605. * _ParseCmdLine
  606. * Description:
  607. * Retreives WHND of tclient.dll feedback window
  608. * passed by the command line
  609. * or retreives TestServer name if clxtshar will be
  610. * executed in RCLX mode
  611. * Win32/Win16/WinCE
  612. * Arguments:
  613. * szCmdLine - command line
  614. * Return value:
  615. * The window handle
  616. * Called by:
  617. * ClxInitialize
  618. --*/
  619. HWND _ParseCmdLine(LPCTSTR szCmdLine)
  620. {
  621. HWND hwnd = NULL;
  622. LPCTSTR pszwnd, pszdot, pszend;
  623. INT nCounter;
  624. if (!szCmdLine)
  625. goto exitpt;
  626. TRACE((INFO_MESSAGE, TEXT("Command line: %s\n"), szCmdLine));
  627. // Check for _RECONIDOPT(ReconID) option
  628. pszwnd = _CLX_strstr(szCmdLine, TEXT(_RECONIDOPT));
  629. if (!pszwnd)
  630. goto skip_reconidopt;
  631. pszwnd += _CLX_strlen(TEXT(_RECONIDOPT));
  632. g_nMyReconId = _CLX_atol(pszwnd);
  633. skip_reconidopt:
  634. // Check for _HWNDOPT(hSMC) option
  635. pszwnd = _CLX_strstr(szCmdLine, TEXT(_HWNDOPT));
  636. if (!pszwnd)
  637. goto exitpt;
  638. // Goto the parameter
  639. pszwnd += _CLX_strlen(TEXT(_HWNDOPT));
  640. // Find the end of the paramter
  641. pszend = _CLX_strchr(pszwnd, TEXT(' '));
  642. if (!pszend)
  643. pszend = pszwnd + _CLX_strlen(pszwnd);
  644. // Check if paramter is valid host name, i.e. not a number
  645. pszdot = _CLX_strchr(pszwnd, TEXT('.'));
  646. if (isalpha(*pszwnd) || (pszdot && (pszdot < pszend)))
  647. {
  648. // This is RCLX mode, grab the TestServer name
  649. #ifdef OS_WIN16
  650. INT len;
  651. #else // !OS_WIN16
  652. LONG_PTR len;
  653. #endif // OS_WIN16
  654. len = pszend - pszwnd;
  655. if (!len || len >= sizeof(g_szTestServer))
  656. {
  657. TRACE((WARNING_MESSAGE,
  658. TEXT("TestServer name is too long\n")));
  659. goto exitpt;
  660. }
  661. for (nCounter = 0;
  662. nCounter < len;
  663. g_szTestServer[nCounter] = (CHAR)(pszwnd[nCounter]), nCounter++)
  664. ;
  665. g_szTestServer[len] = 0;
  666. #ifdef UNICODE
  667. TRACE((INFO_MESSAGE,
  668. L"RCLX mode, connecting to test controler: %S\n",
  669. g_szTestServer));
  670. #else // !UNICODE
  671. TRACE((INFO_MESSAGE,
  672. "RCLX mode, connecting to test controler: %s\n",
  673. g_szTestServer));
  674. #endif // !UNICODE
  675. } else {
  676. // local execution, hwnd passed
  677. #ifdef _WIN64
  678. hwnd = (HWND) _atoi64(pszwnd);
  679. #else // !_WIN64
  680. hwnd = (HWND) _CLX_atol(pszwnd);
  681. #endif // !_WIN64
  682. TRACE((INFO_MESSAGE,
  683. TEXT("Local mode. Sending messages to smclient. HWND=0x%x\n"),
  684. hwnd));
  685. }
  686. exitpt:
  687. return hwnd;
  688. }
  689. #ifndef OS_WINCE
  690. /*++
  691. * Function:
  692. * _EnumWindowsProcForSMC
  693. * Description:
  694. * Searches for the feedback window by class name
  695. * When found, sends a WM_FB_ACCEPTME to ensure that
  696. * this is the right window handle
  697. * Win32/Win16/!WinCE
  698. * Arguments:
  699. * hWnd - current window
  700. * lParam - unused
  701. * Return value:
  702. * FALSE if found
  703. * Called by:
  704. * _FindSMCWindow thru EnumWindows
  705. --*/
  706. BOOL CALLBACK LOADDS _EnumWindowsProcForSMC( HWND hWnd, LPARAM lParam )
  707. {
  708. TCHAR classname[128];
  709. BOOL bCont = TRUE;
  710. if (GetClassName(hWnd, classname, sizeof(classname)))
  711. {
  712. if (!
  713. _CLX_strcmp(classname, TEXT(_TSTNAMEOFCLAS)) &&
  714. #ifdef OS_WIN32
  715. SendMessage(hWnd, WM_FB_ACCEPTME, 0, GetCurrentProcessId()))
  716. #endif
  717. #ifdef OS_WIN16
  718. SendMessage(hWnd, WM_FB_ACCEPTME, (WPARAM)g_hRDPInst, 0))
  719. #endif
  720. {
  721. *((HWND*)lParam) = hWnd;
  722. bCont = FALSE;
  723. }
  724. }
  725. return bCont;
  726. }
  727. /*++
  728. * Function:
  729. * _FindSMCWindow
  730. * Description:
  731. * Finds the tclient feedback window
  732. * Win32/Win16/!WinCE
  733. * Arguments:
  734. * pClx - context
  735. * Return value:
  736. * The window handle
  737. * Called by:
  738. * ClxInitialize, _CheckWindow
  739. --*/
  740. HWND _FindSMCWindow(PCLXINFO pClx)
  741. {
  742. HWND hwndFound = NULL;
  743. EnumWindows(_EnumWindowsProcForSMC, (LPARAM)&hwndFound);
  744. return hwndFound;
  745. }
  746. /*++
  747. * Function:
  748. * _CheckWindow
  749. * Description:
  750. * Checks the feedback window and if neccessary finds it
  751. * Win32/Win16/!WinCE
  752. * Arguments:
  753. * pClx - context
  754. * Return value:
  755. * Feedback window handle
  756. * Called by:
  757. * ClxEvetm ClxTextOut, ClxBitmap
  758. --*/
  759. HWND _CheckWindow(PCLXINFO pClx)
  760. {
  761. if (!pClx->hwndSMC)
  762. {
  763. pClx->hwndSMC = _FindSMCWindow(pClx);
  764. if (pClx->hwndSMC)
  765. {
  766. TRACE((INFO_MESSAGE,
  767. TEXT("SMC window found:0x%x\n"),
  768. pClx->hwndSMC));
  769. }
  770. } else {
  771. #ifdef _WIN64
  772. if (!GetWindowLongPtr(pClx->hwndSMC, GWLP_HINSTANCE))
  773. #else // !_WIN64
  774. #ifdef OS_WIN32
  775. if (!GetWindowLong(pClx->hwndSMC, GWL_HINSTANCE))
  776. #endif
  777. #ifdef OS_WIN16
  778. if (!GetWindowWord(pClx->hwndSMC, GWW_HINSTANCE))
  779. #endif
  780. #endif // _WIN64
  781. {
  782. TRACE((WARNING_MESSAGE, TEXT("SMC window lost\n")));
  783. pClx->hwndSMC = NULL;
  784. }
  785. }
  786. return (pClx->hwndSMC);
  787. }
  788. #endif // !OS_WINCE
  789. #ifdef OS_WIN32
  790. #ifndef OS_WINCE
  791. /*++
  792. * Function:
  793. * _OpenMapFile
  794. * Description:
  795. * Opens a shared memeory for passing feedback to tclient.dll
  796. * Win32/!Win16/!WinCE
  797. * Return value:
  798. * TRUE if handle is allocated successfully
  799. * Called by:
  800. * ClxTextOut, ClxBitmap
  801. --*/
  802. BOOL _OpenMapFile(PCLXINFO pClx, UINT nSize)
  803. {
  804. HANDLE hMapF;
  805. UINT nPageAligned;
  806. if (!nSize)
  807. nPageAligned = ((sizeof(FEEDBACKINFO) / CLX_ONE_PAGE) + 1) *
  808. CLX_ONE_PAGE;
  809. else
  810. nPageAligned = ((nSize / CLX_ONE_PAGE) + 1) * CLX_ONE_PAGE;
  811. hMapF = CreateFileMapping(INVALID_HANDLE_VALUE, //PG.SYS
  812. NULL, // no security
  813. PAGE_READWRITE,
  814. 0, // Size high
  815. nPageAligned, // Size low (1 page)
  816. NULL);
  817. pClx->nMapSize = (hMapF)?nPageAligned:0;
  818. pClx->hMapF = hMapF;
  819. return (hMapF != NULL);
  820. }
  821. /*++
  822. * Function:
  823. * _ReOpenMapFile
  824. * Description:
  825. * Closes and opens a new shared memory with larger size
  826. * Win32/!Win16/!WinCE
  827. * Arguments:
  828. * pClx - context
  829. * newSize - size of the new memory
  830. * Return value:
  831. * TRUE on success
  832. * Called by:
  833. * ClxBitmap
  834. --*/
  835. BOOL _ReOpenMapFile(PCLXINFO pClx, UINT newSize)
  836. {
  837. HANDLE hNewMapF;
  838. UINT nPageAligned;
  839. nPageAligned = ((newSize / CLX_ONE_PAGE) + 1) * CLX_ONE_PAGE;
  840. if (pClx->hMapF)
  841. CloseHandle(pClx->hMapF);
  842. hNewMapF = CreateFileMapping(INVALID_HANDLE_VALUE, //PG.SYS
  843. NULL, // no security
  844. PAGE_READWRITE,
  845. 0, // Size high
  846. nPageAligned, // Size low
  847. NULL);
  848. pClx->nMapSize = (hNewMapF)?nPageAligned:0;
  849. pClx->hMapF = hNewMapF;
  850. return (hNewMapF != NULL);
  851. }
  852. /*++
  853. * Function:
  854. * _SaveinMapFile
  855. * Description:
  856. * Saves a string into the shared memory
  857. * Win32/!Win16/!WinCE
  858. * Arguments:
  859. * hMapF - handle to the map file
  860. * str - the string
  861. * strsize - size of the string
  862. * dwProcessId - our process Id
  863. * Return value:
  864. * TRUE on success
  865. * Called by:
  866. * ClxTextOut
  867. --*/
  868. BOOL _SaveInMapFile(HANDLE hMapF, LPVOID *str, int strsize, DWORD dwProcessId)
  869. {
  870. BOOL rv = FALSE, count = 0;
  871. PFEEDBACKINFO pView;
  872. DWORD laste;
  873. pView = MapViewOfFile(hMapF,
  874. FILE_MAP_ALL_ACCESS,
  875. 0,
  876. 0,
  877. sizeof(*pView));
  878. if (!pView)
  879. goto exitpt;
  880. pView->dwProcessId = dwProcessId;
  881. strsize = (strsize > sizeof(pView->string)/sizeof(WCHAR))?
  882. sizeof(pView->string)/sizeof(WCHAR):
  883. strsize;
  884. CopyMemory(pView->string, str, strsize*sizeof(WCHAR));
  885. ((WCHAR *)(pView->string))[strsize] = 0;
  886. pView->strsize = strsize;
  887. UnmapViewOfFile(pView);
  888. rv = TRUE;
  889. exitpt:
  890. return rv;
  891. }
  892. /*++
  893. * Function:
  894. * _CheckRegistrySettings
  895. * Description:
  896. * Checks if the registry settings are OK for running clxtshar
  897. * "Allow Background Input" must be set to 1 for proper work
  898. * Win32/!Win16/!WinCE
  899. * Return value:
  900. * TRUE if the settings are OK
  901. * Called by:
  902. * DllMain
  903. --*/
  904. BOOL _CheckRegistrySettings(VOID)
  905. {
  906. HKEY key;
  907. DWORD disposition;
  908. DWORD keyType;
  909. DWORD value;
  910. DWORD cbData;
  911. BOOL rv = FALSE;
  912. LONG sysrc;
  913. sysrc = RegCreateKeyEx(HKEY_CURRENT_USER,
  914. REG_BASE,
  915. 0, /* reserved */
  916. NULL, /* class */
  917. REG_OPTION_NON_VOLATILE,
  918. KEY_ALL_ACCESS,
  919. NULL, /* security attributes */
  920. &key,
  921. &disposition);
  922. cbData = sizeof(value);
  923. sysrc = RegQueryValueEx(key,
  924. ALLOW_BACKGROUND_INPUT,
  925. 0, // reserved
  926. &keyType, // returned type
  927. (LPBYTE)&value, // data pointer
  928. &cbData);
  929. if (sysrc != ERROR_SUCCESS)
  930. {
  931. TRACE((WARNING_MESSAGE,
  932. TEXT("RegQueryValueEx failed, status = %d\n"), sysrc));
  933. goto exitpt;
  934. }
  935. if (keyType != REG_DWORD || cbData != sizeof(value))
  936. {
  937. TRACE((WARNING_MESSAGE,
  938. TEXT("Mismatch in type/size of registry entry\n")));
  939. goto exitpt;
  940. }
  941. rv = (value == 1);
  942. exitpt:
  943. return rv;
  944. }
  945. #endif // !OS_WINCE
  946. #endif // OS_WIN32
  947. #ifdef OS_WIN16
  948. /*++
  949. * Function:
  950. * _CheckRegistrySettings
  951. * Description:
  952. * Checks if the ini settings are OK for running clxtshar
  953. * "Allow Background Input" must be set to 1 for proper work
  954. * !Win32/Win16/!WinCE
  955. * Return value:
  956. * TRUE if the settings are OK
  957. * Called by:
  958. * DllMain
  959. --*/
  960. BOOL _CheckIniSettings(VOID)
  961. {
  962. UINT nABI;
  963. nABI = GetPrivateProfileInt("",
  964. ALLOW_BACKGROUND_INPUT,
  965. 0,
  966. "mstsc.ini");
  967. return (nABI == 1);
  968. }
  969. #endif // OS_WIN16
  970. /*++
  971. * Function:
  972. * _GetIniSettings
  973. * Description:
  974. * Gets the verbose level for printing debug messages
  975. * ini file: smclient.ini
  976. * section : clx
  977. * key : verbose, value: 0-4 (0-(default) no debug spew, 4 all debug)
  978. * key : GlyphEnable, value: 0(default), 1 - Enables/Disables glyph sending
  979. * Win32/Win16/WinCE
  980. * Called by:
  981. * DllMain, dllentry, LibMain
  982. --*/
  983. VOID _GetIniSettings(VOID)
  984. {
  985. #ifdef OS_WINCE
  986. g_VerboseLevel = 4;
  987. g_GlyphEnable = 1;
  988. #else // !OS_WINCE
  989. CHAR szIniFileName[_MAX_PATH];
  990. const CHAR smclient_ini[] = "\\smclient.ini";
  991. const CHAR clx_ini_section[] = "clx";
  992. *szIniFileName = 0;
  993. if (!_getcwd (
  994. szIniFileName,
  995. sizeof(szIniFileName) - strlen(smclient_ini) - 1)
  996. )
  997. {
  998. TRACE((ERROR_MESSAGE, TEXT("Current directory length too long.\n")));
  999. }
  1000. strcat(szIniFileName, smclient_ini);
  1001. // Get the timeout value
  1002. g_VerboseLevel = GetPrivateProfileInt(
  1003. clx_ini_section,
  1004. "verbose",
  1005. g_VerboseLevel,
  1006. szIniFileName);
  1007. g_GlyphEnable = GetPrivateProfileInt(
  1008. clx_ini_section,
  1009. "GlyphEnable",
  1010. g_GlyphEnable,
  1011. szIniFileName);
  1012. #endif // !OS_WINCE
  1013. GetPrivateProfileString(
  1014. TEXT("tclient"),
  1015. TEXT("UIYesNoDisconnect"),
  1016. TEXT(YES_NO_SHUTDOWN),
  1017. g_strYesNoShutdown,
  1018. sizeof(g_strYesNoShutdown),
  1019. szIniFileName
  1020. );
  1021. GetPrivateProfileString(
  1022. TEXT("tclient"),
  1023. TEXT("UIDisconnectDialogBox"),
  1024. TEXT(DISCONNECT_DIALOG_BOX),
  1025. g_strDisconnectDialogBox,
  1026. sizeof(g_strDisconnectDialogBox),
  1027. szIniFileName
  1028. );
  1029. GetPrivateProfileString(
  1030. TEXT("tclient"),
  1031. TEXT("UIClientCaption"),
  1032. TEXT(CLIENT_CAPTION),
  1033. g_strClientCaption,
  1034. sizeof(g_strClientCaption),
  1035. szIniFileName
  1036. );
  1037. }
  1038. /*++
  1039. * Function:
  1040. * _StripGlyph
  1041. * Description:
  1042. * Strips leading and trailing blank ... BITS
  1043. * Yes, bits. The glyph must be aligned from left and right on bit
  1044. * And glyph width must be aligned on word
  1045. * Win32/Win16/WinCE
  1046. * Arguments:
  1047. * pData - the glyph bits
  1048. * pxSize - glyph width
  1049. * ySize - glyph height
  1050. * Called by:
  1051. * ClxBitmap
  1052. --*/
  1053. VOID _StripGlyph(LPBYTE pData, UINT *pxSize, UINT ySize)
  1054. {
  1055. UINT xSize = *pxSize;
  1056. UINT leftBytes, leftBits;
  1057. UINT riteBytes, riteBits;
  1058. UINT xBytes = xSize >> 3;
  1059. UINT xScan, yScan, xFinal;
  1060. BOOL bScan, bAddByte;
  1061. BYTE mask;
  1062. BYTE *pSrc, *pDst;
  1063. if (!pData || !xBytes || !ySize)
  1064. goto exitpt;
  1065. leftBytes = riteBytes = 0;
  1066. leftBits = riteBits = 0;
  1067. *pxSize = 0; // Insurance for bad exit
  1068. // Scan from left for first nonzero byte
  1069. bScan = TRUE;
  1070. while(bScan)
  1071. {
  1072. for (yScan = 0; yScan < ySize && bScan; yScan ++)
  1073. bScan = (pData[yScan*xBytes + leftBytes] == 0);
  1074. if (bScan)
  1075. {
  1076. leftBytes++;
  1077. bScan = (leftBytes < xBytes);
  1078. }
  1079. }
  1080. // Trash if blank
  1081. if (leftBytes == xBytes)
  1082. goto exitpt;
  1083. // Scan from left for most left nonzero bit
  1084. for(yScan = 0; yScan < ySize; yScan ++)
  1085. {
  1086. UINT bitc = 0;
  1087. BYTE b = pData[yScan*xBytes + leftBytes];
  1088. while (b)
  1089. {
  1090. b >>= 1;
  1091. bitc ++;
  1092. }
  1093. if (bitc > leftBits)
  1094. leftBits = bitc;
  1095. }
  1096. if (!leftBits)
  1097. // There's something wrong
  1098. goto exitpt;
  1099. leftBits = 8 - leftBits;
  1100. // So far so good. Check the ri(gh)te side
  1101. bScan = TRUE;
  1102. while(bScan)
  1103. {
  1104. for(yScan = 0 ; yScan < ySize && bScan; yScan ++)
  1105. bScan = (pData[(yScan + 1)*xBytes - 1 - riteBytes] == 0);
  1106. if (bScan)
  1107. {
  1108. riteBytes ++;
  1109. bScan = (riteBytes < xBytes);
  1110. }
  1111. }
  1112. // Scan from rite for most rite nonzero bit
  1113. for(yScan = 0; yScan < ySize; yScan ++)
  1114. {
  1115. UINT bitc = 0;
  1116. BYTE b = pData[(yScan+1)*xBytes - 1 - riteBytes];
  1117. while(b)
  1118. {
  1119. b <<= 1;
  1120. bitc ++;
  1121. }
  1122. if (bitc > riteBits)
  1123. riteBits = bitc;
  1124. }
  1125. riteBits = 8 - riteBits;
  1126. // Cool, now get the final width
  1127. xFinal = xSize - riteBits - leftBits - ((leftBytes + riteBytes) << 3);
  1128. // align it and get bytes
  1129. xFinal = (xFinal + 8) >> 3;
  1130. // Now smoothly move the bitmap to the new location
  1131. pDst = pData;
  1132. mask = BitMask[leftBits];
  1133. bAddByte = xFinal & 1;
  1134. for (yScan = 0; yScan < ySize; yScan ++)
  1135. {
  1136. pSrc = pData + yScan*xBytes + leftBytes;
  1137. for(xScan = 0; xScan < xFinal; xScan ++, pDst++, pSrc++)
  1138. {
  1139. BYTE b = *pSrc;
  1140. BYTE r;
  1141. r = (pSrc[1] & mask) >> (8 - leftBits);
  1142. b <<= leftBits;
  1143. b |= r;
  1144. (*pDst) = b;
  1145. }
  1146. pDst[-1] &= BitMask[8 - (riteBits + leftBits) % 8];
  1147. if (bAddByte)
  1148. {
  1149. (*pDst) = 0;
  1150. pDst++;
  1151. }
  1152. }
  1153. // BUG: Yes, this is a real bug. But removing it means to
  1154. // rerecord all glyph database and the impact for
  1155. // glyph recognition is not so bad
  1156. //if (bAddByte)
  1157. // xFinal++;
  1158. *pxSize = xFinal << 3;
  1159. exitpt:
  1160. ;
  1161. }
  1162. /*++
  1163. * Function:
  1164. * LocalPrintMessage
  1165. * Description:
  1166. * Prints debugging and warning/error messages
  1167. * Win32/Win16/WinCE
  1168. * Arguments:
  1169. * errlevel - level of the message to print
  1170. * format - print format
  1171. * Called by:
  1172. * every TRACE line
  1173. --*/
  1174. VOID __cdecl LocalPrintMessage(INT errlevel, LPCTSTR format, ...)
  1175. {
  1176. TCHAR szBuffer[256];
  1177. TCHAR *type;
  1178. va_list arglist;
  1179. int nchr;
  1180. if (errlevel >= g_VerboseLevel)
  1181. goto exitpt;
  1182. va_start (arglist, format);
  1183. nchr = _CLX_vsnprintf (szBuffer, sizeof(szBuffer), format, arglist);
  1184. va_end (arglist);
  1185. switch(errlevel)
  1186. {
  1187. case INFO_MESSAGE: type = TEXT("CLX INF:"); break;
  1188. case ALIVE_MESSAGE: type = TEXT("CLX ALV:"); break;
  1189. case WARNING_MESSAGE: type = TEXT("CLX WRN:"); break;
  1190. case ERROR_MESSAGE: type = TEXT("CLX ERR:"); break;
  1191. default: type = TEXT("UNKNOWN:");
  1192. }
  1193. OutputDebugString(type);
  1194. OutputDebugString(szBuffer);
  1195. exitpt:
  1196. ;
  1197. }
  1198. /*++
  1199. * Function:
  1200. * _ClxAssert
  1201. * Description:
  1202. * Asserts boolean expression
  1203. * Win32/Win16/WinCE
  1204. * Arguments:
  1205. * bCond - boolean condition
  1206. * filename - source file of the assertion
  1207. * line - line of the assertion
  1208. * Called by:
  1209. * every ASSERT line
  1210. --*/
  1211. VOID _ClxAssert( LPCTSTR filename, INT line)
  1212. {
  1213. TRACE((ERROR_MESSAGE,
  1214. TEXT("ASSERT: %s line %d\n"), filename, line));
  1215. DebugBreak();
  1216. }
  1217. /*
  1218. * RCLX (Remote CLient eXecution) functions
  1219. */
  1220. /*++
  1221. * Function:
  1222. * RClx_SendClientInfo
  1223. * Description:
  1224. * Sends platform specific information to the test controller
  1225. * Allows reconnection to a previous thread on the test ctrler
  1226. * Win32/Win16/WinCE
  1227. * Arguments:
  1228. * pClx - context
  1229. * Return value:
  1230. * TRUE on success
  1231. * Called by:
  1232. * _ClxWndProc on WM_TIMER message
  1233. --*/
  1234. BOOL
  1235. RClx_SendClientInfo(PCLXINFO pClx)
  1236. {
  1237. LPCSTR szClientInfo;
  1238. RCLXCLIENTINFOFEED ClntInfo;
  1239. RCLXFEEDPROLOG FeedProlog;
  1240. BOOL rv = FALSE;
  1241. ASSERT(pClx->hSocket != INVALID_SOCKET);
  1242. TRACE((ALIVE_MESSAGE,
  1243. TEXT("Sending Client info\n")));
  1244. #ifdef OS_WIN16
  1245. szClientInfo = "WIN16";
  1246. #endif // OS_WIN16
  1247. #ifdef OS_WIN32
  1248. #ifndef OS_WINCE
  1249. szClientInfo = "WIN32";
  1250. #else
  1251. szClientInfo = "WINCE";
  1252. #endif // OS_WINCE
  1253. #endif // OS_WIN32
  1254. strcpy(ClntInfo.szClientInfo, szClientInfo);
  1255. if (!g_nMyReconId)
  1256. {
  1257. ClntInfo.nReconnectAct = 0;
  1258. ClntInfo.ReconnectID = 0;
  1259. } else {
  1260. ClntInfo.nReconnectAct = 1;
  1261. ClntInfo.ReconnectID = g_nMyReconId;
  1262. }
  1263. FeedProlog.FeedType = FEED_CLIENTINFO;
  1264. FeedProlog.HeadSize = sizeof(ClntInfo);
  1265. FeedProlog.TailSize = 0;
  1266. rv = RClx_SendBuffer(pClx->hSocket,
  1267. &FeedProlog,
  1268. sizeof(FeedProlog));
  1269. rv = RClx_SendBuffer(pClx->hSocket,
  1270. &ClntInfo,
  1271. sizeof(ClntInfo));
  1272. if (rv)
  1273. pClx->bClientInfoSent = TRUE;
  1274. return rv;
  1275. }
  1276. /*++
  1277. * Function:
  1278. * RClx_Connect
  1279. * Description:
  1280. * Connects to the TestServer. The connect call is blocking
  1281. * After the connection succeeds "selects" the socket for
  1282. * async read, write is blocking
  1283. * Win32/Win16/WinCE
  1284. * Arguments:
  1285. * pClx - context
  1286. * Return value:
  1287. * TRUE on success
  1288. * Called by:
  1289. * _ClxWndProc on WM_TIMER message
  1290. --*/
  1291. BOOL RClx_Connect(PCLXINFO pClx)
  1292. {
  1293. SOCKET hRemote;
  1294. BOOL rv = FALSE;
  1295. INT optval;
  1296. ASSERT(pClx);
  1297. if (pClx->hSocket != INVALID_SOCKET)
  1298. {
  1299. TRACE((WARNING_MESSAGE,
  1300. TEXT("RClx_Connect called more than once\n")));
  1301. rv = TRUE;
  1302. goto exitpt;
  1303. }
  1304. #ifdef UNICODE
  1305. TRACE((INFO_MESSAGE,
  1306. L"Connecting to: %S:%d\n", g_szTestServer, g_nPort));
  1307. #else // !UNICODE
  1308. TRACE((INFO_MESSAGE,
  1309. "Connecting to: %s:%d\n", g_szTestServer, g_nPort));
  1310. #endif // !UNICODE
  1311. hRemote = socket(AF_INET, SOCK_STREAM, 0);
  1312. if (hRemote == INVALID_SOCKET)
  1313. {
  1314. TRACE((ERROR_MESSAGE,
  1315. TEXT("Can't create socket: %d\n"), WSAGetLastError()));
  1316. goto exitpt;
  1317. }
  1318. optval = 1;
  1319. setsockopt(hRemote,
  1320. IPPROTO_TCP,
  1321. TCP_NODELAY,
  1322. (const char *)&optval,
  1323. sizeof(optval));
  1324. setsockopt(hRemote,
  1325. SOL_SOCKET,
  1326. SO_DONTLINGER,
  1327. (const char *)&optval,
  1328. sizeof(optval));
  1329. if ((!pClx->sinTestSrv.sin_addr.s_addr ||
  1330. pClx->sinTestSrv.sin_addr.s_addr == INADDR_NONE) &&
  1331. (pClx->sinTestSrv.sin_addr.s_addr = inet_addr(g_szTestServer))
  1332. == INADDR_NONE)
  1333. {
  1334. struct hostent *phostent;
  1335. if ((phostent = gethostbyname(g_szTestServer)) == NULL)
  1336. {
  1337. #ifdef UNICODE
  1338. TRACE((ERROR_MESSAGE,
  1339. L"gethostbyname for %S failed: %d\n",
  1340. g_szTestServer, WSAGetLastError()));
  1341. #else // !UNICODE
  1342. TRACE((ERROR_MESSAGE,
  1343. "gethostbyname for %s failed: %d\n",
  1344. g_szTestServer, WSAGetLastError()));
  1345. #endif // !UNICODE
  1346. goto cleanup;
  1347. }
  1348. pClx->sinTestSrv.sin_addr.s_addr = *(u_long*)(phostent->h_addr);
  1349. }
  1350. pClx->sinTestSrv.sin_family = PF_INET;
  1351. pClx->sinTestSrv.sin_port = htons(g_nPort);
  1352. if (connect(hRemote,
  1353. (SOCKADDR *)&(pClx->sinTestSrv),
  1354. sizeof(pClx->sinTestSrv))
  1355. == SOCKET_ERROR)
  1356. {
  1357. #ifdef UNICODE
  1358. TRACE((WARNING_MESSAGE,
  1359. L"Can't connect to %S: %d\n",
  1360. g_szTestServer, WSAGetLastError()));
  1361. #else // !UNICODE
  1362. TRACE((WARNING_MESSAGE,
  1363. "Can't connect to %s: %d\n",
  1364. g_szTestServer, WSAGetLastError()));
  1365. #endif // !UNICODE
  1366. goto cleanup;
  1367. }
  1368. pClx->bClientInfoSent = FALSE;
  1369. pClx->hSocket = hRemote;
  1370. if (WSAAsyncSelect(hRemote, g_hWindow, WM_WSOCK, FD_CLOSE|FD_READ) ==
  1371. SOCKET_ERROR)
  1372. {
  1373. TRACE((ERROR_MESSAGE,
  1374. TEXT("WSAAsyncSelect failed: %d\n"),
  1375. WSAGetLastError()));
  1376. goto cleanup;
  1377. }
  1378. // If the socket is disconnected somewhere between connect and select
  1379. // we'll miss the notification, so try to read
  1380. // and have chance to fail
  1381. PostMessage(g_hWindow, WM_WSOCK, hRemote, FD_READ);
  1382. rv = TRUE;
  1383. exitpt:
  1384. return rv;
  1385. cleanup:
  1386. pClx->hSocket = hRemote;
  1387. RClx_Disconnect(pClx);
  1388. return rv;
  1389. }
  1390. /*++
  1391. * Function:
  1392. * RClx_Disconnect
  1393. * Description:
  1394. * Gracefully closes the socket to the TestServer. Deinitializes
  1395. * some vars in the context. Removes garbage windows
  1396. * Win32/Win16/WinCE
  1397. * Arguments:
  1398. * pClx - context
  1399. * Called by:
  1400. * ClxTerminate
  1401. * RClx_Connect on error
  1402. * RClx_SendEvent on EVENT_DIACONNECT
  1403. * _ClxWndProc on WM_WSOCK and error
  1404. --*/
  1405. VOID RClx_Disconnect(PCLXINFO pClx)
  1406. {
  1407. INT recvresult;
  1408. CHAR tBuf[128];
  1409. if (pClx && pClx->hSocket != INVALID_SOCKET)
  1410. {
  1411. WSAAsyncSelect(pClx->hSocket, g_hWindow, 0, 0);
  1412. shutdown(pClx->hSocket, SD_SEND);
  1413. do {
  1414. recvresult = recv(pClx->hSocket, tBuf, sizeof(tBuf), 0);
  1415. } while (recvresult && recvresult != SOCKET_ERROR);
  1416. closesocket(pClx->hSocket);
  1417. pClx->hSocket = INVALID_SOCKET;
  1418. }
  1419. // Zero some vars
  1420. pClx->hwndInput = NULL;
  1421. pClx->RClxInfo.szHydraServer[0] = 0;
  1422. if (pClx->alive)
  1423. {
  1424. // attempt to close the client
  1425. _AttemptToCloseTheClient();
  1426. g_pClx->bCloseTrys = TRUE;
  1427. }
  1428. else if (g_hWindow && !g_nMyReconId)
  1429. // Retry to connect
  1430. {
  1431. TRACE((INFO_MESSAGE,
  1432. TEXT("Disconnected from test server.Trying to reconnect\n")));
  1433. // If there's no timer looping
  1434. // Start connecting by posting a message
  1435. if (!pClx->uiReconnectTimer)
  1436. pClx->uiReconnectTimer = SetTimer(g_hWindow, RCLX_RECONNECT_TIMERID,
  1437. RCLX_RECONNECTELAPSETIME, NULL);
  1438. if (!pClx->uiReconnectTimer)
  1439. PostMessage(g_hWindow, WM_TIMER, 0, 0);
  1440. }
  1441. }
  1442. /*++
  1443. * Function:
  1444. * RClx_SendBuffer
  1445. * Description:
  1446. * Sends a buffer thru socket. The socket must be BLOCKING
  1447. * so, all the buffer is sent after this function exits
  1448. * Win32/Win16/WinCE
  1449. * Arguments:
  1450. * hSocket - the socket
  1451. * pBuffer - the buffer
  1452. * nSize - buffer size
  1453. * Return value:
  1454. * TRUE on success, FALSE if the connection failed
  1455. * Called by:
  1456. * RClx_SendEvent
  1457. * RClx_SendBitmap
  1458. *
  1459. --*/
  1460. BOOL
  1461. RClx_SendBuffer(SOCKET hSocket, PVOID pBuffer, DWORD nSize)
  1462. {
  1463. INT result = 0;
  1464. DWORD nBytesToSend = nSize;
  1465. UINT nBytesToSend2;
  1466. BYTE HUGEMOD *pBuffPtr = pBuffer;
  1467. ASSERT(hSocket != INVALID_SOCKET);
  1468. ASSERT(pBuffer);
  1469. if (!nSize)
  1470. goto exitpt;
  1471. do {
  1472. #ifdef OS_WIN16
  1473. nBytesToSend2 = (UINT)((nBytesToSend > 0x1000)?0x1000:nBytesToSend);
  1474. #else
  1475. nBytesToSend2 = nBytesToSend;
  1476. #endif // OS_WIN16
  1477. result = send(hSocket, pBuffPtr, nBytesToSend2, 0);
  1478. if (result != SOCKET_ERROR)
  1479. {
  1480. nBytesToSend -= result;
  1481. pBuffPtr += result;
  1482. } else
  1483. if (WSAGetLastError() == WSAEWOULDBLOCK)
  1484. {
  1485. // The socket is blocked, wait on select until it's writable
  1486. FD_SET fd;
  1487. FD_ZERO(&fd);
  1488. FD_SET(hSocket, &fd);
  1489. select(-1, NULL, &fd, NULL, NULL);
  1490. }
  1491. } while ((result != SOCKET_ERROR || WSAGetLastError() == WSAEWOULDBLOCK) &&
  1492. nBytesToSend);
  1493. exitpt:
  1494. return (result != SOCKET_ERROR);
  1495. }
  1496. /*++
  1497. * Function:
  1498. * RClx_SendEvent
  1499. * Description:
  1500. * Sends an event to the TestServer
  1501. * Win32/Win16/WinCE
  1502. * Arguments:
  1503. * pClx - context
  1504. * Event - the event
  1505. * Return value:
  1506. * TRUE on success
  1507. * Called by:
  1508. * ClxEvent
  1509. --*/
  1510. BOOL RClx_SendEvent(PCLXINFO pClx, CLXEVENT Event, DWORD dwParam)
  1511. {
  1512. BOOL rv = FALSE;
  1513. if (Event == CLX_EVENT_DISCONNECT)
  1514. {
  1515. pClx->alive = FALSE;
  1516. RClx_Disconnect(pClx);
  1517. }
  1518. if (Event == CLX_EVENT_CONNECT)
  1519. {
  1520. RCLXFEEDPROLOG FeedProlog;
  1521. pClx->alive = TRUE;
  1522. FeedProlog.FeedType = FEED_CONNECT;
  1523. FeedProlog.HeadSize = 0;
  1524. FeedProlog.TailSize = 0;
  1525. rv = RClx_SendBuffer(pClx->hSocket,
  1526. &FeedProlog,
  1527. sizeof(FeedProlog));
  1528. }
  1529. if (Event == CLX_EVENT_LOGON)
  1530. {
  1531. RCLXFEEDPROLOG FeedProlog;
  1532. UINT32 uSessionID = dwParam;
  1533. pClx->alive = TRUE;
  1534. FeedProlog.FeedType = FEED_LOGON;
  1535. FeedProlog.HeadSize = sizeof(uSessionID);
  1536. FeedProlog.TailSize = 0;
  1537. rv = RClx_SendBuffer(pClx->hSocket,
  1538. &FeedProlog,
  1539. sizeof(FeedProlog));
  1540. rv = RClx_SendBuffer(pClx->hSocket,
  1541. &uSessionID,
  1542. sizeof(uSessionID));
  1543. }
  1544. return rv;
  1545. }
  1546. /*++
  1547. * Function:
  1548. * RClx_SendClipbaord
  1549. * Description:
  1550. * Sends the current clipbaord content to the test controller
  1551. * Win32/Win16/WinCE
  1552. * Arguments:
  1553. * pClx - context
  1554. * uiFormat - desired clipboard format
  1555. * nSize - size of the data
  1556. * pClipboard - the clipboard data
  1557. * Return value:
  1558. * TRUE on success
  1559. * Called by:
  1560. * _ClxWndProc on WM_CLIPBOARD message
  1561. --*/
  1562. BOOL
  1563. RClx_SendClipboard(
  1564. PCLXINFO pClx,
  1565. UINT uiFormat,
  1566. UINT32 nSize,
  1567. VOID HUGEMOD *pClipboard)
  1568. {
  1569. BOOL rv = FALSE;
  1570. RCLXFEEDPROLOG FeedProlog;
  1571. RCLXCLIPBOARDFEED RClxClipboard;
  1572. ASSERT(pClx);
  1573. // if nSize == 0, then pClipboard == 0
  1574. ASSERT((nSize && pClipboard) || (!nSize && !pClipboard));
  1575. RClxClipboard.uiFormat = uiFormat;
  1576. RClxClipboard.nClipBoardSize = nSize;
  1577. FeedProlog.FeedType = FEED_CLIPBOARD;
  1578. FeedProlog.HeadSize = sizeof(RClxClipboard);
  1579. FeedProlog.TailSize = nSize;
  1580. rv = RClx_SendBuffer(pClx->hSocket,
  1581. &FeedProlog,
  1582. sizeof(FeedProlog));
  1583. if (!rv)
  1584. goto exitpt;
  1585. TRACE((INFO_MESSAGE,
  1586. TEXT("Sending the clipboard, FormatID=%d, Size=%ld\n"),
  1587. uiFormat, nSize));
  1588. rv = RClx_SendBuffer(pClx->hSocket,
  1589. &RClxClipboard,
  1590. sizeof(RClxClipboard));
  1591. if (!rv)
  1592. goto exitpt;
  1593. if (pClipboard)
  1594. rv = RClx_SendBuffer(pClx->hSocket,
  1595. pClipboard,
  1596. nSize);
  1597. exitpt:
  1598. return rv;
  1599. }
  1600. /*++
  1601. * Function:
  1602. * RClx_SendTextOut
  1603. * Description:
  1604. * Sends text out order to the smclient in RCLX mode
  1605. * Win32/Win16/WinCE
  1606. * Arguments:
  1607. * pClx - context
  1608. * pText - unicode string
  1609. * textLength - the string length
  1610. * Return value:
  1611. * TRUE on success
  1612. * Called by:
  1613. * ClxTextOut
  1614. --*/
  1615. BOOL
  1616. RClx_SendTextOut(PCLXINFO pClx, PVOID pText, INT textLength)
  1617. {
  1618. BOOL rv = FALSE;
  1619. RCLXFEEDPROLOG FeedProlog;
  1620. RCLXTEXTFEED FeedText;
  1621. UINT16 *szString;
  1622. ASSERT(pClx);
  1623. if (!pText || !textLength)
  1624. goto exitpt;
  1625. FeedProlog.FeedType = FEED_TEXTOUT;
  1626. FeedProlog.HeadSize = sizeof(FeedText);
  1627. FeedProlog.TailSize = (textLength + 1) * sizeof(UINT16);
  1628. szString = _alloca((textLength + 1) * sizeof(UINT16));
  1629. if (!szString)
  1630. goto exitpt;
  1631. memcpy(szString, pText, textLength * sizeof(UINT16));
  1632. szString[textLength] = 0;
  1633. rv = RClx_SendBuffer(pClx->hSocket,
  1634. &FeedProlog,
  1635. sizeof(FeedProlog));
  1636. if (!rv)
  1637. goto exitpt;
  1638. rv = RClx_SendBuffer(pClx->hSocket,
  1639. &FeedText,
  1640. sizeof(FeedText));
  1641. if (!rv)
  1642. goto exitpt;
  1643. rv = RClx_SendBuffer(pClx->hSocket,
  1644. szString,
  1645. FeedProlog.TailSize);
  1646. exitpt:
  1647. return rv;
  1648. }
  1649. /*++
  1650. * Function:
  1651. * RClx_SendBitmap
  1652. * Description:
  1653. * Sends a bitmap to the TestController
  1654. * Win32/Win16/WinCE
  1655. * Arguments:
  1656. * pClx - context
  1657. * cxSize - bitmap width
  1658. * cySize - bitmap height
  1659. * pBuffer - pointer to bitmap bits
  1660. * nBmiSize- BitmapInfo length
  1661. * pBmi - pointer to BITMAPINFO
  1662. * Return value:
  1663. * TRUE on success
  1664. * Called by:
  1665. * ClxBitmap
  1666. --*/
  1667. BOOL RClx_SendBitmap(
  1668. PCLXINFO pClx,
  1669. UINT cxSize,
  1670. UINT cySize,
  1671. PVOID pBuffer,
  1672. UINT nBmiSize,
  1673. PVOID pBmi)
  1674. {
  1675. BOOL rv = FALSE;
  1676. RCLXFEEDPROLOG FeedProlog;
  1677. RCLXBITMAPFEED FeedBitmap;
  1678. UINT nExtraBmi;
  1679. UINT nBmpSize;
  1680. BYTE *pLocalBits;
  1681. ASSERT(pClx);
  1682. ASSERT(pClx->hSocket != INVALID_SOCKET);
  1683. if (nBmiSize > sizeof(FeedBitmap.BitmapInfo))
  1684. {
  1685. TRACE((WARNING_MESSAGE,
  1686. TEXT("BitmapInfo size larger than expected. Ignoring\n")));
  1687. goto exitpt;
  1688. }
  1689. // Get bitmap size
  1690. if (!nBmiSize)
  1691. {
  1692. nBmpSize = (cxSize * cySize ) >> 3;
  1693. } else {
  1694. nBmpSize = (UINT)(((PBITMAPINFO)pBmi)->bmiHeader.biSizeImage);
  1695. if (!nBmpSize)
  1696. nBmpSize = (cxSize * cySize *
  1697. ((PBITMAPINFO)pBmi)->bmiHeader.biBitCount) >> 3;
  1698. }
  1699. pLocalBits = _alloca(nBmpSize);
  1700. if (!pLocalBits)
  1701. goto exitpt;
  1702. memcpy(pLocalBits, pBuffer, nBmpSize);
  1703. if (!nBmiSize)
  1704. {
  1705. // this is glyph, strip it !
  1706. _StripGlyph(pLocalBits, &cxSize, cySize);
  1707. nBmpSize = (cxSize * cySize ) >> 3;
  1708. }
  1709. // Prepare the prolog
  1710. FeedProlog.FeedType = FEED_BITMAP;
  1711. nExtraBmi = sizeof(FeedBitmap.BitmapInfo) - nBmiSize;
  1712. FeedProlog.HeadSize = sizeof(FeedBitmap) - nExtraBmi;
  1713. FeedProlog.TailSize = nBmpSize;
  1714. FeedBitmap.bmpsize = nBmpSize;
  1715. FeedBitmap.bmisize = nBmiSize;
  1716. FeedBitmap.xSize = cxSize;
  1717. FeedBitmap.ySize = cySize;
  1718. memcpy(&FeedBitmap.BitmapInfo,
  1719. pBmi,
  1720. sizeof(FeedBitmap.BitmapInfo) - nExtraBmi);
  1721. if (!RClx_SendBuffer(pClx->hSocket,
  1722. &FeedProlog,
  1723. sizeof(FeedProlog)))
  1724. {
  1725. TRACE((ERROR_MESSAGE,
  1726. TEXT("FEED_BITMAP:Can't send the prolog. WSAGetLastError=%d\n"),
  1727. WSAGetLastError()));
  1728. goto exitpt;
  1729. }
  1730. if (!RClx_SendBuffer(pClx->hSocket,
  1731. &FeedBitmap,
  1732. FeedProlog.HeadSize))
  1733. {
  1734. TRACE((ERROR_MESSAGE,
  1735. TEXT("FEED_BITMAP:Can't send the header.\n")));
  1736. goto exitpt;
  1737. }
  1738. if (!RClx_SendBuffer(pClx->hSocket, pLocalBits, FeedProlog.TailSize))
  1739. {
  1740. TRACE((ERROR_MESSAGE,
  1741. TEXT("FEED_BITMAP:Can't send the bits.\n")));
  1742. goto exitpt;
  1743. }
  1744. rv = TRUE;
  1745. exitpt:
  1746. return rv;
  1747. }
  1748. /*++
  1749. * Function:
  1750. * _ClxWndProc
  1751. * Description:
  1752. * Dispatche messages procedure. Dispatches WM_TIMER and
  1753. * WM_WSOCK - socket message. WM_TIMER drives _OnBackground
  1754. * and connection retrys
  1755. * Win32/Win16/WinCE
  1756. * Arguments:
  1757. * hwnd - window handle, same as g_hWindow
  1758. * uiMessage - message Id
  1759. * wParam - word param
  1760. * lParam - long param
  1761. * Return value:
  1762. * LRESULT - standard for window procs
  1763. --*/
  1764. LRESULT CALLBACK LOADDS _ClxWndProc( HWND hwnd,
  1765. UINT uiMessage,
  1766. WPARAM wParam,
  1767. LPARAM lParam)
  1768. {
  1769. SOCKET hSocket;
  1770. PCLXINFO pClx = g_pClx;
  1771. switch (uiMessage)
  1772. {
  1773. case WM_WSOCK:
  1774. if (!pClx)
  1775. {
  1776. TRACE((WARNING_MESSAGE,
  1777. TEXT("Winsock message before context initialization\n")));
  1778. goto exitpt;
  1779. }
  1780. hSocket = (SOCKET)wParam;
  1781. if (hSocket != pClx->hSocket)
  1782. {
  1783. TRACE((WARNING_MESSAGE,
  1784. TEXT("Notification for unknown socket\n")));
  1785. goto exitpt;
  1786. }
  1787. if (WSAGETSELECTERROR(lParam))
  1788. {
  1789. TRACE((WARNING_MESSAGE,
  1790. TEXT("Winsock error: %d\n"), WSAGETSELECTERROR(lParam)));
  1791. RClx_Disconnect(pClx);
  1792. goto exitpt;
  1793. }
  1794. if (WSAGETSELECTEVENT(lParam) == FD_CLOSE)
  1795. {
  1796. TRACE((INFO_MESSAGE,
  1797. TEXT("Connection to the test server lost\n")));
  1798. RClx_Disconnect(pClx);
  1799. } else if (WSAGETSELECTEVENT(lParam) == FD_READ)
  1800. {
  1801. if (!RClx_ReadRequest(pClx) &&
  1802. WSAGetLastError() != WSAEWOULDBLOCK)
  1803. {
  1804. TRACE((WARNING_MESSAGE,
  1805. TEXT("Socket read error: %d\n"), WSAGetLastError()));
  1806. RClx_Disconnect(pClx);
  1807. }
  1808. } else {
  1809. TRACE((WARNING_MESSAGE,
  1810. TEXT("Unexpected winsock notification #%d\n"),
  1811. WSAGETSELECTEVENT(lParam)));
  1812. goto exitpt;
  1813. }
  1814. break;
  1815. case WM_TIMER: // Start connection or background process
  1816. {
  1817. BOOL bRunRdp = FALSE;
  1818. HWND hConBtn, hServerBox;
  1819. #ifndef OS_WINCE
  1820. // no resolution box in CE
  1821. HWND hResolutionBox;
  1822. #endif
  1823. CHAR szResSelect[20];
  1824. if (!pClx)
  1825. {
  1826. TRACE((WARNING_MESSAGE,
  1827. TEXT("Timer message before context initialization\n")));
  1828. goto exitpt;
  1829. }
  1830. if (g_uiBackgroundTimer == (UINT_PTR)wParam)
  1831. // This is our background thread
  1832. {
  1833. _OnBackground(pClx);
  1834. goto exitpt;
  1835. }
  1836. if (!g_nMyReconId && !pClx->hwndDialog)
  1837. {
  1838. pClx->hwndDialog = _FindTopWindow(NULL,
  1839. g_strClientCaption,
  1840. g_hRDPInst);
  1841. goto check_timer;
  1842. }
  1843. if (!g_nMyReconId && pClx->hwndDialog &&
  1844. !GetDlgItem(pClx->hwndDialog, UI_IDC_CONNECT))
  1845. {
  1846. TRACE((INFO_MESSAGE, TEXT("No dialog box yet. Waiting...\n")));
  1847. goto check_timer;
  1848. }
  1849. if (pClx->alive && pClx->hSocket == INVALID_SOCKET)
  1850. {
  1851. TRACE((INFO_MESSAGE,
  1852. TEXT("Client is alive, no socket to the test server\n")));
  1853. //_AttemptToCloseTheClient();
  1854. goto exitpt;
  1855. }
  1856. // Check if we are connected
  1857. if (pClx->hSocket == INVALID_SOCKET && (!RClx_Connect(pClx)))
  1858. goto check_timer;
  1859. // We are connected, send the client info
  1860. if (!pClx->bClientInfoSent)
  1861. RClx_SendClientInfo(pClx);
  1862. // if we are reconnecting we don't have UI to set params
  1863. if (g_nMyReconId)
  1864. break;
  1865. // Check if connect dialog is OK
  1866. if (!pClx->hwndDialog)
  1867. goto check_timer;
  1868. if (!strlen(pClx->RClxInfo.szHydraServer))
  1869. {
  1870. TRACE((INFO_MESSAGE,
  1871. TEXT("Connect info is not received yet\n")));
  1872. goto check_timer;
  1873. }
  1874. // set something in server listbox, to enable connect button
  1875. {
  1876. HWND hwndCombo = GetDlgItem(pClx->hwndDialog, UI_IDC_SERVER);
  1877. SetDlgItemText(pClx->hwndDialog, UI_IDC_SERVER, TEXT("vladimis"));
  1878. #ifdef OS_WIN32
  1879. PostMessage(pClx->hwndDialog,
  1880. WM_COMMAND,
  1881. MAKEWPARAM(UI_IDC_SERVER, CBN_EDITCHANGE),
  1882. (LPARAM)hwndCombo);
  1883. #endif
  1884. #ifdef OS_WIN16
  1885. PostMessage(pClx->hwndDialog,
  1886. WM_COMMAND,
  1887. UI_IDC_SERVER,
  1888. MAKELONG(hwndCombo, CBN_EDITCHANGE));
  1889. #endif
  1890. }
  1891. // Check the connect button state
  1892. hConBtn = GetDlgItem(pClx->hwndDialog, UI_IDC_CONNECT);
  1893. if (!hConBtn)
  1894. {
  1895. TRACE((WARNING_MESSAGE,
  1896. TEXT("Can't get Connect button\n")));
  1897. goto check_timer;
  1898. }
  1899. if (!IsWindowEnabled(hConBtn))
  1900. {
  1901. TRACE((INFO_MESSAGE,
  1902. TEXT("Connect button is not enabled yet\n")));
  1903. goto check_timer;
  1904. }
  1905. if (
  1906. // Check for valid controls
  1907. (hServerBox = GetDlgItem(pClx->hwndDialog, UI_IDC_SERVER))
  1908. #ifndef OS_WINCE
  1909. // no resolution box in WinCE
  1910. &&
  1911. (hResolutionBox = GetDlgItem(pClx->hwndDialog, UI_IDC_RESOLUTION))
  1912. #endif // !OS_WINCE
  1913. )
  1914. {
  1915. TRACE((INFO_MESSAGE,
  1916. TEXT("The client is ready to launch.\n")));
  1917. } else
  1918. goto check_timer;
  1919. bRunRdp = TRUE;
  1920. check_timer:
  1921. if (!bRunRdp)
  1922. {
  1923. TRACE((INFO_MESSAGE,
  1924. TEXT("Can't start the client yet. Waiting\n")));
  1925. if (!pClx->uiReconnectTimer)
  1926. pClx->uiReconnectTimer = SetTimer(hwnd, RCLX_RECONNECT_TIMERID,
  1927. RCLX_RECONNECTELAPSETIME, NULL);
  1928. if (!pClx->uiReconnectTimer)
  1929. {
  1930. TRACE((WARNING_MESSAGE,
  1931. TEXT("Can't create timer. Start timer simulation\n")));
  1932. PostMessage(hwnd, WM_TIMER, 0, 0);
  1933. }
  1934. goto exitpt;
  1935. } else {
  1936. if (pClx->uiReconnectTimer)
  1937. {
  1938. KillTimer(g_hWindow, pClx->uiReconnectTimer);
  1939. pClx->uiReconnectTimer = 0;
  1940. }
  1941. }
  1942. // Check that we have clear view for launch
  1943. // no error boxes laying arround
  1944. if (_GarbageCollecting(pClx, TRUE))
  1945. goto exitpt;
  1946. #ifdef UNICODE
  1947. TRACE((INFO_MESSAGE,
  1948. TEXT("Trying to connect to Hydra server: %S\n"),
  1949. pClx->RClxInfo.szHydraServer));
  1950. #else
  1951. TRACE((INFO_MESSAGE,
  1952. TEXT("Trying to connect to Hydra server: %s\n"),
  1953. pClx->RClxInfo.szHydraServer));
  1954. #endif // UNICODE
  1955. // Set server name
  1956. #ifdef UNICODE
  1957. _CLX_SetDlgItemTextA
  1958. #else // !UNICODE
  1959. SetDlgItemText
  1960. #endif // !UNICODE
  1961. (pClx->hwndDialog, UI_IDC_SERVER, pClx->RClxInfo.szHydraServer);
  1962. // Set the resolution
  1963. _snprintf(szResSelect, sizeof(szResSelect), "%dx%d",
  1964. pClx->RClxInfo.xResolution,
  1965. pClx->RClxInfo.yResolution);
  1966. #ifndef OS_WINCE
  1967. // no resolution box
  1968. SendMessage(hResolutionBox, CB_SELECTSTRING, 0, (LPARAM)szResSelect);
  1969. #endif // !OS_WINCE
  1970. // set the low speed option
  1971. CheckDlgButton(pClx->hwndDialog,
  1972. UI_IDC_CONNECTION,
  1973. (pClx->RClxInfo.bLowSpeed)?BST_CHECKED:BST_UNCHECKED
  1974. );
  1975. // set the persistent cache option
  1976. CheckDlgButton(pClx->hwndDialog,
  1977. UI_IDC_BITMAP_PERSISTENCE,
  1978. (pClx->RClxInfo.bPersistentCache)?BST_CHECKED
  1979. :BST_UNCHECKED
  1980. );
  1981. // Now connect
  1982. PostMessage(pClx->hwndDialog, WM_COMMAND, UI_IDC_CONNECT, 0);
  1983. }
  1984. break;
  1985. case WM_CLIPBOARD:
  1986. {
  1987. HGLOBAL ghClipboard = NULL;
  1988. HGLOBAL ghNewData = NULL;
  1989. BOOL bOpened = FALSE;
  1990. BOOL bRetry = TRUE;
  1991. VOID HUGEMOD *pClipboard = NULL;
  1992. UINT32 nSize = 0;
  1993. UINT uiFormat = 0;
  1994. BOOL bReentered;
  1995. #ifndef OS_WIN32
  1996. pClx->bClipboardReenter++;
  1997. bReentered = pClx->bClipboardReenter != 0;
  1998. #else
  1999. bReentered = InterlockedIncrement(&pClx->bClipboardReenter) != 0;
  2000. #endif // OS_WIN32
  2001. if (bReentered)
  2002. {
  2003. TRACE((WARNING_MESSAGE, TEXT("WM_CLIPBOARD reentered\n")));
  2004. bRetry = FALSE;
  2005. goto clpcleanup;
  2006. }
  2007. // lParam contains the desired format
  2008. uiFormat = (UINT)lParam;
  2009. // WinCE version doesn't support clipboard
  2010. #ifndef OS_WINCE
  2011. if (!OpenClipboard(hwnd))
  2012. {
  2013. TRACE((ERROR_MESSAGE, TEXT("Can't open the clipboard. retrying\n")));
  2014. goto clpcleanup;
  2015. }
  2016. bOpened = TRUE;
  2017. // if uiFormat is zero then return empty clipbrd body
  2018. // with the first available format
  2019. if (!uiFormat)
  2020. {
  2021. uiFormat = EnumClipboardFormats(uiFormat);
  2022. TRACE((INFO_MESSAGE,
  2023. TEXT("Responging on format request. FormatID=%d\n"),
  2024. uiFormat));
  2025. goto send_clipboard;
  2026. }
  2027. ghClipboard = GetClipboardData((UINT)uiFormat);
  2028. if (!ghClipboard)
  2029. {
  2030. TRACE((WARNING_MESSAGE, TEXT("Clipboard is empty.\n")));
  2031. } else {
  2032. Clp_GetClipboardData(uiFormat,
  2033. ghClipboard,
  2034. &nSize,
  2035. &ghNewData);
  2036. if (ghNewData)
  2037. ghClipboard = ghNewData;
  2038. pClipboard = GlobalLock(ghClipboard);
  2039. if (!pClipboard)
  2040. {
  2041. TRACE((ERROR_MESSAGE,
  2042. TEXT("Can't lock the clipboard. retrying\n")));
  2043. goto clpcleanup;
  2044. }
  2045. }
  2046. send_clipboard:
  2047. #else // !OS_WINCE
  2048. TRACE((WARNING_MESSAGE, TEXT("WinCE: clipboard not supported\n")));
  2049. #endif // !OS_WINCE
  2050. if (!RClx_SendClipboard(pClx, uiFormat, nSize, pClipboard))
  2051. {
  2052. TRACE((ERROR_MESSAGE, TEXT("Can't send the clipboard\n")));
  2053. bRetry = FALSE;
  2054. goto clpcleanup;
  2055. }
  2056. bRetry = FALSE;
  2057. clpcleanup:
  2058. #ifndef OS_WINCE
  2059. if (pClipboard)
  2060. GlobalUnlock(ghClipboard);
  2061. if (bOpened)
  2062. CloseClipboard();
  2063. if (ghNewData)
  2064. GlobalFree(ghNewData);
  2065. #endif // !OS_WINCE
  2066. #ifndef OS_WIN32
  2067. pClx->bClipboardReenter--;
  2068. #else
  2069. InterlockedDecrement(&pClx->bClipboardReenter);
  2070. #endif // OS_WIN32
  2071. if (bRetry)
  2072. // Retry to send the clipboard
  2073. PostMessage(hwnd, WM_CLIPBOARD, 0, lParam);
  2074. }
  2075. break;
  2076. case WM_CLOSE:
  2077. if (!DestroyWindow(hwnd))
  2078. {
  2079. TRACE((ERROR_MESSAGE,
  2080. TEXT("Can't destroy window. GetLastError: %d\n"),
  2081. _CLXWINDOW_CLASS,
  2082. GetLastError()));
  2083. }
  2084. break;
  2085. default:
  2086. return DefWindowProc(hwnd, uiMessage, wParam, lParam);
  2087. }
  2088. exitpt:
  2089. return 0;
  2090. }
  2091. /*++
  2092. * Function:
  2093. * RClx_CreateWindow
  2094. * Description:
  2095. * Creates g_hWindow for dispatching winsocket and timer
  2096. * messages
  2097. * Win32/Win16/WinCE
  2098. * Arguments:
  2099. * hInstance - Dll instance handle
  2100. * Called by:
  2101. * ClxInitialize
  2102. --*/
  2103. VOID RClx_CreateWindow(HINSTANCE hInstance)
  2104. {
  2105. WNDCLASS wc;
  2106. #ifdef OS_WIN32
  2107. DWORD dwLastErr;
  2108. #endif
  2109. memset(&wc, 0, sizeof(wc));
  2110. wc.lpfnWndProc = _ClxWndProc;
  2111. wc.hInstance = hInstance;
  2112. wc.lpszClassName = TEXT(_CLXWINDOW_CLASS);
  2113. if (!RegisterClass (&wc)
  2114. #ifdef OS_WIN32
  2115. &&
  2116. (dwLastErr = GetLastError()) &&
  2117. dwLastErr != ERROR_CLASS_ALREADY_EXISTS
  2118. #endif // OS_WIN32
  2119. )
  2120. {
  2121. TRACE((WARNING_MESSAGE,
  2122. TEXT("Can't register class. GetLastError=%d\n"),
  2123. GetLastError()));
  2124. goto exitpt;
  2125. }
  2126. g_hWindow = CreateWindow(
  2127. TEXT(_CLXWINDOW_CLASS),
  2128. NULL, // Window name
  2129. 0, // dwStyle
  2130. 0, // x
  2131. 0, // y
  2132. 0, // nWidth
  2133. 0, // nHeight
  2134. NULL, // hWndParent
  2135. NULL, // hMenu
  2136. hInstance,
  2137. NULL); // lpParam
  2138. if (!g_hWindow)
  2139. {
  2140. TRACE((WARNING_MESSAGE,
  2141. TEXT("Can't create window to handle socket messages\n")));
  2142. goto exitpt;
  2143. }
  2144. g_uiBackgroundTimer = SetTimer(g_hWindow,
  2145. RCLX_BACKGNDTIMERID,
  2146. RCLX_TIMERELAPSETIME,
  2147. NULL);
  2148. exitpt:
  2149. ;
  2150. }
  2151. /*++
  2152. * Function:
  2153. * RClx_DestroyWindow
  2154. * Description:
  2155. * Destroys g_hWindow created in RClx_CreateWindow
  2156. * Win32/Win16/WinCE
  2157. * Called by:
  2158. * ClxTerminate
  2159. --*/
  2160. VOID RClx_DestroyWindow(VOID)
  2161. {
  2162. if (g_hWindow)
  2163. {
  2164. if (g_uiBackgroundTimer)
  2165. {
  2166. KillTimer(g_hWindow, g_uiBackgroundTimer);
  2167. g_uiBackgroundTimer = 0;
  2168. }
  2169. PostMessage(g_hWindow, WM_CLOSE, 0, 0);
  2170. if (!UnregisterClass(TEXT(_CLXWINDOW_CLASS), g_hInstance))
  2171. {
  2172. TRACE((WARNING_MESSAGE,
  2173. TEXT("Can't unregister class: %s. GetLastError: %d\n"),
  2174. _CLXWINDOW_CLASS,
  2175. GetLastError()));
  2176. }
  2177. g_hWindow = NULL;
  2178. }
  2179. }
  2180. /*++
  2181. * Function:
  2182. * RClx_ReadRequest
  2183. * Description:
  2184. * CLXINFO contains a buffer for incoming requests
  2185. * this function trys to receive it all. If the socket blocks
  2186. * the function exits with OK and next time FD_READ is received will
  2187. * be called again. If a whole request is received it calls
  2188. * RClx_ProcessRequest
  2189. * Win32/Win16/WinCE
  2190. * Arguments:
  2191. * pClx - the context
  2192. * Return value:
  2193. * TRUE if reading doesn't fail
  2194. * Called by:
  2195. * _ClxWndProc on FD_READ event
  2196. --*/
  2197. BOOL RClx_ReadRequest(PCLXINFO pClx)
  2198. {
  2199. INT recvres;
  2200. INT nErrorCode = 0;
  2201. BYTE HUGEMOD *pRecv = NULL;
  2202. UINT32 nRecv = 0;
  2203. BYTE TempBuff[256];
  2204. ASSERT(pClx);
  2205. ASSERT(pClx->hSocket != INVALID_SOCKET);
  2206. do {
  2207. if (!pClx->bPrologReceived)
  2208. {
  2209. pRecv = (BYTE HUGEMOD *)&(pClx->RClxReqProlog)
  2210. + pClx->nBytesReceived;
  2211. nRecv = sizeof(pClx->RClxReqProlog) - pClx->nBytesReceived;
  2212. #ifndef OS_WINCE
  2213. recvres = recv(pClx->hSocket,
  2214. pRecv,
  2215. (int)nRecv,
  2216. 0);
  2217. nErrorCode = WSAGetLastError();
  2218. #else // OS_WINCE
  2219. recvres = AsyncRecv(pClx->hSocket,
  2220. pRecv,
  2221. nRecv,
  2222. &nErrorCode);
  2223. #endif // OS_WINCE
  2224. if (recvres != SOCKET_ERROR)
  2225. pClx->nBytesReceived += recvres;
  2226. else
  2227. if (nErrorCode != WSAEWOULDBLOCK)
  2228. TRACE((ERROR_MESSAGE, TEXT("recv error: %d, request for 0x%lx bytes\n"),
  2229. nErrorCode,
  2230. nRecv
  2231. ));
  2232. if (pClx->nBytesReceived == sizeof(pClx->RClxReqProlog))
  2233. {
  2234. UINT32 nReqSize = pClx->RClxReqProlog.ReqSize;
  2235. pClx->nBytesReceived = 0;
  2236. pClx->bPrologReceived = TRUE;
  2237. if (nReqSize)
  2238. // If request body is empty, don't allocate
  2239. {
  2240. if (!pClx->pRequest)
  2241. retry_alloc:
  2242. {
  2243. pClx->pRequest =
  2244. _CLXALLOC(nReqSize);
  2245. if (pClx->pRequest)
  2246. pClx->nReqAllocSize = nReqSize;
  2247. else
  2248. pClx->nReqAllocSize = 0;
  2249. }
  2250. else if (nReqSize > pClx->nReqAllocSize)
  2251. {
  2252. pClx->pRequest =
  2253. _CLXREALLOC(pClx->pRequest,
  2254. nReqSize);
  2255. if (pClx->pRequest)
  2256. pClx->nReqAllocSize = nReqSize;
  2257. else
  2258. {
  2259. pClx->nReqAllocSize = 0;
  2260. goto retry_alloc;
  2261. }
  2262. }
  2263. if (!pClx->pRequest)
  2264. {
  2265. TRACE((WARNING_MESSAGE,
  2266. TEXT("Can't alloc 0x%lx bytes for receiving a request. GetLastError=%d. Skipping\n"),
  2267. nReqSize,
  2268. GetLastError()));
  2269. }
  2270. }
  2271. }
  2272. } else {
  2273. if (pClx->nBytesReceived == pClx->RClxReqProlog.ReqSize)
  2274. goto process_req;
  2275. if (pClx->pRequest)
  2276. {
  2277. pRecv = (BYTE HUGEMOD *)pClx->pRequest
  2278. + pClx->nBytesReceived;
  2279. nRecv = pClx->RClxReqProlog.ReqSize - pClx->nBytesReceived;
  2280. } else {
  2281. // point to a temp buffer if pReques is not allocated
  2282. pRecv = TempBuff;
  2283. nRecv = sizeof(TempBuff);
  2284. }
  2285. #ifdef OS_WIN16
  2286. // WFW has problems with receiving big buffers
  2287. if (nRecv >= 0x1000)
  2288. nRecv = 0x1000;
  2289. #endif // OS_WIN16
  2290. #ifndef OS_WINCE
  2291. recvres = recv(pClx->hSocket,
  2292. pRecv,
  2293. (int)nRecv,
  2294. 0);
  2295. nErrorCode = WSAGetLastError();
  2296. #else // OS_WINCE
  2297. recvres = AsyncRecv(pClx->hSocket,
  2298. pRecv,
  2299. nRecv,
  2300. &nErrorCode);
  2301. #endif // OS_WINCE
  2302. if (recvres != SOCKET_ERROR)
  2303. {
  2304. pClx->nBytesReceived += recvres;
  2305. } else {
  2306. if (nErrorCode != WSAEWOULDBLOCK)
  2307. {
  2308. TRACE((ERROR_MESSAGE,
  2309. TEXT("recv error: %d, request for 0x%lx bytes\n"),
  2310. nErrorCode,
  2311. nRecv
  2312. ));
  2313. TRACE((ERROR_MESSAGE,
  2314. TEXT("ReqProlog was received. Type=%d, Size=%d\n"),
  2315. pClx->RClxReqProlog.ReqType,
  2316. pClx->RClxReqProlog.ReqSize
  2317. ));
  2318. }
  2319. }
  2320. process_req:
  2321. if (pClx->nBytesReceived == pClx->RClxReqProlog.ReqSize)
  2322. {
  2323. pClx->nBytesReceived = 0;
  2324. pClx->bPrologReceived = FALSE;
  2325. RClx_ProcessRequest(pClx);
  2326. }
  2327. }
  2328. } while ((recvres != 0 || nRecv == 0) && // recvres will be 0 if nRecv is 0
  2329. recvres != SOCKET_ERROR);
  2330. // return FALSE if error is occured
  2331. if (!recvres)
  2332. return FALSE; // connection was gracefully closed
  2333. if (recvres == SOCKET_ERROR)
  2334. {
  2335. if (nErrorCode == WSAEWOULDBLOCK)
  2336. return TRUE; // the call will block, but ok
  2337. else
  2338. return FALSE; // other SOCKET_ERROR
  2339. }
  2340. return TRUE; // it is ok
  2341. }
  2342. /*++
  2343. * Function:
  2344. * RClx_DataArrived
  2345. * Description:
  2346. * Processes request for data
  2347. * Win32/Win16/WinCE
  2348. * Arguments:
  2349. * pClx - context
  2350. * pRClxData - the request
  2351. * Called by:
  2352. * RClx_ProcessRequest
  2353. --*/
  2354. VOID
  2355. RClx_DataArrived(PCLXINFO pClx, PRCLXDATA pRClxData)
  2356. {
  2357. ASSERT(pRClxData);
  2358. switch(pRClxData->uiType)
  2359. {
  2360. case DATA_BITMAP:
  2361. {
  2362. PREQBITMAP pReqBitmap = (PREQBITMAP)pRClxData->Data;
  2363. RCLXDATA Response;
  2364. RCLXFEEDPROLOG RespProlog;
  2365. HANDLE hDIB = NULL;
  2366. DWORD dwDIBSize = 0;
  2367. TRACE((INFO_MESSAGE,
  2368. TEXT("REQDATA_BITMAP arrived\n")));
  2369. if (pRClxData->uiSize != sizeof(*pReqBitmap))
  2370. ASSERT(0);
  2371. // process differently on WINCE (no shadow bitmap)
  2372. //
  2373. if (pClx->hdcShadowBitmap)
  2374. _GetDIBFromBitmap(pClx->hdcShadowBitmap,
  2375. pClx->hShadowBitmap,
  2376. &hDIB,
  2377. (INT)pReqBitmap->left,
  2378. (INT)pReqBitmap->top,
  2379. (INT)pReqBitmap->right,
  2380. (INT)pReqBitmap->bottom);
  2381. else {
  2382. TRACE((WARNING_MESSAGE, TEXT("Shadow bitmap is NULL\n")));
  2383. }
  2384. if (!hDIB)
  2385. dwDIBSize = 0;
  2386. else
  2387. dwDIBSize = (DWORD)GlobalSize(hDIB);
  2388. RespProlog.FeedType = FEED_DATA;
  2389. RespProlog.HeadSize = sizeof(Response) + dwDIBSize;
  2390. RespProlog.TailSize = 0;
  2391. Response.uiType = DATA_BITMAP;
  2392. Response.uiSize = dwDIBSize;
  2393. RClx_SendBuffer(pClx->hSocket, &RespProlog, sizeof(RespProlog));
  2394. RClx_SendBuffer(pClx->hSocket, &Response, sizeof(Response));
  2395. if (hDIB)
  2396. {
  2397. LPVOID pDIB = GlobalLock(hDIB);
  2398. if (pDIB)
  2399. {
  2400. RClx_SendBuffer(pClx->hSocket, pDIB, dwDIBSize);
  2401. GlobalUnlock(hDIB);
  2402. }
  2403. GlobalFree(hDIB);
  2404. }
  2405. }
  2406. break;
  2407. case DATA_VC:
  2408. {
  2409. LPSTR szChannelName;
  2410. LPVOID pData;
  2411. DWORD dwSize;
  2412. szChannelName = (LPSTR)(pRClxData->Data);
  2413. pData = ((BYTE *)(pRClxData->Data)) + MAX_VCNAME_LEN;
  2414. dwSize = pRClxData->uiSize - MAX_VCNAME_LEN;
  2415. if (pRClxData->uiSize < MAX_VCNAME_LEN)
  2416. {
  2417. TRACE((ERROR_MESSAGE, TEXT("DATA_VC: uiSize too small\n")));
  2418. goto exitpt;
  2419. }
  2420. if (strlen(szChannelName) > MAX_VCNAME_LEN - 1)
  2421. {
  2422. TRACE((ERROR_MESSAGE, TEXT("DATA_VC: channel name too long\n")));
  2423. goto exitpt;
  2424. }
  2425. _CLXSendDataVC(szChannelName, pData, dwSize);
  2426. }
  2427. break;
  2428. default:
  2429. TRACE((WARNING_MESSAGE,
  2430. TEXT("Unknown data request type. Ignoring\n")));
  2431. }
  2432. exitpt:
  2433. ;
  2434. }
  2435. /*++
  2436. * Function:
  2437. * RClx_ProcessRequest
  2438. * Description:
  2439. * Dispatches a request received by RClx_ReadRequest
  2440. * Win32/Win16/WinCE
  2441. * Arguments:
  2442. * pClx - context
  2443. * Called by:
  2444. * RClx_ReadRequest
  2445. --*/
  2446. VOID RClx_ProcessRequest(PCLXINFO pClx)
  2447. {
  2448. PRCLXMSG pClxMsg;
  2449. DWORD ReqType;
  2450. HWND hContainer;
  2451. PRCLXREQPROLOG pReqProlog;
  2452. LPVOID pReq;
  2453. ASSERT(pClx);
  2454. pReqProlog = &(pClx->RClxReqProlog);
  2455. ASSERT(pReqProlog);
  2456. pReq = pClx->pRequest;
  2457. ReqType = pReqProlog->ReqType;
  2458. switch(ReqType)
  2459. {
  2460. case REQ_MESSAGE:
  2461. if (!pReq || pReqProlog->ReqSize != sizeof(*pClxMsg))
  2462. {
  2463. TRACE((WARNING_MESSAGE,
  2464. TEXT("REQ_MESSAGE with different size. Ignoring\n")));
  2465. goto exitpt;
  2466. }
  2467. pClxMsg = (PRCLXMSG)pReq;
  2468. if(!pClx->hwndInput)
  2469. {
  2470. hContainer = _FindWindow(pClx->hwndMain, TEXT(NAME_CONTAINERCLASS));
  2471. if (hContainer)
  2472. pClx->hwndInput = _FindWindow(hContainer, TEXT(NAME_INPUT));
  2473. else
  2474. pClx->hwndInput = NULL;
  2475. if (!pClx->hwndInput)
  2476. {
  2477. TRACE((WARNING_MESSAGE,
  2478. TEXT("Can't find input window.")
  2479. TEXT(" Discarding any user input\n" )));
  2480. goto exitpt;
  2481. }
  2482. }
  2483. SendMessage(pClx->hwndInput,
  2484. (UINT)pClxMsg->message,
  2485. (WPARAM)pClxMsg->wParam,
  2486. (LPARAM)pClxMsg->lParam);
  2487. break;
  2488. case REQ_CONNECTINFO:
  2489. if (!pReq || pReqProlog->ReqSize != sizeof(RCLXCONNECTINFO))
  2490. {
  2491. TRACE((WARNING_MESSAGE,
  2492. TEXT("REQ_CONNECTINFO with different size. Ignoring\n")));
  2493. goto exitpt;
  2494. }
  2495. TRACE((INFO_MESSAGE, TEXT("CONNECTINFO received\n")));
  2496. memcpy(&pClx->RClxInfo, pReq, sizeof(pClx->RClxInfo));
  2497. // Kick _ClxWndProc to connect
  2498. PostMessage(g_hWindow, WM_TIMER, 0, 0);
  2499. break;
  2500. case REQ_GETCLIPBOARD:
  2501. if (!pReq || pReqProlog->ReqSize != sizeof(RCLXCLIPBOARD))
  2502. {
  2503. TRACE((WARNING_MESSAGE,
  2504. TEXT("REQ_GETCLIPBOARD with different size. Ignoring\n")));
  2505. goto exitpt;
  2506. }
  2507. TRACE((INFO_MESSAGE, TEXT("REQ_GETCLIPBOARD received. FormatId=%d\n"),
  2508. ((PRCLXCLIPBOARD)pReq)->uiFormat
  2509. ));
  2510. // Kick _ClxWndProc to send our clipboard
  2511. PostMessage(g_hWindow, WM_CLIPBOARD, 0,
  2512. (LPARAM)((PRCLXCLIPBOARD)pReq)->uiFormat);
  2513. // lParam contains the required format
  2514. break;
  2515. case REQ_SETCLIPBOARD:
  2516. {
  2517. UINT32 nClipSize;
  2518. if (!pReq || pReqProlog->ReqSize < sizeof(RCLXCLIPBOARD))
  2519. {
  2520. TRACE((WARNING_MESSAGE,
  2521. TEXT("REQ_SETCLIPBOARD with wrong size. Ignoring\n")));
  2522. goto exitpt;
  2523. }
  2524. TRACE((INFO_MESSAGE, TEXT("REQ_SETCLIPBOARD received. FormatId=%d, Clipboard size = %d\n"),
  2525. ((PRCLXCLIPBOARD)pReq)->uiFormat,
  2526. pReqProlog->ReqSize - sizeof(UINT)
  2527. ));
  2528. nClipSize = pReqProlog->ReqSize - sizeof(((PRCLXCLIPBOARD)pReq)->uiFormat);
  2529. _SetClipboard(
  2530. (UINT)((PRCLXCLIPBOARD)pReq)->uiFormat,
  2531. ((PRCLXCLIPBOARD)pReq)->pNewClipboard,
  2532. nClipSize);
  2533. }
  2534. break;
  2535. case REQ_DATA:
  2536. {
  2537. PRCLXDATA pRClxData = (PRCLXDATA)pReq;
  2538. ASSERT(pRClxData);
  2539. if (pReqProlog->ReqSize != pRClxData->uiSize + (UINT32)sizeof(*pRClxData))
  2540. ASSERT(0);
  2541. RClx_DataArrived(pClx, pRClxData);
  2542. }
  2543. break;
  2544. default:
  2545. TRACE((WARNING_MESSAGE,
  2546. TEXT("Unknown request type. Ignoring\n")));
  2547. }
  2548. exitpt:
  2549. ;
  2550. }
  2551. /*++
  2552. * Function:
  2553. * _EnumWindowsProc
  2554. * Description:
  2555. * Used to find a specific window
  2556. * Win32/Win16/WinCE
  2557. * Arguments:
  2558. * hWnd - current enumerated window handle
  2559. * lParam - pointer to SEARCHWND passed from
  2560. * _FindTopWindow
  2561. * Return value:
  2562. * TRUE on success but window is not found
  2563. * FALSE if the window is found
  2564. * Called by:
  2565. * _FindTopWindow thru EnumWindows
  2566. --*/
  2567. BOOL CALLBACK LOADDS _EnumWindowsProc( HWND hWnd, LPARAM lParam )
  2568. {
  2569. TCHAR classname[128];
  2570. TCHAR caption[128];
  2571. BOOL rv = TRUE;
  2572. _CLXWINDOWOWNER hInst;
  2573. PSEARCHWND pSearch = (PSEARCHWND)lParam;
  2574. if (pSearch->szClassName &&
  2575. !GetClassName(hWnd, classname, sizeof(classname)/sizeof(TCHAR)))
  2576. {
  2577. goto exitpt;
  2578. }
  2579. if (pSearch->szCaption && !GetWindowText(hWnd, caption, sizeof(caption)/sizeof(TCHAR)))
  2580. {
  2581. goto exitpt;
  2582. }
  2583. #ifdef OS_WINCE
  2584. {
  2585. DWORD procId = 0;
  2586. GetWindowThreadProcessId(hWnd, &procId);
  2587. hInst = procId;
  2588. }
  2589. #else // !OS_WINCE
  2590. #ifdef _WIN64
  2591. hInst = (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE);
  2592. #else // !_WIN64
  2593. #ifdef OS_WIN32
  2594. hInst = (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE);
  2595. #endif // OS_WIN32
  2596. #endif // !OS_WINCE
  2597. #ifdef OS_WIN16
  2598. hInst = (HINSTANCE)GetWindowWord(hWnd, GWW_HINSTANCE);
  2599. #endif
  2600. #endif // _WIN64
  2601. if (
  2602. (!pSearch->szClassName || ! // Check for classname
  2603. _CLX_strcmp(classname, pSearch->szClassName))
  2604. &&
  2605. (!pSearch->szCaption || !
  2606. _CLX_strcmp(caption, pSearch->szCaption))
  2607. &&
  2608. hInst == pSearch->hInstance)
  2609. {
  2610. ((PSEARCHWND)lParam)->hWnd = hWnd;
  2611. rv = FALSE;
  2612. }
  2613. exitpt:
  2614. return rv;
  2615. }
  2616. /*++
  2617. * Function:
  2618. * _FindTopWindow
  2619. * Description:
  2620. * Find specific window by classname and/or caption and/or process Id
  2621. * Win32/Win16/WinCE
  2622. * Arguments:
  2623. * classname - class name to search for, NULL ignore
  2624. * caption - caption to search for, NULL ignore
  2625. * hInst - instance handle, NULL ignore
  2626. * Return value:
  2627. * window handle found, NULL otherwise
  2628. * Called by:
  2629. * SCConnect, SCDisconnect, GetDisconnectResult
  2630. --*/
  2631. HWND _FindTopWindow(LPCTSTR classname, LPCTSTR caption, _CLXWINDOWOWNER hInst)
  2632. {
  2633. SEARCHWND search;
  2634. search.szClassName = classname;
  2635. search.szCaption = caption;
  2636. search.hWnd = NULL;
  2637. search.hInstance = hInst;
  2638. EnumWindows(_EnumWindowsProc, (LPARAM)&search);
  2639. return search.hWnd;
  2640. }
  2641. /*++
  2642. * Function:
  2643. * _FindWindow
  2644. * Description:
  2645. * Find child window by classname
  2646. * Win32/Win16/WinCE
  2647. * Arguments:
  2648. * hwndParent - the parent window handle
  2649. * srchclass - class name to search for, NULL - ignore
  2650. * Return value:
  2651. * window handle found, NULL otherwise
  2652. * Called by:
  2653. *
  2654. --*/
  2655. HWND _FindWindow(HWND hwndParent, LPCTSTR srchclass)
  2656. {
  2657. HWND hWnd, hwndTop, hwndNext;
  2658. BOOL bFound;
  2659. TCHAR classname[128];
  2660. hWnd = NULL;
  2661. hwndTop = GetWindow(hwndParent, GW_CHILD);
  2662. if (!hwndTop)
  2663. {
  2664. TRACE((INFO_MESSAGE, TEXT("GetWindow failed. hwnd=0x%x\n"), hwndParent));
  2665. goto exiterr;
  2666. }
  2667. bFound = FALSE;
  2668. hwndNext = hwndTop;
  2669. do {
  2670. hWnd = hwndNext;
  2671. if (srchclass && !GetClassName(hWnd, classname, sizeof(classname)/sizeof(TCHAR)))
  2672. {
  2673. TRACE((INFO_MESSAGE, TEXT("GetClassName failed. hwnd=0x%x\n")));
  2674. goto nextwindow;
  2675. }
  2676. if (!srchclass || !_CLX_strcmp(classname, srchclass))
  2677. bFound = TRUE;
  2678. nextwindow:
  2679. #ifndef OS_WINCE
  2680. hwndNext = GetNextWindow(hWnd, GW_HWNDNEXT);
  2681. #else // OS_WINCE
  2682. hwndNext = GetWindow(hWnd, GW_HWNDNEXT);
  2683. #endif // OS_WINCE
  2684. } while (hWnd && hwndNext != hwndTop && !bFound);
  2685. if (!bFound) goto exiterr;
  2686. return hWnd;
  2687. exiterr:
  2688. return NULL;
  2689. }
  2690. /*++
  2691. * Function:
  2692. * _OnBackground
  2693. * Description:
  2694. * Simulates a background thread. Called when a message from the
  2695. * background timer is received
  2696. * Win32/Win16/WinCE
  2697. * Arguments:
  2698. * pClx - the context
  2699. * Called by:
  2700. * _ClxWndProc on WM_TIMER message from g_uiBackgroundTimer is received
  2701. --*/
  2702. VOID _OnBackground(PCLXINFO pClx)
  2703. {
  2704. // Try to limit this call, eats lot of the CPU
  2705. _GarbageCollecting(pClx, TRUE);
  2706. }
  2707. /*
  2708. * GarbageCollecting - closes all message boxes asking this and that
  2709. * like "shall i close the connection" or "there's some error"
  2710. * This function is forced by g_uiBackgroundTimer message
  2711. */
  2712. /*++
  2713. * Function:
  2714. * _GarbageCollecting
  2715. * Description:
  2716. * Closes all message boxes asking this and that
  2717. * like "shall i close the connection" or "there's some error"
  2718. * This function is forced by g_uiBackgroundTimer message
  2719. * Win32/Win16/WinCE
  2720. * Arguments:
  2721. * pClx - the context
  2722. * bNotifyForErrorBox - if TRUE calls ClxEvent with
  2723. * "disconnected" event
  2724. * Return value:
  2725. * TRUE if error boxes are found
  2726. * Called by:
  2727. *
  2728. --*/
  2729. BOOL _GarbageCollecting(PCLXINFO pClx, BOOL bNotifyForErrorBox)
  2730. {
  2731. HWND hBox;
  2732. BOOL rv = FALSE;
  2733. // Clean all extra message boxes, like saying that
  2734. // we cannot connect because of this and that
  2735. if (!g_hRDPInst)
  2736. goto exitpt;
  2737. hBox = _FindTopWindow(NULL,
  2738. g_strDisconnectDialogBox,
  2739. g_hRDPInst);
  2740. if (hBox)
  2741. {
  2742. rv = TRUE;
  2743. PostMessage(hBox, WM_CLOSE, 0, 0);
  2744. if (bNotifyForErrorBox)
  2745. // Notifiy that we are disconnected
  2746. ClxEvent(pClx, CLX_EVENT_DISCONNECT, 0);
  2747. }
  2748. hBox = _FindTopWindow(NULL,
  2749. TEXT(FATAL_ERROR_5),
  2750. g_hRDPInst);
  2751. if (hBox)
  2752. {
  2753. rv = TRUE;
  2754. PostMessage(hBox, WM_CLOSE, 0, 0);
  2755. if (bNotifyForErrorBox)
  2756. // Notifiy that we are disconnected
  2757. ClxEvent(pClx, CLX_EVENT_DISCONNECT, 0);
  2758. }
  2759. if (pClx->bCloseTrys)
  2760. {
  2761. _AttemptToCloseTheClient();
  2762. }
  2763. exitpt:
  2764. if (rv)
  2765. TRACE((INFO_MESSAGE, "Error boxes found\n"));
  2766. return rv;
  2767. }
  2768. /*++
  2769. * Function:
  2770. * _SetClipboard
  2771. * Description:
  2772. * Sets the clipboard content in RCLX mode
  2773. * Win32/Win16/WinCE
  2774. * Arguments:
  2775. * uiFormat - clipboard format
  2776. * pClipboard - new clipboard content
  2777. * nSize - the clipboard size
  2778. * Called by:
  2779. * RClx_ProcessRequest on REQ_SETCLIPBOARD
  2780. --*/
  2781. VOID
  2782. _SetClipboard(UINT uiFormat, PVOID pClipboard, UINT32 nSize)
  2783. {
  2784. HGLOBAL ghNewClipboard = NULL;
  2785. BOOL bOpened = FALSE;
  2786. BOOL bFreeClipHandle = TRUE;
  2787. LPVOID pNewClipboard = NULL;
  2788. // WinCE - no clipboard
  2789. #ifndef OS_WINCE
  2790. if (!nSize)
  2791. {
  2792. // Just empty the clipboard
  2793. if (OpenClipboard(NULL))
  2794. {
  2795. bOpened = TRUE;
  2796. EmptyClipboard();
  2797. } else {
  2798. TRACE((ERROR_MESSAGE, TEXT("Can't lock the clipbord. GetLastError=%d\n"),
  2799. GetLastError()));
  2800. }
  2801. goto exitpt;
  2802. }
  2803. if (!pClipboard)
  2804. {
  2805. TRACE((ERROR_MESSAGE, TEXT("_SetClipboard: pClipboard is NULL\n")));
  2806. goto exitpt;
  2807. }
  2808. ghNewClipboard = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, nSize);
  2809. if (!ghNewClipboard)
  2810. {
  2811. TRACE((ERROR_MESSAGE, TEXT("Can't alloc(GlobalAlloc) %d bytes\n"),
  2812. nSize));
  2813. goto exitpt;
  2814. }
  2815. pNewClipboard = GlobalLock(ghNewClipboard);
  2816. if (!pNewClipboard)
  2817. {
  2818. TRACE((ERROR_MESSAGE, TEXT("Can't lock the clipbord. GetLastError=%d\n"),
  2819. GetLastError()));
  2820. goto exitpt;
  2821. }
  2822. // Copy the data
  2823. HUGEMEMCPY(pNewClipboard, pClipboard, nSize);
  2824. if (!OpenClipboard(NULL))
  2825. {
  2826. TRACE((ERROR_MESSAGE, TEXT("Can't open the clipboard. GetLastError=%d\n"),
  2827. GetLastError()));
  2828. goto exitpt;
  2829. }
  2830. bOpened = TRUE;
  2831. // Empty the clipboard, so we'll have only one entry
  2832. EmptyClipboard();
  2833. GlobalUnlock(ghNewClipboard);
  2834. pNewClipboard = NULL;
  2835. if (!Clp_SetClipboardData(uiFormat,
  2836. ghNewClipboard,
  2837. nSize,
  2838. &bFreeClipHandle))
  2839. TRACE((ERROR_MESSAGE, TEXT("SetClipboardData failed. GetLastError=%d\n"), GetLastError()));
  2840. else
  2841. TRACE((INFO_MESSAGE, TEXT("Clipboard is loaded successfuly. %ld bytes\n"),
  2842. nSize));
  2843. exitpt:
  2844. if (pNewClipboard)
  2845. GlobalUnlock(ghNewClipboard);
  2846. if (bOpened)
  2847. CloseClipboard();
  2848. // Do not free already set clipboard
  2849. if (ghNewClipboard && bFreeClipHandle)
  2850. GlobalFree(ghNewClipboard);
  2851. #else // !OS_WINCE
  2852. TRACE((WARNING_MESSAGE, TEXT("WinCE: clipboard not supported\n")));
  2853. #endif // !OS_WINCE
  2854. }
  2855. #ifdef OS_WINCE
  2856. SOCKET g_hSocket = 0;
  2857. LONG g_lEvent = 0;
  2858. HWND g_hNotifyWindow = NULL;
  2859. UINT g_uiMessage = 0;
  2860. HANDLE g_hAsyncThread = NULL;
  2861. BYTE g_pRecvBuffer[1024];
  2862. INT g_nRecvStart, g_nRecvLength;
  2863. BOOL g_bGoAsync = FALSE;
  2864. CRITICAL_SECTION g_AsyncCS;
  2865. /*++
  2866. * Function:
  2867. * WSAAsyncSelect
  2868. * Description:
  2869. * Windows CE doesn't have this function. Here we are using extra thread
  2870. * for implementation of this mechanism
  2871. * WinCE only
  2872. * Arguments:
  2873. * s - socket handle
  2874. * hWnd - notification window
  2875. * wMsg - message to send when event occured
  2876. * lEvent - event mask, on what event this will work
  2877. * Return value:
  2878. * On error returns SOCKET_ERROR
  2879. * Called by:
  2880. * RClx_Connect, RClx_Disconnect
  2881. --*/
  2882. INT WSAAsyncSelect (SOCKET s, HWND hWnd, UINT uiMsg, LONG lEvent)
  2883. {
  2884. INT rv = SOCKET_ERROR;
  2885. if (!g_hAsyncThread)
  2886. {
  2887. TRACE((ERROR_MESSAGE,
  2888. TEXT("WSAAsyncSelect: no AsyncThread\n")));
  2889. goto exitpt;
  2890. }
  2891. if (s == INVALID_SOCKET)
  2892. {
  2893. TRACE((ERROR_MESSAGE,
  2894. TEXT("WSAAsyncSelect: INVALID_SOCKET passed\n")));
  2895. goto exitpt;
  2896. }
  2897. if ((lEvent & FD_WRITE) || (lEvent & FD_CONNECT))
  2898. {
  2899. TRACE((ERROR_MESSAGE,
  2900. TEXT("WSAAsyncSelec: FD_WRITE & FD_CONNECT not supported\n")));
  2901. goto exitpt;
  2902. }
  2903. EnterCriticalSection(&g_AsyncCS);
  2904. g_hSocket = s;
  2905. g_lEvent = lEvent;
  2906. g_hNotifyWindow = hWnd;
  2907. g_uiMessage = uiMsg;
  2908. LeaveCriticalSection(&g_AsyncCS);
  2909. ResumeThread(g_hAsyncThread);
  2910. rv = 0;
  2911. exitpt:
  2912. return rv;
  2913. }
  2914. /*++
  2915. * Function:
  2916. * AsyncRecv
  2917. * Description:
  2918. * Used to receive w/o blocking. WSAAsync Select must be called
  2919. * with FD_READ flag
  2920. * WinCE only
  2921. * Arguments:
  2922. * s - socket handle
  2923. * pBuffer - buffer for received bytes
  2924. * nBytesToRead - how many bytes to receive
  2925. * pnErrorCode - pointer to error code
  2926. * Return value:
  2927. * On error returns SOCKET_ERROR
  2928. * Called by:
  2929. * RClx_ReadRequest
  2930. --*/
  2931. INT AsyncRecv(SOCKET s, PVOID pBuffer, INT nBytesToRead, INT *pnErrorCode)
  2932. {
  2933. INT rv = SOCKET_ERROR;
  2934. if (!g_hAsyncThread)
  2935. {
  2936. TRACE((ERROR_MESSAGE,
  2937. TEXT("WSAAsyncSelect: no AsyncThread\n")));
  2938. goto exitpt;
  2939. }
  2940. ASSERT(s == g_hSocket);
  2941. (*pnErrorCode) = 0;
  2942. EnterCriticalSection(&g_AsyncCS);
  2943. if (!g_nRecvLength)
  2944. {
  2945. (*pnErrorCode) = WSAEWOULDBLOCK;
  2946. }
  2947. else
  2948. {
  2949. INT nToCopy;
  2950. nToCopy = (nBytesToRead < g_nRecvLength)?nBytesToRead:g_nRecvLength;
  2951. memcpy(pBuffer, g_pRecvBuffer + g_nRecvStart, nToCopy);
  2952. rv = nToCopy;
  2953. g_nRecvLength -= nToCopy;
  2954. g_nRecvStart += nToCopy;
  2955. }
  2956. // Resume the thread
  2957. if (!g_nRecvLength)
  2958. ResumeThread(g_hAsyncThread);
  2959. LeaveCriticalSection(&g_AsyncCS);
  2960. exitpt:
  2961. return rv;
  2962. }
  2963. /*++
  2964. * Function:
  2965. * _SelectWorker
  2966. * Description:
  2967. * Simulates WSAAsyncSelect message notification
  2968. * Lifetime: between ClxInitialize and ClxTerminate
  2969. * WinCE only
  2970. * Arguments:
  2971. * lParam - unused parameter
  2972. * Return value:
  2973. * allways 0
  2974. * Called by:
  2975. * _StartAsyncThread as a thread function
  2976. --*/
  2977. UINT _SelectWorker(LPVOID lpParam)
  2978. {
  2979. SOCKET hSocket;
  2980. LONG lEvent;
  2981. FD_SET fdRead;
  2982. HWND hwndNotify;
  2983. UINT uiMsg;
  2984. INT Status;
  2985. while(g_bGoAsync)
  2986. {
  2987. FD_ZERO(&fdRead);
  2988. EnterCriticalSection(&g_AsyncCS);
  2989. hSocket = g_hSocket;
  2990. lEvent = g_lEvent;
  2991. hwndNotify = g_hNotifyWindow;
  2992. uiMsg = g_uiMessage;
  2993. LeaveCriticalSection(&g_AsyncCS);
  2994. if (hSocket == INVALID_SOCKET || !lEvent || !hwndNotify || !uiMsg)
  2995. goto wait;
  2996. if (lEvent & FD_READ)
  2997. FD_SET(hSocket, &fdRead);
  2998. Status = select(-1, &fdRead, NULL, NULL, NULL);
  2999. if (Status == SOCKET_ERROR && (lEvent & FD_CLOSE))
  3000. PostMessage(hwndNotify, uiMsg, hSocket, FD_CLOSE);
  3001. if (FD_ISSET(hSocket, &fdRead) && (lEvent & FD_READ))
  3002. {
  3003. EnterCriticalSection(&g_AsyncCS);
  3004. if (!g_nRecvLength)
  3005. // Read into the buffer
  3006. {
  3007. g_nRecvStart = 0;
  3008. g_nRecvLength = recv(hSocket, g_pRecvBuffer, sizeof(g_pRecvBuffer), 0);
  3009. if (g_nRecvLength == SOCKET_ERROR)
  3010. g_nRecvLength = 0;
  3011. }
  3012. LeaveCriticalSection(&g_AsyncCS);
  3013. if (g_nRecvLength)
  3014. PostMessage(hwndNotify, uiMsg, hSocket, FD_READ);
  3015. else if (lEvent & FD_CLOSE)
  3016. PostMessage(hwndNotify, uiMsg, hSocket, FD_CLOSE);
  3017. }
  3018. wait:
  3019. ASSERT(g_hAsyncThread);
  3020. SuspendThread(g_hAsyncThread);
  3021. }
  3022. return 0;
  3023. }
  3024. /*++
  3025. * Function:
  3026. * _StartAsyncThread
  3027. * Description:
  3028. * Starts thread for simulating WSAAsyncSelect
  3029. * WinCE only
  3030. * Return value:
  3031. * TRUE on success
  3032. * Called by:
  3033. * dllentry on DLL_ATTACH_PROCESS
  3034. --*/
  3035. BOOL _StartAsyncThread(VOID)
  3036. {
  3037. DWORD dwThreadId;
  3038. InitializeCriticalSection(&g_AsyncCS);
  3039. g_bGoAsync = TRUE;
  3040. g_hAsyncThread =
  3041. CreateThread(
  3042. NULL, // security
  3043. 0, // stack size (default)
  3044. _SelectWorker,
  3045. NULL, // parameter
  3046. 0, // flags
  3047. &dwThreadId);
  3048. return (g_hAsyncThread != NULL);
  3049. }
  3050. /*++
  3051. * Function:
  3052. * _CloseAsyncThread
  3053. * Description:
  3054. * Destroys the thread created in _StartAsyncThread
  3055. * WinCE only
  3056. * Called by:
  3057. * dllentry on DLL_DETTACH_PROCESS
  3058. --*/
  3059. VOID _CloseAsyncThread(VOID)
  3060. {
  3061. if (g_hAsyncThread)
  3062. {
  3063. g_bGoAsync = FALSE;
  3064. ResumeThread(g_hAsyncThread);
  3065. TRACE((INFO_MESSAGE, TEXT("Closing Async Thread\n")));
  3066. if (WaitForSingleObject(g_hAsyncThread, 15000) == WAIT_TIMEOUT)
  3067. {
  3068. TRACE((WARNING_MESSAGE,
  3069. TEXT("Async Thread is still alive. Retrying once more time\n")));
  3070. ResumeThread(g_hAsyncThread);
  3071. if (WaitForSingleObject(g_hAsyncThread, 30000) == WAIT_TIMEOUT)
  3072. {
  3073. TRACE((ERROR_MESSAGE,
  3074. TEXT("Async thread is again alive. KILL THE THREAD !!!\n")));
  3075. TerminateThread(g_hAsyncThread, 1);
  3076. }
  3077. }
  3078. g_hAsyncThread = NULL;
  3079. }
  3080. DeleteCriticalSection(&g_AsyncCS);
  3081. }
  3082. BOOL
  3083. CheckDlgButton(
  3084. HWND hDlg,
  3085. INT nIDButton,
  3086. UINT uCheck)
  3087. {
  3088. LONG lres = SendDlgItemMessage(hDlg, nIDButton, BM_SETCHECK, uCheck, 0);
  3089. return (lres == 0);
  3090. }
  3091. #endif // OS_WINCE
  3092. #ifdef UNICODE
  3093. /*++
  3094. * Function:
  3095. * _CLX_SetDlgItemTextA
  3096. * Description:
  3097. * Ascii version for SetDlgItemText
  3098. * WinCE only, UNICODE only
  3099. * Arguments:
  3100. * hDlg - dialog handle
  3101. * nDlgItem - dialog item
  3102. * lpString - item text
  3103. * Return value:
  3104. * TRUE on success
  3105. * Called by:
  3106. * _ClxWndProc on WM_TIMER message
  3107. --*/
  3108. BOOL _CLX_SetDlgItemTextA(HWND hDlg, INT nDlgItem, LPCSTR lpString)
  3109. {
  3110. WCHAR lpStringW[128];
  3111. INT ccLen = strlen(lpString);
  3112. lpStringW[0] = 0;
  3113. MultiByteToWideChar(
  3114. CP_ACP,
  3115. MB_ERR_INVALID_CHARS,
  3116. lpString,
  3117. -1,
  3118. lpStringW,
  3119. ccLen + 1);
  3120. return SetDlgItemText(hDlg, nDlgItem, lpStringW);
  3121. }
  3122. #endif // UNICODE
  3123. #ifndef OS_WINCE
  3124. /*
  3125. *
  3126. * Clipboard functions
  3127. *
  3128. */
  3129. HGLOBAL Clp_GetMFData(HANDLE hData,
  3130. UINT32 *pDataLen);
  3131. HGLOBAL Clp_SetMFData(UINT32 dataLen,
  3132. PVOID pData);
  3133. // next is directly cut & paste from clputil.c
  3134. typedef struct {
  3135. UINT32 mm;
  3136. UINT32 xExt;
  3137. UINT32 yExt;
  3138. } CLIPBOARD_MFPICT, *PCLIPBOARD_MFPICT;
  3139. VOID
  3140. Clp_GetClipboardData(
  3141. UINT format,
  3142. HGLOBAL hClipData,
  3143. UINT32 *pnClipDataSize,
  3144. HGLOBAL *phNewData)
  3145. {
  3146. HGLOBAL hData = hClipData;
  3147. UINT32 dataLen = 0;
  3148. WORD numEntries;
  3149. DWORD dwEntries;
  3150. PVOID pData;
  3151. *phNewData = NULL;
  3152. *pnClipDataSize = 0;
  3153. if (format == CF_PALETTE)
  3154. {
  3155. /****************************************************************/
  3156. /* Find out how many entries there are in the palette and */
  3157. /* allocate enough memory to hold them all. */
  3158. /****************************************************************/
  3159. if (GetObject(hData, sizeof(numEntries), (LPSTR)&numEntries) == 0)
  3160. {
  3161. numEntries = 256;
  3162. }
  3163. dataLen = sizeof(LOGPALETTE) +
  3164. (((UINT32)numEntries - 1) * sizeof(PALETTEENTRY));
  3165. *phNewData = GlobalAlloc(GHND, dataLen);
  3166. if (*phNewData == 0)
  3167. {
  3168. TRACE((ERROR_MESSAGE, "Failed to get %d bytes for palette", dataLen));
  3169. goto exitpt;
  3170. }
  3171. else
  3172. {
  3173. /************************************************************/
  3174. /* now get the palette entries into the new buffer */
  3175. /************************************************************/
  3176. pData = GlobalLock(*phNewData);
  3177. dwEntries = GetPaletteEntries((HPALETTE)hData,
  3178. 0,
  3179. numEntries,
  3180. (PALETTEENTRY*)pData);
  3181. GlobalUnlock(*phNewData);
  3182. if (dwEntries == 0)
  3183. {
  3184. TRACE((ERROR_MESSAGE, "Failed to get any palette entries"));
  3185. goto exitpt;
  3186. }
  3187. dataLen = (UINT32)dwEntries * sizeof(PALETTEENTRY);
  3188. }
  3189. } else if (format == CF_METAFILEPICT)
  3190. {
  3191. *phNewData = Clp_GetMFData(hData, &dataLen);
  3192. if (!*phNewData)
  3193. {
  3194. TRACE((ERROR_MESSAGE, "Failed to set MF data"));
  3195. goto exitpt;
  3196. }
  3197. } else {
  3198. if (format == CF_DIB)
  3199. {
  3200. // Get the exact DIB size
  3201. BITMAPINFOHEADER *pBMI = (BITMAPINFOHEADER *)GlobalLock(hData);
  3202. if (pBMI)
  3203. {
  3204. if (pBMI->biSizeImage)
  3205. dataLen = pBMI->biSize + pBMI->biSizeImage;
  3206. GlobalUnlock(hData);
  3207. }
  3208. }
  3209. /****************************************************************/
  3210. /* just get the length of the block */
  3211. /****************************************************************/
  3212. if (!dataLen)
  3213. dataLen = (DWORD)GlobalSize(hData);
  3214. }
  3215. *pnClipDataSize = dataLen;
  3216. exitpt:
  3217. ;
  3218. }
  3219. BOOL
  3220. Clp_SetClipboardData(
  3221. UINT formatID,
  3222. HGLOBAL hClipData,
  3223. UINT32 nClipDataSize,
  3224. BOOL *pbFreeHandle)
  3225. {
  3226. BOOL rv = FALSE;
  3227. PVOID pData = NULL;
  3228. HGLOBAL hData = NULL;
  3229. LOGPALETTE *pLogPalette = NULL;
  3230. UINT numEntries;
  3231. UINT memLen;
  3232. ASSERT(pbFreeHandle);
  3233. *pbFreeHandle = TRUE;
  3234. if (formatID == CF_METAFILEPICT)
  3235. {
  3236. /********************************************************************/
  3237. /* We have to put a handle to the metafile on the clipboard - which */
  3238. /* means creating a metafile from the received data first */
  3239. /********************************************************************/
  3240. pData = GlobalLock(hClipData);
  3241. if (!pData)
  3242. {
  3243. TRACE((ERROR_MESSAGE, "Failed to lock buffer\n"));
  3244. goto exitpt;
  3245. }
  3246. hData = Clp_SetMFData(nClipDataSize, pData);
  3247. if (!hData)
  3248. {
  3249. TRACE((ERROR_MESSAGE, "Failed to set MF data\n"));
  3250. }
  3251. else if (SetClipboardData(formatID, hData) != hData)
  3252. {
  3253. TRACE((ERROR_MESSAGE, "SetClipboardData. GetLastError=%d\n", GetLastError()));
  3254. }
  3255. GlobalUnlock(hClipData);
  3256. } else if (formatID == CF_PALETTE)
  3257. {
  3258. /********************************************************************/
  3259. /* We have to put a handle to the palette on the clipboard - again */
  3260. /* this means creating one from the received data first */
  3261. /* */
  3262. /* Allocate memory for a LOGPALETTE structure large enough to hold */
  3263. /* all the PALETTE ENTRY structures, and fill it in. */
  3264. /********************************************************************/
  3265. numEntries = (UINT)(nClipDataSize / sizeof(PALETTEENTRY));
  3266. memLen = (sizeof(LOGPALETTE) +
  3267. ((numEntries - 1) * sizeof(PALETTEENTRY)));
  3268. pLogPalette = malloc(memLen);
  3269. if (!pLogPalette)
  3270. {
  3271. TRACE((ERROR_MESSAGE, "Failed to get %d bytes", memLen));
  3272. goto exitpt;
  3273. }
  3274. pLogPalette->palVersion = 0x300;
  3275. pLogPalette->palNumEntries = (WORD)numEntries;
  3276. /********************************************************************/
  3277. /* get a pointer to the data and copy it to the palette */
  3278. /********************************************************************/
  3279. pData = GlobalLock(hClipData);
  3280. if (pData == NULL)
  3281. {
  3282. TRACE((ERROR_MESSAGE, "Failed to lock buffer"));
  3283. goto exitpt;
  3284. }
  3285. HUGEMEMCPY(pLogPalette->palPalEntry, pData, nClipDataSize);
  3286. /********************************************************************/
  3287. /* unlock the buffer */
  3288. /********************************************************************/
  3289. GlobalUnlock(hClipData);
  3290. /********************************************************************/
  3291. /* now create a palette */
  3292. /********************************************************************/
  3293. hData = CreatePalette(pLogPalette);
  3294. if (!hData)
  3295. {
  3296. TRACE((ERROR_MESSAGE, "CreatePalette failed\n"));
  3297. goto exitpt;
  3298. }
  3299. /********************************************************************/
  3300. /* and set the palette handle to the Clipboard */
  3301. /********************************************************************/
  3302. if (SetClipboardData(formatID, hData) != hData)
  3303. {
  3304. TRACE((ERROR_MESSAGE, "SetClipboardData. GetLastError=%d\n", GetLastError()));
  3305. }
  3306. } else {
  3307. /****************************************************************/
  3308. /* Just set it onto the clipboard */
  3309. /****************************************************************/
  3310. if (SetClipboardData(formatID, hClipData) != hClipData)
  3311. {
  3312. TRACE((ERROR_MESSAGE, "SetClipboardData. GetLastError=%d, hClipData=0x%x\n", GetLastError(), hClipData));
  3313. goto exitpt;
  3314. }
  3315. // Only in this case we don't need to free the handle
  3316. *pbFreeHandle = FALSE;
  3317. }
  3318. rv = TRUE;
  3319. exitpt:
  3320. if (!pLogPalette)
  3321. {
  3322. free(pLogPalette);
  3323. }
  3324. return rv;
  3325. }
  3326. HGLOBAL Clp_GetMFData(HANDLE hData,
  3327. UINT32 *pDataLen)
  3328. {
  3329. UINT32 lenMFBits = 0;
  3330. BOOL rc = FALSE;
  3331. LPMETAFILEPICT pMFP = NULL;
  3332. HDC hMFDC = NULL;
  3333. HMETAFILE hMF = NULL;
  3334. HGLOBAL hMFBits = NULL;
  3335. HANDLE hNewData = NULL;
  3336. CHAR *pNewData = NULL;
  3337. PVOID pBits = NULL;
  3338. /************************************************************************/
  3339. /* Lock the memory to get a pointer to a METAFILEPICT header structure */
  3340. /* and create a METAFILEPICT DC. */
  3341. /************************************************************************/
  3342. pMFP = (LPMETAFILEPICT)GlobalLock(hData);
  3343. if (pMFP == NULL)
  3344. goto exitpt;
  3345. hMFDC = CreateMetaFile(NULL);
  3346. if (hMFDC == NULL)
  3347. goto exitpt;
  3348. /************************************************************************/
  3349. /* Copy the MFP by playing it into the DC and closing it. */
  3350. /************************************************************************/
  3351. if (!PlayMetaFile(hMFDC, pMFP->hMF))
  3352. {
  3353. CloseMetaFile(hMFDC);
  3354. goto exitpt;
  3355. }
  3356. hMF = CloseMetaFile(hMFDC);
  3357. if (hMF == NULL)
  3358. goto exitpt;
  3359. /************************************************************************/
  3360. /* Get the MF bits and determine how long they are. */
  3361. /************************************************************************/
  3362. #ifdef OS_WIN16
  3363. hMFBits = GetMetaFileBits(hMF);
  3364. lenMFBits = GlobalSize(hMFBits);
  3365. #else
  3366. lenMFBits = GetMetaFileBitsEx(hMF, 0, NULL);
  3367. #endif
  3368. if (lenMFBits == 0)
  3369. goto exitpt;
  3370. /************************************************************************/
  3371. /* Work out how much memory we need and get a buffer */
  3372. /************************************************************************/
  3373. *pDataLen = sizeof(CLIPBOARD_MFPICT) + lenMFBits;
  3374. hNewData = GlobalAlloc(GHND, *pDataLen);
  3375. if (hNewData == NULL)
  3376. goto exitpt;
  3377. pNewData = GlobalLock(hNewData);
  3378. /************************************************************************/
  3379. /* Copy the MF header and bits into the buffer. */
  3380. /************************************************************************/
  3381. ((PCLIPBOARD_MFPICT)pNewData)->mm = pMFP->mm;
  3382. ((PCLIPBOARD_MFPICT)pNewData)->xExt = pMFP->xExt;
  3383. ((PCLIPBOARD_MFPICT)pNewData)->yExt = pMFP->yExt;
  3384. #ifdef OS_WIN16
  3385. pBits = GlobalLock(hMFBits);
  3386. HUGEMEMCPY((pNewData + sizeof(CLIPBOARD_MFPICT)),
  3387. pBits,
  3388. lenMFBits);
  3389. GlobalUnlock(hMFBits);
  3390. #else
  3391. lenMFBits = GetMetaFileBitsEx(hMF, lenMFBits,
  3392. (pNewData + sizeof(CLIPBOARD_MFPICT)));
  3393. if (lenMFBits == 0)
  3394. goto exitpt;
  3395. #endif
  3396. /************************************************************************/
  3397. /* all OK */
  3398. /************************************************************************/
  3399. rc = TRUE;
  3400. exitpt:
  3401. /************************************************************************/
  3402. /* Unlock any global mem. */
  3403. /************************************************************************/
  3404. if (pMFP)
  3405. {
  3406. GlobalUnlock(hData);
  3407. }
  3408. if (pNewData)
  3409. {
  3410. GlobalUnlock(hNewData);
  3411. }
  3412. /************************************************************************/
  3413. /* if things went wrong, then free the new data */
  3414. /************************************************************************/
  3415. if ((rc == FALSE) && (hNewData != NULL))
  3416. {
  3417. GlobalFree(hNewData);
  3418. hNewData = NULL;
  3419. }
  3420. return(hNewData);
  3421. }
  3422. HGLOBAL Clp_SetMFData(UINT32 dataLen,
  3423. PVOID pData)
  3424. {
  3425. BOOL rc = FALSE;
  3426. HGLOBAL hMFBits = NULL;
  3427. PVOID pMFMem = NULL;
  3428. HMETAFILE hMF = NULL;
  3429. HGLOBAL hMFPict = NULL;
  3430. LPMETAFILEPICT pMFPict = NULL;
  3431. /************************************************************************/
  3432. /* Allocate memory to hold the MF bits (we need the handle to pass to */
  3433. /* SetMetaFileBits). */
  3434. /************************************************************************/
  3435. hMFBits = GlobalAlloc(GHND, dataLen - sizeof(CLIPBOARD_MFPICT));
  3436. if (hMFBits == NULL)
  3437. goto exitpt;
  3438. /************************************************************************/
  3439. /* Lock the handle and copy in the MF header. */
  3440. /************************************************************************/
  3441. pMFMem = GlobalLock(hMFBits);
  3442. if (pMFMem == NULL)
  3443. goto exitpt;
  3444. HUGEMEMCPY(pMFMem,
  3445. (PVOID)((CHAR *)pData + sizeof(CLIPBOARD_MFPICT)),
  3446. dataLen - sizeof(CLIPBOARD_MFPICT) );
  3447. GlobalUnlock(hMFBits);
  3448. /************************************************************************/
  3449. /* Now use the copied MF bits to create the actual MF bits and get a */
  3450. /* handle to the MF. */
  3451. /************************************************************************/
  3452. #ifdef OS_WIN16
  3453. hMF = SetMetaFileBits(hMFBits);
  3454. #else
  3455. hMF = SetMetaFileBitsEx(dataLen - sizeof(CLIPBOARD_MFPICT), pMFMem);
  3456. #endif
  3457. if (hMF == NULL)
  3458. goto exitpt;
  3459. /************************************************************************/
  3460. /* Allocate a new METAFILEPICT structure, and use the data from the */
  3461. /* header. */
  3462. /************************************************************************/
  3463. hMFPict = GlobalAlloc(GHND, sizeof(METAFILEPICT));
  3464. pMFPict = (LPMETAFILEPICT)GlobalLock(hMFPict);
  3465. if (!pMFPict)
  3466. goto exitpt;
  3467. pMFPict->mm = (int)((PCLIPBOARD_MFPICT)pData)->mm;
  3468. pMFPict->xExt = (int)((PCLIPBOARD_MFPICT)pData)->xExt;
  3469. pMFPict->yExt = (int)((PCLIPBOARD_MFPICT)pData)->yExt;
  3470. pMFPict->hMF = hMF;
  3471. GlobalUnlock(hMFPict);
  3472. rc = TRUE;
  3473. exitpt:
  3474. /************************************************************************/
  3475. /* tidy up */
  3476. /************************************************************************/
  3477. if (!rc)
  3478. {
  3479. if (hMFPict)
  3480. {
  3481. GlobalFree(hMFPict);
  3482. }
  3483. if (hMFBits)
  3484. {
  3485. GlobalFree(hMFBits);
  3486. }
  3487. }
  3488. return(hMFPict);
  3489. }
  3490. #endif // !OS_WINCE
  3491. BOOL
  3492. WS_Init(VOID)
  3493. {
  3494. WORD versionRequested;
  3495. WSADATA wsaData;
  3496. INT intRC;
  3497. BOOL rv = FALSE;
  3498. versionRequested = MAKEWORD(1, 1);
  3499. intRC = WSAStartup(versionRequested, &wsaData);
  3500. if (intRC != 0)
  3501. goto exitpt;
  3502. rv = TRUE;
  3503. exitpt:
  3504. return rv;
  3505. }
  3506. VOID
  3507. _AttemptToCloseTheClient(VOID)
  3508. {
  3509. HWND hYesNo = NULL;
  3510. static BOOL bSpeedupTimer = FALSE;
  3511. if (!bSpeedupTimer)
  3512. {
  3513. KillTimer(g_hWindow, g_uiBackgroundTimer);
  3514. g_uiBackgroundTimer = SetTimer(g_hWindow,
  3515. RCLX_BACKGNDTIMERID,
  3516. RCLX_TIMERELAPSETIME/15+1000,
  3517. NULL);
  3518. bSpeedupTimer = TRUE;
  3519. }
  3520. hYesNo = _FindTopWindow(NULL,
  3521. g_strYesNoShutdown,
  3522. g_hRDPInst);
  3523. if (hYesNo)
  3524. {
  3525. PostMessage(hYesNo, WM_KEYDOWN, VK_RETURN, 0);
  3526. } else {
  3527. PostMessage(g_pClx->hwndMain, WM_CLOSE, 0, 0);
  3528. // Don't know how, but this helps for NT4 client
  3529. PostMessage(g_pClx->hwndMain, WM_LBUTTONDOWN, 0, 0);
  3530. }
  3531. }
  3532. /*
  3533. * This came from: \\index1\src\nt\private\samples\wincap32\dibutil.c
  3534. */
  3535. #define WIDTHBYTES(bits) (((bits) + 31) / 32 * 4)
  3536. #define IS_WIN30_DIB(lpbi) ((*(LPDWORD)(lpbi)) == sizeof(BITMAPINFOHEADER))
  3537. WORD DIBNumColors(LPSTR lpDIB)
  3538. {
  3539. WORD wBitCount; // DIB bit count
  3540. // If this is a Windows-style DIB, the number of colors in the
  3541. // color table can be less than the number of bits per pixel
  3542. // allows for (i.e. lpbi->biClrUsed can be set to some value).
  3543. // If this is the case, return the appropriate value.
  3544. if (IS_WIN30_DIB(lpDIB))
  3545. {
  3546. DWORD dwClrUsed;
  3547. dwClrUsed = ((LPBITMAPINFOHEADER)lpDIB)->biClrUsed;
  3548. if (dwClrUsed)
  3549. return (WORD)dwClrUsed;
  3550. }
  3551. // Calculate the number of colors in the color table based on
  3552. // the number of bits per pixel for the DIB.
  3553. if (IS_WIN30_DIB(lpDIB))
  3554. wBitCount = ((LPBITMAPINFOHEADER)lpDIB)->biBitCount;
  3555. else
  3556. wBitCount = ((LPBITMAPCOREHEADER)lpDIB)->bcBitCount;
  3557. // return number of colors based on bits per pixel
  3558. switch (wBitCount)
  3559. {
  3560. case 1:
  3561. return 2;
  3562. case 4:
  3563. return 16;
  3564. case 8:
  3565. return 256;
  3566. default:
  3567. return 0;
  3568. }
  3569. }
  3570. WORD PaletteSize(LPSTR lpDIB)
  3571. {
  3572. // calculate the size required by the palette
  3573. if (IS_WIN30_DIB (lpDIB))
  3574. return (DIBNumColors(lpDIB) * sizeof(RGBQUAD));
  3575. else
  3576. return (DIBNumColors(lpDIB) * sizeof(RGBTRIPLE));
  3577. }
  3578. /*************************************************************************
  3579. *
  3580. * BitmapToDIB()
  3581. *
  3582. * Parameters:
  3583. *
  3584. * HBITMAP hBitmap - specifies the bitmap to convert
  3585. *
  3586. * HPALETTE hPal - specifies the palette to use with the bitmap
  3587. *
  3588. * Return Value:
  3589. *
  3590. * HANDLE - identifies the device-dependent bitmap
  3591. *
  3592. * Description:
  3593. *
  3594. * This function creates a DIB from a bitmap using the specified palette.
  3595. *
  3596. ************************************************************************/
  3597. HANDLE BitmapToDIB(HBITMAP hBitmap, HPALETTE hPal)
  3598. {
  3599. BITMAP bm; // bitmap structure
  3600. BITMAPINFOHEADER bi; // bitmap header
  3601. LPBITMAPINFOHEADER lpbi; // pointer to BITMAPINFOHEADER
  3602. DWORD dwLen; // size of memory block
  3603. HANDLE hDIB, h; // handle to DIB, temp handle
  3604. HDC hDC; // handle to DC
  3605. WORD biBits; // bits per pixel
  3606. // check if bitmap handle is valid
  3607. if (!hBitmap)
  3608. return NULL;
  3609. // fill in BITMAP structure, return NULL if it didn't work
  3610. if (!GetObject(hBitmap, sizeof(bm), (LPSTR)&bm))
  3611. return NULL;
  3612. // if no palette is specified, use default palette
  3613. if (hPal == NULL)
  3614. hPal = GetStockObject(DEFAULT_PALETTE);
  3615. // calculate bits per pixel
  3616. biBits = bm.bmPlanes * bm.bmBitsPixel;
  3617. // make sure bits per pixel is valid
  3618. if (biBits <= 1)
  3619. biBits = 1;
  3620. else if (biBits <= 4)
  3621. biBits = 4;
  3622. else if (biBits <= 8)
  3623. biBits = 8;
  3624. else // if greater than 8-bit, force to 24-bit
  3625. biBits = 24;
  3626. // initialize BITMAPINFOHEADER
  3627. bi.biSize = sizeof(BITMAPINFOHEADER);
  3628. bi.biWidth = bm.bmWidth;
  3629. bi.biHeight = bm.bmHeight;
  3630. bi.biPlanes = 1;
  3631. bi.biBitCount = biBits;
  3632. bi.biCompression = BI_RGB;
  3633. bi.biSizeImage = 0;
  3634. bi.biXPelsPerMeter = 0;
  3635. bi.biYPelsPerMeter = 0;
  3636. bi.biClrUsed = 0;
  3637. bi.biClrImportant = 0;
  3638. // calculate size of memory block required to store BITMAPINFO
  3639. dwLen = bi.biSize + PaletteSize((LPSTR)&bi);
  3640. // get a DC
  3641. hDC = GetDC(NULL);
  3642. if ( !hDC )
  3643. return NULL;
  3644. // select and realize our palette
  3645. hPal = SelectPalette(hDC, hPal, FALSE);
  3646. RealizePalette(hDC);
  3647. // alloc memory block to store our bitmap
  3648. hDIB = GlobalAlloc(GHND, dwLen);
  3649. // if we couldn't get memory block
  3650. if (!hDIB)
  3651. {
  3652. // clean up and return NULL
  3653. SelectPalette(hDC, hPal, TRUE);
  3654. RealizePalette(hDC);
  3655. ReleaseDC(NULL, hDC);
  3656. return NULL;
  3657. }
  3658. // lock memory and get pointer to it
  3659. lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
  3660. /// use our bitmap info. to fill BITMAPINFOHEADER
  3661. *lpbi = bi;
  3662. // call GetDIBits with a NULL lpBits param, so it will calculate the
  3663. // biSizeImage field for us
  3664. GetDIBits(hDC, hBitmap, 0, (UINT)bi.biHeight, NULL, (LPBITMAPINFO)lpbi,
  3665. DIB_RGB_COLORS);
  3666. // get the info. returned by GetDIBits and unlock memory block
  3667. bi = *lpbi;
  3668. GlobalUnlock(hDIB);
  3669. // if the driver did not fill in the biSizeImage field, make one up
  3670. if (bi.biSizeImage == 0)
  3671. bi.biSizeImage = WIDTHBYTES((DWORD)bm.bmWidth * biBits) * bm.bmHeight;
  3672. // realloc the buffer big enough to hold all the bits
  3673. dwLen = bi.biSize + PaletteSize((LPSTR)&bi) + bi.biSizeImage;
  3674. if (h = GlobalReAlloc(hDIB, dwLen, 0))
  3675. hDIB = h;
  3676. else
  3677. {
  3678. // clean up and return NULL
  3679. GlobalFree(hDIB);
  3680. hDIB = NULL;
  3681. SelectPalette(hDC, hPal, TRUE);
  3682. RealizePalette(hDC);
  3683. ReleaseDC(NULL, hDC);
  3684. return NULL;
  3685. }
  3686. // lock memory block and get pointer to it */
  3687. lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
  3688. // call GetDIBits with a NON-NULL lpBits param, and actualy get the
  3689. // bits this time
  3690. if (GetDIBits(hDC, hBitmap, 0, (UINT)bi.biHeight, (LPSTR)lpbi +
  3691. (WORD)lpbi->biSize + PaletteSize((LPSTR)lpbi), (LPBITMAPINFO)lpbi,
  3692. DIB_RGB_COLORS) == 0)
  3693. {
  3694. // clean up and return NULL
  3695. GlobalUnlock(hDIB);
  3696. hDIB = NULL;
  3697. SelectPalette(hDC, hPal, TRUE);
  3698. RealizePalette(hDC);
  3699. ReleaseDC(NULL, hDC);
  3700. return NULL;
  3701. }
  3702. bi = *lpbi;
  3703. // clean up
  3704. GlobalUnlock(hDIB);
  3705. SelectPalette(hDC, hPal, TRUE);
  3706. RealizePalette(hDC);
  3707. ReleaseDC(NULL, hDC);
  3708. // return handle to the DIB
  3709. return hDIB;
  3710. }
  3711. /*++
  3712. * Function:
  3713. * _GetDIBFromBitmap
  3714. * Description:
  3715. * Copies a rectangle from hBitmap and converts it to DIB data
  3716. *
  3717. * Arguments:
  3718. * hBitmap - the main bitmap
  3719. * ppDIB - pointer to DIB data
  3720. * left, top, right, bottom - describes the rectangle
  3721. * - if all are == -1, returns the whole bitmap
  3722. * Return value:
  3723. * TRUE on success
  3724. * Called by:
  3725. * _ClxWndProc on WM_TIMER message
  3726. --*/
  3727. VOID
  3728. _GetDIBFromBitmap(
  3729. HDC hdcMemSrc,
  3730. HBITMAP hBitmap,
  3731. HANDLE *phDIB,
  3732. INT left,
  3733. INT top,
  3734. INT right,
  3735. INT bottom)
  3736. {
  3737. HANDLE hDIB = NULL;
  3738. HDC hdcMemDst = NULL;
  3739. HDC hdcScreen = NULL;
  3740. HBITMAP hDstBitmap = NULL;
  3741. HBITMAP hOldDstBmp = NULL;
  3742. if (!hdcMemSrc)
  3743. goto exitpt;
  3744. if (left == -1 && right == -1 && top == -1 && bottom == -1 && hBitmap)
  3745. {
  3746. BITMAP bitmapInfo;
  3747. if (sizeof(bitmapInfo) !=
  3748. GetObject(hBitmap, sizeof(bitmapInfo), &bitmapInfo))
  3749. goto exitpt;
  3750. left = top = 0;
  3751. right = bitmapInfo.bmWidth;
  3752. bottom = bitmapInfo.bmHeight;
  3753. }
  3754. // reorder left...bottom if needed
  3755. if (left > right)
  3756. {
  3757. INT change = left;
  3758. left = right;
  3759. right = change;
  3760. }
  3761. if (top > bottom)
  3762. {
  3763. INT change = top;
  3764. top = bottom;
  3765. bottom = change;
  3766. }
  3767. hdcScreen = GetDC(NULL);
  3768. hdcMemDst = CreateCompatibleDC(hdcScreen);
  3769. hDstBitmap = CreateCompatibleBitmap(hdcScreen, right - left, bottom - top);
  3770. if (!hdcMemDst || !hDstBitmap)
  3771. {
  3772. TRACE(( ERROR_MESSAGE, TEXT("Can't create destination DC to get client's DIB\n")));
  3773. goto exitpt;
  3774. }
  3775. hOldDstBmp = SelectObject(hdcMemDst, hDstBitmap);
  3776. if (!BitBlt( hdcMemDst,
  3777. 0, 0, // dest x,y
  3778. right - left, // dest width
  3779. bottom - top, // dest height
  3780. hdcMemSrc,
  3781. left, top, // source coordinates
  3782. SRCCOPY))
  3783. goto exitpt;
  3784. TRACE((INFO_MESSAGE, TEXT("Getting DIB (%d, %d, %d, %d)\n"),
  3785. left, top, right, bottom));
  3786. hDIB = BitmapToDIB(hDstBitmap, NULL);
  3787. exitpt:
  3788. if (hdcMemDst)
  3789. {
  3790. if (hOldDstBmp)
  3791. SelectObject(hdcMemDst, hOldDstBmp);
  3792. DeleteDC(hdcMemDst);
  3793. }
  3794. if (hdcScreen)
  3795. ReleaseDC(NULL, hdcScreen);
  3796. if (hDstBitmap)
  3797. DeleteObject(hDstBitmap);
  3798. *phDIB = hDIB;
  3799. if (!hDIB)
  3800. TRACE((ERROR_MESSAGE, TEXT("Can't get client's DIB. GetLastError=%d\n"), GetLastError()));
  3801. }
  3802. #ifndef OS_WINCE
  3803. #ifdef OS_WIN32
  3804. DWORD
  3805. __stdcall
  3806. _ClxSendMsgThread(VOID *param)
  3807. {
  3808. while(1)
  3809. {
  3810. if (!g_pClx || WaitForSingleObject(g_pClx->semSendReady, INFINITE) !=
  3811. WAIT_OBJECT_0)
  3812. goto exitpt;
  3813. if (!g_pClx || g_pClx->bSendMsgThreadExit)
  3814. goto exitpt;
  3815. SendMessage(g_pClx->msg.hwnd,
  3816. g_pClx->msg.message,
  3817. g_pClx->msg.wParam,
  3818. g_pClx->msg.lParam);
  3819. // release the owner of the message
  3820. ReleaseSemaphore(g_pClx->semSendCompleted, 1, NULL);
  3821. // release next waiting worker
  3822. ReleaseSemaphore(g_pClx->semSendDone, 1, NULL);
  3823. }
  3824. exitpt:
  3825. return 0;
  3826. }
  3827. /*++
  3828. * Function:
  3829. * _ClxSendMessage
  3830. * Description:
  3831. * Calls SendMessage from separate thread
  3832. * prevents deadlock on SendMessage (#319816)
  3833. *
  3834. * Arguments:
  3835. * hBitmap - the main bitmap
  3836. * ppDIB - pointer to DIB data
  3837. * left, top, right, bottom - describes the rectangle
  3838. * - if all are == -1, returns the whole bitmap
  3839. * Return value:
  3840. * TRUE on success
  3841. * Called by:
  3842. * _ClxWndProc on WM_TIMER message
  3843. --*/
  3844. LRESULT
  3845. _ClxSendMessage(
  3846. HWND hWnd, // handle of destination window
  3847. UINT Msg, // message to send
  3848. WPARAM wParam, // first message parameter
  3849. LPARAM lParam // second message parameter
  3850. )
  3851. {
  3852. LRESULT rv = 0;
  3853. PCLXINFO pClx = g_pClx;
  3854. DWORD dwThreadId;
  3855. if (!pClx)
  3856. goto exitpt;
  3857. if (!pClx->semSendDone)
  3858. pClx->semSendDone = CreateSemaphore(NULL, 1, 10, NULL);
  3859. if (!pClx->semSendReady)
  3860. pClx->semSendReady = CreateSemaphore(NULL, 0, 10, NULL);
  3861. if (!pClx->semSendCompleted)
  3862. pClx->semSendCompleted = CreateSemaphore(NULL, 0, 10, NULL);
  3863. if (!pClx->semSendDone || !pClx->semSendReady || !pClx->semSendCompleted)
  3864. goto exitpt;
  3865. if (!pClx->hSendMsgThread)
  3866. {
  3867. pClx->hSendMsgThread = CreateThread(
  3868. NULL,
  3869. 0,
  3870. _ClxSendMsgThread,
  3871. NULL,
  3872. 0,
  3873. &dwThreadId);
  3874. }
  3875. if (!pClx->hSendMsgThread)
  3876. goto exitpt;
  3877. // Wait 10 mins send to complete
  3878. if (WaitForSingleObject(pClx->semSendDone, 600000) !=
  3879. WAIT_OBJECT_0)
  3880. goto exitpt;
  3881. pClx->msg.hwnd = hWnd;
  3882. pClx->msg.message = Msg;
  3883. pClx->msg.wParam = wParam;
  3884. pClx->msg.lParam = lParam;
  3885. // Signal the thread for available message
  3886. ReleaseSemaphore(pClx->semSendReady, 1, NULL);
  3887. // Wait for the send to complete
  3888. WaitForSingleObject(pClx->semSendCompleted, 600000);
  3889. exitpt:
  3890. return rv;
  3891. }
  3892. VOID
  3893. _ClxDestroySendMsgThread(PCLXINFO pClx)
  3894. {
  3895. if (!pClx)
  3896. goto exitpt;
  3897. if (!pClx->semSendDone || !pClx->semSendReady || !pClx->hSendMsgThread ||
  3898. !pClx->semSendCompleted)
  3899. goto exitpt;
  3900. // Wait 10 mins send to complete
  3901. WaitForSingleObject(pClx->semSendDone, 600000);
  3902. pClx->bSendMsgThreadExit = TRUE;
  3903. // signal the thread to exit
  3904. ReleaseSemaphore(pClx->semSendReady, 1, NULL);
  3905. // wait for the thread to exit
  3906. if (WaitForSingleObject(pClx->hSendMsgThread, 1200000) != WAIT_OBJECT_0)
  3907. {
  3908. TRACE((ERROR_MESSAGE, TEXT("SendThread can't exit, calling TerminateThread\n")));
  3909. TerminateThread(pClx->hSendMsgThread, 0);
  3910. }
  3911. CloseHandle(pClx->hSendMsgThread);
  3912. exitpt:
  3913. if (pClx->semSendCompleted)
  3914. {
  3915. CloseHandle(pClx->semSendCompleted);
  3916. pClx->semSendCompleted = NULL;
  3917. }
  3918. if (pClx->semSendDone)
  3919. {
  3920. CloseHandle(pClx->semSendDone);
  3921. pClx->semSendDone = NULL;
  3922. }
  3923. if (pClx->semSendReady)
  3924. {
  3925. CloseHandle(pClx->semSendReady);
  3926. pClx->semSendReady = NULL;
  3927. }
  3928. pClx->hSendMsgThread = 0;
  3929. ;
  3930. }
  3931. #endif // OS_WIN32
  3932. #endif // !OS_WINCE
  3933. //////////////////////////////////////////////////////////////////////
  3934. //
  3935. // VC Channel support for RCLX mode
  3936. //
  3937. DWORD
  3938. CLXAPI
  3939. CLXDataReceivedVC(
  3940. LPCSTR szChannelName,
  3941. LPVOID pData,
  3942. DWORD dwSize
  3943. )
  3944. {
  3945. DWORD rv = (DWORD)-1;
  3946. PCLXINFO pClx;
  3947. CHAR szName[MAX_VCNAME_LEN];
  3948. PCLXVCHANNEL pVChannel;
  3949. RCLXDATA Response;
  3950. RCLXFEEDPROLOG Prolog;
  3951. BOOL rc;
  3952. // Check if this channel is already registered
  3953. pVChannel = g_pVChannels;
  3954. // find the channel entry
  3955. while(pVChannel && _stricmp(pVChannel->szName, szChannelName))
  3956. {
  3957. pVChannel = pVChannel->pNext;
  3958. }
  3959. if (!pVChannel)
  3960. {
  3961. TRACE((WARNING_MESSAGE, TEXT("Channel %s is not registered\n"), szChannelName));
  3962. goto exitpt;
  3963. }
  3964. if (!IS_RCLX)
  3965. {
  3966. TRACE((WARNING_MESSAGE, TEXT("CLXDataReceivedVC: not in RCLX mode\n")));
  3967. goto exitpt;
  3968. }
  3969. if (!g_pClx)
  3970. {
  3971. TRACE((ERROR_MESSAGE, TEXT("CLXDataReceivedVC: pClx is NULL\n")));
  3972. goto exitpt;
  3973. }
  3974. if (strlen(szChannelName) > MAX_VCNAME_LEN - 1)
  3975. {
  3976. TRACE((ERROR_MESSAGE, TEXT("Channel name \"%s\"bigger than %d chars\n"),
  3977. szChannelName, MAX_VCNAME_LEN));
  3978. goto exitpt;
  3979. }
  3980. pClx = g_pClx;
  3981. Prolog.FeedType = FEED_DATA;
  3982. Prolog.HeadSize = sizeof(Response) + sizeof(szName) + dwSize;
  3983. Prolog.TailSize = 0;
  3984. Response.uiType = DATA_VC;
  3985. Response.uiSize = sizeof(szName) + dwSize;
  3986. strcpy(szName, szChannelName);
  3987. TRACE((ALIVE_MESSAGE,
  3988. TEXT("Sending VC data, DataSize=%d, HeadSize=%d, TailSize=%d, Name=%s\n"),
  3989. dwSize,
  3990. Prolog.HeadSize,
  3991. Prolog.TailSize,
  3992. szName));
  3993. rc = RClx_SendBuffer(pClx->hSocket, &Prolog, sizeof(Prolog));
  3994. rc = rc && RClx_SendBuffer(pClx->hSocket, &Response, sizeof(Response));
  3995. rc = rc && RClx_SendBuffer(pClx->hSocket, szName, sizeof(szName));
  3996. rc = rc && RClx_SendBuffer(pClx->hSocket, pData, dwSize);
  3997. if (!rc)
  3998. {
  3999. TRACE((WARNING_MESSAGE, TEXT("Unable to sent message\n")));
  4000. goto exitpt;
  4001. }
  4002. rv = 0;
  4003. exitpt:
  4004. return rv;
  4005. }
  4006. DWORD
  4007. _CLXSendDataVC(
  4008. LPCSTR szChannelName,
  4009. LPVOID pData,
  4010. DWORD dwSize
  4011. )
  4012. {
  4013. DWORD rv = (DWORD)-1;
  4014. // Check if this channel is already registered
  4015. PCLXVCHANNEL pVChannel = g_pVChannels;
  4016. // find the channel entry
  4017. while(pVChannel && _stricmp(pVChannel->szName, szChannelName))
  4018. {
  4019. pVChannel = pVChannel->pNext;
  4020. }
  4021. if (!pVChannel)
  4022. {
  4023. TRACE((WARNING_MESSAGE, TEXT("Channel %s is not registered\n"), szChannelName));
  4024. goto exitpt;
  4025. }
  4026. ASSERT(pVChannel->pSendDataFn);
  4027. rv = (pVChannel->pSendDataFn)(pData, dwSize);
  4028. exitpt:
  4029. return rv;
  4030. }
  4031. BOOL
  4032. CLXAPI
  4033. ClxRegisterVC(
  4034. LPCSTR szChannelName,
  4035. PCLXVC_SENDDATA pSendData,
  4036. PCLXVC_RECVDATA *ppRecvData
  4037. )
  4038. {
  4039. BOOL rv = FALSE;
  4040. PCLXVCHANNEL pVChannel;
  4041. UINT counter;
  4042. if (!szChannelName || !pSendData || !ppRecvData ||
  4043. strlen(szChannelName) > MAX_VCNAME_LEN - 1)
  4044. {
  4045. TRACE((ERROR_MESSAGE, TEXT("ClxRegisterVC: invalid parameters\n")));
  4046. goto exitpt;
  4047. }
  4048. pVChannel = malloc(sizeof(*pVChannel));
  4049. if (!pVChannel)
  4050. goto exitpt;
  4051. strcpy(pVChannel->szName, szChannelName);
  4052. // zero the rest of the name
  4053. for(counter = strlen(szChannelName); counter < MAX_VCNAME_LEN; counter++)
  4054. pVChannel->szName[counter] = 0;
  4055. pVChannel->pSendDataFn = pSendData;
  4056. *ppRecvData = CLXDataReceivedVC;
  4057. // Push this in the queue
  4058. pVChannel->pNext = g_pVChannels;
  4059. g_pVChannels = pVChannel;
  4060. rv = TRUE;
  4061. exitpt:
  4062. return rv;
  4063. }
  4064. VOID
  4065. CLXAPI
  4066. ClxUnregisterVC(
  4067. LPCSTR szChannelName
  4068. )
  4069. {
  4070. PCLXVCHANNEL pVChannel = g_pVChannels;
  4071. PCLXVCHANNEL pPrev = NULL;
  4072. // find the channel and remove it from the queue
  4073. while(pVChannel && _stricmp(pVChannel->szName, szChannelName))
  4074. {
  4075. pPrev = pVChannel;
  4076. pVChannel = pVChannel->pNext;
  4077. }
  4078. if (!pVChannel)
  4079. {
  4080. TRACE((WARNING_MESSAGE, TEXT("Can't find channel name: %s\n"),
  4081. szChannelName));
  4082. goto exitpt;
  4083. }
  4084. if (!pPrev)
  4085. g_pVChannels = pVChannel->pNext;
  4086. else
  4087. pPrev->pNext = pVChannel->pNext;
  4088. exitpt:
  4089. ;
  4090. }
  4091. //////////////////////////////////////////////////////////////////////