ATL 编写控件 调用密码键盘 全过程

来源:互联网 发布:淘宝运营方案 编辑:程序博客网 时间:2024/06/13 13:15
写在前面:小哆把详细过程贴出来,一方面是记录备份,可以随时再利用,另一方面是分享,希望后来的初学者可以轻松一些。

[这是一个整体,所以,今后就不在赘述其中的东西,除非是前期本人自己理解错误,会更正,同时特别备注]

没有加入加密功能,MD5/DES加密都已实现,但在资源和其他的文章中有描述,本文加入过于赘述。

没有数字签名和发布部分,还未完全明白。


使用软件:Visual Studio 2010


调用:LOADDLL.dll



"文件"
[选项]
(填写名称)

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


(1)创建项目

文件 -> 新建 -> ATL项目 -> 填写项目名称"ActiveXTest" -> [应用程序类型]选择[动态链接库(DLL)] -> 完成

完成后,会在右边[解决方案资源管理器]生成很多"头文件.h"和"实现文件.CPP",这些都是默认的不要修改。



(2)添加一个ALT简单对象:

右键点击项目名称"ActiveXTest"选择 -> 添加[类] -> 选择[ATL简单对象] -> 添加 -> 简称(test_op) -> 下一步:其他不变,在[支持]中选择[连接点]和[IE对象支持]和[IEI] -> 完成 -> 选择[覆盖]



(3)给"test_op"添加一个方法,以便WEB页面调用。

[类视图]选择"itest_op"(灰色钥匙图标)鼠标右键添加 -> [添加方法] -> 方法起名为"testFunc"
参数类型选择LONG  参数名iFlag   参数属性选择IN -> 添加
参数类型选择BSTR* 参数名passw  参数属性选择RETVAL -> 点击完成。
属性in指输入参数,属性out指输出参数。

这样在项目中就产生了如下变化:

在test_op.h头文件中添加了一个(在最后一行):

STDMETHOD(testFunc)(LONG iFlag, BSTR* passWord);

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

STDMETHODIMP Ctest_op::testFunc(LONG iFlag, BSTR* passWord)
{
// TODO: 在此添加实现代码

return S_OK;
}


(4)在test_op.h 文件中,调用DLL类库。整体代码如下(认为添加的以标注):

// test_op.h : Ctest_op 的声明#pragma once#include "resource.h"       // 主符号#include "ActiveXTest_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 平台支持的唯一线程模型。"#endifusing namespace ATL;// Ctest_opclass ATL_NO_VTABLE Ctest_op :public CComObjectRootEx<CComSingleThreadModel>,public CComCoClass<Ctest_op, &CLSID_test_op>,public ISupportErrorInfo,public IConnectionPointContainerImpl<Ctest_op>,public CProxy_Itest_opEvents<Ctest_op>,public IObjectWithSiteImpl<Ctest_op>,public IDispatchImpl<Itest_op, &IID_Itest_op, &LIBID_ActiveXTestLib, /*wMajor =*/ 1, /*wMinor =*/ 0>{public://*******begin*****以下三行实现定义 add by 莫小哆_ly    typedef int (_stdcall *testGetPwd)(int,char*,char*); //类型定义,对应LOADDLL.dll->LoadFunc方法HINSTANCE hInstLibrary;    testGetPwd _testGetPwd; //类映射//*******end*****Ctest_op(){//*******begin*****开始调用DLL add by 莫小哆_ly        hInstLibrary = LoadLibrary(L"C:\\WINDOWS\\system32\\LOADDLL.dll");//相对路径时把写好的LOADDLL.dll文件放在此项目生成的目录debug下。        if (hInstLibrary == NULL)        {        FreeLibrary(hInstLibrary);//资源释放        }else{        }        //调用方法,返回方法句柄。        _testGetPwd = (testGetPwd)GetProcAddress(hInstLibrary, "LoadFunc");//*******end*****}DECLARE_REGISTRY_RESOURCEID(IDR_test_op)BEGIN_COM_MAP(Ctest_op)COM_INTERFACE_ENTRY(Itest_op)COM_INTERFACE_ENTRY(IDispatch)COM_INTERFACE_ENTRY(ISupportErrorInfo)COM_INTERFACE_ENTRY(IConnectionPointContainer)COM_INTERFACE_ENTRY(IObjectWithSite)END_COM_MAP()BEGIN_CONNECTION_POINT_MAP(Ctest_op)CONNECTION_POINT_ENTRY(__uuidof(_Itest_opEvents))END_CONNECTION_POINT_MAP()// ISupportsErrorInfoSTDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid);DECLARE_PROTECT_FINAL_CONSTRUCT()HRESULT FinalConstruct(){return S_OK;}void FinalRelease(){}public:STDMETHOD(testFunc)(LONG iFlag, BSTR* passWord);};OBJECT_ENTRY_AUTO(__uuidof(test_op), Ctest_op)


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

