VB调用VC写的DLL有感(纪念我这逝去的一周)

0 篇文章 0 订阅

好久没有在空间写点东西了,其实自己写的也乱七八糟,但是很庆幸终于把这个问题解决了,于是就随便记录下这不容易。把自己的快乐与大家分享,望大家提出宝贵意见。言有不尽,大家担待, 言归正传,现在开始。
首先向大家介绍该程序的目的:由于大型数据采集中vb采集不准确,定时器延时等原因造成不精确,于是打算做成DLL可能使数据采集更加准确,于是编写该DLL文件,介绍下:首先传感器将摩擦力或者加载力转化为电信号通过信号放大,通ISA7012卡输入,同过ISA7012DLL.dll文件里面的函数将获取传感器的值。
 
 
下面是我的工程的步骤:
1.文件--新建  新建一个 Win32 Dynamic-Link Library 的工程(在我的VC里面是倒数第二个),工程名称7012DLL,当然你可以根据你的需要任意填写 , 在向导中选择空的工程
2.文件--新建  新建三个文件 7012DLL.cpp(C++代码文件)
                           7012DLL.h(C++头文件)
                           7012DLL.def(模块定义文件,这个文件我是新建的文本文件,在文件名的地方直接写的7012DLL.def,当然你也可以在菜单 工程--增加到工程--文件 处添加也可以)
3.代码
7012DLL.h:
#ifdef __cplusplus
extern "C" {
#endif
__stdcall double  CALLBACK Compare (int, int) ;   //测试使用
__stdcall  CALLBACK Friction ();  //摩擦力
__stdcall  CALLBACK Load ();    //加载力
#ifdef __cplusplus
}
#endif
7012DLL.cpp:
 #include  <windows.h>
#include "7012Demo.h"
#include "Isa7012.h"
#pragma comment(lib, "ISA7012DLL.lib")
BOOL IsIniSuccess = FALSE ;
BOOL Ini7012(DWORD hwnd)
{
 AD7012_WINCTRL_STRUCT ddd;
 memset( &ddd, 0, sizeof(AD7012_WINCTRL_STRUCT) );
 ddd.m_ADType = 1;
 ddd.m_BufferBlock = 4;
ddd.m_ClkSrc = 0;
 ddd.m_EndChn = 15;
 ddd.m_hWnd = hwnd;
 ddd.m_StartChn = 0;
 ddd.m_StartType = 0;
 ddd.m_Timer0Val = 200;
 ddd.m_Timer1Val = 20;
 ddd.m_Timer2Val = 20;

 if ( Isa7012_Open(0) )
 {
  //设备已成功打开
 }
 else
 {
  return FALSE;
 }
 if ( Isa7012_IsOpen(0) )
 {
  //打开Isa7012
 }
 else
 {
  return FALSE;
}
 if ( Isa7012_ADCtrl(0 , &ddd))
 {
  //初始化正确
 }
 else
 {
  return FALSE;
 }
 Isa7012_StartAD(0);
 return TRUE;
}

int WINAPI DllMain (HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved)
{
     return TRUE ;
}    
                                            //DllMain()函数可以不要
double __stdcall  CALLBACK Compare (double a,double b)   //如果写成__stdcall double  CALLBACK Compare (double a,double b)VC默认函数返回值为int型(一定要注意啊 就为此我修改了两三天程序)
{
if(a>=b)
             return a;
        else
             return b;
};
double __stdcall  CALLBACK Friction (DWORD hwnd)
{
 if ( !IsIniSuccess )
  {
   if (Ini7012(hwnd))
   {
    IsIniSuccess = TRUE ;
  
   }
   else
   {
    IsIniSuccess = FALSE ;
    return 100;
   }
  }
  int x =0;
double volL = 0.0;
  WORD dddd;
  if(!Isa7012_SoftADGetVal(0,4,&dddd))
  {
   return -50;
  }
  x = dddd & 0xFFF;
  //x = double(x);
  volL=((double(x) / 4095 * 20 - 3) * 100 / 15);
 return volL;
};
double __stdcall  CALLBACK Load (DWORD hwnd)   //函数定义
{
 if ( !IsIniSuccess )
  {
   if (Ini7012(hwnd))
   {
    IsIniSuccess = TRUE ;
  
   }
   else
   {
    IsIniSuccess = FALSE ;
    return 100;
}
  }
  double vol = 0.0;
  int x = 0;
  WORD ddd;
  if( !Isa7012_SoftADGetVal(0,2,&ddd))
  {
   return -60;
  }
  x = ddd & 0xFFF;
  vol=((double(x) / 4095 * 20 - 3) * 300 / 15);
 return vol;
};
 
TextDll.def:
#ifdef __cplusplus
extern "C" {
#endif
__stdcall double  CALLBACK Compare (int, int) ;
__stdcall  CALLBACK Friction ();
__stdcall  CALLBACK Load ();
#ifdef __cplusplus
}
#endif
ISA7012.h
#ifndef _PCI_7012_INCLUDE_DLLLIB
#define _PCI_7012_INCLUDE_DLLLIB
#define  CLK_2M  0
#define  CLK_125K 1
#define  CLK_EX  2
#define  IN_GATE  0 //内门控
#define  EX_GATE  1 //外门控
#define  CT_GATE  2 //精密时段控制门控
#define WORK_TYPE_CONTINUE  0  //8254A-0连续发生中断
#define WORK_TYPE_STOPALL  1  //8254A-0发生中断停止全部计数
#define WORK_TYPE_STOPCNT  2  //8254A-0对发生计数器中断的停止该计数器计数
#define COUNT8254_TYPE_0  0x0  //计数方式0 0000
#define COUNT8254_TYPE_1  0x2  //计数方式1 0010
#define COUNT8254_TYPE_2  0x4  //计数方式2 0100
#define COUNT8254_TYPE_3  0x6  //计数方式3 0110
#define COUNT8254_TYPE_4  0x8  //计数方式4 1000
#define COUNT8254_TYPE_5  0xc  //计数方式5 1010
#define COUNT8254_CODE_BIN  0x0  //二进制计数
#define COUNT8254_CODE_BCD  0x1  //BCD(十)计数
typedef struct _AD7012_WINCTRL_STRUCT {
 WORD m_ADType;  //触发方式
 //程序触发/定时触发/外触发
 WORD m_StartType; //定时器启动方式
       //内部门控/外部门控/定时器2间歇门控
 WORD m_StartChn;  //起始AD通道号
 WORD m_EndChn;  //结束AD通道号
 WORD m_Timer0Val; //定时器0预置值
 WORD m_Timer1Val; //定时器1预置值
 WORD m_Timer2Val; //定时器2预置值
 WORD m_ClkSrc;       //定时器时钟源
       //定时器使用内部时钟/外部时钟
 WORD m_BufferBlock; //缓冲区长度=m_BufferBlock*512 WORD
       //需要缓冲数据的长度
       //中断方式时为置事件时,到达半满中断的次数
 //WORD m_IntFlag;  //是否产生中断
 WORD m_TransFlag;      //是否使用fifo半满中断传递数据
 DWORD m_hWnd;         //接收消息的OCX窗口
                         //使用中断必须设置
}AD7012_WINCTRL_STRUCT,*PAD7012_WINCTRL_STRUCT;
typedef struct _AD7012_CTRL_STRUCT {
 WORD m_ADType;  //触发方式
       //程序触发/定时出发/外触发
 WORD m_StartType; //定时器启动方式
       //内部门控/外部门控/定时器2间歇门控
 WORD m_StartChn;  //起始AD通道号
 WORD m_EndChn;  //结束AD通道号
 WORD m_Timer0Val; //定时器0预置值
 WORD m_Timer1Val; //定时器1预置值
 WORD m_Timer2Val; //定时器2预置值
 WORD m_ClkSrc;       //定时器时钟源
       //定时器使用内部时钟/外部时钟
 WORD m_BufferBlock; //缓 冲区长度=m_BufferBlock*512 WORD
       //需要缓冲数据的长度,最小值为3
       //FIFO中断方式时为置事件时,到达半满中断的次数
// WORD m_TransFlag; //是否使用FIFO传递数据
 DWORD m_hEvent;       //中断外部事件句柄
                         //使用中断必须设置的中断事件传输局柄
       //=NULL 使用DLL内部事件???
}AD7012_CTRL_STRUCT,*PAD7012_CTRL_STRUCT;
extern BOOL _stdcall  Isa7012_IsOpen(int mDev);
extern BOOL _stdcall  Isa7012_Open(int mDev);
extern BOOL _stdcall  Isa7012_Close(int  mDev);
extern BOOL _stdcall  Isa7012_GetVersion(int  mDev,char *pVersion);
extern BOOL _stdcall  Isa7012_WriteIO(int  mDev,WORD mVal);
extern BOOL _stdcall  Isa7012_ReadIO(int  mDev,WORD *pVal);
extern BOOL _stdcall  Isa7012_WriteIOByte(int  mDev,int Chn,BYTE mVal);
extern BOOL _stdcall  Isa7012_ReadIOByte(int  mDev,int Chn,BYTE *pVal);
extern BYTE _stdcall  Isa7012_LabReadIOByte(int  mDev,int Chn);
extern BOOL _stdcall  Isa7012_InitTimer0(int  mDev,DWORD mType,WORD mVal,BOOL mIntFlag,HWND mWnd);
extern BOOL _stdcall  Isa7012_InitTimer0Ex(int  mDev,DWORD mType,WORD mVal,BOOL mIntFlag,HANDLE mEvent);
extern BOOL _stdcall  Isa7012_StartTimer0(int  mDev);
extern BOOL _stdcall  Isa7012_ReadTimer0(int  mDev,WORD *pVal);
extern BOOL _stdcall  Isa7012_StopTimer0(int  mDev);
extern WORD _stdcall  Isa7012_LabReadTimer0(int  mDev);
extern BOOL _stdcall  Isa7012_SoftADSetChn(int  mDev,DWORD mChn);
extern BOOL _stdcall  Isa7012_SoftADStart(int  mDev);
extern BOOL _stdcall  Isa7012_SoftADRead(int  mDev,WORD *pVal);
extern BOOL _stdcall  Isa7012_SoftADGetVal(int  mDev,DWORD mChn,WORD *pVal);
extern BOOL _stdcall  Isa7012_ADCtrlEx(int  mDev,PAD7012_CTRL_STRUCT pCtrlStru);
extern BOOL _stdcall  Isa7012_ADCtrl(int  mDev,PAD7012_WINCTRL_STRUCT pCtrlStru);
extern DWORD _stdcall  Isa7012_ReadADBuffer(int  mDev,unsigned short int *pADVal,DWORD mDataLength);
        //-1 错误读出
        //0 正确读出 但没有数据
        //正数 读出的数量
extern BOOL _stdcall  Isa7012_StopAD(int  mDev);
extern BOOL _stdcall  Isa7012_StartAD(int  mDev);
extern BOOL _stdcall  Isa7012_ReadStatus(int  mDev,BYTE *pVal);
extern BYTE _stdcall  Isa7012_LabReadStatus(int  mDev);
extern BOOL _stdcall  Isa7012_TimerB_Set0(int  mDev,DWORD mType,WORD mVal0,DWORD mClk,DWORD mGate);
extern BOOL _stdcall  Isa7012_TimerB_Start0(int  mDev);
extern BOOL _stdcall  Isa7012_TimerB_Read0(int  mDev,WORD *pVal0);
extern BOOL _stdcall  Isa7012_TimerB_Stop0(int  mDev);
extern WORD _stdcall  Isa7012_LabTimerB_Read0(int  mDev);
extern BOOL _stdcall  Isa7012_SetTimerAB(int  mDev,WORD mValA1,WORD mValA2,WORD mValB1,WORD mValB2,HANDLE mEvent);
extern BOOL _stdcall  Isa7012_StartTimerAB(int  mDev);
extern BOOL _stdcall  Isa7012_StopTimerAB(int  mDev);
extern BOOL _stdcall  Isa7012_ReadTimerAB(int  mDev,WORD *pValA1,WORD *pValA2,WORD *pValB1,WORD *pValB2);
#endif
好了,下面就是编译了,你可以在 组建菜单里使用组建,也可以使用直接按F7,更可以使用执行菜单,效果都是完成编译的需要~
 编译完成后我们就可以测试一下,为了方便我把编译后的7012DLL放到了与exe同级的文件夹下面,当然也可以扔到SYSTEM32下面,那样声明的时候就不用写路径了,看VB测试代码:
Private Declare Function Friction Lib "7012Demo.dll" _
      (ByVal hwnd As Long) As Double '
      Private Declare Function Load Lib "7012Demo.dll" _
      (ByVal hwnd As Long) As Double '
Private Declare Function Compare Lib "7012Demo.dll" _
(ByVal CompareA As long, ByVal CompareB As long) As Integer
Private Sub Command1_Click()
Dim a As Integer
a = Compare(1.8, 2.6)
MsgBox a
End Sub
Private Sub TmrDraw_Timer(ByVal Milliseconds As Long)
    Dim F As double
    Dim sngLoad  As double   
    F = Friction(Me.hwnd) 
    sngLoad = Load(Me.hwnd)
    Text1.Text = Format(F, "0.000")   '摩擦力
    Text2.Text = Format(sngLoad, "0.000")
End Sub
程序退出千万要记得释放资源,关于这点我会在以后给大家说的。
为此我把一些网络资料放到这儿:

和编写一般的DLL方法相同,需要注意以下两点:
  (1)调用约定
  C函数有_stdcall、_cdecl、_fastcall等多种调用约定,调用约定用来说明函数参数的压栈顺序和由谁(函数自身还是调用者)来修改堆栈。关于调用约定的详细说明,请参考我转载的另一篇文章。
  编写供PB调用DLL,请使用_stdcall调用约定,如下所示:
  extern "C" _declspec(dllexport) int _stdcall GetInt(char* name)
  {
  ...
  }
(2)def文件
  在VC++中,如果生成DLL可以不使用.def文件,只需要在VC++的函数定义前加__declspec(dllexport)修饰就可以了。生成的DLL VC++用户可以直接使用,但PB、VB等用户使用会遇到函数名转换的问题。因为VC++对于__declspec(dllexport)声明的函数会进行名称转换,如下面的函数:
  __declspec(dllexport) int _stdcall GetStr()
  编译后会转换为 GetStr@0,这样在PB、VB中声明函数时应该声明GetStr@0
  如果函数带有参数,转换后的函数名将更加复杂,这使PB、VB用户使用起来很不方便。在def文件中由EXPORT输出函数可解决这个问题。
  如dll要输出如下两个函数:
  extern "C" _declspec(dllexport) int _stdcall GetInt(char* name);
  extern "C" _declspec(dllexport) char* _stdcall GetStr(int id);
  则def文件书写如下(TEST为工程名):
  LIBRARY "TEST"
  DESCRIPTION 'TEST Windows Dynamic Link Library'
  EXPORTS
   ; Explicit exports can go here
  GetInt @1
  GetStr @2
  编译生成DLL后,在PB中要调用GetStr函数,只需做如下声明即可:
  function string GetStr(int a) library("TEST.dll");
  注意,如果您建的是Win32 Dynamic-Link Library 工程,def文件需要自己创建,然后把它加入工程,def文件名需和工程名相同。如您的工程名为test,则创建test.def。
DllMain ()说明:
每一个DLL必须有一个入口点,DllMain是一个缺省的入口函数。DllMain负责初始化(Initialization)和结束(Termination)工作,每当一个新的进程或者该进程的新的线程访问DLL时,或者访问DLL的每一个进程或者线程不再使用DLL或者结束时,都会调用DllMain。但是,使用TerminateProcess或TerminateThread结束进程或者线程,不会调用DllMain。
 
 如何用VC编写供delphi、PB等调用的DLL
extern "C" _declspec(dllexport) int _stdcall GetInt(char* name);
extern "C" _declspec(dllexport) char* _stdcall GetStr(int id);
__declspec (dllexport):这是关键,它标志着这个这个函数将成为对外的接口。(以下是我在网上下载的dllexport、dllimport、_declspec的一些说明):
使用包含在DLL的函数,必须将其导入。导入操作时通过dllimport来完成的,dllexport和dllimport都是vc(visual C++)和bc(Borland C++)所支持的扩展的关键字。但是dllexport和dllimport关键字不能被自身所使用,因此它的前面必须有另一个扩展关键字__declspec。通用格式如下:__declspec(specifier)其中specifier是存储类标示符。对于DLL,specifier将是dllexport和dllimport。而且为了简化说明导入和导出函数的语句,用一个宏名来代替__declspec.在此程序中,使用的是DllExport。如果用户的DLL被编译成一个C++程序,而且希望C程序也能使用它,就需要增加“C”的连接说明。#define DllExport extern "C"__declspec(dllexport),这样就避免了标准C++命名损坏。(当然,如果读者正在编译的是C程序,就不要加入extern “C”,因为不需要它,而且编译器也不接受它)。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值