atl-ActiveX-dll-inf-cab-web调用(总结篇)

【dll - ActiveX调用dll - 生成dll - 2个dll外加1个inf生成cab - 嵌入web网页】


【写在前面的话】


  参与的项目让我第一次略深层次地接触C++。我的项目里需要用ActiveX调用密码小键盘的动态活动库dll,然后嵌入到网页。在网上搜了很多很多,几乎没有这方面的知识,那么一两个相关的介绍也不是很详细。


  所以我按照最实用的一篇文章,结合自己的思路整理下来。供后来者略作参考。


一、 综述


VC++、dll及ActiveX控件


dll(动态链接库): 分WIN32 dll和MFC dll


ActiveX:分ATL控件和MFC控件两类(也是一个dll)


WEB:JavaScript 调用-> ActiveX调用-> dll 完成加法运算并返回值,在页面上显示。


二、开发(Microsoft Visual Studio 2010)


1、dll库编写:--------------【此部分密码键盘自带动态库dll】【以下为举例,简单小dll】


文件 -> 新建 -> WIN32控制台 -> 填写项目名称 -> 选择dll -> 空项目 -> 完成。


(1)在解决方案面板中,加入一个头文件testdll.h,【解决方案资源管理器,右击“头文件”->添加->新建项->头文件】

#ifndef _DLLTUT_DLL_H_

#define _DLLTUT_DLL_H_

#if defined DLL_EXPORT

#define DECLDIR __declspec(dllexport)

#else

#define DECLDIR __declspec(dllimport)

#endif

extern "C"    //告诉编译器该部分可以在C/C++中使用。

{

DECLDIR int Add( int a, int b );

DECLDIR void Function( void );

}

#endif

(2)在解决方案面板中,加入一个实现文件testdll.cpp【解决方案资源管理器,右击“源文件”->添加->新建项->c++文件】

#include <iostream>

#define DLL_EXPORT

#include "testdll.h"

extern "C"

{

DECLDIR int Add( int a, int b )

{

return( a + b );

}

DECLDIR void Function( void )

{

std::cout << "DLL Called!" << std::endl;

}

}

以上为一个项目,保存


2、小测试程序【可选,小哆当时什么都不懂,所以觉得先写个小测试调用一下,以便熟悉熟悉。挺好。】


新建一个WIN32控制台类,测试这个DLL【文件 -> 新建 -> WIN32控制台 -> 填写项目名称 -> 选择控制台程序 -> 空项目 -> 完成】


在解决方案面板中,加入一个实现文件loaddll.cpp 内容:

#include <iostream>

 #include <windows.h>

 using namespace std;

 typedef int (*AddFunc)(int,int); //定义指针函数、接口。

 typedef void (*FunctionFunc)();

 int main()

 {

 AddFunc _AddFunc;

 FunctionFunc _FunctionFunc;

 cout <<"---获取DLL---."<< endl;

 // L 表示使用UNICODE 字符集,要和项目的字符集保持一致。

 HINSTANCE hInstLibrary = LoadLibrary(L"D:\\My Documents\\Visual Studio 2010\\Projects\\test_test\\Debug\\dll_test.dll");

 //这里调用时的路径,跟网上找到的不一样,虽然我觉得相对路径好些。但是奈何有点糊涂。

//相对路径首先一点我明白,文件不能乱放么,最好同一路径下。各位客官有明白的,还望指点一二【小哆拜谢】

 if (hInstLibrary == NULL)

 {

 cout <<"Dll 加载【失败】."<< endl;

 FreeLibrary(hInstLibrary);

 }else{

 cout <<"Dll 加载【成功】."<< endl;

 }

 _AddFunc = (AddFunc)GetProcAddress(hInstLibrary, "Add");

 _FunctionFunc = (FunctionFunc)GetProcAddress(hInstLibrary, "Function");

 if ((_AddFunc == NULL) || (_FunctionFunc == NULL))

 {

 FreeLibrary(hInstLibrary);//释放

 }else{

 cout <<"--- 获取DLL函数【OK】---."<< endl;

 }

 cout << _AddFunc(1, 1) << endl; // 开始调用

 _FunctionFunc(); //

 cin.get(); // 获得焦点,这样就不会程序就不会一闪而过了。

 FreeLibrary(hInstLibrary);//调用完后,要释放内存。

 return(1);

 }

