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
This commit is contained in:
Vadim Zeitlin
1999-11-27 22:57:06 +00:00
parent aa9a4ae1a5
commit b568d04ffa
24 changed files with 1430 additions and 908 deletions

View File

@@ -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

View File

@@ -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

145
distrib/msw/tmake/vc6base.t Normal file
View File

@@ -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

View File

@@ -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"

View File

@@ -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

View File

@@ -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;
// ---------------------------------------------------------------------------
@@ -284,6 +292,8 @@ 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_

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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();
private:
size_t m_n;
};
wxThread::ExitCode MyJoinableThread::Entry()
{
unsigned long res = 1;
for ( size_t n = 1; n < m_n; n++ )
{
res *= n;
// it's a loooong calculation :-)
Sleep(100);
}
return (ExitCode)res;
}
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();
public:
private:
char m_ch;
};
MyThread::MyThread(char ch)
{
m_ch = ch;
Create();
}
void *MyThread::Entry()
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] = new MyDetachedThread('A' + n);
}
threads[0]->SetPriority(WXTHREAD_MIN_PRIORITY);
threads[1]->SetPriority(WXTHREAD_MAX_PRIORITY);
for ( n = 0; n < nThreads; n++ )
{
threads[n]->Run();
}
// wait until all threads terminate
for ( ;; )
{
wxCriticalSectionLocker lock(gs_critsect);
if ( !gs_counter )
break;
}
wxMutex mutex;
mutex.Lock();
gs_cond.Wait(mutex);
mutex.Unlock();
puts("\nThat's all, folks!");
puts("\n\nTesting a joinable thread used for a loooong calculation...");
for ( n = 0; n < nThreads; n++ )
{
threads[n]->Delete();
}
// 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();

View File

@@ -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;

View File

@@ -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;

View File

@@ -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();

View File

@@ -30,7 +30,6 @@
#include "wx/module.h"
// ----------------------------------------------------------------------------
// global vars
// ----------------------------------------------------------------------------

View File

@@ -48,6 +48,7 @@
#include "wx/utils.h"
#include "wx/wxchar.h"
#include "wx/log.h"
#include "wx/thread.h"
// other standard headers
#include <errno.h>
@@ -55,9 +56,7 @@
#include <time.h>
#ifdef __WXMSW__
#include <windows.h>
// Redefines OutputDebugString if necessary
#include "wx/msw/private.h"
#include "wx/msw/private.h" // includes windows.h for OutputDebugString
#else //Unix
#include <signal.h>
#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
}

View File

@@ -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;
}

View File

@@ -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
}

View File

@@ -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__))

View File

@@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////////
// Name: main.cpp
// Name: msw/main.cpp
// Purpose: Main/DllMain
// Author: Julian Smart
// Modified by:
@@ -9,6 +9,14 @@
// Licence: wxWindows license
/////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#ifdef __GNUG__
#pragma implementation
#endif
@@ -22,11 +30,26 @@
#include "wx/event.h"
#include "wx/app.h"
#include <windows.h>
#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)
@@ -96,7 +119,21 @@ BOOL WINAPI DllMain (HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)
return TRUE;
}
#endif
#endif // _WINDLL
#endif
#endif // !NOMAIN
// ----------------------------------------------------------------------------
// global functions
// ----------------------------------------------------------------------------
HINSTANCE wxGetInstance()
{
return wxhInstance;
}
void wxSetInstance(HINSTANCE hInst)
{
wxhInstance = hInst;
}

View File

@@ -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);

View File

