Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1403 lines
47 KiB

  1. /*************************************************************************
  2. * compatfl.c
  3. *
  4. * Routines used to get Citrix application compatibility flags
  5. *
  6. * Copyright (C) 1997-1999 Microsoft Corp.
  7. *************************************************************************/
  8. #include "precomp.h"
  9. #pragma hdrstop
  10. #include <ntverp.h>
  11. typedef VOID (*GETDOSAPPNAME)(LPSTR);
  12. ULONG gCompatFlags = 0xFFFFFFFF;
  13. DWORD gdwAppType = 0;
  14. WCHAR *
  15. Ctx_wcsistr( WCHAR * pString, WCHAR * pPattern )
  16. {
  17. WCHAR * pBuf1;
  18. WCHAR * pBuf2;
  19. WCHAR * pCh;
  20. if ( pString == NULL )
  21. return( NULL );
  22. pBuf1 = RtlAllocateHeap( RtlProcessHeap(), 0, (wcslen(pString) * sizeof(WCHAR)) + sizeof(WCHAR) );
  23. if ( pBuf1 == NULL )
  24. return( NULL );
  25. wcscpy( pBuf1, pString );
  26. pBuf2 = _wcslwr( pBuf1 );
  27. pCh = wcsstr( pBuf2, pPattern );
  28. RtlFreeHeap( RtlProcessHeap(), 0, pBuf1 );
  29. if ( pCh == NULL )
  30. return( NULL );
  31. return( pString + (pCh - pBuf2) );
  32. }
  33. //*****************************************************************************
  34. // GetAppTypeAndModName
  35. //
  36. // Returns the application type and module name of the running application.
  37. //
  38. // Parameters:
  39. // LPDWORD pdwAppType (IN) - (IN optional) ptr to app type
  40. // (OUT) - Application Type
  41. // PWCHAR ModName (OUT) - Module Name
  42. // Length (IN) - Maximum length of ModName including NULL
  43. //
  44. // Return Value:
  45. // TRUE on successfully finding the application name, FALSE otherwise.
  46. //
  47. // Notes:
  48. //
  49. // If the caller knows that this is a win32 app, they can set pdwAppType
  50. // to TERMSRV_COMPAT_WIN32 to save some overhead.
  51. //
  52. //*****************************************************************************
  53. BOOL GetAppTypeAndModName(OUT LPDWORD pdwAppType, OUT PWCHAR ModName, ULONG Length)
  54. {
  55. PWCHAR pwch, pwchext;
  56. WCHAR pwcAppName[MAX_PATH+1];
  57. CHAR pszAppName[MAX_PATH+1];
  58. HANDLE ntvdm = NULL;
  59. GETDOSAPPNAME GetDOSAppNamep = NULL;
  60. ANSI_STRING AnsiString;
  61. UNICODE_STRING UniString;
  62. PRTL_PERTHREAD_CURDIR pRtlInfo;
  63. PRTL_USER_PROCESS_PARAMETERS pUserParam;
  64. // Get the path of the executable name
  65. pUserParam = NtCurrentPeb()->ProcessParameters;
  66. // Get the executable name, if there's no \ just use the name as it is
  67. pwch = wcsrchr(pUserParam->ImagePathName.Buffer, L'\\');
  68. if (pwch) {
  69. pwch++;
  70. } else {
  71. pwch = pUserParam->ImagePathName.Buffer;
  72. }
  73. wcscpy(pwcAppName, pwch);
  74. pwch = pwcAppName;
  75. // If it's not a Win32 app, do the extra work to get the image name
  76. if (!(*pdwAppType & TERMSRV_COMPAT_WIN32)) {
  77. *pdwAppType = TERMSRV_COMPAT_WIN32; // Default to a Win32 app
  78. // Check if it's a DOS or Win16 app by checking if the app is ntvdm.exe
  79. if (!_wcsicmp(pwch, L"ntvdm.exe")) {
  80. pRtlInfo = RtlGetPerThreadCurdir();
  81. // If there's per-thread data, it's a Win16 app
  82. if (pRtlInfo) {
  83. *pdwAppType = TERMSRV_COMPAT_WIN16;
  84. wcscpy(pwcAppName, pRtlInfo->ImageName->Buffer);
  85. } else {
  86. // Load NTVDM
  87. if ((ntvdm = LoadLibrary(L"ntvdm.exe"))) {
  88. // Get the address of GetDOSAppName
  89. if ((GetDOSAppNamep = (GETDOSAPPNAME)GetProcAddress(
  90. ntvdm,
  91. "GetDOSAppName"))) {
  92. RtlInitUnicodeString(&UniString, pwcAppName);
  93. UniString.MaximumLength = MAX_PATH;
  94. //
  95. // Use pszAppName only if not NULL otherwise we are processing the PIF
  96. // so go w/ NTVDM as the name.
  97. //
  98. GetDOSAppNamep(pszAppName);
  99. if (*pszAppName != '\0') {
  100. RtlInitAnsiString(&AnsiString, pszAppName);
  101. RtlAnsiStringToUnicodeString(&UniString,
  102. &AnsiString,
  103. FALSE);
  104. }
  105. pwch = UniString.Buffer;
  106. *pdwAppType = TERMSRV_COMPAT_DOS;
  107. FreeLibrary(ntvdm);
  108. } else {
  109. #if DBG
  110. DbgPrint( "KERNEL32: Couldn't get GetDOSAppName entry point\n" );
  111. #endif
  112. FreeLibrary(ntvdm);
  113. return (FALSE);
  114. }
  115. } else {
  116. #if DBG
  117. DbgPrint( "KERNEL32: Couldn't load ntvdm.exe\n" );
  118. #endif
  119. return(FALSE);
  120. }
  121. }
  122. } else if (!_wcsicmp(pwch, L"os2.exe")) {
  123. *pdwAppType = TERMSRV_COMPAT_OS2;
  124. // Look in the command line for /p, which is fully qualified path
  125. pwch = wcsstr(pUserParam->CommandLine.Buffer, L"/P");
  126. if (!pwch) {
  127. pwch = wcsstr(pUserParam->CommandLine.Buffer, L"/p");
  128. }
  129. if (pwch) {
  130. pwch += 3; // skip over /p and blank
  131. if (pwchext = wcschr(pwch, L' ')) {
  132. wcsncpy(pwcAppName, pwch, (size_t)(pwchext - pwch));
  133. pwcAppName[pwchext - pwch] = L'\0';
  134. } else {
  135. return (FALSE);
  136. }
  137. } else{
  138. return (FALSE);
  139. }
  140. }
  141. // Get rid of the app's path, if necessary
  142. if (pwch = wcsrchr(pwcAppName, L'\\')) {
  143. pwch++;
  144. } else {
  145. pwch = pwcAppName;
  146. }
  147. //
  148. //Set global gdwAppType only if we did the real type checking.
  149. //
  150. gdwAppType = *pdwAppType;
  151. }
  152. // Remove the extension
  153. if (pwchext = wcsrchr(pwch, L'.')) {
  154. *pwchext = '\0';
  155. }
  156. // Copy out the Module name
  157. if (((wcslen(pwch) + 1) * sizeof(WCHAR)) > Length) {
  158. return(FALSE);
  159. }
  160. wcscpy(ModName, pwch);
  161. return(TRUE);
  162. }
  163. //*****************************************************************************
  164. // GetCtxPhysMemoryLimits
  165. //
  166. // Returns the Physical Memory limits for the current application.
  167. //
  168. // Parameters:
  169. // LPDWORD pdwAppType (IN) - (IN optional) ptr to app type
  170. // (OUT) - Application Type
  171. // LPDWORD pdwPhysMemLim (OUT) - Value of physical memory limit
  172. //
  173. // Return Value:
  174. // TRUE on successfully finding a limit, ZERO if no limit.
  175. //
  176. // Notes:
  177. //
  178. // If the caller knows that this is a win32 app, they can set pdwAppType
  179. // to TERMSRV_COMPAT_WIN32 to save some overhead.
  180. //
  181. //*****************************************************************************
  182. ULONG GetCtxPhysMemoryLimits(OUT LPDWORD pdwAppType, OUT LPDWORD pdwPhysMemLim)
  183. {
  184. WCHAR ModName[MAX_PATH+1];
  185. ULONG ulrc = FALSE;
  186. ULONG dwCompatFlags;
  187. *pdwPhysMemLim = 0;
  188. if (!GetAppTypeAndModName(pdwAppType, ModName, sizeof(ModName))) {
  189. goto CtxGetPhysMemReturn;
  190. }
  191. // Get the compatibility flags to look for memory limits flag
  192. ulrc = GetTermsrCompatFlags(ModName, &dwCompatFlags, CompatibilityApp);
  193. if ( ulrc & ((dwCompatFlags & TERMSRV_COMPAT_PHYSMEMLIM ) &&
  194. (dwCompatFlags & *pdwAppType)) ) {
  195. NTSTATUS NtStatus;
  196. OBJECT_ATTRIBUTES ObjectAttributes;
  197. UNICODE_STRING UniString;
  198. HKEY hKey = 0;
  199. ULONG ul, ulcbuf;
  200. ULONG DataLen;
  201. PKEY_VALUE_PARTIAL_INFORMATION pKeyValInfo = NULL;
  202. LPWSTR UniBuff = NULL;
  203. RtlInitUnicodeString( &UniString, NULL ); // we test for this below
  204. ulrc = TRUE;
  205. *pdwPhysMemLim = TERMSRV_COMPAT_DEFAULT_PHYSMEMLIM;
  206. ul = sizeof(TERMSRV_COMPAT_APP) + (wcslen(ModName) + 1)*sizeof(WCHAR);
  207. UniBuff = RtlAllocateHeap(RtlProcessHeap(),
  208. 0,
  209. ul);
  210. if (UniBuff) {
  211. wcscpy(UniBuff, TERMSRV_COMPAT_APP);
  212. wcscat(UniBuff, ModName);
  213. RtlInitUnicodeString(&UniString, UniBuff);
  214. }
  215. // Determine the value info buffer size
  216. ulcbuf = sizeof(KEY_VALUE_FULL_INFORMATION) + MAX_PATH*sizeof(WCHAR) +
  217. sizeof(ULONG);
  218. pKeyValInfo = RtlAllocateHeap(RtlProcessHeap(),
  219. 0,
  220. ulcbuf);
  221. // Did everything initialize OK?
  222. if (UniString.Buffer && pKeyValInfo) {
  223. InitializeObjectAttributes(&ObjectAttributes,
  224. &UniString,
  225. OBJ_CASE_INSENSITIVE,
  226. NULL,
  227. NULL
  228. );
  229. NtStatus = NtOpenKey(&hKey, KEY_READ, &ObjectAttributes);
  230. if (NT_SUCCESS(NtStatus)) {
  231. RtlInitUnicodeString(&UniString, TERMSRV_PHYSMEMLIM );
  232. NtStatus = NtQueryValueKey(hKey,
  233. &UniString,
  234. KeyValuePartialInformation,
  235. pKeyValInfo,
  236. ulcbuf,
  237. &DataLen);
  238. if (NT_SUCCESS(NtStatus) && (REG_DWORD == pKeyValInfo->Type)) {
  239. *pdwPhysMemLim = *(PULONG)pKeyValInfo->Data;
  240. ulrc = TRUE;
  241. }
  242. NtClose(hKey);
  243. }
  244. }
  245. // Free up the buffers we allocated
  246. // Need to zero out the buffers, because some apps (MS Internet Assistant)
  247. // won't install if the heap is not zero filled.
  248. if (UniBuff) {
  249. memset(UniBuff, 0, ul);
  250. RtlFreeHeap( RtlProcessHeap(), 0, UniBuff );
  251. }
  252. if (pKeyValInfo) {
  253. memset(pKeyValInfo, 0, ulcbuf);
  254. RtlFreeHeap( RtlProcessHeap(), 0, pKeyValInfo );
  255. }
  256. }
  257. else {
  258. ulrc = FALSE;
  259. }
  260. CtxGetPhysMemReturn:
  261. //#if DBG
  262. //DbgPrint("CtxGetPhysMemLim returning %d; PhysMemLim=%d\n", ulrc, *pdwPhysMemLim);
  263. //#endif
  264. return(ulrc);
  265. }
  266. //*****************************************************************************
  267. // GetCtxAppCompatFlags -
  268. //
  269. // Returns the Citrix compatibility flags for the current application.
  270. //
  271. // Parameters:
  272. // LPDWORD pdwCompatFlags (OUT) - Ptr to DWORD return value for flags
  273. // LPDWORD pdwAppType (IN) - (IN optional) ptr to app type
  274. // (OUT) - Application Type
  275. //
  276. // Return Value:
  277. // TRUE on success, FALSE on failure.
  278. //
  279. // Notes:
  280. //
  281. // If the caller knows that this is a win32 app, they can set pdwAppType
  282. // to TERMSRV_COMPAT_WIN32 to save some overhead.
  283. //
  284. // Flag values are defined in syslib.h:
  285. //
  286. // TERMSRV_COMPAT_DOS - Compatibility flags are for DOS app
  287. // TERMSRV_COMPAT_OS2 - Compatibility flags are for OS2 app
  288. // TERMSRV_COMPAT_WIN16 - Compatibility flags are for Win16 app
  289. // TERMSRV_COMPAT_WIN32 - Compatibility flags are for Win32 app
  290. // TERMSRV_COMPAT_ALL - Compatibility flags are for any app
  291. // TERMSRV_COMPAT_USERNAME - Return Username instead of Computername
  292. // TERMSRV_COMPAT_MSBLDNUM - Return MS build number, not Citrix build no.
  293. // TERMSRV_COMPAT_INISYNC - Sync user ini file with system version
  294. //*****************************************************************************
  295. ULONG GetCtxAppCompatFlags(OUT LPDWORD pdwCompatFlags, OUT LPDWORD pdwAppType)
  296. {
  297. WCHAR ModName[MAX_PATH+1];
  298. if((gCompatFlags != 0xFFFFFFFF) && (gdwAppType == TERMSRV_COMPAT_WIN32))
  299. {
  300. *pdwCompatFlags = gCompatFlags;
  301. *pdwAppType = gdwAppType;
  302. return (TRUE);
  303. }
  304. if (!GetAppTypeAndModName(pdwAppType, ModName, sizeof(ModName))) {
  305. return (FALSE);
  306. }
  307. // Get the flags
  308. return (GetTermsrCompatFlags(ModName, pdwCompatFlags, CompatibilityApp));
  309. }
  310. //*****************************************************************************
  311. // GetTermsrCompatFlags -
  312. //
  313. // Returns the Citrix compatibility flags for the specified task.
  314. //
  315. // Parameters:
  316. // LPWSTR lpModName (IN) - Image name to look up in registry
  317. // LPDWORD pdwCompatFlags (OUT) - Ptr to DWORD return value for flags
  318. // TERMSRV_COMPATIBILITY_CLASS CompatType (IN) - Indicates app or inifile
  319. //
  320. // Return Value:
  321. // TRUE on success, FALSE on failure.
  322. //
  323. // Notes:
  324. // Assumes it's being called in the context of the current application -
  325. // we use the current Teb to get the compatibility flags.
  326. //
  327. // Flag values are defined in syslib.h.
  328. //
  329. //*****************************************************************************
  330. ULONG GetTermsrCompatFlags(LPWSTR lpModName,
  331. LPDWORD pdwCompatFlags,
  332. TERMSRV_COMPATIBILITY_CLASS CompatType)
  333. {
  334. NTSTATUS NtStatus;
  335. OBJECT_ATTRIBUTES ObjectAttributes;
  336. UNICODE_STRING UniString;
  337. HKEY hKey = 0;
  338. ULONG ul, ulcbuf;
  339. PKEY_VALUE_PARTIAL_INFORMATION pKeyValInfo = NULL;
  340. ULONG ulRetCode = FALSE;
  341. LPWSTR UniBuff = NULL;
  342. *pdwCompatFlags = 0;
  343. // If terminal services aren't enabled, just return
  344. if (!IsTerminalServer()) {
  345. return(TRUE);
  346. }
  347. UniString.Buffer = NULL;
  348. if (CompatType == CompatibilityApp) {
  349. if (gCompatFlags != 0xFFFFFFFF) {
  350. //DbgPrint( "GetTermsrCompatFlags: Return cached compatflags (gCompatFlags)%lx for app %ws\n",gCompatFlags,lpModName );
  351. *pdwCompatFlags = gCompatFlags;
  352. return TRUE;
  353. }
  354. // Look and see if the compat flags in the Teb are valid (right now
  355. // they're only valid for Win16 apps). Don't set them for DOS apps
  356. // unless you can have a mechanism to have unique values for each
  357. // DOS app in a VDM.
  358. // if (wcsstr(NtCurrentPeb()->ProcessParameters->ImagePathName.Buffer, L"ntvdm.exe")) {
  359. // PVOID Ra;
  360. // ASSERT(gpTermsrvTlsIndex != 0xFFFFFFFF);
  361. // Ra = TlsGetValue( gpTermsrvTlsIndex );
  362. // if (Ra != NULL) {
  363. // //DbgPrint( "GetTermsrCompatFlags: Return cached compatflags (Ra)%lx for app %ws\n",Ra,lpModName );
  364. // *pdwCompatFlags = (DWORD)PtrToUlong(Ra);
  365. // return TRUE;
  366. // }
  367. // }
  368. #if 0
  369. if (NtCurrentTeb()->CtxCompatFlags & TERMSRV_COMPAT_TEBVALID) {
  370. *pdwCompatFlags = NtCurrentTeb()->CtxCompatFlags;
  371. return(TRUE);
  372. }
  373. #endif
  374. ul = sizeof(TERMSRV_COMPAT_APP) + (wcslen(lpModName) + 1)*sizeof(WCHAR);
  375. UniBuff = RtlAllocateHeap(RtlProcessHeap(),
  376. 0,
  377. ul);
  378. if (UniBuff) {
  379. wcscpy(UniBuff, TERMSRV_COMPAT_APP);
  380. wcscat(UniBuff, lpModName);
  381. RtlInitUnicodeString(&UniString, UniBuff);
  382. }
  383. } else {
  384. RtlInitUnicodeString(&UniString,
  385. (CompatType == CompatibilityIniFile) ?
  386. TERMSRV_COMPAT_INIFILE : TERMSRV_COMPAT_REGENTRY
  387. );
  388. }
  389. // Determine the value info buffer size
  390. ulcbuf = sizeof(KEY_VALUE_FULL_INFORMATION) + MAX_PATH*sizeof(WCHAR) +
  391. sizeof(ULONG);
  392. pKeyValInfo = RtlAllocateHeap(RtlProcessHeap(),
  393. 0,
  394. ulcbuf);
  395. // Did everything initialize OK?
  396. if (UniString.Buffer && pKeyValInfo) {
  397. InitializeObjectAttributes(&ObjectAttributes,
  398. &UniString,
  399. OBJ_CASE_INSENSITIVE,
  400. NULL,
  401. NULL
  402. );
  403. NtStatus = NtOpenKey(&hKey, KEY_READ, &ObjectAttributes);
  404. if (NT_SUCCESS(NtStatus)) {
  405. // If we're not checking for a registry entry, just try to get
  406. // the value for the key
  407. if (CompatType != CompatibilityRegEntry) {
  408. RtlInitUnicodeString(&UniString,
  409. CompatType == CompatibilityApp ? COMPAT_FLAGS : lpModName);
  410. NtStatus = NtQueryValueKey(hKey,
  411. &UniString,
  412. KeyValuePartialInformation,
  413. pKeyValInfo,
  414. ulcbuf,
  415. &ul);
  416. if (NT_SUCCESS(NtStatus) && (REG_DWORD == pKeyValInfo->Type)) {
  417. *pdwCompatFlags = *(PULONG)pKeyValInfo->Data;
  418. ulRetCode = TRUE;
  419. }
  420. //
  421. // Cache the appcompatiblity flags
  422. //
  423. // if (CompatType == CompatibilityApp) {
  424. // if (wcsstr(NtCurrentPeb()->ProcessParameters->ImagePathName.Buffer, L"ntvdm.exe")) {
  425. // TlsSetValue(gpTermsrvTlsIndex,(PVOID)((*pdwCompatFlags)| TERMSRV_COMPAT_TEBVALID));
  426. // //DbgPrint( "GetTermsrCompatFlags: Setting cached compatflags (gCompatFlags)%lx for WOW app %ws\n",((*pdwCompatFlags)| TERMSRV_COMPAT_TEBVALID),lpModName );
  427. // } else {
  428. // gCompatFlags = *pdwCompatFlags;
  429. // //DbgPrint( "GetTermsrCompatFlags: Setting cached compatflags (gCompatFlags)%lx for app %ws\n",gCompatFlags,lpModName );
  430. // }
  431. // }
  432. if (CompatType == CompatibilityApp) {
  433. if(!gdwAppType) {
  434. DWORD dwTmp = 0;
  435. GetAppTypeAndModName(&dwTmp, NULL, 0);
  436. }
  437. if (gdwAppType == TERMSRV_COMPAT_WIN32) {
  438. gCompatFlags = *pdwCompatFlags;
  439. }
  440. }
  441. // For registry keys, we need to enumerate all of the keys, and
  442. // check if the the substring matches our current path.
  443. } else {
  444. PWCH pwch;
  445. ULONG ulKey = 0;
  446. PKEY_VALUE_FULL_INFORMATION pKeyFullInfo;
  447. pKeyFullInfo = (PKEY_VALUE_FULL_INFORMATION)pKeyValInfo;
  448. // Get to the software section
  449. pwch = Ctx_wcsistr(lpModName, L"\\software");
  450. // Skip past the next backslash
  451. if (pwch) {
  452. pwch = wcschr(pwch + 1, L'\\');
  453. }
  454. // We don't need to look for a key if this isn't in the user
  455. // software section
  456. if (pwch) {
  457. // Skip over the leading backslash
  458. pwch++;
  459. // Go through each value, looking for this path
  460. while (NtEnumerateValueKey(hKey,
  461. ulKey++,
  462. KeyValueFullInformation,
  463. pKeyFullInfo,
  464. ulcbuf,
  465. &ul) == STATUS_SUCCESS) {
  466. if (!_wcsnicmp(pKeyFullInfo->Name,
  467. pwch,
  468. pKeyFullInfo->NameLength/sizeof(WCHAR))) {
  469. *pdwCompatFlags = *(PULONG)((PCHAR)pKeyFullInfo +
  470. pKeyFullInfo->DataOffset);
  471. ulRetCode = TRUE;
  472. break;
  473. }
  474. }
  475. }
  476. }
  477. NtClose(hKey);
  478. } else {
  479. if (NtStatus == STATUS_OBJECT_NAME_NOT_FOUND &&
  480. CompatType == CompatibilityApp) {
  481. if(!gdwAppType) {
  482. DWORD dwTmp = 0;
  483. GetAppTypeAndModName(&dwTmp, NULL, 0);
  484. }
  485. if (gdwAppType == TERMSRV_COMPAT_WIN32) {
  486. gCompatFlags = 0;
  487. ulRetCode = TRUE;
  488. }
  489. }
  490. }
  491. }
  492. // Free up the buffers we allocated
  493. // Need to zero out the buffers, because some apps (MS Internet Assistant)
  494. // won't install if the heap is not zero filled.
  495. if (UniBuff) {
  496. memset(UniBuff, 0, UniString.MaximumLength);
  497. RtlFreeHeap( RtlProcessHeap(), 0, UniBuff );
  498. }
  499. if (pKeyValInfo) {
  500. memset(pKeyValInfo, 0, ulcbuf);
  501. RtlFreeHeap( RtlProcessHeap(), 0, pKeyValInfo );
  502. }
  503. return(ulRetCode);
  504. }
  505. //*****************************************************************************
  506. // CtxGetBadAppFlags -
  507. //
  508. // Gets the Citrix badapp and compatibility flags for the specified task.
  509. //
  510. // Parameters:
  511. // LPWSTR lpModName (IN) - Image name to look up in registry
  512. // PBADAPP pBadApp (OUT) - Structure to used to return flags
  513. //
  514. // Return Value:
  515. // TRUE on success, FALSE on failure.
  516. //
  517. // Flag values are defined in syslib.h.
  518. //
  519. //*****************************************************************************
  520. BOOL CtxGetBadAppFlags(LPWSTR lpModName, PBADAPP pBadApp)
  521. {
  522. NTSTATUS NtStatus;
  523. OBJECT_ATTRIBUTES ObjectAttributes;
  524. UNICODE_STRING UniString;
  525. HKEY hKey = 0;
  526. ULONG ul, ulcnt, ulcbuf, ulrc = FALSE;
  527. PKEY_VALUE_PARTIAL_INFORMATION pKeyValueInfo = NULL;
  528. LPWSTR UniBuff;
  529. PWCHAR pwch;
  530. static ULONG badappregdefaults[3] = {1,15,5};
  531. static BOOL fgotdefaults = FALSE;
  532. WCHAR *pbadappNameValue[] = {
  533. COMPAT_MSGQBADAPPSLEEPTIMEINMILLISEC,
  534. COMPAT_FIRSTCOUNTMSGQPEEKSSLEEPBADAPP,
  535. COMPAT_NTHCOUNTMSGQPEEKSSLEEPBADAPP,
  536. COMPAT_FLAGS
  537. };
  538. // Get the executable name only, no path.
  539. pwch = wcsrchr(lpModName, L'\\');
  540. if (pwch) {
  541. pwch++;
  542. } else {
  543. pwch = lpModName;
  544. }
  545. // Get the buffers we need
  546. ul = sizeof(TERMSRV_COMPAT_APP) + (wcslen(pwch) + 1)*sizeof(WCHAR);
  547. UniBuff = RtlAllocateHeap(RtlProcessHeap(), 0, ul);
  548. ulcbuf = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG);
  549. pKeyValueInfo = RtlAllocateHeap(RtlProcessHeap(), 0, ulcbuf);
  550. if (UniBuff && pKeyValueInfo) {
  551. if (!fgotdefaults) {
  552. // Get the default values from the registry
  553. RtlInitUnicodeString(&UniString,
  554. TERMSRV_REG_CONTROL_NAME
  555. );
  556. InitializeObjectAttributes(&ObjectAttributes,
  557. &UniString,
  558. OBJ_CASE_INSENSITIVE,
  559. NULL,
  560. NULL
  561. );
  562. NtStatus = NtOpenKey(&hKey, KEY_READ, &ObjectAttributes);
  563. if (NT_SUCCESS(NtStatus)) {
  564. for (ulcnt = 0; ulcnt < 3; ulcnt++) {
  565. RtlInitUnicodeString(&UniString, pbadappNameValue[ulcnt]);
  566. NtStatus = NtQueryValueKey(hKey,
  567. &UniString,
  568. KeyValuePartialInformation,
  569. pKeyValueInfo,
  570. ulcbuf,
  571. &ul);
  572. if (NT_SUCCESS(NtStatus) &&
  573. (REG_DWORD == pKeyValueInfo->Type)) {
  574. badappregdefaults[ulcnt] = *(PULONG)pKeyValueInfo->Data;
  575. }
  576. }
  577. NtClose(hKey);
  578. }
  579. fgotdefaults = TRUE;
  580. }
  581. wcscpy(UniBuff, TERMSRV_COMPAT_APP);
  582. wcscat(UniBuff, pwch);
  583. // Remove the extension
  584. if (pwch = wcsrchr(UniBuff, L'.')) {
  585. *pwch = '\0';
  586. }
  587. RtlInitUnicodeString(&UniString,
  588. UniBuff
  589. );
  590. InitializeObjectAttributes(&ObjectAttributes,
  591. &UniString,
  592. OBJ_CASE_INSENSITIVE,
  593. NULL,
  594. NULL
  595. );
  596. NtStatus = NtOpenKey(&hKey, KEY_READ, &ObjectAttributes);
  597. if (NT_SUCCESS(NtStatus)) {
  598. ulrc = TRUE;
  599. for (ulcnt = 0; ulcnt < 4; ulcnt++) {
  600. RtlInitUnicodeString(&UniString, pbadappNameValue[ulcnt]);
  601. NtStatus = NtQueryValueKey(hKey,
  602. &UniString,
  603. KeyValuePartialInformation,
  604. pKeyValueInfo,
  605. ulcbuf,
  606. &ul);
  607. if (NT_SUCCESS(NtStatus) &&
  608. (REG_DWORD == pKeyValueInfo->Type)) {
  609. switch (ulcnt) {
  610. case 0:
  611. pBadApp->BadAppTimeDelay =
  612. RtlEnlargedIntegerMultiply(
  613. *(PULONG)pKeyValueInfo->Data,
  614. -10000 );
  615. break;
  616. case 1:
  617. pBadApp->BadAppFirstCount =
  618. *(PULONG)pKeyValueInfo->Data;
  619. break;
  620. case 2:
  621. pBadApp->BadAppNthCount =
  622. *(PULONG)pKeyValueInfo->Data;
  623. break;
  624. case 3:
  625. pBadApp->BadAppFlags =
  626. *(PULONG)pKeyValueInfo->Data;
  627. break;
  628. }
  629. } else {
  630. switch (ulcnt) {
  631. case 0:
  632. pBadApp->BadAppTimeDelay =
  633. RtlEnlargedIntegerMultiply(
  634. badappregdefaults[ulcnt],
  635. -10000 );
  636. break;
  637. case 1:
  638. pBadApp->BadAppFirstCount = badappregdefaults[ulcnt];
  639. break;
  640. case 2:
  641. pBadApp->BadAppNthCount = badappregdefaults[ulcnt];
  642. break;
  643. case 3:
  644. pBadApp->BadAppFlags = 0;
  645. break;
  646. }
  647. }
  648. }
  649. NtClose(hKey);
  650. }
  651. }
  652. // Free the memory we allocated
  653. // Need to zero out the buffers, because some apps (MS Internet Assistant)
  654. // won't install if the heap is not zero filled.
  655. if (UniBuff) {
  656. memset(UniBuff, 0, UniString.MaximumLength);
  657. RtlFreeHeap( RtlProcessHeap(), 0, UniBuff );
  658. }
  659. if (pKeyValueInfo) {
  660. memset(pKeyValueInfo, 0, ulcbuf);
  661. RtlFreeHeap( RtlProcessHeap(), 0, pKeyValueInfo );
  662. }
  663. return(ulrc);
  664. }
  665. //*****************************************************************************
  666. // GetCitrixCompatClipboardFlags -
  667. //
  668. // Returns the Citrix compatibility clipboard flags for the specified
  669. // application
  670. //
  671. // Parameters:
  672. // LPWSTR lpModName (IN) - Image name to look up in registry
  673. // LPDWORD pdwCompatFlags (OUT) - Ptr to DWORD return value for clipboard flags
  674. //
  675. // Return Value:
  676. // TRUE on success, FALSE on failure.
  677. //
  678. // Notes:
  679. // Flag values are defined in syslib.h.
  680. //
  681. //*****************************************************************************
  682. ULONG
  683. GetCitrixCompatClipboardFlags(LPWSTR lpModName,
  684. LPDWORD pdwClipboardFlags)
  685. {
  686. NTSTATUS NtStatus;
  687. OBJECT_ATTRIBUTES ObjectAttributes;
  688. UNICODE_STRING UniString;
  689. HKEY hKey = 0;
  690. ULONG ul, ulcbuf;
  691. PKEY_VALUE_PARTIAL_INFORMATION pKeyValInfo = NULL;
  692. ULONG ulRetCode = FALSE;
  693. LPWSTR UniBuff = NULL;
  694. UniString.Buffer = NULL;
  695. ul = sizeof(TERMSRV_COMPAT_APP) + (wcslen(lpModName) + 1)*sizeof(WCHAR);
  696. UniBuff = RtlAllocateHeap(RtlProcessHeap(),
  697. 0,
  698. ul);
  699. if (UniBuff) {
  700. wcscpy(UniBuff, TERMSRV_COMPAT_APP);
  701. wcscat(UniBuff, lpModName);
  702. RtlInitUnicodeString(&UniString, UniBuff);
  703. }
  704. // Determine the value info buffer size
  705. ulcbuf = sizeof(KEY_VALUE_FULL_INFORMATION) + MAX_PATH*sizeof(WCHAR) +
  706. sizeof(ULONG);
  707. pKeyValInfo = RtlAllocateHeap(RtlProcessHeap(),
  708. 0,
  709. ulcbuf);
  710. // Did everything initialize OK?
  711. if (UniString.Buffer && pKeyValInfo) {
  712. InitializeObjectAttributes(&ObjectAttributes,
  713. &UniString,
  714. OBJ_CASE_INSENSITIVE,
  715. NULL,
  716. NULL
  717. );
  718. NtStatus = NtOpenKey(&hKey, KEY_READ, &ObjectAttributes);
  719. if (NT_SUCCESS(NtStatus)) {
  720. RtlInitUnicodeString(&UniString, COMPAT_CLIPBOARDFLAGS );
  721. NtStatus = NtQueryValueKey(hKey,
  722. &UniString,
  723. KeyValuePartialInformation,
  724. pKeyValInfo,
  725. ulcbuf,
  726. &ul);
  727. if (NT_SUCCESS(NtStatus) && (REG_DWORD == pKeyValInfo->Type)) {
  728. *pdwClipboardFlags = *(PULONG)pKeyValInfo->Data;
  729. ulRetCode = TRUE;
  730. }
  731. NtClose(hKey);
  732. }
  733. }
  734. // Free up the buffers we allocated
  735. // Need to zero out the buffers, because some apps (MS Internet Assistant)
  736. // won't install if the heap is not zero filled.
  737. if (UniBuff) {
  738. memset(UniBuff, 0, UniString.MaximumLength);
  739. RtlFreeHeap( RtlProcessHeap(), 0, UniBuff );
  740. }
  741. if (pKeyValInfo) {
  742. memset(pKeyValInfo, 0, ulcbuf);
  743. RtlFreeHeap( RtlProcessHeap(), 0, pKeyValInfo );
  744. }
  745. return(ulRetCode);
  746. }
  747. //*****************************************************************************
  748. // CitrixGetAppModuleName -
  749. //
  750. // Extracts the module name for a given process handle. The directory
  751. // path and the file extension are stripped off.
  752. //
  753. // Parameters:
  754. // HANDLE ProcHnd (IN) - Handle to the process
  755. // LPWSTR buffer (IN) - buffer used to return the module
  756. // LPWSTR lpModName (IN) - Available size of the buffer in bytes
  757. // LPDWORD pdwCompatFlags (OUT) - Ptr to DWORD return value for clipboard flags
  758. //
  759. // Return Value:
  760. // TRUE on success, FALSE on failure.
  761. //
  762. // Notes:
  763. // Function only works for 32 bit windows applications
  764. //
  765. //*****************************************************************************
  766. BOOLEAN
  767. CitrixGetAppModuleName ( HANDLE ProcHnd, LPWSTR Buffer, ULONG Length )
  768. {
  769. PROCESS_BASIC_INFORMATION ProcInfo;
  770. ULONG retLen;
  771. PEB peb;
  772. RTL_USER_PROCESS_PARAMETERS params;
  773. WCHAR pwcAppName[MAX_PATH];
  774. PWCHAR pwch;
  775. if ( NtQueryInformationProcess( ProcHnd, ProcessBasicInformation,
  776. (PVOID) &ProcInfo, sizeof(ProcInfo),
  777. &retLen ) ) {
  778. return ( FALSE );
  779. }
  780. if ( !ProcInfo.PebBaseAddress ) {
  781. return ( FALSE );
  782. }
  783. if ( ! ReadProcessMemory(ProcHnd, (PVOID)ProcInfo.PebBaseAddress, &peb,
  784. sizeof(peb), NULL ) ) {
  785. return ( FALSE );
  786. }
  787. if ( !ReadProcessMemory(ProcHnd, peb.ProcessParameters, &params,
  788. sizeof(params), NULL ) ) {
  789. return ( FALSE );
  790. }
  791. if ( !ReadProcessMemory( ProcHnd, params.ImagePathName.Buffer, pwcAppName,
  792. sizeof(pwcAppName), NULL) ) {
  793. return ( FALSE );
  794. }
  795. pwch = wcsrchr(pwcAppName, L'\\');
  796. if ( pwch ) {
  797. pwch++;
  798. }
  799. else {
  800. pwch = pwcAppName;
  801. }
  802. if ( wcslen(pwch) >= (Length / sizeof(WCHAR)) ) {
  803. return ( FALSE );
  804. }
  805. wcscpy(Buffer, pwch);
  806. // Remove the extension
  807. if (pwch = wcsrchr(Buffer, L'.')) {
  808. *pwch = '\0';
  809. }
  810. return ( TRUE );
  811. }
  812. // Globals for logging
  813. // We cache the compatibility flags for the running 32 bit app.
  814. // If the logging is enabled for ntvdm, we'll check the flags of the
  815. // Win16 or DOS app on each object create.
  816. DWORD CompatFlags = 0;
  817. BOOL CompatGotFlags = FALSE;
  818. DWORD CompatAppType = TERMSRV_COMPAT_WIN32;
  819. void CtxLogObjectCreate(PUNICODE_STRING ObjName, PCHAR ObjType,
  820. PVOID RetAddr)
  821. {
  822. CHAR RecBuf[2 * MAX_PATH];
  823. CHAR ObjNameA[MAX_PATH];
  824. PCHAR DllName;
  825. WCHAR FileName[MAX_PATH];
  826. WCHAR ModName[MAX_PATH];
  827. ANSI_STRING AnsiString;
  828. PRTL_PROCESS_MODULES LoadedModules;
  829. PRTL_PROCESS_MODULE_INFORMATION Module;
  830. HANDLE LogFile;
  831. OVERLAPPED Overlapped;
  832. NTSTATUS Status;
  833. ULONG i;
  834. DWORD BytesWritten;
  835. DWORD lCompatFlags; // For Win16 or DOS Apps
  836. DWORD AppType = 0;
  837. ULONG AllocSize = 4096;
  838. BOOL NameFound = FALSE;
  839. // Determine the log file name
  840. if (GetEnvironmentVariableW(OBJ_LOG_PATH_VAR, FileName, MAX_PATH)) {
  841. if (GetAppTypeAndModName(&AppType,ModName,sizeof(ModName))) {
  842. if (AppType != TERMSRV_COMPAT_WIN32 ) {
  843. // Logging was enabled for ntvdm - check the
  844. // compatibility flags of the Win16 or DOS app
  845. if (!GetTermsrCompatFlags(ModName,
  846. &lCompatFlags,
  847. CompatibilityApp) ||
  848. !(lCompatFlags & TERMSRV_COMPAT_LOGOBJCREATE))
  849. return;
  850. }
  851. if ((wcslen(FileName) + wcslen(ModName) + 2) <= MAX_PATH) {
  852. lstrcatW(FileName, L"\\");
  853. lstrcatW(FileName,ModName);
  854. lstrcatW(FileName,L".log");
  855. } else
  856. return;
  857. } else
  858. return;
  859. } else
  860. return;
  861. //Format the log record
  862. AnsiString.Buffer = ObjNameA;
  863. AnsiString.MaximumLength = MAX_PATH;
  864. RtlUnicodeStringToAnsiString(&AnsiString, ObjName, FALSE);
  865. // Try to get the DLL name of the caller
  866. AllocSize = 4096;
  867. for (;;) {
  868. LoadedModules = (PRTL_PROCESS_MODULES)
  869. RtlAllocateHeap(RtlProcessHeap(), 0, AllocSize);
  870. if (!LoadedModules) {
  871. return;
  872. }
  873. Status = LdrQueryProcessModuleInformation(LoadedModules, AllocSize, NULL);
  874. if (NT_SUCCESS(Status)) {
  875. break;
  876. }
  877. if (Status == STATUS_INFO_LENGTH_MISMATCH) {
  878. RtlFreeHeap( RtlProcessHeap(), 0, LoadedModules );
  879. LoadedModules = NULL;
  880. AllocSize += 4096;
  881. continue;
  882. }
  883. // Other error;
  884. RtlFreeHeap( RtlProcessHeap(), 0, LoadedModules );
  885. return;
  886. }
  887. for (i=0,Module = &LoadedModules->Modules[0];
  888. i<LoadedModules->NumberOfModules;
  889. i++, Module++ ) {
  890. if ((RetAddr >= Module->ImageBase) &&
  891. ((ULONG_PTR) RetAddr < (((ULONG_PTR)Module->ImageBase) + Module->ImageSize))) {
  892. NameFound = TRUE;
  893. DllName = Module->FullPathName;
  894. break;
  895. }
  896. }
  897. if (!NameFound) {
  898. DllName = "DLL Not Found";
  899. }
  900. sprintf(RecBuf,"Create %s name: %s Return Addr: %p (%s)\n",
  901. ObjType, ObjNameA, RetAddr, DllName);
  902. if (LoadedModules) {
  903. RtlFreeHeap( RtlProcessHeap(), 0, LoadedModules );
  904. LoadedModules = NULL;
  905. }
  906. // Write log record
  907. if ((LogFile = CreateFileW(FileName, GENERIC_WRITE,
  908. FILE_SHARE_WRITE,
  909. NULL, OPEN_ALWAYS, 0, NULL)) ==
  910. INVALID_HANDLE_VALUE ) {
  911. return;
  912. }
  913. // Lock the file exclusive since we always write at the end.
  914. // We get mutual exclusion by always locking the first 64k bytes
  915. Overlapped.Offset = 0;
  916. Overlapped.OffsetHigh = 0;
  917. Overlapped.hEvent = NULL;
  918. LockFileEx(LogFile, LOCKFILE_EXCLUSIVE_LOCK, 0, 0x10000, 0, &Overlapped);
  919. // Write at the end of the file
  920. SetFilePointer(LogFile, 0, NULL, FILE_END);
  921. WriteFile(LogFile, RecBuf, strlen(RecBuf), &BytesWritten, NULL);
  922. UnlockFileEx(LogFile, 0, 0x10000, 0, &Overlapped);
  923. CloseHandle(LogFile);
  924. }
  925. //*****************************************************************************
  926. // CtxGetCrossWinStationDebug -
  927. //
  928. // Gets the Citrix Cross Winstation debug flag
  929. //
  930. // Parameters:
  931. // NONE
  932. // Return Value:
  933. // TRUE Cross WinStation Debug enabled
  934. // FALSE CrosS WinStation Debug Disabled
  935. //
  936. //
  937. //*****************************************************************************
  938. BOOL CtxGetCrossWinStationDebug()
  939. {
  940. NTSTATUS NtStatus;
  941. OBJECT_ATTRIBUTES ObjectAttributes;
  942. UNICODE_STRING UniString;
  943. HKEY hKey = 0;
  944. ULONG ul, ulcnt, ulcbuf, ulrc = FALSE;
  945. PKEY_VALUE_PARTIAL_INFORMATION pKeyValueInfo = NULL;
  946. LPWSTR UniBuff;
  947. ULONG Flag = 0;
  948. // Get the buffers we need
  949. ul = sizeof(TERMSRV_REG_CONTROL_NAME);
  950. UniBuff = RtlAllocateHeap(RtlProcessHeap(), 0, ul);
  951. ulcbuf = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG);
  952. pKeyValueInfo = RtlAllocateHeap(RtlProcessHeap(), 0, ulcbuf);
  953. if (UniBuff && pKeyValueInfo) {
  954. RtlInitUnicodeString(&UniString, TERMSRV_REG_CONTROL_NAME );
  955. InitializeObjectAttributes(&ObjectAttributes,
  956. &UniString,
  957. OBJ_CASE_INSENSITIVE,
  958. NULL,
  959. NULL
  960. );
  961. NtStatus = NtOpenKey(&hKey, KEY_READ, &ObjectAttributes);
  962. if (NT_SUCCESS(NtStatus)) {
  963. RtlInitUnicodeString(&UniString, TERMSRV_CROSS_WINSTATION_DEBUG);
  964. NtStatus = NtQueryValueKey(hKey,
  965. &UniString,
  966. KeyValuePartialInformation,
  967. pKeyValueInfo,
  968. ulcbuf,
  969. &ul);
  970. if ( NT_SUCCESS(NtStatus) ) {
  971. if ( REG_DWORD == pKeyValueInfo->Type ) {
  972. Flag = *(PULONG)pKeyValueInfo->Data;
  973. }
  974. }
  975. NtClose(hKey);
  976. }
  977. }
  978. // Free the memory we allocated
  979. // Need to zero out the buffers, because some apps (MS Internet Assistant)
  980. // won't install if the heap is not zero filled.
  981. if (UniBuff) {
  982. memset(UniBuff, 0, UniString.MaximumLength);
  983. RtlFreeHeap( RtlProcessHeap(), 0, UniBuff );
  984. }
  985. if (pKeyValueInfo) {
  986. memset(pKeyValueInfo, 0, ulcbuf);
  987. RtlFreeHeap( RtlProcessHeap(), 0, pKeyValueInfo );
  988. }
  989. return( Flag ? TRUE : FALSE );
  990. }
  991. //*****************************************************************************
  992. // CtxGetModuleBadClpbrdAppFlags -
  993. //
  994. // Gets the Citrix BadClpbrdApp and compatibility flags for the specified
  995. // module.
  996. //
  997. // Parameters:
  998. // LPWSTR lpModName (IN) - Image name to look up in registry
  999. // PBADCLPBRDAPP pBadClpbrdApp (OUT) - Structure to used to return flags
  1000. //
  1001. // Return Value:
  1002. // TRUE on success, FALSE on failure.
  1003. //
  1004. // The BADCLPBRDAPP structure is defined in:
  1005. // base\client\citrix\compatfl.h and user\inc\user.h.
  1006. //
  1007. //*****************************************************************************
  1008. BOOL CtxGetModuleBadClpbrdAppFlags(LPWSTR lpModName, PBADCLPBRDAPP pBadClpbrdApp)
  1009. {
  1010. NTSTATUS NtStatus;
  1011. OBJECT_ATTRIBUTES ObjectAttributes;
  1012. UNICODE_STRING UniString;
  1013. HKEY hKey = 0;
  1014. ULONG ul, ulcnt, ulcbuf, ulrc = FALSE;
  1015. PKEY_VALUE_PARTIAL_INFORMATION pKeyValueInfo = NULL;
  1016. LPWSTR UniBuff;
  1017. PWCHAR pwch;
  1018. WCHAR *pbadappNameValue[] = { COMPAT_OPENCLIPBOARDRETRIES,
  1019. COMPAT_OPENCLIPBOARDDELAYINMILLISECS,
  1020. COMPAT_CLIPBOARDFLAGS,
  1021. NULL
  1022. };
  1023. // Get the executable name only, no path.
  1024. pwch = wcsrchr(lpModName, L'\\');
  1025. if (pwch) {
  1026. pwch++;
  1027. } else {
  1028. pwch = lpModName;
  1029. }
  1030. // Get the buffers we need
  1031. ul = sizeof(TERMSRV_COMPAT_APP) + (wcslen(pwch) + 1)*sizeof(WCHAR);
  1032. UniBuff = RtlAllocateHeap(RtlProcessHeap(), 0, ul);
  1033. ulcbuf = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG);
  1034. pKeyValueInfo = RtlAllocateHeap(RtlProcessHeap(), 0, ulcbuf);
  1035. if (UniBuff && pKeyValueInfo) {
  1036. wcscpy(UniBuff, TERMSRV_COMPAT_APP);
  1037. wcscat(UniBuff, pwch);
  1038. // Remove the extension
  1039. if (pwch = wcsrchr(UniBuff, L'.')) {
  1040. *pwch = '\0';
  1041. }
  1042. RtlInitUnicodeString(&UniString,
  1043. UniBuff
  1044. );
  1045. InitializeObjectAttributes(&ObjectAttributes,
  1046. &UniString,
  1047. OBJ_CASE_INSENSITIVE,
  1048. NULL,
  1049. NULL
  1050. );
  1051. NtStatus = NtOpenKey(&hKey, KEY_READ, &ObjectAttributes);
  1052. if (NT_SUCCESS(NtStatus)) {
  1053. ulrc = TRUE;
  1054. for (ulcnt = 0; pbadappNameValue[ulcnt]; ulcnt++) {
  1055. RtlInitUnicodeString(&UniString, pbadappNameValue[ulcnt]);
  1056. NtStatus = NtQueryValueKey(hKey,
  1057. &UniString,
  1058. KeyValuePartialInformation,
  1059. pKeyValueInfo,
  1060. ulcbuf,
  1061. &ul);
  1062. if (NT_SUCCESS(NtStatus) &&
  1063. (REG_DWORD == pKeyValueInfo->Type)) {
  1064. switch (ulcnt) {
  1065. case 0:
  1066. pBadClpbrdApp->BadClpbrdAppEmptyRetries =
  1067. *(PULONG)pKeyValueInfo->Data;
  1068. break;
  1069. case 1:
  1070. pBadClpbrdApp->BadClpbrdAppEmptyDelay =
  1071. *(PULONG)pKeyValueInfo->Data;
  1072. break;
  1073. case 2:
  1074. pBadClpbrdApp->BadClpbrdAppFlags =
  1075. *(PULONG)pKeyValueInfo->Data;
  1076. break;
  1077. }
  1078. } else {
  1079. switch (ulcnt) {
  1080. case 0:
  1081. pBadClpbrdApp->BadClpbrdAppEmptyRetries = 0;
  1082. break;
  1083. case 1:
  1084. pBadClpbrdApp->BadClpbrdAppEmptyDelay = 50;
  1085. break;
  1086. case 2:
  1087. pBadClpbrdApp->BadClpbrdAppFlags = 0;
  1088. break;
  1089. }
  1090. }
  1091. }
  1092. NtClose(hKey);
  1093. }
  1094. }
  1095. // Free the memory we allocated
  1096. // Need to zero out the buffers, because some apps (MS Internet Assistant)
  1097. // won't install if the heap is not zero filled.
  1098. if (UniBuff) {
  1099. memset(UniBuff, 0, UniString.MaximumLength);
  1100. RtlFreeHeap( RtlProcessHeap(), 0, UniBuff );
  1101. }
  1102. if (pKeyValueInfo) {
  1103. memset(pKeyValueInfo, 0, ulcbuf);
  1104. RtlFreeHeap( RtlProcessHeap(), 0, pKeyValueInfo );
  1105. }
  1106. return(ulrc);
  1107. }
  1108. //*****************************************************************************
  1109. // CtxGetBadClpbrdAppFlags -
  1110. //
  1111. // Gets the Citrix BadClpbrdApp and compatibility flags for the
  1112. // current task.
  1113. //
  1114. // Parameters:
  1115. // LPWSTR lpModName (IN) - Image name to look up in registry
  1116. // PBADCLPBRDAPP pBadClpbrdApp (OUT) - Structure to used to return flags
  1117. //
  1118. // Return Value:
  1119. // TRUE on success, FALSE on failure.
  1120. //
  1121. // The BADCLPBRDAPP structure is defined in:
  1122. // base\client\citrix\compatfl.h and user\inc\user.h.
  1123. //
  1124. //*****************************************************************************
  1125. BOOL CtxGetBadClpbrdAppFlags(OUT PBADCLPBRDAPP pBadClpbrdApp)
  1126. {
  1127. WCHAR ModName[MAX_PATH+1];
  1128. DWORD dwAppType = 0;
  1129. if (!GetAppTypeAndModName(&dwAppType, ModName, sizeof(ModName))) {
  1130. return (FALSE);
  1131. }
  1132. // Get the flags
  1133. return (CtxGetModuleBadClpbrdAppFlags(ModName, pBadClpbrdApp));
  1134. }
  1135. //*****************************************************************************
  1136. //
  1137. // Same as GetTermsrCompatFlags(), except that the first argument is name
  1138. // of an executable module with possible path and extention.
  1139. // This func will strip path and extension, and then call GetTermsrCompatFlags()
  1140. // with just the module name
  1141. //
  1142. //*****************************************************************************
  1143. ULONG GetTermsrCompatFlagsEx(LPWSTR lpModName,
  1144. LPDWORD pdwCompatFlags,
  1145. TERMSRV_COMPATIBILITY_CLASS CompatType)
  1146. {
  1147. // drop the path and extension from the module name
  1148. WCHAR *p, *e;
  1149. int size;
  1150. size = wcslen(lpModName);
  1151. p = &lpModName[size-1]; // move to to the end of string
  1152. // walk back to the start, break if you hit a back-slash
  1153. while (p != lpModName)
  1154. {
  1155. if ( *p == TEXT('\\') )
  1156. { ++p; //move past the back-slash
  1157. break;
  1158. }
  1159. --p;
  1160. }
  1161. // p is at the begining of the name of an executable.
  1162. // get rid of the extension, set end pointer e to the start of str
  1163. // move forward until you hit '.'
  1164. e = p;
  1165. while (*e)
  1166. {
  1167. if (*e == TEXT('.') )
  1168. {
  1169. *e = TEXT('\0'); // terminate at "."
  1170. break;
  1171. }
  1172. e++;
  1173. }
  1174. // 'p' is the module/executable name, no path, and no extension.
  1175. return ( GetTermsrCompatFlags( p, pdwCompatFlags, CompatType) );
  1176. }