完成,运行一下生成。会在文件夹的debug路径下产生一个exe文件,运行。哦耶~~


 2、ActiveX 控件(ATL)实现:


这里选择ATL控件实现。


文件 -> 新建 -> ATL项目 -> 填写项目名称(“Test_ActiveX”) -> 选择动态链接库(DLL) -> 完成。完成后,会在右边“解决方案资源管理器”生成很多头H文件和CPP实现文件,这些都是默认的不要修改。


 (1)添加一个ALT简单对象:【鼠标右键点击项目名称(刚才起的名字)选择 -> 添加类 -> 选择ATL简单对象】


下一步起一个名字:“test_op” -> 下一步:其他不变,在支持中,选择“连接点”和“IE对象支持” -> 完成。


下一步给“test_op”添加一个方法,以便WEB页面调用。在“类视图”选择“itest_op”(有个灰色的钥匙图标)鼠标右键添加 -> 添加方法。方法起名为“GetContent” -> 参数属性选择IN,参数类型选择LONG 参数名 a -> 添加;继续;参数属性选择IN,参数类型选择LONG 参数名 B -> 添加;继续;参数属性选择OUT和RETVAL ,参数类型选择LONG* 参数名 out -> 添加 -> 点击完成。


属性in指输入参数,属性out指输出参数。


这样就在test_op.H头文件中添加了一个(在最后一行):


STDMETHOD(GetContent)(LONG a, LONG b, LONG* out);


并在test_op.CPP文件中添加了一个实现类:


STDMETHODIMP CCaluNumCtrl::GetContent(LONG a, LONG b, LONG* out)

{

// TODO: 在此添加实现代码

return S_OK;

}


(2)在test_op.H 文件中,调用DLL类库。代码如下:

// test_op.h : Ctest_op 的声明

#pragma once

#include "resource.h"       // 主符号

#include <windows.h> //添加 by 莫小哆_ly

#include "testweb_i.h"

#include "_Itest_opEvents_CP.h"

#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA)

#error "Windows CE 平台(如不提供完全 DCOM 支持的 Windows Mobile 平台)上无法正确支持单线程 COM 对象。定义 _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA 可强制 ATL 支持创建单线程 COM 对象实现并允许使用其单线程 COM 对象实现。rgs 文件中的线程模型已被设置为“Free”,原因是该模型是非 DCOM Windows CE 平台支持的唯一线程模型。"

#endif

using namespace ATL;

// Ctest_op

class ATL_NO_VTABLE Ctest_op :

    //增加下一行 by 莫小哆_ly:安全提示解除,--当运行浏览器调用时,不会提示安全问题。

    public IObjectSafetyImpl<Ctest_op, INTERFACESAFE_FOR_UNTRUSTED_CALLER| INTERFACESAFE_FOR_UNTRUSTED_DATA>,

    public CComObjectRootEx<CComSingleThreadModel>,

    public CComCoClass<Ctest_op, &CLSID_test_op>,

    public IConnectionPointContainerImpl<Ctest_op>,

    public CProxy_Itest_opEvents<Ctest_op>,

    public IObjectWithSiteImpl<Ctest_op>,

    public IDispatchImpl<Itest_op, &IID_Itest_op, &LIBID_testwebLib, /*wMajor =*/ 1, /*wMinor =*/ 0>

