From b568d04ffa191f9e3b643ca33526094eca0ba304 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 27 Nov 1999 22:57:06 +0000 Subject: [PATCH] 1. wxThread changes (detached/joinable) for MSW and docs updates 2. wxUSE_GUI=0 compilation for MSW (use vc6dll.t with tmake) and many small fixes related to this 3. an attempt to make wxLog more MT friendly 4. a small fix for wxRegConfig: it doesn't create empty unused keys any more (SetPath() would always create a key, now it's deleted if it was empty) git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@4712 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- distrib/msw/tmake/filelist.txt | 14 +- distrib/msw/tmake/vc6.t | 4 +- distrib/msw/tmake/vc6base.t | 145 +++++ distrib/msw/tmake/vc6dll.t | 4 +- include/wx/app.h | 11 +- include/wx/msw/private.h | 14 +- include/wx/msw/winundef.h | 13 + include/wx/thread.h | 97 ++-- include/wx/utils.h | 2 +- samples/console/console.cpp | 98 ++-- samples/thread/test.cpp | 25 +- src/common/appcmn.cpp | 2 +- src/common/event.cpp | 8 +- src/common/init.cpp | 1 - src/common/log.cpp | 51 +- src/common/mimetype.cpp | 3 + src/common/string.cpp | 7 +- src/msw/app.cpp | 25 +- src/msw/main.cpp | 81 ++- src/msw/regconf.cpp | 14 +- src/msw/thread.cpp | 441 +++++++++++----- src/msw/utils.cpp | 938 +++++++++++++++++---------------- src/msw/utilsexc.cpp | 115 ++-- src/unix/threadpsx.cpp | 11 +- 24 files changed, 1323 insertions(+), 801 deletions(-) create mode 100644 distrib/msw/tmake/vc6base.t diff --git a/distrib/msw/tmake/filelist.txt b/distrib/msw/tmake/filelist.txt index 5b66d38147..1d196a9b91 100644 --- a/distrib/msw/tmake/filelist.txt +++ b/distrib/msw/tmake/filelist.txt @@ -239,7 +239,7 @@ iniconf.cpp M 16 joystick.cpp M listbox.cpp M listctrl.cpp M 32 -main.cpp M +main.cpp M B mdi.cpp M menu.cpp M menuitem.cpp M @@ -258,9 +258,9 @@ printdlg.cpp M printwin.cpp M radiobox.cpp M radiobut.cpp M -regconf.cpp M 32 +regconf.cpp M 32,B region.cpp M -registry.cpp M 32 +registry.cpp M 32,B scrolbar.cpp M settings.cpp M slider95.cpp M 32 @@ -277,12 +277,12 @@ taskbar.cpp M 32 tbar95.cpp M 32 tbarmsw.cpp M 16 textctrl.cpp M -thread.cpp M 32 +thread.cpp M 32,B timer.cpp M tooltip.cpp M 32 treectrl.cpp M 32 -utils.cpp M -utilsexc.cpp M +utils.cpp M B +utilsexc.cpp M B uuid.cpp M O wave.cpp M window.cpp M @@ -292,7 +292,7 @@ gsocket.c M S dialup.cpp U fontenum.cpp U fontutil.cpp U -threadpsx.cpp U +threadpsx.cpp U B utilsunx.cpp U B gsocket.c U diff --git a/distrib/msw/tmake/vc6.t b/distrib/msw/tmake/vc6.t index 79796d7e75..fb73d3dee8 100644 --- a/distrib/msw/tmake/vc6.t +++ b/distrib/msw/tmake/vc6.t @@ -81,7 +81,7 @@ RSC=rc.exe # PROP Intermediate_Dir "Release" # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c -# ADD CPP /nologo /W3 /Zi /O2 /I "$(wx)\include" /I "$(wx)\src\zlib" /D "NDEBUG" /D WIN95=1 /D "__WIN95__" /D "WIN32" /D "_WIN32" /D WINVER=0x400 /D "__WINDOWS__" /D "__WXMSW__" /D "__WIN32__" /Yu"wx/wxprec.h" /FD /c +# ADD CPP /nologo /W3 /Zi /O2 /I "$(wx)\include" /I "$(wx)\src\zlib" /D "NDEBUG" /D wxUSE_GUI=1 /D WIN95=1 /D "__WIN95__" /D "WIN32" /D "_WIN32" /D WINVER=0x400 /D "__WINDOWS__" /D "__WXMSW__" /D "__WIN32__" /Yu"wx/wxprec.h" /FD /c # ADD BASE RSC /l 0x409 # ADD RSC /l 0x409 BSC32=bscmake.exe @@ -104,7 +104,7 @@ LIB32=link.exe -lib # PROP Intermediate_Dir "Debug" # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c -# ADD CPP /nologo /W4 /Zi /Od /I "$(wx)\include" /I "$(wx)\src\zlib" /D "_DEBUG" /D DEBUG=1 /D WXDEBUG=1 /D "__WXDEBUG__" /D "__WIN95__" /D "WIN32" /D "_WIN32" /D WINVER=0x400 /D "__WINDOWS__" /D "__WIN32__" /D "__WXMSW__" /Fr /Yu"wx/wxprec.h" /FD /c +# ADD CPP /nologo /W4 /Zi /Od /I "$(wx)\include" /I "$(wx)\src\zlib" /D "_DEBUG" /D DEBUG=1 /D WXDEBUG=1 /D "__WXDEBUG__" /D wxUSE_GUI=1 /D "__WIN95__" /D "WIN32" /D "_WIN32" /D WINVER=0x400 /D "__WINDOWS__" /D "__WIN32__" /D "__WXMSW__" /Fr /Yu"wx/wxprec.h" /FD /c # ADD BASE RSC /l 0x409 # ADD RSC /l 0x409 BSC32=bscmake.exe diff --git a/distrib/msw/tmake/vc6base.t b/distrib/msw/tmake/vc6base.t new file mode 100644 index 0000000000..35ad0adaab --- /dev/null +++ b/distrib/msw/tmake/vc6base.t @@ -0,0 +1,145 @@ +#!############################################################################# +#! File: vc6base.t +#! Purpose: tmake template file from which wxBase.dsp is generated by running +#! tmake -t vc6base wxwin.pro -o wxBase.dsp +#! Author: Vadim Zeitlin +#! Created: 27.11.99 +#! Version: $Id$ +#!############################################################################# +#${ + #! include the code which parses filelist.txt file and initializes + #! %wxCommon, %wxGeneric and %wxMSW hashes. + IncludeTemplate("filelist.t"); + + #! now transform these hashes into $project tags + foreach $file (sort keys %wxCommon) { + next if $wxCommon{$file} !~ /\bB\b/; + + my $tag = $file =~ /\.c$/ ? "WXCSRCS" : "WXCOMMONSRCS"; + $project{$tag} .= $file . " " + } + + foreach $file (sort keys %wxMSW) { + next if $wxMSW{$file} !~ /\bB\b/; + + my $tag = $file =~ /\.c$/ ? "WXMSWCSRCS" : "WXMSWSRCS"; + $project{$tag} .= $file . " " + } + + foreach $file (sort keys %wxBase) { + my $tag = $file =~ /\.c$/ ? "WXCSRCS" : "WXCOMMONSRCS"; + $project{$tag} .= $file . " " + } +#$} +# Microsoft Developer Studio Project File - Name="wxBase" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=wxBase - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "wxBase.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "wxBase.mak" CFG="wxBase - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "wxBase - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "wxBase - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "wxBase - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /W3 /Zi /O2 /I "$(wx)\include" /I "$(wx)\src\zlib" /D "NDEBUG" /D wxUSE_GUI=0 /D WIN95=1 /D "__WIN95__" /D "WIN32" /D "_WIN32" /D WINVER=0x400 /D "__WINDOWS__" /D "__WXMSW__" /D "__WIN32__" /Yu"wx/wxprec.h" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "wxBase - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /W4 /Zi /Od /I "$(wx)\include" /I "$(wx)\src\zlib" /D "_DEBUG" /D DEBUG=1 /D WXDEBUG=1 /D "__WXDEBUG__" /D wxUSE_GUI=0 /D "__WIN95__" /D "WIN32" /D "_WIN32" /D WINVER=0x400 /D "__WINDOWS__" /D "__WIN32__" /D "__WXMSW__" /Fr /Yu"wx/wxprec.h" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo /o"lib/wxBase.bsc" +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "wxBase - Win32 Release" +# Name "wxBase - Win32 Debug" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\src\msw\dummy.cpp +# ADD CPP /Yc"wx/wxprec.h" +# End Source File +#$ ExpandGlue("WXCOMMONSRCS", "# Begin Source File\n\nSOURCE=.\\src\\common\\", "\n# End Source File\n# Begin Source File\n\nSOURCE=.\\src\\common\\", "\n# End Source File\n"); +#$ ExpandGlue("WXMSWSRCS", "# Begin Source File\n\nSOURCE=.\\src\\msw\\", "\n# End Source File\n# Begin Source File\n\nSOURCE=.\\src\\msw\\", "\n# End Source File\n"); +#$ ExpandGlue("WXCSRCS", "# Begin Source File\n\nSOURCE=.\\src\\common\\", "\n# SUBTRACT CPP /YX /Yc /Yu\n# End Source File\n# Begin Source File\n\nSOURCE=.\\src\\common\\", "\n# SUBTRACT CPP /YX /Yc /Yu\n# End Source File\n"); +#$ ExpandGlue("WXMSWCSRCS", "# Begin Source File\n\nSOURCE=.\\src\\msw\\", "\n# SUBTRACT CPP /YX /Yc /Yu\n# End Source File\n# Begin Source File\n\nSOURCE=.\\src\\common\\", "\n# SUBTRACT CPP /YX /Yc /Yu\n# End Source File\n"); + +# Begin Source File + +SOURCE=.\src\common\y_tab.c + +!IF "$(CFG)" == "wxBase - Win32 Release" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "wxBase - Win32 Debug" + +# ADD CPP /W1 +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# End Target +# End Project diff --git a/distrib/msw/tmake/vc6dll.t b/distrib/msw/tmake/vc6dll.t index ce5182d4f9..fb98ecfa6b 100644 --- a/distrib/msw/tmake/vc6dll.t +++ b/distrib/msw/tmake/vc6dll.t @@ -83,7 +83,7 @@ RSC=rc.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W4 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "WXWINDLL_EXPORTS" /YX /FD /c -# ADD CPP /nologo /MT /W4 /GX /O2 /I "$(wx)\include" /I "$(wx)\src\zlib" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D "WXWINDLL_EXPORTS" /D "__WXMSW__" /D "__WIN95__" /D "__WINDOWS__" /D "__WIN32__" /D "WXMAKINGDLL" /Yu"wx/wxprec.h" /FD /c +# ADD CPP /nologo /MT /W4 /GX /O2 /I "$(wx)\include" /I "$(wx)\src\zlib" /D "NDEBUG" /D wxUSE_GUI=1 /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D "WXWINDLL_EXPORTS" /D "__WXMSW__" /D "__WIN95__" /D "__WINDOWS__" /D "__WIN32__" /D "WXMAKINGDLL" /Yu"wx/wxprec.h" /FD /c # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "NDEBUG" @@ -109,7 +109,7 @@ LINK32=link.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "WXWINDLL_EXPORTS" /YX /FD /GZ /c -# ADD CPP /nologo /MTd /W4 /Gm /ZI /Od /I "$(wx)\include" /I "$(wx)\src\zlib" /D "_DEBUG" /D "__WXDEBUG__" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D "WXWINDLL_EXPORTS" /D "__WXMSW__" /D "__WIN95__" /D "__WINDOWS__" /D "__WIN32__" /D "WXMAKINGDLL" /Yu"wx/wxprec.h" /FD /GZ /c +# ADD CPP /nologo /MTd /W4 /Gm /ZI /Od /I "$(wx)\include" /I "$(wx)\src\zlib" /D "_DEBUG" /D "__WXDEBUG__" /D wxUSE_GUI=1 /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D "WXWINDLL_EXPORTS" /D "__WXMSW__" /D "__WIN95__" /D "__WINDOWS__" /D "__WIN32__" /D "WXMAKINGDLL" /Yu"wx/wxprec.h" /FD /GZ /c # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" diff --git a/include/wx/app.h b/include/wx/app.h index 51d126b8ea..5341e7d2b1 100644 --- a/include/wx/app.h +++ b/include/wx/app.h @@ -282,7 +282,10 @@ protected: #include "wx/stubs/app.h" #endif #else // !GUI - typedef wxAppBase wxApp; + // can't use typedef because wxApp forward declared as a class + class WXDLLEXPORT wxApp : public wxAppBase + { + }; #endif // GUI/!GUI // ---------------------------------------------------------------------------- @@ -322,13 +325,13 @@ inline void WXDLLEXPORT wxPostEvent(wxEvtHandler *dest, wxEvent& event) dest->AddPendingEvent(event); } -#endif // wxUSE_GUI/!wxUSE_GUI +#endif // wxUSE_GUI // console applications may avoid using DECLARE_APP and IMPLEMENT_APP macros // and call these functions instead at the program startup and termination // ------------------------------------------------------------------------- -#if wxUSE_NOGUI +#if !wxUSE_GUI // initialize the library (may be called as many times as needed, but each // call to wxInitialize() must be matched by wxUninitialize()) @@ -338,7 +341,7 @@ extern bool WXDLLEXPORT wxInitialize(); // wxUninitialize() extern void WXDLLEXPORT wxUninitialize(); -#endif // wxUSE_NOGUI +#endif // !wxUSE_GUI // ---------------------------------------------------------------------------- // macros for dynamic creation of the application object diff --git a/include/wx/msw/private.h b/include/wx/msw/private.h index 981189b3ff..d43c09dd93 100644 --- a/include/wx/msw/private.h +++ b/include/wx/msw/private.h @@ -43,6 +43,8 @@ static const double pt2mm = (1/(METRIC_CONVERSION_CONSTANT*72)); // standard icons from the resources // --------------------------------------------------------------------------- +#if wxUSE_GUI + WXDLLEXPORT_DATA(extern HICON) wxSTD_FRAME_ICON; WXDLLEXPORT_DATA(extern HICON) wxSTD_MDIPARENTFRAME_ICON; WXDLLEXPORT_DATA(extern HICON) wxSTD_MDICHILDFRAME_ICON; @@ -51,6 +53,8 @@ WXDLLEXPORT_DATA(extern HICON) wxDEFAULT_MDIPARENTFRAME_ICON; WXDLLEXPORT_DATA(extern HICON) wxDEFAULT_MDICHILDFRAME_ICON; WXDLLEXPORT_DATA(extern HFONT) wxSTATUS_LINE_FONT; +#endif // wxUSE_GUI + // --------------------------------------------------------------------------- // define things missing from some compilers' headers // --------------------------------------------------------------------------- @@ -268,9 +272,13 @@ private: // global data // --------------------------------------------------------------------------- +#if 0 // where is this?? // The MakeProcInstance version of the function wxSubclassedGenericControlProc WXDLLEXPORT_DATA(extern FARPROC) wxGenericControlSubClassProc; +#endif // 0 + WXDLLEXPORT_DATA(extern wxChar*) wxBuffer; + WXDLLEXPORT_DATA(extern HINSTANCE) wxhInstance; // --------------------------------------------------------------------------- @@ -279,11 +287,13 @@ WXDLLEXPORT_DATA(extern HINSTANCE) wxhInstance; extern "C" { -WXDLLEXPORT HINSTANCE wxGetInstance(); + WXDLLEXPORT HINSTANCE wxGetInstance(); } WXDLLEXPORT void wxSetInstance(HINSTANCE hInst); +#if wxUSE_GUI + WXDLLEXPORT wxWindow* wxFindWinFromHandle(WXHWND hWnd); WXDLLEXPORT void wxGetCharSize(WXHWND wnd, int *x, int *y, const wxFont *the_font); @@ -316,5 +326,7 @@ inline bool wxStyleHasBorder(long style) wxSUNKEN_BORDER | wxDOUBLE_BORDER)) != 0; } +#endif // wxUSE_GUI + #endif // _WX_PRIVATE_H_ diff --git a/include/wx/msw/winundef.h b/include/wx/msw/winundef.h index 04ab36ae4d..e580f24650 100644 --- a/include/wx/msw/winundef.h +++ b/include/wx/msw/winundef.h @@ -187,6 +187,19 @@ } #endif +// FindResource +#ifdef FindResource + #undef FindResource + inline HRSRC FindResource(HMODULE hModule, LPCTSTR lpName, LPCTSTR lpType) + { + #ifdef _UNICODE + return FindResourceW(hModule, lpName, lpType); + #else + return FindResourceA(hModule, lpName, lpType); + #endif + } +#endif + // IsMaximized #ifdef IsMaximized diff --git a/include/wx/thread.h b/include/wx/thread.h index 641ce6330b..3f1415adc7 100644 --- a/include/wx/thread.h +++ b/include/wx/thread.h @@ -53,9 +53,16 @@ enum wxThreadError wxTHREAD_NO_RESOURCE, // No resource left to create a new thread wxTHREAD_RUNNING, // The thread is already running wxTHREAD_NOT_RUNNING, // The thread isn't running + wxTHREAD_KILLED, // Thread we waited for had to be killed wxTHREAD_MISC_ERROR // Some other error }; +enum wxThreadKind +{ + wxTHREAD_DETACHED, + wxTHREAD_JOINABLE +}; + // defines the interval of priority enum { @@ -231,15 +238,18 @@ private: }; // ---------------------------------------------------------------------------- -// Thread management class +// Thread class // ---------------------------------------------------------------------------- -// FIXME Thread termination model is still unclear. Delete() should probably -// have a timeout after which the thread must be Kill()ed. +// there are two different kinds of threads: joinable and detached (default) +// ones. Only joinable threads can return a return code and only detached +// threads auto-delete themselves - the user should delete the joinable +// threads manually. // NB: in the function descriptions the words "this thread" mean the thread // created by the wxThread object while "main thread" is the thread created // during the process initialization (a.k.a. the GUI thread) + class wxThreadInternal; class WXDLLEXPORT wxThread { @@ -266,34 +276,52 @@ public: // NB: at least under MSW worker threads can not call ::wxSleep()! static void Sleep(unsigned long milliseconds); - // default constructor - wxThread(); + // constructor only creates the C++ thread object and doesn't create (or + // start) the real thread + wxThread(wxThreadKind kind = wxTHREAD_DETACHED); + + // functions that change the thread state: all these can only be called + // from _another_ thread (typically the thread that created this one, e.g. + // the main thread), not from the thread itself - // function that change the thread state // create a new thread - call Run() to start it wxThreadError Create(); - // starts execution of the thread - from the moment Run() is called the - // execution of wxThread::Entry() may start at any moment, caller + // starts execution of the thread - from the moment Run() is called + // the execution of wxThread::Entry() may start at any moment, caller // shouldn't suppose that it starts after (or before) Run() returns. wxThreadError Run(); - // stops the thread if it's running and deletes the wxThread object - // freeing its memory. This function should also be called if the - // Create() or Run() fails to free memory (otherwise it will be done by - // the thread itself when it terminates). The return value is the - // thread exit code if the thread was gracefully terminated, 0 if it - // wasn't running and -1 if an error occured. - ExitCode Delete(); + // stops the thread if it's running and deletes the wxThread object if + // this is a detached thread freeing its memory - otherwise (for + // joinable threads) you still need to delete wxThread object + // yourself. + // + // this function only works if the thread calls TestDestroy() + // periodically - the thread will only be deleted the next time it + // does it! + // + // will fill the rc pointer with the thread exit code if it's !NULL + wxThreadError Delete(ExitCode *rc = (ExitCode *)NULL); + + // waits for a joinable thread to finish and returns its exit code + // + // Returns (ExitCode)-1 on error (for example, if the thread is not + // joinable) + ExitCode Wait(); // kills the thread without giving it any chance to clean up - should // not be used in normal circumstances, use Delete() instead. It is a // dangerous function that should only be used in the most extreme - // cases! The wxThread object is deleted by Kill() if thread was - // killed (i.e. no errors occured). + // cases! + // + // The wxThread object is deleted by Kill() if the thread is + // detachable, but you still have to delete it manually for joinable + // threads. wxThreadError Kill(); - // pause a running thread + // pause a running thread: as Delete(), this only works if the thread + // calls TestDestroy() regularly wxThreadError Pause(); // resume a paused thread @@ -308,10 +336,6 @@ public: // Get the current priority. unsigned int GetPriority() const; - // Get the thread ID - a platform dependent number which uniquely - // identifies a thread inside a process - unsigned long GetID() const; - // thread status inquiries // Returns true if the thread is alive: i.e. running or suspended bool IsAlive() const; @@ -320,11 +344,22 @@ public: // Returns true if the thread is suspended bool IsPaused() const; + // is the thread of detached kind? + bool IsDetached() const { return m_isDetached; } + + // Get the thread ID - a platform dependent number which uniquely + // identifies a thread inside a process + unsigned long GetId() const; + // called when the thread exits - in the context of this thread // // NB: this function will not be called if the thread is Kill()ed virtual void OnExit() { } + // dtor is public, but the detached threads should never be deleted - use + // Delete() instead (or leave the thread terminate by itself) + virtual ~wxThread(); + protected: // Returns TRUE if the thread was asked to terminate: this function should // be called by the thread from time to time, otherwise the main thread @@ -332,14 +367,7 @@ protected: bool TestDestroy(); // exits from the current thread - can be called only from this thread - void Exit(void *exitcode = 0); - - // destructor is private - user code can't delete thread objects, they will - // auto-delete themselves (and thus must be always allocated on the heap). - // Use Delete() or Kill() instead. - // - // NB: derived classes dtors shouldn't be public neither! - virtual ~wxThread(); + void Exit(ExitCode exitcode = 0); // entry point for the thread - called by Run() and executes in the context // of this thread. @@ -357,6 +385,9 @@ private: // protects access to any methods of wxThreadInternal object wxCriticalSection m_critsect; + + // true if the thread is detached, false if it is joinable + bool m_isDetached; }; // ---------------------------------------------------------------------------- @@ -369,9 +400,9 @@ void WXDLLEXPORT wxMutexGuiLeave(); // macros for entering/leaving critical sections which may be used without // having to take them inside "#if wxUSE_THREADS" -#define wxENTER_CRIT_SECT(cs) (cs)->Enter() -#define wxLEAVE_CRIT_SECT(cs) (cs)->Leave() -#define wxCRIT_SECT_LOCKER(name, cs) wxCriticalSectionLocker name(*cs) +#define wxENTER_CRIT_SECT(cs) (cs).Enter() +#define wxLEAVE_CRIT_SECT(cs) (cs).Leave() +#define wxCRIT_SECT_LOCKER(name, cs) wxCriticalSectionLocker name(cs) #else // !wxUSE_THREADS diff --git a/include/wx/utils.h b/include/wx/utils.h index 48ee355683..73b50a162b 100644 --- a/include/wx/utils.h +++ b/include/wx/utils.h @@ -172,7 +172,7 @@ WXDLLEXPORT int wxKill(long pid, wxSignal sig = wxSIGTERM); // If no command then just the shell WXDLLEXPORT bool wxShell(const wxString& command = wxEmptyString); -// Sleep for nSecs seconds under UNIX, do nothing under Windows +// Sleep for nSecs seconds WXDLLEXPORT void wxSleep(int nSecs); // Sleep for a given amount of milliseconds diff --git a/samples/console/console.cpp b/samples/console/console.cpp index ed86aa6d79..09e4536954 100644 --- a/samples/console/console.cpp +++ b/samples/console/console.cpp @@ -30,8 +30,8 @@ // what to test? //#define TEST_ARRAYS -#define TEST_LOG -//#define TEST_THREADS +//#define TEST_LOG +#define TEST_THREADS // ============================================================================ // implementation @@ -47,30 +47,51 @@ static size_t gs_counter = (size_t)-1; static wxCriticalSection gs_critsect; +static wxCondition gs_cond; -class MyThread : public wxThread +class MyJoinableThread : public wxThread { public: - MyThread(char ch); + MyJoinableThread(size_t n) : wxThread(wxTHREAD_JOINABLE) + { m_n = n; Create(); } // thread execution starts here - virtual void *Entry(); + virtual ExitCode Entry(); - // and stops here - virtual void OnExit(); - -public: - char m_ch; +private: + size_t m_n; }; -MyThread::MyThread(char ch) +wxThread::ExitCode MyJoinableThread::Entry() { - m_ch = ch; + unsigned long res = 1; + for ( size_t n = 1; n < m_n; n++ ) + { + res *= n; + + // it's a loooong calculation :-) + Sleep(100); + } - Create(); + return (ExitCode)res; } -void *MyThread::Entry() +class MyDetachedThread : public wxThread +{ +public: + MyDetachedThread(char ch) { m_ch = ch; Create(); } + + // thread execution starts here + virtual ExitCode Entry(); + + // and stops here + virtual void OnExit(); + +private: + char m_ch; +}; + +wxThread::ExitCode MyDetachedThread::Entry() { { wxCriticalSectionLocker lock(gs_critsect); @@ -80,7 +101,8 @@ void *MyThread::Entry() gs_counter++; } - for ( size_t n = 0; n < 10; n++ ) + static const size_t nIter = 10; + for ( size_t n = 0; n < nIter; n++ ) { if ( TestDestroy() ) break; @@ -91,13 +113,14 @@ void *MyThread::Entry() wxThread::Sleep(100); } - return NULL; + return 0; } -void MyThread::OnExit() +void MyDetachedThread::OnExit() { wxCriticalSectionLocker lock(gs_critsect); - gs_counter--; + if ( !--gs_counter ) + gs_cond.Signal(); } #endif // TEST_THREADS @@ -178,33 +201,44 @@ int main(int argc, char **argv) printf(msg); // but this one will because log functions use fixed size buffer - wxLogMessage("A very very long message 2: '%s', the end!\n", s.c_str()); + // (note that it doesn't need '\n' at the end neither - will be added + // by wxLog anyhow) + wxLogMessage("A very very long message 2: '%s', the end!", s.c_str()); #endif // TEST_LOG #ifdef TEST_THREADS + puts("Testing detached threads..."); + static const size_t nThreads = 3; - MyThread *threads[nThreads]; + MyDetachedThread *threads[nThreads]; size_t n; for ( n = 0; n < nThreads; n++ ) { - threads[n] = new MyThread('+' + n); - threads[n]->Run(); + threads[n] = new MyDetachedThread('A' + n); } - // wait until all threads terminate - for ( ;; ) - { - wxCriticalSectionLocker lock(gs_critsect); - if ( !gs_counter ) - break; - } - - puts("\nThat's all, folks!"); + threads[0]->SetPriority(WXTHREAD_MIN_PRIORITY); + threads[1]->SetPriority(WXTHREAD_MAX_PRIORITY); for ( n = 0; n < nThreads; n++ ) { - threads[n]->Delete(); + threads[n]->Run(); } + + // wait until all threads terminate + wxMutex mutex; + mutex.Lock(); + gs_cond.Wait(mutex); + mutex.Unlock(); + + puts("\n\nTesting a joinable thread used for a loooong calculation..."); + + // calc 10! in the background + MyJoinableThread thread(10); + thread.Run(); + + printf("\nThread terminated with exit code %lu.\n", + (unsigned long)thread.Wait()); #endif // TEST_THREADS wxUninitialize(); diff --git a/samples/thread/test.cpp b/samples/thread/test.cpp index 1d8d3423be..f43a48d919 100644 --- a/samples/thread/test.cpp +++ b/samples/thread/test.cpp @@ -150,7 +150,7 @@ void *MyThread::Entry() wxString text; text.Printf("Thread 0x%x started (priority = %d).\n", - GetID(), GetPriority()); + GetId(), GetPriority()); WriteText(text); for ( m_count = 0; m_count < 10; m_count++ ) @@ -159,14 +159,14 @@ void *MyThread::Entry() if ( TestDestroy() ) break; - text.Printf("[%u] Thread 0x%x here.\n", m_count, GetID()); + text.Printf("[%u] Thread 0x%x here.\n", m_count, GetId()); WriteText(text); // wxSleep() can't be called from non-GUI thread! wxThread::Sleep(1000); } - text.Printf("Thread 0x%x finished.\n", GetID()); + text.Printf("Thread 0x%x finished.\n", GetId()); WriteText(text); return NULL; @@ -266,17 +266,18 @@ MyThread *MyFrame::CreateThread() void MyFrame::OnStartThreads(wxCommandEvent& WXUNUSED(event) ) { - static wxString s_str; - s_str = wxGetTextFromUser("How many threads to start: ", - "wxThread sample", - s_str, this); - if ( s_str.IsEmpty() ) - return; + static long s_num = 10; + + s_num = wxGetNumberFromUser("How many threads to start: ", "", + "wxThread sample", s_num, 1, 10000, this); + if ( s_num == -1 ) + { + s_num = 10; - size_t count, n; - sscanf(s_str, "%u", &count); - if ( count == 0 ) return; + } + + size_t count = (size_t)s_num, n; wxArrayThread threads; diff --git a/src/common/appcmn.cpp b/src/common/appcmn.cpp index ee097b6b70..3276436a6e 100644 --- a/src/common/appcmn.cpp +++ b/src/common/appcmn.cpp @@ -47,7 +47,7 @@ void wxAppBase::ProcessPendingEvents() { // ensure that we're the only thread to modify the pending events list - wxCRIT_SECT_LOCKER(locker, wxPendingEventsLocker); + wxCRIT_SECT_LOCKER(locker, *wxPendingEventsLocker); if ( !wxPendingEvents ) return; diff --git a/src/common/event.cpp b/src/common/event.cpp index fb953f101a..e6190d9674 100644 --- a/src/common/event.cpp +++ b/src/common/event.cpp @@ -609,13 +609,13 @@ void wxEvtHandler::AddPendingEvent(wxEvent& event) m_pendingEvents->Append(event2); - wxENTER_CRIT_SECT(wxPendingEventsLocker); + wxENTER_CRIT_SECT(*wxPendingEventsLocker); if ( !wxPendingEvents ) wxPendingEvents = new wxList; wxPendingEvents->Append(this); - wxLEAVE_CRIT_SECT(wxPendingEventsLocker); + wxLEAVE_CRIT_SECT(*wxPendingEventsLocker); wxWakeUpIdle(); } @@ -623,9 +623,9 @@ void wxEvtHandler::AddPendingEvent(wxEvent& event) void wxEvtHandler::ProcessPendingEvents() { #if defined(__VISAGECPP__) - wxCRIT_SECT_LOCKER(locker, &m_eventsLocker); -#else wxCRIT_SECT_LOCKER(locker, m_eventsLocker); +#else + wxCRIT_SECT_LOCKER(locker, *m_eventsLocker); #endif wxNode *node = m_pendingEvents->First(); diff --git a/src/common/init.cpp b/src/common/init.cpp index 846026eb93..0fa42d7d8f 100644 --- a/src/common/init.cpp +++ b/src/common/init.cpp @@ -30,7 +30,6 @@ #include "wx/module.h" - // ---------------------------------------------------------------------------- // global vars // ---------------------------------------------------------------------------- diff --git a/src/common/log.cpp b/src/common/log.cpp index 01f2b0b01b..a4647eee3c 100644 --- a/src/common/log.cpp +++ b/src/common/log.cpp @@ -48,6 +48,7 @@ #include "wx/utils.h" #include "wx/wxchar.h" #include "wx/log.h" +#include "wx/thread.h" // other standard headers #include @@ -55,9 +56,7 @@ #include #ifdef __WXMSW__ - #include - // Redefines OutputDebugString if necessary - #include "wx/msw/private.h" + #include "wx/msw/private.h" // includes windows.h for OutputDebugString #else //Unix #include #endif //Win/Unix @@ -78,23 +77,36 @@ // ============================================================================ // ---------------------------------------------------------------------------- -// implementation of Log functions -// -// NB: unfortunately we need all these distinct functions, we can't make them -// macros and not all compilers inline vararg functions. +// globals // ---------------------------------------------------------------------------- // log functions can't allocate memory (LogError("out of memory...") should // work!), so we use a static buffer for all log messages #define LOG_BUFFER_SIZE (4096) -// static buffer for error messages (FIXME MT-unsafe) +// static buffer for error messages static wxChar s_szBuf[LOG_BUFFER_SIZE]; +#if wxUSE_THREADS + +// the critical section protecting the static buffer +static wxCriticalSection gs_csLogBuf; + +#endif // wxUSE_THREADS + +// ---------------------------------------------------------------------------- +// implementation of Log functions +// +// NB: unfortunately we need all these distinct functions, we can't make them +// macros and not all compilers inline vararg functions. +// ---------------------------------------------------------------------------- + // generic log function void wxLogGeneric(wxLogLevel level, const wxChar *szFormat, ...) { if ( wxLog::GetActiveTarget() != NULL ) { + wxCRIT_SECT_LOCKER(locker, gs_csLogBuf); + va_list argptr; va_start(argptr, szFormat); wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr); @@ -108,6 +120,8 @@ void wxLogGeneric(wxLogLevel level, const wxChar *szFormat, ...) void wxLog##level(const wxChar *szFormat, ...) \ { \ if ( wxLog::GetActiveTarget() != NULL ) { \ + wxCRIT_SECT_LOCKER(locker, gs_csLogBuf); \ + \ va_list argptr; \ va_start(argptr, szFormat); \ wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr); \ @@ -129,6 +143,8 @@ void wxLogVerbose(const wxChar *szFormat, ...) { wxLog *pLog = wxLog::GetActiveTarget(); if ( pLog != NULL && pLog->GetVerbose() ) { + wxCRIT_SECT_LOCKER(locker, gs_csLogBuf); + va_list argptr; va_start(argptr, szFormat); wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr); @@ -144,6 +160,8 @@ void wxLogVerbose(const wxChar *szFormat, ...) void wxLog##level(const wxChar *szFormat, ...) \ { \ if ( wxLog::GetActiveTarget() != NULL ) { \ + wxCRIT_SECT_LOCKER(locker, gs_csLogBuf); \ + \ va_list argptr; \ va_start(argptr, szFormat); \ wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr); \ @@ -158,6 +176,8 @@ void wxLogVerbose(const wxChar *szFormat, ...) wxLog *pLog = wxLog::GetActiveTarget(); if ( pLog != NULL && wxLog::IsAllowedTraceMask(mask) ) { + wxCRIT_SECT_LOCKER(locker, gs_csLogBuf); + va_list argptr; va_start(argptr, szFormat); wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr); @@ -175,6 +195,8 @@ void wxLogVerbose(const wxChar *szFormat, ...) // that wxLogTrace(wxTraceRefCount | wxTraceOle) will only do something // if both bits are set. if ( pLog != NULL && ((pLog->GetTraceMask() & mask) == mask) ) { + wxCRIT_SECT_LOCKER(locker, gs_csLogBuf); + va_list argptr; va_start(argptr, szFormat); wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr); @@ -207,6 +229,8 @@ void wxLogSysErrorHelper(long lErrCode) void WXDLLEXPORT wxLogSysError(const wxChar *szFormat, ...) { + wxCRIT_SECT_LOCKER(locker, gs_csLogBuf); + va_list argptr; va_start(argptr, szFormat); wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr); @@ -217,6 +241,8 @@ void WXDLLEXPORT wxLogSysError(const wxChar *szFormat, ...) void WXDLLEXPORT wxLogSysError(long lErrCode, const wxChar *szFormat, ...) { + wxCRIT_SECT_LOCKER(locker, gs_csLogBuf); + va_list argptr; va_start(argptr, szFormat); wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr); @@ -361,15 +387,16 @@ void wxLogStderr::DoLogString(const wxChar *szString, time_t WXUNUSED(t)) { wxString str; TimeStamp(&str); - str << szString << wxT('\n'); + str << szString; fputs(str.mb_str(), m_fp); + fputc(_T('\n'), m_fp); fflush(m_fp); // under Windows, programs usually don't have stderr at all, so show the - // messages also under debugger -#ifdef __WXMSW__ - OutputDebugString(str + wxT('\r')); + // messages also under debugger - unless it's a console program +#if defined(__WXMSW__) && wxUSE_GUI + OutputDebugString(str + wxT("\r\n")); #endif // MSW } diff --git a/src/common/mimetype.cpp b/src/common/mimetype.cpp index 796a19f062..11e01b7291 100644 --- a/src/common/mimetype.cpp +++ b/src/common/mimetype.cpp @@ -771,6 +771,7 @@ bool wxFileTypeImpl::GetMimeType(wxString *mimeType) const bool wxFileTypeImpl::GetIcon(wxIcon *icon) const { +#if wxUSE_GUI if ( m_info ) { // we don't have icons in the fallback resources return FALSE; @@ -819,6 +820,8 @@ bool wxFileTypeImpl::GetIcon(wxIcon *icon) const } // no such file type or no value or incorrect icon entry +#endif // wxUSE_GUI + return FALSE; } diff --git a/src/common/string.cpp b/src/common/string.cpp index 9582bca6d9..280e105f25 100644 --- a/src/common/string.cpp +++ b/src/common/string.cpp @@ -200,7 +200,12 @@ extern int WXDLLEXPORT wxVsnprintf(wxChar *buf, size_t len, return iLen; #else // ANSI - return wxVsnprintfA(buf, len, format, argptr); + // vsnprintf() will not terminate the string with '\0' if there is not + // enough place, but we want the string to always be NUL terminated + int rc = wxVsnprintfA(buf, len - 1, format, argptr); + buf[len] = 0; + + return rc; #endif // Unicode/ANSI } diff --git a/src/msw/app.cpp b/src/msw/app.cpp index 3528af8915..0b947a5409 100644 --- a/src/msw/app.cpp +++ b/src/msw/app.cpp @@ -100,7 +100,6 @@ extern wxList WXDLLEXPORT wxPendingDelete; extern void wxSetKeyboardHook(bool doIt); extern wxCursor *g_globalCursor; -HINSTANCE wxhInstance = 0; MSG s_currentMsg; wxApp *wxTheApp = NULL; @@ -1217,11 +1216,16 @@ void wxWakeUpIdle() { // Send the top window a dummy message so idle handler processing will // start up again. Doing it this way ensures that the idle handler - // wakes up in the right thread. + // wakes up in the right thread (see also wxWakeUpMainThread() which does + // the same for the main app thread only) wxWindow *topWindow = wxTheApp->GetTopWindow(); - if ( topWindow ) { - HWND hWnd = (HWND)topWindow->GetHWND(); - ::PostMessage(hWnd, WM_NULL, 0, 0); + if ( topWindow ) + { + if ( !::PostMessage(GetHwndOf(topWindow), WM_NULL, 0, 0) ) + { + // should never happen + wxLogLastError("PostMessage(WM_NULL)"); + } } } @@ -1250,17 +1254,6 @@ wxApp::GetStdIcon(int which) const } } - -HINSTANCE wxGetInstance() -{ - return wxhInstance; -} - -void wxSetInstance(HINSTANCE hInst) -{ - wxhInstance = hInst; -} - // For some reason, with MSVC++ 1.5, WinMain isn't linked in properly // if in a separate file. So include it here to ensure it's linked. #if (defined(__VISUALC__) && !defined(__WIN32__)) || (defined(__GNUWIN32__) && !defined(__TWIN32__)) diff --git a/src/msw/main.cpp b/src/msw/main.cpp index 3565e7fa23..cfa9a598c9 100644 --- a/src/msw/main.cpp +++ b/src/msw/main.cpp @@ -1,36 +1,59 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: main.cpp +// Name: msw/main.cpp // Purpose: Main/DllMain // Author: Julian Smart // Modified by: // Created: 04/01/98 // RCS-ID: $Id$ // Copyright: (c) Julian Smart and Markus Holzem -// Licence: wxWindows license +// Licence: wxWindows license ///////////////////////////////////////////////////////////////////////////// +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + #ifdef __GNUG__ -#pragma implementation + #pragma implementation #endif // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ -#pragma hdrstop + #pragma hdrstop #endif #include "wx/event.h" #include "wx/app.h" -#include + +#include "wx/msw/private.h" + +// ---------------------------------------------------------------------------- +// globals +// ---------------------------------------------------------------------------- + +HINSTANCE wxhInstance = 0; + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// various entry points +// ---------------------------------------------------------------------------- // May wish not to have a DllMain or WinMain, e.g. if we're programming -// a Netscape plugin. -#ifndef NOMAIN +// a Netscape plugin or if we're writing a console application +#if wxUSE_GUI && !defined(NOMAIN) // NT defines APIENTRY, 3.x not #if !defined(APIENTRY) -#define APIENTRY FAR PASCAL + #define APIENTRY FAR PASCAL #endif ///////////////////////////////////////////////////////////////////////////////// @@ -78,25 +101,39 @@ BOOL WINAPI DllMain (HANDLE hModule, DWORD fdwReason, LPVOID lpReserved) #endif { switch (fdwReason) - { - case DLL_PROCESS_ATTACH: - // Only call wxEntry if the application itself is part of the DLL. - // If only the wxWindows library is in the DLL, then the initialisation - // will be called when the application implicitly calls WinMain. + { + case DLL_PROCESS_ATTACH: + // Only call wxEntry if the application itself is part of the DLL. + // If only the wxWindows library is in the DLL, then the initialisation + // will be called when the application implicitly calls WinMain. #if !defined(WXMAKINGDLL) - return wxEntry((WXHINSTANCE) hModule); + return wxEntry((WXHINSTANCE) hModule); #endif - break; + break; - case DLL_PROCESS_DETACH: - default: - break; - } - return TRUE; + case DLL_PROCESS_DETACH: + default: + break; + } + return TRUE; } -#endif +#endif // _WINDLL -#endif +#endif // !NOMAIN + +// ---------------------------------------------------------------------------- +// global functions +// ---------------------------------------------------------------------------- + +HINSTANCE wxGetInstance() +{ + return wxhInstance; +} + +void wxSetInstance(HINSTANCE hInst) +{ + wxhInstance = hInst; +} diff --git a/src/msw/regconf.cpp b/src/msw/regconf.cpp index 4fb34f240d..e62511ca68 100644 --- a/src/msw/regconf.cpp +++ b/src/msw/regconf.cpp @@ -160,13 +160,25 @@ void wxRegConfig::SetPath(const wxString& strPath) } // recombine path parts in one variable - wxString strRegPath; + wxString strOldPath = m_strPath, strRegPath; m_strPath.Empty(); for ( size_t n = 0; n < aParts.Count(); n++ ) { strRegPath << '\\' << aParts[n]; m_strPath << wxCONFIG_PATH_SEPARATOR << aParts[n]; } + if ( m_strPath == strOldPath ) + return; + + // as we create the registry key when SetPath(key) is done, we can be left + // with plenty of empty keys if this was only done to try to read some value + // which, in fact, doesn't exist - to prevent this from happening we + // automatically delete the old key if it was empty + if ( m_keyLocal.IsEmpty() ) + { + m_keyLocal.DeleteSelf(); + } + // change current key(s) m_keyLocal.SetName(m_keyLocalRoot, strRegPath); m_keyGlobal.SetName(m_keyGlobalRoot, strRegPath); diff --git a/src/msw/thread.cpp b/src/msw/thread.cpp index 22cc54ffe0..a3929b693f 100644 --- a/src/msw/thread.cpp +++ b/src/msw/thread.cpp @@ -36,6 +36,19 @@ #include "wx/module.h" #include "wx/thread.h" +// must have this symbol defined to get _beginthread/_endthread declarations +#ifndef _MT + #define _MT +#endif + +#ifdef __VISUALC__ + #include +#endif + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + // the possible states of the thread ("=>" shows all possible transitions from // this state) enum wxThreadState @@ -48,32 +61,32 @@ enum wxThreadState }; // ---------------------------------------------------------------------------- -// static variables +// this module globals // ---------------------------------------------------------------------------- // TLS index of the slot where we store the pointer to the current thread -static DWORD s_tlsThisThread = 0xFFFFFFFF; +static DWORD gs_tlsThisThread = 0xFFFFFFFF; // id of the main thread - the one which can call GUI functions without first // calling wxMutexGuiEnter() -static DWORD s_idMainThread = 0; +static DWORD gs_idMainThread = 0; // if it's FALSE, some secondary thread is holding the GUI lock -static bool s_bGuiOwnedByMainThread = TRUE; +static bool gs_bGuiOwnedByMainThread = TRUE; // critical section which controls access to all GUI functions: any secondary // thread (i.e. except the main one) must enter this crit section before doing // any GUI calls -static wxCriticalSection *s_critsectGui = NULL; +static wxCriticalSection *gs_critsectGui = NULL; -// critical section which protects s_nWaitingForGui variable -static wxCriticalSection *s_critsectWaitingForGui = NULL; +// critical section which protects gs_nWaitingForGui variable +static wxCriticalSection *gs_critsectWaitingForGui = NULL; // number of threads waiting for GUI in wxMutexGuiEnter() -static size_t s_nWaitingForGui = 0; +static size_t gs_nWaitingForGui = 0; // are we waiting for a thread termination? -static bool s_waitingForThread = FALSE; +static bool gs_waitingForThread = FALSE; // ============================================================================ // Windows implementation of thread classes @@ -169,6 +182,46 @@ wxMutexError wxMutex::Unlock() class wxConditionInternal { public: + wxConditionInternal() + { + event = ::CreateEvent( + NULL, // default secutiry + FALSE, // not manual reset + FALSE, // nonsignaled initially + NULL // nameless event + ); + if ( !event ) + { + wxLogSysError(_("Can not create event object.")); + } + waiters = 0; + } + + bool Wait(wxMutex& mutex, DWORD timeout) + { + mutex.Unlock(); + waiters++; + + // FIXME this should be MsgWaitForMultipleObjects() as well probably + DWORD rc = ::WaitForSingleObject(event, timeout); + + waiters--; + mutex.Lock(); + + return rc != WAIT_TIMEOUT; + } + + ~wxConditionInternal() + { + if ( event ) + { + if ( !::CloseHandle(event) ) + { + wxLogLastError("CloseHandle(event)"); + } + } + } + HANDLE event; int waiters; }; @@ -176,59 +229,46 @@ public: wxCondition::wxCondition() { p_internal = new wxConditionInternal; - p_internal->event = CreateEvent(NULL, FALSE, FALSE, NULL); - if ( !p_internal->event ) - { - wxLogSysError(_("Can not create event object.")); - } - - p_internal->waiters = 0; } wxCondition::~wxCondition() { - CloseHandle(p_internal->event); + delete p_internal; } void wxCondition::Wait(wxMutex& mutex) { - mutex.Unlock(); - p_internal->waiters++; - WaitForSingleObject(p_internal->event, INFINITE); - p_internal->waiters--; - mutex.Lock(); + (void)p_internal->Wait(mutex, INFINITE); } bool wxCondition::Wait(wxMutex& mutex, unsigned long sec, unsigned long nsec) { - DWORD ret; - - mutex.Unlock(); - p_internal->waiters++; - ret = WaitForSingleObject(p_internal->event, (sec*1000)+(nsec/1000000)); - p_internal->waiters--; - mutex.Lock(); - - return (ret != WAIT_TIMEOUT); + return p_internal->Wait(mutex, sec*1000 + nsec/1000000); } void wxCondition::Signal() { - SetEvent(p_internal->event); + // set the event to signaled: if a thread is already waiting on it, it will + // be woken up, otherwise the event will remain in the signaled state until + // someone waits on it. In any case, the system will return it to a non + // signalled state afterwards. If multiple threads are waiting, only one + // will be woken up. + if ( !::SetEvent(p_internal->event) ) + { + wxLogLastError("SetEvent"); + } } void wxCondition::Broadcast() { - int i; - - for (i=0;iwaiters;i++) + // this works because all these threads are already waiting and so each + // SetEvent() inside Signal() is really a PulseEvent() because the event + // state is immediately returned to non-signaled + for ( int i = 0; i < p_internal->waiters; i++ ) { - if ( SetEvent(p_internal->event) == 0 ) - { - wxLogSysError(_("Couldn't change the state of event object.")); - } + Signal(); } } @@ -238,7 +278,7 @@ void wxCondition::Broadcast() wxCriticalSection::wxCriticalSection() { - wxASSERT_MSG( sizeof(CRITICAL_SECTION) == sizeof(m_buffer), + wxASSERT_MSG( sizeof(CRITICAL_SECTION) <= sizeof(m_buffer), _T("must increase buffer size in wx/thread.h") ); ::InitializeCriticalSection((CRITICAL_SECTION *)m_buffer); @@ -276,6 +316,24 @@ public: m_priority = WXTHREAD_DEFAULT_PRIORITY; } + ~wxThreadInternal() + { + Free(); + } + + void Free() + { + if ( m_hThread ) + { + if ( !::CloseHandle(m_hThread) ) + { + wxLogLastError("CloseHandle(thread)"); + } + + m_hThread = 0; + } + } + // create a new (suspended) thread (for the given thread object) bool Create(wxThread *thread); @@ -289,7 +347,7 @@ public: wxThreadState GetState() const { return m_state; } // thread priority - void SetPriority(unsigned int priority) { m_priority = priority; } + void SetPriority(unsigned int priority); unsigned int GetPriority() const { return m_priority; } // thread handle and id @@ -309,41 +367,38 @@ private: DWORD wxThreadInternal::WinThreadStart(wxThread *thread) { // store the thread object in the TLS - if ( !::TlsSetValue(s_tlsThisThread, thread) ) + if ( !::TlsSetValue(gs_tlsThisThread, thread) ) { wxLogSysError(_("Can not start thread: error writing TLS.")); return (DWORD)-1; } - DWORD ret = (DWORD)thread->Entry(); + DWORD rc = (DWORD)thread->Entry(); + + // enter m_critsect before changing the thread state + thread->m_critsect.Enter(); + bool wasCancelled = thread->p_internal->GetState() == STATE_CANCELED; thread->p_internal->SetState(STATE_EXITED); + thread->m_critsect.Leave(); + thread->OnExit(); - delete thread; + // if the thread was cancelled (from Delete()), then it the handle is still + // needed there + if ( thread->IsDetached() && !wasCancelled ) + { + // auto delete + delete thread; + } + //else: the joinable threads handle will be closed when Wait() is done - return ret; + return rc; } -bool wxThreadInternal::Create(wxThread *thread) +void wxThreadInternal::SetPriority(unsigned int priority) { - m_hThread = ::CreateThread - ( - NULL, // default security - 0, // default stack size - (LPTHREAD_START_ROUTINE) // thread entry point - wxThreadInternal::WinThreadStart, // - (LPVOID)thread, // parameter - CREATE_SUSPENDED, // flags - &m_tid // [out] thread id - ); - - if ( m_hThread == NULL ) - { - wxLogSysError(_("Can't create thread")); - - return FALSE; - } + m_priority = priority; // translate wxWindows priority to the Windows one int win_priority; @@ -363,10 +418,49 @@ bool wxThreadInternal::Create(wxThread *thread) win_priority = THREAD_PRIORITY_NORMAL; } - if ( ::SetThreadPriority(m_hThread, win_priority) == 0 ) + if ( !::SetThreadPriority(m_hThread, win_priority) ) { wxLogSysError(_("Can't set thread priority")); } +} + +bool wxThreadInternal::Create(wxThread *thread) +{ + // for compilers which have it, we should use C RTL function for thread + // creation instead of Win32 API one because otherwise we will have memory + // leaks if the thread uses C RTL (and most threads do) +#ifdef __VISUALC__ + typedef unsigned (__stdcall *RtlThreadStart)(void *); + + m_hThread = (HANDLE)_beginthreadex(NULL, 0, + (RtlThreadStart) + wxThreadInternal::WinThreadStart, + thread, CREATE_SUSPENDED, + (unsigned int *)&m_tid); +#else // !VC++ + m_hThread = ::CreateThread + ( + NULL, // default security + 0, // default stack size + (LPTHREAD_START_ROUTINE) // thread entry point + wxThreadInternal::WinThreadStart, // + (LPVOID)thread, // parameter + CREATE_SUSPENDED, // flags + &m_tid // [out] thread id + ); +#endif // VC++/!VC++ + + if ( m_hThread == NULL ) + { + wxLogSysError(_("Can't create thread")); + + return FALSE; + } + + if ( m_priority != WXTHREAD_DEFAULT_PRIORITY ) + { + SetPriority(m_priority); + } return TRUE; } @@ -406,7 +500,7 @@ bool wxThreadInternal::Resume() wxThread *wxThread::This() { - wxThread *thread = (wxThread *)::TlsGetValue(s_tlsThisThread); + wxThread *thread = (wxThread *)::TlsGetValue(gs_tlsThisThread); // be careful, 0 may be a valid return value as well if ( !thread && (::GetLastError() != NO_ERROR) ) @@ -421,16 +515,13 @@ wxThread *wxThread::This() bool wxThread::IsMain() { - return ::GetCurrentThreadId() == s_idMainThread; + return ::GetCurrentThreadId() == gs_idMainThread; } -#ifdef Yield - #undef Yield -#endif - void wxThread::Yield() { - // 0 argument to Sleep() is special + // 0 argument to Sleep() is special and means to just give away the rest of + // our timeslice ::Sleep(0); } @@ -439,11 +530,28 @@ void wxThread::Sleep(unsigned long milliseconds) ::Sleep(milliseconds); } +// ctor and dtor +// ------------- + +wxThread::wxThread(wxThreadKind kind) +{ + p_internal = new wxThreadInternal(); + + m_isDetached = kind == wxTHREAD_DETACHED; +} + +wxThread::~wxThread() +{ + delete p_internal; +} + // create/start thread // ------------------- wxThreadError wxThread::Create() { + wxCriticalSectionLocker lock(m_critsect); + if ( !p_internal->Create(this) ) return wxTHREAD_NO_RESOURCE; @@ -460,6 +568,7 @@ wxThreadError wxThread::Run() return wxTHREAD_RUNNING; } + // the thread has just been created and is still suspended - let it run return Resume(); } @@ -483,7 +592,23 @@ wxThreadError wxThread::Resume() // stopping thread // --------------- -wxThread::ExitCode wxThread::Delete() +wxThread::ExitCode wxThread::Wait() +{ + // although under Windows we can wait for any thread, it's an error to + // wait for a detached one in wxWin API + wxCHECK_MSG( !IsDetached(), (ExitCode)-1, + _T("can't wait for detached thread") ); + + ExitCode rc = (ExitCode)-1; + + (void)Delete(&rc); + + p_internal->Free(); + + return rc; +} + +wxThreadError wxThread::Delete(ExitCode *pRc) { ExitCode rc = 0; @@ -491,24 +616,28 @@ wxThread::ExitCode wxThread::Delete() if ( IsPaused() ) Resume(); + HANDLE hThread = p_internal->GetHandle(); + if ( IsRunning() ) { if ( IsMain() ) { // set flag for wxIsWaitingForThread() - s_waitingForThread = TRUE; + gs_waitingForThread = TRUE; +#if wxUSE_GUI wxBeginBusyCursor(); +#endif // wxUSE_GUI } - HANDLE hThread; + // ask the thread to terminate { wxCriticalSectionLocker lock(m_critsect); p_internal->Cancel(); - hThread = p_internal->GetHandle(); } +#if wxUSE_GUI // we can't just wait for the thread to terminate because it might be // calling some GUI functions and so it will never terminate before we // process the Windows messages that result from these functions @@ -530,7 +659,7 @@ wxThread::ExitCode wxThread::Delete() // error wxLogSysError(_("Can not wait for thread termination")); Kill(); - return (ExitCode)-1; + return wxTHREAD_KILLED; case WAIT_OBJECT_0: // thread we're waiting for terminated @@ -543,14 +672,14 @@ wxThread::ExitCode wxThread::Delete() // WM_QUIT received: kill the thread Kill(); - return (ExitCode)-1; + return wxTHREAD_KILLED; } if ( IsMain() ) { // give the thread we're waiting for chance to exit // from the GUI call it might have been in - if ( (s_nWaitingForGui > 0) && wxGuiOwnedByMainThread() ) + if ( (gs_nWaitingForGui > 0) && wxGuiOwnedByMainThread() ) { wxMutexGuiLeave(); } @@ -562,28 +691,50 @@ wxThread::ExitCode wxThread::Delete() wxFAIL_MSG(wxT("unexpected result of MsgWaitForMultipleObject")); } } while ( result != WAIT_OBJECT_0 ); +#else // !wxUSE_GUI + // simply wait for the thread to terminate + // + // OTOH, even console apps create windows (in wxExecute, for WinSock + // &c), so may be use MsgWaitForMultipleObject() too here? + if ( WaitForSingleObject(hThread, INFINITE) != WAIT_OBJECT_0 ) + { + wxFAIL_MSG(wxT("unexpected result of WaitForSingleObject")); + } +#endif // wxUSE_GUI/!wxUSE_GUI if ( IsMain() ) { - s_waitingForThread = FALSE; + gs_waitingForThread = FALSE; +#if wxUSE_GUI wxEndBusyCursor(); +#endif // wxUSE_GUI } + } - if ( !::GetExitCodeThread(hThread, (LPDWORD)&rc) ) - { - wxLogLastError("GetExitCodeThread"); - - rc = (ExitCode)-1; - } + if ( !::GetExitCodeThread(hThread, (LPDWORD)&rc) ) + { + wxLogLastError("GetExitCodeThread"); - wxASSERT_MSG( (LPVOID)rc != (LPVOID)STILL_ACTIVE, - wxT("thread must be already terminated.") ); + rc = (ExitCode)-1; + } - ::CloseHandle(hThread); + if ( IsDetached() ) + { + // if the thread exits normally, this is done in WinThreadStart, but in + // this case it would have been too early because + // MsgWaitForMultipleObject() would fail if the therad handle was + // closed while we were waiting on it, so we must do it here + delete this; } - return rc; + wxASSERT_MSG( (DWORD)rc != STILL_ACTIVE, + wxT("thread must be already terminated.") ); + + if ( pRc ) + *pRc = rc; + + return rc == (ExitCode)-1 ? wxTHREAD_MISC_ERROR : wxTHREAD_NO_ERROR; } wxThreadError wxThread::Kill() @@ -598,20 +749,37 @@ wxThreadError wxThread::Kill() return wxTHREAD_MISC_ERROR; } - delete this; + p_internal->Free(); + + if ( IsDetached() ) + { + delete this; + } return wxTHREAD_NO_ERROR; } -void wxThread::Exit(void *status) +void wxThread::Exit(ExitCode status) { - delete this; + p_internal->Free(); + if ( IsDetached() ) + { + delete this; + } + +#ifdef __VISUALC__ + _endthreadex((unsigned)status); +#else // !VC++ ::ExitThread((DWORD)status); +#endif // VC++/!VC++ wxFAIL_MSG(wxT("Couldn't return from ExitThread()!")); } +// priority setting +// ---------------- + void wxThread::SetPriority(unsigned int prio) { wxCriticalSectionLocker lock(m_critsect); @@ -621,28 +789,28 @@ void wxThread::SetPriority(unsigned int prio) unsigned int wxThread::GetPriority() const { - wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); + wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast return p_internal->GetPriority(); } -unsigned long wxThread::GetID() const +unsigned long wxThread::GetId() const { - wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); + wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast return (unsigned long)p_internal->GetId(); } bool wxThread::IsRunning() const { - wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); + wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast return p_internal->GetState() == STATE_RUNNING; } bool wxThread::IsAlive() const { - wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); + wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast return (p_internal->GetState() == STATE_RUNNING) || (p_internal->GetState() == STATE_PAUSED); @@ -650,28 +818,18 @@ bool wxThread::IsAlive() const bool wxThread::IsPaused() const { - wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); + wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast - return (p_internal->GetState() == STATE_PAUSED); + return p_internal->GetState() == STATE_PAUSED; } bool wxThread::TestDestroy() { - wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); + wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast return p_internal->GetState() == STATE_CANCELED; } -wxThread::wxThread() -{ - p_internal = new wxThreadInternal(); -} - -wxThread::~wxThread() -{ - delete p_internal; -} - // ---------------------------------------------------------------------------- // Automatic initialization for thread module // ---------------------------------------------------------------------------- @@ -691,8 +849,8 @@ IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule) bool wxThreadModule::OnInit() { // allocate TLS index for storing the pointer to the current thread - s_tlsThisThread = ::TlsAlloc(); - if ( s_tlsThisThread == 0xFFFFFFFF ) + gs_tlsThisThread = ::TlsAlloc(); + if ( gs_tlsThisThread == 0xFFFFFFFF ) { // in normal circumstances it will only happen if all other // TLS_MINIMUM_AVAILABLE (>= 64) indices are already taken - in other @@ -706,10 +864,10 @@ bool wxThreadModule::OnInit() // main thread doesn't have associated wxThread object, so store 0 in the // TLS instead - if ( !::TlsSetValue(s_tlsThisThread, (LPVOID)0) ) + if ( !::TlsSetValue(gs_tlsThisThread, (LPVOID)0) ) { - ::TlsFree(s_tlsThisThread); - s_tlsThisThread = 0xFFFFFFFF; + ::TlsFree(gs_tlsThisThread); + gs_tlsThisThread = 0xFFFFFFFF; wxLogSysError(_("Thread module initialization failed: " "can not store value in thread local storage")); @@ -717,36 +875,37 @@ bool wxThreadModule::OnInit() return FALSE; } - s_critsectWaitingForGui = new wxCriticalSection(); + gs_critsectWaitingForGui = new wxCriticalSection(); - s_critsectGui = new wxCriticalSection(); - s_critsectGui->Enter(); + gs_critsectGui = new wxCriticalSection(); + gs_critsectGui->Enter(); // no error return for GetCurrentThreadId() - s_idMainThread = ::GetCurrentThreadId(); + gs_idMainThread = ::GetCurrentThreadId(); return TRUE; } void wxThreadModule::OnExit() { - if ( !::TlsFree(s_tlsThisThread) ) + if ( !::TlsFree(gs_tlsThisThread) ) { wxLogLastError("TlsFree failed."); } - if ( s_critsectGui ) + if ( gs_critsectGui ) { - s_critsectGui->Leave(); - delete s_critsectGui; - s_critsectGui = NULL; + gs_critsectGui->Leave(); + delete gs_critsectGui; + gs_critsectGui = NULL; } - wxDELETE(s_critsectWaitingForGui); + delete gs_critsectWaitingForGui; + gs_critsectWaitingForGui = NULL; } // ---------------------------------------------------------------------------- -// under Windows, these functions are implemented usign a critical section and +// under Windows, these functions are implemented using a critical section and // not a mutex, so the names are a bit confusing // ---------------------------------------------------------------------------- @@ -760,38 +919,38 @@ void WXDLLEXPORT wxMutexGuiEnter() // set the flag telling to the main thread that we want to do some GUI { - wxCriticalSectionLocker enter(*s_critsectWaitingForGui); + wxCriticalSectionLocker enter(*gs_critsectWaitingForGui); - s_nWaitingForGui++; + gs_nWaitingForGui++; } wxWakeUpMainThread(); // now we may block here because the main thread will soon let us in // (during the next iteration of OnIdle()) - s_critsectGui->Enter(); + gs_critsectGui->Enter(); } void WXDLLEXPORT wxMutexGuiLeave() { - wxCriticalSectionLocker enter(*s_critsectWaitingForGui); + wxCriticalSectionLocker enter(*gs_critsectWaitingForGui); if ( wxThread::IsMain() ) { - s_bGuiOwnedByMainThread = FALSE; + gs_bGuiOwnedByMainThread = FALSE; } else { // decrement the number of waiters now - wxASSERT_MSG( s_nWaitingForGui > 0, + wxASSERT_MSG( gs_nWaitingForGui > 0, wxT("calling wxMutexGuiLeave() without entering it first?") ); - s_nWaitingForGui--; + gs_nWaitingForGui--; wxWakeUpMainThread(); } - s_critsectGui->Leave(); + gs_critsectGui->Leave(); } void WXDLLEXPORT wxMutexGuiLeaveOrEnter() @@ -799,17 +958,17 @@ void WXDLLEXPORT wxMutexGuiLeaveOrEnter() wxASSERT_MSG( wxThread::IsMain(), wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") ); - wxCriticalSectionLocker enter(*s_critsectWaitingForGui); + wxCriticalSectionLocker enter(*gs_critsectWaitingForGui); - if ( s_nWaitingForGui == 0 ) + if ( gs_nWaitingForGui == 0 ) { // no threads are waiting for GUI - so we may acquire the lock without // any danger (but only if we don't already have it) if ( !wxGuiOwnedByMainThread() ) { - s_critsectGui->Enter(); + gs_critsectGui->Enter(); - s_bGuiOwnedByMainThread = TRUE; + gs_bGuiOwnedByMainThread = TRUE; } //else: already have it, nothing to do } @@ -826,14 +985,14 @@ void WXDLLEXPORT wxMutexGuiLeaveOrEnter() bool WXDLLEXPORT wxGuiOwnedByMainThread() { - return s_bGuiOwnedByMainThread; + return gs_bGuiOwnedByMainThread; } // wake up the main thread if it's in ::GetMessage() void WXDLLEXPORT wxWakeUpMainThread() { // sending any message would do - hopefully WM_NULL is harmless enough - if ( !::PostThreadMessage(s_idMainThread, WM_NULL, 0, 0) ) + if ( !::PostThreadMessage(gs_idMainThread, WM_NULL, 0, 0) ) { // should never happen wxLogLastError("PostThreadMessage(WM_NULL)"); @@ -842,7 +1001,7 @@ void WXDLLEXPORT wxWakeUpMainThread() bool WXDLLEXPORT wxIsWaitingForThread() { - return s_waitingForThread; + return gs_waitingForThread; } #endif // wxUSE_THREADS diff --git a/src/msw/utils.cpp b/src/msw/utils.cpp index 8b36c7a3de..d2a2872995 100644 --- a/src/msw/utils.cpp +++ b/src/msw/utils.cpp @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: utils.cpp +// Name: mse/utils.cpp // Purpose: Various utilities // Author: Julian Smart // Modified by: @@ -9,6 +9,14 @@ // Licence: wxWindows license ///////////////////////////////////////////////////////////////////////////// +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + #ifdef __GNUG__ // #pragma implementation "utils.h" // Note: this is done in utilscmn.cpp now. #endif @@ -21,18 +29,16 @@ #endif #ifndef WX_PRECOMP - #include "wx/setup.h" #include "wx/utils.h" #include "wx/app.h" #include "wx/cursor.h" #endif //WX_PRECOMP -#include "wx/msw/private.h" +#include "wx/msw/private.h" // includes + #include "wx/timer.h" #include "wx/intl.h" -#include - #include #if !defined(__GNUWIN32__) && !defined(__WXWINE__) && !defined(__SALFORDC__) @@ -118,36 +124,61 @@ // __VISUALC__ /// END for console support +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + // In the WIN.INI file static const wxChar WX_SECTION[] = wxT("wxWindows"); +static const wxChar eUSERNAME[] = wxT("UserName"); + +// these are only used under Win16 +#ifndef __WIN32__ static const wxChar eHOSTNAME[] = wxT("HostName"); static const wxChar eUSERID[] = wxT("UserId"); -static const wxChar eUSERNAME[] = wxT("UserName"); +#endif // !Win32 -// For the following functions we SHOULD fill in support -// for Windows-NT (which I don't know) as I assume it begin -// a POSIX Unix (so claims MS) that it has some special -// functions beyond those provided by WinSock +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// get host name and related +// ---------------------------------------------------------------------------- // Get full hostname (eg. DoDo.BSn-Germany.crg.de) bool wxGetHostName(wxChar *buf, int maxSize) { #if defined(__WIN32__) && !defined(__TWIN32__) - DWORD nSize = maxSize; - return (::GetComputerName(buf, &nSize) != 0); + // TODO should use GetComputerNameEx() when available + + DWORD nSize = maxSize; + if ( !::GetComputerName(buf, &nSize) ) + { + wxLogLastError("GetComputerName"); + + return FALSE; + } + + return TRUE; #else - wxChar *sysname; - const wxChar *default_host = wxT("noname"); - - if ((sysname = wxGetenv(wxT("SYSTEM_NAME"))) == NULL) { - GetProfileString(WX_SECTION, eHOSTNAME, default_host, buf, maxSize - 1); - } else - wxStrncpy(buf, sysname, maxSize - 1); - buf[maxSize] = wxT('\0'); - return *buf ? TRUE : FALSE; + wxChar *sysname; + const wxChar *default_host = wxT("noname"); + + if ((sysname = wxGetenv(wxT("SYSTEM_NAME"))) == NULL) { + GetProfileString(WX_SECTION, eHOSTNAME, default_host, buf, maxSize - 1); + } else + wxStrncpy(buf, sysname, maxSize - 1); + buf[maxSize] = wxT('\0'); + return *buf ? TRUE : FALSE; #endif } +bool wxGetFullHostName(wxChar *buf, int maxSize) +{ + return wxGetHostName(buf, maxSize); +} + // Get user ID e.g. jacs bool wxGetUserId(wxChar *buf, int maxSize) { @@ -166,23 +197,23 @@ bool wxGetUserId(wxChar *buf, int maxSize) return TRUE; #else // Win16 or Win32s - wxChar *user; - const wxChar *default_id = wxT("anonymous"); + wxChar *user; + const wxChar *default_id = wxT("anonymous"); - // Can't assume we have NIS (PC-NFS) or some other ID daemon - // So we ... - if ( (user = wxGetenv(wxT("USER"))) == NULL && - (user = wxGetenv(wxT("LOGNAME"))) == NULL ) - { - // Use wxWindows configuration data (comming soon) - GetProfileString(WX_SECTION, eUSERID, default_id, buf, maxSize - 1); - } - else - { - wxStrncpy(buf, user, maxSize - 1); - } + // Can't assume we have NIS (PC-NFS) or some other ID daemon + // So we ... + if ( (user = wxGetenv(wxT("USER"))) == NULL && + (user = wxGetenv(wxT("LOGNAME"))) == NULL ) + { + // Use wxWindows configuration data (comming soon) + GetProfileString(WX_SECTION, eUSERID, default_id, buf, maxSize - 1); + } + else + { + wxStrncpy(buf, user, maxSize - 1); + } - return *buf ? TRUE : FALSE; + return *buf ? TRUE : FALSE; #endif } @@ -190,244 +221,263 @@ bool wxGetUserId(wxChar *buf, int maxSize) bool wxGetUserName(wxChar *buf, int maxSize) { #if wxUSE_PENWINDOWS && !defined(__WATCOMC__) && !defined(__GNUWIN32__) - extern HANDLE g_hPenWin; // PenWindows Running? - if (g_hPenWin) - { - // PenWindows Does have a user concept! - // Get the current owner of the recognizer - GetPrivateProfileString("Current", "User", default_name, wxBuffer, maxSize - 1, "PENWIN.INI"); - strncpy(buf, wxBuffer, maxSize - 1); - } - else + extern HANDLE g_hPenWin; // PenWindows Running? + if (g_hPenWin) + { + // PenWindows Does have a user concept! + // Get the current owner of the recognizer + GetPrivateProfileString("Current", "User", default_name, wxBuffer, maxSize - 1, "PENWIN.INI"); + strncpy(buf, wxBuffer, maxSize - 1); + } + else #endif - { + { #ifdef USE_NET_API - CHAR szUserName[256]; - if ( !wxGetUserId(szUserName, WXSIZEOF(szUserName)) ) - return FALSE; + CHAR szUserName[256]; + if ( !wxGetUserId(szUserName, WXSIZEOF(szUserName)) ) + return FALSE; - // TODO how to get the domain name? - CHAR *szDomain = ""; + // TODO how to get the domain name? + CHAR *szDomain = ""; - // the code is based on the MSDN example (also see KB article Q119670) - WCHAR wszUserName[256]; // Unicode user name - WCHAR wszDomain[256]; - LPBYTE ComputerName; + // the code is based on the MSDN example (also see KB article Q119670) + WCHAR wszUserName[256]; // Unicode user name + WCHAR wszDomain[256]; + LPBYTE ComputerName; - USER_INFO_2 *ui2; // User structure + USER_INFO_2 *ui2; // User structure - // Convert ANSI user name and domain to Unicode - MultiByteToWideChar( CP_ACP, 0, szUserName, strlen(szUserName)+1, - wszUserName, WXSIZEOF(wszUserName) ); - MultiByteToWideChar( CP_ACP, 0, szDomain, strlen(szDomain)+1, - wszDomain, WXSIZEOF(wszDomain) ); + // Convert ANSI user name and domain to Unicode + MultiByteToWideChar( CP_ACP, 0, szUserName, strlen(szUserName)+1, + wszUserName, WXSIZEOF(wszUserName) ); + MultiByteToWideChar( CP_ACP, 0, szDomain, strlen(szDomain)+1, + wszDomain, WXSIZEOF(wszDomain) ); - // Get the computer name of a DC for the domain. - if ( NetGetDCName( NULL, wszDomain, &ComputerName ) != NERR_Success ) - { - wxLogError(wxT("Can not find domain controller")); + // Get the computer name of a DC for the domain. + if ( NetGetDCName( NULL, wszDomain, &ComputerName ) != NERR_Success ) + { + wxLogError(wxT("Can not find domain controller")); - goto error; - } + goto error; + } - // Look up the user on the DC - NET_API_STATUS status = NetUserGetInfo( (LPWSTR)ComputerName, - (LPWSTR)&wszUserName, - 2, // level - we want USER_INFO_2 - (LPBYTE *) &ui2 ); - switch ( status ) - { - case NERR_Success: - // ok - break; + // Look up the user on the DC + NET_API_STATUS status = NetUserGetInfo( (LPWSTR)ComputerName, + (LPWSTR)&wszUserName, + 2, // level - we want USER_INFO_2 + (LPBYTE *) &ui2 ); + switch ( status ) + { + case NERR_Success: + // ok + break; - case NERR_InvalidComputer: - wxLogError(wxT("Invalid domain controller name.")); + case NERR_InvalidComputer: + wxLogError(wxT("Invalid domain controller name.")); - goto error; + goto error; - case NERR_UserNotFound: - wxLogError(wxT("Invalid user name '%s'."), szUserName); + case NERR_UserNotFound: + wxLogError(wxT("Invalid user name '%s'."), szUserName); - goto error; + goto error; - default: - wxLogSysError(wxT("Can't get information about user")); + default: + wxLogSysError(wxT("Can't get information about user")); - goto error; - } + goto error; + } - // Convert the Unicode full name to ANSI - WideCharToMultiByte( CP_ACP, 0, ui2->usri2_full_name, -1, - buf, maxSize, NULL, NULL ); + // Convert the Unicode full name to ANSI + WideCharToMultiByte( CP_ACP, 0, ui2->usri2_full_name, -1, + buf, maxSize, NULL, NULL ); - return TRUE; + return TRUE; error: - wxLogError(wxT("Couldn't look up full user name.")); + wxLogError(wxT("Couldn't look up full user name.")); - return FALSE; + return FALSE; #else // !USE_NET_API - // Could use NIS, MS-Mail or other site specific programs - // Use wxWindows configuration data - bool ok = GetProfileString(WX_SECTION, eUSERNAME, wxT(""), buf, maxSize - 1) != 0; - if ( !ok ) - { - ok = wxGetUserId(buf, maxSize); - } + // Could use NIS, MS-Mail or other site specific programs + // Use wxWindows configuration data + bool ok = GetProfileString(WX_SECTION, eUSERNAME, wxT(""), buf, maxSize - 1) != 0; + if ( !ok ) + { + ok = wxGetUserId(buf, maxSize); + } - if ( !ok ) - { - wxStrncpy(buf, wxT("Unknown User"), maxSize); - } + if ( !ok ) + { + wxStrncpy(buf, wxT("Unknown User"), maxSize); + } #endif // Win32/16 - } + } - return TRUE; + return TRUE; } -int wxKill(long pid, int sig) +const wxChar* wxGetHomeDir(wxString *pstr) { - return 0; -} + wxString& strDir = *pstr; -// -// Execute a program in an Interactive Shell -// -bool -wxShell(const wxString& command) -{ - wxChar *shell; - if ((shell = wxGetenv(wxT("COMSPEC"))) == NULL) - shell = wxT("\\COMMAND.COM"); + #if defined(__UNIX__) && !defined(__TWIN32__) + const wxChar *szHome = wxGetenv("HOME"); + if ( szHome == NULL ) { + // we're homeless... + wxLogWarning(_("can't find user's HOME, using current directory.")); + strDir = wxT("."); + } + else + strDir = szHome; - wxChar tmp[255]; - if (command != wxT("")) - wxSprintf(tmp, wxT("%s /c %s"), shell, WXSTRINGCAST command); - else - wxStrcpy(tmp, shell); + // add a trailing slash if needed + if ( strDir.Last() != wxT('/') ) + strDir << wxT('/'); + #else // Windows + #ifdef __WIN32__ + const wxChar *szHome = wxGetenv(wxT("HOMEDRIVE")); + if ( szHome != NULL ) + strDir << szHome; + szHome = wxGetenv(wxT("HOMEPATH")); + if ( szHome != NULL ) { + strDir << szHome; - return (wxExecute((wxChar *)tmp, FALSE) != 0); -} + // the idea is that under NT these variables have default values + // of "%systemdrive%:" and "\\". As we don't want to create our + // config files in the root directory of the system drive, we will + // create it in our program's dir. However, if the user took care + // to set HOMEPATH to something other than "\\", we suppose that he + // knows what he is doing and use the supplied value. + if ( wxStrcmp(szHome, wxT("\\")) != 0 ) + return strDir.c_str(); + } -// Get free memory in bytes, or -1 if cannot determine amount (e.g. on UNIX) -long wxGetFreeMemory() -{ -#if defined(__WIN32__) && !defined(__BORLANDC__) && !defined(__TWIN32__) - MEMORYSTATUS memStatus; - memStatus.dwLength = sizeof(MEMORYSTATUS); - GlobalMemoryStatus(&memStatus); - return memStatus.dwAvailPhys; -#else - return (long)GetFreeSpace(0); -#endif -} + #else // Win16 + // Win16 has no idea about home, so use the working directory instead + #endif // WIN16/32 -// Sleep for nSecs seconds. Attempt a Windows implementation using timers. -static bool inTimer = FALSE; -class wxSleepTimer: public wxTimer -{ - public: - inline void Notify() - { - inTimer = FALSE; - Stop(); - } -}; + // 260 was taken from windef.h + #ifndef MAX_PATH + #define MAX_PATH 260 + #endif -static wxTimer *wxTheSleepTimer = NULL; + wxString strPath; + ::GetModuleFileName(::GetModuleHandle(NULL), + strPath.GetWriteBuf(MAX_PATH), MAX_PATH); + strPath.UngetWriteBuf(); -void wxUsleep(unsigned long milliseconds) -{ -#ifdef __WIN32__ - ::Sleep(milliseconds); -#else - if (inTimer) - return; + // extract the dir name + wxSplitPath(strPath, &strDir, NULL, NULL); - wxTheSleepTimer = new wxSleepTimer; - inTimer = TRUE; - wxTheSleepTimer->Start(milliseconds); - while (inTimer) - { - if (wxTheApp->Pending()) - wxTheApp->Dispatch(); - } - delete wxTheSleepTimer; - wxTheSleepTimer = NULL; -#endif + #endif // UNIX/Win + + return strDir.c_str(); } -void wxSleep(int nSecs) +wxChar *wxGetUserHome(const wxString& user) { -#if 0 // WIN32 hangs app - Sleep( 1000*nSecs ); -#else - if (inTimer) - return; + // VZ: the old code here never worked for user != "" anyhow! Moreover, it + // returned sometimes a malloc()'d pointer, sometimes a pointer to a + // static buffer and sometimes I don't even know what. + static wxString s_home; - wxTheSleepTimer = new wxSleepTimer; - inTimer = TRUE; - wxTheSleepTimer->Start(nSecs*1000); - while (inTimer) - { - if (wxTheApp->Pending()) - wxTheApp->Dispatch(); - } - delete wxTheSleepTimer; - wxTheSleepTimer = NULL; -#endif + return (wxChar *)wxGetHomeDir(&s_home); } -// Consume all events until no more left -void wxFlushEvents() +bool wxDirExists(const wxString& dir) { -// wxYield(); -} +#if defined(__WIN32__) + WIN32_FIND_DATA fileInfo; +#else // Win16 + #ifdef __BORLANDC__ + struct ffblk fileInfo; + #else + struct find_t fileInfo; + #endif +#endif // Win32/16 -// Output a debug mess., in a system dependent fashion. -void wxDebugMsg(const wxChar *fmt ...) -{ - va_list ap; - static wxChar buffer[512]; +#if defined(__WIN32__) + HANDLE h = ::FindFirstFile(dir, &fileInfo); - if (!wxTheApp->GetWantDebugOutput()) - return ; + if ( h == INVALID_HANDLE_VALUE ) + { + wxLogLastError("FindFirstFile"); - va_start(ap, fmt); + return FALSE; + } - wvsprintf(buffer,fmt,ap) ; - OutputDebugString((LPCTSTR)buffer) ; + ::FindClose(h); + + return (fileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; +#else // Win16 + // In Borland findfirst has a different argument + // ordering from _dos_findfirst. But _dos_findfirst + // _should_ be ok in both MS and Borland... why not? + #ifdef __BORLANDC__ + return (findfirst(dir, &fileInfo, _A_SUBDIR) == 0 && + (fileInfo.ff_attrib & _A_SUBDIR) != 0); + #else + return (_dos_findfirst(dir, _A_SUBDIR, &fileInfo) == 0) && + ((fileInfo.attrib & _A_SUBDIR) != 0); + #endif +#endif // Win32/16 +} - va_end(ap); +// ---------------------------------------------------------------------------- +// process management +// ---------------------------------------------------------------------------- + +int wxKill(long pid, int sig) +{ + // TODO use SendMessage(WM_QUIT) and TerminateProcess() if needed + + return 0; } -// Non-fatal error: pop up message box and (possibly) continue -void wxError(const wxString& msg, const wxString& title) +// Execute a program in an Interactive Shell +bool wxShell(const wxString& command) { - wxSprintf(wxBuffer, wxT("%s\nContinue?"), WXSTRINGCAST msg); - if (MessageBox(NULL, (LPCTSTR)wxBuffer, (LPCTSTR)WXSTRINGCAST title, - MB_ICONSTOP | MB_YESNO) == IDNO) - wxExit(); + wxChar *shell = wxGetenv(wxT("COMSPEC")); + if ( !shell ) + shell = wxT("\\COMMAND.COM"); + + wxString cmd; + if ( !command ) + { + // just the shell + cmd = shell; + } + else + { + // pass the command to execute to the command processor + cmd.Printf(wxT("%s /c %s"), shell, command.c_str()); + } + + return wxExecute(cmd, FALSE) != 0; } -// Fatal error: pop up message box and abort -void wxFatalError(const wxString& msg, const wxString& title) +// ---------------------------------------------------------------------------- +// misc +// ---------------------------------------------------------------------------- + +// Get free memory in bytes, or -1 if cannot determine amount (e.g. on UNIX) +long wxGetFreeMemory() { - wxSprintf(wxBuffer, wxT("%s: %s"), WXSTRINGCAST title, WXSTRINGCAST msg); - FatalAppExit(0, (LPCTSTR)wxBuffer); +#if defined(__WIN32__) && !defined(__BORLANDC__) && !defined(__TWIN32__) + MEMORYSTATUS memStatus; + memStatus.dwLength = sizeof(MEMORYSTATUS); + GlobalMemoryStatus(&memStatus); + return memStatus.dwAvailPhys; +#else + return (long)GetFreeSpace(0); +#endif } // Emit a beeeeeep void wxBell() { - // Removed by RD because IHMO syncronous sound is a Bad Thing. MessageBeep - // will do a similar thing anyway if there is no sound card... -//#ifdef __WIN32__ -// Beep(1000,1000) ; // 1kHz during 1 sec. -//#else - MessageBeep((UINT)-1) ; -//#endif + ::MessageBeep((UINT)-1); // default sound } // Chris Breeze 27/5/98: revised WIN32 code to @@ -477,6 +527,128 @@ int wxGetOsVersion(int *majorVsn, int *minorVsn) #endif } +// ---------------------------------------------------------------------------- +// sleep functions +// ---------------------------------------------------------------------------- + +#if wxUSE_GUI + +// Sleep for nSecs seconds. Attempt a Windows implementation using timers. +static bool gs_inTimer = FALSE; + +class wxSleepTimer: public wxTimer +{ +public: + virtual void Notify() + { + gs_inTimer = FALSE; + Stop(); + } +}; + +static wxTimer *wxTheSleepTimer = NULL; + +void wxUsleep(unsigned long milliseconds) +{ +#ifdef __WIN32__ + ::Sleep(milliseconds); +#else + if (gs_inTimer) + return; + + wxTheSleepTimer = new wxSleepTimer; + gs_inTimer = TRUE; + wxTheSleepTimer->Start(milliseconds); + while (gs_inTimer) + { + if (wxTheApp->Pending()) + wxTheApp->Dispatch(); + } + delete wxTheSleepTimer; + wxTheSleepTimer = NULL; +#endif +} + +void wxSleep(int nSecs) +{ + if (gs_inTimer) + return; + + wxTheSleepTimer = new wxSleepTimer; + gs_inTimer = TRUE; + wxTheSleepTimer->Start(nSecs*1000); + while (gs_inTimer) + { + if (wxTheApp->Pending()) + wxTheApp->Dispatch(); + } + delete wxTheSleepTimer; + wxTheSleepTimer = NULL; +} + +// Consume all events until no more left +void wxFlushEvents() +{ +// wxYield(); +} + +#elif defined(__WIN32__) // wxUSE_GUI + +void wxUsleep(unsigned long milliseconds) +{ + ::Sleep(milliseconds); +} + +void wxSleep(int nSecs) +{ + wxUsleep(1000*nSecs); +} + +#endif // wxUSE_GUI/!wxUSE_GUI + +// ---------------------------------------------------------------------------- +// deprecated (in favour of wxLog) log functions +// ---------------------------------------------------------------------------- + +#if wxUSE_GUI + +// Output a debug mess., in a system dependent fashion. +void wxDebugMsg(const wxChar *fmt ...) +{ + va_list ap; + static wxChar buffer[512]; + + if (!wxTheApp->GetWantDebugOutput()) + return ; + + va_start(ap, fmt); + + wvsprintf(buffer,fmt,ap) ; + OutputDebugString((LPCTSTR)buffer) ; + + va_end(ap); +} + +// Non-fatal error: pop up message box and (possibly) continue +void wxError(const wxString& msg, const wxString& title) +{ + wxSprintf(wxBuffer, wxT("%s\nContinue?"), WXSTRINGCAST msg); + if (MessageBox(NULL, (LPCTSTR)wxBuffer, (LPCTSTR)WXSTRINGCAST title, + MB_ICONSTOP | MB_YESNO) == IDNO) + wxExit(); +} + +// Fatal error: pop up message box and abort +void wxFatalError(const wxString& msg, const wxString& title) +{ + wxSprintf(wxBuffer, wxT("%s: %s"), WXSTRINGCAST title, WXSTRINGCAST msg); + FatalAppExit(0, (LPCTSTR)wxBuffer); +} + +// ---------------------------------------------------------------------------- +// functions to work with .INI files +// ---------------------------------------------------------------------------- + // Reading and writing resources (eg WIN.INI, .Xdefaults) #if wxUSE_RESOURCES bool wxWriteResource(const wxString& section, const wxString& entry, const wxString& value, const wxString& file) @@ -495,84 +667,87 @@ bool wxWriteResource(const wxString& section, const wxString& entry, const wxStr bool wxWriteResource(const wxString& section, const wxString& entry, float value, const wxString& file) { - wxChar buf[50]; - wxSprintf(buf, wxT("%.4f"), value); - return wxWriteResource(section, entry, buf, file); + wxString buf; + buf.Printf(wxT("%.4f"), value); + + return wxWriteResource(section, entry, buf, file); } bool wxWriteResource(const wxString& section, const wxString& entry, long value, const wxString& file) { - wxChar buf[50]; - wxSprintf(buf, wxT("%ld"), value); - return wxWriteResource(section, entry, buf, file); + wxString buf; + buf.Printf(wxT("%ld"), value); + + return wxWriteResource(section, entry, buf, file); } bool wxWriteResource(const wxString& section, const wxString& entry, int value, const wxString& file) { - wxChar buf[50]; - wxSprintf(buf, wxT("%d"), value); - return wxWriteResource(section, entry, buf, file); + wxString buf; + buf.Printf(wxT("%d"), value); + + return wxWriteResource(section, entry, buf, file); } bool wxGetResource(const wxString& section, const wxString& entry, wxChar **value, const wxString& file) { - static const wxChar defunkt[] = wxT("$$default"); - if (file != wxT("")) - { - int n = GetPrivateProfileString((LPCTSTR)WXSTRINGCAST section, (LPCTSTR)WXSTRINGCAST entry, (LPCTSTR)defunkt, - (LPTSTR)wxBuffer, 1000, (LPCTSTR)WXSTRINGCAST file); - if (n == 0 || wxStrcmp(wxBuffer, defunkt) == 0) - return FALSE; - } - else - { - int n = GetProfileString((LPCTSTR)WXSTRINGCAST section, (LPCTSTR)WXSTRINGCAST entry, (LPCTSTR)defunkt, - (LPTSTR)wxBuffer, 1000); - if (n == 0 || wxStrcmp(wxBuffer, defunkt) == 0) - return FALSE; - } - if (*value) delete[] (*value); - *value = copystring(wxBuffer); - return TRUE; + static const wxChar defunkt[] = wxT("$$default"); + if (file != wxT("")) + { + int n = GetPrivateProfileString((LPCTSTR)WXSTRINGCAST section, (LPCTSTR)WXSTRINGCAST entry, (LPCTSTR)defunkt, + (LPTSTR)wxBuffer, 1000, (LPCTSTR)WXSTRINGCAST file); + if (n == 0 || wxStrcmp(wxBuffer, defunkt) == 0) + return FALSE; + } + else + { + int n = GetProfileString((LPCTSTR)WXSTRINGCAST section, (LPCTSTR)WXSTRINGCAST entry, (LPCTSTR)defunkt, + (LPTSTR)wxBuffer, 1000); + if (n == 0 || wxStrcmp(wxBuffer, defunkt) == 0) + return FALSE; } + if (*value) delete[] (*value); + *value = copystring(wxBuffer); + return TRUE; +} bool wxGetResource(const wxString& section, const wxString& entry, float *value, const wxString& file) { - wxChar *s = NULL; - bool succ = wxGetResource(section, entry, (wxChar **)&s, file); - if (succ) - { - *value = (float)wxStrtod(s, NULL); - delete[] s; - return TRUE; - } - else return FALSE; + wxChar *s = NULL; + bool succ = wxGetResource(section, entry, (wxChar **)&s, file); + if (succ) + { + *value = (float)wxStrtod(s, NULL); + delete[] s; + return TRUE; + } + else return FALSE; } bool wxGetResource(const wxString& section, const wxString& entry, long *value, const wxString& file) { - wxChar *s = NULL; - bool succ = wxGetResource(section, entry, (wxChar **)&s, file); - if (succ) - { - *value = wxStrtol(s, NULL, 10); - delete[] s; - return TRUE; - } - else return FALSE; + wxChar *s = NULL; + bool succ = wxGetResource(section, entry, (wxChar **)&s, file); + if (succ) + { + *value = wxStrtol(s, NULL, 10); + delete[] s; + return TRUE; + } + else return FALSE; } bool wxGetResource(const wxString& section, const wxString& entry, int *value, const wxString& file) { - wxChar *s = NULL; - bool succ = wxGetResource(section, entry, (wxChar **)&s, file); - if (succ) - { - *value = (int)wxStrtol(s, NULL, 10); - delete[] s; - return TRUE; - } - else return FALSE; + wxChar *s = NULL; + bool succ = wxGetResource(section, entry, (wxChar **)&s, file); + if (succ) + { + *value = (int)wxStrtol(s, NULL, 10); + delete[] s; + return TRUE; + } + else return FALSE; } #endif // wxUSE_RESOURCES @@ -615,228 +790,89 @@ bool wxIsBusy() return (gs_wxBusyCursorCount > 0); } -// --------------------------------------------------------------------------- -const wxChar* wxGetHomeDir(wxString *pstr) -{ - wxString& strDir = *pstr; - - #if defined(__UNIX__) && !defined(__TWIN32__) - const wxChar *szHome = wxGetenv("HOME"); - if ( szHome == NULL ) { - // we're homeless... - wxLogWarning(_("can't find user's HOME, using current directory.")); - strDir = wxT("."); - } - else - strDir = szHome; - - // add a trailing slash if needed - if ( strDir.Last() != wxT('/') ) - strDir << wxT('/'); - #else // Windows - #ifdef __WIN32__ - const wxChar *szHome = wxGetenv(wxT("HOMEDRIVE")); - if ( szHome != NULL ) - strDir << szHome; - szHome = wxGetenv(wxT("HOMEPATH")); - if ( szHome != NULL ) { - strDir << szHome; - - // the idea is that under NT these variables have default values - // of "%systemdrive%:" and "\\". As we don't want to create our - // config files in the root directory of the system drive, we will - // create it in our program's dir. However, if the user took care - // to set HOMEPATH to something other than "\\", we suppose that he - // knows what he is doing and use the supplied value. - if ( wxStrcmp(szHome, wxT("\\")) != 0 ) - return strDir.c_str(); - } - - #else // Win16 - // Win16 has no idea about home, so use the working directory instead - #endif // WIN16/32 - - // 260 was taken from windef.h - #ifndef MAX_PATH - #define MAX_PATH 260 - #endif - - wxString strPath; - ::GetModuleFileName(::GetModuleHandle(NULL), - strPath.GetWriteBuf(MAX_PATH), MAX_PATH); - strPath.UngetWriteBuf(); - - // extract the dir name - wxSplitPath(strPath, &strDir, NULL, NULL); - - #endif // UNIX/Win - - return strDir.c_str(); -} - -// Hack for MS-DOS -wxChar *wxGetUserHome (const wxString& user) -{ - wxChar *home; - wxString user1(user); - - if (user1 != wxT("")) { - wxChar tmp[64]; - if (wxGetUserId(tmp, sizeof(tmp)/sizeof(char))) { - // Guests belong in the temp dir - if (wxStricmp(tmp, wxT("annonymous")) == 0) { - if ((home = wxGetenv(wxT("TMP"))) != NULL || - (home = wxGetenv(wxT("TMPDIR"))) != NULL || - (home = wxGetenv(wxT("TEMP"))) != NULL) - return *home ? home : (wxChar*)wxT("\\"); - } - if (wxStricmp(tmp, WXSTRINGCAST user1) == 0) - user1 = wxT(""); - } - } - if (user1 == wxT("")) - if ((home = wxGetenv(wxT("HOME"))) != NULL) - { - wxStrcpy(wxBuffer, home); - Unix2DosFilename(wxBuffer); - return wxBuffer; - } - return NULL; // No home known! -} - // Check whether this window wants to process messages, e.g. Stop button // in long calculations. bool wxCheckForInterrupt(wxWindow *wnd) { - if(wnd){ + wxCHECK( wnd, FALSE ); + MSG msg; - HWND win= (HWND) wnd->GetHWND(); - while(PeekMessage(&msg,win,0,0,PM_REMOVE)){ - TranslateMessage(&msg); - DispatchMessage(&msg); + while ( ::PeekMessage(&msg, GetHwndOf(wnd), 0, 0, PM_REMOVE) ) + { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); } - return TRUE;//*** temporary? - } - else{ - wxFAIL_MSG(wxT("wnd==NULL !!!")); - return FALSE;//*** temporary? - } + return TRUE; } +#endif // wxUSE_GUI + // MSW only: get user-defined resource from the .res file. // Returns NULL or newly-allocated memory, so use delete[] to clean up. -#ifdef __WXMSW__ wxChar *wxLoadUserResource(const wxString& resourceName, const wxString& resourceType) { - wxChar *s = NULL; -#if !defined(__WIN32__) || defined(__TWIN32__) - HRSRC hResource = ::FindResource(wxGetInstance(), WXSTRINGCAST resourceName, WXSTRINGCAST resourceType); -#else -#ifdef UNICODE - HRSRC hResource = ::FindResourceW(wxGetInstance(), WXSTRINGCAST resourceName, WXSTRINGCAST resourceType); -#else - HRSRC hResource = ::FindResourceA(wxGetInstance(), WXSTRINGCAST resourceName, WXSTRINGCAST resourceType); -#endif -#endif + HRSRC hResource = ::FindResource(wxGetInstance(), resourceName, resourceType); + if ( hResource == 0 ) + return NULL; + + HGLOBAL hData = ::LoadResource(wxGetInstance(), hResource); + if ( hData == 0 ) + return NULL; - if (hResource == 0) - return NULL; - HGLOBAL hData = ::LoadResource(wxGetInstance(), hResource); - if (hData == 0) - return NULL; - wxChar *theText = (wxChar *)LockResource(hData); - if (!theText) - return NULL; + wxChar *theText = (wxChar *)::LockResource(hData); + if ( !theText ) + return NULL; - s = copystring(theText); + wxChar *s = copystring(theText); - // Obsolete in WIN32 + // Obsolete in WIN32 #ifndef __WIN32__ - UnlockResource(hData); + UnlockResource(hData); #endif - // No need?? -// GlobalFree(hData); + // No need?? + // GlobalFree(hData); - return s; + return s; } -#endif + +// ---------------------------------------------------------------------------- +// get display info +// ---------------------------------------------------------------------------- void wxGetMousePosition( int* x, int* y ) { - POINT pt; - GetCursorPos( & pt ); - *x = pt.x; - *y = pt.y; + POINT pt; + GetCursorPos( & pt ); + if ( x ) *x = pt.x; + if ( y ) *y = pt.y; }; // Return TRUE if we have a colour display bool wxColourDisplay() { - HDC dc = ::GetDC((HWND) NULL); - bool flag; - int noCols = GetDeviceCaps(dc, NUMCOLORS); - if ((noCols == -1) || (noCols > 2)) - flag = TRUE; - else - flag = FALSE; - ReleaseDC((HWND) NULL, dc); - return flag; + ScreenHDC dc; + int noCols = GetDeviceCaps(dc, NUMCOLORS); + + return (noCols == -1) || (noCols > 2); } // Returns depth of screen int wxDisplayDepth() { - HDC dc = ::GetDC((HWND) NULL); - int planes = GetDeviceCaps(dc, PLANES); - int bitsPerPixel = GetDeviceCaps(dc, BITSPIXEL); - int depth = planes*bitsPerPixel; - ReleaseDC((HWND) NULL, dc); - return depth; + ScreenHDC dc; + return GetDeviceCaps(dc, PLANES) * GetDeviceCaps(dc, BITSPIXEL); } // Get size of display void wxDisplaySize(int *width, int *height) { - HDC dc = ::GetDC((HWND) NULL); - *width = GetDeviceCaps(dc, HORZRES); *height = GetDeviceCaps(dc, VERTRES); - ReleaseDC((HWND) NULL, dc); -} - -bool wxDirExists(const wxString& dir) -{ - /* MATTHEW: [6] Always use same code for Win32, call FindClose */ -#if defined(__WIN32__) - WIN32_FIND_DATA fileInfo; -#else -#ifdef __BORLANDC__ - struct ffblk fileInfo; -#else - struct find_t fileInfo; -#endif -#endif - -#if defined(__WIN32__) - HANDLE h = FindFirstFile((LPTSTR) WXSTRINGCAST dir,(LPWIN32_FIND_DATA)&fileInfo); + ScreenHDC dc; - if (h==INVALID_HANDLE_VALUE) - return FALSE; - else { - FindClose(h); - return ((fileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY); - } -#else - // In Borland findfirst has a different argument - // ordering from _dos_findfirst. But _dos_findfirst - // _should_ be ok in both MS and Borland... why not? -#ifdef __BORLANDC__ - return ((findfirst(WXSTRINGCAST dir, &fileInfo, _A_SUBDIR) == 0 && (fileInfo.ff_attrib & _A_SUBDIR) != 0)); -#else - return (((_dos_findfirst(WXSTRINGCAST dir, _A_SUBDIR, &fileInfo) == 0) && (fileInfo.attrib & _A_SUBDIR)) != 0); -#endif -#endif + if ( width ) *width = GetDeviceCaps(dc, HORZRES); + if ( height ) *height = GetDeviceCaps(dc, VERTRES); } // --------------------------------------------------------------------------- diff --git a/src/msw/utilsexc.cpp b/src/msw/utilsexc.cpp index e6570d80a3..9d778c9d5b 100644 --- a/src/msw/utilsexc.cpp +++ b/src/msw/utilsexc.cpp @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: utilsexec.cpp +// Name: msw/utilsexec.cpp // Purpose: Various utilities // Author: Julian Smart // Modified by: @@ -9,48 +9,51 @@ // Licence: wxWindows license ///////////////////////////////////////////////////////////////////////////// +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + #ifdef __GNUG__ -#pragma implementation + #pragma implementation #endif // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ -#pragma hdrstop + #pragma hdrstop #endif #ifndef WX_PRECOMP -#include "wx/setup.h" -#include "wx/utils.h" -#include "wx/app.h" -#include "wx/intl.h" + #include "wx/utils.h" + #include "wx/app.h" + #include "wx/intl.h" #endif #include "wx/log.h" #ifdef __WIN32__ -#include "wx/process.h" + #include "wx/process.h" #endif #include "wx/msw/private.h" -#include - #include #if !defined(__GNUWIN32__) && !defined(__WXWINE__) && !defined(__SALFORDC__) -#include + #include #ifndef __MWERKS__ -#include + #include #endif #endif -#ifdef __GNUWIN32__ -#ifndef __TWIN32__ -#include -#include -#endif +#if defined(__GNUWIN32__) && !defined(__TWIN32__) + #include + #include #endif #if defined(__WIN32__) && !defined(__WXWINE__) @@ -71,9 +74,26 @@ #endif #include +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + // this message is sent when the process we're waiting for terminates #define wxWM_PROC_TERMINATED (WM_USER + 10000) +// ---------------------------------------------------------------------------- +// this module globals +// ---------------------------------------------------------------------------- + +// we need to create a hidden window to receive the process termination +// notifications and for this we need a (Win) class name for it which we will +// register the first time it's needed +static const wxChar *gs_classForHiddenWindow = NULL; + +// ---------------------------------------------------------------------------- +// private types +// ---------------------------------------------------------------------------- + // structure describing the process we're being waiting for struct wxExecuteData { @@ -96,6 +116,9 @@ public: bool state; // set to FALSE when the process finishes }; +// ============================================================================ +// implementation +// ============================================================================ #ifdef __WIN32__ static DWORD wxExecuteThread(wxExecuteData *data) @@ -150,8 +173,6 @@ LRESULT APIENTRY _EXPORT wxExecuteWindowCbk(HWND hWnd, UINT message, } #endif -extern wxChar wxPanelClassName[]; - long wxExecute(const wxString& command, bool sync, wxProcess *handler) { wxCHECK_MSG( !!command, 0, wxT("empty command in wxExecute") ); @@ -242,17 +263,31 @@ long wxExecute(const wxString& command, bool sync, wxProcess *handler) if ( !::CloseHandle(pi.hThread) ) wxLogLastError("CloseHandle(hThread)"); + if ( !gs_classForHiddenWindow ) + { + gs_classForHiddenWindow = _T("wxHiddenWindow"); + + WNDCLASS wndclass; + wxZeroMemory(wndclass); + wndclass.lpfnWndProc = (WNDPROC)wxExecuteWindowCbk; + wndclass.hInstance = wxGetInstance(); + wndclass.lpszClassName = gs_classForHiddenWindow; + + if ( !::RegisterClass(&wndclass) ) + { + wxLogLastError("RegisterClass(hidden window)"); + + return FALSE; + } + } + // create a hidden window to receive notification about process // termination - HWND hwnd = ::CreateWindow(wxPanelClassName, NULL, 0, 0, 0, 0, 0, NULL, + HWND hwnd = ::CreateWindow(gs_classForHiddenWindow, NULL, + 0, 0, 0, 0, 0, NULL, (HMENU)NULL, wxGetInstance(), 0); wxASSERT_MSG( hwnd, wxT("can't create a hidden window for wxExecute") ); - FARPROC ExecuteWindowInstance = MakeProcInstance((FARPROC)wxExecuteWindowCbk, - wxGetInstance()); - - ::SetWindowLong(hwnd, GWL_WNDPROC, (LONG) ExecuteWindowInstance); - // Alloc data wxExecuteData *data = new wxExecuteData; data->hProcess = pi.hProcess; @@ -338,33 +373,3 @@ long wxExecute(char **argv, bool sync, wxProcess *handler) return wxExecute(command, sync, handler); } -bool wxGetFullHostName(wxChar *buf, int maxSize) -{ -#if defined(__WIN32__) && !defined(__TWIN32__) - DWORD nSize = maxSize ; - if ( !::GetComputerName(buf, &nSize) ) - { - wxLogLastError("GetComputerName"); - - return FALSE; - } -#else - char *sysname; - const char *default_host = "noname"; -static const char WX_SECTION[] = "wxWindows"; -static const char eHOSTNAME[] = "HostName"; - - if ((sysname = getenv("SYSTEM_NAME")) == NULL) { - GetProfileString(WX_SECTION, eHOSTNAME, default_host, buf, maxSize - 1); - } else - strncpy(buf, sysname, maxSize - 1); - buf[maxSize] = '\0'; - if ( *buf == '\0' ) - { - wxLogLastError("GetComputerName"); - - return FALSE; - } -#endif - return TRUE; -} diff --git a/src/unix/threadpsx.cpp b/src/unix/threadpsx.cpp index e1ea13a436..0b33684eae 100644 --- a/src/unix/threadpsx.cpp +++ b/src/unix/threadpsx.cpp @@ -685,7 +685,14 @@ wxThreadError wxThread::Resume() // exiting thread // ----------------------------------------------------------------------------- -wxThread::ExitCode wxThread::Delete() +wxThread::ExitCode Wait() +{ + wxFAIL_MSG("TODO"); + + return 0; +} + +wxThreadError wxThread::Delete(ExitCode *rc) { if (IsPaused()) Resume(); @@ -745,7 +752,7 @@ wxThreadError wxThread::Kill() } } -void wxThread::Exit(void *status) +void wxThread::Exit(ExitCode status) { // first call user-level clean up code OnExit(); -- 2.45.2