Software Archive
Read-only legacy content
17061 Discussions

A Dialog Box in a DLL

Intel_C_Intel
Employee
906 Views
I am using DF 5.0. I have a problem to call a simple Dialog Box written in DLL from VB. It can be compiled, but can not be called by VB. (just shutdown the VB project). It appears DlgInit can not initialize the Dialog box. Maybe in version 6.x, one can use DlgInitWithResourcehandle, but in version 5.0D, there is no such function. From reference manual, I found Dlginit is compatible with Window Dll. My example below is working perfectly in QuickWin, but not in DLL. Can anyone help?

subroutine dgbox1()
use dfwin
use dflogm
implicit none
!dec$ attributes dllexport, alias : "dgbox1" :: dgbox1
!DEC$OBJCOMMENT LIB:"USER32.LIB"
include 'resource.fd'
type (dialog) dlg
logical retlog
integer retint
retlog = DlgInit(idd_box,dlg)
if (.not. retlog) then
write (*,*) "Error: dialog not found"
endif
retint = dlgmodal(dlg)
call dlguninit(dlg)
end
Also I used resource editor to created a Dialog and my VB codes are
Declare sub dgbox1 lib "dgbox.dll" () in Module and
call dgbox in Form
0 Kudos
10 Replies
Jugoslav_Dujic
Valued Contributor II
906 Views
Um, the only place I'd expect DFLOGM to fail is DlgModal,
not DlgInit. Having taken a look into DlgInit, the only place
that might fail is call to .cpp routine DlgGetRes. Its equivalent
in Fortran is:

 
LOGICAL FUNCTION DlgGetRes(ID,lpDlgRsrc) 
 
USE DFWIN 
 
INTEGER:: hRsrc, hGlob 
INTEGER:: lpDlgRsrc 
 
hrsrc = FindResource( NULL, ID, RT_DIALOG ); 
 
IF (hrsrc == NULL) THEN 
   DlgGetRes=.FALSE. 
   RETURN 
END IF 
 
hGlob = LoadResource( NULL, hrsrc ) 
 
IF (hGlob == NULL) THEN 
   DlgGetRes=.FALSE. 
   RETURN 
END IF 
 
lpDlgRsrc = LockResource( hGlob ) 
 
END FUNCTION 


The documentation for FindResource says that, quote,

"hModule - A handle to the module whose executable file contains the resource. A value of NULL specifies the module handle associated with the image file that the operating system used to create the current process. "

It's not very clear, but it looks that the NULL in FindResource call
specifies that the resource should be looked for in calling VB program,
not in DLL itself.

If you're brave enough - and if it's important - I'd suggest that you
try to fix the problem by tweaking DFLOGM a little (my favourite sport :-)).

1) Copy DFLOGM.f90 from DevStudio/DF/Include into your project directory. Add it to the project.


2) Add the above code somewhere inside MODULE DFLOGM. Rename it
to, say, DlgGetRes1.


3) Change the following lines in DlgInit from


 
	type (DialogResource) dlgres, dlgres2 
                ... 
	if ( .not. DlgGetRes( id, dlgres ) ) then 
                ... 
                dlgres=dlgres2 

to
 
	type (DialogResource) dlgres, dlgres2 
                pointer(pdlgres,dlgres) 
                pointer(pdlgres2,dlgres2) 
               ... 
	if ( .not. DlgGetRes1( id, pdlgres) ) then 
               ... 
               pdlgres2=pdlgres 


4) Add the following code at the beginning of DlgGetRes1:

 
integer hModule 
hModule=GetModuleHandle('MyDllName.dll') 


replace NULLs in calls to FindResource and LoadResource with
hModule.

