分享

VB调用C编写的DLL的分析

 华灯初放l 2013-02-28
有两个部分说明了每种技术: C Visual Basic 代码中的声明函数和 C 的内部函数过程的数据被传递、 修改或发回。

将一个字符串传递到 C DLL

声明用于 C 函数必须使用 c ByVal 来接收一个字符串。C 函数通常需要结束"空值字符"(二进制零) 的字符串。当声明函数的参数使用 ByVal 时,这会告诉 Visual Basic 以空值终止的字符串形式传递字符串。因此,声明如下所示:
   Declare Sub passOneString Lib "mydll.dll" (ByVal lpszBuf As String)
实际的 C 函数如下所示:
   void __far __pascal __export passOneString(char __far *lpszBuf)
实际的内部机制的 C 函数是简单而它将接收到的参数作为标准 C 字符串。

注意: 两个"pascal"和"远"是编译器特定的关键字所允许的 ANSI 标准。它们应具有适当数量的下划线,若要将它们放在适当的名称空间。最新的编译器,严格遵循标准并说出您需要两个下划线 (但允许较少的向后兼容性)。某些以前的 Microsoft 编译器只允许使用 0 或 1 的下划线。

传递 (和修改) c DLL 的字符串数组

演示此方法的函数声明不使用 ByVal。原因传递的数组,该声明需要将字符串数组传递给该函数使用内部 Visual Basic 数组说明符 (HAD)。因此,声明如下所示:
   Declare Sub passStrings Lib "mydll.dll" (theArray() As String,                    ByVal nIndex% )
实际的 C 函数如下所示:
   void __far __pascal __export passStrings(HAD had, int nIndex)
VBArrayElement() 用于提取 Visual Basic 字符串的函数从数组 (使用由 nIndex 指定数组中的索引) 处理 (HLSTR)。VBGetHlstr() 将转换该字符串句柄,然后到标准 C 字符串。如果您希望,如果用于接收字符串缓冲区和足够大,所做的更改,则可以修改该 C 字符串随意。但是,修改后的字符串必须存储在原始的 Visual Basic 字符串句柄。这是通过 VBSetHlstr() 函数。

从 C DLL 中函数返回一个字符串

Visual Basic 例程从函数接收一个字符串,该函数必须返回一个字符串,并在 C 中侧边、 返回类型为 HLSTR 的变量声明。因此,声明如下所示:
   Declare Function returnAString Lib "mydll.dll" () As String
实际的 C 函数如下所示:
   hlstr __far __pascal __export returnAString()
这一次,VBCreateTempHlstr 用来转换指定的标准 C 字符串到 Visual Basic 字符串句柄。然后该函数只返回该句柄,以字符串的形式接收 Visual Basic。

此外,VBRuntimeError 函数用于生成 Visual Basic 运行时错误。如果在调用 VBCreateTempHlstr 后存在的错误条件,VBRuntimeError 设置 Visual Basic 错误代码,然后退出函数。出于此原因,此函数只应由 Visual Basic,不在控件的过程中自定义控件或 Windows 本身在调用代码的其他位置的直接调用的例程中。

若要创建 DLL 的分步示例

