Windowed DLL GUI (+bug ?)
Posted: Sat Feb 07, 2015 7:58 pm
****************************************************************
*** updated with object oriented examples (vtables)
*** added a simple DLL-validation
****************************************************************
Initially, I tried to make an application that was able to run DLLs with GUi elements inside a containergadget.
@Luis : thank for your suggestions and help.
http://www.purebasic.fr/english/viewtop ... =4&t=61559
The last few days, I took a sidestep, and tried to put these in child-windows, which to my
seems to works better then hoped for - tought I should share with all. Please forward any feedback and suggestions.
By no means, the code is finished nor polished. In the end the DLLs management should eventually go "object oriented with virtual tables" etc., the main program should query the DLLs for properties and capabilities such required screen size, shared inputs, outputs ... But the basics are there.
Remember : I am not a pro at all, so there may be oddities in there.
The idea is to have a main program that opens DLLs inside windows (when clicking the buttons). The windows as such are under control of the main calling program, the GUI-parts within the assigned windows are handled by the DLLs. The DLLs also have to handle their own gadgets etc ... The DLLs have to follow a minimal set of conventions (required functions e.g.), the main program doesn't want to know anything about the DLLs.
Luis suggested to stay away from the #WM_COMMAND stuff - at the time of write, I'm glad he did
A couple of weird things occured to me however. @Fred : this is really feels to me like a bug ...
I would really hope to find an explanation here.
The thing is : the example ddl2 contains a lot of gadgets within their own window. It surprises me that some gadgets such as listviewgadget() report to their own windows, but the buttongadget() some others are not. These are reporting to the main calling program. That might well be lack of understanding, but nevertheless feels like awkward.
Eventually, I added a bit of code in the main program that intercepts the gadget events from the child windows, and forwards them back to the originating window. This might be a bit clumsy and way of the beaten tracks, but it seems to work.
The DLLs need few functions (and again I learnt it the hard way : names are case sensitive) :
[*] AttachProcess() : define the global variables here
[*] Create() : initalize the variables and create the GUI elements - only ran once
[*] HandleEvents() : is run every cycle to allow the DLL to handle the local events, and also the ones forwarded by the main program
[*] Run() : is run every cycle to do things - whatever
Please let me know what you think and/or suggestions for improvements.
Below are the demo-programs - running PB 5.31 on Windows 8.
Ludo
Main calling program
Include file that goes in all : WindowedDLLCommon.pbi
minimal framework dll
OpenGL example (rework of Purebasic demoprogram)
Example with just a log of gadgets
*** updated with object oriented examples (vtables)
*** added a simple DLL-validation
****************************************************************
Initially, I tried to make an application that was able to run DLLs with GUi elements inside a containergadget.
@Luis : thank for your suggestions and help.
http://www.purebasic.fr/english/viewtop ... =4&t=61559
The last few days, I took a sidestep, and tried to put these in child-windows, which to my



By no means, the code is finished nor polished. In the end the DLLs management should eventually go "object oriented with virtual tables" etc., the main program should query the DLLs for properties and capabilities such required screen size, shared inputs, outputs ... But the basics are there.
Remember : I am not a pro at all, so there may be oddities in there.
The idea is to have a main program that opens DLLs inside windows (when clicking the buttons). The windows as such are under control of the main calling program, the GUI-parts within the assigned windows are handled by the DLLs. The DLLs also have to handle their own gadgets etc ... The DLLs have to follow a minimal set of conventions (required functions e.g.), the main program doesn't want to know anything about the DLLs.
Luis suggested to stay away from the #WM_COMMAND stuff - at the time of write, I'm glad he did

A couple of weird things occured to me however. @Fred : this is really feels to me like a bug ...

The thing is : the example ddl2 contains a lot of gadgets within their own window. It surprises me that some gadgets such as listviewgadget() report to their own windows, but the buttongadget() some others are not. These are reporting to the main calling program. That might well be lack of understanding, but nevertheless feels like awkward.

