描述:
江湖救急:~~~~~
项目背景介绍:
1. 应用环境:金融行业的金融衍生工具定价。
2. 软件平台:vc.net,excel
3. 项目简介:输入数据源为 excel中的若干列数据,通过一系列运算后,输出最后得到一个的价格到 excel.
由于运算的数据量很大,并相对速度要求比较高,所以老板要求中间运算使用c/c++编写。
所以我的解决方案是 用c++ 编写 dll, 然后在 vba中引用。。
4. 目前进展: 中间程序已经在VC++中编写成功,不过使用的是MFC界面编制的,通过触发控件事件调用了中间的运算过程。(编制的流程以及对EXCEL的控制参考自 徐景周的 “直接通过ODBC读写Excel表格文件”译文)
接着我在运用ATL封装中间程序后生成DLL也运行成功,但是在VBA中引用时,却出现了毁灭性错误,EXCEL总是自动关掉。
在DUBUG时推断,是数据集打开有问题。执行到这句话EXCEL就自动关掉,recset.Open(CRecordset::forwardOnly,sSql);
5.我的推断:是不是因为excel所调用的dll通过odbc又访问了本excel来获得数据源,所以出错??? 我只能想到这个原因,如果是这个原因,我还能通过别的什么办法在编制dll的时候来获得excel中的数据源呢?
请各路大虾指点迷经?
ps:本人学金融的,编程水平比较菜,一般纯C,C++还可以。。但是没有系统的研究过VC++,所以还请见谅!。。。。
主要代码:
DLL中的ATL_Tree事件函数:
STDMETHODIMP CATL_BDT::ATL_Tree(void)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// TODO: 在此添加实现代码
CDatabase database;
CString sSql,sDriver,sDsn,sFile,sPath;
//获取主程序所在路径,存在sPath中。 实际上DLL就嵌在 DEMO中应用。
GetModuleFileName(NULL,sPath.GetBufferSetLength (MAX_PATH+1),MAX_PATH);
sPath.ReleaseBuffer ();
int nPos;
nPos=sPath.ReverseFind ('\\');
sPath=sPath.Left (nPos);
sFile = sPath + "\\Demo.xls"; // 将被读取的Excel文件名
sDriver="MICROSOFT EXCEL DRIVER (*.XLS)";
if (sDriver.IsEmpty())
{
// 没有发现Excel驱动
AfxMessageBox("没有安装Excel驱动!");
return 0;
}
// 创建进行存取的字符串
sDsn.Format("ODBC;DRIVER={%s};DSN='';DBQ=%s", sDriver, sFile);
// 打开数据库(既Excel文件)
database.Open(NULL, false, false, sDsn);
CRecordset recset(&database);
// 设置读取的查询语句.
sSql = "SELECT * FROM Exceldemo "
"WHERE Id is not null";
"ORDER BY Id ";
// // 执行查询语句------出错语句,,就在EXCEL执行到DLL下面的这句话时,自动关闭了。。不知道是啥原因。。。
recset.Open(CRecordset::forwardOnly, sSql, CRecordset::readOnly);
// 获取查询总纪录数
while (!recset.IsEOF())
{
sItemCount = recset.GetRecordCount();
recset.MoveNext();
t++;
}
database.Close();
。。。。。。
。。。。。。。
。。。。。。
省略
return S_OK;
}
在VBA中的引用时的语句:
Dim objTestATL As test123Lib.ATL_BDT
Set objTestATL = New ATL_BDT
objTestATL.ATL_Tree
Set objTestATL = Nothing
解决方案1:
可能的原因:
1 你的EXCEL表中的数据类型(列)不一致(虽然看起来象一样的,但类型不一样);
2 你的EXCEL表中的数据不对齐;
看看你的EXCEL表中的数据对不对
把你的代码和Excel发给我的邮箱看看:IUnknown886@yahoo.com.cn
不过,为什么要用odbc打开EXCEL呢?
如果使用ATL,就直接写个COM访问EXCEL中的对象实例就行了,比如WorkBook WorkSheet,
做一个COM,在stdafx.h中加下面代码:
#import "d:\\Program Files\\Common Files\\Microsoft Shared\\OFFICE11\\MSO.DLL" rename_namespace("Office")
using namespace Office;
#import "d:\\Program Files\\Common Files\\Microsoft Shared\\VBA\\VBA6\\VBE6EXT.olb" rename_namespace("VBE6")
using namespace VBE6;
#import "d:\\Program Files\\Microsoft Office\\OFFICE11\\excel.exe" rename("RGB","RBGEx"),rename("DialogBox","DialogBoxEx"),named_guids,rename_namespace("Excel")
using namespace Excel;
在接口中定义函数:
GetExcelApp(LPDISPATCH lpApp)
{
Excel::_ApplicationPtr ptrXlApp;
Excel::WorkbooksPtr ptrWbs;
Excel::_WorkbookPtr ptrWb;
Excel::_WorksheetPtr ptrWs;
Excel::RangePtr ptrRange;
ptrXlApp=lpApp;
ptrWbs=ptrXlApp->GetWorkbooks();
...... //由Application得到WorkBook,再由WorkBook得到WorkSheet,再得到Range等,和VBA中差不多的.这种直接访问应该比ODBC的间接访问速度更快.
}
个人观点,仅供参考:)