DLLmain

General FreeBASIC programming questions.
Rens
Posts: 256
Joined: Jul 06, 2005 21:09

DLLmain

Postby Rens » Jun 01, 2010 18:59

I desperately need a function which run when a dll is started en when it is ended. I have tried making a dll with this (simpilfied) code:

Code: Select all

#Include Once "windows.bi"

Declare Sub TheStart()
Declare Sub TheEnd()

Extern "windows"
Function DllMain Alias "DllMain" (ByVal hModule As HMODULE,ByVal reason As Integer,ByVal lpReserved As LPVOID) As BOOL export
   Select Case reason
      Case DLL_PROCESS_ATTACH
         TheStart() 
      Case DLL_PROCESS_DETACH
         TheEnd()
   End Select 
   Return TRUE
End Function
Sub TheStart() Export
   ?"DLL started"
End Sub
Sub TheEnd() Export
   ?"Dll ended"   
End Sub
End Extern

No luck, 1 compiling error:

error symbol '_DllMain@12' is already defined.

Has someone some simple working code for me or can show me what is wrong with the code. I really appreciate it!
vdecampo
Posts: 2982
Joined: Aug 07, 2007 23:20
Location: Maryland, USA
Contact:

Postby vdecampo » Jun 01, 2010 19:20

Try this...

Code: Select all

#Include "windows.bi"

Function DllMain( hDllHandle As HINSTANCE,  nReason As DWORD, Reserved As LPVOID) As Integer
 
  Dim As Integer bSuccess = TRUE


  'Perform global initialization.

  Select Case ( nReason )
   
    Case DLL_PROCESS_ATTACH

      ' For optimization.
      DisableThreadLibraryCalls( hDllHandle )
     
      ' Initialization code here
     
     
    Case DLL_PROCESS_DETACH

      ' DeInitialization code here
     
  End Select
 
  Return bSuccess
 
End Function


-Vince
MichaelW
Posts: 3500
Joined: May 16, 2006 22:34
Location: USA

Postby MichaelW » Jun 01, 2010 19:37

I have never found any way to replace the DllMain that is automatically linked in when you build a DLL. The best I have been able to do is to put the necessary initialization code in an exported sub/function and call it from the main app.
dkl
Site Admin
Posts: 3221
Joined: Jul 28, 2005 14:45
Location: Germany

Postby dkl » Jun 01, 2010 19:39

Hello,

fbc usually emits the DllMain automatically, just like the implicit main() for a normal program. However, you can prevent it from doing that, and put in your own DllMain.

(simply having a DllMain function won't work, because that's mangled to DLLMAIN, and the default DllMain will still be emitted)

An example DllMain, containing the required calls to initialization routines:

Code: Select all

public function DllMain alias "DllMain" _
    ( _
        byval hinstDLL as HINSTANCE, _
        byval fdwReason as DWORD, _
        byval lpvReserved as LPVOID _
    ) as BOOL

    select case (fdwReason)
    case DLL_PROCESS_ATTACH
        __main( )
        fb_Init( 0, NULL, 0 )

    case DLL_PROCESS_DETACH

    case DLL_THREAD_ATTACH

    case DLL_THREAD_DETACH

    end select

    return 1
end function


You can either put that in your main module, and trick fbc into believing it isn't the main module:
fbc my_dll.bas -dll -m foobar

or put it in a separate module.
fbc my_dll.bas -c
fbc my_dllmain.bas -c
fbc my_dll.o my_dllmain.o -dll


