[求教]dll里含多个函数是否正确

山书生 2010-08-02 01:21:12
#include "afx.h"
#include "stdafx.h"
#include <stdio.h>
#include <string.h>

BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
return TRUE;
}

extern "C" _declspec(dllexport) int SendCRMservice( char *saleOrder)
{

//......

}

extern "C" _declspec(dllexport) int SendR3delivery( char *saleOrder)
{

//......

}

常出现第三方程序调该DLL会出现异常,——调用dll函数后,发现功能不再执行,日志文件不写,连接数据库不在生效……
重启第三方程序,又正常了
...全文
128 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
山书生 2010-08-12
  • 打赏
  • 举报
回复
应该是采用ado连库造成的吊死线程。。。

在网上查了查,据说ado在dll下是非多线程安全应用,多线程调用会引起吊死ado连接。
需要以连接池的方式来解决……

又有说当开启了企业管理器的时候,会吊死ado连接……
正在测试此,看看 :(
zhanshen2891 2010-08-02
  • 打赏
  • 举报
回复
没抓一下dump看看么??
cdm2179 2010-08-02
  • 打赏
  • 举报
回复
第三方程序是什么语言写的,会不会和函数调用约定由关系
yuejunqi 2010-08-02
  • 打赏
  • 举报
回复
个人认为关于连接数据库的程序还是不要写成dll最好,把要提供的变量写成一个结构,编写dll导出到主线程去上传
ouyh12345 2010-08-02
  • 打赏
  • 举报
回复
用procexp之类的软件看进程停在哪个线程
或者写日志

然后再分析
山书生 2010-08-02
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 yuejunqi 的回复:]
个人认为关于连接数据库的程序还是不要写成dll最好,把要提供的变量写成一个结构,编写dll导出到主线程去上传
[/Quote]
根据重启应用来看,会在dll的log文件中补写一段长时间的连数据库日志。该连库是用一个ADOConn.cpp实现的。奇怪呀……

// ADOConn.cpp: implementation of the ADOConn class.
//////////////////////////////////////////////////////////////////////
#include "afx.h"//#include <afx.h>
#include "stdafx.h"
#include "ADOConn.h"
//#include "Global.h"
#include <stdio.h>
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
ADOConn::ADOConn()
{
}

ADOConn::~ADOConn()
{
}

// 初始化—连接数据库
int ADOConn::OnInitADOConn()
{
// 初始化OLE/COM库环境
::CoInitialize(NULL);
// CGlobal global;
FILE *fp = fopen("ivrSendDBinfo.txt", "a"); //以添加的方式输出到文件
CTime tm;
tm = CTime::GetCurrentTime();
fprintf(fp,"[%s] ",tm.Format("%m/%d/%Y %H:%M:%S"));
try
{
// 创建Connection对象
m_pConnection.CreateInstance("ADODB.Connection");
// 设置连接字符串,必须是BSTR型或者_bstr_t类型
//读取ini文件
char strsv[20];
if(GetPrivateProfileString("paramter","Server","",strsv,sizeof(strsv),".\\ivrSendDBinfo.ini") == NULL)
{
printf("读取文件失败");
exit(1);
}

//读取ini文件
char strdb[20];
if(GetPrivateProfileString("paramter","Database","",strdb,sizeof(strdb),".\\ivrSendDBinfo.ini") == NULL)
{
printf("读取文件失败");
exit(1);
}

//读取ini文件
char struid[20];
if(GetPrivateProfileString("paramter","uid","",struid,sizeof(struid),".\\ivrSendDBinfo.ini") == NULL)
{
printf("读取文件失败");
exit(1);
}

//读取ini文件
char strpwd[20];
if(GetPrivateProfileString("paramter","pwd","",strpwd,sizeof(strpwd),".\\ivrSendDBinfo.ini") == NULL)
{
printf("读取文件失败");
exit(1);
}
CString str,str1,str2,str3;
str = (char*)strsv;
str1 = (char*)strdb;
str2 = (char*)struid;
str3 = (char*)strpwd;

_bstr_t strConnect = "Provider=SQLOLEDB;Server="+str+";Database="+str1+";uid="+str2+";pwd="+str3+";";
fprintf(fp," server=%s database=%s uid = %s pwd = ****",str,str1,str2); //////////重启应用之后,log文件补写此处log日志到log文件
fprintf(fp,"\n");
m_pConnection->ConnectionTimeout = 40; //设置连接数据库的时间
m_pConnection->CommandTimeout = 40; //设置查询等操作命令的时间
m_pConnection->Open(strConnect,"","",adModeUnknown);
return 1;
}
// 捕捉异常
catch(_com_error e)
{
// 显示错误信息
// MessageBox(e.Description());
tm = CTime::GetCurrentTime();
fprintf(fp,"[%s] ",tm.Format("%m/%d/%Y %H:%M:%S"));
fprintf(fp," 连接数据库不成功!!");
fprintf(fp,"\n");
printf(e.Description());
printf("\n");
return 3;
}
}

