vc开发ActiveX总结

vc开发ActiveX可选两种框架,一种是ATL COM结构,还有一种是MFC结构。

一.打开vc6.0,新建一个MFC ActiveXControlWizard项目:  

vc6开发activex并发布全攻略(初级篇)(原创) - 一闪而过 - 一闪而过的博客

 工程名称随便起,比如我的叫MyActiveX。点击确定,一路默认下一步,完成后生成的文件目录如下:

vc6开发activex并发布全攻略(初级篇)(原创) - 一闪而过 - 一闪而过的博客

 生成的文件包括源文件夹,头文件夹和资源文件夹。还是那句话,想知道这些文件具体都是做什么的,去问下百度,我这里只讲步骤。

二.其实这个工程本身生成的就是一个ActiveX控件,它的功能是在页面上画个圆。那我们现在先查看下效果。直接点击F7,控制台显示编译成功,并生成MyActiveX.ocx文件。 

vc6开发activex并发布全攻略(初级篇)(原创) - 一闪而过 - 一闪而过的博客

我的这个工程目录是在E:/MyPro下,那生成的MyActiveX.ocx就在E:/MyPro/MyActiveX/Debug下:

vc6开发activex并发布全攻略(初级篇)(原创) - 一闪而过 - 一闪而过的博客

 恩,就是那个万花丛中一行红的那个。

那我们看看运行效果。

vc6开发activex并发布全攻略(初级篇)(原创) - 一闪而过 - 一闪而过的博客

点开vc的工具->ActiveX Control Test Container菜单,你的VC看不到这个选项,那你可能是安装了精简版:

 弹出下面这个对话框:

vc6开发activex并发布全攻略(初级篇)(原创) - 一闪而过 - 一闪而过的博客

 然后选择edit->Insert New Control选项弹出下面这个窗口:

vc6开发activex并发布全攻略(初级篇)(原创) - 一闪而过 - 一闪而过的博客 

 然后选择edit->Insert New Control选项弹出下面这个窗口:

vc6开发activex并发布全攻略(初级篇)(原创) - 一闪而过 - 一闪而过的博客

 在列表中我们可以看到MyActiveX这个我们刚刚生成的控件。选择OK,看看效果,一个圆:

vc6开发activex并发布全攻略(初级篇)(原创) - 一闪而过 - 一闪而过的博客

 这个工具很好用,我们在activeX中的自定义方法在这个测试容器里测试:

选择Control->InvokeMethods选项:

vc6开发activex并发布全攻略(初级篇)(原创) - 一闪而过 - 一闪而过的博客

 弹出下面的对话框:

vc6开发activex并发布全攻略(初级篇)(原创) - 一闪而过 - 一闪而过的博客

选择方法名,通过parmeter列表还可以设置方法的参数,设置好以后,点击Invoke就可以看到我们自定义方法的效果。如果只返回参数,那返回的结果就显示在Return文本框里。如果是弹出对话框,

vc6开发activex并发布全攻略(初级篇)(原创) - 一闪而过 - 一闪而过的博客

那将弹出你设计的对话框。现在方法中只有一个系统默认的弹出软件相关的一个对话框。看看:

 三.下面我们就在activex中添加自定义方法。

     这个自定义方法很简单,就是增加一个test(short  a,short b)方法,返回a+b的值。也许某些高手看到这里会笑,这么简单的方法还好意思写啊。呵呵。没关系,毕竟这篇文章只是菜鸟之作,给入门者看的。

  选择左边工程目录的ClassView选择项(下图中红色方框里的),也就是显示类图:.下面我们就在activex中添加自定义方法。

     这个自定义方法很简单,就是增加一个test(short  a,short b)方法,返回a+b的值。也许某些高手看到这里会笑,这么简单的方法还好意思写啊。呵呵。没关系,毕竟这篇文章只是菜鸟之作,给入门者看的。

  选择左边工程目录的ClassView选择项(下图中红色方框里的),也就是显示类图:

vc6开发activex并发布全攻略(一)(初级篇)(原创) - 一闪而过 - 一闪而过的博客

 然后选择菜单查看->建立类向导,弹出对话框:

vc6开发activex并发布全攻略(一)(初级篇)(原创) - 一闪而过 - 一闪而过的博客

vc6开发activex并发布全攻略(一)(初级篇)(原创) - 一闪而过 - 一闪而过的博客

 选择上图中automation(自定义)标签页,ClassName选择CMyActivexCtr类,因为我们自定义的方法一般都是在Ctrl这个类文件中实现的。选择Add Method按钮,弹出对话框:

vc6开发activex并发布全攻略(一)(初级篇)(原创) - 一闪而过 - 一闪而过的博客

 在External name填入我们的方法名。比如我的这个方法叫做test,有两个参数a和b,如下图:

vc6开发activex并发布全攻略(一)(初级篇)(原创) - 一闪而过 - 一闪而过的博客

 点击确定:

vc6开发activex并发布全攻略(一)(初级篇)(原创) - 一闪而过 - 一闪而过的博客

继续确定,看看工程类列表有什么变化:

vc6开发activex并发布全攻略(一)(初级篇)(原创) - 一闪而过 - 一闪而过的博客

 恩,多了两项:一个test的接口和一个test的实现类。

双击test实现类,也就是上面图中的第二个红框类,找到

short CMyActiveXCtrl::test(short a, short b)
{
       // TODO: Add your dispatch handler code here
       return 0;
}

 

 方法,将它改为

short CMyActiveXCtrl::test(short a, short b)
{
       // TODO: Add your dispatch handler code here
       return a+b;
}

 

呵呵,只是将return 0该成了return a+b;

直接F7,

vc6开发activex并发布全攻略(一)(初级篇)(原创) - 一闪而过 - 一闪而过的博客

 显示编译成功。

那现在再打开vc的工具->ActiveX Control Test Container菜单(参照前面的图)。选择MyActivex控件,然后再选择Control->InvokeMethods选项:

看看,在MethodName中多了一个test方法,而且有两个参数a,b

vc6开发activex并发布全攻略(一)(初级篇)(原创) - 一闪而过 - 一闪而过的博客

通过SetValue给a与b赋值。点击invoke在Return中就会显示结果,2+4=6:

vc6开发activex并发布全攻略(一)(初级篇)(原创) - 一闪而过 - 一闪而过的博客

那我们这个Activex就算做好了,在E:/MyPro/MyActiveX/Debug目录下的MyActiveX.ocx就是我们的成品。下面就进行发布工作。

双击DMyActiveX接口类,

找到

 

复制代码
[ uuid(743F39F2-E3A5-4550-A203-4A1CFAE9ABCF),
         helpstring("MyActiveX Control"), control ]
coclass MyActiveX
{
      [default] dispinterface _DMyActiveX;
      [default, source] dispinterface _DMyActiveXEvents;
};
复制代码

 

 

 

方法中743F39F2-E3A5-4550-A203-4A1CFAE9ABCF就是我们ActiveX的GUID.

 vc6开发activex并发布全攻略(二)(初级篇) - 一闪而过 - 一闪而过的博客

 还有一种方法就是打开VC的工具OLEView,懒的敲字了,看图吧:

vc6开发activex并发布全攻略(二)(初级篇) - 一闪而过 - 一闪而过的博客

vc6开发activex并发布全攻略(二)(初级篇) - 一闪而过 - 一闪而过的博客

vc6开发activex并发布全攻略(二)(初级篇) - 一闪而过 - 一闪而过的博客

我的MyActiveX.inf如下:

复制代码
   [version]  
    signature="$CHINA$" 
    AdvancedINF=1.0 
    [Add.Code]  
    MyActiveX.ocx=MyActiveX.ocx  
    msvcr71.dll=msvcr71.dll  
    mfc71.dll=mfc71.dll  
    msvcp71.dll=msvcp71.dll
   [MyActiveX.ocx]  
   file=thiscab  
   clsid={743F39F2-E3A5-4550-A203-4A1CFAE9ABCF}  
   FileVersion=1,0,0,0 
   RegisterServer=yes  
   [msvcr71.dll]  
   file-win32-x86=thiscab  
   RegisterServer=no  
   DestDir=11 
   FileVersion=7,10,3052,4 
   [mfc71.dll]  
   file-win32-x86=thiscab  
   RegisterServer=no  
   DestDir=11 
   FileVersion=7,10,3077,0 
   [msvcp71.dll]  
   file-win32-x86=thiscab  
   RegisterServer=no  
   DestDir=11 
   FileVersion=7,10,3077,0 
 
复制代码

 

按照上面的方法,用cabarc -s 6144 n MyActiveX.cab msvcr71.dll mfc71.dll msvcp71.dll MyActiveX.ocx MyActiveX.inf命令制作好MyActiveX..cab。

文件目录:

vc6开发activex并发布全攻略(二)(初级篇) - 一闪而过 - 一闪而过的博客

我们来写个测试页面,代码如下: 

复制代码
<object id='test1' codeBase='http://10.79.108.108/MyActiveX.cab#version=1,0,0,0' classid='clsid: 743F39F2-E3A5-4550-A203-4A1CFAE9ABCF ' height=0 width=0 ></object>

<script>

       a=test1.test(2,1);

       alert(a);

</script>
复制代码

 注意:链接IP改成你机子的IP

将它保存为test.html格式存放到IIS下,同时把MyActiveX也拷贝到IIS下,也就是C:/Inetpub/wwwroot下。

打开页面测试下:

http://10.79.108.108/test.html

弹出对话框:

vc6开发activex并发布全攻略(二)(初级篇) - 一闪而过 - 一闪而过的博客

选择是:

vc6开发activex并发布全攻略(二)(初级篇) - 一闪而过 - 一闪而过的博客

 

呵呵,弹出计算值3。算是成功了一半。那为什么系统没有提示下载控件呢?这是因为VS在编译的时候已经帮我们把控件注册到系统中了。

那现在首要的问题,就是先解决上面那个是否允许activex运行的提示框。

在网上查了下资料,说是要实现ISafeObject接口。那好,我们下面就来实现:打开工程,找到CMyActiveXCtr类,双击打开文件:

vc6开发activex并发布全攻略(二)(初级篇) - 一闪而过 - 一闪而过的博客

在文件中添加引用:

复制代码
#include "comcat.h"

#include "Objsafe.h"

两个头文件。

并在DECLARE_DYNCREATE(CMyActiveXCtro)后添加如下代码:

DECLARE_INTERFACE_MAP()

       BEGIN_INTERFACE_PART(ObjSafe, IObjectSafety)

       STDMETHOD_(HRESULT, GetInterfaceSafetyOptions) (

               /* [in] */ REFIID riid,

               /* [out] */ DWORD __RPC_FAR *pdwSupportedOptions,

               /* [out] */ DWORD __RPC_FAR *pdwEnabledOptions

       );

        

       STDMETHOD_(HRESULT, SetInterfaceSafetyOptions) (

               /* [in] */ REFIID riid,

               /* [in] */ DWORD dwOptionSetMask,

               /* [in] */ DWORD dwEnabledOptions

       );

       END_INTERFACE_PART(ObjSafe);
复制代码

效果如图:

vc6开发activex并发布全攻略(二)(初级篇) - 一闪而过 - 一闪而过的博客

在工程目录中切换到FileView模式,打开MyActiveXCtrl.cpp文件,

然后将以下代码添加到构造函数CMyActiveXCtrl:: CMyActiveXCtrl ()上面,CMyActiveXCtrl替换为你的控件名称: 

复制代码
/////////////////////////////////////////////////////////////////////////////
// Interface map for IObjectSafety
BEGIN_INTERFACE_MAP( CMyActiveXCtrl, COleControl )
INTERFACE_PART(CMyActiveXCtrl, IID_IObjectSafety, ObjSafe)
END_INTERFACE_MAP()
/////////////////////////////////////////////////////////////////////////////
// IObjectSafety member functions
// Delegate AddRef, Release, QueryInterface
ULONG FAR EXPORT CMyActiveXCtrl::XObjSafe::AddRef()
{
METHOD_PROLOGUE(CMyActiveXCtrl, ObjSafe)
return pThis->ExternalAddRef();
}
ULONG FAR EXPORT CMyActiveXCtrl::XObjSafe::Release()
{
METHOD_PROLOGUE(CMyActiveXCtrl, ObjSafe)
return pThis->ExternalRelease();
}
HRESULT FAR EXPORT CMyActiveXCtrl::XObjSafe::QueryInterface(
REFIID iid, void FAR* FAR* ppvObj)
{
METHOD_PROLOGUE(CMyActiveXCtrl, ObjSafe)
return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj);
}
const DWORD dwSupportedBits =
INTERFACESAFE_FOR_UNTRUSTED_CALLER |
INTERFACESAFE_FOR_UNTRUSTED_DATA;
const DWORD dwNotSupportedBits = ~ dwSupportedBits;
/////////////////////////////////////////////////////////////////////////////
// CStopLiteCtrl::XObjSafe::GetInterfaceSafetyOptions
// Allows container to query what interfaces are safe for what. We're
// optimizing significantly by ignoring which interface the caller is
// asking for.
HRESULT STDMETHODCALLTYPE
CMyActiveXCtrl::XObjSafe::GetInterfaceSafetyOptions(
/* [in] */ REFIID riid,
/* [out] */ DWORD __RPC_FAR *pdwSupportedOptions,
/* [out] */ DWORD __RPC_FAR *pdwEnabledOptions)
{
METHOD_PROLOGUE(CMyActiveXCtrl, ObjSafe)
HRESULT retval = ResultFromScode(S_OK);
// does interface exist?
IUnknown FAR* punkInterface;
retval = pThis->ExternalQueryInterface(&riid,
(void * *)&punkInterface);
if (retval != E_NOINTERFACE) { // interface exists
punkInterface->Release(); // release it--just checking!
}
// we support both kinds of safety and have always both set,
// regardless of interface
*pdwSupportedOptions = *pdwEnabledOptions = dwSupportedBits;

return retval; // E_NOINTERFACE if QI failed
}

/////////////////////////////////////////////////////////////////////////////
// CStopLiteCtrl::XObjSafe::SetInterfaceSafetyOptions
// Since we're always safe, this is a no-brainer--but we do check to make
// sure the interface requested exists and that the options we're asked to
// set exist and are set on (we don't support unsafe mode).
HRESULT STDMETHODCALLTYPE
CMyActiveXCtrl::XObjSafe::SetInterfaceSafetyOptions(
/* [in] */ REFIID riid,
/* [in] */ DWORD dwOptionSetMask,
/* [in] */ DWORD dwEnabledOptions)
{
METHOD_PROLOGUE(CMyActiveXCtrl, ObjSafe)

// does interface exist?
IUnknown FAR* punkInterface;
pThis->ExternalQueryInterface(&riid, (void * *)&punkInterface);
if (punkInterface) { // interface exists
punkInterface->Release(); // release it--just checking!
}
else { // interface doesn't exist
return ResultFromScode(E_NOINTERFACE);
}

// can't set bits we don't support
if (dwOptionSetMask & dwNotSupportedBits) {
return ResultFromScode(E_FAIL);
}

// can't set bits we do support to zero
dwEnabledOptions &= dwSupportedBits;
// (we already know there are no extra bits in mask )
if ((dwOptionSetMask & dwEnabledOptions) !=
dwOptionSetMask) {
return ResultFromScode(E_FAIL);
} 

// don't need to change anything since we're always safe
return ResultFromScode(S_OK);
}
复制代码

 

效果如下图,注意画红框的地方:

vc6开发activex并发布全攻略(二)(初级篇) - 一闪而过 - 一闪而过的博客

 

F7编译以后,按前面的步骤重新发布。

打开测试页面http://10.79.108.108/test.html,呵呵那个讨厌的对话框消失了。

现在这个ActiveX是完全做好了,下一步我们来看看怎样让用户下载安装。

先在本地电脑测试:

因为我们用VC编译时,VC已经帮我们把ActiveX注册到系统中了,所以我们想看到下载安装画面,先必须删除注册信息。

打开运行窗口,输出regedit命令,查找我们的控件GUI: 743F39F2-E3A5-4550-A203-4A1CFAE9ABCF

vc6开发activex并发布全攻略(二)(初级篇) - 一闪而过 - 一闪而过的博客

 

我这里找到三项,那全部删除。

在打开测试页面之前,我们还得做个工作,就是设置IE安全。打开IE工具->Internet选项,如果是局域网,设置本地Intrance,允许下载未签名和已签名的ActiveX。如果是外网,方法一样。

vc6开发activex并发布全攻略(二)(初级篇) - 一闪而过 - 一闪而过的博客

 

现在打开测试页http://10.79.108.108/test.html

vc6开发activex并发布全攻略(二)(初级篇) - 一闪而过 - 一闪而过的博客

 

成功弹出下载ActiveX对话框。

点击安装,程序正常运行。OK,我们已经成功了一半。

上面只是在本地测试成功。现在在其他计算机上访问测试页,不要忘了IE的安全设置。打开页面后也是弹出上面的安装界面。可是,点安装后,程序无法正常运行。而且每次刷新页面,安装对话框总是弹出,很是郁闷。

经过Baidu,又找到了方法。原来是其他计算机上没有安装我们activeX运行所需的库文件。那我们就想办法让用户把这用到的DLL全部下载。

那首先得知道我们的activeX用到了哪些库。如下图,打开VC的工具Depends

vc6开发activex并发布全攻略(二)(初级篇) - 一闪而过 - 一闪而过的博客

 选择我们的MyActiveX.ocx控件,如下图:

