-
Notifications
You must be signed in to change notification settings - Fork 0
/
ComCtlv6ActivationContext.cs
134 lines (114 loc) · 4.96 KB
/
ComCtlv6ActivationContext.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
using System;
using System.IO;
using System.Runtime.InteropServices;
namespace TaskDialogApi
{
internal sealed class ComCtlv6ActivationContext : IDisposable
{
private IntPtr _cookie;
private static ActCtx _enableThemingActivationContext;
private static ActivationContextSafeHandle _activationContext;
private static bool _contextCreationSucceeded;
private static readonly object _contextCreationLock = new object();
public ComCtlv6ActivationContext(bool enable)
{
if (!enable || !EnvironmentOS.IsWindowsXPOrLater) return;
if (!EnsureActivateContextCreated()) return;
if (!ActivateActCtx(_activationContext, out _cookie))
{
// Be sure cookie always zero if activation failed
_cookie = IntPtr.Zero;
}
}
~ComCtlv6ActivationContext()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
// ReSharper disable once UnusedParameter.Local
private void Dispose(bool disposing)
{
if (_cookie == IntPtr.Zero) return;
if (DeactivateActCtx(0, _cookie))
{
// deactivation succeeded...
_cookie = IntPtr.Zero;
}
}
private static bool EnsureActivateContextCreated()
{
lock (_contextCreationLock)
{
if (!_contextCreationSucceeded)
{
// Pull manifest from the .NET Framework install
// directory
var assemblyLoc = typeof(object).Assembly.Location;
string manifestLoc = null;
var installDir = string.Empty;
if (!string.IsNullOrWhiteSpace(assemblyLoc))
{
installDir = Path.GetDirectoryName(assemblyLoc) ?? string.Empty;
const string manifestName = "XPThemes.manifest";
manifestLoc = Path.Combine(installDir, manifestName);
}
if (!string.IsNullOrWhiteSpace(manifestLoc) && !string.IsNullOrWhiteSpace(installDir))
{
_enableThemingActivationContext = new ActCtx
{
cbSize = Marshal.SizeOf(typeof(ActCtx)),
lpSource = manifestLoc,
lpAssemblyDirectory = installDir,
dwFlags = ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID,
};
// Set the lpAssemblyDirectory to the install
// directory to prevent Win32 Side by Side from
// looking for comctl32 in the application
// directory, which could cause a bogus dll to be
// placed there and open a security hole.
// Note this will fail gracefully if file specified
// by manifestLoc doesn't exist.
_activationContext = CreateActCtx(ref _enableThemingActivationContext);
_contextCreationSucceeded = !_activationContext.IsInvalid;
}
}
// If we return false, we'll try again on the next call into
// EnsureActivateContextCreated(), which is fine.
return _contextCreationSucceeded;
}
}
[DllImport("Kernel32.dll", SetLastError = true)]
private static extern ActivationContextSafeHandle CreateActCtx(ref ActCtx actCtx);
[DllImport("Kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool ActivateActCtx(ActivationContextSafeHandle hActCtx, out IntPtr lpCookie);
[DllImport("Kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool DeactivateActCtx(uint dwFlags, IntPtr lpCookie);
// ReSharper disable InconsistentNaming
private struct ActCtx
{
#pragma warning disable 649
// ReSharper disable NotAccessedField.Local
// ReSharper disable UnusedMember.Global
public int cbSize;
public uint dwFlags;
public string lpSource;
public ushort wProcessorArchitecture;
public ushort wLangId;
public string lpAssemblyDirectory;
public string lpResourceName;
public string lpApplicationName;
// ReSharper restore UnusedMember.Global
// ReSharper restore NotAccessedField.Local
#pragma warning restore 649
}
// ReSharper restore InconsistentNaming
// ReSharper disable once InconsistentNaming
private const int ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID = 0x004;
}
}