刚接手一个VB程序,以前没用过VB,结果碰到好多问题啊。。都快疯了。我的需求:
调用exe所在文件夹下的一个dll文件dll的接口函数:
extern "C" __declspec(dllexport) int LOGON_LogOn(void);我的方法:
VB6不能使用相对路径来调用
so我用了LoadLibrary代码如下:
Private Declare Function FreeLibrary Lib "kernel32" (ByVal hLibModule As Long) As Long
Private Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long
Private Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Long, ByVal lpProcName As String) As Long
Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Any, ByVal wParam As Any, ByVal lParam As Any) As LongPrivate Sub Form_Load()
    On Error Resume Next
    Dim lb As Long, pa As Long
    Lb = LoadLibrary("LogOn.dll")
    pa = GetProcAddress(lb, "LOGON_LogOn")
    CallWindowProc GetProcAddress(lb, "LOGON_LogOn"), Me.hWnd, 0, 0, 0
    FreeLibrary lb
End Sub结果CallWindowProc GetProcAddress(lb, "LOGON_LogOn"), Me.hWnd, 0, 0, 0出错
查了一下,发现CallWindowProc只能引用:有四个入参的函数....那请问大侠,我想要调用任意个数的DLL接口函数,该如何实现?或者更直接一点,如何才能让我使用相对路径来调用DLL?