vc6开发activex并发布全攻略(二)(初级篇) - 一闪而过 - 一闪而过的博客

 那我们可以看到我们用到的DLL有6个,一般Kernel32.DLL和OLEAUT32.DLL文件每个操作系统都有,所以剩下的4个DLL,在你机子上全盘搜索,找到这4个dll后将他们放入你的MyActiveX.ocx相同文件夹下,编辑MyActiveX.inf, 这些dll的版本信息FileVersion可以在此dll上点击右键->属性中得到:

    [version]  

    signature="$CHINA$" 

    AdvancedINF=1.0 

     

    [Add.Code]  

    MyActiveX.ocx=MyActiveX.ocx  

    msvcr71.dll=msvcr71.dll  

    mfc71.dll=mfc71.dll  

    msvcp71.dll=msvcp71.dll

    MFC42D.dll=MFC42D.dll  

    MSVCRTD.DLL=MSVCRTD.DLL

    gdi32.dll=gdi32.dll

    MFCO42D.DLL=MFCO42D.DLL

 

   [MyActiveX.ocx]  

   file=thiscab  

   clsid={743F39F2-E3A5-4550-A203-4A1CFAE9ABCF}  

   FileVersion=1,0,0,0 

   RegisterServer=yes  

    

   [msvcr71.dll]  

   file-win32-x86=thiscab  

   RegisterServer=no  

   DestDir=11 

   FileVersion=7,10,3052,4 

    

   [mfc71.dll]  

   file-win32-x86=thiscab  

   RegisterServer=no  

   DestDir=11 

   FileVersion=7,10,3077,0 

    

   [msvcp71.dll]  

   file-win32-x86=thiscab  

   RegisterServer=no  

   DestDir=11 

   FileVersion=7,10,3077,0 

 

   [MFC42D.dll]  

   file-win32-x86=thiscab  

   RegisterServer=no  

   DestDir=11 

   FileVersion=6.0.9782.0

 

   [MSVCRTD.DLL]  

   file-win32-x86=thiscab  

   RegisterServer=no  

   DestDir=11 

   FileVersion=6.0.9782.0

 

   [gdi32.dll]  

   file-win32-x86=thiscab  

   RegisterServer=no  

   DestDir=11 

   FileVersion=5.2.3790.2542 

 

   [MFCO42D.DLL]  

   file-win32-x86=thiscab  

   RegisterServer=no  

   DestDir=11 

   FileVersion=6.0.9782.0

保存后文件目录如下:

vc6开发activex并发布全攻略(二)(初级篇) - 一闪而过 - 一闪而过的博客

 

用 cabarc -s 6144 n MyActiveX.cab msvcr71.dll mfc71.dll msvcp71.dll MFC42D.dll MSVCRTD.DLL gdi32.dll MFCO42D.DLL MyActiveX.ocx MyActiveX.inf

命令生成MyActiveX.cab文件。

在其他计算机上打开测试页。安装ActiveX成功,并且运行正常。

就此,一个简单的ActiveX发布成功了。

 


前面两片文章我们制作了个一简单的 ActiveX,而这个ActiveX只实现了一个简单的计算功能。其实ActiveX控件的功能很好很强大,只要你能想到的,它基本都能够实现。可我现在的水平那也只能想到而做不到 >_< 。所以,还是在网上多找些例子,边做边学。

下面是我转载的一个例子,实现的功能是将网页保存到本地。照旧,我会在后面列出我制作时出现的问题及解决方案。

原文地址:http://www.7880.com/info/2005/06/08/article-14697.html

ActiveX控件的开发

    这段时间因为工作的需要,开发了一个ActiveX控件,采用的开发工具是VC,希望可以给大家做类似的开发时提供参考。

一,ActiveX控件的功能:

1,主要是用来下载和保存指定的网页。

2,要能够嵌在网页中,供服务器页面的脚本调用。

3,提供下载保存到哪个文件夹的窗口,给用户自己选择保存位置的机会。

4,提供程序接口,使得用户可以保存单个文件。

5,提供程序接口,使得用户可以保存多个文件,文件名以数组的方式传递过来。

 

二,ActiveX控件的开发过程:

1,通过VC的MFC ActiveX  ControlWizard 向导开发这个控件,将项目命名为ActiveX3

2,在向导的Step2 of 2中为Invisible at runtime打钩,并去掉Has an “About” Box前面的钩,该控件在调用时则不显示。

