关于VC6.0 MFC+ATL做出的COM,其内部的windows窗口不能以XP Theme模式显示的问题彻底解决

 最近用vc6.0做windows SHELL CONTEXT开发,其框架是用ATL向导生成的,并且用了MFC窗体,想使窗体以XP风格显示,在网上搜遍了所有的文章,发现采用通用的方法只能在.exe中实现,用MFC做的dll或者activex无法显示xp风格,就在快要绝望之时,看到了以下文章,请注意红色部分,作者解释的非常清楚,提出了要实现XP风格的通用方法。

原帖地址:http://groups.google.com/group/microsoft.public.platformsdk.shell/browse_thread/thread/f1aece47175ebae8/17d14d09ecf4ecfd?lnk=st&rnum=7

 

  
Matt Attaway  
查看个人资料   翻译成中文(简体) 翻译内容(查看原文内容)
 更多选项 2004年3月10日, 上午11时33分
新闻论坛: microsoft.public.platformsdk.shell
发件人: Matt Attaway <anonym...@discussions.microsoft.com>
日期: Tue, 9 Mar 2004 16:56:06 -0800
当地时间: 2004年3月10日(星期三) 上午8时56分
主题: How to force XP look in feel in shell extensions
Hello all,

I'm working on shell extension which uses ATL for the dialogs.
( I was using WTL, but I've gone back to simple ATL dialogs for now. )
An interesting factoid about shell extensions is that if they are invoked
from Explorer the resulting dialogs to not pick up the XP look and feel. If they
are called from Windows open dialog they do pick up the "Luna" look. A bit odd, but that's life. =)

I would like to force my dialog to have the XP look if appropriate. I've
heard mutterings on the Internet about having to set the "context." However that
appears to be an MFC concept.

My questions are, has anyone heard of this "context?" If so, is there a
way with ATL to set the context or should I look into using MFC instead?

And yup, I'm following all of the proper guidelines for picking up the XP
look. =)

Thanks,
Matt


 
   
 

  
David Lowndes  
查看个人资料   翻译成中文(简体) 翻译内容(查看原文内容)
 更多选项 2004年3月10日, 下午6时16分
新闻论坛: microsoft.public.platformsdk.shell
发件人: David Lowndes <dav...@example.invalid>
日期: Wed, 10 Mar 2004 10:14:41 +0000
当地时间: 2004年3月10日(星期三) 下午6时14分
主题: Re: How to force XP look in feel in shell extensions

>I'm working on shell extension which uses ATL for the dialogs.
>( I was using WTL, but I've gone back to simple ATL dialogs for now. )
>An interesting factoid about shell extensions is that if they are invoked
>from Explorer the resulting dialogs to not pick up the XP look and feel. If they
>are called from Windows open dialog they do pick up the "Luna" look. A bit odd, but that's life. =)

Matt,

This sounds similar to the situation I experienced with an MFC based
shell extension.

I don't really understand the fix I was given from MS, but this is the
essence of it. I don't know if it'll work (with a bit of alteration)
in your ATL situation.

class CMyContext
{
  public:
          BOOL Init()
          {
                   BOOL bRet = FALSE;
                   BOOL bTemp = FALSE;

                   OSVERSIONINFO info = { 0 };
               info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);

               bTemp = GetVersionEx(&info);
               if (bTemp)
                   {
                      //do special XP theme activation code only on XP
or higher...
                  if ( (info.dwMajorVersion >= 5) &&
                       (info.dwMinorVersion >= 1) &&
                       (info.dwPlatformId == VER_PLATFORM_WIN32_NT))
                          {
                       ACTCTX actctx = {0};
                   TCHAR szModule[MAX_PATH] = {0};

                           HINSTANCE hinst = AfxGetInstanceHandle();
                   ::GetModuleFileName(hinst, szModule, MAX_PATH);

                   actctx.cbSize = sizeof(ACTCTX);
                   actctx.dwFlags = ACTCTX_FLAG_HMODULE_VALID |
                                    ACTCTX_FLAG_RESOURCE_NAME_VALID;

                   actctx.lpSource = szModule;
                   actctx.lpResourceName = MAKEINTRESOURCE(2);
                   actctx.hModule = hinst;

                   m_hActCtx = ::CreateActCtx(&actctx);
                   if (INVALID_HANDLE_VALUE != m_hActCtx)
                                   {
                                  bRet = TRUE;
                                   }
                          }
                   }

                   return bRet;
          }

          CMyContext() : m_ulActivationCookie(0), m_hActCtx(0)
          {
                 BOOL bRet = Init();

                 if (bRet && m_hActCtx && (INVALID_HANDLE_VALUE !=
m_hActCtx))
            ActivateActCtx(m_hActCtx, &m_ulActivationCookie);
          }

          ~CMyContext()
          {
                 if (m_hActCtx && (m_hActCtx!= INVALID_HANDLE_VALUE))
                 {
                        DeactivateActCtx(0, m_ulActivationCookie);
                        ReleaseActCtx(m_hActCtx);
                 }
          }

  private:
          ULONG_PTR m_ulActivationCookie;
          HANDLE m_hActCtx;

};

