测试环境: VS2008 + SP1 补丁 XP 32位系统
1、启动VS2008,新建项目,如图
2、再次新建项目,如图
需要注意的就是 在 Solution 那里 选择 Add to Solution ,同时,上面的 Location 会自动定位到当前的解决方案里。这个项目,直接点击Finish 结束就行了。
3、将视图切换到文件视图(View 菜单中的 Solution Explorer) ,如图
可以看到这里面有 类似 文件夹的 东东,,它们是 Filter 就是将某一些相同类型的文件 整理在一起的功能,我们将它们全部折合起来。
还有一点,我们会看到这里有两个项目 ,带 PS 的那个,我们暂时用不到,直接 在 它上面 右击,选择 Remove 即可 ,这样,我们这个解决方案里就只有一个 项目 了。
然后,我们 选中 QMath 这个 项目 ,然后在 Project菜单项 中 选择 Add Class ,为它添加一个类
左边选择 ATL ,右边选择 ATL SIMPLE OBJECT 。然后点击 ADD。
在弹出的对话框中,只需要要在 C++ SHORT NAME 中 写上 QPrimerMath 即可,
然后点击下一步,这里比较重要,我们一定要选择 Custom
然后就可以点击 Finish了。
切换到类视图,我们可以看到 多了 两个东东,,一个 是 I.... ,这个就是接口啦,一个是C...,这个就是组件类了。
然后,我们要为 接口添加 方法 ,在接口 上右击 ,选择 Add --> Add Method 弹出图示对话框
在这里面,我们可以 为 我们的接口添加 方法 ,这个 地方的步骤 ,我还是一步一步写下来吧,
1、输入 方法名 ,如 Add
2、点击 in ,然后 参数类型 输入 LONG 参数名称 输入 nA,然后点击Add ,这样就添加了一个输入参数,然后再次点击 in ,同之前的操作一样,添加第二个参数,nB ,在COM 中 返回值是要用指针往外带值的,但是我们看到 retval 这个参数属性又是灰掉的,,肿么办? 先在 参数类型中 输入 LONG* ,然后你就看到 out 和 retval 都可以用了,然后输入 参数名,其它的都一样操作了。
这样来理解一下,这个函数 叫 Add, 有两个输入参数,一个通过指针向外带的 返回值,OK。
然后直接 点击 Finish 就可以了。
在整个过程中,时刻要记得保存代码。
下面,我们就在 组件类中 实现代码
双击 这个 Add 方法,然后为它 写上 实现代码。
好了,然后我们 迅速的 再 做 其它 4 个 方法 ,,Sub,Mul,Div,Mod
,,,,等等,,迅速,怎么迅速呢?当然是 手工添加啦,因为这些函数 参数都是类似的,,只是函数名 和 实现代码不同而以。
1、为 接口 添加上 其它 4 个方法 ,如何快速呢? 这里要告诉你几个小技巧,快速复制一行,鼠标只要在当前行,按下 CTRL + C 就复制了当前行,不需要选中哦。双击 接口 中的 Add 的声明 ,定位到了如下 位置
其实它里面就 一行,
[helpstring("method Add")] HRESULT Add([in] LONG nA, [in] LONG nB, [out,retval] LONG* nResult);
我们只要将 光标 定位 到这一行,注意,不要选中 任何东东,,直接 CTRL + C ,然后 CTRL + V 四次。 效果如下图
哈哈,是不是 很方便 ,然后 就是 修改函数名,这里也有小技巧,,就是 块选,我先演示一下效果,
不只是可以 块选择,还可以块复制 和 粘贴 ,所以嘛,你懂的,,先改 前面的 五个,然后 复制,然后再 选中 后面的 五个,再 粘贴,那么到底怎么块选择呢,技巧就是 在选择的时候 按住 ALT 键。
其实很多编辑类的软件都提供了这一功能哦,比如 NOTEPAD++。
接口中 声明了 这五个方法 了,,在 组件类 中 也要 进行声明 ,并且 还要实现它们的功能。
直接打开组件类对应的 头文件, 或者 直接 双击 组件类 的类名 也可以,在这里面,我们可以找到 如下图所示的 Add函数声明
所以嘛,其它的我也不用说了,你都会了,不要忘记 块操作哦。
OK,类中,我们也声明完了,,接下来,我们就是 要到 类中 实现 操作了。其实,在这里,还有小技巧,那就是 VS中快捷键的 定制,我相信你,如果看到这里了,你的VS 应该是 安装有 VAX 插件了,,。没有的话,你可以百度一下 VS2008 VAX 插件了。
然后我们 点击 工具 菜单下 自定义 ,弹出
点击 左下角 的 键盘,
在 Show commands containing 中 输入 VAssistX.RefactorCreateIm ,下面的列表中 就会只剩余一项了,然后 在下面 可以为它 指定 加速键 ,我指定为 了 CTRL + Q,按两次。
好了,我相信你可以搞定它。
那么这个功能是做什么用的呢,说白了 就是 为我们 自动 添加 实现代码的,,然后我们将 鼠标 放在 组件类 中 声明 的 Sub 方法 上, 按下 上面的 加速键, 会发现,CPP文件中 自动添加了
这个时候,如果我们 按 CTRL + TAB 键,则会 切换 加 头文件中,按一下 下方向键,就会定位到 Mul 这三个字母上,然后再 CTRL + Q 两次,是不是很方便呢。
快速添加完五个函数的实现。
同时呢,我们的五个 函数的 具体实现 也 差不多,只是 运算符不一样而以,复制行,粘贴,但是在粘贴的时候要注意,这个 复制行 在复制的时候 ,将换行符也复制了,,而且在 粘贴的时候 是 将数据 粘贴在 鼠标所在 当前行的 上一行。
所以,我们先 将 鼠标 放在
*nResult = nA + nB; 这一行上
然后 复制,
STDMETHODIMP CQPrimerMath::Sub( LONG nA, LONG nB, LONG* nResult )
{
return S_OK; 然后将鼠标 放在 这一行上,再 粘贴
}
上面都是一些技巧,掌握了这些技巧 ,你的效率会高出很多哦。
由于 除法中 nB 是不可以 为0 的,,但是我们只是 为了演示 ,不做 特殊处理。
这样,我们就 制作了一 个 组件类了,,是不是感觉 很棒呢。
我们编译生成一下。然后大家去网上下载一个 OLEVIEW 的工具,,VS2008中好像没有,但 2010中又有了。
打开这个工具,
然后点击 工具栏中 3个红色箭头的 图标,然后,打开我们生成的 DLL 文件
好,我们按上面的方法 ,再添加一个组件类,名字叫做 QAdvancedMath ,注意一定要选择 CUSTOM 。
为它添加 一个 求 阶乘的 方法。
很简单,然后我们再生成 一下。
哦,我的生成出错了。
1>LINK : fatal error LNK1168: cannot open Debug\QMath.dll for writing
这是因为我的OLEVIEW 还在使用着 这个DLL,所以 要关掉它。
然后再生成 就OK了。
再用工具查看一下
我们发现,我们这里有两个 COCLASS,也叫做 组件类,下面,我们要 来 画一下,这里面的 继承关系
好,这就是 它的 最基本的 继承 图表啦。。当然 ,中间的 两个 接口 还 继承了 其它 的 接口,这个暂时不讨论它。
上图中 的 第三层,,是表示 组件类的,,每个组件类 都有一个 类ID,也叫 CLSID ,其形式 表示为 CLSID_类名 ,但是类名 是要 去年 最前面的 字母 C 的。
上图中 的 第二层,,是表示 接口的,每个接口也都有一个 接口ID,也叫 IID,其形式 表示 为
IID_I类名 ,但是类名 是要 去年 最前面的 字母 C 的。
因为组件类 是 二进制 共享的 ,所以 每个 组件类 实现的 功能 只能由 接口负责 调用,为了区分开 所有的 组件类,就使用了上面的 类ID 和 接口ID。
在OLEVIEW 里,可以看到它们的具体定义。
好了,既然是 共享使用的,那么我们就演示一下 在MFC 中 如何使用 它。
点击 File -- Add -- Add New Project 选择MFC 应用程序,
下面的有一步 要对着 下图 所示进行选择
这里选择 Active Accessibility 主要是 让 MFC 做 COM 的自动 初始化 ,加上这句话后,在
BOOL CTestQMathApp::InitInstance() 中 会添加如下 语句。
if (!AfxOleInit())
{
AfxMessageBox(IDP_OLE_INIT_FAILED);
return FALSE;
}
然后,我们 在对话框 中 添加 两个 按钮
ID 分别为
IDC_BTN_PRIMER_MATH
IDC_BTN_ADVANCED_MATH
标题分别为
Test Primer Math
Test Advanced Math
添加响应函数
void CTestQMathDlg::OnBnClickedBtnPrimerMath()
{
IQPrimerMath * pPrimerMath = NULL;
HRESULT hr = CoCreateInstance(CLSID_QPrimerMath,NULL,CLSCTX_INPROC_SERVER,IID_IQPrimerMath,(LPVOID *)&pPrimerMath);
if (FAILED(hr)) return;
LONG n1 = 100,n2 = 25, nResult = 0;
pPrimerMath->Add(n1,n2,&nResult);
pPrimerMath->Sub(n1,n2,&nResult);
pPrimerMath->Mul(n1,n2,&nResult);
pPrimerMath->Div(n1,n2,&nResult);
pPrimerMath->Mod(n1,n2,&nResult);
pPrimerMath->Release();
CoFreeUnusedLibraries();
}
void CTestQMathDlg::OnBnClickedBtnAdvancedMath()
{
IQAdvancedMath * pAdvancedMath = NULL;
HRESULT hr = CoCreateInstance(CLSID_QAdvancedMath,NULL,CLSCTX_INPROC_SERVER,IID_IQAdvancedMath,(LPVOID *)&pAdvancedMath);
if (FAILED(hr)) return;
LONG nVal = 10 ,nResult = 0;
pAdvancedMath->Factorial(nVal,&nResult);
SetDlgItemInt(IDC_BTN_ADVANCED_MATH,nResult);
pAdvancedMath->Release();
CoFreeUnusedLibraries();
}
好了,一编译会出很多错误。
这是为什么呢,因为我们没有引入相关的定义,这些定义在哪里呢? 我们DLL 项目中 还有一个过滤器呢,就是它们两个啦,只要将它们 加入 我们 的 对话框 项目 中就 可以了。
#include "../QMath/QMath_i.h"
#include "../QMath/QMath_i.c"
好了,最后呢,我们的代码 还是有一个小问题呢,,就留给大家去发现,,去解决啦。。。
TIPS: 就是 求 阶乘 那里,,,我们没有 对 *nResult 赋值为 1,所以结果 一直是 0.。大家自己改改吧,,我们不是来说明这些东西的,,大家要弄清楚 重点。
好了,,就倒这里,,,2个半小时 过去了。。。
转载于:https://blog.51cto.com/qianqianquege/1439713