Eventually, I added a bit of code in the main program that intercepts the gadget events from the child windows, and forwards them back to the originating window. This might be a bit clumsy and way of the beaten tracks, but it seems to work.
The DLLs need few functions (and again I learnt it the hard way : names are case sensitive) :
[*] AttachProcess() : define the global variables here
[*] Create() : initalize the variables and create the GUI elements - only ran once
[*] HandleEvents() : is run every cycle to allow the DLL to handle the local events, and also the ones forwarded by the main program
[*] Run() : is run every cycle to do things - whatever
Please let me know what you think and/or suggestions for improvements.
Below are the demo-programs - running PB 5.31 on Windows 8.
Ludo
Main calling program
Code: Select all
XIncludeFile "WindowedDLLCommon.pbi"
Enumeration
#MainWindow
#GLib
#GObjects
#GListView
#GFrameRate
EndEnumeration
Structure DLLInfo
Name.s
Library.i
CreateAddress.i
EndStructure
Global NewMap DLLs.DLLInfo()
Global NewList *Objects.WindowedDLLInterface()
Global tmpDir.i,tmpLib.i
Global libName.s
Procedure OpenDLLs()
Protected lcount,tmpDir,tmpName,tmpLib
tmpDir=ExamineDirectory(#PB_Any,"","*.dll")
;first, examine all the DLLs in the folder
While NextDirectoryEntry(tmpDir)
libName=DirectoryEntryName(tmpDir)
tmpLib=OpenLibrary(#PB_Any,libName)
If tmpLib
AddMapElement(DLLs(),libName)
DLLs(libName)\Name=libName
DLLs(libName)\Library=tmpLib
If GetFunction(tmpLib,"Validate") And CallFunction(tmpLib,"Validate")=#WDLL_Validation
DLLs(libName)\CreateAddress=GetFunction(tmpLib,"Create") ; remember, so the we can callfunctionfast()
EndIf
EndIf
Wend
FinishDirectory(tmpDir)
; then clear out which are invalid
ForEach(DLLs())
If Dlls()\CreateAddress=0
CloseLibrary(Dlls()\Library)
DeleteMapElement(Dlls())
Else
lcount=lcount+1
EndIf
Next
ProcedureReturn lcount
EndProcedure
Procedure MoveWindows()
Protected px=WindowX(#MainWindow),py=WindowY(#MainWindow),npx,npy,wind
*oldelement=@*Objects() ;remember the current element
ForEach(*Objects())
npx=*Objects()\GetP(#WDLL_x)
npy=*Objects()\GetP(#WDLL_y)
wind=*Objects()\GetP(#WDLL_Window)
ResizeWindow(wind,px+npx,py+npy,#PB_Ignore,#PB_Ignore)
Next
ChangeCurrentElement(*Objects(),*oldelement) ; and set it back afterwards - otherwise crash !
EndProcedure
; *************************************
;-*** MAIN PROGRAM STARTS HERE ***
; *************************************
; Developed by Ludo Roose - free to use
; Thanks to Luis @ Purebasic forum for spending lots of his time
; Thanks to all who shared stuff on the forum
; PB 5.31 - Windows
OpenDLLs()
OpenWindow(#MainWindow,10,10,1400,700,"Windowed DLLs")
ComboBoxGadget(#GLib,10,10,200,22) ; list DLLs
ForEach(DLLs())
AddGadgetItem(#GLib,-1,DLLs()\Name)
Next
StringGadget(#GFrameRate,10,40,90,20,"0") ; list framerate
ListViewGadget(#GListView,10,70,480,60) ; list local events
AddGadgetItem(#GListView,-1,Str(#GListView))
AddGadgetItem(#GListView,-1,Str(GadgetID(#GListView)))
ObjectCount=0
Loopcount=0
LoopTime=ElapsedMilliseconds()+1000
BindEvent(#PB_Event_MoveWindow,@MoveWindows())
offsx=3
offsy=200
Repeat
If ElapsedMilliseconds()>LoopTime
SetGadgetText(#GFrameRate,Str(Loopcount))
LoopTime=ElapsedMilliseconds()+1000
Loopcount=0
Else
Loopcount=Loopcount+1
EndIf
SomeEvent=#False
ForEach(*Objects())
*Objects()\HandleEvents(0,0,0)
*Objects()\Run()
Next
MainEvent=WindowEvent()
If MainEvent
MainEventWindow=EventWindow()
MainGadget=EventGadget()
MainEventType=EventType()
If MainEventWindow<>#MainWindow
ForEach(*Objects()) ; could be done with a map too ? maybe faster ?
If *Objects()\GetP(#WDLL_Window)=MainEventWindow
AddGadgetItem(#GListView,0,"FWD >>> "+Str(MainEventWindow)+" "+Str(MainEvent)+" "+Str(MainGadget)+" "+Str(MainEventType))
*Objects()\HandleEvents(MainEvent,MainGadget,MainEventType)
Break
EndIf
Next
Else
If MainEvent=#PB_Event_Gadget
AddGadgetItem(#GListView,0,"MAIN >>> "+Str(MainEventWindow)+" "+Str(MainEvent)+" "+Str(MainGadget)+" "+Str(MainEventType))
EndIf
EndIf
If MainEvent=#PB_Event_Gadget
Select EventGadget()
Case #GLib
ObjectCount=ObjectCount+1
tmpLibname.s=GetGadgetText(#GLib)
tmpName.s=tmpLibname+" "+Str(ObjectCount)
AddElement(*Objects())
tmpWin=OpenWindow(#PB_Any,WindowX(#MainWindow)+offsx,WindowY(#MainWindow)+offsy,50,50,"test",#PB_Window_BorderLess,WindowID(#MainWindow))
ButtonGadget(#PB_Any,1,1,15,15,"°")
tmpWinID=WindowID(tmpWin)
*Objects()=CallFunction(DLLs(tmpLibName)\Library,"Create",@tmpName,tmpWin,tmpWinID)
*Objects()\SetP(#WDLL_Window,tmpWin)
*Objects()\SetP(#WDLL_WindowID,tmpWindID)
*Objects()\SetP(#WDLL_x,offsx)
*Objects()\SetP(#WDLL_y,offsy)
ResizeWindow(tmpWin,#PB_Ignore,#PB_Ignore,*objects()\GetP(#WDLL_Width),*Objects()\GetP(#WDLL_Height))
offsx=offsx+*objects()\GetP(#WDLL_Width)+1
EndSelect
EndIf
EndIf
Until MainEvent=#PB_Event_CloseWindow
CloseWindow(#MainWindow)
Include file that goes in all : WindowedDLLCommon.pbi
Code: Select all
Enumeration
#WDLL_Name
#WDLL_Window
#WDLL_WindowID
#WDLL_x
#WDLL_y
#WDLL_Width
#WDLL_Height
; more to come here ...
EndEnumeration
#WDLL_Validation=3256680939 ; any random number
Structure WindowedDLL ; basic structure, custom DLLs must extend these
Vtable.i
name.s{32}
Window.i
WindowID.i
x.i
y.i
Width.i
Height.i
thumbWidth.i
thumbHeight.i
minWidth.i
minHeight.i
Variables.i
EndStructure
Interface WindowedDLLInterface ; must be defined for every DLL
Create(*Name,Window,WindowID)
Run()
HandleEvents(ExtEvent,ExtGadget,ExtEventType)
Get()
Set()
GetP(Item)
SetP(Item,Value,Value2=0)
EndInterface
ProcedureDLL SetP(*This.WindowedDLL,Item,Value,Value2=0)
; set private properties of the window
; only to be used for stuff that is common to all DLLs
Select Item
Case #WDLL_Window
*This\Window=Value
Case #WDLL_WindowID
*This\WindowID=Value
Case #WDLL_x
*This\x=Value
Case #WDLL_y
*This\y=Value
Default
ProcedureReturn 0
EndSelect
EndProcedure
ProcedureDLL GetP(*This.WindowedDLL,Item)
; get private properties of the window
; only to be used for stuff that is common to all DLLs
Select Item
Case #WDLL_Window
ProcedureReturn *This\Window
Case #WDLL_WindowID
ProcedureReturn *This\WindowID
Case #WDLL_x
ProcedureReturn *This\x
Case #WDLL_y
ProcedureReturn *This\y
Case #WDLL_Width
ProcedureReturn *This\Width
Case #WDLL_Height
ProcedureReturn *This\Height
Default
ProcedureReturn 0
EndSelect
EndProcedure
ProcedureDLL Validate()
; make sure the DLL is compliant
ProcedureReturn #WDLL_Validation
EndProcedure
minimal framework dll
Code: Select all
EnableExplicit
XIncludeFile "WindowedDLLCommon.pbi"
Structure FrameWorkWindowedDLL Extends WindowedDLL ; always build a local structure that extends on WindowedDLL
;custom code from here
Gadget.i ;***
;to here
EndStructure
ProcedureDLL AttachProcess(Instance)
Global *this.FrameWorkWindowedDLL ; make sure to create a global object
EndProcedure
ProcedureDLL Create(*Name,Window,WindowID)
Protected prevID=UseGadgetList(WindowID)
*this.FrameWorkWindowedDLL=AllocateMemory(SizeOf(FrameWorkWindowedDLL))
*this\Vtable=?WindowedDLLTable
*this\name=PeekS(*name)
*this\Width=80
*this\Height=70
;custom GUI building and initalization code from here
*this\Gadget=StringGadget(#PB_Any,5,30,70,20,"framework")
FrameGadget(#PB_Any,0,0,*this\Width,*this\Height,"",#PB_Frame_Flat)
;to here
UseGadgetList(prevID)
ProcedureReturn *this
EndProcedure
ProcedureDLL Run(*this.FrameWorkWindowedDLL)
; put code here that needs to run every cycle
EndProcedure
ProcedureDLL HandleEvents(*this.FrameWorkWindowedDLL,ExtEvent,ExtGadget,ExtEventType)
If Not ExtEvent ; nothing was passed from the main program
ExtEvent=WindowEvent()
ExtGadget=EventGadget()
ExtEventType=EventType()
EndIf
; put code here to handle local events
EndProcedure
ProcedureDLL Get(*this.FrameWorkWindowedDLL)
; put code here the retrieve information from your object
EndProcedure
ProcedureDLL Set(*this.FrameWorkWindowedDLL)
; put code here that sets information in your object
EndProcedure
DataSection
WindowedDLLTable:
Data.i @Create()
Data.i @Run()
Data.i @HandleEvents()
Data.i @Get()
Data.i @Set()
Data.i @GetP()
Data.i @SetP()
EndDataSection
OpenGL example (rework of Purebasic demoprogram)
Code: Select all
EnableExplicit
XIncludeFile "WindowedDLLCommon.pbi"
Structure GLWindowedDLL Extends WindowedDLL
GOpenGL.i
RollAxisX.f
RollAxisY.f
RollAxisZ.f
RotateSpeedX.f
RotateSpeedY.f
RotateSpeedZ.f
ZoomFactor.f ; Distance of the camera. Negative value = zoom back
GZoomIn.i
GZoomOut.i
NextRun.i
EndStructure
ProcedureDLL AttachProcess(Instance)
Global *this.GLWindowedDLL
EndProcedure
ProcedureDLL Run(*This.GLWindowedDLL)
If ElapsedMilliseconds()>*this\NextRun
SetGadgetAttribute(*this\GOpenGL, #PB_OpenGL_SetContext, #True)
glPushMatrix_() ; Save the original Matrix coordinates
glMatrixMode_(#GL_MODELVIEW)
glTranslatef_(0, 0, *this\ZoomFactor) ; move it forward a bit
glRotatef_ (*this\RollAxisX, 1.0, 0, 0) ; rotate around X axis
glRotatef_ (*this\RollAxisY, 0, 1.0, 0) ; rotate around Y axis
glRotatef_ (*this\RollAxisZ, 0, 0, 1.0) ; rotate around Z axis
*this\RollAxisX + *this\RotateSpeedX
*this\RollAxisY + *this\RotateSpeedY
*this\RollAxisZ + *this\RotateSpeedZ
; clear framebuffer And depth-buffer
glClear_(#GL_COLOR_BUFFER_BIT | #GL_DEPTH_BUFFER_BIT)
; draw the faces of a cube
; draw colored faces
glDisable_(#GL_LIGHTING)
glBegin_(#GL_QUADS)
; Build a face, composed of 4 vertex !
; glBegin() specify how the vertexes are considered. Here a group of
; 4 vertexes (GL_QUADS) form a rectangular surface.
; Now, the color stuff: It's r,v,b but with float values which
; can go from 0.0 To 1.0 (0 is .. zero And 1.0 is full intensity)
glNormal3f_(0,0,1.0)
glColor3f_(0,0,1.0)
glVertex3f_(0.5,0.5,0.5)
glColor3f_(0,1.0,1.0)
glVertex3f_(-0.5,0.5,0.5)
glColor3f_(1.0,1.0,1.0)
glVertex3f_(-0.5,-0.5,0.5)
glColor3f_(0,0,0)
glVertex3f_(0.5,-0.5,0.5)
; The other face is the same than the previous one
; except the colour which is nice blue To white gradiant
glNormal3f_(0,0,-1.0)
glColor3f_(0,0,1.0)
glVertex3f_(-0.5,-0.5,-0.5)
glColor3f_(0,0,1.0)
glVertex3f_(-0.5,0.5,-0.5)
glColor3f_(1.0,1.0,1.0)
glVertex3f_(0.5,0.5,-0.5)
glColor3f_(1.0,1.0,1.0)
glVertex3f_(0.5,-0.5,-0.5)
glEnd_()
; draw shaded faces
glEnable_(#GL_LIGHTING)
glEnable_(#GL_LIGHT0)
glBegin_ (#GL_QUADS)
glNormal3f_( 0, 1.0, 0)
glVertex3f_ ( 0.5, 0.5, 0.5)
glVertex3f_ ( 0.5, 0.5,-0.5)
glVertex3f_ (-0.5, 0.5,-0.5)
glVertex3f_ (-0.5, 0.5, 0.5)
glNormal3f_ (0,-1.0,0)
glVertex3f_ (-0.5,-0.5,-0.5)
glVertex3f_ (0.5,-0.5,-0.5)
glVertex3f_ (0.5,-0.5,0.5)
glVertex3f_ (-0.5,-0.5,0.5)
glNormal3f_ (1.0,0,0)
glVertex3f_ (0.5,0.5,0.5)
glVertex3f_ (0.5,-0.5,0.5)
glVertex3f_ (0.5,-0.5,-0.5)
glVertex3f_ (0.5,0.5,-0.5)
glNormal3f_ (-1.0, 0, 0)
glVertex3f_ (-0.5,-0.5,-0.5)
glVertex3f_ (-0.5,-0.5, 0.5)
glVertex3f_ (-0.5, 0.5, 0.5)
glVertex3f_ (-0.5, 0.5,-0.5)
glEnd_()
glPopMatrix_()
glFinish_()
SetGadgetAttribute(*this\GOpenGL, #PB_OpenGL_FlipBuffers, #True)
*this\NextRun=ElapsedMilliseconds()+1000/60-1 ; about 60 Hz = framerate of display
EndIf
EndProcedure
Procedure SetupGL()
glMatrixMode_(#GL_PROJECTION)
gluPerspective_(30.0, 200/200, 1.0, 10.0)
; position viewer
glMatrixMode_(#GL_MODELVIEW)
glTranslatef_(0, 0, -5.0)
glEnable_(#GL_DEPTH_TEST) ; Enabled, it slowdown a lot the rendering. It's to be sure than the
; rendered objects are inside the z-buffer.
glEnable_(#GL_CULL_FACE) ; This will enhance the rendering speed as all the back face will be
; ignored. This works only with CLOSED objects like a cube... Singles
; planes surfaces will be visibles only on one side.
glShadeModel_(#GL_SMOOTH)
EndProcedure
ProcedureDLL HandleEvents(*This.GLWindowedDLL,ExtEvent,ExtGadget,ExtEventType)
If Not ExtEvent ; nothing was passed from the main program
ExtEvent=WindowEvent()
If ExtEvent=#PB_Event_Gadget
ExtGadget=EventGadget()
ExtEventType=EventType()
EndIf
EndIf
If ExtEvent=#PB_Event_Gadget
If ExtGadget=*this\GZoomIn
*this\ZoomFactor=*this\ZoomFactor/0.7
ProcedureReturn #True
ElseIf ExtGadget=*this\GZoomOut
*this\ZoomFactor=*this\ZoomFactor*0.7
ProcedureReturn #True
EndIf
EndIf
ProcedureReturn #False
EndProcedure
ProcedureDLL Create(*Name,Window,WindowID)
Protected previd=UseGadgetList(WindowID)
*This.GLWindowedDLL=AllocateMemory(SizeOf(GLWindowedDLL))
*This\Vtable=?WindowedDLLTable
*This\name=PeekS(*name)
*this\NextRun=ElapsedMilliseconds()+14
*this\RollAxisX.f=0
*this\RollAxisY.f=0
*this\RollAxisZ.f=0
*this\RotateSpeedX.f = 1.0
*this\RotateSpeedY.f = 0
*this\RotateSpeedZ.f = 1.0
*this\ZoomFactor.f = 1.0 ; Distance of the camera. Negative value = zoom back
SetWindowColor(Window,Random($FFFFFF)) ; just for the fun
*this\GOpenGL=OpenGLGadget(#PB_Any,25,25,200,200)
SetupGL()
*this\GZoomIn=ButtonGadget(#PB_Any,10,240,50,20,"+")
*this\GZoomOut=ButtonGadget(#PB_Any,70,240,50,20,"-")
*this\Width=240
*this\Height=270
UseGadgetList(previd)
ProcedureReturn *This
EndProcedure
ProcedureDLL Get(*This.GLWindowedDLL)
EndProcedure
ProcedureDLL Set(*This.GLWindowedDLL)
EndProcedure
DataSection
WindowedDLLTable:
Data.i @Create()
Data.i @Run()
Data.i @HandleEvents()
Data.i @Get()
Data.i @Set()
Data.i @GetP()
Data.i @SetP()
EndDataSection
Example with just a log of gadgets
Code: Select all
EnableExplicit
XIncludeFile "WindowedDLLCommon.pbi"
Structure Dll2WindowedDLL Extends WindowedDLL
GList.i
GComboBox.i
GButton.i
GCanvas.i
GCheckBox.i
GImage.i
IImage.i
GSpin.i
delayTime.i
nextUpdate.i
EndStructure
; make these variables global for the DLL, but don't assign values
Procedure AttachProcess(instance)
Global *this.Dll2WindowedDLL
EndProcedure
; just to report that the "globals" are visible
ProcedureDLL ReportThings(*this.Dll2WindowedDLL)
AddGadgetItem(*this\GList,-1,"------------------")
AddGadgetItem(*this\GList,-1,Str(*this\GButton))
AddGadgetItem(*this\GList,-1,Str(*this\GCanvas))
AddGadgetItem(*this\GList,-1,Str(*this\GCheckBox))
AddGadgetItem(*this\GList,-1,Str(*this\GImage))
AddGadgetItem(*this\GList,-1,Str(*this\delayTime))
AddGadgetItem(*this\GList,-1,Str(*this\nextUpdate))
EndProcedure
; try to handle events
ProcedureDLL HandleEvents(*this.Dll2WindowedDLL,ExtEvent,ExtGadget,ExtEventType)
If Not ExtEvent ; nothing was passed from the main program
ExtEvent=WindowEvent()
If ExtEvent=#PB_Event_Gadget
ExtGadget=EventGadget()
ExtEventType=EventType()
EndIf
EndIf
If ExtEvent=#PB_Event_Gadget
Select ExtGadget
Case *this\GComboBox
AddGadgetItem(*this\GList,0,"lib "+GetGadgetText(*this\GComboBox))
ProcedureReturn #True
Default
AddGadgetItem(*this\GList,0,"lib "+Str(ExtEvent)+" "+Str(ExtGadget)+" "+Str(ExtEventType))
ProcedureReturn #True
EndSelect
EndIf
ProcedureReturn #False
EndProcedure
; the "run" will be called every windows cycle, as a sort of "callback()"
; you can do things here
ProcedureDLL Run(*this.Dll2WindowedDLL)
If ElapsedMilliseconds()>*this\nextUpdate
SetGadgetState(*this\GSpin,GetGadgetState(*this\GSpin)+1)
*this\nextUpdate=*this\nextUpdate+*this\delayTime
EndIf
EndProcedure
; build the GUI, initialize variables
ProcedureDLL Create(*Name,Window,WindowID)
Protected previd
previd=UseGadgetList(WindowID)
*this.Dll2WindowedDLL=AllocateMemory(SizeOf(Dll2WindowedDLL))
*this\Vtable=?WindowedDLLTable
*this\name=PeekS(*name)
*this\delayTime=200+Random(5000)
*this\nextUpdate=ElapsedMilliseconds()
*this\Width=390
*this\Height=480
SetWindowColor(Window,Random($FFFFFF))
*this\GComboBox=ComboBoxGadget(#PB_Any,10,10,370,25)
AddGadgetItem(*this\GComboBox,-1,Str(*this\GComboBox)+":"+Str(GadgetID(*this\GComboBox)))
AddGadgetItem(*this\GComboBox,-1,Str(WindowID))
SetGadgetState(*this\GComboBox,1)
*this\GCanvas=CanvasGadget(#PB_Any,10,40,370,50,#PB_Canvas_Border)
StartDrawing(CanvasOutput(*this\GCanvas))
DrawText(0,0,Str(*this\GCanvas)+":"+Str(GadgetID(*this\GCanvas)))
StopDrawing()
*this\GButton=ButtonGadget(#PB_Any,10,100,200,20,"")
SetGadgetText(*this\GButton,Str(*this\GButton)+":"+Str(GadgetID(*this\GButton)))
*this\GCheckBox=CheckBoxGadget(#PB_Any,220,100,150,20,"CBG")
*this\GList=ListViewGadget(#PB_Any,10,140,370,200)
AddGadgetItem(*this\GList,-1,Str(*this\GList))
AddGadgetItem(*this\GList,-1,Str(GadgetID(*this\GList)))
*this\GImage=ImageGadget(#PB_Any,10,350,370,20,0)
*this\IImage=CreateImage(#PB_Any,370,20)
StartDrawing(ImageOutput(*this\IImage))
DrawText(0,0,Str(*this\GImage)+":"+Str(GadgetID(*this\GImage))+" < "+Str(*this\IImage)+":"+Str(ImageID(*this\IImage)))
StopDrawing()
SetGadgetState(*this\GImage,ImageID(*this\IImage))
*this\GSpin=SpinGadget(#PB_Any,10,400,200,20,0,1000,#PB_Spin_Numeric)
SetGadgetState(*this\GSpin,0)
UseGadgetList(previd)
ProcedureReturn *this
EndProcedure
ProcedureDLL Get(*This.WindowedDLL)
EndProcedure
ProcedureDLL Set(*This.WindowedDLL)
EndProcedure
DataSection
WindowedDLLTable:
Data.i @Create()
Data.i @Run()
Data.i @HandleEvents()
Data.i @Get()
Data.i @Set()
Data.i @GetP()
Data.i @SetP()
EndDataSection