首先是引用的文章: http://support.microsoft.com/kb/279721/zh-cn—————————————————————————————————————————————————————————————————本文介绍了如何在 Visual C++ 中使用动态数据交换 (DDE),与 Excel 和 Word 进行通信。
注意: 如果可能,建议使用自动化,不 DDE,与 Excel 或 Word 进行通信。Excel 和 Word 具有丰富的对象模型提供了通过使用 DDE 不可用的自动化功能。5.0 及更高版本的 Excel 版本和版本 7.0 及更高版本的 Word 支持自动化。DDE 客户示例
下面的示例使用 Excel 工作簿或 Word 文档的 DDE 主题。
对于 Excel,创建一个新工作簿 (C:\Test.xls),其中包含在单元格 A1 和 A2 中的数据。对于 Word,请创建包含文本的新文档 (C:\Test.doc)。选择文档中的文本的部分但非全部) 并创建一个名为"在"在该位置的书签。
- 在 Visual C++,将创建一个新的 Win32 控制台应用程序名为"DDEClient"。
- 在应用程序向导,选择简单的应用程序,然后单击完成。
#include "stdafx.h"
#include "windows.h"
#include "ddeml.h"
#include "stdio.h"
HDDEDATA CALLBACK DdeCallback(
UINT uType, // Transaction type.
UINT uFmt, // Clipboard data format.
HCONV hconv, // Handle to the conversation.
HSZ hsz1, // Handle to a string.
HSZ hsz2, // Handle to a string.
HDDEDATA hdata, // Handle to a global memory object.
DWORD dwData1, // Transaction-specific data.
DWORD dwData2) // Transaction-specific data.
{
return 0;
}
void DDEExecute(DWORD idInst, HCONV hConv, char* szCommand)
{
HDDEDATA hData = DdeCreateDataHandle(idInst, (LPBYTE)szCommand,
lstrlen(szCommand)+1, 0, NULL, CF_TEXT, 0);
if (hData==NULL) {
printf("Command failed: %s\n", szCommand);
}
else {
DdeClientTransaction((LPBYTE)hData, 0xFFFFFFFF, hConv, 0L, 0,
XTYP_EXECUTE, TIMEOUT_ASYNC, NULL);
}
}
void DDERequest(DWORD idInst, HCONV hConv, char* szItem, char* sDesc)
{
HSZ hszItem = DdeCreateStringHandle(idInst, szItem, 0);
HDDEDATA hData = DdeClientTransaction(NULL,0,hConv,hszItem,CF_TEXT,
XTYP_REQUEST,5000 , NULL);
if (hData==NULL)
{
printf("Request failed: %s\n", szItem);
}
else
{
char szResult[255];
DdeGetData(hData, (unsigned char *)szResult, 255, 0);
printf("%s%s\n", sDesc, szResult);
}
}
void DDEPoke(DWORD idInst, HCONV hConv, char* szItem, char* szData)
{
HSZ hszItem = DdeCreateStringHandle(idInst, szItem, 0);
DdeClientTransaction((LPBYTE)szData, (DWORD)(lstrlen(szData)+1),
hConv, hszItem, CF_TEXT,
XTYP_POKE, 3000, NULL);
DdeFreeStringHandle(idInst, hszItem);
}
int main(int argc, char* argv[])
{
char szApp[] = "EXCEL";
char szTopic[] = "C:\\Test.xls";
char szCmd1[] = "[APP.MINIMIZE()]";
char szItem1[] = "R1C1"; char szDesc1[] = "A1 Contains: ";
char szItem2[] = "R2C1"; char szDesc2[] = "A2 Contains: ";
char szItem3[] = "R3C1"; char szData3[] = "Data from DDE Client";
char szCmd2[] = "[SELECT(\"R3C1\")][FONT.PROPERTIES(,\"Bold\")][SAVE()][QUIT()]";
//DDE Initialization
DWORD idInst=0;
UINT iReturn;
iReturn = DdeInitialize(&idInst, (PFNCALLBACK)DdeCallback,
APPCLASS_STANDARD | APPCMD_CLIENTONLY, 0 );
if (iReturn!=DMLERR_NO_ERROR)
{
printf("DDE Initialization Failed: 0x%04x\n", iReturn);
Sleep(1500);
return 0;
}
//Start DDE Server and wait for it to become idle.
HINSTANCE hRet = ShellExecute(0, "open", szTopic, 0, 0, SW_SHOWNORMAL);
if ((int)hRet < 33)
{
printf("Unable to Start DDE Server: 0x%04x\n", hRet);
Sleep(1500); DdeUninitialize(idInst);
return 0;
}
Sleep(1000);
//DDE Connect to Server using given AppName and topic.
HSZ hszApp, hszTopic;
HCONV hConv;
hszApp = DdeCreateStringHandle(idInst, szApp, 0);
hszTopic = DdeCreateStringHandle(idInst, szTopic, 0);
hConv = DdeConnect(idInst, hszApp, hszTopic, NULL);
DdeFreeStringHandle(idInst, hszApp);
DdeFreeStringHandle(idInst, hszTopic);
if (hConv == NULL)
{
printf("DDE Connection Failed.\n");
Sleep(1500); DdeUninitialize(idInst);
return 0;
}
//Execute commands/requests specific to the DDE Server.
DDEExecute(idInst, hConv, szCmd1);
DDERequest(idInst, hConv, szItem1, szDesc1);
DDERequest(idInst, hConv, szItem2, szDesc2);
DDEPoke(idInst, hConv, szItem3, szData3);
DDEExecute(idInst, hConv, szCmd2);
//DDE Disconnect and Uninitialize.
DdeDisconnect(hConv);
DdeUninitialize(idInst);
Sleep(3000);
return 1;
}
char szApp[] = "WINWORD";
char szTopic[] = "C:\\test.doc";
char szCmd1[] = "[AppMinimize][EditGoTo Destination:=\"\\EndofDoc\"][InsertPara]";
char szItem1[] = "\\Doc"; char szDesc1[] = "Document contains: \n";
char szItem2[] = "MyBookmark"; char szDesc2[] = "MyBookmark contains: \n";
char szItem3[] = "\\EndofDoc"; char szData3[] = "Data from DDE Client";
char szCmd2[] = "[FileSave][FileExit(2)]";
使用 Excel,DDE 客户端初始化 DDE 对话 (C:\Test.xls) 的工作簿文件中使用的主题,并执行下列操作:执行该应用程序。
R1C1 和 R2C1 项中的数据的请求。
Pokes 到 R3C1 的数据。
将 R3C1 格式设置为粗体、 保存该工作簿,然后退出 Excel。
使用 Word,DDE 客户端启动文档文件 (C:\Test.doc) 使用该主题的 DDE 对话并执行下列操作:
执行命令,以最小化应用程序,转到文档的末尾插入一个新段落。
请求的项"\Doc"来检索整个文档的内容。
请求的项目"在"以检索在书签中的文本。
执行命令,以将该文档保存并退出 Word。
—————————————————————————————————————————————————————————————————
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
网上找的很多例子也与这个类似,这个例子很好的教大家怎么使用DDE与Excel进行交互,但我在用这个例子大量的读取excel表格时,运行一段时间程序都读异常了,读到表格的内容不正确。
经过认真观察测试发现,在多次读excel表格的过程中,程序内存也有累计增长(一到两兆)。多种测试后,想到了在调用
DDERequest时加上计数器,结果发现调用到16384(0x4000,或2^14)次之后就出错,改变excel格式,表格中的内容的长短,都在达到这个次数后就报错。于是猜到可能是哪里没有释放,或dde的限制,并查看ddl的相关函数,从网上找用法,最终定位到了DdeFreeDataHandle这个函数(也尝试了DdeFreeStringHandle,但在这里没效果)。
修改后的DDERequest函数如下:
void DDERequest(DWORD idInst, HCONV hConv, char* szItem, char* sDesc)
{
HSZ hszItem = DdeCreateStringHandle(idInst, szItem, 0);
HDDEDATA hData = DdeClientTransaction(NULL,0,hConv,hszItem,CF_TEXT,
XTYP_REQUEST,5000 , NULL);
if (hData==NULL)
{
printf("Request failed: %s\n", szItem);
}
else
{
char szResult[255];
DdeGetData(hData, (unsigned char *)szResult, 255, 0);
printf("%s%s\n", sDesc, szResult);
}
//改进,增加的两行
DdeFreeStringHandle(idInst,hszItem);
DdeFreeDataHandle(hData); //关键
}
参考:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms648752(v=vs.85).aspx
http://publib.boulder.ibm.com/infocenter/cmod/v7r1m1/index.jsp?topic=%2Fcom.ibm.ondemand.doc%2Fars5u271262.htm
由ibm网站中的例子调用
DdeUnaccessData释放想到,才联想和找到
DdeFreeDataHandle。