/// <summary> /// helper method that queries Windows7 compat section in applciation EXE and returns OS compat flags from there. /// </summary> /// <returns></returns> private static OsCompatibilityFlags QueryStaticContext() { if (!s_staticContextCachePresent) { lock (s_staticContextCacheLock) { if (!s_staticContextCachePresent) { if (!IsWindows7CompatibilitySupported) { // we cannot use the API with CompatibilityInformationInActivationContext on current OS, set as unknown s_staticContextCache = OsCompatibilityFlags.Unknown; } else { s_staticContextCache = NativeMethods.QueryOsCompatibilityInformation(NativeMethods.GetModuleHandleW(null)); } s_staticContextCachePresent = true; } } } return(s_staticContextCache); }
/// <summary> /// helper method that queries Windows7 compat section in applciation EXE and returns OS compat flags from there. /// </summary> /// <returns></returns> private static OsCompatibilityFlags QueryStaticContext() { if (!s_staticContextCachePresent) { lock (s_staticContextCacheLock) { if (!s_staticContextCachePresent) { if (!IsWindows7CompatibilitySupported) { // we cannot use the API with CompatibilityInformationInActivationContext on current OS, set as unknown s_staticContextCache = OsCompatibilityFlags.Unknown; } else { s_staticContextCache = NativeMethods.QueryOsCompatibilityInformation(NativeMethods.GetModuleHandleW(null)); } s_staticContextCachePresent = true; } } } return s_staticContextCache; }
/// <summary> /// use this method in your tests to assert that Windows7 dynamic compat context is active. The method first checks the context, and /// if it is not currently active, the method raises exception. /// /// Exceptions raised: /// * NotSupportedException: current OS is not Windows7, nor Win2K8R2, nor later. Use IsWindows7CompatibilitySupported before! /// * InvalidOperationException: dynamic context for Windows7 compat mode has been deactivated. The exception includes list of modules /// that might be the cause for the downgrade to happen! /// * other exceptions are unwelcome /// </summary> public static void EnsureWindows7DynamicContextIsActive() { if (!IsWindows7CompatibilitySupported) { throw new NotSupportedException("Current OS does not support Win7 compat mode testing. Please use IsWindows7CompatibilitySupported before asserting"); } if (IsWindows7DynamicContextActive) { // the true test passed: GetOverlappedResult behaves as expected in Win7 compat mode // OK to continue return; } // The process is not running in Windows7 compat mode, check for possible reasons. // The code below is for collecting troubleshooting information to be raised as InvalidOperationException to the user. if (!IsWindows7CompatibilityContextEnabled) { // current process has neither Windows7 compat manifest nor proper exe subversion (not compiled with WINVER >= 6.1) // there is no point to query other modules since QueryActCtxW (CompatibilityInformationInActivationContext) // returns no GUIDs in this case, even if modules do have compat manifest. throw new InvalidOperationException(string.Format( "Process executable ({0}) has neither Windows7 GUID in its RT_MANIFEST nor compiled with WINVER>=6.1", System.Diagnostics.Process.GetCurrentProcess().ProcessName)); } // Process exe seems to be Win7 compatible, search for modules that are not compatible. // To ease on troubleshooting, collect incompatible modules list and add them to // exception message. This way the caller can find out which of the modules // downgrade the process. StringWriter exceptionMessage = new StringWriter(); exceptionMessage.WriteLine( "The dynamic Win7 compat context for this process has been downgraded due " + "to one or more incompatible modules."); IntPtr[] modules = NativeMethods.GetModules(); bool incompatibleModuleDetected = false; for (int i = 0; i < modules.Length; i++) { IntPtr module = modules[i]; OsCompatibilityFlags osCompatFlags = NativeMethods.QueryOsCompatibilityInformation(module); bool isWin7CompatModule = (osCompatFlags & OsCompatibilityFlags.Windows7) != 0; if (!isWin7CompatModule) { if (!incompatibleModuleDetected) { // first incompatible module exceptionMessage.WriteLine("Incompatible modules list:"); } incompatibleModuleDetected = true; string moduleName = NativeMethods.GetModuleFileName(module); exceptionMessage.WriteLine("Module: {0}; flags: {1}", moduleName, osCompatFlags); } } if (!incompatibleModuleDetected) { exceptionMessage.WriteLine("Cannot detect incompatible modules."); } // troubleshooting info is ready, raise the message to the user throw new InvalidOperationException(exceptionMessage.ToString()); }
internal static OsCompatibilityFlags QueryOsCompatibilityInformation(IntPtr dllHandle) { if (Environment.OSVersion.Version < Win7_Win2K8R2_Version) { throw new NotSupportedException( "CompatibilityInformationInActivationContext flag was added in Win7 and Windows 2008 R2 only. It is not supported on current OS."); } const int QUERY_ACTCTX_FLAG_ACTCTX_IS_HMODULE = 0x00000008; const int CompatibilityInformationInActivationContext = 6; IntPtr cbBuffer = IntPtr.Zero; bool ret = QueryActCtxW( QUERY_ACTCTX_FLAG_ACTCTX_IS_HMODULE, dllHandle, IntPtr.Zero, CompatibilityInformationInActivationContext, null, IntPtr.Zero, ref cbBuffer); if (ret) { Debug.Assert(cbBuffer == IntPtr.Zero); return(OsCompatibilityFlags.None); } int status = Marshal.GetLastWin32Error(); if (status != ERROR_INSUFFICIENT_BUFFER) { throw new Win32Exception(status); } byte[] CtxCompatInfo = new byte[cbBuffer.ToInt32()]; ret = QueryActCtxW( QUERY_ACTCTX_FLAG_ACTCTX_IS_HMODULE, dllHandle, IntPtr.Zero, CompatibilityInformationInActivationContext, CtxCompatInfo, cbBuffer, ref cbBuffer); if (!ret) { throw new Win32Exception(); // error message is taken from GetLastError } // read the compatibility information, native structures are: // typedef struct _ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION { // DWORD ElementCount; // COMPATIBILITY_CONTEXT_ELEMENT Elements[]; // } ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION, *PACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION; // typedef struct _COMPATIBILITY_CONTEXT_ELEMENT { // GUID Id; // ACTCTX_COMPATIBILITY_ELEMENT_TYPE Type; // } COMPATIBILITY_CONTEXT_ELEMENT, *PCOMPATIBILITY_CONTEXT_ELEMENT; BinaryReader reader = new BinaryReader(new MemoryStream(CtxCompatInfo)); int elmCount = 0; elmCount = reader.ReadInt32(); OsCompatibilityFlags osCompatFlags = OsCompatibilityFlags.None; for (int i = 0; i < elmCount; i++) { Guid g = new Guid(reader.ReadBytes(16)); ActcxCompatibilityElementType type = (ActcxCompatibilityElementType)reader.ReadInt32(); if (type == ActcxCompatibilityElementType.OS) { if (g == Win7Compat) { osCompatFlags |= OsCompatibilityFlags.Windows7; } else if (g == VistaCompat) { osCompatFlags |= OsCompatibilityFlags.Vista; } else { osCompatFlags |= OsCompatibilityFlags.Unknown; } } } return(osCompatFlags); }