vc6开发activex并发布全攻略(三)(进阶篇) - 一闪而过 - 一闪而过的博客

3,打开ClassWizard,在Automation下添加方法:

(1) External Name: DownloadSingle

 Internal Name: DownloadSingle

 Return Type: BOOL

 Parameter List: strDownload  LPCTSTR

         

         该方法的作用:接受并处理参数为字符串类型的下载请求,同时为操作员提供指定下载目录的机会并接受其指定。  

 

(2)    External  Name: DownloadArray

Internal Name: DownloadArray

Return Type: BOOL

Parameter List: arrDownload  Variant

 

         该方法的作用:接受并处理参数字符串数组类型的下载请求,同时为操作员提供指定下载目录的机会并接受其指定。

 

4,通过手工添加方法:  

   void TryUrl(CString strAddress)

   被DownloadArray和DownloadSingle调用,用来实现具体下载功能。

 

三,关键代码

复制代码
 1,   BOOL CActiveX3Ctrl::DownloadSingle(LPCTSTR strDownload)

{

       // TODO: Add your dispatch handler code here

      char buf[MAX_PATH];

       _getcwd(buf,MAX_PATH);

   location=”d://”;

   TryUrl(strDownload);

       MessageBox("下载完成!");

       return TRUE;

}

 

2, BOOL CActiveX3Ctrl::DownloadArray(const VARIANT FAR& arrDownload)

{

       // TODO: Add your dispatch handler code here

       char buf[MAX_PATH];

       _getcwd(buf,MAX_PATH);

       location=”d://”;

       const VARIANT *varArray;

       if(arrDownload.vt==(VT_VARIANT|VT_BYREF))

       {

          varArray=arrDownload.pvarVal;

       }

       else

       {

          varArray=&arrDownload;

    }

   if((varArray->vt)==(VT_ARRAY | VT_BYREF | VT_VARIANT))

        {

              VARIANT* strarray;

              SAFEARRAY* psa = *(varArray->pparray);

              SafeArrayAccessData(psa,(void**)&strarray);

              UINT uDim = SafeArrayGetDim(psa);

              if(uDim==1)

              {

                     long lLbound,lRbound;

                     SafeArrayGetLBound(psa,1,&lLbound);

                     SafeArrayGetUBound(psa,1,&lRbound);

                     for(long i=lLbound;i<=lRbound;i++)

                     {

                            if(strarray[i].vt==VT_BSTR)

                            {    

                                 TryUrl(strarray[i].bstrVal);

                            }

                     }

              }

              SafeArrayUnaccessData(psa);

       }

    MessageBox("下载完成!");

       return TRUE;

}

3void CActiveX3Ctrl::TryUrl(CString strAddress)

{

       CFile newFile;

              Cstring fileName=strAddress.Mid(strAddress.ReverseFind('/')+1); 

              newFile.Open(location+"//"+fileName,CFile::modeCreate | CFile::modeWrite); 

              CInternetSession session;

       CInternetFile* file=NULL;

       try

         {

              file=(CInternetFile*)session.OpenURL(strAddress);      }

          catch(CInternetException* pEx)

         {

              file=NULL;

              pEx->Delete();

         }

         if(file)

         { 

              int number=0;

              BYTE *buf;

              buf=new BYTE[1024];

              do

              {

              number=file->Read(buf,1024);

           newFile.Write(buf,number);

              }

              while(number>0);

        delete []buf;

         }

         file->Close();

      newFile.Close();

       return;

}
复制代码

 

四,测试页面

复制代码
<html>

<head>

<title>Download three files from the web.</title>

<script language="javascript">

function download1()

{

var file;

file=document.form1.text1.value;

FavouriteDown.downloadSingle(file);

return;

}

</script>

<script language="VBScript">

<!--

Sub downN_OnClick

Dim s(2)

s(0)=document.form1.text1.value

s(1)=document.form1.text2.value

s(2)=document.form1.text3.value

ActiveXDown.DownloadArray(s)

End Sub

-->

</script>

</head>

<body>

<OBJECT ID="ActiveXDown"

CLASSID="CLSID:ADD73828-78F4-4EF1-8734-61590B044F87"

CODEBASE="ActiveX3.ocx#version=1,0,0,0">

</OBJECT>

<center>

<form name="form1">

<input type="text" name="text1" size="50"><p>

下载一个文件:<input type="button" name="down1" value="down1" onclick="javascript:download1();"><p>

<input type="text" name="text2" size="50"><p>