5) Compile the DLL & prey. In any case, try to debug carefully and
step into all functions in DFLOGM. I'm 99% sure I screwed up something
in the explanation above. The basic idea was to replace the DlgGetRes
with the one that searches for resource in DLL, not in calling VB exe...
Perhaps the last piece of code (involving GetModuleHandle) could have
been written more ellegantly, but right now I can't recall the way to
get the name of "this" module (exe or dll). Perhaps renaming of MODULE DFLOGM into something else will be necessary (I don't know the default search rules for modules). Even if this succeeds, you might have a problem later in DlgModal, since it calls GetHwndQQ(QWIN$FRAMEWINDOW), but then... post another message.

Regards

Jugoslav

P.S. Try to enclose the posted code in
 and 
HTML tags (replace ['s with <'s)... Forum software... sigh.
0 Kudos
Intel_C_Intel
Employee
906 Views
Jugoslav, thanks for the help. I need to study your approach. But I think DlgInit is the problem. Try this
subroutine dgbox()
use dfwin
use dflogm
!dec$ attributes dllexport, alias: "dgbox" :: dgbox
!dec$objcomment lib: "user32.lib"
logical retlog
integer retint
type(dialog) dlg
retlog = dlginit(idd_box, dlg)
if (.not. retlog) then
retlog = AllocConsole()
write(*,*) "Error, resource not found"
retlog = FreeConsole
else
retlog = dlgmodal(dlg)
endif
end subroutine dgbox

You can see it DlgInit = false.
0 Kudos
Intel_C_Intel
Employee
906 Views
Jugoslav, it does not work when I tried your approach. I can not even compiled the code. I got error message like Error: This statement is invalid in an INTERFACE block.
hModule = GetModuleHandle('MyDllName.dll')
Is there any other way to do this. I wish someone from Compaq can give an answer.
0 Kudos
Jugoslav_Dujic
Valued Contributor II
906 Views
Well, I did say "if you're brave enough" :-). And, as I promised, I did
screwed up something in the code. Finally, I did actually try to
modify DFLOGM.

Apparently, you inserted the DlgGetRes1 into INTERFACE section,
not into module itself. Let's start from the beginning... so, re-copy
original DFLOGM.f90, and do _only_ these two modifications:

Add the following DlgGetRes1 immediately before line
"END MODULE DFLOGM" (at the end of file):

 
LOGICAL FUNCTION DlgGetRes1(ID,DlgRsrc)    
 
USE DFWIN    
 
CHARACTER(LEN=20)::  szModuleName='dgbox.dll'C 
INTEGER:: ID, hRsrc, hGlob, hModule 
TYPE(DialogResource):: DlgRsrc 
 
hModule=GetModuleHandle(LOC(szModuleName)) 
 
hrsrc = FindResource( hModule, ID, RT_DIALOG );    
IF (hrsrc == NULL) THEN   
   DlgGetRes1=.FALSE.   
   RETURN   
END IF    
 
hGlob = LoadResource( hModule, hrsrc )    
IF (hGlob == NULL) THEN   
   DlgGetRes1=.FALSE.   
   RETURN   
END IF    
DlgRsrc%ptr = LockResource( hGlob )    
DlgGetRes1 = DlgRsrc%ptr .NE. 0 
 
END FUNCTION DlgGetRes1 


And only replace call to DlgGetRes (in DlgInit) with
call to DlgGetRes1. (Do not insert POINTER declarations etc.).
Now, recompile and try. It would be a good idea to put a
breakpoint at first line of DlgGetRes1 and watch return values
of functions, especially hModule.

I did not find time to try it with DLL - it
works in an .exe... I just think it should work in the DLL
also. Of course, the method is not universal, since it depends
on value of szModuleName (i.e. name of the dll itself)...

Regards
Jugoslav
0 Kudos
Intel_C_Intel
Employee
906 Views
Jugoslav, following the procedures you provided, it passed compile, and it seems DlgInit is initializing, but the Dialog Box is still not shown up. I guess it is what you talked erlier that DlgModal is a problem. Anyway to fix it? I really appreciate your time and help.
0 Kudos
Jugoslav_Dujic
Valued Contributor II
906 Views
What is the return value of DlgModal? Is it -1? If so, perhaps the problem is similar to the previous one: DialogBox tries to locate the resource in VB caller, not in Dll itself. Try adding the following lines in DlgModal:

 
  recursive function DlgModal ( dlg, hwndParent ) result  
  use dfwin 
  integer hModule 
  character*20::    szModuleName='dgbox.dll'C 
... 
  hModule=GetModuleHandle(LOC(szModuleName)) 
  if ( DialogBox (hModule, MAKEINTRESOURCE(dlg % dlgid), hwndParent, LOC(DlgProc) ) .eq. -1 ) then 
    r=-1 
    else 
      r = dlg % retval 
    end if 
... 


(Replace existing if (DlgDoModal...else...endif with the above block.)

Also, find the body of DlgProc function and add the following line immediately after "recursive function DlgProc(..."

!DEC$ATTRIBUTES STDCALL:: DlgProc

I hope that would finally fix the thing.

Regards

Jugoslav
0 Kudos
Intel_C_Intel
Employee
906 Views
Something was wrong when compile it. I got 58 error messages. I could not find Dialogbox defined anywhere in Dflogm.f90. Is that a problem? I tried several ways but got nowhere. I still need your kind help. Thanks
0 Kudos
Intel_C_Intel
Employee
906 Views
BTW, the return value is -1
0 Kudos
Jugoslav_Dujic
Valued Contributor II
906 Views
Unfortunately, time-zone difference makes this discussion lasting
for days. It looks as if I leave my job about at the same time when
you start yours :-(.

The fragment from DlgModal I posted yesterday is syntactically OK
(I tested it) and I think it does the job. You just have to be more
careful when editing. DlgModal already exists in DFLOGM; just
add lines

 
use dfwin 
integer:: hModule 
character(len=20):: szModuleName="dgbox.dll"C 


and replace the if-block in the original DlgModal with
the if-block in the above code.
DialogBox is not part of the DFLOGM module; it is a system
(API) function which can be accessed by putting USE DFWIN
as the first line of FUNCTION or MODULE.

If you still cannot solve the problem, please post first 4-5
error messages you get - and/or please leave your e-mail so
I could send you the working DFLOGM.

Regards
Jugoslav
0 Kudos
Intel_C_Intel
Employee
906 Views
Here is the error:
dflogm.lib(dflogm.obj) : error LNK2005: _DFLOGM_mp_LOG2INT@4 already defined in Dflogm.obj
dflogm.lib(dflogm.obj) : error LNK2005: _DFLOGM_mp_STRFOR2C@12 already defined in Dflogm.obj
dflogm.lib(dflogm.obj) : error LNK2005: _DFLOGM_mp_STRC2FOR@4 already defined in Dflogm.obj
dflogm.lib(dflogm.obj) : error LNK2005: _DFLOGM_mp_PADSTRFOR@8 already defined in Dflogm.obj

I really appreciate if you can e-maol me the DFLOmG.f90. My e-mail address is

rshen@hotmail.com
0 Kudos
Reply