@@ -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 <process.h>
#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;i<p_internal->waiters;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();
// 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,12 +691,25 @@ 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) )
@@ -577,13 +719,22 @@ wxThread::ExitCode wxThread::Delete()
rc = (ExitCode)-1;
}
wxASSERT_MSG( (LPVOID)rc != (LPVOID)STILL_ACTIVE,
wxT("thread must be already terminated.") );
::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;
}
p_internal->Free();
if ( IsDetached() )
{
delete this;
}
return wxTHREAD_NO_ERROR;
}
void wxThread::Exit(void *status)
void wxThread::Exit(ExitCode status)
{
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

View File

@@ -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 <windows.h>
#include "wx/timer.h"
#include "wx/intl.h"
#include <windows.h>
#include <ctype.h>
#if !defined(__GNUWIN32__) && !defined(__WXWINE__) && !defined(__SALFORDC__)
@@ -118,23 +124,43 @@
// __VISUALC__
/// END for console support
// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------
// In the WIN.INI file
static const wxChar WX_SECTION[] = wxT("wxWindows");
static const wxChar eHOSTNAME[] = wxT("HostName");
static const wxChar eUSERID[] = wxT("UserId");
static const wxChar eUSERNAME[] = wxT("UserName");
// 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
// these are only used under Win16
#ifndef __WIN32__
static const wxChar eHOSTNAME[] = wxT("HostName");
static const wxChar eUSERID[] = wxT("UserId");
#endif // !Win32
// ============================================================================
// 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__)
// TODO should use GetComputerNameEx() when available
DWORD nSize = maxSize;
return (::GetComputerName(buf, &nSize) != 0);
if ( !::GetComputerName(buf, &nSize) )
{
wxLogLastError("GetComputerName");
return FALSE;
}
return TRUE;
#else
wxChar *sysname;
const wxChar *default_host = wxT("noname");
@@ -148,6 +174,11 @@ bool wxGetHostName(wxChar *buf, int maxSize)
#endif
}
bool wxGetFullHostName(wxChar *buf, int maxSize)
{
return wxGetHostName(buf, maxSize);
}
// Get user ID e.g. jacs
bool wxGetUserId(wxChar *buf, int maxSize)
{
@@ -286,29 +317,149 @@ error:
return TRUE;
}
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();
}
wxChar *wxGetUserHome(const wxString& user)
{
// 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;
return (wxChar *)wxGetHomeDir(&s_home);
}
bool wxDirExists(const wxString& dir)
{
#if defined(__WIN32__)
WIN32_FIND_DATA fileInfo;
#else // Win16
#ifdef __BORLANDC__
struct ffblk fileInfo;
#else
struct find_t fileInfo;
#endif
#endif // Win32/16
#if defined(__WIN32__)
HANDLE h = ::FindFirstFile(dir, &fileInfo);
if ( h == INVALID_HANDLE_VALUE )
{
wxLogLastError("FindFirstFile");
return FALSE;
}
::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
}
// ----------------------------------------------------------------------------
// process management
// ----------------------------------------------------------------------------
int wxKill(long pid, int sig)
{
// TODO use SendMessage(WM_QUIT) and TerminateProcess() if needed
return 0;
}
//
// Execute a program in an Interactive Shell
//
bool
wxShell(const wxString& command)
bool wxShell(const wxString& command)
{
wxChar *shell;
if ((shell = wxGetenv(wxT("COMSPEC"))) == NULL)
wxChar *shell = wxGetenv(wxT("COMSPEC"));
if ( !shell )
shell = wxT("\\COMMAND.COM");
wxChar tmp[255];
if (command != wxT(""))
wxSprintf(tmp, wxT("%s /c %s"), shell, WXSTRINGCAST command);
else
wxStrcpy(tmp, shell);
return (wxExecute((wxChar *)tmp, FALSE) != 0);
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;
}
// ----------------------------------------------------------------------------
// misc
// ----------------------------------------------------------------------------
// Get free memory in bytes, or -1 if cannot determine amount (e.g. on UNIX)
long wxGetFreeMemory()
@@ -323,111 +474,10 @@ long wxGetFreeMemory()
#endif
}
// 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();
}
};
static wxTimer *wxTheSleepTimer = NULL;
void wxUsleep(unsigned long milliseconds)
{
#ifdef __WIN32__
::Sleep(milliseconds);
#else
if (inTimer)
return;
wxTheSleepTimer = new wxSleepTimer;
inTimer = TRUE;
wxTheSleepTimer->Start(milliseconds);
while (inTimer)
{
if (wxTheApp->Pending())
wxTheApp->Dispatch();
}
delete wxTheSleepTimer;
wxTheSleepTimer = NULL;
#endif
}
void wxSleep(int nSecs)
{
#if 0 // WIN32 hangs app
Sleep( 1000*nSecs );
#else
if (inTimer)
return;
wxTheSleepTimer = new wxSleepTimer;
inTimer = TRUE;
wxTheSleepTimer->Start(nSecs*1000);
while (inTimer)
{
if (wxTheApp->Pending())
wxTheApp->Dispatch();
}
delete wxTheSleepTimer;
wxTheSleepTimer = NULL;
#endif
}
// Consume all events until no more left
void wxFlushEvents()
{
// wxYield();
}
// 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);
}
// 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,22 +667,25 @@ 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);
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);
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);
wxString buf;
buf.Printf(wxT("%d"), value);
return wxWriteResource(section, entry, buf, file);
}
@@ -615,142 +790,42 @@ 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){
MSG msg;
HWND win= (HWND) wnd->GetHWND();
while(PeekMessage(&msg,win,0,0,PM_REMOVE)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return TRUE;//*** temporary?
}
else{
wxFAIL_MSG(wxT("wnd==NULL !!!"));
wxCHECK( wnd, FALSE );
return FALSE;//*** temporary?
MSG msg;
while ( ::PeekMessage(&msg, GetHwndOf(wnd), 0, 0, PM_REMOVE) )
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
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;
wxChar *theText = (wxChar *)LockResource(hData);
wxChar *theText = (wxChar *)::LockResource(hData);
if ( !theText )
return NULL;
s = copystring(theText);
wxChar *s = copystring(theText);
// Obsolete in WIN32
#ifndef __WIN32__
@@ -762,81 +837,42 @@ wxChar *wxLoadUserResource(const wxString& resourceName, const wxString& resourc
return s;
}
#endif
// ----------------------------------------------------------------------------
// get display info
// ----------------------------------------------------------------------------
void wxGetMousePosition( int* x, int* y )
{
POINT pt;
GetCursorPos( & pt );
*x = pt.x;
*y = pt.y;
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;
ScreenHDC dc;
int noCols = GetDeviceCaps(dc, NUMCOLORS);
if ((noCols == -1) || (noCols > 2))
flag = TRUE;
else
flag = FALSE;
ReleaseDC((HWND) NULL, dc);
return flag;
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);
}
ScreenHDC 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);
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);
}
// ---------------------------------------------------------------------------

View File

@@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////////
// Name: utilsexec.cpp
// Name: msw/utilsexec.cpp
// Purpose: Various utilities
// Author: Julian Smart
// Modified by:
@@ -9,6 +9,14 @@
// Licence: wxWindows license
/////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#ifdef __GNUG__
#pragma implementation
#endif
@@ -21,7 +29,6 @@
#endif
#ifndef WX_PRECOMP
#include "wx/setup.h"
#include "wx/utils.h"
#include "wx/app.h"
#include "wx/intl.h"
@@ -35,8 +42,6 @@
#include "wx/msw/private.h"
#include <windows.h>
#include <ctype.h>
#if !defined(__GNUWIN32__) && !defined(__WXWINE__) && !defined(__SALFORDC__)
@@ -46,12 +51,10 @@
#endif
#endif
#ifdef __GNUWIN32__
#ifndef __TWIN32__
#if defined(__GNUWIN32__) && !defined(__TWIN32__)
#include <sys/unistd.h>
#include <sys/stat.h>
#endif
#endif
#if defined(__WIN32__) && !defined(__WXWINE__)
#include <io.h>
@@ -71,9 +74,26 @@
#endif
#include <stdarg.h>
// ----------------------------------------------------------------------------
// 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;
}

View File

@@ -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();