<input type="text" name="text3" size="50"><p>

下载三个文件:<input type="button" name="downN" value="downN"><p>

</form>

</body>

</html>
复制代码

 

 

 #######################以下是在开发ActiveX时出现的问题补充########################

 按照上面的方法,我们要添加三个方法,添加方法我就不具体讲了,前面一篇已经抓过图。需要注意的是博文中第四步说要手动添加void TryUrl(CString strAddress)方法,我到现在也还没理解,只有通过Automation添加了。在添加过程中,参数无法选择Cstring类型,如图:

 vc6开发activex并发布全攻略(三)(进阶篇) - 一闪而过 - 一闪而过的博客

 如有高手路过,请指点一二。

那我们只能先选择LPCTSTR代替。那我们就必须在程序里该下,将LPCTSTR转换为CString类型。

//下载网页

 

复制代码
void CMyActiveXCtrl::TryUrl(LPCTSTR str)
{       // TODO: Add your dispatch handler code here
      CString   strAddress(str);//在这里转换成CString类型 
         CFile newFile;
      CString fileName=strAddress.Mid(strAddress.ReverseFind('/')+1);
      newFile.Open(location+"//"+fileName,CFile::modeCreate | CFile::modeWrite);
      CInternetSession session;
      CInternetFile* file=NULL;
      try
      {
            file=(CInternetFile*)session.OpenURL(strAddress);     
         }
       catch(CInternetException* pEx)
       {
            file=NULL;
            pEx->Delete();
          }
       if(file)
          { 
              int number=0;
              BYTE *buf;
              buf=new BYTE[1024];
              do
              {
                  number=file->Read(buf,1024);
                  newFile.Write(buf,number);
              }
              while(number>0);
              delete []buf;
       }
       file->Close();
       newFile.Close();
       return;
} 
复制代码

 

 

 

 而且程序中的location也得通过Automation选项卡添加成全局变量(添加变量请参见前面的一篇文章),并且赋初值,如下图:

vc6开发activex并发布全攻略(三)(进阶篇) - 一闪而过 - 一闪而过的博客

 还有BOOL CActiveX3Ctrl::DownloadArray(const VARIANT FAR& arrDownload)编译时也出错,说是字符分割时出现错误:修改后的代码如下:

 

复制代码
BOOLCMyActiveXCtrl::DownloadArray(constVARIANTFAR&arrDownload)
{// TODO: Add your dispatch handler code here
       charbuf[MAX_PATH];
        _getcwd(buf,MAX_PATH);
        constVARIANT*varArray;
        if(arrDownload.vt==(VT_VARIANT|VT_BYREF))
       {
          varArray=arrDownload.pvarVal;
       }
        else
        {
           varArray=&arrDownload;
     }
    if((varArray->vt)==(VT_ARRAY|VT_BYREF|VT_VARIANT))
   {
         VARIANT*strarray;
         SAFEARRAY*psa=*(varArray->pparray);
         SafeArrayAccessData(psa,(void**)&strarray);
         UINTuDim=SafeArrayGetDim(psa);
         if(uDim==1)
               {
              longlLbound,lRbound;
              SafeArrayGetLBound(psa,1,&lLbound);
              SafeArrayGetUBound(psa,1,&lRbound);
              for(longi=lLbound;i<=lRbound;i++)
                       {
                   if(strarray[i].vt==VT_BSTR)
                               {
                                     //这里编译时出错,下面是改动后的代码
                                          intsize=WideCharToMultiByte(CP_ACP,0,strarray[i].bstrVal,-1,NULL,0,NULL,0);
                                          char*AsciiBuff=newchar[size];
                                          WideCharToMultiByte(CP_ACP,0,strarray[i].bstrVal,-1,AsciiBuff,size,NULL,0);
                        TryUrl(AsciiBuff);
                    }
                       }
               }
         SafeArrayUnaccessData(psa);
     }
        MessageBox("下载完成!");
       returnTRUE;
}
复制代码

 

 

 

//同时保存多个网页哦,还要注意添加一个头文件引用:

#include <afxinet.h>

如下图:

vc6开发activex并发布全攻略(三)(进阶篇) - 一闪而过 - 一闪而过的博客

现在编译下,直接通过,呵呵。

 编译通过后,你可以通过ActiveXControlTestContainer对控件进行调试。调试前先设置下:打开

工程->设置,弹出对话框设置调试,选择可执行调试设置为ActiveXControlTestContainer,如下图:

vc6开发activex并发布全攻略(三)(进阶篇) - 一闪而过 - 一闪而过的博客

然后在程序里打上断点。按F5启动调试,在方法中选择DownloadSingle方法,设置参数,我这里输入http://localhost/test.html,点击invoke按钮,程序就会走到你设置的断点处:

vc6开发activex并发布全攻略(三)(进阶篇) - 一闪而过 - 一闪而过的博客

那我们点击invoke按钮,如果没有断点,程序直接执行,弹出下载完成对话框。因为程序中我设置的路径是D:/,所以应该在我的D盘下可以找到一个名为test.html的文件。如果你也找到了,说明你的控件也可以正常运行了。

下面就该发布这个ActiveX了。如果你是第一次让用户安装此控件,那你可以参照我的上一篇文章进行发布。如果前面用户已经安装了上一个版本,那我们这次就是让用户升级ActiveX了。

升级ActiveX,我们需要修改三个地方。

一, 我们首先要修改程序中的版本。打开工程的ResourceView资源浏览菜单,选择VS_VERSION_INFO节点,我们可以看到原来的FILEVERSION中的版本号是1.0.0.1, 我们把它改成1,0,0,2。如下图:

 

F7直接编译完成。

二,修改发布文件信息

MyActiveX.inf,将FileVersion该为1,0,0,2

 vc6开发activex并发布全攻略(三)(进阶篇) - 一闪而过 - 一闪而过的博客

 重新生成cab文件并签名。将生成的MyActiveX.cab拷贝到服务器IIS发布目录。

三, 修改test.html页面cab的版本信息,将version改为1,0,0,2 

vc6开发activex并发布全攻略(三)(进阶篇) - 一闪而过 - 一闪而过的博客

 注意:文中的版本信息1,0,0,2中间一定是逗号。

那现在我们就可以让用户打开这个包含控件的页面,IE会提示用户重新安装ActiveX控件。

如果用户安装成功,我们可以在C:/WINDOWS/Downloaded Program Files目录下看到这个Activex控件信息:

vc6开发activex并发布全攻略(三)(进阶篇) - 一闪而过 - 一闪而过的博客

 

 

 

还可以打开IE中的Internet选项,程序->管理加载项目中查看

vc6开发activex并发布全攻略(三)(进阶篇) - 一闪而过 - 一闪而过的博客

也可以点击删除按钮对我们的ActiveX进行删除。

下面我们开始对ActiveX进行测试:

Test.html页面我做了下改动,代码如下:

 

复制代码
<html>
<head>
<title>Download three files from the web.</title>
</head>
<body>
<object id='test1' codeBase='http://10.79.108.75/MyActiveX.cab#version=1,0,0,2' classid='clsid:743F39F2-E3A5-4550-A203-4A1CFAE9ABCF' height=0 width=0 ></object>
<center>
<form name="form1">
<input type="text" name="text1" size="50"><p>
下载一个文件:<input type="button" name="down1" value="down1" onclick="javascript:download1();"><p>
<input type="text" name="text2" size="50"><p>
<input type="text" name="text3" size="50"><p>
下载三个文件:<input type="button" name="downN" value="downN"><p>
</form>
</body>
</html>
<script language="javascript">
       a=test1.test(2,1);
       alert(a);
function download1()
{
       var file;
       file=document.form1.text1.value;
       test1.downloadSingle(file);
       return;
}
 
</script>
<script language="VBScript">
<!--
Sub downN_OnClick
Dim s(2)
s(0)=document.form1.text1.value
s(1)=document.form1.text2.value
s(2)=document.form1.text3.value
test1.DownloadArray(s)
End Sub
-->
</script>
复制代码

 

 

 

如图:

 

 vc6开发activex并发布全攻略(三)(进阶篇) - 一闪而过 - 一闪而过的博客

 

输入网址进行测试,下载成功。
如果你输入为空,或者网页打不开,IE就会崩溃而退出,这是因为我们在程序中都没有做验证。反正大概功能已经实现,验证你可以自己修改正下。
还有就是我把test.html中的的vbscript该为javascript后,点多个下载后程序执行失败,很是郁闷,javascript代码如下:
function download2()
{
alert(1);
var a1=new Array(3);
a1[0]=document.form1.text1.value;
a1[1]=document.form1.text2.value;
a1[2]=document.form1.text3.value;
test1.DownloadArray(a1);
}

posted @ 2013-01-14 22:28  宝马良驹  阅读(411)  评论(0)    收藏  举报