你好,欢迎来到电脑编程技巧与维护杂志社! 杂志社简介广告服务读者反馈编程社区  
合订本订阅
 
 
您的位置:杂志经典 / 编程语言
利用IContextMenu接口实现Windows外壳的上下文菜单操作
 

Windows 外壳的上下文菜单给使用者带来了很多方便之处,若能把此项功能加入到自己开发的项目中,肯定会为产品增色不少。下面,我就向大家介绍一种用MFC(微软基础类)实现Windows 外壳上下文菜单的方法。

 

一、实现过程概述

Windows 外壳的上下文菜单属于Windows外壳扩展操作的一种,若想使用外壳扩展操作(例如:属性页、上下文菜单、拖拽操作)就必须首先对外壳扩展操作进行初始化,我们可通过调用IshellExtInit接口来完成此项工作,初始化完毕后我们便可调用IContextMenu接口来完成Windows 外壳的上下文菜单。

二、相关背景知识简介

由于我们的编码工作是基于COM(组件对象模型)基础上的,所以还应具备一些

编写COM程序的基本知识,编写COM程序可用多种语言、多种方法,这里只简要介绍使用VCMFC编写COM程序的方法。关于其他方法,有兴趣的读者可参阅一些相关资料。

虽然MFC不支持直接使用COM,但是MFC的结构提供了特殊的技术支持,它可以使加入COM功能变得非常简单。在MFC中类CCmdTargetIunknown接口提供了标准实现,如果对象从CCmdTarget基类继承,则该对象可通过MFCCOleObjectFactory来自动创建,COleObjectFactory通过DLL入口点DllGetClassObject调用。如果COM类不是从CCmdTarget为基类的类中继承而来,就必须在函数DllGetClassObject中加入特殊的对象创建代码以创建对象的实例。在使用CCmdTarget作为基类后,我们便可调用一系列的支持宏来轻松实现COM对象。

MFC实现COM对象的过程有了一定了解后,我们就来具体谈一谈程序中所要用到的两个接口IContextMenuIshellExtInit(详细信息请查阅微软相关文档):

1        IContextMenu的方法:

1) IContextMenu::GetCommandString

格式:HRESULT GetCommandString(

       UINT idCmd,

                                UINT uFlags,

                                UINT *pwReserved,

                                LPSTR pszName,

                                UINT cchMax

  );

参数:uFlags  指定的信息标志。

  pwReserved  保留字。必须为NULL

     pszName   以空结尾的字符的串地址。

  cchMax   以空结尾的字符的最大长度。

作用:得到上下文菜单选项的命令行和帮助文字。

返回值:成功返回NOERROR,否则返回一个OLE错误值。 

2) IContextMenu::InvokeCommand

格式:HRESULT InvokeCommand( LPCMINVOKECOMMANDINFO lpici );

参数: lpici 上下文菜单选项的命令信息结构。

作用:得到上下文菜单选项的命令信息。

       返回值:成功返回NOERROR,否则返回一个OLE错误值。

3) IContextMenu::QueryContextMenu

格式:HRESULT QueryContextMenu(

                                HMENU hmenu,

                                UINT indexMenu,

                                UINT idCmdFirst,

                                UINT idCmdLast,

                                UINT uFlags

                               );

作用:可加入菜单选项到指定菜单。

参数:hmenu  指定菜单句柄。

      indexMenu  插入菜单选项的位置索引(以0为基准)。

      idCmdFirst  菜单选项可被指定的最小命令编号。

      idCmdLast  菜单选项可被指定的最大命令编号。

      uFlags  菜单选项的风格标志。

       返回值:成功返回添加菜单项数。

三、IShellExtInit的方法:

1IShellExtInit::Initialize

    格式:HRESULT Initialize(

                                  LPCITEMIDLIST pidlFolder,

                              LPDATAOBJECT lpdobj,

                              HKEY hkeyProgID

                             );

    作用:初始化外壳扩展操作(例如:属性页、上下文菜单、拖拽操作)。

    参数:pidlFolder  一个ITEMIDLIST结构的地址。

             lpdobj  一个能被用的IDataObject接口地址。

             hkeyProgID  文件对象或文件夹类型的注册号。

    返回值:成功返回NOERROR,否则返回一个OLE错误值。

1          主要源程序:

1 ContextMenuSample.h文件

#if !defined(AFX_CONTEXTMENUSAMPLE_H__5F5F7E71_ADC6_11D3_AF23_AC9F5AA57808__INCLUDED_)

#define AFX_CONTEXTMENUSAMPLE_H__5F5F7E71_ADC6_11D3_AF23_AC9F5AA57808__INCLUDED_

#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000

// ContextMenuSample.h : header file

//

#include <shlobj.h>

/////////////////////////////////////////////////////////////////////////////