Note that you must be very careful about what you do in DllMain and what not. For example, it's a bad idea to load other DLLs (LoadLibrary). This also means functions from other DLLs shouldn't be called, except for kernel32. (This is because of possible dead locks in Windows' DLL loader, not because of FreeBASIC)
Rens
Posts: 256
Joined: Jul 06, 2005 21:09

Postby Rens » Jun 01, 2010 20:58

Thank you very much.

The reason i must have startup and exit code in the dll is to close and open a COM port before and after executing other code in the dll for a infrared related electronics projects.

The problem is that if the communication port is not closed before or after then my pc locks up, have to cold reset my pc and wait a long time till checkdisks is ready.
Last edited by Rens on Jun 01, 2010 22:13, edited 1 time in total.
Rens
Posts: 256
Joined: Jul 06, 2005 21:09

Postby Rens » Jun 01, 2010 21:54

@MichaelW,

That doesn't work in this case because if there is a error in the main module then there is no way i can close the COM ports and my pc locks up. The dll must do it for me.

@Dkl
I don't really get it. Thought it was as simple as in Delphi.

my_dll.bas

Code: Select all

#Include Once "windows.bi"

Extern "windows"
Sub TheStart() Export
   ?"DLL started"
End Sub
Sub TheEnd() Export
   ?"Dll ended"   
End Sub
End Extern


foobar.bas

Code: Select all

#Include Once "windows.bi"
Public Function DllMain Alias "DllMain" _
    ( _
        Byval hinstDLL As HINSTANCE, _
        Byval fdwReason As DWORD, _
        Byval lpvReserved As LPVOID _
    ) As BOOL

    Select Case (fdwReason)
       Case DLL_PROCESS_ATTACH
          ?"here"
        fb_Init( 0, NULL, 0 )
         ?"or here"
    Case DLL_PROCESS_DETACH

    Case DLL_THREAD_ATTACH

    Case DLL_THREAD_DETACH

    End Select

    Return 1
End Function
Dim As String filename

FileName =  "foobar.dll"

Dim h As hinstance
h=loadlibrary("foobar.dll" )
freelibrary( h )
Sleep
End

fbc my_dll.bas -dll -m foobar


No luck! Compiles fine, but nothing happens. Whats wrong?

Now i think about it, is there another way to have a sub or function somewhere in memory which can do the startup and closedown code for me?
dkl
Site Admin
Posts: 3221
Joined: Jul 28, 2005 14:45
Location: Germany

Postby dkl » Jun 01, 2010 22:26

Sorry, let me explain: The DllMain goes into 'my_dll.bas'. Don't create a 'foobar.bas'. The purpose of '-m foobar' is to trick fbc into believing that 'my_dll' is *not* the main module, so that no default DllMain() gets added.

This is 'my_dll.bas':

Code: Select all

#include "windows.bi"

sub test() export
end sub

Public Function DllMain Alias "DllMain"  _
    ( _
        Byval hinstDLL As HINSTANCE, _
        Byval fdwReason As DWORD, _
        Byval lpvReserved As LPVOID _
    ) As BOOL

    Select Case (fdwReason)
    Case DLL_PROCESS_ATTACH
        __main( )
        fb_Init( 0, NULL, 0 )

        '' being loaded

    Case DLL_PROCESS_DETACH

        '' being unloaded

    Case DLL_THREAD_ATTACH

    Case DLL_THREAD_DETACH

    End Select

    Return 1
End Function

It can be compiled with:
fbc my_dll.bas -dll -m blabla
dkl
Site Admin
Posts: 3221
Joined: Jul 28, 2005 14:45
Location: Germany

Postby dkl » Jun 01, 2010 22:37

You know what, does it have to be DllMain()?

FB has module constructors/destructors, that could do exactly what you need.

An example:

Code: Select all

'' fbc my_dll.bas -dll
sub ctor() constructor
    print "DLL loaded"
end sub

sub dtor() destructor
    print "DLL unloaded"
end sub

sub test() export
    print "test"
end sub


Code: Select all

'' fbc test.bas
#inclib "my_dll"
declare sub test()
test()
Rens
Posts: 256
Joined: Jul 06, 2005 21:09

Postby Rens » Jun 01, 2010 23:38

YES,

Real clever, easy to follow and works like a charm.

You know what, does it have to be DllMain()?


The next time i will remind myself to be more specific.

Thank you dkl
recode
Posts: 12
Joined: Feb 10, 2009 6:58

Postby recode » Jul 27, 2010 18:25

makedll.bas

Code: Select all

'fbc -s console

#Include "windows.bi"
#include "crt/stdlib.bi"

Function main(argc As Integer, argv As ZString Ptr Ptr) As Integer
   Dim As ZString * 256 CodeFile
   Dim As ZString * 256 ExtName
   If argc >= 2 Then
      CodeFile = *argv[1]
      CodeFile = Left(CodeFile, Len(CodeFile) - 4)
      system_(ExePath & "\fbc -c " & CodeFile & ".bas")
      
      If argc = 4 Then
         ExtName = *argv[3]
         system_(ExePath & "\fbc -dll " & CodeFile & ".o -x " & ExtName)
      Else
         system_(ExePath & "\fbc -dll " & CodeFile & ".o")
      EndIf
      
      
   EndIf
   
   Return 0
   
End Function

main(__FB_ARGC__, __FB_ARGV__)


copy makedll.exe to fbc folder.
usr
makedll.exe codefile.bas
or
makedll.exe codefile.bas -x extname.dll

in fbedit. compile command is makedll.exe
vbman
Posts: 3
Joined: Nov 09, 2008 15:23
Location: Kirovohrad, Ukraine

YES!

Postby vbman » Aug 03, 2010 12:46

FreeBASIC Dll (ded.bas):

Code: Select all

#Include Once "windows.bi"
#Include Once "win/winnt.bi"

Extern "windows-ms"
Function Msg() As DWORD Export
   Return Cast(DWORD,1UL)
End Function
End Extern

Public Function Main(   ByVal hinstDLL As HINSTANCE, _
                 ByVal fdwReason As DWORD, _
                 Byval lpvReserved As LPVOID ) As DWORD
   Dim s As String
   
   Select Case fdwReason
      Case DLL_PROCESS_ATTACH
         s="DLL_PROCESS_ATTACH"
         
      Case DLL_PROCESS_DETACH
         s="DLL_PROCESS_DETTACH"
   End Select
   
   MessageBox 0,s,0,MB_ICONHAND
   Return Cast(DWORD,1UL)
End Function


Compile:
C:\FreeBASIC\fbc -s gui -dll -export -Wl " --entry _MAIN@12" "ded.bas"

-r - crashes to create a dll file ???
AnotherLife
Posts: 94
Joined: Feb 07, 2011 22:48

Re: DLLmain

Postby AnotherLife » Nov 23, 2013 20:00

Bump.

Just had to do that stuff to get my DllMain working. Maybe there should be a switch or something so that we don't have to fool the compiler to avoid it creating its own DllMain.

Also, a dll without exports is valid, but the compiler forces us to have at least one. It shouldn't.
dkl
Site Admin
Posts: 3221
Joined: Jul 28, 2005 14:45
Location: Germany

Re: DLLmain

Postby dkl » Nov 23, 2013 20:19

Maybe a -nomain command line option? (that could also be used from source code once something like an #fbc statement is added)

DLLs without export should build ok in the next release, the problem has been fixed in the development version of FB: [71e87f19].
AnotherLife
Posts: 94
Joined: Feb 07, 2011 22:48

Re: DLLmain

Postby AnotherLife » Nov 23, 2013 20:26

Great news. Is it possible for the compiler in the case of dll linking to see if the main module contains a DllMain function ? If it does, it uses that one. So it wouldn't need a new cmdline option. I think it won't break existing projects that use the current method, right ?

Return to “General”

Who is online

Users browsing this forum: No registered users and 6 guests