// test_op.cpp : Ctest_op 的实现#include "stdafx.h"#include "test_op.h"//*****begin*****add by 莫小哆_ly//#include "md5.h"//用于MD5加密,与本文无关,略去#pragma comment(lib, "comsuppw.lib")#include <comutil.h>//*****end*****// Ctest_opSTDMETHODIMP Ctest_op::InterfaceSupportsErrorInfo(REFIID riid){static const IID* const arr[] = {&IID_Itest_op};for (int i=0; i < sizeof(arr) / sizeof(arr[0]); i++){if (InlineIsEqualGUID(*arr[i],riid))return S_OK;}return S_FALSE;}STDMETHODIMP Ctest_op::testFunc(LONG iFlag, BSTR* passWord){// TODO: 在此添加实现代码//*****begin*****add by 莫小哆_lyint iflag = (int)(iFlag);char* pwd = new char[7];//参考testFunc的约定长度。char* mac = new char[33];char *pwd_md5 = new char[32];_testGetPwd(iflag,pwd,mac);//这里要求厂家提供的dll里(int,char*,char*)//结尾加结束符,防止数组溢出出现乱码[烫]pwd[6]='\0';//密码6位.0.1.2.3.4.5/pwd[6]->结束符//MD5加密//pwd_md5 = MD5String(pwd);//char*型转换成BSTR*类型*passWord = _com_util::ConvertStringToBSTR(pwd);//*****end*****this->_AtlFinalRelease();return S_OK;}


(7)生成DLL:
选[生成],在项目的Debug文件夹里找到dll文件"ActiveXTest.dll"
把LOADDLL.dll按照"test_op.h"里的描述放置,相对路径时可以放入Debug文件夹



(8)打包CAB文件:

利用iexpress.exe软件

1.准备好所有你用到的、调用的dll,外加1个写好的inf文件。[好吧,如果你不会,那小哆后面会一步步教你]

2.解压后,双击iexpress.exe。

[create new self extraction directive file] -> 下一步
[create compressed files only(activex installs)] -> 下一步
[add] ->选中准备好的文件 -> 下一步
[browse] - 选择好路径/命名/保存 ->[store files long file name inside package] -> 下一步
[don't save] -> 下一步 -> 下一步 -> 完成


3.cab包就此生成。

PS:小哆根据项目经验,总结出来的。所以肯定是可行的。

附注:setup.inf文件:

[version]signature="$CHICAGO{1}quot;AdvancedINF=2.0[Add.Code]ActiveXTest.dll=ActiveXTest.dllLOADDLL.dll=LOADDLL.dll[install.files]ActiveXTest.dll=ActiveXTest.dllLOADDLL.dll=LOADDLL.dll[ActiveXTest.dll]file-win32-x86=thiscabRegisterServer=yesclsid={197E37FC-9916-4881-B766-D43FDD0376E8}DestDir=11FileVersion=1,0,0,1[LOADDLL.dll]file-win32-x86=thiscabDestDir=11FileVersion=1,0,0,1[RegisterFiles]%11%/ActiveXTest.dll


【说明】

①[Add.Code]中dll顺序:

{举例说明}最终生成和调用的ActiveXTest.dll,其内部调用了LOADDLL.dll。

内部顺序是:

ActiveXTest.dll
LOADDLL.dll

②clsid={197E37FC-9916-4881-B766-D43FDD0376E8}

项目里的idl文件中,有一段这么记录:

library ActiveXTestLib
{
importlib("stdole2.tlb");
[
uuid(197E37FC-9916-4881-B766-D43FDD0376E8)
]
dispinterface _Itest_opEvents
{
properties:
methods:
};

那就选这个uuid吧,别问我为什么,我也不知道

这个到底是什么情况,我也没搞清楚,反正选了个这个可以正常运行。



(8)htm文件

<HTML><HEAD><TITLE>New Page</TITLE><OBJECT id=CaluNumCtrl codeBase="ActiveXTest.CAB#version=1,0,0,1" classid="clsid:3968A893-A79C-4AB9-B2FD-73BA2B76FB23"></OBJECT><script language="javascript">function doTest(){var pwd = CaluNumCtrl.testFunc(1);alert(pwd);}</script></HEAD><BODY><input type="button" value="调用" id="btnOK" onclick="doTest();"></input></BODY></HTML>


【附注】
<OBJECT id=CaluNumCtrl codeBase="test2.CAB#version=1,0,0,1" classid="clsid:225EDF53-A85F-4CB5-977D-69509C7E675C"></OBJECT>
CLSID 是 ActiveX 项目生成的序号,具体可以在项目的test_op.rgs 文件中找到。

ForceRemove {3968A893-A79C-4AB9-B2FD-73BA2B76FB23} = s 'test_op Class'
原创粉丝点击