// CContextMenuSample command target

class CContextMenuSample : public CCmdTarget

{

    DECLARE_DYNCREATE(CContextMenuSample)

    CContextMenuSample();           // protected constructor used by dynamic creation

// Attributes

public:

// Operations

public:

// Overrides

    // ClassWizard generated virtual function overrides

    //{{AFX_VIRTUAL(CContextMenuSample)

    public:

    virtual void OnFinalRelease();

    //}}AFX_VIRTUAL

// Implementation

protected:

    virtual ~CContextMenuSample();

    // Generated message map functions

    //{{AFX_MSG(CContextMenuSample)

        // NOTE - the ClassWizard will add and remove member functions here.

    //}}AFX_MSG

    DECLARE_MESSAGE_MAP()

    // Generated OLE dispatch map functions

    //{{AFX_DISPATCH(CContextMenuSample)

        // NOTE - the ClassWizard will add and remove member functions here.

    //}}AFX_DISPATCH

    DECLARE_DISPATCH_MAP()

    DECLARE_OLECREATE(CContextMenuSample)

    //支持COM接口映射

    DECLARE_INTERFACE_MAP()

    //BEGIN_INTERFACE_PART(类名,接口名)

    //开始定义接口类

    //不必要加入IUnknown接口方法,IUnknown接口方法可自动加入类中

    BEGIN_INTERFACE_PART(CMS,IContextMenu)

    STDMETHOD(QueryContextMenu)(HMENU hmenu,

                                UINT indexMenu,

                                UINT idCmdFirst,

                                UINT idCmdLast,

                                UINT uFlags);

    STDMETHOD(InvokeCommand)(LPCMINVOKECOMMANDINFO lpici);

    STDMETHOD(GetCommandString)(UINT        idCmd,

                                UINT        uType,

                                UINT      * pwReserved,

                                LPSTR       pszName,

                                UINT        cchMax);

    END_INTERFACE_PART(CMS)

    //

    //BEGIN_INTERFACE_PART(类名,接口名)

    //开始定义接口类

    BEGIN_INTERFACE_PART(SEI,IShellExtInit)

    STDMETHOD(Initialize)(LPCITEMIDLIST pidlFolder,

                          LPDATAOBJECT lpdobj,

                          HKEY hkeyProgID);

   

    END_INTERFACE_PART(SEI)

};

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}

// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_CONTEXTMENUSAMPLE_H__5F5F7E71_ADC6_11D3_AF23_AC9F5AA57808__INCLUDED_)

2. ContextMenuSample.cpp文件

// ContextMenuSample.cpp : implementation file

//

#include "stdafx.h"

#include "CMS.h"

#include "ContextMenuSample.h"

#include "Commacros.h"

 

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[] = __FILE__;

#endif

//

#define ResultFromShort(i)  ResultFromScode(MAKE_SCODE(SEVERITY_SUCCESS, 0, (USHORT)(i)))

/////////////////////////////////////////////////////////////////////////////

// CContextMenuSample

IMPLEMENT_DYNCREATE(CContextMenuSample, CCmdTarget)

CContextMenuSample::CContextMenuSample()

{

    EnableAutomation();

}

CContextMenuSample::~CContextMenuSample()

{

}

void CContextMenuSample::OnFinalRelease()

{

    // When the last reference for an automation object is released

    // OnFinalRelease is called.  The base class will automatically

    // deletes the object.  Add additional cleanup required for your

    // object before calling the base class.

    CCmdTarget::OnFinalRelease();

}

BEGIN_MESSAGE_MAP(CContextMenuSample, CCmdTarget)

    //{{AFX_MSG_MAP(CContextMenuSample)

        // NOTE - the ClassWizard will add and remove mapping macros here.

    //}}AFX_MSG_MAP

END_MESSAGE_MAP()

BEGIN_DISPATCH_MAP(CContextMenuSample, CCmdTarget)

    //{{AFX_DISPATCH_MAP(CContextMenuSample)

        // NOTE - the ClassWizard will add and remove mapping macros here.

    //}}AFX_DISPATCH_MAP

END_DISPATCH_MAP()

// Note: we add support for IID_IContextMenuSample to support typesafe binding

//  from VBA.  This IID must match the GUID that is attached to the

//  dispinterface in the .ODL file.

//

// {5F5F7E70-ADC6-11D3-AF23-AC9F5AA57808}

static const IID IID_IContextMenuSample =

{ 0x5f5f7e70, 0xadc6, 0x11d3, { 0xaf, 0x23, 0xac, 0x9f, 0x5a, 0xa5, 0x78, 0x8 } };

//IMPLEMENT_OLECREATE宏,可自动实现类对象实例化

IMPLEMENT_OLECREATE(CContextMenuSample,"ContextMenuSample",  0x5f5f7e70, 0xadc6, 0x11d3,  0xaf, 0x23, 0xac, 0x9f, 0x5a, 0xa5, 0x78, 0x8 )

//实现接口映射

BEGIN_INTERFACE_MAP(CContextMenuSample, CCmdTarget)

    //IContextMenu  接口

    INTERFACE_PART(CContextMenuSample, IID_IContextMenu, CMS)

    //IShellExtInit 接口

    INTERFACE_PART(CContextMenuSample, IID_IShellExtInit, SEI)

END_INTERFACE_MAP()

/////////////////////////////////////////////////////////////////////////////

// CContextMenuSample message handlers

//IShellExtInit接口的实现

//IMPLEMENT_IUNKNOWN实现了IUnknown接口的基本方法,请参阅Commacros.h文件

IMPLEMENT_IUNKNOWN(CContextMenuSample,SEI)

STDMETHODIMP CContextMenuSample::XSEI::Initialize(LPCITEMIDLIST pidlFolder,

                                                            LPDATAOBJECT lpdobj,

HKEY hkeyProgID)

{

    //METHOD_PROLOGUE 宏用于建立名叫pThis的局部变量,该变量是指向接口函数表的指针。

    //该宏必须置于每个接口实现之前。

    METHOD_PROLOGUE(CContextMenuSample,SEI);

    return (HRESULT)NOERROR;

}

//IMPLEMENT_IUNKNOWN实现了IUnknown接口的基本方法,请参阅Commacros.h文件

IMPLEMENT_IUNKNOWN(CContextMenuSample,CMS)

STDMETHODIMP CContextMenuSample::XCMS::QueryContextMenu(

                                                 HMENU hmenu,

                                                 UINT indexMenu,

                                                 UINT idCmdFirst,

                                                 UINT idCmdLast,

                                                 UINT uFlags)

{

    METHOD_PROLOGUE(CContextMenuSample,CMS);

    UINT idCmd = idCmdFirst;

    //在上下文菜单中添加菜单选项

    InsertMenu(hmenu,indexMenu,MF_STRING|MF_BYPOSITION,idCmd++,"CMS Sample");

    //得到位图

    HBITMAP hBmp = LoadBitmap(AfxGetApp()->m_hInstance, MAKEINTRESOURCE(IDB_BMP));

    //在菜单旁设置位图

    SetMenuItemBitmaps(hmenu, indexMenu, MF_BYPOSITION, hBmp, hBmp);

    return ResultFromShort(idCmd - idCmdFirst);

}

STDMETHODIMP CContextMenuSample::XCMS::InvokeCommand(LPCMINVOKECOMMANDINFO lpici)

{

    METHOD_PROLOGUE(CContextMenuSample,CMS);

    //检测菜单项是否被选中

    if (!HIWORD(lpici->lpVerb))

    {

       UINT idCmd = LOWORD(lpici->lpVerb);

       if(idCmd==0)

           AfxMessageBox("ContextMenu Sample !");

    }

    return (HRESULT)NOERROR;

 

}

STDMETHODIMP CContextMenuSample::XCMS::GetCommandString(

                                                 UINT        idCmd,

                                                 UINT        uType,

                                                 UINT      * pwReserved,

                                                 LPSTR       pszName,

                                                 UINT        cchMax)

{

    METHOD_PROLOGUE(CContextMenuSample,CMS);

    return (HRESULT)NOERROR;

}

四、测试方法:

1.将生成的cms.dll拷入C:\windows\system文件夹下。

2.双击CMS文件夹下的CMS.reg文件,注册完毕后会显示对话框。

3.选取任一文件夹,按右键弹出上下文菜单后,点击上下文菜单上的CMS Sample选项即可。

有兴趣的朋友,可到我们的主页(http://cave.163.net)下载源程序cmsdoc.zip

参考文献:

    1. Visual C++ 5 ActiveX 编程指南》,清华大学出版社,1998

    2. 《基于组件的应用程序设计》,北京大学出版社,1999

 

  推荐精品文章

·2024年9月目录 
·2024年8月目录 
·2024年7月目录 
·2024年6月目录 
·2024年5月目录 
·2024年4月目录 
·2024年3月目录 
·2024年2月目录 
·2024年1月目录
·2023年12月目录
·2023年11月目录
·2023年10月目录
·2023年9月目录 
·2023年8月目录 

  联系方式
TEL:010-82561037
Fax: 010-82561614
QQ: 100164630
Mail:gaojian@comprg.com.cn

  友情链接
 
Copyright 2001-2010, www.comprg.com.cn, All Rights Reserved
京ICP备14022230号-1,电话/传真:010-82561037 82561614 ,Mail:gaojian@comprg.com.cn
地址:北京市海淀区远大路20号宝蓝大厦E座704,邮编:100089