在一个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 .其实在微软的文档中,对此错误已经有了说明,文章内容如下:
/* 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> //在shlobj的前面include这个wininet头文件 #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> ...
原因就是在wininet头文件中有这样的定义:
//File wininet.h ... #if !defined(_WININET_) #define _WININET_ ...