{

public:

        //以下三行实现定义 modified by 莫小哆_ly。

    typedef int (*AddFunc)(int,int); //类型定义,对应DLL ADD方法。Func自定义,随便写。

    HINSTANCE hInstLibrary;

    AddFunc _AddFunc; //类映射

    Ctest_op()

    {

        //开始调用DLL,进行计算。

        hInstLibrary = LoadLibrary(L"dll_test.dll");//把写好的dll_test.dll文件放在此项目生成的目录debug下。

                //小哆觉得这应该就是相对路径的成功应用了。以后打包时,因为一直在同一路径下,所以,只要同时移动就不会出问题。

        if (hInstLibrary == NULL)

        {

        FreeLibrary(hInstLibrary);//资源释放

        }else{

        }

        //调用方法,返回方法句柄。

        _AddFunc = (AddFunc)GetProcAddress(hInstLibrary, "Add");

    }

DECLARE_REGISTRY_RESOURCEID(IDR_TEST_OP)

BEGIN_COM_MAP(Ctest_op)

    COM_INTERFACE_ENTRY(Itest_op)

    COM_INTERFACE_ENTRY(IDispatch)

    COM_INTERFACE_ENTRY(IConnectionPointContainer)

    COM_INTERFACE_ENTRY(IObjectWithSite)

 

    //增加下一行 by 莫小哆_ly:安全提示解除,--当运行浏览器调用时,不会提示安全问题。

    COM_INTERFACE_ENTRY(IObjectSafety)

 END_COM_MAP()

BEGIN_CONNECTION_POINT_MAP(Ctest_op)

    CONNECTION_POINT_ENTRY(__uuidof(_Itest_opEvents))

END_CONNECTION_POINT_MAP()

// ISupportsErrorInfo

    STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid);

    DECLARE_PROTECT_FINAL_CONSTRUCT()

    HRESULT FinalConstruct()

    {

        return S_OK;

    }

    void FinalRelease()

    {

    }

 public:

    STDMETHOD(Add)(LONG a, LONG b, LONG* sum);

};

OBJECT_ENTRY_AUTO(__uuidof(test_op), Ctest_op)

(3)回到在test_op.PP 文件中,添加实现代码如下:

STDMETHODIMP CCaluNumCtrl::GetContent(LONG a, LONG b, LONG* out)

{

// TODO: 在此添加实现代码

int sum = this->_AddFunc(static_cast<int>(a),static_cast<int>(b));

*out = static_cast<LONG>(sum);

this->_AtlFinalRelease();

return S_OK;

}

(4)生成DLL:


选“生成”,在项目的Debug文件夹里找到dll文件


3、dll和 ATL ActiveX 控件dll 打包为CAB文件:


(1)首先定义setup.inf文件:它描述了下载的内容和目标目录还有版本号及相应的DLL文件。这个要手动编写的(对应名称自行修改):

[version]

signature="$CHICAGO{1}quot;

AdvancedINF=2.0

[Add.Code]

testweb.dll=testweb.dll

dll_test.dll=dll_test.dll

[install.files]

testweb.dll=testweb.dll

dll_test.dll=dll_test.dll

[testweb.dll]

file-win32-x86=thiscab

RegisterServer=yes

clsid={125FFB0B-F4B9-4BFC-944D-7DF811E00852}

DestDir=11

FileVersion=1,0,0,1

[dll_test.dll]

file-win32-x86=thiscab

DestDir=11

FileVersion=1,0,0,1

[RegisterFiles]

%11%/testweb.dll

【怎么写inf】


[Version]区:不用修改

[version]

signature="$CHICAGO$"

AdvancedINF=2.0


接下来就[Add.Code]区:

[Add.Code]

testweb.dll=testweb.dll

dll_test.dll=dll_test.dll


前面是要下载的文件名,后面是对应这个文件的区域名,可以是任何名字,建议前后名字相同,方便维护。


还有需要注意是在[Add.Code]区出现的文件要根据依赖性进行排序,例如testweb.dll要依赖于dll_test.dll,则dll_test.dll在dll_test.dll的下面。因为安装时是按照相反的顺序进行的,先安装dll_test.dll,然后才是testweb.dll。


再接下来是各个文件的区域了


[testweb.dll]

file-win32-x86=thiscab

RegisterServer=yes

clsid={125FFB0B-F4B9-4BFC-944D-7DF811E00852}

DestDir=11

FileVersion=1,0,0,1


[testweb.dll]区域中的第一个file值告诉IE到哪里得到这个dll。file包括三部分,file永远都是这样的(至少目前来说);第二部分声明支持的OS,win32表示windows,mac就是苹果MAC OX了;第三部分CPU类型,比如说x86、 ppc (Power PC)、 mips或者alpha了。


file的值可以取三种值:URL、ignore和thiscab,URL说明到URL所在的位置去下;ignore说明对于这种OS和CPU,不需要下载这个文件(ctrl1.dll);thiscab很明显就在当前的cab文件中了。


接下来是RegisterServer,可以取两个值yes和no,yes说明IE要注册该dll,no就不必了;


