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.

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