.Net下通过CoGetClassObjectFromURL 安装 ActiveX控件

来源:互联网 发布:海南易建科技知乎 编辑:程序博客网 时间:2024/06/10 13:38
 
.Net下通过CoGetClassObjectFromURL 安装 ActiveX控件
 
 
1CoGetClassObjectFromURLMSDN上的说明
 
CoGetClassObjectFromURL Function
Returns a factory object for a given CLSID.
Syntax
HRESULT CoGetClassObjectFromURL(      
    REFCLSID rclsid,
    LPCWSTR szCodeURL,
    DWORD dwFileVersionMS,
    DWORD dwFileVersionLS,
    LPCWSTR szContentType,
    LPBINDCTX pBindCtx,
    DWORD dwClsContext,
    LPVOID pvReserved,
    REFIID riid,
    VOID **ppv
);
Parameters
rclsid
[in] CLSID of the Microsoft ActiveX object to be installed. If the value is CLSID_NULL, szContentType is used to determine the CLSID.
需要安装的ClassID,如果为空,则根据安装包里Inf文件信息进行安装。不过通常这样安装的时候会报错,但是基本上ActiveX都能安装上去。
szCodeURL
[in] Address of a string value that contains the full URL of the code for the ActiveX object.
AcitveX的安装路径,路径除了URL格式外,本地文件路径格式也支持。
dwFileVersionMS
[in] Unsigned long integer value that contains the major version number for the object to be installed. If this value and the value for dwFileVersionLS are both 0xFFFFFFFF, the latest version of the code should always be installed. This means that Internet Component Download will always attempt to download new code.
在安装AcitveX的时候,需要通过传入的的版本号与以安装文件的版本号进行比对,如果传入的版本号大于文件的版本号,则需要重新下载ActiveX控件。
通常文件版本由4位数字组成 a,b,c,d。例:1,0,0,3。这里的主版本由版本号的前两位a b数字组成,并使用MAKELONG(b,a)函数进行合并。对于下面的副版本,则通过MAKELONG(d,c)进行合并。
如果想每次安装都进行更新就将参数设为0xFFFFFFFF,实际上就是按照最大的版本号进行更新。
dwFileVersionLS
[in] Unsigned long integer value that contains the minor version number for the object to be installed. If this value and the value for dwFileVersionMS are both 0xFFFFFFFF, the latest version of the code should always be installed. This means that Internet Component Download will always attempt to download new code.
szContentType
[in] Pointer to a string value that contains the Multipurpose Internet Mail Extensions (MIME) type to be understood by the installed ActiveX object. If rclsid is CLSID_NULL, this string is used to determine the CLSID of the object to be installed. Note that this parameter is useful only when trying to download a viewer for a particular media type, when the MIME type of media is known but the CLSID is not.
pBindCtx
[in] Pointer to the bind context to use for downloading/installing component code. An implementation of IBindStatusCallback must be registered on this bind context before calling this function.
一个绑定有IbindStatuseCallback接口的对象,通常是用于显示ActiveX的安装进度。这个对象创建比较简单。按照提供的示例代码一步步完成即可。
dwClsContext
[in] Unsigned long integer value that specifies the execution context for the class object. This can be one of the values taken from the CLSCTX enumeration.
pvReserved
[in] Reserved. Must be set to NULL.
riid
[in] Reference identifier of the interface to obtain on the factory object. Usually this interface is IClassFactory.
ppv
[out] Address of an interface pointer for synchronous calls, or NULL otherwise.
Return Value
Returns one of the following values:

