浅析Winform的可视样式

609 阅读1分钟

 每一个C#的Winform项目的Main方法里,都有这么一行代码,那么它究竟是用来做什么的呢?

 

Application.EnableVisualStyles();

 

从注释来看,这是一行用作设置样式的代码,那么它究竟设置了哪些样式呢?

源码浅析

public static void EnableVisualStyles() {
            string assemblyLoc = null;
 
            // SECREVIEW : This Assert is ok, getting the module path is a safe operation, 
            //             the result is provided by the system.
            //
            FileIOPermission fiop = new FileIOPermission(PermissionState.None);
            fiop.AllFiles = FileIOPermissionAccess.PathDiscovery;
            fiop.Assert();
            try {
                assemblyLoc = typeof(Application).Assembly.Location;
            }
            finally {
                CodeAccessPermission.RevertAssert();
            }
            // Pull manifest from our resources
            if (assemblyLoc != null) {
                EnableVisualStylesInternal(assemblyLoc, 101);
            }
        }

从代码来看,最关键的也就是最后那句

EnableVisualStylesInternal(assemblyLoc, 101);

在这句代码里,将本地GAC_MSIL文件夹里的System.Windows.Forms.dll路径和一个“101”传了进去,用于设置所谓的样式。

当我们进入到CreateActivationContext方法里后,会看到如下代码:

[ResourceExposure(ResourceScope.None)]
            [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
            public static bool CreateActivationContext(string dllPath, int nativeResourceManifestID)
            {
                lock (typeof(ThemingScope))
                {
                    if (!contextCreationSucceeded && OSFeature.Feature.IsPresent(OSFeature.Themes))
                    {
 
                        enableThemingActivationContext = new ACTCTX();
 
                        enableThemingActivationContext.cbSize = Marshal.SizeOf(typeof(ACTCTX));
                        enableThemingActivationContext.lpSource = dllPath;
                        enableThemingActivationContext.lpResourceName = (IntPtr)nativeResourceManifestID;
                        enableThemingActivationContext.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID;
 
                        hActCtx = CreateActCtx(ref enableThemingActivationContext);
                        contextCreationSucceeded = (hActCtx != new IntPtr(-1));
                    }
 
                    return contextCreationSucceeded;
                }
            }

在设置了一通ACTCTX的属性后,将它传入了CreateActCtx方法内,用于创建ActivationContext。

而那个“101”则被赋值给了lpResourceName ,那么我们如果想搞懂那个“101”是做什么的,就要先看懂lpResourceName 是什么意思。

在微软官方文档里找到了答案:

 ACTCTXA结构

在这里我们可以看到lpResourceName指的是和dll或者exe同级目录的资源,接下来我们只需要用vs打开一下上文提到的dll,就可以真相大白了。

 这下我们明白了,所谓的资源就是清单文件(manifest文件),也就是说这个所谓的EnableVisualStyles方法其实设置的并不是我们常规意义上的样式,而是设置的程序应用信息,比如引用dll、注册路径、版本号等。

这是清单文件的内容。

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> 
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <description>Windows Forms Common Control manifest</description> 
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*" /> 
    </dependentAssembly>
  </dependency>
</assembly>

从这里我们可以看到,这里映射到了name叫“Microsoft.Windows.Common-Controls”的文件夹,果不其然,我在C:\Windows\WinSxS找到了它。

 这里可以看到版本号也是一致的,接下来我们看一下里面记录的哪些东西?

 随机点开一个

看到这里我们就明白了,这个 comctl32.dll里面记录的是一些常用的图标之类的资源文件,而这个Application.EnableVisualStyles();设置的也是这些。