如何寻找clsid值:项目里的idl文件中,有一段这么记录:

library testwebLib

{

importlib("stdole2.tlb");

[

uuid(125FFB0B-F4B9-4BFC-944D-7DF811E00852)

]

那就选这个uuid吧,别问我为什么,我也不知道。反正很多个,试了好久,用这个最后可以运行出来。


再下来是DestDir,它的值是dll将要存到本地硬盘的位置。10,则将dll放到\Windows或者\WinNT下;11,则放到\Windows\System或者\WinNT\System32下;空(就是没有值)则会放到\Windows或者\WinNT下的Downloaded Program Files目录下;


最后是FileVersion,这个就比较明显了,说明了testweb.dll的版本号。


 (2)整合资源:


将所用到的DLL全部放到一个目录下包括setup.inf文件,然后在开始运行:IExpress 命令去生成CAB包。


运行后,选择“Create new Self...”,下一步,选择第三个“Create compressed...(ActiveX Installs)”,下一步,添加文件(选择用到的2个dll和INF文件),下一步,选择一个输出目录并创建一个CAB文件名,再选择第二个选项“store files using...”,下一步,选择第二个选项“Don't save”,然后一直下一步。这样就生成了一个CAB文件。


 (3)WEB页面调用 ActiveX 控件 进行加法运算 :


写一个test.htm网页和CAB文件放在一个目录,test.htm内容如下:

 <HTML>

     <HEAD>

         <TITLE>New Page</TITLE>

         <OBJECT id=CaluNumCtrl codeBase="testcab.CAB#version=1,0,0,1" classid="clsid:8C0F4EAC-2BE4-4526-8A2B-FFF97374DC6A"></OBJECT>

         <script language="javascript">

             function doTest()

             {

                alert("test");                

                var sum = CaluNumCtrl.Add(1,1);

                                alert(sum);

             }

         </script>

     </HEAD>

     <BODY>

                <input type="button" value="调用" id="btnOK" onclick="doTest();"></input>

            </BODY>

 </HTML>

说明: codeBase="test.CAB#version=9,0,0,1" codeBase表示文件相对或者绝对路径;version表示版本号,如果这个号和INF文件的版本号一样,那么第二次访问页面就不会下载,否则每次都下载。CLSID 是 ActiveX 项目生成的序号,具体可以在项目的*.rgs 文件中找到。


 将2个dll文件、1个cabw文件、外加html文件,一起放到C:\WINDOWS\system32路径下。小哆也不明白该放哪些,不该放哪些。总之一开始放在别的地方,运行总是不成功,网页会自动关掉。后来就这样做了,也成功了。


 运行test.htm,【工具 - Internet选项 - 安全 - 自定义级别 - ActiveX控件和插件下面的选项凡是禁用的都改成启用或者提示,尤其是“下载未签名的ActiveX控件”】 提示ActiveX控件,选择允许,然后就可以调用出加法运算了。


 【简单的例子,其中的DLL中,可以实现自己的应用】


 ====================================================

 【写在最后】


首写于百度空间

http://hi.baidu.com/%C4%AA%D0%A1%B6%DF_ly/blog/item/2d23cd9512277f126e068c31.html


参考资料:

http://www.cnblogs.com/zhangqi/archive/2009/09/08/1562284.html


DLL+ ActiveX控件+WEB页面调用例子


很多一模一样的稿子,这个大概是时间最早的,所以就把它贴出来了。


打包工具:

iexpress.exe (试了一下,貌似必须配另一个文件makecab.exe才可以使用)

windows本身自带的,可以搜一下。搜出来以后随便复制到哪个位置。


====================================================

 【新问题】


小哆在试着调用密码小键盘自带的dll时遇到难题。


厂家设定dll里有个函数,我在另一个PB的系统中找到是这么运用的:


Function int GetPwd(int iFlag ,ref string psPwd, ref string clientmac) library "MISPOSADD.dll"


那我如果想在ActiveX里运用,首先怎么定义这个函数呢?string类型又改成什么呢?我注意到没有string呢。


到目前为止,这一块还是比较混乱呢。


所以求高手指教,【小哆拜谢】~


你可能感兴趣的:(JavaScript,windows,function,String,dll,interface)