Using dflogm dialogs from a DLL called by VB6

Using dflogm dialogs from a DLL called by VB6

greebie's picture

Dear All,

I'm having no success in initiating dialog boxes from a Fortran DLL used from VB6.
The DLGINITWITHRESOURCEHANDLE function always returns false. I've constructed
a simple example based on ones on the Compaq online documentation. Can anybody
see what I'm doing wrong?

Thanks,

Russell Millar

=================
Fortran Code
===================

!===================================================================
! Code copied from DLGINITWITHRESOURCEHANDLE documentation example
!===================================================================
module dll_globals
integer(4) ghInst ! DLL instance handle
end module dll_globals

!********************************************************************
!* FUNCTION: DllMain(HANDLE, DWORD, LPVOID)
!*
!* PURPOSE: DllMain is called by Windows when
!* the DLL is initialized, Thread Attached, and other times.
!* Refer to SDK documentation, as to the different ways this
!* may be called.
!*
!* The DllMain function should perform additional initialization
!* tasks required by the DLL. DllMain should return a value of 1
!* if the initialization is successful.
!*
!*********************************************************************

integer(4) function DllMain (hInst, ul_reason_being_called, lpReserved)
!DEC$ ATTRIBUTES DLLEXPORT :: DllMain
!DEC$ ATTRIBUTES ALIAS:'DllMain' :: DllMain

use dll_globals

integer(4) hInst
integer(4) ul_reason_being_called
integer(4) lpReserved

! Save the module instance handle in a global variable
! This would typically be in a Module or a COMMON block.
ghInst = hInst

DllMain = 1
return
end

!===================================================================
! Modified Compaq DLL VB6 example
! Fortran part of a VB-Fortran DLL example. This
! routine DLL_ROUT is called from a VB executable
! program.
!===================================================================

SUBROUTINE DLL_ROUT (STR_IN, STR_OUT)
! Specify that DLL_ROUT is exported to a DLL
! and that the external name is 'DLL_ROUT'
!DEC$ ATTRIBUTES DLLEXPORT :: DLL_ROUT
!DEC$ ATTRIBUTES ALIAS:'DLL_ROUT' :: DLL_ROUT

USE DFLOGM
USE dll_globals
IMPLICIT NONE
INCLUDE "resource.fd"
CHARACTER*(*) STR_IN, STR_OUT
type (DIALOG) dlg
logical lret
integer iret

lret = DLGINITWITHRESOURCEHANDLE (IDD_DIALOG1, ghInst, dlg)
if (lret) then
iret = DlgModal(dlg)
call DlgUninit(dlg)
STR_OUT=STR_IN // "succeeded"
else
STR_OUT=STR_IN // "failed"
end if


RETURN
END

================================
VB6 base module
=================================

Option Explicit

Declare Sub DLL_ROUT Lib _
"C:Documents and SettingsRussellMy DocumentsMyVBStuffDLLPlayFCALL4DebugFCALL4.dll" _
(ByVal STR_IN As String, ByVal STR_IN_LEN As Long, _
ByVal STR_OUT As String, ByVal STR_OUT_LEN As Long)

Declare Function DllMain Lib _
"C:Documents and SettingsRussellMy DocumentsMyVBStuffDLLPlayFCALL4DebugFCALL4.dll" _
(hInst As Long, Int1 As Long, Int2 As Long) As Long

====================
VB Form1
====================

Option Explicit
Private hInst As Long
Private Int1 A
s Long
Private Int2 As Long
Private Flag As Long

Private Sub Command1_Click()

Static STR_IN As String * 10, STR_OUT As String * 20
STR_IN = "Test..."
Int1 = 1
Int2 = 2

hInst = App.hInstance
'TextBox1.Text = "hinstance=" & hInst & _
", Flag=" & Flag

Flag = DllMain(hInst, Int1, Int2)

'Pass lengths of string arguments
Call DLL_ROUT(STR_IN, Len(STR_IN), STR_OUT, Len(STR_OUT))

TextBox1.Text = STR_OUT & ", hinstance=" & hInst & _
", Flag=" & Flag
End Sub


5 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.
Jugoslav Dujic's picture

A brief explanation first: HINSTANCE or HMODULE is Windows' handle of a module -- an exe or a dll. Physically, it presents base (starting) address of module's code+data+resources. Resource-management function need this handle to "see" where they should start looking at requested resource (dialog in this case).
hInstance for .exes always have value of 0x00400000 because that's the default start of .exe's address space in virtual memory. For .dlls, it's another value.

Are you sure DllMain is actually being called? If I recall correctly, the compiler supplies the default entry-point function if you don't write it -- but if you do, you have to say it to the linker in Project Settings/Link/Output/Entry-point symbol.

Besides, your DllMain looks wrong: hInst is passed by value, but it isn't specified in your DllMain -- without a VALUE or STDCALL modifier, it is being read as by reference, i.e. it contains garbage.

So, it should be:

integer(4) function DllMain (hInst, ul_reason, lpReserved)
!DEC$ ATTRIBUTES DLLEXPORT, STDCALL :: DllMain

use dll_globals

integer(4) hInst, ul_reason, lpReserved

ghInst = hInst

DllMain = 1
end function DllMain

Also, specify

dllmain@8

(case matters) as entry-point symbol in linker settings.

Jugoslav

Jugoslav www.xeffort.com
Jugoslav Dujic's picture

...ah, I missed that call to DllMain in your VB code -- it explains a lot. You mustn't call DllMain explicitly -- you shouldn't even dllexport it. DllMain is automatically called by Windows when the dll is loaded (thus the need to specify it in linker settings). What you were doing is to pass hInstance of VB .exe -- DlgInitWithResourceHandle was trying to load the dialog from VB exe, not from your dll, and thus it failed.

Jugoslav www.xeffort.com
Jugoslav Dujic's picture

...d'oh, it should be dllmain@12, obviously :-(

Jugoslav www.xeffort.com
greebie's picture

Jugoslav,

Thanks for the clear explanation - worked first time after making the changes.

I've been running DLL's that hadn't used a DllMain, and I hadn't realized
the special role of a DllMain when used in a DLL.

Russell

Login to leave a comment.