S_OK
The operation completed successfully and the ppv parameter contains the requested interface pointer.
ActiveX已经安装过
E_NOINTERFACE
The requested interface pointer is not available.
MK_S_ASYNCHRONOUS
Component code will be downloaded and installed asynchronously. The client will receive notifications through the IBindStatusCallback interface registered on pBindCtx.
ActiveX没有安装过,正在进行异步的安装,安装过程通过IBindStatusCallback的回调过程通知用户

 
Remarks
If no CLSID is specified (CLSID_NULL), this function chooses the appropriate CLSID for interpreting the MIME type specified in szContentType. If the desired object is installed on the system, it is instantiated. Otherwise, the necessary code is downloaded and installed from the location specified in szCodeURL.
CoGetClassObjectFromURL was designed to be used by MSHTML to retrieve the code for objects on a Web page. When the requested object is available for use on the user's computer, this function typically returns synchronously with a valid object reference. For objects that aren't available on the user's computer and need to be downloaded from szCodeURL, CoGetClassObjectFromURL will return asynchronously with MK_S_ASNYNCHRONOUS and notify the calling application through the IBindStatusCallback interface that was registered on pBindCtx.
Function Information

Stock Implementation
urlmon.dll
Custom Implementation
No
Header
Urlmon.h
Import library
Urlmon.lib
Minimum availability
Internet Explorer 4.0
Minimum operating systems
Windows NT 4.0, Windows 95

 
2CoGetClassObjectFromURL.Net 封装
     
      说明:安装ActiveX代码是用MSDN上的例子程序改编而成的,其目是为了给.net程序安装AcitveX控件。例子程序可以以“CoGetClassObjectFromURL”为关键字进行搜索MSDN找到。
 
      2.1 .Net
      regActiveX是一个封装了安装AcitveX控件的.net类,用托管C++编写(实际上是因为在调用windows资源的时候托管C++C#方便)其主要功能是调用CoGetClassObjectFromURL函数去安装AcitveX控件。在类里还增加两个时间,用于通知用户当前的安装进度已经安装结果。
 
     CDownload 实现了IBindStatusCallback接口,在安装ActiveX的过程中实现安装函数异步安装时的回调功能。该函数为C++代码。
StdAfx.h
#pragma once

#define VC_EXTRALEAN        // Exclude rarely-used stuff from Windows headers

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

regActiveX.h

#pragma once

#include 
"stdafx.h"
#include 
"string"

using namespace System;

namespace RegActiveX
{

    
public __delegate void OnProcessHandler(int Progress, int ProgressMax, int StatusCode, System::String* StatusText);
    
public __delegate void OnStopBindingHandler(int hrResult, System::String* Error);

    __gc 
public   class regActiveX: public System::Object
    {
    
private:

        regActiveX()
        {
            hwnd 
= NULL;
        }

    
protected:

        
//    注册 ActiveX 控件,该函数为执行函数
        void RegisterActiveX(wchar_t * classid, wchar_t * url, int v1, int v2, int v3, int v4);

    
public:

        regActiveX(System::IntPtr hWnd)
        {
            hwnd 
= hWnd;
        }

        System::IntPtr hwnd;

        
void RegisterActiveX(System::String * classid, System::String * url);
        
void RegisterActiveX(System::String * classid, System::String * url, int v1, int v2, int v3, int v4);

        __event OnProcessHandler
* OnProcess;
        __event OnStopBindingHandler
* OnStopBinding;

        
void onProcess(int Progress, int ProgressMax, int StatusCode, System::String* StatusText)
        {
            
if (OnProcess)
                OnProcess(Progress, ProgressMax, StatusCode, StatusText);
        }

        
void onStopBinding(int hrResult, System::String* Error)
        {
            
if (OnStopBinding)
                OnStopBinding(hrResult, Error);
        }

    };
}

regActiveX.cpp

#include 
"stdafx.h"

#include 
"RegActiveX.h"
#include 
"DownLoad.h"
#include 
"urlmon.h"

#pragma comment( lib, "Urlmon.lib" )
using namespace RegActiveX;

void regActiveX::RegisterActiveX(System::String * classid, System::String * url, int v1, int v2, int v3, int v4)
{
    
using namespace System::Runtime::InteropServices;
    wchar_t
* id = (wchar_t*)(void*)(Marshal::StringToHGlobalUni(classid));
    wchar_t
* u    = (wchar_t*)(void*)(Marshal::StringToHGlobalUni(url));
    RegisterActiveX(id, u, v1, v2, v3, v4);
}

void regActiveX::RegisterActiveX(System::String * classid, System::String * url)
{
    
using namespace System::Runtime::InteropServices;
    wchar_t
* id = (wchar_t*)(void*)(Marshal::StringToHGlobalUni(classid));
    wchar_t
* u    = (wchar_t*)(void*)(Marshal::StringToHGlobalUni(url));
    RegisterActiveX(id, u, 
0xFFFF0xFFFF0xFFFF0xFFFF);
}

void regActiveX::RegisterActiveX(wchar_t * classid, wchar_t * url, int v1, int v2, int v3, int v4)
{
    LPCLASSFACTORY pClassFactory;
    HRESULT hr;

    CLSID m_clsid;
    LPBINDCTX m_pBindContext 
= NULL;
    LPBINDSTATUSCALLBACK m_pBindStatusCallback    
= NULL;

    hr 
= OleInitialize(NULL);
    USES_CONVERSION;
    CLSIDFromString(classid, 
&m_clsid);

    hr 
= CreateBindCtx(0&m_pBindContext);

    BIND_OPTS bindopts;
    m_pBindContext
->GetBindOptions(&bindopts);
    bindopts.grfFlags 
|= BIND_MAYBOTHERUSER;
    m_pBindContext
->SetBindOptions(&bindopts);

    
//    绑定回调函数
    CDownload *download = new CDownload(this);
    download
->ExternalQueryInterface(&IID_IBindStatusCallback, (void **)&m_pBindStatusCallback);
    hr 
= RegisterBindStatusCallback(m_pBindContext, m_pBindStatusCallback, 00);

    
//    调用安装AcitveX的API函数
    hr = CoGetClassObjectFromURL(m_clsid, url, 
        MAKELONG(v2, v1),  MAKELONG(v4, v3), 
        NULL, m_pBindContext, 
        CLSCTX_INPROC_HANDLER 
| CLSCTX_INPROC_SERVER,
        
0, IID_IClassFactory, (void **)&pClassFactory);

    
//    如果ActiveX已经安装过,直接触发安装结束的事件
    if (hr == 0)    
        
if (OnStopBinding)
            OnStopBinding(
0, System::String::Empty);
}

int main()
{
    
//    不要问我为什么有这个东西,我也不清楚,反正没这个东西编译器不让我编译过去
}


CDownLoad.h

#pragma once
#include 
"RegActiveX.h"

#define VC_EXTRALEAN        // Exclude rarely-used stuff from Windows headers

#include 
<afxwin.h>         // MFC core and standard components
#include <afxext.h>         // MFC extensions
//#include <afxdisp.h>        // MFC OLE automation classes
//#ifndef _AFX_NO_AFXCMN_SUPPORT
//#include <afxcmn.h>            // MFC support for Windows Common Controls
//#endif // _AFX_NO_AFXCMN_SUPPORT
#define WM_ONSTOPBINDING WM_USER + 1001

/////////////////////////////////////////////////////////////////////////////
// CDownload command target

class CDownload : public CCmdTarget
{
    DECLARE_DYNCREATE(CDownload)

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

    
//    在安装过程中,需要触发一些安装事件,因此需要有一个 regActiveX 对象
    gcroot<RegActiveX::regActiveX*>  active;
    
// Attributes
public:
    CFormView
* m_pView;
    CDownload(gcroot
<RegActiveX::regActiveX*>  act)
    {
        active 
= act;
        hwnd 
= (HWND)(void*)act->hwnd;
    }

    
// Operations
public:
    
virtual ~CDownload();  // had to make the destructor public

    
//    显示安全提示时需要的句柄,这个不是必须存在的
    
//    到时候可以通过 active 来获取,这里独立出来只是为了方便而已。
    HWND hwnd;

    
// Overrides
    
// ClassWizard generated virtual function overrides
    
//{{AFX_VIRTUAL(CDownload)
    
//}}AFX_VIRTUAL

    
// Implementation
protected:
    
//    virtual ~CDownload();

    
// Generated message map functions
    
//{{AFX_MSG(CDownload)
    
// NOTE - the ClassWizard will add and remove member functions here.
    
//}}AFX_MSG

    DECLARE_MESSAGE_MAP()

public:
    DECLARE_INTERFACE_MAP()

    
// IBindStatusCallback
    BEGIN_INTERFACE_PART(BindStatusCallback, IBindStatusCallback)
        STDMETHOD(OnStartBinding)(DWORD grfBSCOption, IBinding
* pbinding);
        STDMETHOD(GetPriority)(LONG
* pnPriority);
        STDMETHOD(OnLowResource)(DWORD dwReserved);
        STDMETHOD(OnProgress)(ULONG ulProgress, ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText);
        STDMETHOD(OnStopBinding)(HRESULT hrResult, LPCWSTR szError);
        STDMETHOD(GetBindInfo)(DWORD
* pgrfBINDF, BINDINFO* pbindinfo);
        STDMETHOD(OnDataAvailable)(DWORD grfBSCF, DWORD dwSize, FORMATETC 
*pfmtetc, STGMEDIUM* pstgmed);
        STDMETHOD(OnObjectAvailable)(REFIID riid, IUnknown
* punk);
    END_INTERFACE_PART(BindStatusCallback)

        
// IWindowForBindingUI
        BEGIN_INTERFACE_PART(WindowForBindingUI, IWindowForBindingUI)
            STDMETHOD(GetWindow)(REFGUID rguidReason, HWND
* phwnd);
        END_INTERFACE_PART(WindowForBindingUI)
};

CDownLoad.cpp

#include 
"StdAfx.h"
#include 
".download.h"
#
using <mscorlib.dll>


IMPLEMENT_DYNCREATE(CDownload, CCmdTarget)

CDownload::CDownload()
{
    hwnd 
= NULL;
}

CDownload::
~CDownload()
{
}


BEGIN_MESSAGE_MAP(CDownload, CCmdTarget)
    
//{{AFX_MSG_MAP(CDownload)
    
// NOTE - the ClassWizard will add and remove mapping macros here.
    
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

BEGIN_INTERFACE_MAP(CDownload, CCmdTarget)
    INTERFACE_PART(CDownload, IID_IBindStatusCallback, BindStatusCallback)
    INTERFACE_PART(CDownload, IID_IWindowForBindingUI, WindowForBindingUI)
END_INTERFACE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CDownload message handlers

STDMETHODIMP_(ULONG) CDownload::XBindStatusCallback::AddRef()
{   
    METHOD_PROLOGUE(CDownload, BindStatusCallback)
        
return pThis->ExternalAddRef();
}   

STDMETHODIMP_(ULONG) CDownload::XBindStatusCallback::Release()
{   
    METHOD_PROLOGUE(CDownload, BindStatusCallback)
        
return pThis->ExternalRelease();
}   

STDMETHODIMP CDownload::XBindStatusCallback::QueryInterface(REFIID iid, 
void** ppvObj)
{   
    METHOD_PROLOGUE(CDownload, BindStatusCallback)
        
return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj) ;
}   

