This question may be so basic.
To call DLL in C/C++, we should add(inform) .lib file of the DLL to the Linker.
This .lib contains the information needed at run time.
However VB6 calls DLL function which is exported without .lib.
The function declaration has just function name, parameter, and DLL name in VB6's DLL procedure call.
What is the difference between VB6 and C/C++ in DLL call?
The lib tells the linker where to find the function and how to call it... in VB6, that's done through the Declare format... same thing, same result, just a different means to get there.
Be sure to know what calling convention the DLL uses. VB6 does not play nicely with non stdCall conventions. For those more knowledgeable, does linking the DLL tell VB how to properly handle the clean up after the DLL call?
Edited: Or will VB only allow linking to stdCall functions?
Last edited by LaVolpe; Sep 3rd, 2015 at 02:36 PM.
Insomnia is just a byproduct of, "It can't be done"
VB6 allows work with CDECL calling convention too if this function was declared in tlb. But only at the compiled form.
lib files can contain the executable code and any binary data. When you use the .lib-file it is called - "static linking". It may combine either executable code (or any data) or import section.
You can use *lib-files in VB too.
When you call function by Declare-statement then it performs the dynamic call (LoadLibrary, GetProcAddress only once for each function), therefore you can process error (for example if dll not exists), and using the alternative solution if needed. This method uses runtime for calling function by DllFunctionCall, this function fills the special structure in the PE-image in order for next time not perform the initialization. When you using tlb, lib (with import section) you can't process error because initialization of dll's going on at running time.
Last edited by The trick; Dec 14th, 2015 at 08:26 AM.
Note If you use Visual C++ (or a similar tool) to create DLLs that will be called by Visual Basic, use the __stdcall calling convention. Do not use the default calling convention (_cdecl).
EDIT Disregard that; didn't see The trick's post before I posted mine.
Originally Posted by jdy0803
What is the difference between VB6 and C/C++ in DLL call?
When you load a DLL in an application, two methods of linking let you call the exported DLL functions. The two methods of linking are load-time dynamic linking and run-time dynamic linking.
Load-time dynamic linking
In load-time dynamic linking, an application makes explicit calls to exported DLL functions like local functions. To use load-time dynamic linking, provide a header (.h) file and an import library (.lib) file when you compile and link the application. When you do this, the linker will provide the system with the information that is required to load the DLL and resolve the exported DLL function locations at load time.
Run-time dynamic linking
In run-time dynamic linking, an application calls either the LoadLibrary function or the LoadLibraryEx function to load the DLL at run time. After the DLL is successfully loaded, you use the GetProcAddress function to obtain the address of the exported DLL function that you want to call. When you use run-time dynamic linking, you do not need an import library file.
Both VB6 and C/C++, however, supports both methods of linking. In VB6, run-time dynamic linking is normally achieved through the Declare statement. Load-time dynamic linking, on the other hand, can be accomplished by declaring a particular DLL's exported function(s) in a Type Library.
Last edited by Bonnie West; Sep 3rd, 2015 at 04:06 PM.
On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
Mark this thread.
Does VBForums has a function to add and save favorite thread?
Right?
For the life of me I can't get the unsupported CDecl declarations to work in a compiled wrapper DLL. It should be as simple as creating a basic ActiveX DLL, with the Declared CDecl Declare, and compiling. I'm willing to go the typelib route - before I try and build the DLL using __stdcall but that's a last resort. Setting up a complete build environment for some of these open source projects can be quite a pain.
Care to share, which open C-source project you're trying to wrap?
Olaf
SDL2 / Simple Direct Media Layer. It's a media/game dev API. I'd like to forgo the DispCallFunc overhead, so compiling using STDCALL is still a big option.
Example of calling CDecl functions (wsprintf, wcstoul). Note it works only in the exe.
I'll have to play with that idea sometime soon. Though, you said it only works when compiled? What would you suggest to also be able to use the DLLs during IDE? Maybe something like this?
Code:
#If uncompiled
DispCallFunc routines
#Else
TLB calls
#End If
Insomnia is just a byproduct of, "It can't be done"
I'll have to play with that idea sometime soon. Though, you said it only works when compiled? What would you suggest to also be able to use the DLLs during IDE? Maybe something like this?
Code:
#If uncompiled
DispCallFunc routines
#Else
TLB calls
#End If
Yes, it'll work. Usually i use other debugger, it allows to debug lot of things, such as multithreading, drivers, interceptions, etc.
You can do the addin that fix the IDE problem, and then user can uses the cdecl convention without "crutches".
Yes, it'll work. Usually i use other debugger, it allows to debug lot of things, such as multithreading, drivers, interceptions, etc.
You can do the addin that fix the IDE problem, and then user can uses the cdecl convention without "crutches".
Can you expand on your comments more. I admit that I do not completely follow. For example, what exactly are you suggesting if we wanted to your your wsprintf TLB both during IDE & when compiled to exe?
Insomnia is just a byproduct of, "It can't be done"
Yes, it'll work. Usually i use other debugger, it allows to debug lot of things, such as multithreading, drivers, interceptions, etc.
You can do the addin that fix the IDE problem, and then user can uses the cdecl convention without "crutches".
I'm always curious what debugers people use, and (resource watchers). Also what IDE add-in would allow this?
Can you expand on your comments more. I admit that I do not completely follow. For example, what exactly are you suggesting if we wanted to your your wsprintf TLB both during IDE & when compiled to exe?
As i imagine it:
When user adds an item in the references, addin checks whether it's a typelib. If so, addin parses it and looking for all members that have the cdecl calling convention. Then addin dynamically creates typelib just replaces cdecl calling convention to stdcall and changes library name to special library.
This library contains some functions that accept different numbers of parameters (these functions may be generated dynamically too). Each function from the library forms the stack (__stdcall -> __cdecl), and calls original function. Actually vb6 calls __stdcall function, therefore crash isn't happening. During compilation just replace typelib to original. You can synchronize all steps by the events.
Originally Posted by DEXWERX
I'm always curious what debugers people use, and (resource watchers). Also what IDE add-in would allow this?
In order to embed the debugger to IDE you need spend very much times and efforts, because it's very difficult (many things is undocumented). I use simple debbuger that debugs executable files. I use OllyDbg for user mode debugging and Syser for kernel mode debugging.
This is example of using OllyDbg for debugging vb6 code:
Last edited by The trick; Dec 14th, 2015 at 06:33 PM.
SDL2 / Simple Direct Media Layer. It's a media/game dev API. I'd like to forgo the DispCallFunc overhead, so compiling using STDCALL is still a big option.
The DispCallFunc-Overhead isn't all that "critical" for most calls -
it's only when you plan to e.g. render 20,000 lines for e.g. a "WireFrame-Model"
in a tight loop, that differences might become more obvious - but for those
kind of calls there often exist alternatives in the API like e.g. a "Polygon-" or
"RenderPath-" call or something (where the Coords sit in structures you pass along).
So, yeah - I'd perhaps go without a typelib, since a decent "Class-Wrapping" would
have to be done anyways (each Flat-API represented behind a Class-method).
I've just played a bit (for reasons of convenience with the builtin cdecl-support-calls
of the RichClient, which are also faster than calls over DispCallFunc - especially
New_c.cdeclCallDirect would be nearly as fast as a "natively declared call").
The following Class-Module (please name it cSDL2) wraps already a good part of the
"video"-functionality of SDL2-lib, so that most simple video-related examples on the
SDL-site should be supported (when converted to VB6-syntax)....
Code:
Option Explicit
Public Enum SDL_EventType
SDL_FIRSTEVENT = 0
SDL_QUIT_ = &H100
SDL_APP_TERMINATING
SDL_APP_LOWMEMORY
SDL_APP_WILLENTERBACKGROUND
SDL_APP_DIDENTERBACKGROUND
SDL_APP_WILLENTERFOREGROUND
SDL_APP_DIDENTERFOREGROUND
SDL_WindowEvent = &H200
SDL_SysWMEvent
SDL_KEYDOWN = &H300
SDL_KEYUP
SDL_TEXTEDITING
SDL_TEXTINPUT
SDL_MOUSEMOTION = &H400
SDL_MOUSEBUTTONDOWN
SDL_MOUSEBUTTONUP
SDL_MOUSEWHEEL
SDL_JOYAXISMOTION = &H600
SDL_JOYBALLMOTION
SDL_JOYHATMOTION
SDL_JOYBUTTONDOWN
SDL_JOYBUTTONUP
SDL_JOYDEVICEADDED
SDL_JOYDEVICEREMOVED
SDL_CONTROLLERAXISMOTION = &H650
SDL_CONTROLLERBUTTONDOWN
SDL_CONTROLLERBUTTONUP
SDL_CONTROLLERDEVICEADDED
SDL_CONTROLLERDEVICEREMOVED
SDL_CONTROLLERDEVICEREMAPPED
SDL_FINGERDOWN = &H700
SDL_FINGERUP
SDL_FINGERMOTION
SDL_DOLLARGESTURE = &H800
SDL_DOLLARRECORD
SDL_MULTIGESTURE
SDL_CLIPBOARDUPDATE = &H900
SDL_DROPFILE = &H1000
SDL_UserEvent = &H8000&
SDL_LASTEVENT = &HFFFF&
End Enum
Public Enum SDL_LOG_CATEGORY
SDL_LOG_CATEGORY_APPLICATION
SDL_LOG_CATEGORY_ERROR
SDL_LOG_CATEGORY_ASSERT
SDL_LOG_CATEGORY_SYSTEM
SDL_LOG_CATEGORY_AUDIO
SDL_LOG_CATEGORY_VIDEO
SDL_LOG_CATEGORY_RENDER
SDL_LOG_CATEGORY_INPUT
SDL_LOG_CATEGORY_TEST
End Enum
Public Enum SDL_LogPriority
SDL_LOG_PRIORITY_VERBOSE = 1
SDL_LOG_PRIORITY_DEBUG
SDL_LOG_PRIORITY_INFO
SDL_LOG_PRIORITY_WARN
SDL_LOG_PRIORITY_ERROR
SDL_LOG_PRIORITY_CRITICAL
End Enum
Public Enum SDL_INIT_FLAGS
SDL_INIT_TIMER = &H1
SDL_INIT_AUDIO = &H10
SDL_INIT_VIDEO = &H20
SDL_INIT_JOYSTICK = &H200
SDL_INIT_HAPTIC = &H1000
SDL_INIT_GAMECONTROLLER = &H2000
SDL_INIT_EVENTS = &H4000
SDL_INIT_NOPARACHUTE = &H100000
End Enum
Public Enum SDL_WindowFlags
SDL_WINDOW_FULLSCREEN = &H1
SDL_WINDOW_OPENGL = &H2
SDL_WINDOW_SHOWN = &H4
SDL_WINDOW_HIDDEN = &H8
SDL_WINDOW_BORDERLESS = &H10
SDL_WINDOW_RESIZABLE = &H20
SDL_WINDOW_MINIMIZED = &H40
SDL_WINDOW_MAXIMIZED = &H80
SDL_WINDOW_INPUT_GRABBED = &H100
SDL_WINDOW_INPUT_FOCUS = &H200
SDL_WINDOW_MOUSE_FOCUS = &H400
SDL_WINDOW_FULLSCREEN_DESKTOP = (SDL_WINDOW_FULLSCREEN Or &H1000)
SDL_WINDOW_FOREIGN = &H800
SDL_WINDOW_ALLOW_HIGHDPI = &H2000
End Enum
Public Enum SDL_RendererFlags
SDL_RENDERER_SOFTWARE = &H1
SDL_RENDERER_ACCELERATED = &H2
SDL_RENDERER_PRESENTVSYNC = &H4
SDL_RENDERER_TARGETTEXTURE = &H8
End Enum
Public Enum SDL_WINDOWPOS
SDL_WINDOWPOS_UNDEFINED = &H1FFF0000
SDL_WINDOWPOS_CENTERED = &H2FFF0000
End Enum
'****** end of Public EnumDefs (which will show up on the Class-Interface) *****
'the rest is Private-stuff for Class-internal usage...
'these two are used to convert Zero-terminated 8Bit-CharSequences into VBStrings
Private Declare Function lstrlenA& Lib "kernel32" (ByVal lpszSrc&)
Private Declare Function lstrcpyA& Lib "kernel32" (ByVal lpszDest$, ByVal lpszSrc&)
'the SDL-Event-struct is a Union - but most "Sub-Structs" have at least the first 3 Members in common
Private Type SDL_EVENT
eType As SDL_EventType
eTimeStamp As Long
eID As Long
eBytes(0 To 63) As Byte
End Type
Private mEvt As SDL_EVENT 'this Class-Variable is the one used for Polling
'the below ENum is used as a "speaking Index" in conjunction with the Function-Table (vTbl) directly below
Private Enum SDL_Methods
SDL_LogSetPriority
SDL_Init
SDL_GetError
SDL_CreateWindow
SDL_GetWindowSurface
SDL_CreateSoftwareRenderer
SDL_CreateRenderer
SDL_SetRenderDrawColor
SDL_RenderClear
SDL_RenderGetViewport
SDL_RenderFillRect
SDL_RenderPresent
SDL_UpdateWindowSurface
SDL_PollEvent
SDL_FreeSurface
SDL_DestroyRenderer
SDL_DestroyWindow
SDL_Quit
'... put additional methods here
SDL_MethodsCount
End Enum
Private vTbl(0 To SDL_MethodsCount - 1) As Long 'and here's our Private vTbl-Array for the Func-Pointers
Private Sub Class_Initialize()
Dim DllPath$: DllPath = App.Path & "\SDL2.dll"
vTbl(SDL_LogSetPriority) = New_c.GetFuncPtr(DllPath, "SDL_LogSetPriority", True)
vTbl(SDL_Init) = New_c.GetFuncPtr(DllPath, "SDL_Init", True)
vTbl(SDL_GetError) = New_c.GetFuncPtr(DllPath, "SDL_GetError", True)
vTbl(SDL_CreateWindow) = New_c.GetFuncPtr(DllPath, "SDL_CreateWindow", True)
vTbl(SDL_GetWindowSurface) = New_c.GetFuncPtr(DllPath, "SDL_GetWindowSurface", True)
vTbl(SDL_CreateSoftwareRenderer) = New_c.GetFuncPtr(DllPath, "SDL_CreateSoftwareRenderer", True)
vTbl(SDL_CreateRenderer) = New_c.GetFuncPtr(DllPath, "SDL_CreateRenderer", True)
vTbl(SDL_SetRenderDrawColor) = New_c.GetFuncPtr(DllPath, "SDL_SetRenderDrawColor", True)
vTbl(SDL_RenderClear) = New_c.GetFuncPtr(DllPath, "SDL_RenderClear", True)
vTbl(SDL_RenderGetViewport) = New_c.GetFuncPtr(DllPath, "SDL_RenderGetViewport", True)
vTbl(SDL_RenderFillRect) = New_c.GetFuncPtr(DllPath, "SDL_RenderFillRect", True)
vTbl(SDL_RenderPresent) = New_c.GetFuncPtr(DllPath, "SDL_RenderPresent", True)
vTbl(SDL_UpdateWindowSurface) = New_c.GetFuncPtr(DllPath, "SDL_UpdateWindowSurface", True)
vTbl(SDL_PollEvent) = New_c.GetFuncPtr(DllPath, "SDL_PollEvent", True)
vTbl(SDL_FreeSurface) = New_c.GetFuncPtr(DllPath, "SDL_FreeSurface", True)
vTbl(SDL_DestroyRenderer) = New_c.GetFuncPtr(DllPath, "SDL_DestroyRenderer", True)
vTbl(SDL_DestroyWindow) = New_c.GetFuncPtr(DllPath, "SDL_DestroyWindow", True)
vTbl(SDL_Quit) = New_c.GetFuncPtr(DllPath, "SDL_Quit", True)
LogSetPriority SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO
End Sub
Public Function LogSetPriority(ByVal Cat As SDL_LOG_CATEGORY, ByVal Prio As SDL_LogPriority) As Long
LogSetPriority = New_c.cdeclCall(retLong, vTbl(SDL_LogSetPriority), Cat, Prio)
End Function
Public Function Init(ByVal Flags As SDL_INIT_FLAGS) As Long
Init = New_c.cdeclCall(retLong, vTbl(SDL_Init), Flags)
End Function
Public Function GetError() As String
Dim pErrStr As Long, SLen As Long
pErrStr = New_c.cdeclCall(retLong, vTbl(SDL_GetError))
If pErrStr = 0 Then Exit Function Else SLen = lstrlenA(pErrStr)
If SLen Then GetError = Space$(SLen): lstrcpyA GetError, pErrStr
End Function
Public Function CreateWindow(Caption As String, ByVal x&, ByVal y&, ByVal dx&, ByVal dy&, Optional ByVal Flags As SDL_WindowFlags = SDL_WINDOW_RESIZABLE) As Long
CreateWindow = New_c.cdeclCall(retLong, vTbl(SDL_CreateWindow), StrPtr(StrConv(Caption, vbFromUnicode)), x, y, dx, dy, Flags)
End Function
Public Function GetWindowSurface(Window As Long) As Long
GetWindowSurface = New_c.cdeclCall(retLong, vTbl(SDL_GetWindowSurface), Window)
End Function
Public Function CreateSoftwareRenderer(Surface As Long) As Long
CreateSoftwareRenderer = New_c.cdeclCall(retLong, vTbl(SDL_CreateSoftwareRenderer), Surface)
End Function
Public Function CreateRenderer(Window As Long, Optional ByVal Flags As SDL_RendererFlags = SDL_RENDERER_SOFTWARE) As Long
CreateRenderer = New_c.cdeclCall(retLong, vTbl(SDL_CreateRenderer), Window, -1, Flags)
End Function
Public Function SetRenderDrawColor(Renderer As Long, ByVal R As Byte, ByVal G As Byte, ByVal B As Byte, Optional ByVal A As Byte = 255) As Long
SetRenderDrawColor = New_c.cdeclCall(retLong, vTbl(SDL_SetRenderDrawColor), Renderer, R, G, B, A)
End Function
Public Function RenderClear(Renderer As Long) As Long
RenderClear = New_c.cdeclCall(retLong, vTbl(SDL_RenderClear), Renderer)
End Function
Public Sub RenderGetViewport(Renderer As Long, x As Long, y As Long, dx As Long, dy As Long)
Static Rct(0 To 3) As Long
New_c.cdeclCall retVoid, vTbl(SDL_RenderGetViewport), Renderer, VarPtr(Rct(0))
x = Rct(0): y = Rct(1): dx = Rct(2): dy = Rct(3)
End Sub
Public Function RenderFillRect(Renderer As Long, ByVal x As Long, ByVal y As Long, ByVal dx As Long, ByVal dy As Long) As Long
Static Rect(0 To 3) As Long
Rect(0) = x: Rect(1) = y: Rect(2) = dx: Rect(3) = dy
RenderFillRect = New_c.cdeclCall(retLong, vTbl(SDL_RenderFillRect), Renderer, VarPtr(Rect(0)))
End Function
Public Function UpdateWindowSurface(Window As Long) As Long
UpdateWindowSurface = New_c.cdeclCall(retLong, vTbl(SDL_UpdateWindowSurface), Window)
End Function
Public Sub RenderPresent(Renderer As Long)
New_c.cdeclCall retVoid, vTbl(SDL_RenderPresent), Renderer
End Sub
Public Function PollEvent(eType As SDL_EventType) As Long
PollEvent = New_c.cdeclCall(retLong, vTbl(SDL_PollEvent), VarPtr(mEvt))
eType = mEvt.eType
End Function
Public Function Event_KeySym() As KeyCodeConstants
Event_KeySym = mEvt.eBytes(8) + 256& * mEvt.eBytes(9)
End Function
Public Sub FreeSurface(Surface As Long)
New_c.cdeclCall retVoid, vTbl(SDL_FreeSurface), Surface
End Sub
Public Sub DestroyRenderer(Renderer As Long)
New_c.cdeclCall retVoid, vTbl(SDL_DestroyRenderer), Renderer
End Sub
Public Sub DestroyWindow(Window As Long)
New_c.cdeclCall retVoid, vTbl(SDL_DestroyWindow), Window
End Sub
Private Sub Class_Terminate()
New_c.cdeclCall retVoid, vTbl(SDL_Quit)
End Sub
Here is "Sub Main()" code which implements the ChessBoard-example from the
SDL-WebSite, translated to VB6-Wrapper-Code...
The VB-Project needs a reference to RC5, and you should place the SDL2.dll
directly in the App.Path (beside the *.vbp) ... using the latest (win-x86) version
2.0.3 from the SDL-download page: https://www.libsdl.org/download-2.0.php
Code:
Option Explicit
Public SDL2 As New cSDL2
Sub Main()
Dim Window As Long, Renderer As Long, eType As SDL_EventType
If SDL2.Init(SDL_INIT_VIDEO) Then Err.Raise vbObjectError, , SDL2.GetError
'Create a Host-Window and a Renderer
Window = SDL2.CreateWindow("Chess-Board", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 560)
If Window = 0 Then Err.Raise vbObjectError, , SDL2.GetError
Renderer = SDL2.CreateRenderer(Window, SDL_RENDERER_ACCELERATED Or SDL_RENDERER_PRESENTVSYNC)
If Renderer = 0 Then Err.Raise vbObjectError, , SDL2.GetError
Do Until eType = SDL_QUIT_ Or (eType = SDL_KEYDOWN And SDL2.Event_KeySym = vbKeyEscape)
DrawChessBoard Renderer
SDL2.RenderPresent Renderer 'update the View (flipping the Backbuf, whilst waiting for VSync)
SDL2.PollEvent eType 'poll the Event-Status (before usage in the "Until"-condition at Loop-Entry)
Loop
SDL2.DestroyRenderer Renderer
SDL2.DestroyWindow Window
End Sub
Sub DrawChessBoard(Renderer As Long)
Dim Row&, Col&, x&, y&, dx&, dy&
SDL2.SetRenderDrawColor Renderer, 255, 255, 255
SDL2.RenderClear Renderer 'fill the entire render-area with the above color (white in this case)
SDL2.RenderGetViewport Renderer, x, y, dx, dy 'get the Size of the viewport
dx = dx \ 8: dy = dy \ 8 'adjust the retrieved client-area-dimensions to 1/8th
For Row = 0 To 7: For Col = Row Mod 2 To 7 Step 2 'now render any second chessboard-rectangle...
SDL2.SetRenderDrawColor Renderer, 0, 0, 0 '...with black color...
SDL2.RenderFillRect Renderer, Col * dx, Row * dy, dx, dy '... and fill it
Next Col, Row
End Sub
Then producing this:
Something to play around with... maybe it's a good start for your own Binding
(I think the VB6-community could use more such wrappers around OpenSource-libs -
. another good candidate would be e.g. libGit, which also exists in a Windows-version).