以下是生成 DLL 使用 Visual C++ 所需的步骤:
  1. 启动 Visual C++。
  2. 通过从项目菜单中选择新建来创建一个新的项目。选择以下选项:

    1. 将项目类型设置为"Windows 动态链接库 (。DLL)"。
    2. 清除"使用 Microsoft 基础类"复选框。
  3. 创建一个新文件,添加以下文本并将它另存为"MYDLL。DEF":
       LIBRARY        MYDLL    DESCRIPTION    "String Manipulation DLL"    EXETYPE        WINDOWS 3.1    CODE           PRELOAD MOVEABLE DISCARDABLE    DATA           PRELOAD MOVEABLE SINGLE    HEAPSIZE       4096    EXPORTS             passOneString  @1             passStrings    @2             returnAString  @3 
  4. 创建一个新文件、 添加下面的代码,并将它另存为"MYDLL。C":
       #include <windows.h>    #include <string.h>    #include <stdio.h>    #include "vbapi.h"     #define USHORT unsigned short     //-------------------------------------------------------------------    // Global Variables    //-------------------------------------------------------------------    HANDLE hmodDLL;     //-------------------------------------------------------------------    // Receive a single string in functions argument list:    // display string to user    //-------------------------------------------------------------------    void __far __pascal __export passOneString(LPSTR lpszBuf)    {       // Display old string to user.       MessageBox( NULL, lpszBuf, "Inside DLL...  (unmodified)", 0 );    }     //-------------------------------------------------------------------    // Receive/modify array of strings in functions argument list:    // - Retrieve a specified element in an array of strings.    // - Transform that element into a standard C string.    // - Modify that standard C string.    // - Save the modified string back into the original element of the    //   array.    //-------------------------------------------------------------------    void __far __pascal __export passStrings(HAD had, int nIndex)    {       HLSTR       hlstr;               // Reference to VB string       int         idx[1];              // Array in one dimension       char        lpszBuf[255];        // "Std C" string buffer       USHORT      cbCount;             // # of characters in string        // Retrieve a specified element (nIndex) in an array of strings.       idx[0] = nIndex;       hlstr = VBArrayElement(had, 1, (LPINT)idx);        // Transform that element into a standard C string.       cbCount = VBGetHlstr( hlstr, lpszBuf, sizeof( lpszBuf ) - 1 );        // Display old string to user.       MessageBox( NULL, lpszBuf, "Inside DLL...  (unmodified)", 0 );        // Modify that standard C string.       wsprintf(lpszBuf, "%s <-- size = %d", lpszBuf, lstrlen(lpszBuf));        // Save the modified string in the original element of the array.       VBSetHlstr( &hlstr, lpszBuf, lstrlen( lpszBuf ) );    }     //-------------------------------------------------------------------    // Return a string from a function back to a Visual Basic program:    // - Create Hlstr from standard C string.    // - Report error (if any).    // - Return Hlstr to calling VB function.    //-------------------------------------------------------------------    HLSTR __far __pascal __export returnAString()    {        HLSTR temp;        char *buff = {"This function returns a string from a DLL."};        // Creates Hlstr from standard C string.        temp = VBCreateTempHlstr(buff, lstrlen(buff));        // Report error (if any).       if (HIWORD(temp) == -1)          VBRuntimeError(LOWORD(temp));        // Return Hlstr to calling VB function.       return temp;    }     //-------------------------------------------------------------------    // Initialize library.    // This routine is called from the DLL entry point in LIBINIT.ASM,    // which is called when the first client loads the DLL.    //-------------------------------------------------------------------    BOOL FAR PASCAL LibMain(HANDLE hmod, HANDLE segDS, USHORT cbHeapSize)    {        // Avoid warnings on unused (but required) formal parameters.        cbHeapSize = cbHeapSize;        segDS = segDS;         hmodDLL = hmod;         // Leave the DS unlocked when not running.        // Required only under Windows version 3.1        // Win32 does not require or support UnlockData()        UnlockData( 0 );         return TRUE;    }     //-------------------------------------------------------------------    // Handle exit notification from Windows.    // This routine is called by Windows when the library is freed    // by its last client.    //-------------------------------------------------------------------    VOID __far __pascal __export WEP (BOOL fSystemExit)    {        // Avoid warnings on unused (but required) formal parameters.        fSystemExit = fSystemExit;    } 
  5. 从项目菜单中,选择生成 MYDLL。DLL 的选项。
  6. 添加 MYDLL。定义,MYDLL。C 和 \VB\CDK\VBAPI。LIB 文件复制到项目。本示例假定已安装 Visual Basic 到 \VB 目录中。否则,请修改此为正确的路径的最后一个条目。

若要创建 Visual Basic 应用程序使用 DLL 的分步示例

  1. 在 Visual Basic 中开始一个新项目。默认情况下,将创建 Form1。
  2. 在 Form1 中放置三个命令按钮 (Command1 和 Command2,Command3)。
  3. 作为指导,使用下表设置第 2 步中添加的控件的属性。
       Control name   Property   New value    ---------------------------------------------    Command1       Caption    &Pass a String    Command2       Caption    Pass &And Modify Array    Command3       Caption    &Receive a String 
  4. 将下面的代码添加到 Form1 的常规 (声明) 部分中:
       ' Enter each of the following Declare statements as one, single line:     Declare Sub passOneString Lib "mydll.dll" (ByVal lpszBuf As String)    Declare Sub passStrings Lib "mydll.dll" (theArray() As String,       ByVal nIndex%)    Declare Function returnAString Lib "mydll.dll" () As String 
  5. 将下面的代码放在 Command1 单击事件过程中:

       Sub Command1_Click ()       Dim MyStr As String * 80       Dim My2ndStr$        MyStr = "Hello World (First String)"       My2ndStr$ = "Hello World Again (Second String)"        Call passOneString(MyStr)       Call passOneString(My2ndStr$)    End Sub 
    注意: 此示例演示定义的字符串的任何一种方法同样适用很好地。
  6. 将下面的代码放在 Command2 单击事件过程中:
       Sub Command2_Click ()       Dim i%       ReDim array(0 To 2) As String        array(0) = "Short"       array(1) = "Medium Medium"       array(2) = "Long Longer Longest"        For i% = 0 To 2          Call passStrings(array(), i%)          MsgBox array(i%), 0, "Inside VB...  (modified)"       Next i%    End Sub 
  7. 将下面的代码放在 Command3 单击事件过程中:
       Sub Command3_Click ()       Dim MyStr$        MyStr$ = returnAString()        MsgBox MyStr$, 0, "Returned from DLL..."    End Sub 
  8. 若要运行该程序运行菜单中选择启动。
  评论这张
转发至微博
转发至微博

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多