网站公告列表

  没有公告

加入收藏
设为首页
联系站长
您现在的位置: 网络学院 >> 程序设计 >> VB编程 >> 文章正文
  vb调用VC动态连接库的总结            【字体:
vb调用VC动态连接库的总结
作者:佚名    文章来源:不详    点击数:    更新时间:2007-8-26    
 
第一 VB中调用VC++开发的DLL
 
再谈在VB中调用VC++开发的DLL
 
 
 
 
 
 
[ 来源:xue5.com | 作者:学网 | 时间:2005-5-8 ]
[学网]:http://www.xue5.com
 
 

 共有 133[学网]的网友和你一起阅读过:再谈在VB中调用VC++开发的DLL

 
 
 
 
 
 
 
 
【学网教程
  近日开发一个程序,用到动态链接库,在VB中调用时遇到了一些问题。
正在装载数据……
我查了一些资料,也看了一下
CSDN上的文章,感觉这些文章对在VB中调用VC++开发的DLL这一问题阐述得不够详细。因此在我的问题得到解决之余,特为初接触DLL的朋友们写下这篇文章。
本文中关于调用约定的解决方法,也适用于解决其它编程语言之间DLL调用的兼容问题。
 
  ①关于DLL的创建与调用
  使用VC++的向导即可。具体操作如下:打开菜单“File\New”→选择“Projects\Win32 Dynamic-Link Library”→选择“A simple DLL project”即可。这时系统会自动生成3个文件:*.cppstdafx.cppstdafx.h
  之后将入口函数DLLMain()补充完整,再添加你自定义的函数的代码。如果你自定义的函数很多,可以将这些函数的声明部分统一写入一个头文件中。再在.cpp文件首部用“#include”语句引入这个头文件。注意函数声明前要加上“__declspec(dllexport)”。
  (如果你建DLL时选择的是第三种类型(加入示例代码),则在函数声明及定义前都要加上系统定义的宏“*_API”。)
  在VB中用如下语句声明:“Declare Function 函数名Lib "完整路径\文件名.dll" [Alias "函数别名"] (ByVal 变量1 As 类型1, ByVal 变量2 As 类型2,) As 类型3,与调用API函数类似。
  注意:若在窗体代码的“通用”部分使用,“Declare”前要加“Private”;若在Moudle中使用,“Declare”前要加“Public”。若将DLL文件放在“\Windows\System”或“\WinNT\System32”目录下,“Lib”后只写出DLL主文件名即可。
具体的实例代码见④(修正后的,可直接运行)。 
 
  ②关于入口点
  如上编写Cipher.dll,运行,出现错误信息“找不到DLL入口点(Error 53)”。出现这一错误的原因是C++编译器在编译时对函数名Encrypt作了修改。打开快速查看程序(D:\WINNT\System32\Viewers\QuikView.exe,Cipher.dll拖入查看窗口,找到字段?Encrypt@@YAHHH@Z,发现函数名被加了一串字符。
  解决方法有二。第一,直接在VB声明中将“?Encrypt@@Y AHHH@Z”作为别名放在“Alias”后即可;第二,在Cipher.dll代码中在语句“__declspec(dllexport) int __stdcall Encrypt(int p, int k); ”前加上“extern "C" ”,编译后,用QuikView查看,函数名变为“_Encrypt”,之后再在VB声明中做相应调整即可。
  (对于使用宏的DLL,在“#define”语句中,对宏“Cipher_API”的替换值做更改即可。)
进行了③的更改后,程序又找不到入口点了。再用QuikView查看,发现函数名变为_Encrypt@8”。还有解决方法。在Cipher.dll工程中添加一个文本文件,命名为“Cipher.def,添加代码如④。编译后再用QuikView查看,函数名变回“Encrypt”,在VB中调用,运行正常。
 
  ③关于调用约定
  采用②中第二种解决方法,运行,出现错误信息“DLL调用约定错误(Error 49)”。原因是调用约定共有4种方式:__fastcall__pascal__stdcall__cdeclVC++默认调用方式为__cdecl,而VB默认调用方式则为__stdcall。解决方法是,更改代码如下(限定调用方式):
  extern “C”__declspec(dllexport)int__stdcall Encrypt(int p, int k);
  …………
  int__stdcall Encrypt(int p, int k)
    {
           int c = p+k;
           return c;
    }
 
  ④源代码
Cipher.dll
 Cipher.cpp
    //引入预编译头文件
  #include “stdafx.h”
    //声明我的函数
extern “C”__declspec(dllexport)int __stdcall Encrypt( int p, int k );
    //DLL入口函数
       BOOLAPIENTRY DllMain( HANDLE hModule,
                                                   DWORD ul_reason_for_call,
                                                   LPVOID lpReserved
                                                  )
       {
           switch( ul_reason_for_call )
           {
             case DLL_PROCESS_ATTACH:
             case DLL_THREAD_ATTACH:
             case DLL_THREAD_DETACH:
             case DLL_PROCESS_DETACH:
                     break;
           }
           return TRUE;
       }
 
       //我的函数
        int __stdcall Encrypt ( int p, int k )
        {
            int c = p + k ;
            return c ;
        }
 
 Cipher.def
  LIBRARY Cipher
  EXPORTS Encrypt
 
编译后,将Cipher.dll复制到“D:\WINNT\System32目录。
VB中调用:
  Option Explicit
Private Declare Function Encrypt Lib “Cipher” _
(ByVal p As Long, ByVal k As Long) As Long
        Private Sub Form_Load()
  Dimc As Long
  c = Encrypt(24, 8)
  Text1.Text = c
  End Sub
 
 
 
 
 
 
 
VBVC混合编程
 
编号:QA000072
建立日期: 1998114最后修改日期:200128
所属类别:
Visual Basic - 其他方面

C/C++ - 其他方面
吴强:
    
本人初学VC5,现与几个同事合作开发单位课题(WIN95应用程序)。我负责数据计算,并将计算结果以图形的方式显示。由于计算的复杂性,也为提高速度,我准备用VC5编程,但伙伴们却用VB5开发主界面。请指教:我如何从VB5程序中获取数据(数据量很大,且对传输速度要求很高),我又如何接管伙伴用VB5生成的窗口,在不开新窗口,不破坏主界面的前提下,将图形输出到视窗的指定位置,并进行一系列的图形操作;我应生成什么类型的文件,伙伴在VB5中如何调用我的程序?能否举例说明?
回答:
    一般来说,VBVC共同编程3种方式:一种是VC生成DLL,在VB中调用DLL;一种是VC生成ActiveX控件(.ocx),在VB中插入;还有一种是在VC中生成ActiveX Automation服务器,在VB中调用。相对而言,第一种方法对VC编程者的要求最低,但要求你的伙伴进行配合,我推荐这种方法。
    
先说说VC++的编程。首先在VC++中生成Win32 DLL工程。在这个工程中添加几个函数供VB用户调用。一个DLL中的函数要想被VB调用,必须满足两个条件:一是调用方式为stdcall,另一个是必须是export的。要做到第一条,只须在函数声明前加上__stdcall关键字。如:
    short __stdcall sample(short nLen, short *buffer)
    
要做到第二条,需要在*.def文件中加上如下的几行:
    EXPORTS
     sample @1
    
这里的sample是你要在VB中调用的函数名,@1表示该函数在DLL中的编号,每个函数都不一样。注意这里的函数名是区分大小写的。至于你说的需要传递大量数据,可以这样做,在VB中用一个数组存放数据,然后将该数组的大小和地址传给VC(至于如何在VB中编程我会在下面介绍)。就象上面的例子,nLen是数组大小,buffer是数组地址,有了这两条,你可以象使用VC的数组一样进行处理了。至于输出图形,可以生成WMFBMP格式,让VB调用。不过,我认为也可以直接输出到视窗,只要VB将窗口的句柄hWndhDC以及视窗的绘图位置(VBVC采用的坐标系必须一致才行)传给VC就行了。而VBAutoRedraw属性必须为False,在Paint事件中调用VC的绘图程序。
    
再谈谈VB的编程。VB调用DLL的方法和调用Windows API的方法是一样的,一般在VB的书中有介绍。对于上面一个例子,先要声明VC函数:
    Declare Function sample Lib "mydll.dll" (ByVal nLen As Integer, buffer As Integer) As Integer
    
这里mydll.dll是你的dll的名字。你可能已经注意到了两个参数的声明有所不同,第一个参数加上了ByVal。规则是这样的:如果在VC中某个参数声明为指针和数组,就不加ByVal,否则都要加上ByVal。在VB中调用这个函数采用这样的语法:
    sample 10, a(0)
    
这里的a()数组是用来存放数据的,10为数组长度,这里的第二个参数不能a(),而必须是要传递的数据中的第一个。这是VB编程的关键。
    
下面在说几个可能遇到的问题。一个问题是VB可能报告找不到dll,你可以把dll放到system目录下,并确保VBDeclare语句正确。另一个问题是VB报告找不到需要的函数,这通常是因为在VC*.def文件没设置。第三种情况是VB告诉不能进行转换,这可能是在VC中没有加上__stdcall关键字,也可能是VBVC的参数类型不一致,注意在VCint4个字节(相当于VBLong),而VBInteger只有2个字节。必须保证VBVC的参数个数相同,所占字节数也一致。最后一个要注意的问题是VC中绝对不能出现数组越界的情况,否则会导致VB程序崩溃。
    
总的来说,你和你的伙伴需要一些时间来进行协调和摸索,但这种方法绝对可行,也不难掌握。
    
    
相关问题:
    QA000981 "VC写的程序中调用用VB写的函数和方法"
    
    
石雨的意见:
    
您回答了在VB中调用DLL文件中的函数问题,如果我想在VB中调用DLL文件中所定义的类,那么该如何做呢?拜托!!!
    
答:如果你说的DLL的类是Automation方式的,只要在VB引用对话框中添加该DLL就可以。但是如果该类是在VC++中以dllexport形式定义的,则除了VC++,其他语言都无法调用。如果你想让VBDeclare的方式调用C++的类,你需要改写DLL为普通C语言函数的形式,DLL内部可以使用类,但对外的调用接口必须是简单的函数。
    
     spencer yang
的意见:
    
具体范例,请到纪文和网站 VB入门网
    http://www.vbguide.com.tw/webback.asp
    
看看「个个击破」单元中的
    ---------------------------------------
    
问题389 如何解一元二次方程式 (Quadratic Equation of One Variable)
    ---------------------------------------
    1)
请先阅读前言之说明。
    2)
若适合现状者可以下载范例,研究程序写法。
    3)
参考其标示之『参考资料』及『网络资源』。
 
 
 
VB中调用DLL显示Bad DLL calling convention
编号:
QA001383
 
 
建立日期:
1999722
最后修改日期:
2005822
所属类别:
Visual Basic - 错误信息
 
 
    使用的操作系统:Win95/98
    
使用的编程工具:VB6VC6
    
遇到的问题 :鉴于VB的速度和在位操作方面的不足,我不得不用VC来编写一个DLL来实现一些功能。可在VB中调用是总是说"Bad DLL calling convention"
    
VC中的源程序如下:(一个极其简单的试验用的函数)
    #define DllExport __declspec( dllexport )
    
    DllExport int Gen(int a)
    {
     return 2;
    }
    
    DllExport int Gen2(void)
    {
     return 1;
    }
    
    
VB中声明如下:
    Declare Function Gen Lib "Paper.dll" (ByVal a As Integer) As Integer
    Declare Function Gen2 Lib "Paper.dll" () As Integer
    
调用程序:
    
    Dim SS As Integer
     SS = 1
     SS= Gen2() //
调用成功
     SS = Gen(SS) //
一到这就报错,?????????(Stone)
 
 
    产生这条错误有几个原因:
    1
、参数声明错误,C语言的int型对应为VBLong型。在VB中声明如下:
     Declare Function Gen Lib "Paper.dll" (ByVal a As long) As long
     Declare Function Gen2 Lib "Paper.dll" () As long
    2
DLL中的函数没有使用stdcall调用方式。
    VB
的错误信息指的是第二条原因。你定义的调用方式为__declspec,而VB要求必须是stdcall方式,这对没有参数的函数影响不大,但对有参数的函数有影响。你可以参照QA000072 "VBVC混合编程"修改你的VC程序。
 
第二 调用中注意
VB定义中注意:
函数如果有返回值定义为FUNCTION
如果没有返回值定义为SUB
否则也会报Bad DLL calling convention错误
 
一个成功的例子
WordCutDllProject.cpp
// WordCutDllProject.cpp : Defines the initialization routines for the DLL.
//
 
#include "stdafx.h"
#include "WordCutDllProject.h"
 
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
 
extern "C" void _stdcall HelloWorld();
 
//
//     Note!
//
//            If this DLL is dynamically linked against the MFC
//            DLLs, any functions exported from this DLL which
//            call into MFC must have the AFX_MANAGE_STATE macro
//            added at the very beginning of the function.
//
//            For example:
//
//            extern "C" BOOL PASCAL EXPORT ExportedFunction()
//            {
//                   AFX_MANAGE_STATE(AfxGetStaticModuleState());
//                   // normal function body here
//            }
//
//            It is very important that this macro appear in each
//            function, prior to any calls into MFC. This means that
//            it must appear as the first statement within the
//            function, even before any object variable declarations
//            as their constructors may generate calls into the MFC
//            DLL.
//
//            Please see MFC Technical Notes 33 and 58 for additional
//            details.
//
 
/////////////////////////////////////////////////////////////////////////////
// CWordCutDllProjectApp
 
BEGIN_MESSAGE_MAP(CWordCutDllProjectApp, CWinApp)
       //{{AFX_MSG_MAP(CWordCutDllProjectApp)
              // NOTE - the ClassWizard will add and remove mapping macros here.
              //    DO NOT EDIT what you see in these blocks of generated code!
       //}}AFX_MSG_MAP
END_MESSAGE_MAP()
 
/////////////////////////////////////////////////////////////////////////////
// CWordCutDllProjectApp construction
 
CWordCutDllProjectApp::CWordCutDllProjectApp()
{
       // TODO: add construction code here,
       // Place all significant initialization in InitInstance
}
 
void __stdcall HelloWorld()
{
       AfxMessageBox("HelloWorld!");
}
/////////////////////////////////////////////////////////////////////////////
// The one and only CWordCutDllProjectApp object
 
CWordCutDllProjectApp theApp;
 
 
WordCutDllProject.def
; WordCutDllProject.def : Declares the module parameters for the DLL.
 
LIBRARY      "WordCutDllProject"
DESCRIPTION 'WordCutDllProject Windows Dynamic Link Library'
 
EXPORTS
    ; Explicit exports can go here
 
       HelloWorld    @1
Vb 代码
Private Declare Sub HelloWorld Lib "D:\VBPROJECT\GeoCodingBatchMatchProject\GeoCodingBatchMatchProject\GeoCodingBatchMatchProject\bin\Debug\WordCutDllProject.dll" ()
 
Private Sub Command1_Click()
    HelloWorld
End Sub
 
 
VBVC通信初探(二)
】【打印】【加入收藏】【关闭收藏到新浪ViVi】【收藏到365KEY浏览字号:

日期:2005-06-23人气: 560 出处:CSDN 作者: eliner

     在通过DLL实现VBVC的过程中,一般的简单的通信过程很容易建立。在《VBVC通信初探(一)》中,我已经把基本的通信过程给描述了一下,但是,有些时候,事件的发展并不总是一帆风顺的,当我们以为可以轻松的实现VBVC的通信的时候,就经常发生这样的情况,还是先看看例子再说。
 
VC中的程序:
extern "C" _declspec(dllexport) bool ReadString(LPCSTR lpString)
 {
        char str[]="Hello World!";
        if(strcmp(lpString,str)==0)
              return true ;
        else
              return false ;
}
 
VB中的程序:
Private Declare Function ReadString Lib "commication.dll" (ByVal send As String) as Boolean
……………………
Dim result As Boolean
Dim send As String
 
send =”Hello,World!”
 
result = ReadString(send)
 
If result Then
 MsgBox "The return value is 'true'"
Else
 MsgBox "The return value is 'false'"
End If
 
        可以上机运行这个程序,一样的,实现了通信的功能,但是这里有几个地方是应该引起我们注意的,首先就是在VB中声明传递的字符串参数的时候,按照常规的理解,好像应该是传递地址才对,但是这里使用的方法是ByVal,为什么?原因比较复杂,但是可以简单的来分析一下,在VB中,使用的字符串实际上是BSTR类型的,它是由自动化(以前被称为OLE Automation)定义的数据类型。一个BSTR由头部和字符串组成,头部包含了字符串的长度信息,字符串中可以包含嵌入的null值。大部分的BSTR Unicode的,即每个字符需要两个字节。BSTR通常以两字节的两个null字符结束。下图表示了一个BSTR类型的字符串。

  (前缀)aTest\0
  头部BSTR指向数据的第一个字节

  另一方面,大部分的DLL过程(包括Windows 95 API中的所有过程)使用LPSTR类型字符串,这是指向标准的以null结束的C语言字符串的指针,它也被称为ASCIIZ字符串。LPSTR 没有前缀。下图显示了一个指向ASCIIZ字符串的LPSTR

  aTest\0

  LPSTR指向一个以null结尾的字符串数据的第一个字节

   
通过上面的简单分析,不难看出,如果均以地址的方式传递参数的话,那么VB中的字符串将会包含更多德内容,所以,在这里,就必须以值的方式传递参数,虽然是以值得方式传递的参数,但是在DLL中还是能够识别得出来这是一个字符串,并且将它转换成为字符串。
 
    好了,上面的这个问题我们已经解决了,但是,我们现在的胃口肯定也变得慢慢得有点大了,既然我们已经实现了能够从VB中把字符串传给DLL,那么,又应该怎么样才能够从DLL中把字符串返回给VB程序呢?通过上面的分析我们知道,因为两者之间使用的字符不是相同的格式的,所以简单的传输肯定是不行的,那么应该如何解决呢?其实,在明白了上面我们分析的道理后,再来解决这个问题就太easy了,只需要把传回的字符串进行一次转换就可以了,是的,下面就给出这个实例,注意的黑体部分就可以了。
 
VC中的程序:
extern "C" _declspec(dllexport) BSTR ReadString(LPCSTR lpString)
 {
        char str="Hello ,World!";
        if(strcmp(lpString,str)==0)
                     return SysAllocString((BSTR)str);
        else
               return SysAllocString((BSTR)lpString);
 }
 
VB中的程序:
Private Declare Function ReadString Lib "commication.dll" (ByVal send As String) as String
……………………
Dim result As String
Dim send As String
 
send =”Hello,World!”
 
result = ReadString(send)
 
MsgBox result
 
为了继续学习下去,我一定会继续完成这一系列的文章,同时也希望可以看到愿意一起学习这方面的知识的朋友给我提意见,与我联系,共同进步!
 
 
第三 VB。NET中程序的退出
触发关闭窗口:
Process.GetCurrentProcess().CloseMainWindow()
当窗口关闭后无法关闭进程,在MainForm_FormClosed事件中强制关闭进程
       Process.GetCurrentProcess().Close()
        If Not Process.GetCurrentProcess().HasExited Then
            Process.GetCurrentProcess().Kill()
        End If
 
 
第四 关于dll生成的问题
 
在发布打包时一定要用release方式(不能是debug模式)生成的dll,否则在没有vc开发环境下,运行是有问题的。
报:找不到指定的模块(Exception from HRESULT:0X8007007E异常
 


本文来源:http://blog.csdn.net/strong_chenfei/archive/2007/08/22/1753988.aspx
站内文章搜索 高级搜索
文章录入:admin    责任编辑:admin 
  • 上一篇文章:

  • 下一篇文章:
  • 发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口