一、 概述
因项目需要,开始学习并研究VC、DLL及ActiveX控件。
DLL(动态链接库): 分WIN32 DLL和MFC DLL
ActiveX:分ATL控件和MFC控件两类(也是一个DLL)
WEB:JAVASCRIPT 调用-> ActiveX调用-> DLL 完成加法运算并返回值,在页面上显示。
以数学运算库DLL的开发为例
二、开发(VS2008)
1、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++中使用。
extern "C"
{
DECLDIR int Add( int a, int b );
DECLDIR void Function( void );
}
#endif
(2)实现代码testdll.cpp,代码如下:
#include <iostream>
#define DLL_EXPORT
#include "testdll.h"
extern "C"
{
// 这里主要用到 ADD 方法。
DECLDIR int Add( int a, int b )
{
return( a + b );
}
DECLDIR void Function( void )
{
std::cout << "DLL Called!" << std::endl;
}
}
(3)可选。新建一个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"E:\\Project\\VS\\LoadDll\\Release\\TestDll.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);
}
由于组件的语言无关性要求调用和被调双方必须在函数调用的约定上一致,因此在后面加载DLL并获取此方法时也要求和你的声明一致。
至此我们的数学运算函数库DLL就完成了。
2,用ATL开发ActiveX控件
开发ActiveX控件有两种方式,一是MFC,二是ATL,而后者是专门用于COM组件开发,因此更适合于ActiveX。因此这里选择后者,前者的开发示例参考我这篇文章(待完成)。
文件->新建->ATL项目->填写项目名称(“FuckATL”)->选择动态链接库(DLL)->完成。
完成后,会在右边“解决方案资源管理器”生成很多头H文件和CPP实现文件,这些都是默认的不要修改。
(1)、添加一个ALT简单对象:鼠标右键点击项目名称(刚才起的名字)选择 –>添加类 –>选择ATL简单对象。
下一步取一个名字:“CaluNumCtrl” –>其他不变,在支持中,选择“连接点”和“IE对象支持”->完成。
下一步给“CaluNumCtrl”添加一个方法,以便WEB页面调用。在“类视图”选择“ICaluNumCtrl”(有个灰色的钥匙图标)鼠标右键->添加方法。方法起名为“GetContent”->参数属性选择IN,参数类型选择LONG 参数名 Num1 –>添加;继续;参数属性选择IN,参数类型选择LONG 参数名 Num2 –>添加;继续;参数属性选择OUT和RETVAL ,参数类型选择LONG* 参数名 ReturnVal–>添加 –>点击完成。
在CaluNumCtrl.h 文件中,调用DLL类库。代码如下:
// CaluNumCtrl.h : CCaluNumCtrl 的声明
#pragma once
#include "resource.h" // 主符号
#include <Windows.h> //添加
#include "FuckATL_i.h"
#include "_ICaluNumCtrlEvents_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
// CCaluNumCtrl
class ATL_NO_VTABLE CCaluNumCtrl :
////去掉与页面交互的警告
public IObjectSafetyImpl<CCaluNumCtrl, INTERFACESAFE_FOR_UNTRUSTED_CALLER| INTERFACESAFE_FOR_UNTRUSTED_DATA>,
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CCaluNumCtrl, &CLSID_CaluNumCtrl>,
public IConnectionPointContainerImpl<CCaluNumCtrl>,
public CProxy_ICaluNumCtrlEvents<CCaluNumCtrl>,
public IObjectWithSiteImpl<CCaluNumCtrl>,
public IDispatchImpl<ICaluNumCtrl, &IID_ICaluNumCtrl, &LIBID_FuckATLLib, /*wMajor =*/ 1, /*wMinor =*/ 0>
{
public:
typedef int (*AddFunc)(int,int); //类型定义,对应DLL ADD方法。Func自定义,随便写。
HINSTANCE hInstLibrary;
AddFunc _AddFunc; //类映射
CCaluNumCtrl()
{
//开始调用DLL,进行计算。
hInstLibrary = LoadLibrary(L"TestDll.dll");//把写好的DLL文件放在此项目生成的目录下
if (hInstLibrary == NULL)
{
FreeLibrary(hInstLibrary);//资源释放
}else{
}
//调用方法,返回方法句柄。
_AddFunc = (AddFunc)GetProcAddress(hInstLibrary, "Add");
}
DECLARE_REGISTRY_RESOURCEID(IDR_CALUNUMCTRL)
BEGIN_COM_MAP(CCaluNumCtrl)
COM_INTERFACE_ENTRY(ICaluNumCtrl)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(IConnectionPointContainer)
COM_INTERFACE_ENTRY(IObjectWithSite)
////
COM_INTERFACE_ENTRY(IObjectSafety)
END_COM_MAP()
BEGIN_CONNECTION_POINT_MAP(CCaluNumCtrl)
CONNECTION_POINT_ENTRY(__uuidof(_ICaluNumCtrlEvents))
END_CONNECTION_POINT_MAP()
// ISupportsErrorInfo
//STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid);
DECLARE_PROTECT_FINAL_CONSTRUCT()
HRESULT FinalConstruct()
{
return S_OK;
}
void FinalRelease()
{
}
public:
STDMETHOD(GetContent)(LONG Num1, LONG Num2, LONG* ReturnVal);
};
OBJECT_ENTRY_AUTO(__uuidof(CaluNumCtrl), CCaluNumCtrl)
在控件实现文件CaluNumCtrl.cpp中,代码如下:
// CaluNumCtrl.cpp : CCaluNumCtrl 的实现
#include "stdafx.h"
#include "CaluNumCtrl.h"
// CCaluNumCtrl
STDMETHODIMP CCaluNumCtrl::GetContent(LONG Num1, LONG Num2, LONG* ReturnVal)
{
// TODO: 在此添加实现代码
int sum = this->_AddFunc(static_cast<int>(Num1),static_cast<int>(Num2));
*ReturnVal = static_cast<LONG>(sum);
return S_OK;
}
生成DLL。
好了,ActiveX控件仅仅是简单地调用底层的数学运算库DLL来完成运算,下面我们写一个exe程序对这个COM组件进行测试。
3,一个控制台测试程序
建立一个最简单的控制台程序来进行测试,代码如下:
#include "E:\project\FuckATL\FuckATL\FuckATL_i.h"
#include "..\..\FuckATL\FuckATL\FuckATL_i.c"
#include <iostream>
using namespace std;
void main(void)
{
// Declare and HRESULT and a pointer to the Simple_ATL interface
HRESULT hr;
ICaluNumCtrl *IFirstATL = NULL;
// Now we will intilize COM
hr = CoInitialize(0);
// Use the SUCCEDED macro and see if we can get a pointer to
// the interface
if(SUCCEEDED(hr))
{
hr = CoCreateInstance( CLSID_CaluNumCtrl, NULL, CLSCTX_INPROC_SERVER,
IID_ICaluNumCtrl, (void**) &IFirstATL);
// If we succeeded then call the AddNumbers method, if it failed
// then display an appropriate message to the user.
if(SUCCEEDED(hr))
{
long ReturnValue;
hr = IFirstATL->GetContent(5, 7, &ReturnValue);
cout << "The answer for 5 + 7 is: " << ReturnValue << endl;
hr = IFirstATL->Release();
}
else
{
cout << "CoCreateInstance Failed." << endl;
}
}
// Uninitialize COM
CoUninitialize();
system("pause");
}
三,来到IE的世界
最后我们将此ActiveX组件嵌入到html页面中,对其进行测试.新建一个html页面,代码如下:
<HTML>
<HEAD>
<TITLE>Test ATL</TITLE>
</HEAD>
<OBJECT id=AxCon classid=clsid:8D27C00E-F7F8-4801-9025-E5E4CD13E35E height=50 width=100 codebase="FuckATL.dll">
</OBJECT>
<BODY>
Hello, ATL!
<script language="javascript">
function init() {
var foo = AxCon;
if (foo == null) {
window.alert("foo is null.");
return;
}
var val = null;
try {
val = AxCon.GetContent(5, 7);
window.alert(val);
} catch (e) {
window.alert("AxCon.GetContent() failed.");
return;
}
if (val == null) {
window.alert("val is null.");
return;
}
}
</script>
<INPUT type="button" value="Test" id="button1" name="button1" onclick="init();"></P>
</BODY>
</HTML>