在XP下使用Link控件

    From: xuyibo.org  Updated: 2021-08-03

    邮件通知当更新时自动发送邮件通知。
    评论本文有什么建议或评论,可以贴一下。
    我要捐助你的支持,让我们做的更好。

  1. 介绍
  2. 很早就像自己写一个超链接的窗口控件,可惜自己能力有限,对于用户界面,自己花的时间不多。今天偶然看到:

    Windows调用ShellAbout将弹出这个对话框,查MSDN,发现这个函数在模块Shell32.dll中,使用Resource Hacker来Dump资源:

    噢!一个新的窗口类。在MSDN 2001中搜索没有收获(XP可是2001年就有了),在MSDN 2005中搜索搜到了:

    BOOL InitCommonControlsEx(LPINITCOMMONCONTROLSEX lpInitCtrls);

    设置:lpInitCtrls->dwICC = ICC_LINK_CLASS就OK了。

    本文该结束了,No!当我这么做的时候,InitCommonControlsEx执行失败,GetLastError()返回6(估计对于comctl32.dll来说,内部就没有实现这种错误抛出机制。)我就开始纳闷了,为什么在这台机器上,微软的shell32.dll就可以成功调用,我的就不可以。逆向分析system32comctl32.dll中的InitCommonControlsEx:

    5D173619 > $ 8BFF mov edi,edi
    5D17361B . 55 push ebp
    5D17361C . 8BEC mov ebp,esp
    5D17361E . 53 push ebx
    5D17361F . 56 push esi
    5D173620 . 33DB xor ebx,ebx
    5D173622 . 57 push edi
    5D173623 . 8B7D 08 mov edi,dword ptr ss:[ebp+8]
    5D173626 . 33F6 xor esi,esi
    5D173628 . 43 inc ebx
    5D173629 . 3BFE cmp edi,esi
    5D17362B . 74 5E je short comctl32.5D17368B
    5D17362D . 833F 08 cmp dword ptr ds:[edi],8
    5D173630 . 75 59 jnz short comctl32.5D17368B
    5D173632 . F747 04 00C0FF7F test dword ptr ds:[edi+4],7FFFC000
    5D173639 . 75 50 jnz short comctl32.5D17368B
    5D17363B . 3935 38201E5D cmp dword ptr ds:[5D1E2038],esi

    [edi+4]保存的是lpInitCtrls->dwICC,查看XP SP2中ICC_LINK_CLASS的定义为:0x00004000,这样语句:TEST 00004000h, 7FFFC000h的结果就不等于0了。直接跳出了,没有任何动作。

    下面的路该怎么走?噢,对了,可以用spy++查看这个窗口类的窗口函数,看它在那个模块里面:

    当比较这个进程控件加载的dll地址,找到这里:

    C:WINDOWSWinSxSx86_Microsoft.Windows.Common-Controls_6595b64144ccf1df_6.0.2600.2982_x-ww_ac3f9c03comctl32.dll

    My God! 怎么,这里面还有一个同名的comctl32.dll!! Google一下WinSxS,一点资料:

    WinSxS – Windows Side by Side

    How to bypass the WinSxS for CRT/MFC/ATL DLLs

    Starting with VC8, you have two options to distribute the DLL version of the CRT/MFC/ATL with your application:

    1. You can redistribute the DLLs with your application in the same directory and also put a valid manifest for these DLLs into this directory
    2. You can install the redist.exe and the DLL will be installed in the WinSxS folder (on XP and later)

    So, if you want to be independed from global DLLs, you might think that you can simply put the DLLs into your applications directory. But this is a false conclusion.
    If a DLL is installed in the WinSxS folder, the local DLLs will be ignored. This might be even true, if a newer DLL was installed (for example by security hotfixes). This is possible due to policy redirections of these SxS-DLLs.
    In most cases this also makes sense, because you always get the latest (hopefully compatible) version of the DLL.

    But there might be some situations in which you might have full control over which DLLs are loaded from where. Now, Andre Stille (an other VC++ MVP), found a very simple solution : just remove the “publicKeyToken” attribute from the manifests!
    So an application manifest looks like:

    Application.exe.manifest:

     <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    		<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
      <dependency>
        <dependentAssembly>
          <assemblyIdentity type="win32" name="Microsoft.VC80.CRT" 
     version="8.0.50727.42" processorArchitecture="x86" />
        </dependentAssembly>
      </dependency>
     </assembly>

    You must also set the correct verion-number of the DLL! And remove the “publicKeyToken” attribute.
    The manifest the for DLL looks like:

    Microsoft.VC80.CRT.Manifest:

     <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
        <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
        <assemblyIdentity type="win32" name="Microsoft.VC80.CRT" 
     version="8.0.50727.42" processorArchitecture="x86"></assemblyIdentity>
        <file name="msvcr80.dll"></file>
        <file name="msvcp80.dll"></file>
        <file name="msvcm80.dll"></file>
     </assembly>

    Now the CRT DLLs in the WinSxS will be ignored and only the local DLLs will be loaded.

    好,那就从manifest开始,给我的exe工程.rc文件里面增加下面一句话:

    1 RT_MANIFEST "MANIFEST.XML"

    MANIFEST.XML文件内容(ANSI,not UTF8 or UNICODE):

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

    编译运行:

    一个遗憾:这样的程序无法在Windows 2000机器上运行。

  3. 相关文章
  4. 程序异常捕获库 – CrashRpt
    注册表API简易教程
    MAPI MAPISendMail
    轻量级的浏览器控件HTMLLITE
    我的电脑软配置
    让你的程序支持脱拽
    背景透明的按钮

  5. 评论本文:
  6. EMail: