设置桌面壁纸时 'IActiveDesktop' : undeclared identifier 的处理

VC/MFC 同时被 2 个专栏收录
199 篇文章 3 订阅
56 篇文章 0 订阅

//Added by jiangqin 2016-09-10
//修改桌面壁纸的相关接口虽在shlobj.h中定义,但却又依赖宏开关_WININET_
//而宏_WININET_在wininet.h定义,必须要将wininet.h声明放在shlobj.h前面
//参考:http://blog.csdn.net/sibylle/article/details/2029457
//最好将wininet.h声明在stdafx.h文件中的,但声明位置要注意,如下:
//#include <afxwin.h>         //MFC 核心组件和标准组件
//#include <afxext.h>         //MFC 扩展
//#include <wininet.h>        //在这里声明,不能早也不能晚


具体分析如下:

 在一个COM例子中,编译出现了错误,这个例子很简单,用vc新建一个Win32 Console Application项目,然后选择An application that supports MFC,然后加入如下函数,并在_tmain()里调用.

TestIActiveDesktop()
{
    WCHAR   wszWallpaper [MAX_PATH]; 
    CString strPath; 
    HRESULT hr; 
    IActiveDesktop
* pIAD; 
    
    
// 1. 初始化COM库(让Windows加载DLLs)。通常是在程序的InitInstance()中调用 
    
// CoInitialize ( NULL )或其它启动代码。MFC程序使用AfxOleInit()。 
    
    CoInitialize ( NULL ); 
    
    
// 2. 使用外壳提供的活动桌面组件对象类创建COM对象。 
    
// 第四个参数通知COM需要什么接口(这里是IActiveDesktop). 
    
    hr 
= CoCreateInstance ( CLSID_ActiveDesktop, 
        NULL, 
        CLSCTX_INPROC_SERVER, 
        IID_IActiveDesktop, 
        (
void**&pIAD ); 
    
    
if ( SUCCEEDED(hr) ) 
    

        
// 3. 如果COM对象被创建成功,则调用这个对象的GetWallpaper() 方法。 
        hr = pIAD->GetWallpaper ( wszWallpaper, MAX_PATH, 0 ); 
        
        
if ( SUCCEEDED(hr) ) 
        

            
// 4. 如果 GetWallpaper() 成功,则输出它返回的文件名字。 
            
// 注意这里使用wcout 来显示Unicode 串wszWallpaper.  wcout 是 
            
// Unicode 专用,功能与cout.相同。 
            wcout << L"Wallpaper path is:    " << wszWallpaper << endl << endl; 
        }
 
        
else 
        

            cout 
<< _T("GetWallpaper() failed."<< endl << endl; 
        }
 
        
        
// 5. 释放接口。 
        pIAD->Release(); 
    }
 
    
else 
    

        cout 
<< _T("CoCreateInstance() failed."<< endl << endl; 
    }
 
    
    
// 6. 收回COM库。MFC 程序不用这一步,它自动完成。 
    CoUninitialize(); 
    
}

 

    编译,发生错误.编译错误信息为 error C2065: 'IActiveDesktop' : undeclared identifier .其实在微软的文档中,对此错误已经有了说明,文档号为Q196342,那么到哪去找这个文档呢?网址在 http://msdn2.microsoft.com/zh-cn/aa570318.aspx 搜索Q196342即可.如果没有搜索到,在显示更多搜索选项里扩大范围,文章内容如下:

/*
http://support.microsoft.com/kb/196342/en-us

PRB: ActiveDesktop Compilation Errors Under Visual C++ 6.0 MFC
View products that this article applies to.
Article ID : 196342 
Last Review : June 18, 2001 
Revision : 1.0 
This article was previously published under Q196342
SYMPTOMS
Under Visual C++ 6.0 Microsoft Foundation Classes (MFC), compiling code related to the IActiveDesktop interface will fail with multiple errors, including an "undeclared identifier" for LPACTIVEDESKTOP. 

Note that this occurs specifically when compiling an MFC program using Visual C++ 6.0. There is no report of the problem occurring in previous versions of MFC or in the general Visual C++ 6.0 case where C or C++ programs are being compiled. 
Back to the top

CAUSE
When an MFC application includes the Stdafx.h header file, the file *Vc98MfcIncludeAfxdisp.h is included by default. Within Afxdisp.h the file Shlobj.h (required for ActiveDesktop) is included. But at this point, Wininet.h has not been included, so certain portions of Shlobj.h are not correctly initialized for ActiveDesktop support. 

The inclusion of Shlobj.h by Afxdisp.h also sets a variable preventing Shlobj.h from being included twice. Later, when an MFC application explicitly and correctly includes Wininet.h followed by Shlobj.h, the previously set variable prevents the second Shlobj.h inclusion and also prevents critical ActiveDesktop definitions, such as for LPACTIVEDESKTOP, from being made. 
Back to the top

RESOLUTION
Add a #include for the Wininet.h header to the Stdafx.h precompiled header file, just above the Afxdisp.h include. Here's an example of Stdafx.h: // stdafx.h : include file for standard system include files,

...

#include <wininet.h>
#include <afxdisp.h>        // MFC Automation classes

...

#endif //!defined(AFX_STDAFX_H__D5E466A9...
                
After correcting Stdafx.h, rebuild the entire project to ensure that the precompiled header is re-compiled. 

*/

    也就是说,在使用vc6.0的向导生成的项目中,生成的project都默认生成并包含Stdafx.h,此头文件中又默认包涵Afxdisp.h(系统头文件),而Shlobj.h又默认包含在Afxdisp.h中,而在此之前Wininet.h并没有包含进来,导致_WININET_没有预定义,IActiveDesktop的声明就不会编译(需要首先有_WININET_的声明).而就算后面明确的包含了Wininet.h和Shlobj.h,由于头文件的有宏保护重定义,所以依然无效.

    具体到我的项目,有所不同,看代码:

// File stdafx.h

...
#include <afx.h>
#include <afxwin.h>         // MFC core and standard components
#include <afxext.h>         // MFC extensions
#include <afxdtctl.h>        // MFC support for Internet Explorer 4 Common Controls
#ifndef _AFX_NO_AFXCMN_SUPPORT
#include <afxcmn.h>            // MFC support for Windows Common Controls
#endif // _AFX_NO_AFXCMN_SUPPORT

#include <iostream>
...

 

// File afxdtctl.h

...
#ifndef __AFXDISP_H__
    #include 
< afxdisp.h >
#endif
...

 

// File afxdisp.h

...
//  Shell interface support
#ifndef _SHLOBJ_H_
    #include 
< shlobj.h >
#endif
...

 

// File shlobj.h

...
//
//  We need to make sure that WININET.H is included before this interface is
//  used because the COMPONENT structure uses INTERNET_MAX_URL_LENGTH
//
#ifdef _WININET_
//
//   Flags and structures used by IActiveDesktop
//

typedef 
struct  _tagWALLPAPEROPT
{
    DWORD   dwSize;     
// size of this Structure.
    DWORD   dwStyle;    // WPSTYLE_* mentioned above
}

WALLPAPEROPT;

typedef WALLPAPEROPT  
* LPWALLPAPEROPT;
typedef 
const  WALLPAPEROPT  * LPCWALLPAPEROPT;

typedef 
struct  _tagCOMPONENTSOPT
{
    DWORD   dwSize;             
//Size of this structure
    BOOL    fEnableComponents;  //Enable components?
    BOOL    fActiveDesktop;     // Active desktop enabled ?
}

COMPONENTSOPT;

typedef COMPONENTSOPT   
* LPCOMPONENTSOPT;
typedef 
const  COMPONENTSOPT    * LPCCOMPONENTSOPT;

typedef 
struct  _tagCOMPPOS
{
    DWORD   dwSize;             
//Size of this structure
    int     iLeft;              //Left of top-left corner in screen co-ordinates.
    int     iTop;               //Top of top-left corner in screen co-ordinates.
    DWORD   dwWidth;            // Width in pixels.
    DWORD   dwHeight;           // Height in pixels.
    int     izIndex;            // Indicates the Z-order of the component.
    BOOL    fCanResize;         // Is the component resizeable?
    BOOL    fCanResizeX;        // Resizeable in X-direction?
    BOOL    fCanResizeY;        // Resizeable in Y-direction?
    int     iPreferredLeftPercent;    //Left of top-left corner as percent of screen width
    int     iPreferredTopPercent;     //Top of top-left corner as percent of screen height
}

COMPPOS;

typedef COMPPOS 
* LPCOMPPOS;
typedef 
const  COMPPOS  * LPCCOMPPOS;




#define  COMPONENT_TOP (0x7fffffff)   //  izOrder value meaning component is at the top


//  iCompType values
#define  COMP_TYPE_HTMLDOC       0
#define  COMP_TYPE_PICTURE       1
#define  COMP_TYPE_WEBSITE       2
#define  COMP_TYPE_CONTROL       3
#define  COMP_TYPE_CFHTML        4
#define  COMP_TYPE_MAX           4

typedef 
struct  _tagCOMPONENT
{
    DWORD   dwSize;             
//Size of this structure
    DWORD   dwID;               //Reserved: Set it always to zero.
    int     iComponentType;     //One of COMP_TYPE_*
    BOOL    fChecked;           // Is this component enabled? 
    BOOL    fDirty;             // Had the component been modified and not yet saved to disk?
    BOOL    fNoScroll;          // Is the component scrollable?
    COMPPOS cpPos;              // Width, height etc.,
    WCHAR   wszFriendlyName[MAX_PATH];          // Friendly name of component.
    WCHAR   wszSource[INTERNET_MAX_URL_LENGTH]; //URL of the component.
    WCHAR   wszSubscribedURL[INTERNET_MAX_URL_LENGTH]; //Subscrined URL
}

COMPONENT;

typedef COMPONENT 
* LPCOMPONENT;
typedef 
const  COMPONENT  * LPCCOMPONENT;




////
//  Flags for IActiveDesktop::ApplyChanges()
#define  AD_APPLY_SAVE         0x00000001
#define  AD_APPLY_HTMLGEN      0x00000002
#define  AD_APPLY_REFRESH      0x00000004
#define  AD_APPLY_ALL     (AD_APPLY_SAVE | AD_APPLY_HTMLGEN | AD_APPLY_REFRESH)
#define  AD_APPLY_FORCE        0x00000008
#define  AD_APPLY_BUFFERED_REFRESH 0x00000010

////
//  Flags for IActiveDesktop::GetWallpaperOptions()
//            IActiveDesktop::SetWallpaperOptions()
#define  WPSTYLE_CENTER      0
#define  WPSTYLE_TILE        1
#define  WPSTYLE_STRETCH     2
#define  WPSTYLE_MAX         3


////
//  Flags for IActiveDesktop::ModifyComponent()

#define  COMP_ELEM_TYPE          0x00000001
#define  COMP_ELEM_CHECKED       0x00000002
#define  COMP_ELEM_DIRTY         0x00000004
#define  COMP_ELEM_NOSCROLL      0x00000008
#define  COMP_ELEM_POS_LEFT      0x00000010
#define  COMP_ELEM_POS_TOP       0x00000020
#define  COMP_ELEM_SIZE_WIDTH    0x00000040
#define  COMP_ELEM_SIZE_HEIGHT   0x00000080
#define  COMP_ELEM_POS_ZINDEX    0x00000100
#define  COMP_ELEM_SOURCE        0x00000200
#define  COMP_ELEM_FRIENDLYNAME  0x00000400
#define  COMP_ELEM_SUBSCRIBEDURL 0x00000800

#define  COMP_ELEM_ALL   (COMP_ELEM_TYPE | COMP_ELEM_CHECKED | COMP_ELEM_DIRTY |          
                         COMP_ELEM_NOSCROLL 
|  COMP_ELEM_POS_LEFT  |  COMP_ELEM_SIZE_WIDTH  
                         COMP_ELEM_SIZE_HEIGHT 
|  COMP_ELEM_POS_ZINDEX  |  COMP_ELEM_SOURCE 
                         COMP_ELEM_FRIENDLYNAME )


////
//  Flags for IActiveDesktop::AddDesktopItemWithUI()
typedef  enum  tagDTI_ADTIWUI
{
    DTI_ADDUI_DEFAULT               
= 0x00000000,
    DTI_ADDUI_DISPSUBWIZARD         
= 0x00000001,
}
;


////
//  Flags for IActiveDesktop::AddUrl()
#define  ADDURL_SILENT           0X0001





//
//   Interface for manipulating the Active Desktop.
//

#undef  INTERFACE
#define  INTERFACE IActiveDesktop

DECLARE_INTERFACE_( IActiveDesktop, IUnknown )
{
    
// IUnknown methods
    STDMETHOD (QueryInterface)(THIS_ REFIID riid, void ** ppv) PURE;
    STDMETHOD_(ULONG, AddRef) ( THIS ) PURE;
    STDMETHOD_(ULONG, Release) ( THIS ) PURE;

    
// IActiveDesktop methods
    STDMETHOD (ApplyChanges)(THIS_ DWORD dwFlags) PURE;
    STDMETHOD (GetWallpaper)(THIS_ LPWSTR pwszWallpaper, UINT cchWallpaper, DWORD dwReserved) PURE;
    STDMETHOD (SetWallpaper)(THIS_ LPCWSTR pwszWallpaper, DWORD dwReserved) PURE;
    STDMETHOD (GetWallpaperOptions)(THIS_ LPWALLPAPEROPT pwpo, DWORD dwReserved) PURE;
    STDMETHOD (SetWallpaperOptions)(THIS_ LPCWALLPAPEROPT pwpo, DWORD dwReserved) PURE;
    STDMETHOD (GetPattern)(THIS_ LPWSTR pwszPattern, UINT cchPattern, DWORD dwReserved) PURE;
    STDMETHOD (SetPattern)(THIS_ LPCWSTR pwszPattern, DWORD dwReserved) PURE;
    STDMETHOD (GetDesktopItemOptions)(THIS_ LPCOMPONENTSOPT pco, DWORD dwReserved) PURE;
    STDMETHOD (SetDesktopItemOptions)(THIS_ LPCCOMPONENTSOPT pco, DWORD dwReserved) PURE;
    STDMETHOD (AddDesktopItem)(THIS_ LPCCOMPONENT pcomp, DWORD dwReserved) PURE;
    STDMETHOD (AddDesktopItemWithUI)(THIS_ HWND hwnd, LPCOMPONENT pcomp, DWORD dwReserved) PURE;
    STDMETHOD (ModifyDesktopItem)(THIS_ LPCCOMPONENT pcomp, DWORD dwFlags) PURE;
    STDMETHOD (RemoveDesktopItem)(THIS_ LPCCOMPONENT pcomp, DWORD dwReserved) PURE;
    STDMETHOD (GetDesktopItemCount)(THIS_ LPINT lpiCount, DWORD dwReserved) PURE;
    STDMETHOD (GetDesktopItem)(THIS_ 
int nComponent, LPCOMPONENT pcomp, DWORD dwReserved) PURE;
    STDMETHOD (GetDesktopItemByID)(THIS_ DWORD dwID, LPCOMPONENT pcomp, DWORD dwReserved) PURE;
    STDMETHOD (GenerateDesktopItemHtml)(THIS_ LPCWSTR pwszFileName, LPCOMPONENT pcomp, DWORD dwReserved) PURE;
    STDMETHOD (AddUrl)(THIS_ HWND hwnd, LPCWSTR pszSource, LPCOMPONENT pcomp, DWORD dwFlags) PURE;
    STDMETHOD (GetDesktopItemBySource)(THIS_ LPCWSTR pwszSource, LPCOMPONENT pcomp, DWORD dwReserved) PURE;
}
;

typedef IActiveDesktop 
*  LPACTIVEDESKTOP;


#endif   //  _WININET_
...

    可以看出,IActiveDesktop 的定义是在#ifdef  _WININET_   后才有意义的,但是默认是没有_WININET_定义的,所以解决方案也很简单,在包含头文件shlobj.h前包含Wininet.h即可,如下所示:

// File stdafx.h
...
#include 
< afx.h >
#include 
< afxwin.h >           //  MFC core and standard components
#include  < afxext.h >           //  MFC extensions

#include 
< wininet.h >

#include 
< afxdtctl.h >          //  MFC support for Internet Explorer 4 Common Controls
#ifndef _AFX_NO_AFXCMN_SUPPORT
#include 
< afxcmn.h >              //  MFC support for Windows Common Controls
#endif   //  _AFX_NO_AFXCMN_SUPPORT

#include 
< iostream >
...




// File wininet.h
...
#if  !defined(_WININET_)
#define  _WININET_
...

    OK程序编译正常.

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值