// 执行查询
_RecordsetPtr& ADOConn::GetRecordSet(_bstr_t bstrSQL)
{
try
{
// 连接数据库,如果Connection对象为空,则重新连接数据库
if(m_pConnection==NULL)
OnInitADOConn();
// 创建记录集对象
m_pRecordset.CreateInstance(__uuidof(Recordset));
// 取得表中的记录
m_pRecordset->Open(bstrSQL,m_pConnection.GetInterfacePtr(),adOpenDynamic,adLockOptimistic,adCmdText);
}
// 捕捉异常
catch(_com_error e)
{
// 显示错误信息
// AfxMessageBox(e.Description());
printf(e.Description());
}
// 返回记录集
return m_pRecordset;
}

// 执行SQL语句,Insert Update _variant_t
BOOL ADOConn::ExecuteSQL(_bstr_t bstrSQL)
{
// _variant_t RecordsAffected;
try
{
// 是否已经连接数据库
if(m_pConnection == NULL)
OnInitADOConn();
// Connection对象的Execute方法:(_bstr_t CommandText,
// VARIANT * RecordsAffected, long Options )
// 其中CommandText是命令字串,通常是SQL命令。
// 参数RecordsAffected是操作完成后所影响的行数,
// 参数Options表示CommandText的类型:adCmdText-文本命令;adCmdTable-表名
// adCmdProc-存储过程;adCmdUnknown-未知
m_pConnection->Execute(bstrSQL,NULL,adCmdText);
return true;
}
catch(_com_error e)
{
// AfxMessageBox(e.Description());
printf(e.Description());
return false;
}
}

void ADOConn::ExitConnect()
{
// 关闭记录集和连接
if (m_pRecordset != NULL)
m_pRecordset->Close();
m_pConnection->Close();
// 释放环境
::CoUninitialize();
}
山书生 2010-08-02
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 coding_hello 的回复:]
导出多个函数显然是可以的。系统DLL导出的函数海了去了。
第三方程序是指啥? PB之类的? //第三方程序是一个软件,它提供了调用dll的接口
注意一下Call Convention。你这里默认应该是cdecl,可以改为stdcall试试。
extern "C" _declspec(dllexport) int WINAPI SendCRMservice( char *saleOrder)
//extern "C"的格式也是这个第三方软件要求
WINAPI是个宏定义,也可以写成……
[/Quote]

[Quote=引用 3 楼 ouyh12345 的回复:]
用procexp之类的软件看进程停在哪个线程 //在服务器上可不敢乱装软件:(
或者写日志
然后再分析
[/Quote]

野男孩 2010-08-02
  • 打赏
  • 举报
回复
导出多个函数显然是可以的。系统DLL导出的函数海了去了。

第三方程序是指啥? PB之类的?

注意一下Call Convention。你这里默认应该是cdecl,可以改为stdcall试试。

extern "C" _declspec(dllexport) int WINAPI SendCRMservice( char *saleOrder)

WINAPI是个宏定义,也可以写成__stdcall
山书生 2010-08-02
  • 打赏
  • 举报
回复
#include "afx.h"//#include <afx.h>	报重复定义DllMain 注释afx.h USRDLL段代码 并将该.h放入本地路径
#include "stdafx.h"
#include "soapH.h"
#include "MediaPlatformServiceHttpBinding.nsmap"
#include <stdio.h>
#include "ADOConn.h"
#include <string.h>

BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
return TRUE;
}