解决方案 »

  1.   

    费那事儿。
    你把LogOn.dll放在c:\windows\system32文件夹下(Win64位系统放在c:\windows\syswow64文件夹下)
    Private Declare Function LOGON_LogOn Lib "LogOn" () As Long
      

  2.   

    系统会自动查找以下路径:
    * 可执行文件(程序)所在的路径,可能就是你所说的 exe 所在路径;
    * Windows 所在路径
    * Windows\System32 路径所以,你直接如 1 楼声明即可调用。“VB6不能使用相对路径来调用”是听谁说的?
      

  3.   


    我就是不想使用这个,我想把dll和配置文件,exe等放在一个文件夹下,这样在其他机器上使用时直接拷贝过去就可以了。
    如果直接显式调用,Private Declare Function
    我怎么还会这么烦呢。。
      

  4.   


    确实不行啊,或者你给我段代码参考一下?
    Private Declare Function LOGON_LogOn Lib "LogOn" () As Long
    Private Declare Function LOGON_LogOn Lib ".\LogOn" () As Long
    Private Declare Function LOGON_LogOn Lib "\LogOn" () As Long
    都不行,
    必须是绝对路径
      

  5.   

    Declare 语句示例
    该示例演示如何在标准模块的模块级使用 Declare 语句来声明对动态链接库 (DLL) 中的一个外部过程的引用。如果是 Private 的 Declare 语句,则可以用于类模块。'在 Microsoft Windows(16 位)中:
    Declare Sub MessageBeep Lib "User" (ByVal N As Integer)
    '假设 SomeBeep 是该过程名的别名。
    Declare Sub MessageBeep Lib "User" Alias "SomeBeep"(ByVal N As Integer)
    '在 Alias 子句使用顺序号来调用 GetWinFlags。
    Declare Function GetWinFlags Lib "Kernel" Alias "#132"() As Long'在 32 位 Microsoft Windows 系统中,指定的库应是 USER32.DLL,
    '而不是 USER.DLL。可以使用条件编译来编写
    '既可在 Win32 又可在 Win16 环境运行的代码。
    #If Win32 Then
       Declare Sub MessageBeep Lib "User32" (ByVal N As Long)
    #Else
       Declare Sub MessageBeep Lib "User" (ByVal N As Integer)
    #End If
      

  6.   


    我就是不想使用这个,我想把dll和配置文件,exe等放在一个文件夹下,这样在其他机器上使用时直接拷贝过去就可以了。
    如果直接显式调用,Private Declare Function
    我怎么还会这么烦呢。。

    用这个不会死人的!
      

  7.   


    我就是不想使用这个,我想把dll和配置文件,exe等放在一个文件夹下,这样在其他机器上使用时直接拷贝过去就可以了。
    如果直接显式调用,Private Declare Function
    我怎么还会这么烦呢。。

    用这个不会死人的!
    流行的安装程序都用这个的。
      

  8.   


    我就是不想使用这个,我想把dll和配置文件,exe等放在一个文件夹下,这样在其他机器上使用时直接拷贝过去就可以了。
    如果直接显式调用,Private Declare Function
    我怎么还会这么烦呢。。

    用这个不会死人的!
    流行的安装程序都用这个的。我已经说了,我需要的不是这个
    我需要的是能使用相对路径来调用DLL。因为条件规定就是一个工具包,没有安装,在任意电脑上解压直接可用。如果用Private Declare Function可以实现,可以告诉我怎么在这条代码里面使用相对路径吗?
    或者使用LoadLibrary的话,如何才能让CallWindowProc调用只有一个参数的函数?
      

  9.   

    我可以换个方式,比如在LoadForm时运行一个bat文件,自动把dll拷贝到System32目录下。
    但是这样只是换个方法实现而且,而且治标不治本。万一有的电脑有系统文件夹访问权限,这样就执行不了了。
    所以我才想问一下,有什么办法能在代码中调用相对路径的DLL(DLL就放在程序exe同目录下)因为我对VB不熟悉,现在又需要拿VB来改以前别人写的一个测量程序。
      

  10.   

    可不可以在环境变量里加path?
      

  11.   

    你就照 1 楼那样声明。然后将 DLL 放在可执行程序同一路径下即可。我从来就没有用过动态加载。做安装包时,注意将 DLL 的路径改为 AppPath(缺省是系统路径)。
      

  12.   

    注意,相对路径,相对的就是可执行文件的当前路径。至于 VB 提供的 Windows 路径,Windows System 路径, Visual Basic 路径,都时一些附送的便利。此外,微软认为你使用的 DLL 可能是公用的,放在系统路径中,当你卸载程序时,DLL 仍会保留。
      

  13.   

    LoadLibrary
    The LoadLibrary function maps the specified executable module into the address space of the calling process. HINSTANCE LoadLibrary(
      LPCTSTR lpLibFileName   // address of filename of executable module
    );
     
    Parameters
    lpLibFileName 
    Pointer to a null-terminated string that names the executable module (either a .DLL or .EXE file). The name specified is the filename of the module and is not related to the name stored in the library module itself, as specified by the LIBRARY keyword in the module-definition (.DEF) file. 
    If the string specifies a path but the file does not exist in the specified directory, the function fails. When specifying a path, be sure to use backslashes (\), not forward slashes (/). If the string does not specify a path, the function uses a standard search strategy to find the file. See the Res for more information. Return Values
    If the function succeeds, the return value is a handle to the module.If the function fails, the return value is NULL. To get extended error information, call GetLastError. Res
    LoadLibrary can be used to map a DLL module and return a handle that can be used in GetProcAddress to get the address of a DLL function. LoadLibrary can also be used to map other executable modules. For example, the function can specify an .EXE file to get a handle that can be used inFindResource orLoadResource. Do not use LoadLibrary to "run" a .EXE file. If the module is a DLL not already mapped for the calling process, the system calls the DLL's DllMain function with the DLL_PROCESS_ATTACH value. If the DLL's entry-point function does not return TRUE, LoadLibrary fails and returns NULL. It is not safe to call LoadLibrary from DllMain. For more information, see the Res section in DllMain. Module handles are not global or inheritable. A call to LoadLibrary by one process does not produce a handle that another process can use — for example, in calling GetProcAddress. The other process must make its own call to LoadLibrary for the module before calling GetProcAddress. If no filename extension is specified in the lpLibFileName parameter, the default library extension .DLL is appended. However, the filename string can include a trailing point character (.) to indicate that the module name has no extension. When no path is specified, the function searches for loaded modules whose base name matches the base name of the module to be loaded. If the name matches, the load succeeds. Otherwise, the function searches for the file in the following sequence: The directory from which the application loaded. 
    The current directory. 
    Windows 95 and Windows 98: The Windows system directory. Use theGetSystemDirectory function to get the path of this directory.
    Windows NT: The 32-bit Windows system directory. Use the GetSystemDirectory function to get the path of this directory. The name of this directory is SYSTEM32. Windows NT: The 16-bit Windows system directory. There is no function that obtains the path of this directory, but it is searched. The name of this directory is SYSTEM. 
    The Windows directory. Use theGetWindowsDirectory function to get the path of this directory. 
    The directories that are listed in the PATH environment variable. 
    The first directory searched is the one directory containing the image file used to create the calling process (for more information, see the CreateProcess function). Doing this allows private dynamic-link library (DLL) files associated with a process to be found without adding the process's installed directory to the PATH environment variable. 

    The Visual C++ compiler supports a syntax that enables you to declare thread-local variables: _declspec(thread). If you use this syntax in a DLL, you will not be able to load the DLL explicitly using LoadLibrary or LoadLibraryEx. If your DLL will be loaded explicitly, you must use the thread local storage functions instead of _declspec(thread). Windows 95: If you are using LoadLibrary to load a module that contains a resource whose numeric identifier is greater than 0x7FFF, LoadLibrary fails. Windows CE: Two different modules cannot have the same filename, given that the extensions are different. These effectively have the same "module" name. For example, if LoadLibrary is made on "Sample.cpl", the operating system will not load Sample.cpl, but instead will again load Sample.dll. A similar limitation exists for modules with the same name but residing in different directories. For example, if LoadLibrary is called on "\\Windows\Sample.dll", and then LoadLibrary is called on "\\MyDir\Sample.dll", "\\Windows\Sample.dll" will simply be reloaded.A search path to the executable module cannot be specified. Unless the full path to the module is given, Windows CE will search the following path for the module: The root directory of the PC Card RAM expansion card, if one exists. 
    The windows directory (\Windows). 
    The root directory (\). 
    QuickInfo
      Windows NT: Requires version 3.1 or later.
      Windows: Requires Windows 95 or later.
      Windows CE: Requires version 1.0 or later.
      Header: Declared in winbase.h.
      Import Library: Use kernel32.lib.
      Unicode: Implemented as Unicode and ANSI versions on Windows NT.See Also
    Dynamic-Link Libraries Overview, Dynamic-Link Library Functions, DllMain,FindResource, FreeLibrary, GetProcAddress,GetSystemDirectory,GetWindowsDirectory, LoadLibraryEx,LoadResource  
      

  14.   

    http://www.vbgood.com/forum.php?mod=viewthread&tid=88386&extra=&mobile=yes
    看看这个行吗?
      

  15.   

    坛子上有这个问题的讨论。找不到路径是在VS环境中,你要是编译生成exe了,执行exe的时候,不会找不到。你可以试试,应该这个问题根本就不用担心。如果你实在觉得即使在Visual Basic环境下未编译的时候也不想拷贝那个dll,偷来的代码:做一点特殊处理:Function InDebugMode() As Boolean
        OnError Goto ErrProc:
        Debug.Print 1 / 0
        InDebugMode = False
        Exit Function
    ErrProc:
        InDebugMode = True
    End Function在主程序中
    If InDebugMode Then
        使用一个硬编码的路径
    Else
        使用App.Path找相对路径
    End If
      

  16.   

    用Declare声明API,直接就能用了,干吗在VB6中来“动态调用”!
    你说的那些“路径问题”根本就是不存在的问题。
    楼主真是没事找事!
      

  17.   

    兄弟,都三星了啊。VB能够调用的DLL,要声明成_stdcall。
      

  18.   

    严重同意17楼!
    先用C封装一个 dll,接口为 stdcall 的,也放在 exe 目录下。
    然后直接 Declare 声明即可调用。
    不用 LoadLibrary,也不存在路径问题,一切 OK!
      

  19.   

    我是用这个方式实现的:
    Function RunDll(SubFunctionName As String, ParamArray Parameters() As Variant)
     RunDll (“LOGON_LogOn”,参数1,参数2,参数3,参数4)ParamArray Parameters(,这个是可以压入任意个参数的
      

  20.   

    一定要用stdcall,动态不动态调用取决于需求。如果需要动态调用,网上搜,有相关类库,专门实现这个功能的。
      

  21.   

    兄弟,都三星了啊。VB能够调用的DLL,要声明成_stdcall。
    刚升3星没多久。
    最近偶尔来看看,回复一些贴子。
    我用手机上的论坛,我自己都不清楚哪天升级的。
    手机上进论坛后,必须要点“电脑版”,才能看到头像和等级。
    要不然只看到个ID,不是特别熟悉的人,都“不认识”呢。 
    你好像很久没有来论坛了,现在怎么有空来呀?
      

  22.   

    OCX不用注册?COM DLL也不用注册?
    你忽悠谁呢!!!
    你如果通过程序指令完成注册过程,
    那不代表“不需要注册”!
    OCX文件如果跟.EXE放一块,
    那可以说“不用注册”:
    系统加载程序时,会帮你把它注册。
    但COM的DLL好像跟.exe放一起也不行。更何况,你说你的“全在内存中”,
    系统在哪去找它?
      

  23.   

    系统要找一个东西,并不一定要在**文件夹中查找的。说白了,DLL,ocx都只是一些二进制代码,如果有能力把这些代码直接加到本EXE之内,也可以说相当于这些二进制代码就是EXE自身的一部分。全内存中是可以完全实现的,需要用到汇编之类的技术,难度是比较大一点。一般的注册OCX,之类是需要写注册表好几个地方的,不注册呢,无非是用代码来实现这些要写注册表的GUID之类的内部调用。