写在前面:小哆把详细过程贴出来,一方面是记录备份,可以随时再利用,另一方面是分享,希望后来的初学者可以轻松一些。
"文件"
[选项]
(填写名称)
=============================
(1)创建项目
文件 -> 新建 -> ATL项目 -> 填写项目名称"ActiveXTest" -> [应用程序类型]选择[动态链接库(DLL)] -> 完成
完成后,会在右边[解决方案资源管理器]生成很多"头文件.h"和"实现文件.CPP",这些都是默认的不要修改。
(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类库。整体代码如下(认为添加的以标注):
(6)回到在test_op.cpp 文件中,添加实现代码如下:
(7)生成DLL:
选[生成],在项目的Debug文件夹里找到dll文件"ActiveXTest.dll"
把LOADDLL.dll按照"test_op.h"里的描述放置,相对路径时可以放入Debug文件夹
利用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文件:
【说明】
①[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文件
【附注】
<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'
[这是一个整体,所以,今后就不在赘述其中的东西,除非是前期本人自己理解错误,会更正,同时特别备注]
没有加入加密功能,MD5/DES加密都已实现,但在资源和其他的文章中有描述,本文加入过于赘述。
没有数字签名和发布部分,还未完全明白。
调用:LOADDLL.dll
"文件"
[选项]
(填写名称)
=============================
(1)创建项目
文件 -> 新建 -> ATL项目 -> 填写项目名称"ActiveXTest" -> [应用程序类型]选择[动态链接库(DLL)] -> 完成
完成后,会在右边[解决方案资源管理器]生成很多"头文件.h"和"实现文件.CPP",这些都是默认的不要修改。
右键点击项目名称"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 平台支持的唯一线程模型。"
#endif
using namespace ATL;
// Ctest_op
class 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()
// ISupportsErrorInfo
STDMETHOD(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_op
STDMETHODIMP 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 莫小哆_ly
int 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文件夹
利用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.dll
LOADDLL.dll=LOADDLL.dll
[install.files]
ActiveXTest.dll=ActiveXTest.dll
LOADDLL.dll=LOADDLL.dll
[ActiveXTest.dll]
file-win32-x86=thiscab
RegisterServer=yes
clsid={197E37FC-9916-4881-B766-D43FDD0376E8}
DestDir=11
FileVersion=1,0,0,1
[LOADDLL.dll]
file-win32-x86=thiscab
DestDir=11
FileVersion=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" οnclick="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'