... and before you call DoModal to display your dialog in your shell
extension, create an instance of that class to run the code in that
class:

        CMyContext con;
        dlg.DoModal();

Dave
--
MVP VC++ FAQ: http://www.mvps.org/vcfaq


 
 

 

  
Henk Devos  
查看个人资料   翻译成中文(简体) 翻译内容(查看原文内容)
 更多选项 2004年3月11日, 下午7时31分
新闻论坛: microsoft.public.platformsdk.shell
发件人: "Henk Devos" <i...@dontspamme.regxplor.com>
日期: Thu, 11 Mar 2004 12:31:46 +0100
当地时间: 2004年3月11日(星期四) 下午7时31分
主题: Re: How to force XP look in feel in shell extensions
The ActCtx functions only exist in XP, so if you link to them statically
your DLL can't get loaded in older Windows versions. So if you want it to
run on older Windows versions, you should use dynamic linking. If you don't
the version check is wrong.
You also make a classical mistake in the version checking: Version 6.0 is
higher than 5.1.

"David Lowndes" <dav ...@example.invalid> wrote in message

news:rcqt40159b0i6lj156nl4oalrcb96ojo4t@4ax.com...
> >I'm working on shell extension which uses ATL for the dialogs.
> >( I was using WTL, but I've gone back to simple ATL dialogs for now. )
> >An interesting factoid about shell extensions is that if they are invoked
> >from Explorer the resulting dialogs to not pick up the XP look and feel.
If they
> >are called from Windows open dialog they do pick up the "Luna" look. A

bit odd, but that's life. =)

- 隐藏被引用文字 -
- 显示引用的文字 -

> Matt,

> This sounds similar to the situation I experienced with an MFC based
> shell extension.

> I don't really understand the fix I was given from MS, but this is the
> essence of it. I don't know if it'll work (with a bit of alteration)
> in your ATL situation.

> class CMyContext
> {
>   public:
>   BOOL Init()
>   {
>    BOOL bRet = FALSE;
>    BOOL bTemp = FALSE;

>    OSVERSIONINFO info = { 0 };
>        info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);

>        bTemp = GetVersionEx(&info);
>        if (bTemp)
>    {
>       file://do special XP theme activation code only on XP
> or higher...
>           if ( (info.dwMajorVersion >= 5) &&
>                (info.dwMinorVersion >= 1) &&
>                (info.dwPlatformId == VER_PLATFORM_WIN32_NT))
>   {
>                  ACTCTX actctx = {0};
>                    TCHAR szModule[MAX_PATH] = {0};

>            HINSTANCE hinst = AfxGetInstanceHandle();
>                    ::GetModuleFileName(hinst, szModule, MAX_PATH);

>                    actctx.cbSize = sizeof(ACTCTX);
>                    actctx.dwFlags = ACTCTX_FLAG_HMODULE_VALID |
>                                     ACTCTX_FLAG_RESOURCE_NAME_VALID;

>                    actctx.lpSource = szModule;
>                    actctx.lpResourceName = MAKEINTRESOURCE(2);
>                    actctx.hModule = hinst;

>                    m_hActCtx = ::CreateActCtx(&actctx);
>                    if (INVALID_HANDLE_VALUE != m_hActCtx)
>    {
>           bRet = TRUE;
>    }
>   }
>    }

>      return bRet;
>   }

>   CMyContext() : m_ulActivationCookie(0), m_hActCtx(0)
>   {
> BOOL bRet = Init();

> if (bRet && m_hActCtx && (INVALID_HANDLE_VALUE !=
> m_hActCtx))
>             ActivateActCtx(m_hActCtx, &m_ulActivationCookie);
>   }

>   ~CMyContext()
>   {
> if (m_hActCtx && (m_hActCtx!= INVALID_HANDLE_VALUE))
> {
> DeactivateActCtx(0, m_ulActivationCookie);
> ReleaseActCtx(m_hActCtx);
> }
>   }

>   private:
>   ULONG_PTR m_ulActivationCookie;
>   HANDLE m_hActCtx;
> };

> ... and before you call DoModal to display your dialog in your shell
> extension, create an instance of that class to run the code in that
> class:

> CMyContext con;
> dlg.DoModal();

> Dave
> --
> MVP VC++ FAQ: http://www.mvps.org/vcfaq


 
   
您需要先 登录才能发帖。
要发帖,您需要先 加入此论坛
请先在 订阅设置页上更新您的昵称,然后再进行发帖。
您没有发帖的权限。

 

  
David Lowndes  
查看个人资料   翻译成中文(简体) 翻译内容(查看原文内容)
 更多选项 2004年3月12日, 上午1时35分
新闻论坛: microsoft.public.platformsdk.shell
发件人: David Lowndes <dav...@example.invalid>
日期: Thu, 11 Mar 2004 17:32:19 +0000
当地时间: 2004年3月12日(星期五) 上午1时32分
主题: Re: How to force XP look in feel in shell extensions

>The ActCtx functions only exist in XP, so if you link to them statically
>your DLL can't get loaded in older Windows versions. So if you want it to
>run on older Windows versions, you should use dynamic linking.

Hmm, my program does work on Win9x systems, so now you've said this.
I'll have to check why - I may have it delayloaded, I can't remember.

>You also make a classical mistake in the version checking: Version 6.0 is
>higher than 5.1.

My fault for not checking the code MS gave me - unless they know
something we don't with regards to Windows 6! :)

Dave
--
MVP VC++ FAQ: http://www.mvps.org/vcfaq


 
   
您需要先 登录才能发帖。
要发帖,您需要先 加入此论坛
请先在 订阅设置页上更新您的昵称,然后再进行发帖。
您没有发帖的权限。

 

  
David Lowndes  
查看个人资料   翻译成中文(简体) 翻译内容(查看原文内容)
 更多选项 2004年3月12日, 上午3时27分
新闻论坛: microsoft.public.platformsdk.shell
发件人: David Lowndes <dav...@example.invalid>
日期: Thu, 11 Mar 2004 19:26:03 +0000
当地时间: 2004年3月12日(星期五) 上午3时26分
主题: Re: How to force XP look in feel in shell extensions

>>The ActCtx functions only exist in XP, so if you link to them statically
>>your DLL can't get loaded in older Windows versions. So if you want it to
>>run on older Windows versions, you should use dynamic linking.
>Hmm, my program does work on Win9x systems, so now you've said this.
>I'll have to check why - I may have it delayloaded, I can't remember.

In fact those functions are in kernel32 which can't be delayloaded, so
I don't know how this works with older OS's - there must be something
going on that I'm not aware of and hadn't thought to consider since it
hadn't shown any problems with older OS's.

Looking at my DLL with depends doesn't indicate that the AxtCtx
functions are referenced.

Dave
--
MVP VC++ FAQ: http://www.mvps.org/vcfaq


 
   
您需要先 登录才能发帖。
要发帖,您需要先 加入此论坛
请先在 订阅设置页上更新您的昵称,然后再进行发帖。
您没有发帖的权限。

 

  
Dave Anderson [MS]  
查看个人资料   翻译成中文(简体) 翻译内容(查看原文内容)
 更多选项 2004年3月13日, 上午8时06分
新闻论坛: microsoft.public.platformsdk.shell
发件人: dav...@online.microsoft.com (Dave Anderson [MS])
日期: Sat, 13 Mar 2004 00:05:13 GMT
当地时间: 2004年3月13日(星期六) 上午8时05分
主题: Re: How to force XP look in feel in shell extensions
I suspect that you are building with ISOLATION_AWARE_ENABLED defined to 1.
ISOLATION_AWARE_ENABLED enables wrapper functions in winbase.inl (and other
files, such an Winuser.inl) for the activation context functions. These
wrappers essentially use the function address returned by calling
GetProcAddress on Kernel32 to call the specified function. This would allow
you to call CreateActCtx, etc. and still run on pre-Windows XP systems.

For example, the function that wraps CreateActCtxW (from Winbase.inl):

ISOLATION_AWARE_INLINE HANDLE WINAPI IsolationAwareCreateActCtxW(PCACTCTXW
pActCtx)
{
    HANDLE result = INVALID_HANDLE_VALUE;
    typedef HANDLE (WINAPI* PFN)(PCACTCTXW pActCtx);
    static PFN s_pfn;
    if (s_pfn == NULL)
    {
        s_pfn =
(PFN)WinbaseIsolationAwarePrivatetRgCebPnQQeRff_xReaRYQP_QYY("CreateActCtxW­"
);
        if (s_pfn == NULL)
            return result;
    }
    result = s_pfn(pActCtx);
    return result;

}

ISOLATION_AWARE_ENABLED also enables wrappers for functions in USER32 (such
as CreateWindowEx), COMCTL32 (such as PropertySheet), and COMDLG32 (such as
GetOpenFileName). These functions will activate the activation context
based on the module's manifest, call the specified function, then
deactivate the activation context. For example, the function that wraps
CreateWindowExW (from Winuser.inl):

ISOLATION_AWARE_INLINE HWND WINAPI IsolationAwareCreateWindowExW(DWORD
dwExStyle,LPCWSTR lpClassName,LPCWSTR lpWindowName,DWORD dwStyle,int X,int
Y,int nWidth,int nHeight,HWND hWndParent,HMENU hMenu,HINSTANCE
hInstance,LPVOID lpParam)
{
    HWND windowResult = NULL;
    ULONG_PTR  ulpCookie = 0;
    const BOOL fActivateActCtxSuccess = IsolationAwarePrivateT_SqbjaYRiRY
|| IsolationAwarePrivatenPgViNgRzlnPgpgk(&ulpCookie);
    if (!fActivateActCtxSuccess)
        return windowResult;
    __try
    {
        windowResult =
CreateWindowExW(dwExStyle,lpClassName,lpWindowName,dwStyle,X,Y,nWidth,nHeig­h
t,hWndParent,hMenu,hInstance,lpParam);
    }
    __finally
    {
        if (!IsolationAwarePrivateT_SqbjaYRiRY)
        {
            const BOOL fPreserveLastError = (windowResult == NULL);
            const DWORD dwLastError = fPreserveLastError ? GetLastError() :
NO_ERROR;
            (void)IsolationAwareDeactivateActCtx(0, ulpCookie);
            if (fPreserveLastError)
                SetLastError(dwLastError);
        }
    }
    return windowResult;

}

What does ISOLATION_AWARE_ENABLED have to do with creating Window controls
from a shell extension? Explorer will load both the 5.82 and 6.0 versions
of COMCTL32.DLL when it starts. This allows for components that rely on
version 5.82 to continue to get their expected behavior while allowing
other components to use 6.0 version. COMCTL32 5.82 and 6.0 implement most
of the same window classes (SysListView32, SysTreeView32, etc.), while
version 6.0 also implements standard window controls that are found in
USER32 (Button, Edit, ComboBox, etc.) How does Windows know which version
to use when calling CreateWindowEx? This is where the activation context
comes into play. Windows allows for side-by-side window classes and the
activation context determines which implementation of the window class to
use when a window of that class is created. See "Creating Side-By-Side
Window Classes" for more information.
<
http://msdn.microsoft.com/library/en-us/sbscs/setup/creating_side-by-...
indows_classes.asp>

So why doesn't defining ISOLATION_AWARE_ENABLED work with shell extensions
that use MFC or ATL? The short answer is that the runtime libraries were
not built using ISOLATION_AWARE_ENABLED. Therefore, the runtime libraries
will not use the IsolationAware* wrappers when calling Win32 functions such
as CreateWindowEx. Consider that when you call Create on a CButton object,
you are calling into the MFC runtime to create the button, which eventually
calls CreateWindowEx without activating an activation context. The likely
outcome is that the Create call will create an instance of the Button class
that is implemented in USER32, even if you have a manifest in the calling
module that references COMCTL32 version 6.

Anyone that is creating a DLL that is loaded into a process and wants to
use the version 6 common controls will need to create and manage an
activation context. This applies to shell extensions, ActiveX controls, and
other types of add-ins, such as add-ins for Office applications. Defining
ISOLATION_AWARE_ENABLED generally can handle managing an activation context
for you without having to write any additional code, provided the
IsolationAware* functions are used to 'wrap' the underlying Win32 call with
an activation context. As we have found, ISOLATION_AWARE_ENABLED does not
wrap Win32 calls made by MFC/ATL. Therefore, it is up to a component that
is using MFC/ATL to manage its own activation context.

In the example given above, a DLL calling CButton::Create should call
ActivateActCtx to activate the activation context prior to the Create call
and then call DeactivateActCtx after the create call to deactivate the
activation context. The button will then be created using the version 6
COMCTL32 implementation of the Button class, assuming that the activation
context is created using a manifest that references COMCTL32 version 6.

For those interested in how this applies to the .NET Framework, the
Application.EnableVisualStyles instructs the Framework to create and manage
an activation context when creating windows.

I recommend reading the "Using the Activation Context API" section in the
Platform SDK for more information.
<
http://msdn.microsoft.com/library/en-us/sbscs/setup/using_the_activat...
ntext_api.asp>

Dave Anderson
Microsoft Developer Support

This posting is provided "AS IS" with no warranties, and confers no rights.


 
   
您需要先 登录才能发帖。
要发帖,您需要先 加入此论坛
请先在 订阅设置页上更新您的昵称,然后再进行发帖。
您没有发帖的权限。

 

  
David Lowndes  
查看个人资料   翻译成中文(简体) 翻译内容(查看原文内容)
 更多选项 2004年3月13日, 下午11时56分
新闻论坛: microsoft.public.platformsdk.shell
发件人: David Lowndes <dav...@example.invalid>
日期: Sat, 13 Mar 2004 15:53:33 +0000
当地时间: 2004年3月13日(星期六) 下午11时53分
主题: Re: How to force XP look in feel in shell extensions

>I suspect that you are building with ISOLATION_AWARE_ENABLED defined to 1.

You're right, I am. Thanks for the explanation Dave, that's certainly
helped clarify what's going on and how it works.

There just aren't enough hours in the day to find out about all the
things I ought to have some insight into - at least not, and have any
semblance of a life too!

Cheers
Dave Lowndes

 

另外,根据IsolationAwarePrivateT_SqbjaYRiRY 这个关键字,又搜到了这篇文章,地址:http://blog.csdn.net/zhangym365/article/details/6295127,估计该方法也是来自于以上红色部分的启发。

 

网上基于vc6.0的activex增加 xp 风格(theme)都不起作用(其实已经实现了,只是大多数程序都是用mfc的创建用户控件函数所以还是不起作用),

如何定义XP风格的文章很多,可参见http://blog.csdn.net/greenerycn/article/details/3150247,但是纯粹采用这个办法采用MFC的Activex或者DLL项目根本就没有反应。原因如下:

原来是因为定义了#define ISOLATION_AWARE_ENABLED 1关键字后,所有的创建函数转到WinBase.Inl中,

通过 application and hosted component来实现,但是mfc中的实现并没有转

,所以只要在调用前稍作修改就能真正实现vc6的 activex控件xp风格了。

所以通过这个方法,用vc6编写的activex IE插件 动态库等应该都能实现xp风格了。

 

关键代码:

 

BOOL fResult = FALSE;

    ULONG_PTR  ulpCookie = 0;

    const BOOL fActivateActCtxSuccess = IsolationAwarePrivateG_FqbjaLEiEL || IsolationAwarePrivatenCgIiAgEzlnCgpgk(&ulpCookie);

    if (!fActivateActCtxSuccess)

        return fResult;

    __try

    {

        //fResult = GetClassInfoExW(unnamed1,unnamed2,unnamed3);

CRect rect(0,0,200,20);

button.Create("test",WS_VISIBLE,rect,this,12);   //这里是真正的mfc创建控件的调用

    }

    __finally

    {

        if (!IsolationAwarePrivateG_FqbjaLEiEL)

        {

            const BOOL fPreserveLastError = (fResult == FALSE);

            const DWORD dwLastError = fPreserveLastError ? GetLastError() : NO_ERROR;

            (void)IsolationAwareDeactivateActCtx(0, ulpCookie);

            if (fPreserveLastError)

                SetLastError(dwLastError);

        }

    }

    return fResult;

 

 

朋友做的封装,可以参考:

class CXP

{

public:

CXP() {

m_ulpCookie = 0;

m_bCtxSuccess = IsolationAwarePrivateG_FqbjaLEiEL || IsolationAwarePrivatenCgIiAgEzlnCgpgk(&m_ulpCookie);

}

virtual ~CXP() {

if(m_bCtxSuccess) IsolationAwareDeactivateActCtx(0, m_ulpCookie);

}

 

ULONG_PTR  m_ulpCookie;

BOOL m_bCtxSuccess;

};

CDlg_Test dlg;

{

  CXP XP;

  if(dlg.DoModal()==IDCANCEL) return FALSE;

}

 

根据以上两篇文章,总结出在dll或activex里,如果采用MFC来创建出具有xp风格的窗体,需要经过以下步骤:

1.创建mydll.manifest资源文件,该文件内容为

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

 

2.在vc6.0的资源编辑器中,importt一个类型为24,ID为2的资源,文件指向mydll.manifest.

3.在stdafx.h中,在所有的#include语句前加入#define ISOLATION_AWARE_ENABLED 1

4.创建一个类:

class CXP

{

public:

CXP() {

m_ulpCookie = 0;

m_bCtxSuccess = IsolationAwarePrivateG_FqbjaLEiEL || IsolationAwarePrivatenCgIiAgEzlnCgpgk(&m_ulpCookie);

}

virtual ~CXP() {

if(m_bCtxSuccess) IsolationAwareDeactivateActCtx(0, m_ulpCookie);

}

 

ULONG_PTR  m_ulpCookie;

BOOL m_bCtxSuccess;

};

5.你的dll或activex中,在每个要创建的窗体前加上CXP XP,然后再调用创建窗体的语句。

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值