extern "C" _declspec(dllexport) int SendCRMservice( char *saleOrder)
{
ns2__MBFRequestHeader header; //定义 header
ns3__saleOrderInformationRequestBody body; //定义 body
ns3__saleOrderInformationRequest request; //定义 request

ns3__saleOrderInformationserviceInformation serviceInfo;//定义 serviceInfo SOA返回详细信息
ns3__saleOrderInformationResponse response; //定义 response

_ns3__saleOrderInformation soapinput; //定义 soap输入信息
_ns3__saleOrderInformationResponse soapoutput; //定义 soap输出信息

//初始化soap
struct soap soap;
soap_init ( &soap );

const char* server = "http://192.168.130.106:9106/SuNingServiceWeb/mb"; //定义生产服务器的URL //20091028a v10.

//给输入变量赋值
header.MBServiceCode = "MBF_IVRCRM_SALEORDERINFORMATION"; //-0-
body.saleOrder = saleOrder; //-1-IVR收销售订单号,送至SOA

request.MbfHeader = &header;
request.MbfBody = &body;
soapinput.input1 = &request;

//输出项--记录到DBtable
char *saleOrdero = new char[256]; //-2-SOA返回销售订单号
char *orderType = new char[256]; //-3-SOA返回服务订类型
char *serviceDate = new char[256]; //-4-SOA返回服务日期
char *serviceTime = new char[256]; //-5-SOA返回服务时间
char *maintenanceRank = new char[256]; //-6-SOA返回安维排程顺序
char *maintenanceTime = new char[256]; //-7-SOA返回安维排程时间
char *workerTel = new char[256]; //-8-SOA返回作业人员电话
char *workerName = new char[256]; //-9-SOA返回作业人员姓名

CTime tm; //定义时间参数
tm = CTime::GetCurrentTime(); //获取系统时间
FILE *fp = fopen("ivrSendCRMservice.txt", "a"); //以添加的方式输出到文件
fprintf(fp,"--------***--------Here is the comparting line--------***--------\n");
fprintf(fp,"[%s] ",tm.Format("%m/%d/%Y %H:%M:%S"));
fprintf(fp," %s, %s; ", header.MBServiceCode,body.saleOrder);
fprintf(fp,"\n");

//调用Webservice
if(soap_call___ns1__saleOrderInformation(&soap,server,NULL,&soapinput,&soapoutput) == SOAP_OK)//0)
{
response = *soapoutput.output1;
int sizeserviceInfo;
sizeserviceInfo= (int) response.__sizeserviceInformation;
serviceInfo = **response.serviceInformation;

strcpy(saleOrdero,serviceInfo.saleOrderCode); //-2-
strcpy(orderType,serviceInfo.serviceOderType); //-3-
strcpy(serviceDate,serviceInfo.serviceDate); //-4-
strcpy(serviceTime,serviceInfo.serviceTime); //-5-
strcpy(maintenanceRank,serviceInfo.planningSequence); //-6-
strcpy(maintenanceTime,serviceInfo.planningTime); //-7-
strcpy(workerTel,serviceInfo.workerTelephone); //-8-
strcpy(workerName,serviceInfo.workerName); //-9-

tm = CTime::GetCurrentTime();
fprintf(fp,"[%s] ",tm.Format("%m/%d/%Y %H:%M:%S"));
fprintf(fp," saleOrdero=%s,orderType=%s;serviceDate=%s,serviceTime=%s;maintenanceRank=%s,maintenanceTime=%s;workerTel=%s,workerName=%s;",saleOrdero,orderType,serviceDate,serviceTime,maintenanceRank,maintenanceTime,workerTel,workerName);
fprintf(fp,"\n");

CString cssaleOrder,cssaleOrdero,csorderType,csserviceDate,csserviceTime,csmaintenanceRank,csmaintenanceTime,csworkerTel,csworkerName,inststr,updstr;
cssaleOrder = saleOrder; //-1-
cssaleOrdero = saleOrdero; //-2-
csorderType = orderType; //-3-
csserviceDate = serviceDate; //-4-
csserviceTime = serviceTime; //-5-
csmaintenanceRank = maintenanceRank; //-6-
csmaintenanceTime = maintenanceTime; //-7-
csworkerTel = workerTel; //-8-
csworkerName = workerName; //-9-
inststr = "19";
updstr = "28";

if(cssaleOrdero != '0')
{
//连接数据库
ADOConn m_AdoConn;

if(m_AdoConn.OnInitADOConn() == 3) //连接数据库不成功
return 3;
else
{
//设置INSERT语句
_bstr_t vSQL;
vSQL = "select * from order_info where saleOrder = '"+cssaleOrder+"' "; //// and orderType = '"+csorderType+"' and serviceDate = '"+csserviceDate+"' and serviceTime = '"+csserviceTime+"' and maintenanceRank = '"+csmaintenanceRank+"' and maintenanceTime = '"+csmaintenanceTime+"' and workerTel = '"+csworkerTel+"' and workerName = '"+csworkerName+"'";
//执行SELETE语句
_RecordsetPtr m_pRecordset;
m_pRecordset = m_AdoConn.GetRecordSet(vSQL);

if(m_pRecordset->adoEOF) //判断数据库中是否有这条记录
{
CTime tm_insert = CTime::GetCurrentTime(); //获取插入时间
CString tm_istr = tm_insert.Format("%Y-%m-%d %H:%M:%S");
vSQL = "INSERT INTO order_info(saleOrder, saleOrdero, orderType, serviceDate, serviceTime, maintenanceRank, maintenanceTime, workerTel, workerName, instime, instid, instbk1, instbk2) VALUES('"+cssaleOrder+"' , '"+cssaleOrdero+"' , '"+csorderType+"' , '"+csserviceDate+"' , '"+csserviceTime+"' , '"+csmaintenanceRank+"' , '"+csmaintenanceTime+"' , '"+csworkerTel+"' , '"+csworkerName+"' , '"+tm_istr+"' , '"+inststr+"' , '""' , '""' )"; //// item-id, 1+8, instime, instid=19, instbk1, instbk2 共14个字段,要insert的为后13个字段。
//执行INSERT语句
m_AdoConn.ExecuteSQL(vSQL);
tm = CTime::GetCurrentTime();
fprintf(fp,"[%s] ",tm.Format("%m/%d/%Y %H:% M:%S"));
fprintf(fp," 插入数据库成功!!");
fprintf(fp,"\n");
fclose(fp); ////////关闭文件
}
else
{
CTime tm_update = CTime::GetCurrentTime(); //获取更新时间
CString tm_ustr = tm_update.Format("%Y-%m-%d %H:%M:%S");
vSQL = "update order_info set saleOrdero = '"+cssaleOrdero+"', orderType = '"+csorderType+"', serviceDate = '"+csserviceDate+"', serviceTime = '"+csserviceTime+"', maintenanceRank = '"+csmaintenanceRank+"', maintenanceTime = '"+csmaintenanceTime+"', workerTel = '"+csworkerTel+"', workerName = '"+csworkerName+"', instime = '"+tm_ustr+"', instid='"+updstr+"' where saleOrder = '"+cssaleOrder+"' ";
m_AdoConn.ExecuteSQL(vSQL);
tm = CTime::GetCurrentTime();
fprintf(fp,"[%s] ",tm.Format("%m/%d/%Y %H:%M:%S"));
fprintf(fp," 更新数据库成功!!");
fprintf(fp,"\n");
fclose(fp); ////////关闭文件
}

//断开与数据库的连接
m_AdoConn.ExitConnect();
}

return 1;
delete []saleOrdero; //-2-
delete []orderType; //-3-
delete []serviceDate; //-4-
delete []serviceTime; //-5-
delete []maintenanceRank; //-6-
delete []maintenanceTime; //-7-
delete []workerTel; //-8-
delete []workerName; //-9-
}
}//web service
else
{
soap_print_fault(&soap, stderr); // display the SOAP fault message on the stderr stream
tm = CTime::GetCurrentTime();
fprintf(fp,"[%s] ",tm.Format("%m/%d/%Y %H:%M:%S"));
fprintf(fp," error:与web service 接口对接失败!");
fprintf(fp,"\n");
fclose(fp); ////////关闭文件
return 2;
// exit(1);
}
//收尾
soap_destroy(&soap); // delete deserialized class instances
soap_end(&soap); // remove deserialized data and clean up
soap_done(&soap); // detach the gSOAP environment }
return 0;
}

贴出一个函数代码……求教各位是否存在问题。

15,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