I try to display a splash screen at startup. The SplashScreen is a DevExpress component.
So that the SplashSreen is updated, I think it has to be started in a separate task.
Unfortunately I get this error:
System.ArgumentNullException: Der Wert darf nicht NULL sein.
Parametername: start
bei System.Threading.Thread..ctor(ThreadStart start)
bei XApp.Start(__Usual[] Xs$Args) in F:VSVisual Studio 2017XSWinQuickDev20VOMDIApp1Start.prg:Zeile 21.
bei VOMDIApp.Exe.Functions.Start() in F:VSVisual Studio 2017XSWinQuickDev20VOMDIApp1Start.prg:Zeile 8.
USING System
USING System.Threading.Tasks
[STAThread];
FUNCTION Start() AS INT
LOCAL oXApp AS XApp
TRY
oXApp:=XApp{}
oXApp:Start()
CATCH oException AS Exception
ErrorDialog(oException)
END TRY
RETURN 0
CLASS XApp INHERIT App
METHOD Start()
LOCAL oMainWindow AS StandardShellWindow
local i AS DWORD
local thread1 as System.Threading.Thread
thread1:=System.Threading.Thread{XApp:ShowSreen()}
thread1:Start()
//Do Some Start routine
For I:=1 to 100
sleep(50)
NEXT
//how to close the SplashSreen Form? Kill the Task?
thread1:Abort()
oMainWindow:Show(SHOWCENTERED)
local Nw1 as Window1
Nw1:=Window1{oMainWindow}
Nw1:Show()
SELF:Exec()
RETURN NIL
Static method ShowSreen() as System.Threading.ThreadStart
Local sp as AuftragSQLKasseCSWinForms.SplashScreen1
sp:=AuftragSQLKasseCSWinForms.SplashScreen1{}
sp:Show()
return
END CLASS
thread1:=System.Threading.Thread{ThreadStart{ShowSreen}}
...
method ShowSreen() as void
Local sp as AuftragSQLKasseCSWinForms.SplashScreen1
sp:=AuftragSQLKasseCSWinForms.SplashScreen1{}
sp:Show()
return
thread1:=System.Threading.Thread{ShowSreen}
...
Static method ShowSreen() as void
Local sp as AuftragSQLKasseCSWinForms.SplashScreen1
sp:=AuftragSQLKasseCSWinForms.SplashScreen1{}
sp:Show()
thread1:=System.Threading.Thread{ThreadStart{ShowSreen}}
...
method ShowSreen() as void
Local sp as AuftragSQLKasseCSWinForms.SplashScreen1
sp:=AuftragSQLKasseCSWinForms.SplashScreen1{}
sp:Show()
Most likely you have the /vo5 compiler option enabled, and this options makes methods without parameters to be emitted as CLIPPER methods, which are indeed incompatible with the ThreadStart delegate and this is why you get that error message.
Please add the STRICT clause to the method declaration and it should work fine:
you are right, the option /VO5 is activated.
I no longer get an error message, and the method ShowSreen() is called , but the SplashSreen is not displayed either. Another tip on what I'm doing wrong?
My final Code:
CLASS XApp INHERIT App
METHOD Start()
LOCAL oMainWindow AS StandardShellWindow
local i AS DWORD
oMainWindow := StandardShellWindow{}
local thread1 as System.Threading.Thread
thread1:=System.Threading.Thread{ThreadStart{ShowSreen}}
thread1:Start()
//Do Some Start routine
For I:=1 to 100
sleep(50)
NEXT
thread1:Abort()
oMainWindow:Show(SHOWCENTERED)
local Nw1 as Window1
Nw1:=Window1{oMainWindow}
Nw1:Show()
SELF:Exec()
RETURN NIL
Static method ShowSreen() as void STRICT
Local sp as AuftragSQLKasseCSWinForms.SplashScreen1
sp:=AuftragSQLKasseCSWinForms.SplashScreen1{}
sp:Show()
return
return
END CLASS
Maybe you need to use ShowDialog() instead of Show()? At least for regular forms, you'd need to use ShowDialog(), not sure how this particular component works.
If that still doesn't work, try using a simple regular (empty) Form instead, does it work with that? If yes, then we need to find what is special about this component.
But a general comment, I do not think you need a thread anyway. You'd need a thread in order to do things in parallel, but when you just want to show a splash screen for a while, you can simply do it in the Start() function. Or maybe I did not understand correctly how you plan to use this?
You do not have a message loop running when you are showing the window, so I believe a simple Show() will just show the window for a brief moment and it will close right after. Did you have success using the exact same code with a regular windows forms Form?
Btw, another thing that you need to pay attention when using threads and GUI, is that you need to make sure you have included a STAThread attribute on your Start() funcntion:
When you build with VO a StandardMDI app there´s also a splash window included. The splash window is created at the beginning of the VO App Start() and it´s destroyed via a timer. That´s the content of the SplashScreen Show() method.
METHOD Show(kShowState) CLASS SplashScreen
SUPER:show(kShowState)
// Make window topmost
SetWindowPos(SELF:handle(), HWND_TOPMOST, 0, 0, 0, 0, DWORD(_OR(SWP_NOSIZE, SWP_NOMOVE)))
// Register Timer
SELF:RegisterTimer(3, TRUE)
// Remove the following two lines if you don't want to show the Splashscreen separatly
GetAppObject():Exec(EXECWHILEEVENT)
Sleep(1000)
RETURN NIL
METHOD Timer() CLASS SplashScreen
SELF:Destroy()
RETURN SELF
But you don´t really need a timer. Just paint a centered and *modeless* DialogWindow. Now your X# Start() method might look like:
CLASS XApp INHERIT App
METHOD Start()
LOCAL oMainWindow AS StandardShellWindow
LOCAL I as DWORD
local SplashScreenHelper AS AuftragSQLKasseCSWinForms.XSTools
SplashScreenHelper:=AuftragSQLKasseCSWinForms.XSTools{}
SplashScreenHelper:TestAsyncWaitForm()
For I:=1 to 100
sleep(50)
NEXT
SplashScreenHelper:nStatus=1 //Close
For I:=1 to 20
sleep(50)
DoEvents()
if SplashScreenHelper:nStatus=0 //is Closed
Exit
endif
next
SplashScreenHelper:=NULL_OBJECT
oMainWindow := StandardShellWindow{SELF}
oMainWindow:Show(SHOWCENTERED)
SELF:Exec()
RETURN NIL
END CLASS