Introduction
I program with a ansi-c compile tools named Labwindows/CVI. My OS is Windows 2k advance server. Everyone know that ANSI-C can not use OLE-DB but the Win2k OS support it. So I think I can let the CVI support the OLE-DB through DLL file. And finally I succeeded and here is how.
Details
First Use Wizard Create a MFC DLL project. And then update the stdafx.h file.
#define VC_EXTRALEAN
#include <AFXWIN.H> // MFC core and standard components
#include <AFXEXT.H> // MFC extensions
#include <AFXCVIEW.H>
#include <AFXDISP.H> // MFC Automation classes
#include <AFXDTCTL.H> // MFC support for Internet Explorer
#import "c:\program files\common files\system\ado\msado15.dll" \
no_namespace \
rename ("EOF", "adoEOF")
The last statement can let the project support the ADO ole-db version 2. The class cTestCpp
(sorry , I made a test name for this project) does the main work and the testDll.c does the interface work.
Code Listings
class cTestCpp
{
public:
int Execute(const char *sql,int *AffectedRecord);
int CloseRst(void);
int CloseConn(void);
BOOL IsBof(void);
BOOL IsEof(void);
int GetCount(int *iResult);
int MoveLast(void);
int MoveFirst(void);
int MovePrevious(void);
int Movenext(void);
int openConn(const char *connStr);
void test(void);
int DBConnect(const char *strConn);
int CreateRst(void);
int openRst(const char *sql);
int getCol(const char *colName,int dataType,char *result);
cTestCpp();
virtual ~cTestCpp();
private:
_ConnectionPtr m_pConnection;
_RecordsetPtr pRecordSet;
};
#include "stdafx.h"
#include "cTestCpp.h"
cTestCpp::cTestCpp(){
if (!AfxOleInit())
{
AfxMessageBox("ole Init Error");
return ;
}
CoInitialize(NULL);
}
int cTestCpp::DBConnect(const char *strConn)
{
return 0;
}
cTestCpp::~cTestCpp()
{
CoUninitialize();
}
int cTestCpp::openConn(const char *connStr)
{
try{
HRESULT hr;
hr = m_pConnection.CreateInstance( __uuidof( Connection ) );
if (SUCCEEDED(hr)){
hr = m_pConnection->Open(
_bstr_t(connStr),
_bstr_t(L""),
_bstr_t(L""),
adModeUnknown);
return 0;
}
}
catch (...) {
return -1;
}
return -1;
}
int cTestCpp::CreateRst()
{
HRESULT hr;
hr=pRecordSet.CreateInstance( __uuidof(Recordset));
if(SUCCEEDED(hr)){
return 0;
}
pRecordSet->Release();
return -1;
}
int cTestCpp::openRst(const char *sql)
{
_variant_t vRecsAffected(0L);
_bstr_t bstrQuery(sql);
HRESULT hr;
_variant_t vNull;
vNull.vt = VT_ERROR;
vNull.scode = DISP_E_PARAMNOTFOUND;
try{
hr = pRecordSet.CreateInstance(__uuidof(Recordset));
if (SUCCEEDED(hr))
{
pRecordSet->PutRefActiveConnection(m_pConnection);
hr = pRecordSet->Open(_variant_t(bstrQuery), vNull,
adOpenForwardOnly, adLockOptimistic, adCmdText);
}
}
catch(...){
return -1;
}
return 0;
}
int cTestCpp::getCol(const char *colName,int dataType,char *result)
{
try{
_variant_t ss;
CString s;
ss = pRecordSet->GetCollect(colName);
switch(dataType) {
case INTEGER_TYPE:
s.Format("%d",ss.intVal);
break;
case STRING_TYPE:
s=CString(ss.bstrVal);
break;
case DOUBLE_TYPE:
s.Format("%f",ss.dblVal);
break;
case DATE_TYPE:
s.Format("%s",ss.date);
default:
s="error data type";
}
strcpy(result,(const char*)s);
}
catch(...){
return -1;
}
return 0;
}
int cTestCpp::Movenext()
{
try{
pRecordSet->MoveNext();
}
catch(...){
return -1;
}
return 0;
}
int cTestCpp::MovePrevious()
{
try{
pRecordSet->MovePrevious();
}
catch(...){
return -1;
}
return 0;
}
int cTestCpp::MoveFirst()
{
try{
pRecordSet->MoveFirst();
}
catch(...){
return -1;
}
return 0;
}
int cTestCpp::MoveLast()
{
try{
pRecordSet->MoveLast();
}
catch (...) {
return -1;
}
return 0;
}
int cTestCpp::GetCount(int *iResult)
{
try{
*iResult=pRecordSet->GetRecordCount();
}
catch (...) {
return -1;
}
return 0;
}
BOOL cTestCpp::IsEof(void){
VARIANT_BOOL bl;
try{
bl=pRecordSet->GetadoEOF();
}
catch (...) {
return FALSE;
}
return bl;
}
BOOL cTestCpp::IsBof()
{
VARIANT_BOOL bl;
try{
bl=pRecordSet->GetBOF();
}
catch (...) {
return FALSE;
}
return bl;
}
int cTestCpp::CloseConn()
{
HRESULT hr;
try{
hr=m_pConnection->Close();
m_pConnection.Release();
if(!SUCCEEDED(hr)){
return -1;
}
}
catch (...) {
return -1;
}
return 0;
}
int cTestCpp::CloseRst()
{
HRESULT hr;
try{
hr = pRecordSet->Close();
pRecordSet.Release();
if(!SUCCEEDED(hr)){
return -1;
}
}
catch (...) {
return -1;
}
return 0;
}
int cTestCpp::Execute(const char *sql, int *AffectedRecord)
{
_variant_t vRecsAffected(0L);
_bstr_t bstrQuery(sql);
try{
m_pConnection->Execute(bstrQuery, &vRecsAffected,
adOptionUnspecified);
}
catch (...) {
return -1;
}
*AffectedRecord=vRecsAffected.intVal;
return 0;
}
And the interface code.
#include "stdafx.h"
#include "testDll.h"
#include "cTestCpp.h"
int openConn(const char *connstr){
return test.openConn(connstr);
}
int CreateRst(void){
return test.CreateRst();
}
int openRst(const char *sql){
return test.openRst(sql);
}
int getCol(const char *colName,int dataType,char *result){
return test.getCol(colName,dataType,result);
}
int movenext(){
return test.Movenext();
}
int movePrevious(){
return test.MovePrevious();
}
int moveFirst(){
return test.MoveFirst();
}
int moveLast(){
return test.Movenext();
}
int GetCount(int *iResult){
return test.GetCount(iResult);
}
BOOL IsEof(){
return test.IsEof();
}
BOOL IsBof(){
return test.IsBof();
}
int closeConn(){
return test.CloseConn();
}
int closeRst(){
return test.CloseRst();
}
int Execute(const char *sql, int *AffectedRecord){
return test.Execute(sql,AffectedRecord);
}
In the interface code all parameter is the const char*
, because the ansi code can not support CString
class etc. At last, we update the testDll.def file to export the function.