STDMETHODIMP CDownload::XBindStatusCallback::OnStartBinding(DWORD grfBSCOption, IBinding
* pbinding)
{
    METHOD_PROLOGUE(CDownload, BindStatusCallback)
        
return S_OK;
}

STDMETHODIMP CDownload::XBindStatusCallback::GetPriority(LONG
* pnPriority) 
{
    METHOD_PROLOGUE(CDownload, BindStatusCallback)
        
return E_NOTIMPL;
}

STDMETHODIMP CDownload::XBindStatusCallback::OnLowResource(DWORD dwReserved)
{
    METHOD_PROLOGUE(CDownload, BindStatusCallback)
        
return E_NOTIMPL;
}

STDMETHODIMP CDownload::XBindStatusCallback::OnProgress(ULONG ulProgress, ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText) 
{
    METHOD_PROLOGUE(CDownload, BindStatusCallback)

    
//    触发 OnProcess 事件,通知用户当前 Activex 安装进度
    if (pThis->active)
    {            
        pThis
->active->onProcess(ulProgress,
                                                 ulProgressMax,
                                                 ulStatusCode,
                                                 szStatusText
?new System::String(szStatusText):System::String::Empty        //状态字符串,在给用户的时候,把NULL转为空串                                );
    }    
    
return NOERROR;
}

STDMETHODIMP CDownload::XBindStatusCallback::OnStopBinding(HRESULT hrResult, LPCWSTR szError) 
{
    METHOD_PROLOGUE(CDownload, BindStatusCallback)

    
//    触发 OnStopBinding 事件,通知外层安装结束
    
//    如果hrResult为0,表示安装成功,并且szError为空
    
//    如果hrResult非0,表示安装失败,szError为安装失败原因
    if (pThis->active)
    {
            pThis
->active->onStopBinding(hrResult, 
                                                            szError
?new System::String(szError):System::String::Empty);
    }
    
return S_OK;
}

STDMETHODIMP CDownload::XBindStatusCallback::GetBindInfo(DWORD
* pgrfBINDF, BINDINFO* pbindinfo) 
{
     METHOD_PROLOGUE(CDownload, BindStatusCallback)
        
return S_OK;
}

STDMETHODIMP CDownload::XBindStatusCallback::OnDataAvailable(DWORD grfBSCF, DWORD dwSize, FORMATETC 
*pfmtetc, STGMEDIUM* pstgmed) 
{
    METHOD_PROLOGUE(CDownload, BindStatusCallback)
        
return S_OK;
}

STDMETHODIMP CDownload::XBindStatusCallback::OnObjectAvailable(REFIID riid, IUnknown
* punk) 
{
    METHOD_PROLOGUE(CDownload, BindStatusCallback)

        
if (riid != IID_IClassFactory || punk == NULL)
            
return E_INVALIDARG;

    
//pThis->m_pView->PostMessage(WM_ONSTOPBINDING, (WPARAM)punk);

    
return S_OK;
}

STDMETHODIMP_(ULONG) CDownload::XWindowForBindingUI::AddRef()
{   
    METHOD_PROLOGUE(CDownload, WindowForBindingUI)
        
return pThis->ExternalAddRef();
}   

STDMETHODIMP_(ULONG) CDownload::XWindowForBindingUI::Release()
{   
    METHOD_PROLOGUE(CDownload, WindowForBindingUI)
        
return pThis->ExternalRelease();
}   

STDMETHODIMP CDownload::XWindowForBindingUI::QueryInterface(REFIID iid, 
void** ppvObj)
{   
    METHOD_PROLOGUE(CDownload, WindowForBindingUI)
        
return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj) ;
}   

STDMETHODIMP CDownload::XWindowForBindingUI::GetWindow(REFGUID rguidReason, HWND
* phwnd)
{
    METHOD_PROLOGUE(CDownload, WindowForBindingUI)

    
//    如果希望在安装之前弹出安全提示,需要传入安装程序窗体的句柄

    
//    如果调用安装函数的时候,没有传入窗体句柄,并且 IE 对该下载ActiveX控件的地址没有设置为安全
    
//    则可能会出现安装失败,错误字符串: Generic trust failure.
    *phwnd = pThis->hwnd;
    
return S_OK;
}

原创粉丝点击