-
Jun 6th, 2014, 08:16 PM
#1
Thread Starter
New Member
[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.
-
Jun 6th, 2014, 08:23 PM
#2
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
-
Jun 7th, 2014, 02:07 PM
#3
Thread Starter
New Member
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
-
Jun 7th, 2014, 02:29 PM
#4
Re: Calling a C++ Dll from VB6
Originally Posted by Nightwalker83
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.
-
Jun 7th, 2014, 05:24 PM
#5
Re: Calling a C++ Dll from VB6
Originally Posted by mflum7
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.
-
Jun 7th, 2014, 06:37 PM
#6
Re: Calling a C++ Dll from VB6
Originally Posted by dilettante
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
-
Jun 8th, 2014, 12:34 AM
#7
Thread Starter
New Member
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
-
Jun 8th, 2014, 01:53 AM
#8
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
-
Jun 9th, 2014, 10:59 AM
#9
Thread Starter
New Member
Re: Calling a C++ Dll from VB6
Originally Posted by Nightwalker83
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
-
Jun 9th, 2014, 11:20 AM
#10
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.
-
Jun 9th, 2014, 08:40 PM
#11
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
-
Jun 9th, 2014, 08:44 PM
#12
Thread Starter
New Member
Re: Calling a C++ Dll from VB6
Originally Posted by Schmidt
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
-
Jun 9th, 2014, 08:59 PM
#13
Re: Calling a C++ Dll from VB6
Originally Posted by mflum7
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
-
Jun 10th, 2014, 09:14 PM
#14
Thread Starter
New Member
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
-
Jun 11th, 2014, 03:35 AM
#15
Re: Calling a C++ Dll from VB6
Originally Posted by mflum7
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
-
Jun 11th, 2014, 07:57 PM
#16
Thread Starter
New Member
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
-
Jun 11th, 2014, 08:26 PM
#17
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.
-
Jun 11th, 2014, 09:51 PM
#18
Thread Starter
New Member
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|