Direct funtion call works - CALLFUNCTION() does not

Just starting out? Need help? Post your questions and find answers here.
Ludo
User
User
Posts: 40
Joined: Thu Oct 16, 2008 12:55 pm
Location: Belgium-Tiegem

Direct funtion call works - CALLFUNCTION() does not

Post by Ludo »

Hi,

A weird problem that makes me think of a bug ... Or - lack of knowlegde :oops:

Some background to start with ...

I'm trying to write a program where different functional blocks are run from different external DLLs. Think of it as e.g. an object oriented drafting program.

By definition, all these external DLLs will have the same interface format/functions, I only attach one as a demo (ccDll1.pbi) as a sort of template - I stripped the code as much as possible. So by definition, they all have to use the same common structure definitions (ccCommon.pbi).

The approach is an object oriented approach with virtual tables. Every DLL is supposed to represent one type of an object (think square, circle, box, sphere ...). Object types are simply named after the DLL name.

Every object and it's related gadgets are hooked to an *Objects()-item and go inside a containergadget so that they're isolated from the rest. Apart from the interface-definitions and some conventions, the calling program (cc.pb) is not supposed to know anything about the internals of the DLLs. Everyone who knows the ccCommon.pbi and sticks to the conventions, should be able to write a DLL without knowing about the main program (cc.pb). The goal is that DLLs can be added without having to touch/recompile the main program.

I'm running PB 5.31-x86 on 64 bit Windows 7.

Now, the problem ...

In the example, I'm creating 4 instances/objects from the same DLL/type with the AddObject() procedure.

