Results 1 to 18 of 18

Thread: [RESOLVED] Calling a C++ Dll from VB6

  1. #1

    Thread Starter
    New Member
    Join Date
    Mar 2014
    Posts
    10

    Resolved [RESOLVED] Calling a C++ Dll from VB6

    Following the article Step-by-Step-Calling-C-DLLs-from-VC-and-VB-Part on Code Project I have an interesting problem.

    I created the DLL2.dll using Visual Studio 5 and 2008 on a Windows 7 machine. On an XP I created a VB6 test project to call the DLL. All Fine.

    It works on the Windows 7 machine just great, but when executed on a Windows XP or Windows 8 it tells me it can't find the DLL, even though it is in the same folder as the VB6 program?

    Any help would be appreciated.
    Last edited by mflum7; Jun 7th, 2014 at 02:07 PM.

  2. #2
    PowerPoster Nightwalker83's Avatar
    Join Date
    Dec 2001
    Location
    Adelaide, Australia
    Posts
    13,344

    Re: Calling a C++ Dll from VB6

    See if the solution here solves the problem.
    when you quote a post could you please do it via the "Reply With Quote" button or if it multiple post click the "''+" button then "Reply With Quote" button.
    If this thread is finished with please mark it "Resolved" by selecting "Mark thread resolved" from the "Thread tools" drop-down menu.
    https://get.cryptobrowser.site/30/4111672

  3. #3

    Thread Starter
    New Member
    Join Date
    Mar 2014
    Posts
    10

    Re: Calling a C++ Dll from VB6

    Thanks Nightwalker83, I now have more to read. I am still at a loss that it works on a Win 7 machine but not on an XP or Win 8 machine

  4. #4
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: Calling a C++ Dll from VB6

    Quote Originally Posted by Nightwalker83 View Post
    See if the solution here solves the problem.
    Don't even bother.

    The "information" there is so full of pointless vitriol from .Net fanboys, misdirection, half-truths, and untruths that I can't believe anyone posted a link to it. For shame!

    None of it applies anyway since the DLL calls clearly work on one machine.

    Something else is at play here and we don't have enough information to help. A specific error message and error number might be a start.

  5. #5
    PowerPoster
    Join Date
    Aug 2011
    Location
    B.C., Canada
    Posts
    2,887

    Re: Calling a C++ Dll from VB6

    Quote Originally Posted by mflum7 View Post
    Following the article Step-by-Step-Calling-C-DLLs-from-VC-and-VB-Part on Code Project I have an interesting problem.

    I created the DLL2.dll using Visual Studio 5 and 2008 on a Windows 7 machine. On an XP I created a VB6 test project to call the DLL. All Fine.

    It works on the Windows 7 machine just great, but when executed on a Windows XP or Windows 8 it tells me it can't find the DLL, even though it is in the same folder as the VB6 program?

    Any help would be appreciated.
    First you said it works on xp then you say it doesn't work on xp and windows 8. I might be reading the post wrong...

    It would be nice to see how you call your dll and how you declare it.
    I'm assuming the dll works on windows 7 so it should not be a dll code error (hopefully).
    If you can post the code you use to execute the .dll file from your vb6 project, it would be a start, as well as what the error says.

    The .dll file, does it contain a lot of api calls? Maybe some are not supported (or changed) on xp? For windows 8 I do not know I never tested that OS.

  6. #6
    PowerPoster Nightwalker83's Avatar
    Join Date
    Dec 2001
    Location
    Adelaide, Australia
    Posts
    13,344

    Re: Calling a C++ Dll from VB6

    Quote Originally Posted by dilettante View Post
    Don't even bother.

    The "information" there is so full of pointless vitriol from .Net fanboys, misdirection, half-truths, and untruths that I can't believe anyone posted a link to it. For shame!

    None of it applies anyway since the DLL calls clearly work on one machine.

    Something else is at play here and we don't have enough information to help. A specific error message and error number might be a start.
    Ah ok! That is the first I heard of it.
    when you quote a post could you please do it via the "Reply With Quote" button or if it multiple post click the "''+" button then "Reply With Quote" button.
    If this thread is finished with please mark it "Resolved" by selecting "Mark thread resolved" from the "Thread tools" drop-down menu.
    https://get.cryptobrowser.site/30/4111672

  7. #7

    Thread Starter
    New Member
    Join Date
    Mar 2014
    Posts
    10

    Re: Calling a C++ Dll from VB6

    Project1.vbp

    Type=Exe
    Reference=*\G{00020430-0000-0000-C000-000000000046}#2.0#0#..\WINDOWS\system32\stdole2.tlb#OLE Automation
    Form=VB2.frm
    IconForm="VB2"
    Startup="VB2"
    ExeName32="Project1.exe"
    Command32=""
    Name="Project1"
    HelpContextID="0"
    CompatibleMode="0"
    MajorVer=1
    MinorVer=0
    RevisionVer=0
    AutoIncrementVer=0
    ServerSupportFiles=0
    VersionCompanyName=" Wellsonic"
    CompilationType=0
    OptimizationType=0
    FavorPentiumPro(tm)=0
    CodeViewDebugInfo=0
    NoAliasing=0
    BoundsCheck=0
    OverflowCheck=0
    FlPointCheck=0
    FDIVCheck=0
    UnroundedFP=0
    StartMode=0
    Unattended=0
    Retained=0
    ThreadPerObject=0
    MaxNumberOfThreads=1

    [MS Transaction Server]
    AutoRefresh=1

    Project1.vbw
    VB2 = 49, 46, 1248, 684, , 132, 174, 1331, 812, C

    VB2.frm
    VERSION 5.00
    Begin VB.Form VB2
    Caption = "VB2"
    ClientHeight = 1260
    ClientLeft = 60
    ClientTop = 450
    ClientWidth = 4680
    LinkTopic = "Form1"
    ScaleHeight = 1260
    ScaleWidth = 4680
    StartUpPosition = 3 'Windows Default
    Begin VB.TextBox Text1
    Height = 375
    Left = 1920
    TabIndex = 1
    Text = "Text1"
    Top = 480
    Width = 2535
    End
    Begin VB.CommandButton Command1
    Caption = "GetCpuSpeed()"
    Height = 375
    Left = 240
    TabIndex = 0
    Top = 480
    Width = 1455
    End
    End
    Attribute VB_Name = "VB2"
    Attribute VB_GlobalNameSpace = False
    Attribute VB_Creatable = False
    Attribute VB_PredeclaredId = True
    Attribute VB_Exposed = False
    Private Declare Function GetCpuSpeed Lib "DLL2.dll" () As Integer
    Private Declare Sub InitCommonControls Lib "comctl32.dll" ()

    Private Sub Form_Initialize()
    InitCommonControls
    'ChDir App.Path

    End Sub

    Private Sub Command1_Click()

    Dim nSpeed As Integer
    Dim s As String

    'ChDir App.Path

    Screen.MousePointer = vbHourglass
    nSpeed = GetCpuSpeed()
    Screen.MousePointer = 0

    s = nSpeed

    VB2.Text1.Text = "GetCpuSpeed() returned " + s

    End Sub

    Private Sub Form_Load()

    VB2.Text1.Text = ""

    End Sub

  8. #8
    PowerPoster Nightwalker83's Avatar
    Join Date
    Dec 2001
    Location
    Adelaide, Australia
    Posts
    13,344

    Re: Calling a C++ Dll from VB6

    I would suggest opening the project in Visual Basic then copy and pasting the code to avoid that mess.
    when you quote a post could you please do it via the "Reply With Quote" button or if it multiple post click the "''+" button then "Reply With Quote" button.
    If this thread is finished with please mark it "Resolved" by selecting "Mark thread resolved" from the "Thread tools" drop-down menu.
    https://get.cryptobrowser.site/30/4111672

  9. #9

    Thread Starter
    New Member
    Join Date
    Mar 2014
    Posts
    10

    Re: Calling a C++ Dll from VB6

    Quote Originally Posted by Nightwalker83 View Post
    I would suggest opening the project in Visual Basic then copy and pasting the code to avoid that mess.
    Private Declare Function GetCpuSpeed Lib "DLL2.dll" () As Integer
    Private Declare Sub InitCommonControls Lib "comctl32.dll" ()

    Private Sub Form_Initialize()
    InitCommonControls
    'ChDir App.Path

    End Sub

    Private Sub Command1_Click()

    Dim nSpeed As Integer
    Dim s As String

    'ChDir App.Path

    Screen.MousePointer = vbHourglass
    nSpeed = GetCpuSpeed()
    Screen.MousePointer = 0

    s = nSpeed

    VB2.Text1.Text = "GetCpuSpeed() returned " + s

    End Sub

    Private Sub Form_Load()

    VB2.Text1.Text = ""

    End Sub

  10. #10
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,219

    Re: Calling a C++ Dll from VB6

    What about changing that Integer Return-Value to a Long-Type in your Declare-Statement?

    Also take care, in which Folder your Dll-File (Dll2.dll) is placed.
    If it is placed in the same Path as your compiled Executable, then the Systems Dll-Loader
    will reliably find it only, when you run the compiled Exe-Binary.

    When running in the IDE (in case your Dll2.dll is placed beside your *.vbp-File),
    it might or might not work - better to explicitely pre-load the Dll-File in question
    per LoadLibrary then.

    Olaf
    Last edited by Schmidt; Jun 9th, 2014 at 11:25 AM.

  11. #11
    PowerPoster Nightwalker83's Avatar
    Join Date
    Dec 2001
    Location
    Adelaide, Australia
    Posts
    13,344

    Re: Calling a C++ Dll from VB6

    I forgot to mention this in my other post but wrapping the code in [code[/code] tags makes it easier to read.
    when you quote a post could you please do it via the "Reply With Quote" button or if it multiple post click the "''+" button then "Reply With Quote" button.
    If this thread is finished with please mark it "Resolved" by selecting "Mark thread resolved" from the "Thread tools" drop-down menu.
    https://get.cryptobrowser.site/30/4111672

  12. #12

    Thread Starter
    New Member
    Join Date
    Mar 2014
    Posts
    10

    Re: Calling a C++ Dll from VB6

    Quote Originally Posted by Schmidt View Post
    What about changing that Integer Return-Value to a Long-Type in your Declare-Statement?

    Also take care, in which Folder your Dll-File (Dll2.dll) is placed.
    If it is placed in the same Path as your compiled Executable, then the Systems Dll-Loader
    will reliably find it only, when you run the compiled Exe-Binary.

    When running in the IDE (in case your Dll2.dll is placed beside your *.vbp-File),
    it might or might not work - better to explicitely pre-load the Dll-File in question
    per LoadLibrary then.

    Olaf
    Thanks Olaf,
    You may be onto something. I compiled using VC 2005 on the Win7 machine and it works ok on the Win7 machine. I then compiled on XP using VC++ 2008 Express and it now works on both the XP and Win7. But it still will not work on the Win8.

    I tried the long but no it had no effect. Note: I always test using the DLL in a folder.

    Do you think I should research the LoadLibrary (I have never used it from VB6) as an answer?

    Michael

  13. #13
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,219

    Re: Calling a C++ Dll from VB6

    Quote Originally Posted by mflum7 View Post
    Thanks Olaf,
    You may be onto something. I compiled using VC 2005 on the Win7 machine and it works ok on the Win7 machine. I then compiled on XP using VC++ 2008 Express and it now works on both the XP and Win7. But it still will not work on the Win8.

    I tried the long but no it had no effect. Note: I always test using the DLL in a folder.

    Do you think I should research the LoadLibrary (I have never used it from VB6) as an answer?
    As long as you don't give the error-code you get when calling the Dll,
    or state clearly, if the code only chokes, when run from within the VB6-IDE,
    we can only guess.

    Also the C-Code would be nice to see.

    Olaf

  14. #14

    Thread Starter
    New Member
    Join Date
    Mar 2014
    Posts
    10

    Re: Calling a C++ Dll from VB6

    Olaf,

    The error code is as follows on Win 8 or XP (using VC++ 2005):

    "Run-time error '48: File not found: DLL2.dll

    "C" Code no fancy switchs and I am using a DLL2.def (see Bottom of page) to fix name mangling.

    Code:
    // DLL2.cpp : Defines the entry point for the DLL application.
    //
    
    #include "stdafx.h"
    #define DLL2_EXPORTS
    #include "DLL2.h"
    
    
    #ifdef _MANAGED
    #pragma managed(push, off)
    #endif
    
    BOOL APIENTRY DllMain( HMODULE /*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;
    }
    ///////////////////////////////////////////////////////////////////////////////
    // GetCycleCount - private function of DLL2.cpp.  The static keyword ensures
    //                 that this function name is not visible outside DLL2.cpp.
    static inline unsigned __int64 GetCycleCount()
    {
        unsigned int timehi, timelo;
    
        // Use the assembly instruction rdtsc, which gets the current
        // cycle count (since the process started) and puts it in edx:eax.
        __asm
        {
            rdtsc
            mov timehi, edx;
            mov timelo, eax;
        }
    
        return ((unsigned __int64)timehi << 32) + (unsigned __int64)timelo;
    }
    
    
    ///////////////////////////////////////////////////////////////////////////////
    // Example of an exported function
    ///////////////////////////////////////////////////////////////////////////////
    // GetCpuSpeed - returns CPU speed in MHz;  for example, ~2193 will be 
    //               returned for a 2.2 GHz CPU.
    int __stdcall GetCpuSpeed()
    {
        const unsigned __int64 ui64StartCycle = GetCycleCount();
        Sleep(1000);
        return static_cast<int>((GetCycleCount() - ui64StartCycle) / 1000000);
    }
    DEF
    Code:
    ; DLL2.def - defines the exports for DLL2.dll
    
    LIBRARY DLL2
    ;DESCRIPTION 'A C++ dll that can be called from VB'
    
    EXPORTS
        GetCpuSpeed
    DLL2.H
    Code:
    #ifndef DLL2_H
    #define DLL2_H
    
    // The following ifdef block is the standard way of creating macros which 
    // make exporting from a DLL simpler.  The DLL2.cpp file is compiled with 
    // the symbol DLL2_EXPORTS defined at the top of DLL2.cpp.  This symbol 
    // should *not* be defined in any project that uses DLL2.  This way any 
    // other project whose source files include DLL2.h will see DLL2_API defined 
    // as __declspec(dllimport), whereas within DLL2.cpp, DLL2_API is defined as
    // __declspec(dllexport).
    
    //#ifdef DLL2_EXPORTS
    //    #define DLL2_API __declspec(dllexport)
    //#else
    //    #define DLL2_API __declspec(dllimport)
    //#endif
    
    ///////////////////////////////////////////////////////////////////////////////
    // This function is exported from the DLL2.dll
    //DLL2_API int __stdcall GetCpuSpeed();
    int __stdcall GetCpuSpeed();
    
    #endif //DLL2_H

  15. #15
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,219

    Re: Calling a C++ Dll from VB6

    Quote Originally Posted by mflum7 View Post
    The error code is as follows on Win 8 or XP (using VC++ 2005):

    "Run-time error '48: File not found: DLL2.dll
    Ok, as far as I see, there's nothing wrong with the C-Code - and it's also exported
    as __stdcall - and your Declare line in VB6 is also OK.

    So it is a I guessed, and the Error-Description above should have given you the same idea.

    If a File is not found, named Dll2.dll - then you didn't even reached the point yet,
    where VB6 is trying a "jump into your declared function".

    With VB6 Declare-Lines you define a "Job-Description".

    And other than with typelib-defined API-Calls (where the *.tlb-defined Dll is early loaded,
    at Startup-Time), VB will use "delayed loading" of the Dll-File itself, at the first reached
    Position in your Code, where the Declared Function is about to be used (called).

    The first thing VB does (under the covers), when it reaches such an external
    Function-Call-definition, is to look up in you Declare-Line, which Dll-file to load
    (with the goal to retrieve a "Library-Handle" for it).

    The API-call which is used under the covers for that is: LoadLibrary

    If VB cannot find the Dll with its own, internal Call to LoadLibrary, then the
    Error you've reported is thrown at you...

    If it was able to load the Dll-File, then the retrieved Dll-Handle is cached for
    later usage (of other declared calls on the same Dll-Name), and the next
    hidden API-call is performed: GetProcAddress
    GetProcAddress is using the earlier retrieved LibHandle in conjunction with
    the "FunctionName-String" you gave in your Declare-Line - in case the
    Name of this function is not found in this already loaded library, you will
    get a different kind of error, which clearly states also that.

    In case of a successful retrieval of the Function-Address (per GetProcAddress),
    VB will also cache this Function-Pointer - and only then proceeds with "jumping
    into the Dll-Code", calling the externally defined function (with again different
    Errors, when the Parameter-Count - or -Types didn't match).

    But as said, you didn't even reached all those later points, the only thing you
    will have to fix is the problem, VBs internal LoadLibrary-Call has, in finding
    your Dll2.dll.

    As I said earlier - this problem will surely not happen (not on XP, not on WIn7
    and also not on Vista or WIn8), when you compile a small Test-Executable,
    and try to call your Dll2.dll directly from this compiled Binary - it will work in
    all cases.

    An early info about that, would also have given a good hint to us, what's going
    wrong.

    And what's going wrong is, that you will have those problems only in the VB6-IDE,
    since the location where you placed that Dll2.dll is important.

    If it sits "directly beside your compiled Executable", then everything will *always* work
    fine (when you run the compiled executable).

    If it's sitting directly beside a *.vbp - and you try to run that project in the IDE,
    then it will work only fine, when the Folder which contains your Dll2.dll, is the
    CurrentDirectory - and that is not always the case.

    The Windows-Dll-Loader (the LoadLibrary-call) tries to find Dlls with a certain
    pattern, in a certain lookup-order:
    http://msdn.microsoft.com/en-us/libr...p_applications

    The Host-Process when you work with a Project in the IDE is not your compiled
    Binary - it's VB6.exe, which runs from a different path, usually not the path your *.vbp
    is placed in.

    And as already said, one can resolve those IDE-Problems with Dll-Lookups, when you load
    them yourself with explicite full-paths as e.g. in your case:

    LoadLibrary App.Path & "\Dll2.dll"

    That's all.

    Once the Dll is loaded into the VB6.exe process, it will get found there, when you
    reach the line, where your declared Dll-call is first used in your Code - you successfully
    performed a kind of "early Dll-loading on App-Startup" in this case.

    Olaf

  16. #16

    Thread Starter
    New Member
    Join Date
    Mar 2014
    Posts
    10

    Re: Calling a C++ Dll from VB6

    Great response Olaf,

    I have implemented the VB6 as follows:

    Code:
    Private Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long
    Private Declare Function GetCpuSpeed Lib "DLL2.dll" () As Long
    Private Declare Sub InitCommonControls Lib "comctl32.dll" ()
    
    Private Sub Form_Initialize()
    Dim results As Long
    Dim dllpath As String
    
        dllpath = App.Path & "\DLL2.dll"
    
        InitCommonControls
        ChDir App.Path
        results = LoadLibrary(dllpath)
        
        MsgBox dllpath
    
    
    End Sub
    
    Private Sub Command1_Click()
    
        Dim nSpeed As Long
        Dim s As String
        
        Screen.MousePointer = vbHourglass
        nSpeed = GetCpuSpeed()
        Screen.MousePointer = 0
        
        s = nSpeed
        
        VB2.Text1.Text = "GetCpuSpeed() returned " + s
    
    End Sub
    
    Private Sub Form_Load()
    
        VB2.Text1.Text = ""
        
    End Sub
    Using the XP machine I tried this code and the "LoadLibrary" returned a 0(zero) using the DLL2.dll compiled on the Windows 7 machine, using VC++ 2005 and VC++ 2014.

    I then recompiled the DLL2 on the XP machine using VC++ 2008 Express and ran it again on the same XP machine in the project folder.

    This time LoadLibrary return a proper value. I also ran the VB program in a folder on the desktop (standalone without the VB6 IDE) using the same (2008) DLL2.dll. Again it worked just fine.

    It also worked on the Windows 7 machine (I copied the folder containing the VB6 program "Project1" and DLL2.dll from XP).

    It did not work when I copied the folder to the Windows 8 machine.

    I am beginning to believe the problem resides in the way windows interfaces with the DLL2.dll and has little to do with the VC6 code.

    Michael

  17. #17
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,219

    Re: Calling a C++ Dll from VB6

    Ok, then the only remaining reason for the Error-Message (File not found) is an "indirect one"...

    If LoadLibrary fails to load an existing file from an apparently existing path, then it cannot
    resolve one of the Dll-dependencies of Dll2.dll.

    I suspect (since you get different results after compiling with different VC-Versions) the
    appropriate VC-runtimes to be the culprit (being not installed on some systems).

    E.g. your XP doesn't have the VC-runtimes which come with VC++ 2005 and VC++ 2014 -
    whilst your Win8 machine doesn't have the VC++ 2008 related runtimes.

    You can easily workaround this by compiling the needed VC-runtime-parts into your
    Dll statically - the appropriate switch for that is /MT (you currently have perhaps /MD,
    which is the default, produces the somewhat leaner binaries, but then depends
    on the properly installed and shipped VC-runtime-files)...
    http://msdn.microsoft.com/en-us/library/2kzt1wy3.aspx

    Olaf
    Last edited by Schmidt; Jun 11th, 2014 at 08:30 PM.

  18. #18

    Thread Starter
    New Member
    Join Date
    Mar 2014
    Posts
    10

    Thumbs up Re: Calling a C++ Dll from VB6

    Thanks Olaf for hanging in there. It works in all three VC++ and on all three machines (XP, 7 and 8).

    Thanks for a being a Professional and working through it with me.

    Many Thanks,

    Michael

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width