When running the program so that it calls the Create() procedure directly from the DLL (tweak the constant #CallDirect to do so) then the 4 containers with their gadgets show. Also, when exiting the program, all is nicely cleaned and the program terminates normal.

When running the program so that CallFunction() is used, or CallFunctionFast(), with or without prototypes, then the first topleft container is not showing but the 3 others do. When exiting this program, the program crashes.

Even though only 3 objects actually shown on screen, the 4 objects can be seen in the debugger.


Calling the Create() procedure directly, is not an option as by definition, the Create() will have to be in all DLLs - it needs to be called in some "library-oriented" manner ... :shock:



I can't explain - hopefully, somebody else can. Maybe I'm just doing something wrong.

Any suggestions on coding style and/or approach are welcomed.

Thanks,
Ludo


Main program (cc.pb)

Code: Select all

EnableExplicit

XIncludeFile("ccCommon.pbi")

#Calldirect=#True ; set to true for calling the function directly, set to false fo using the library-calls

CompilerIf #Calldirect
   XIncludeFile("ccDll1.pbi")  ; include only when trying to call directly 
CompilerEndIf

Enumeration
   #MainWindow
   #G_Objects
   #G_Libraries
   #G_Container
EndEnumeration

Global MainEvent
Global MainGadget
Global MainEventType

Global NewList *Objects.ObjectInterface()
Global NewMap Libraries.L()
Global NewMap CreateAddresses.L()

Global cntObject=-1
Global libName.s

Prototype.i MyCreatePrototype(WindowID.L,pX.L,pY.L,lW.L,lH.L,lID.L,lType.S)

Procedure LoadDLLs()
Protected tmpDir,libName.S,libNum

tmpDir=ExamineDirectory(#PB_Any,"","cc*.dll")
If tmpDir
   ClearGadgetItems(#G_Libraries)
   While NextDirectoryEntry(tmpDir)
      libName.S=ReplaceString(DirectoryEntryName(tmpDir),".dll","")
      AddGadgetItem(#G_Libraries,-1,libName)  
      libNum=OpenLibrary(#PB_Any,libName)
      Libraries(libName)=libNum      
      CreateAddresses(libName)=GetFunction(libNum,"Create")
   Wend
   FinishDirectory(tmpDir)
EndIf
EndProcedure

Procedure AddObject(libName.s)
Protected MyCreate.MyCreatePrototype=CreateAddresses(libName)

cntObject=cntObject+1
AddElement(*Objects())

CompilerIf #Calldirect

; when calling the create function directly, all containers show 
   *Objects()=Create(WindowID(#MainWindow),10+Int(cntObject/3)*150,100+150*Mod(cntObject,3),140,140,cntObject,libName)
CompilerElse

; when calling the create function with any of these methods, the first "container" does not show. 
   *Objects()=MyCreate(WindowID(#MainWindow),10+Int(cntObject/3)*150,100+150*Mod(cntObject,3),140,140,cntObject,libName)
   ;*Objects()=CallFunction(Libraries(libName),"Create",WindowID(#MainWindow),10+Int(cntObject/3)*150,100+150*Mod(cntObject,3),140,140,cntObject,libName)
   ;*Objects()=CallFunctionFast(CreateAddresses(libName),WindowID(#MainWindow),10+Int(cntObject/3)*150,100+150*Mod(cntObject,3),140,140,cntObject,libName)
CompilerEndIf

EndProcedure

If OpenWindow(#MainWindow,10,10,500,600,"CC")
   ComboBoxGadget(#G_Libraries,5,5,200,22)
   UseGadgetList(WindowID(#MainWindow))
   LoadDLLs()
   
   AddObject("ccDll1")
   AddObject("ccDll1")
   AddObject("ccDll1")
   AddObject("ccDll1")
   
   Repeat
      MainEvent=WaitWindowEvent(0)
      
      If MainEvent=#PB_Event_Gadget
         MainGadget=EventGadget()
         MainEventType=EventType()
         
         Select MainGadget
            Case #G_Libraries
               libName.s=GetGadgetText(#G_Libraries)
               Debug libName
               AddObject(libName)
         EndSelect
         
      EndIf
      
   Until MainEvent=#PB_Event_CloseWindow
EndIf

ForEach *Objects()
   *Objects()\Free()
Next


Main include file (ccCommon.pbi) :

Code: Select all

; definitions

Interface ObjectInterface 
   Initialize()
   Free()
   Set()
   Get()
   Gadgets()
   Update()
EndInterface

Structure Buffer ; output buffers
   Address.L
   Type.L
   Size.L
   Name.s
EndStructure

Structure VTableStructure ; The *VTable structure  
   Initialize.L
   Free.L
   Set.L
   Get.L
   Gadgets.L
   Update.L
EndStructure 

Structure ObjectStructure
   *VTable.VTableStructure
   Type.s{32}
   Name.L
   Container.L
   x.L
   y.L
   w.L
   h.L
EndStructure

DLL-file (ccDll1.pbi) :

Code: Select all

EnableExplicit

XIncludeFile "ccCommon.pbi"

Structure Dll1Structure Extends ObjectStructure
   Dll1Gadget.L
EndStructure

ProcedureDLL Initialize()
MessageRequester("euuh","init")
EndProcedure

ProcedureDLL Free(*This.DLL1Structure)
OpenGadgetList(*This\Container)
FreeGadget(*This\Name)
FreeGadget(*This\Dll1Gadget)
CloseGadgetList()
FreeGadget(*This\Container)
FreeMemory(*This)
EndProcedure

ProcedureDLL Set()
MessageRequester("euuh","set")
EndProcedure

ProcedureDLL Get()
MessageRequester("euuh","get")
EndProcedure

ProcedureDLL Gadgets()
MessageRequester("euuh","gadgets")
EndProcedure

ProcedureDLL Update()
MessageRequester("euuh","update")
EndProcedure

ProcedureDLL.L Create(WindowID.L,pX.L,pY.L,lW.L,lH.L,lID.L,lType.S)

Protected tmpGadget
Protected tmpStr.s=lType

Protected ttt.s=Str(windowid)+Chr(10)+"x:"+Str(px)+" y:"+Str(py)+" w:"+Str(lw)+" h:"+Str(lh)+Chr(10)+Str(lid)+" "+tmpStr
MessageRequester("parameter",ttt)

Protected *Ptr.Dll1Structure=AllocateMemory(SizeOf(Dll1Structure))
*Ptr\Vtable=?FunctionTable

tmpGadget=ContainerGadget(#PB_Any,pX,pY,lW,lH,#PB_Container_Flat)
*Ptr\Container=tmpGadget
*Ptr\Type=tmpStr
*Ptr\w=lW
*Ptr\h=lH
*Ptr\Name=TextGadget(#PB_Any,0,0,100,20,tmpStr+" "+Str(lID))
*Ptr\Dll1Gadget=StringGadget(#PB_Any,10,20,50,20,Str(lID))
CloseGadgetList()
UseGadgetList(WindowID)
ProcedureReturn *Ptr
EndProcedure

DataSection
   FunctionTable:
   Data.L @Initialize()
   Data.L @Free()
   Data.L @Set()
   Data.L @Get()
   Data.L @Gadgets()
   Data.L @Update()
EndDataSection
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Direct funtion call works - CALLFUNCTION() does not

Post by luis »

Ludo wrote: When running the program so that CallFunction() is used, or CallFunctionFast(), with or without prototypes, then the first topleft container is not showing but the 3 others do. When exiting this program, the program crashes.
Uhmm... for the first problem:

UseGadgetList() is not required for the "included code" version for obvious reasons, but it's required in the "dll version" because otherwise, being the main window created elsewhere, the container does not know about the default gadgetlist created when opening the main window and simply does not appear, right ?
In that case I think you should move the UseGadgetList(WindowID) before the tmpGadget=ContainerGadget(#PB_Any,pX,pY,lW,lH,#PB_Container_Flat) and all four containers should appear.

About the crash, I cannot say.
Looks to me it has again something to do with UseGadgetList() and the fact the window is created elsewhere, and if that's the case I don't know if it is a bug or not. If you remove UseGadgetList() it stops crashing ?
I don't really know what you are allowed to do in a DLL when you are creating some PB GUI elements there, what it's supposed to work or not and I don't have any real experience with that, so beyond the fact it seems to me the problem could lie there, I cannot help you.

I hope someone else will chime in.
"Have you tried turning it off and on again ?"
A little PureBasic review
Ludo
User
User
Posts: 40
Joined: Thu Oct 16, 2008 12:55 pm
Location: Belgium-Tiegem

Re: Direct funtion call works - CALLFUNCTION() does not

Post by Ludo »

Thanks Luis - moving the UseGadgetList() indeed now shows the first container. I seems like it cannot be assumed that a called DLL knows about "current window".

Nevertheless, the crashing is still there... :cry:

It happens after the "freeing" construct (ForEach/Next).

Ludo
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Direct funtion call works - CALLFUNCTION() does not

Post by luis »

Ludo wrote:Thanks Luis - moving the UseGadgetList() indeed now shows the first container. I seems like it cannot be assumed that a called DLL knows about "current window".
Yes.
Ludo wrote: Nevertheless, the crashing is still there... :cry:
It happens after the "freeing" construct (ForEach/Next).
I think it just happens when unloading the DLL, it has nothing to do IMO with your freeing of the objects or using prototypes opposed to callfunction() etc.

Try to add CloseWindow(#MainWindow) as the last instruction in the main test program.

EDIT: I've just tried it and it fixes the crash for me.
"Have you tried turning it off and on again ?"
A little PureBasic review
Ludo
User
User
Posts: 40
Joined: Thu Oct 16, 2008 12:55 pm
Location: Belgium-Tiegem

Re: Direct funtion call works - CALLFUNCTION() does not

Post by Ludo »

Indeed Luis - fixed the crash for me too.
But something else is weird. It looks as of the whole thing with Usegadgetlist() / Opengadgetlist() does not work when in DLLs.
I'm one a small test-program right now. Will post when usefull.
Ludo
User
User
Posts: 40
Joined: Thu Oct 16, 2008 12:55 pm
Location: Belgium-Tiegem

Re: Direct funtion call works - CALLFUNCTION() does not

Post by Ludo »

Really something weird. I'm not even sure how to understand the results.

Application builds a couple of windows with some container/gadgets.
The call to the DLL is supposed to add a stringgadget to the windows/container.

It surprises me that the gadgets are added and visual on the screen ...
... but the gadget in the second window seems to be lost
... no matter what, isgadget() is finding the gadgets added in the main program
... no matter what, isgadget() is never finding the gadgets added in the DLL
... isgadget() with the DLL is never returning something usefull when checking the containergadget

And also - without the closewindow() at the end, the program crashes.

Really in doubt here ...

Ludo



test_container_dll.pbi -> test_container_dll.dll

Code: Select all

Enumeration 0
   #MainWindow
   #MainButton
   
   #SecondWindow
   #SecondButton
   #SecondContainer
EndEnumeration

ProcedureDLL addcontainer(WindID,ContGadget)
Protected somevar

MessageRequester("Start    ",Str(IsGadget(ContGadget)))

UseGadgetList(WindID)
MessageRequester("After UGL",Str(IsGadget(ContGadget)))

If ContGadget>0
OpenGadgetList(ContGadget)
MessageRequester("After OGL",Str(IsGadget(ContGadget)))
EndIf

somevar=StringGadget(#PB_Any,60,60,200,20,"DLL'd")

If ContGadget>0
CloseGadgetList()
EndIf

ProcedureReturn somevar

EndProcedure


test_container.pb -> test_container.exe

Code: Select all

Enumeration 0
   #MainWindow
   #MainButton
   
   #SecondWindow
   #SecondButton
   #SecondContainer
EndEnumeration

OpenLibrary(0,"test_container_dll.dll")

OpenWindow(#MainWindow,10,10,500,500,"main")
ButtonGadget(#MainButton,10,10,100,20,"Useless")

OpenWindow(#SecondWindow,200,200,400,400,"second",#PB_Window_SystemMenu,WindowID(#MainWindow))
;UseGadgetList(WindowID(#SecondWindow))
ContainerGadget(#SecondContainer,5,5,300,300,#PB_Container_Flat)
ButtonGadget(#SecondButton,10,10,100,20,"Contained")
CloseGadgetList()

tmpvar1=CallFunction(0,"addcontainer",WindowID(#SecondWindow),#SecondContainer)
tmpvar2=CallFunction(0,"addcontainer",WindowID(#MainWindow),0)
Debug tmpvar1
Debug tmpvar2
Debug ""

UseGadgetList(WindowID(#MainWindow))
Debug IsGadget(#MainButton)
Debug IsGadget(#SecondContainer)
Debug IsGadget(#SecondButton)
Debug IsGadget(tmpvar1)
Debug IsGadget(tmpvar2)
Debug ""

UseGadgetList(WindowID(#SecondWindow))
Debug IsGadget(#MainButton)
Debug IsGadget(#SecondContainer)
Debug IsGadget(#SecondButton)
Debug IsGadget(tmpvar1)
Debug IsGadget(tmpvar2)
Debug ""

OpenGadgetList(#SecondContainer)
Debug IsGadget(#MainButton)
Debug IsGadget(#SecondContainer)
Debug IsGadget(#SecondButton)
Debug IsGadget(tmpvar1)
Debug IsGadget(tmpvar2)
Debug ""

Repeat
Until WaitWindowEvent(1)=#PB_Event_CloseWindow

CloseWindow(#MainWindow)



User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Direct funtion call works - CALLFUNCTION() does not

Post by luis »

I think it's normal, I'll explain when I get back if no one does it first.
I'm outside running :mrgreen:
"Have you tried turning it off and on again ?"
A little PureBasic review
Ludo
User
User
Posts: 40
Joined: Thu Oct 16, 2008 12:55 pm
Location: Belgium-Tiegem

Re: Direct funtion call works - CALLFUNCTION() does not

Post by Ludo »

Some further narrowing of what I suppose is the problem ...
The question gets easier : why is the "addcontainer" call not adding to the container, but to the gadgetlist of the mainwindow ?

It should be adding to the container. :?

Is this "fixable" with WinAPI calls - whatever ?

Ludo

test_container.pb -> test_container.exe

Code: Select all

Enumeration 
   #MainWindow
   #MainButton
   
   #SecondButton
   #SecondContainer
EndEnumeration

OpenLibrary(0,"test_container_dll.dll")

OpenWindow(#MainWindow,10,10,500,500,"main")
StringGadget(#MainButton,10,10,100,20,"Useless")

ContainerReference=ContainerGadget(#SecondContainer,45,245,300,300,#PB_Container_Flat)
ButtonGadget(#SecondButton,10,30,100,20,"Contained")
CloseGadgetList()

; WHY IS THIS NOT ADDING A GADGET TO THE CONTAINER ? 
tmpvar1=CallFunction(0,"addcontainer",WindowID(#MainWindow),#SecondContainer,100,100)

MessageRequester("wait ...","before setting 1")
CallFunction(0,"setcontainer",WindowID(#MainWindow),#SecondContainer,tmpvar1,12345)

MessageRequester("wait ...","before setting 2")
CallFunction(0,"setcontainer",WindowID(#MainWindow),#SecondContainer,tmpvar1,34567)

MessageRequester("wait ...","before hide")
HideGadget(#SecondContainer,1)

MessageRequester("wait ...","after hide")
HideGadget(#SecondContainer,0)

Repeat
Until WaitWindowEvent(1)=#PB_Event_CloseWindow

CloseWindow(#MainWindow)

test_container_dll.pbi -> test_container_dll.dll

Code: Select all


ProcedureDLL addcontainer(WindID,ContGadget,x,y)
Protected somevar
UseGadgetList(WindID)
OpenGadgetList(ContGadget)
somevar=StringGadget(#PB_Any,x,y,200,20,"in container ?")
CloseGadgetList()
ProcedureReturn somevar
EndProcedure

ProcedureDLL setcontainer(WindID,ContGadget,StrGadget,value)
Protected somevar
UseGadgetList(WindID)
OpenGadgetList(ContGadget)
SetGadgetText(StrGadget,Str(value))
CloseGadgetList()
ProcedureReturn somevar
EndProcedure
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Direct funtion call works - CALLFUNCTION() does not

Post by luis »

Here I am, I'll try to keep it short.
These are basically deductions, but should be correct enough.

A DLL is basically an EXE (don't laugh), which you can import in the address space of your program and from which you can call selected functions you decided to make accessible (exported).
It has its own data, separated from the main program which is using it.
That explains why you can get #true from a IsGadget() in the main program when applied to a local gadget, but you get #false if you call IsGadget() with that same id from inside the DLL, or if you call IsGadget() in the main program with an id returned by a PB command executed inside the DLL.
In short, the PB code executed in the DLL keeps its own data tables with info about the gadgets created there, and the same does the main exe.
They are not shared.
This has the consequences you see in your last snippet, when you pass to addcontainer() the id of a gadget created in the main exe. The PB code inside the DLL does not have it listed in its local tables, so OpenGadgetList(ContGadget) fails and the new gadget ends up outside the container in the main window's gadgetlist.
Also you should notice UseGadgetList(WindID) does not have a PB id as param, but a handle ( WindowID(#MainWindow) ) and being this OS specific (and so system wide) it can cross the DLL barrier and it's valid in both the environment.

That's why your original code, with the two fixes here discussed, was able to work.

What you are doing is running a single PB program with GUI elements splitted in two different exe which can communicate to each other to SOME EXTENT.
But are still two separated entities.

It's probably possible to make this work "properly" is some way, but as I said I don't know for certain what you are supposed to be able to do or not in a DDL when PB GUI elements are involved, I don't know about PB internals, and I don't want to go there anyway. The above is something I discovered by trying things similar to what you are doing but probably there are many more surprises in store.

Anyway, this is what you were looking for in your last post I think:

Code: Select all

Enumeration
   #MainWindow
   #MainButton
   
   #SecondButton
   #SecondContainer
EndEnumeration

OpenLibrary(0,"test_container_dll.dll")

OpenWindow(#MainWindow,1000,10,500,500,"main")
StringGadget(#MainButton,10,10,100,20,"Useless")

ContainerReference=ContainerGadget(#SecondContainer,45,245,300,300,#PB_Container_Flat)
ButtonGadget(#SecondButton,10,10,100,20,"Contained")
CloseGadgetList()

; WHY WAS SOMETHING SIMILAR TO THIS NOT ADDING A GADGET TO THE CONTAINER ?
tmpvar1=CallFunction(0,"addcontainer",WindowID(#MainWindow),GadgetID(#SecondContainer),10,50)
tmpvar2=CallFunction(0,"addcontainer",WindowID(#MainWindow),GadgetID(#SecondContainer),10,80)
tmpvar3=CallFunction(0,"addcontainer",WindowID(#MainWindow),GadgetID(#SecondContainer),10,110)

Repeat
Until WaitWindowEvent(1)=#PB_Event_CloseWindow

CloseWindow(#MainWindow)

Code: Select all

ProcedureDLL addcontainer(WindID,ContGadgetID,x,y)
Protected somevar, previd
previd = UseGadgetList(ContGadgetID) ; bleah, will it explode ? who knows
somevar=StringGadget(#PB_Any,x,y,200,20,"in container ?")
UseGadgetList(previd)
ProcedureReturn somevar
EndProcedure
PS: If you want to use something affected by this problem, like IsGadget() in the main exe on a object built in the DLL, export from the DLL a "DDL_IsGadget()" which wraps IsGadget(). That way you can call DDL_IsGadget() from your main exe and successfully test for a gadget created in the DLL.

PPS: I think it would be a good idea to drop all the .L stuff unless a long is really REQUIRED -> http://www.purebasic.fr/blog/?p=42
"Have you tried turning it off and on again ?"
A little PureBasic review
Ludo
User
User
Posts: 40
Joined: Thu Oct 16, 2008 12:55 pm
Location: Belgium-Tiegem

Re: Direct funtion call works - CALLFUNCTION() does not

Post by Ludo »

:D

Now, this is exactly what I want it to do. An hey ho, your explanation actually explains it ! 8)

From now on, the working name of my program will be Luis !

Thanks a lot.

Ludo



P.S. : I was aware of the .L thing - but it's like any other bad habbit - but while on 32bit only, it wouldn't harm too much. I'm afraid I have lots of code with the .L is still around ... :oops: If only I had the time ...


P.S. @Fred @Andre - the documentation of usegadgetlist() is confusing in that sense that it clearly hints for a WindowID where it seems to be more than "the ID of a Window".
Ludo
User
User
Posts: 40
Joined: Thu Oct 16, 2008 12:55 pm
Location: Belgium-Tiegem

Re: Direct funtion call works - CALLFUNCTION() does not

Post by Ludo »

@Luis - well, it almost works as expected. :?

I expanded the test-code a little bit, to include two instances, and to have more gadgets.

While the button/string gadgets are working as hoped for, the combobox and the canvasgadget are not yielding events in the main window.
Is there an explanation for these ?

Would these have to be treated differently ? I can imagine these events are locked up in the DLLs as well, and I need to "message" them to the main window somehow ?

Ludo

Code: Select all

Enumeration 
   #MainWindow
   #MainButton
   
   #SecondButton
   #SecondContainer

   #ThirdButton
   #ThirdContainer
EndEnumeration

OpenLibrary(0,"test_container_dll.dll")

OpenWindow(#MainWindow,10,10,1000,500,"main")
StringGadget(#MainButton,10,10,100,20,"Not contained")
tmp=CanvasGadget(#PB_Any,30,30,50,50,#PB_Canvas_Border)
StartDrawing(CanvasOutput(tmp))
Circle(5,5,5,RGB(0,255,0))
StopDrawing()
tmp=ComboBoxGadget(#PB_Any,230,50,200,20)
AddGadgetItem(tmp,-1,"test a")
AddGadgetItem(tmp,-1,"test b")

ContainerReference=ContainerGadget(#SecondContainer,45,145,400,300,#PB_Container_Flat)
ButtonGadget(#PB_Any,0,0,15,15,"")
CloseGadgetList()

ContainerReference=ContainerGadget(#ThirdContainer,545,145,400,300,#PB_Container_Flat)
ButtonGadget(#PB_Any,0,0,15,15,"") 
CloseGadgetList()

; WHY IS THIS NOT WORKING WITH COMBOBOX AND CANVASGADGET ?

tmpvar1=CallFunction(0,"addcontainer",WindowID(#MainWindow),GadgetID(#SecondContainer),100,100)
CallFunction(0,"setcontainer",WindowID(#MainWindow),GadgetID(#SecondContainer),tmpvar1,12345)
CallFunction(0,"setcontainer",WindowID(#MainWindow),GadgetID(#SecondContainer),tmpvar1,34567)

tmpvar2=CallFunction(0,"addcontainer",WindowID(#MainWindow),GadgetID(#ThirdContainer),100,100)
CallFunction(0,"setcontainer",WindowID(#MainWindow),GadgetID(#ThirdContainer),tmpvar2,12345)
CallFunction(0,"setcontainer",WindowID(#MainWindow),GadgetID(#ThirdContainer),tmpvar2,34567)

Repeat
   Mainevent=WaitWindowEvent(1)
   Select Mainevent
      Case #PB_Event_Gadget
         Debug EventGadget()
   EndSelect
Until Mainevent=#PB_Event_CloseWindow

CloseWindow(#MainWindow)


Code: Select all

ProcedureDLL addcontainer(WindID,ContGadget,x,y)
Protected somevar,prevID

prevID=UseGadgetList(ContGadget)
StringGadget(#PB_Any,x,y,200,20,"in container ?")
ButtonGadget(#PB_Any,x,y+25,200,20,"in container ?")
tmp2=ComboBoxGadget(#PB_Any,x,y+50,200,20)
AddGadgetItem(tmp2,-1,"contained 1")
AddGadgetItem(tmp2,-1,"contained 2")
tmp3=CanvasGadget(#PB_Any,x,y+90,100,20,#PB_Canvas_Border)
StartDrawing(CanvasOutput(tmp3))
Circle(5,5,5,RGB(255,0,0))
StopDrawing()
UseGadgetList(prevID)

ProcedureReturn somevar
EndProcedure

ProcedureDLL setcontainer(WindID,ContGadget,StrGadget,value)
Protected somevar
prevID=UseGadgetList(ContGadget)
SetGadgetText(StrGadget,Str(value))
UseGadgetList(prevID)
ProcedureReturn somevar
EndProcedure
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Direct funtion call works - CALLFUNCTION() does not

Post by luis »

Ludo wrote:While the button/string gadgets are working as hoped for, the combobox and the canvasgadget are not yielding events in the main window.
Is there an explanation for these ?
Certainly, but unfortunately I don't know it.
"Have you tried turning it off and on again ?"
A little PureBasic review
Ludo
User
User
Posts: 40
Joined: Thu Oct 16, 2008 12:55 pm
Location: Belgium-Tiegem

Re: Direct funtion call works - CALLFUNCTION() does not

Post by Ludo »

When setting a windowscallback, I see do see messages flying around. It's "only" :? a matter of understanding the contents of the lparams en wparams.
So I might get somewhere after the study ...
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Direct funtion call works - CALLFUNCTION() does not

Post by luis »

To avoid all these problems, and more, I tell you what I would do (if not exactly like this, something along these lines).

You seem to want to build gui elements in your dll, but then process their events in your main program where the window is created.

But you are even doing a mix in your examples, creating containers in the main program and populating them in the dll.

See if you can do all the "adding of gui elements" in dll. If not what follows is probably still doable with some small additions.

You could write a proc in your DLL, let's call it SendGUIRequest(). That must call a GetGUIRequest() you will have in your main progam.
It will be in a include, available to every "main program" you want to write.
In every DLL you export a RegisterGUIRequest(). You call it from the "main" program after loading the DLL to pass the address of GetGUIRequest() so the DLL knows how to call it.

Every time you want to add an element from inside a DLL, you call SendGUIRequest() and pass a structure with data. A different structure for each type of gui element.

The first byte in the structure identify the type of data (a buttongadget, a container, whatever) and the struct is filled with the appropriate data (coordinates, flags, strings etc).
The structures definitions are again in the same include above, to be available to all the the "main" programs and the "dll" objects.

SendGUIRequest() in turn calls GetGUIRequest() in the main passing a pointer to the structure.
In GetGUIRequest() you have a select case, which uses the first byte at the pointer address to know what type of structure is following the base address, and you cast the generic pointer to a structured pointer of the appropriate type. Now you can access all the data in the structure and you can call the correspondent ButtonGadget(), ContainerGadget(), etc. to actually create the gui element in the main program. When you need to do multistep actions, like when you need to populate a combobox gadget you just created, you get the return value from GetGUIRequest() identifying the remote PB object it has created (valid locally only to the main program) and in the subsequent SendGUIRequest() you will make to add data to the combobox gadget you will pass that object ID back in the structure, so the remote "main" know the gui element you want to operate on.

That way, you can build gui elements from the dll, but they are created in the main, and you have no problem with events, gadgetlists, isgadget, etc.

If that's not applicable to what you have in mind, see if you can adapt this general idea to your specs.

Anyway, it's just a suggestion, could be off the mark. Good luck :wink:
"Have you tried turning it off and on again ?"
A little PureBasic review
Ludo
User
User
Posts: 40
Joined: Thu Oct 16, 2008 12:55 pm
Location: Belgium-Tiegem

Re: Direct funtion call works - CALLFUNCTION() does not

Post by Ludo »

Hi Luis,

The containers in the main, and rest of the GUI in the DLLs was done deliberately : in my thinking, that meant that whatever the DLLs do, all additional GUI-elements created would be isolated from the rest (and indeed they are, but only a little bit too much :mrgreen: ) : the containers under control of the main (hiding/moving/displaying), the internal GUI-elements under control of the DLL.

Nevertheless, I believe I understand the :idea: you're sharing. Food for tought and sleepless nights.

As the main program doesn't need/want to know what the DLL actually does, it can only handle it's own elements, and the handling of the events related to the DLL is to be done by the DLL. The same principle can be followed here : when it's about an event for the DLLs, I can call a DLL-procedure to process it - which again be definition need to be in all DLLs. Hope this makes sense too.

I'm very grateful you want to share these ideas. I'll post a framework here when I get it to work.


Ludo
Post Reply