1 //####COPYRIGHTBEGIN####
3 // ----------------------------------------------------------------------------
4 // Copyright (C) 1998, 1999, 2000 Red Hat, Inc.
5 // Copyright (C) 2003 John Dallaway
7 // This program is part of the eCos host tools.
9 // This program is free software; you can redistribute it and/or modify it
10 // under the terms of the GNU General Public License as published by the Free
11 // Software Foundation; either version 2 of the License, or (at your option)
14 // This program is distributed in the hope that it will be useful, but WITHOUT
15 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 // You should have received a copy of the GNU General Public License along with
20 // this program; if not, write to the Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 // ----------------------------------------------------------------------------
25 //####COPYRIGHTEND####
27 //===========================================================================
28 //===========================================================================
29 //#####DESCRIPTIONBEGIN####
31 // Author(s): sdf, jld
36 // Description: This is a collection of utility functions.
37 // Modified by julians for wxWindows (originally CTUtils.h)
44 //####DESCRIPTIONEND####
46 //===========================================================================
49 #pragma implementation "ecutils.h"
52 // Includes other headers for precompiled compilation
60 #include "wx/listctrl.h"
61 #include "wx/stream.h"
63 #include <float.h> // for DBL_DIG macro
64 #include <sys/types.h>
76 #include <sys/cygwin.h> /* for cygwin_conv_to_*_path() */
81 #define INCLUDEFILE <string>
82 #include "IncludeSTL.h"
86 // Chop str into pieces, using cSep as separator.
87 // " and \ have usual semantics
88 // Return value is array of pieces found.
90 int ecUtils::Chop(const wxString& psz, wxArrayString &ar, wxChar cSep,
91 bool bObserveStrings/*=false*/,bool bBackslashQuotes/*=false*/)
96 return Chop(psz, ar, wxT("\t\n\v\f\r "), bObserveStrings, bBackslashQuotes);
98 wxASSERT(wxT('\0')!=cSep);
99 wxChar c[2]={cSep,wxT('\0')};
100 return Chop(psz,ar,wxString(c),bObserveStrings,bBackslashQuotes);
104 int ecUtils::Chop(const wxString& str, wxArrayString &ar, const wxString& sep,
105 bool bObserveStrings/*=false*/,bool bBackslashQuotes/*=false*/)
109 const wxChar* pszSep = (const wxChar*) sep;
110 const wxChar* psz = (const wxChar*) str;
114 // Skip multiple separators
115 while(*psz && wxStrchr(pszSep,*psz)){
123 bool bInString=FALSE;
125 if(*psz == wxT('\\') && bBackslashQuotes && psz[1]){
128 } else if(*psz == wxT('"')){
130 } else if (!bInString && *psz && NULL != wxStrchr(pszSep,*psz)) {
137 const wxChar* pszStart=psz;
140 } while (*psz && ! wxStrchr(pszSep,*psz));
141 strTok=wxString(pszStart,psz-pszStart);
146 return ar.GetCount();
151 // vararg-style message box formatter
152 int ecUtils::MessageBoxF (LPCTSTR pszFormat, ...)
156 va_start(args, pszFormat);
157 rc=ecUtils::vMessageBox(MB_OK, pszFormat,args);
162 // As above, but with type as first parameter.
163 int ecUtils::MessageBoxFT (UINT nType, LPCTSTR pszFormat, ...)
167 va_start(args, pszFormat);
168 rc=ecUtils::vMessageBox(nType, pszFormat,args);
173 int ecUtils::vMessageBox(UINT nType, LPCTSTR pszFormat, va_list marker)
176 for(int nLength=100;nLength;) {
177 TCHAR *buf=new TCHAR[1+nLength];
178 int n=_vsntprintf(buf, nLength, pszFormat, marker );
180 nLength*=2; // NT behavior
181 } else if (n<nLength){
182 rc=AfxMessageBox(buf,nType);
183 nLength=0; // trigger exit from loop
185 nLength=n+1; // UNIX behavior generally, or NT behavior when buffer size exactly matches required length
194 bool ecUtils::StrToItemIntegerType(const wxString & str, long &d)
199 bool bHex=(str.Len() > 2 && str[0]==wxT('0') && (str[1]==wxT('x')||str[1]==wxT('X')));
200 //d=_tcstol(str,&pEnd,bHex?16:10);
201 d=wxStrtol(str,&pEnd,bHex?16:10);
202 rc=(0==errno && (*pEnd==wxT('\0')));
206 const wxString ecUtils::IntToStr(long d,bool bHex)
209 s.Printf(bHex?wxT("0x%08x"):wxT("%d"),d);
213 const wxString ecUtils::DoubleToStr (double dValue)
216 s.Printf(wxT("%.*e"), DBL_DIG, dValue);
220 bool ecUtils::StrToDouble (const wxString & strValue, double &dValue)
224 //dValue = _tcstod (strValue, &pEnd);
225 dValue = wxStrtod(strValue, &pEnd);
226 return (0 == errno) && (*pEnd == wxT('\0'));
230 const wxString ecUtils::Explanation(CFileException & exc)
234 case CFileException::none: strMsg=wxT("No error occurred.");break;
235 case CFileException::generic: strMsg=wxT(" An unspecified error occurred.");break;
236 case CFileException::fileNotFound: strMsg=wxT(" The file could not be located.");break;
237 case CFileException::badPath: strMsg=wxT(" All or part of the path is invalid.");break;
238 case CFileException::tooManyOpenFiles: strMsg=wxT(" The permitted number of open files was exceeded.");break;
239 case CFileException::accessDenied: strMsg=wxT(" The file could not be accessed.");break;
240 case CFileException::invalidFile: strMsg=wxT(" There was an attempt to use an invalid file handle.");break;
241 case CFileException::removeCurrentDir: strMsg=wxT(" The current working directory cannot be removed.");break;
242 case CFileException::directoryFull: strMsg=wxT(" There are no more directory entries.");break;
243 case CFileException::badSeek: strMsg=wxT(" There was an error trying to set the file pointer.");break;
244 case CFileException::hardIO: strMsg=wxT(" There was a hardware error.");break;
245 case CFileException::sharingViolation: strMsg=wxT(" SHARE.EXE was not loaded, or a shared region was locked.");break;
246 case CFileException::lockViolation: strMsg=wxT(" There was an attempt to lock a region that was already locked.");break;
247 case CFileException::diskFull: strMsg=wxT(" The disk is full.");break;
248 case CFileException::endOfFile: strMsg=wxT(" The end of file was reached. ");break;
250 strMsg=wxT(" Unknown cause");
257 const wxString ecUtils::LoadString(UINT id)
265 const wxString ecUtils::NativeToPosixPath(const wxString & native)
268 if (native.IsEmpty())
273 cygwin_conv_to_posix_path(native.c_str(), posix.GetWriteBuf(MAXPATHLEN + 1));
274 posix.UngetWriteBuf();
282 const wxString ecUtils::PosixToNativePath(const wxString & posix)
290 cygwin_conv_to_win32_path(posix.c_str(), native.GetWriteBuf(MAXPATHLEN + 1));
291 native.UngetWriteBuf();
299 bool ecUtils::AddToPath(const ecFileName & strFolder, bool bAtFront)
301 wxString strPath,strOldPath;
303 if (wxGetEnv(wxT("PATH"), & strOldPath))
305 // Place the user tools folders at the head or tail of the new path
308 strPath.Printf(wxT("%s;%s"), (const wxChar*) strFolder.ShortName(), (const wxChar*) strOldPath);
311 strPath.Printf(wxT("%s;%s"), (const wxChar*) strOldPath, (const wxChar*) strFolder.ShortName());
318 return (TRUE == wxSetEnv(wxT("PATH"),strPath));
322 wxString ecUtils::GetLastErrorMessageString()
327 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
330 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
336 // Display the string.
345 bool ecUtils::Launch(const ecFileName &strFileName, const ecFileName &strViewer)
349 if(!strViewer.IsEmpty())//use custom editor
351 wxString strCmdline(strViewer);
353 PTCHAR pszCmdLine=strCmdline.GetBuffer(strCmdline.GetLength());
354 GetShortPathName(pszCmdLine,pszCmdLine,strCmdline.GetLength());
355 strCmdline.ReleaseBuffer();
357 strCmdline+=_TCHAR(' ');
358 strCmdline+=strFileName;
359 PROCESS_INFORMATION pi;
362 si.cb = sizeof(STARTUPINFO);
363 si.lpReserved = NULL;
364 si.lpReserved2 = NULL;
372 //strCmdline.GetBuffer(strCmdline.GetLength()), // command line
373 strCmdline.GetBuffer(strCmdline.GetLength()), // command line
374 NULL, // process security
375 NULL, // thread security
376 TRUE, // inherit handles
382 CloseHandle(pi.hProcess);
383 CloseHandle(pi.hThread);
386 MessageBoxF(wxT("Failed to invoke %s.\n"),strCmdline);
388 strCmdline.ReleaseBuffer();
389 } else {// Use association
390 TCHAR szExe[MAX_PATH];
391 HINSTANCE h=FindExecutable(strFileName,wxT("."),szExe);
395 case 0: str=wxT("The system is out of memory or resources.");break;
396 case 31: str=wxT("There is no association for the specified file type.");break;
397 case ERROR_FILE_NOT_FOUND: str=wxT("The specified file was not found.");break;
398 case ERROR_PATH_NOT_FOUND: str=wxT("The specified path was not found.");break;
399 case ERROR_BAD_FORMAT: str=wxT("The .EXE file is invalid (non-Win32 .EXE or error in .EXE image).");break;
402 MessageBoxF(wxT("Failed to open document %s.\r\n%s"),strFileName,str);
405 SHELLEXECUTEINFO sei = {sizeof(sei), 0, AfxGetMainWnd()->GetSafeHwnd(), wxT("open"),
406 strFileName, NULL, NULL, SW_SHOWNORMAL, AfxGetInstanceHandle( )};
409 HINSTANCE hInst=ShellExecute(AfxGetMainWnd()->GetSafeHwnd(),wxT("open"), strFileName, NULL, wxT("."), 0)/*ShellExecuteEx(&sei)*/;
410 if(int(hInst)<=32/*sei.hInstApp==0*/)
415 case 0 : str=wxT("The operating system is out of memory or resources. ");break;
416 case ERROR_FILE_NOT_FOUND : str=wxT("The specified file was not found. ");break;
417 case ERROR_PATH_NOT_FOUND : str=wxT("The specified path was not found. ");break;
418 case ERROR_BAD_FORMAT : str=wxT("The .EXE file is invalid (non-Win32 .EXE or error in .EXE image). ");break;
419 case SE_ERR_ACCESSDENIED : str=wxT("The operating system denied access to the specified file. ");break;
420 case SE_ERR_ASSOCINCOMPLETE : str=wxT("The filename association is incomplete or invalid. ");break;
421 case SE_ERR_DDEBUSY : str=wxT("The DDE transaction could not be completed because other DDE transactions were being processed. ");break;
422 case SE_ERR_DDEFAIL : str=wxT("The DDE transaction failed. ");break;
423 case SE_ERR_DDETIMEOUT : str=wxT("The DDE transaction could not be completed because the request timed out. ");break;
424 case SE_ERR_DLLNOTFOUND : str=wxT("The specified dynamic-link library was not found. ");break;
425 //case SE_ERR_FNF : str=wxT("The specified file was not found. ");break;
426 case SE_ERR_NOASSOC : str=wxT("There is no application associated with the given filename extension. ");break;
427 case SE_ERR_OOM : str=wxT("There was not enough memory to complete the operation. ");break;
428 //case SE_ERR_PNF : str=wxT("The specified path was not found. ");break;
429 case SE_ERR_SHARE : str=wxT("A sharing violation occurred. ");break;
430 default: str=wxT("An unexpected error occurred");break;
432 MessageBoxF(wxT("Failed to open document %s using %s.\r\n%s"),strFileName,szExe,str);
443 void ecUtils::UnicodeToCStr(const wxChar* str,char *&psz)
445 int nLength=1 + wxStrlen(str);
446 psz=new char[nLength];
448 WideCharToMultiByte(CP_ACP, 0, str, -1, psz, nLength, NULL, NULL);
454 std::string ecUtils::UnicodeToStdStr(const wxChar* str)
458 UnicodeToCStr(str,psz);
459 stdstr=std::string(psz);
464 // ecUtils::StripExtraWhitespace() returns a modified version of
465 // a string in which each sequence of whitespace characters is
466 // replaced by a single space
468 static bool ecIsSpace(wxChar ch)
470 return (ch == wxT(' ') || ch == wxT('\r') || ch == wxT('\n') || ch == wxT('\t'));
473 wxString ecUtils::StripExtraWhitespace (const wxString & strInput)
476 wxChar* o=strOutput.GetWriteBuf(1+strInput.Len());
477 for(const wxChar* c=strInput.GetData();*c;c++){
480 if (ecIsSpace(c[1])){
481 for(c=c+2; ecIsSpace(*c);c++);
489 strOutput.UngetWriteBuf();
490 strOutput.Trim(TRUE);
491 strOutput.Trim(FALSE);
495 LPTSTR o=strOutput.GetBuffer(1+strInput.GetLength());
496 for(LPCTSTR c=strInput;*c;c++){
499 if (_istspace(c[1])){
500 for(c=c+2;_istspace(*c);c++);
508 strOutput.ReleaseBuffer();
509 strOutput.TrimLeft();
510 strOutput.TrimRight();
516 ecFileName ecUtils::WPath(const std::string &str)
518 // Convert a path as read from cdl into host format
519 // Change / to \ throughout
521 strPath(str.c_str());
522 strPath.Replace (_TCHAR('/'), _TCHAR('\\'));
526 // Copy file helper function.
527 // This makes sure the destination file is only touched as necessary.
528 // It is written using Posix calls lest it should be more broadly applicable.
530 bool ecUtils::CopyFile(LPCTSTR pszSource,LPCTSTR pszDest)
532 // Compare the files. First set rc to the result of the comparison (true if the same)
536 if(-1!=_tstat(pszSource,&s1) && -1!=_tstat(pszDest,&s2) && s1.st_size==s2.st_size){
537 // Files both exist and are of equal size
538 FILE *f1=_tfopen(pszSource,wxT("rb"));
540 FILE *f2=_tfopen(pszDest,wxT("rb"));
545 char buf1[4096],buf2[4096];
546 nSize1=fread(buf1,1,sizeof buf1,f1);
547 nSize2=fread(buf2,1,sizeof buf2,f2);
548 if(nSize1!=nSize2 || 0!=memcmp(buf1,buf2,nSize1)){
560 // Files are identical
562 rc=TRUE==::CopyFile(pszSource,pszDest,FALSE);
565 MessageBoxF(wxT("Failed to copy '%s' to '%s' - %s"),pszSource,pszDest,GetLastErrorMessageString());
575 * wxStringToStringMap
577 * Stores string values keyed by strings
580 void wxStringToStringMap::Set(const wxString& key, const wxString& value)
583 if (Find(key, oldValue))
585 m_hashTable.Put(key, (wxObject*) new wxString(value));
588 bool wxStringToStringMap::Remove(const wxString& key)
590 wxString* str = (wxString*) m_hashTable.Delete(key);
600 bool wxStringToStringMap::Find(const wxString& key, wxString& value)
602 wxString* str = (wxString*) m_hashTable.Get(key);
612 void wxStringToStringMap::Clear()
614 m_hashTable.BeginFind();
616 while ((node = m_hashTable.Next()))
618 wxString* str = (wxString*) node->Data();
623 void wxStringToStringMap::BeginFind()
625 m_hashTable.BeginFind();
628 bool wxStringToStringMap::Next(wxString& key, wxString& value)
630 wxNode* node = m_hashTable.Next();
633 value = * (wxString*) node->Data();
640 // Is str a member of arr?
641 bool wxArrayStringIsMember(const wxArrayString& arr, const wxString& str)
644 for (i = (size_t) 0; i < arr.GetCount(); i++)
651 // Eliminate .. and .
652 wxString wxGetRealPath(const wxString& path)
654 wxChar* p = new wxChar[path.Len() + 1];
655 wxStrcpy(p, (const wxChar*) path);
663 // A version of the above but prepending 'cwd' (current path) first
664 // if 'path' is relative
665 wxString wxGetRealPath(const wxString& cwd, const wxString& path)
667 wxString path1(path);
669 if (!wxIsAbsolutePath(path))
672 if (path1.Last() != wxFILE_SEP_PATH)
673 path1 += wxFILE_SEP_PATH;
677 return wxGetRealPath(path1);
680 // Find the absolute path where this application has been run from.
681 // argv0 is wxTheApp->argv[0]
682 // cwd is the current working directory (at startup)
683 // appVariableName is the name of a variable containing the directory for this app, e.g.
684 // MYAPPDIR. This is checked first.
686 wxString wxFindAppPath(const wxString& argv0, const wxString& cwd, const wxString& appVariableName)
690 // Try appVariableName
691 if (!appVariableName.IsEmpty())
693 str = wxGetenv(appVariableName);
698 if (wxIsAbsolutePath(argv0))
699 return wxPathOnly(argv0);
702 // Is it a relative path?
703 wxString currentDir(cwd);
704 if (currentDir.Last() != wxFILE_SEP_PATH)
705 currentDir += wxFILE_SEP_PATH;
707 str = currentDir + argv0;
708 if (wxFileExists(str))
709 return wxPathOnly(str);
712 // OK, it's neither an absolute path nor a relative path.
716 pathList.AddEnvList(wxT("PATH"));
717 str = pathList.FindAbsoluteValidPath(argv0);
719 return wxPathOnly(str);
722 return wxEmptyString;
725 // Make a path name with no separators, out of a full pathname,
726 // e.g. opt_ecos_ecos-1.4.5 out of /opt/ecos/ecos-1.4.5
727 wxString ecMakeNameFromPath(const wxString& path)
730 p.Replace(wxT("/"), wxT("_"));
731 p.Replace(wxT("\\"), wxT("_"));
732 p.Replace(wxT(":"), wxT("_"));
737 // Find the text of the list control item at the given column
738 wxString wxListCtrlGetItemTextColumn(wxListCtrl& listCtrl, long item, int col)
741 listItem.m_mask = wxLIST_MASK_TEXT;
742 listItem.m_itemId = item;
743 listItem.m_col = col;
745 if (listCtrl.GetItem(listItem))
746 return listItem.m_text;
748 return wxEmptyString;
751 // Select the given item
752 void wxListCtrlSelectItem(wxListCtrl& listCtrl, long sel, bool deselectOthers)
754 long n = listCtrl.GetItemCount();
758 for (i = 0; i < n; i++)
760 if (listCtrl.GetItemState(i, wxLIST_STATE_SELECTED) & wxLIST_STATE_SELECTED)
762 listCtrl.SetItemState(i, wxLIST_STATE_SELECTED, 0);
766 listCtrl.SetItemState(sel, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
769 // Find the selection
770 long wxListCtrlGetSelection(wxListCtrl& listCtrl)
772 long n = listCtrl.GetItemCount();
774 for (i = 0; i < n; i++)
776 if (listCtrl.GetItemState(i, wxLIST_STATE_SELECTED) & wxLIST_STATE_SELECTED)
784 // Find which column the cursor is on
785 int wxListCtrlFindColumn(wxListCtrl& listCtrl, int noCols, int x)
789 // Find which column we're on
792 for (i = 0; i < noCols; i++)
794 width += listCtrl.GetColumnWidth(i);
805 void wxRefreshControls(wxWindow* win)
807 wxNode *node = win->GetChildren().First();
810 wxWindow* win = (wxWindow*) node->Data();
816 wxOutputStream& operator <<(wxOutputStream& stream, const wxString& s)
818 stream.Write(s, s.Length());
822 wxOutputStream& operator <<(wxOutputStream& stream, long l)
825 str.Printf("%ld", l);
826 return stream << str;
829 wxOutputStream& operator <<(wxOutputStream& stream, const char c)
833 return stream << str;
838 * Supports features we want to have for all dialogs in the application.
839 * So far, this just allows dialogs to be resizeable under MSW by
840 * refreshing the controls in OnSize (otherwise there's a mess)
843 IMPLEMENT_CLASS(ecDialog, wxDialog)
845 BEGIN_EVENT_TABLE(ecDialog, wxDialog)
847 EVT_SIZE(ecDialog::OnSize)
851 void ecDialog::OnSize(wxSizeEvent& event)
853 wxDialog::OnSize(event);
855 wxRefreshControls(this);
859 * Implements saving/loading of window settings - fonts only for now
862 wxWindowSettingsObject* wxWindowSettings::FindSettings(const wxString& windowName) const
864 wxNode* node = m_settings.First();
867 wxWindowSettingsObject* obj = (wxWindowSettingsObject*) node->Data();
868 if (obj->m_windowName.CmpNoCase(windowName) == 0)
875 bool wxWindowSettings::LoadConfig(wxConfigBase& config)
878 for (i = 0; i < GetCount(); i++)
880 wxWindowSettingsObject* obj = GetNth(i);
882 wxString name(obj->m_windowName);
883 name.Replace(wxT(" "), wxT(""));
885 LoadFont(config, name, obj->m_font);
891 bool wxWindowSettings::SaveConfig(wxConfigBase& config)
894 for (i = 0; i < GetCount(); i++)
896 wxWindowSettingsObject* obj = GetNth(i);
898 wxString name(obj->m_windowName);
899 name.Replace(wxT(" "), wxT(""));
901 SaveFont(config, name, obj->m_font);
907 // Load and save font descriptions
908 bool wxWindowSettings::LoadFont(wxConfigBase& config, const wxString& windowName, wxFont& font)
910 wxString pathBase(wxT("/Fonts/"));
911 pathBase += windowName;
912 pathBase += wxT("/");
914 int pointSize, family, style, weight;
915 bool underlined = FALSE;
918 if (!config.Read(pathBase + wxT("PointSize"), & pointSize))
921 if (!config.Read(pathBase + wxT("Family"), & family))
924 if (!config.Read(pathBase + wxT("Style"), & style))
927 if (!config.Read(pathBase + wxT("Weight"), & weight))
930 config.Read(pathBase + wxT("Underlined"), (bool*) & underlined);
931 config.Read(pathBase + wxT("FaceName"), & faceName);
933 wxFont font1(pointSize, family, style, weight, underlined, faceName);
939 bool wxWindowSettings::SaveFont(wxConfigBase& config, const wxString& windowName, const wxFont& font)
944 wxString pathBase(wxT("/Fonts/"));
945 pathBase += windowName;
946 pathBase += wxT("/");
948 config.Write(pathBase + wxT("PointSize"), (long) font.GetPointSize());
949 config.Write(pathBase + wxT("Family"), (long) font.GetFamily());
950 config.Write(pathBase + wxT("Style"), (long) font.GetStyle());
951 config.Write(pathBase + wxT("Weight"), (long) font.GetWeight());
952 config.Write(pathBase + wxT("Underlined"), (long) font.GetUnderlined());
953 config.Write(pathBase + wxT("FaceName"), font.GetFaceName());
958 wxFont wxWindowSettings::GetFont(const wxString& name) const
960 wxWindowSettingsObject* obj = FindSettings(name);
967 void wxWindowSettings::SetFont(const wxString& name, const wxFont& font)
969 wxWindowSettingsObject* obj = FindSettings(name);
972 obj = new wxWindowSettingsObject(name, NULL) ;
974 m_settings.Append(obj);
979 wxWindow* wxWindowSettings::GetWindow(const wxString& name) const
981 wxWindowSettingsObject* obj = FindSettings(name);
984 if (obj->m_arrWindow.GetCount() > 0)
985 return (wxWindow*) obj->m_arrWindow[0];
990 void wxWindowSettings::SetWindow(const wxString& name, wxWindow* win)
992 wxWindowSettingsObject* obj = FindSettings(name);
995 obj = new wxWindowSettingsObject(name, win) ;
996 m_settings.Append(obj);
998 obj->m_arrWindow.Clear();
1001 obj->m_arrWindow.Add(win);
1004 wxArrayPtrVoid* wxWindowSettings::GetWindows(const wxString& name) const
1006 wxWindowSettingsObject* obj = FindSettings(name);
1009 return & obj->m_arrWindow ;
1012 void wxWindowSettings::SetWindows(const wxString& name, wxArrayPtrVoid& arr)
1014 wxWindowSettingsObject* obj = FindSettings(name);
1017 obj = new wxWindowSettingsObject(name, NULL) ;
1018 m_settings.Append(obj);
1020 obj->m_arrWindow.Clear() ;
1021 obj->m_arrWindow = arr;
1024 bool wxWindowSettings::ApplyFontsToWindows()
1030 for (i = 0; i < GetCount(); i++)
1032 wxWindowSettingsObject* obj = GetNth(i);
1035 for (j = 0; j < obj->m_arrWindow.GetCount(); j++)
1037 wxWindow* win = (wxWindow*) obj->m_arrWindow[j];
1038 win->SetFont(obj->m_font);
1046 // This will be obsolete when we switch to using the version included
1047 // in wxWindows (from wxWin 2.3.1 onwards)
1050 ecKILL_OK, // no error
1051 ecKILL_BAD_SIGNAL, // no such signal
1052 ecKILL_ACCESS_DENIED, // permission denied
1053 ecKILL_NO_PROCESS, // no such process
1054 ecKILL_ERROR // another, unspecified error
1058 // ----------------------------------------------------------------------------
1059 // process management
1060 // ----------------------------------------------------------------------------
1064 // structure used to pass parameters from wxKill() to wxEnumFindByPidProc()
1065 struct wxNewFindByPidParams
1067 wxNewFindByPidParams() { hwnd = 0; pid = 0; }
1069 // the HWND used to return the result
1072 // the PID we're looking from
1076 // wxKill helper: EnumWindows() callback which is used to find the first (top
1077 // level) window belonging to the given process
1078 static BOOL CALLBACK wxEnumFindByPidProc(HWND hwnd, LPARAM lParam)
1081 (void)::GetWindowThreadProcessId(hwnd, &pid);
1083 wxNewFindByPidParams *params = (wxNewFindByPidParams *)lParam;
1084 if ( pid == params->pid )
1086 // remember the window we found
1087 params->hwnd = hwnd;
1089 // return FALSE to stop the enumeration
1093 // continue enumeration
1097 // This will be obsolete when we switch to using the version included
1098 // in wxWindows (from wxWin 2.3.1 onwards)
1099 int wxNewKill(long pid, wxSignal sig, ecKillError *krc = NULL)
1102 // get the process handle to operate on
1103 HANDLE hProcess = ::OpenProcess(SYNCHRONIZE |
1105 PROCESS_QUERY_INFORMATION,
1106 FALSE, // not inheritable
1108 if ( hProcess == NULL )
1112 if ( ::GetLastError() == ERROR_ACCESS_DENIED )
1114 *krc = ecKILL_ACCESS_DENIED;
1118 *krc = ecKILL_NO_PROCESS;
1129 // kill the process forcefully returning -1 as error code
1130 if ( !::TerminateProcess(hProcess, (UINT)-1) )
1132 wxLogSysError(_("Failed to kill process %d"), pid);
1136 // this is not supposed to happen if we could open the
1138 *krc = ecKILL_ERROR;
1146 // do nothing, we just want to test for process existence
1150 // any other signal means "terminate"
1152 wxNewFindByPidParams params;
1153 params.pid = (DWORD)pid;
1155 // EnumWindows() has nice semantics: it returns 0 if it found
1156 // something or if an error occured and non zero if it
1157 // enumerated all the window
1158 if ( !::EnumWindows(wxEnumFindByPidProc, (LPARAM)¶ms) )
1160 // did we find any window?
1163 // tell the app to close
1165 // NB: this is the harshest way, the app won't have
1166 // opportunity to save any files, for example, but
1167 // this is probably what we want here. If not we
1168 // can also use SendMesageTimeout(WM_CLOSE)
1169 if ( !::PostMessage(params.hwnd, WM_QUIT, 0, 0) )
1171 wxLogLastError(_T("PostMessage(WM_QUIT)"));
1174 else // it was an error then
1176 wxLogLastError(_T("EnumWindows"));
1181 else // no windows for this PID
1185 *krc = ecKILL_ERROR;
1198 // as we wait for a short time, we can use just WaitForSingleObject()
1199 // and not MsgWaitForMultipleObjects()
1200 switch ( ::WaitForSingleObject(hProcess, 500 /* msec */) )
1203 // process terminated
1204 if ( !::GetExitCodeProcess(hProcess, &rc) )
1206 wxLogLastError(_T("GetExitCodeProcess"));
1211 wxFAIL_MSG( _T("unexpected WaitForSingleObject() return") );
1215 wxLogLastError(_T("WaitForSingleObject"));
1221 *krc = ecKILL_ERROR;
1230 // just to suppress the warnings about uninitialized variable
1234 ::CloseHandle(hProcess);
1236 // the return code is the same as from Unix kill(): 0 if killed
1237 // successfully or -1 on error
1238 if ( sig == wxSIGNONE )
1240 if ( ok && rc == STILL_ACTIVE )
1242 // there is such process => success
1248 if ( ok && rc != STILL_ACTIVE )
1250 // killed => success
1255 wxFAIL_MSG( _T("not implemented") );
1256 #endif // Win32/Win16
1263 int ecKill(long pid, wxSignal sig)
1265 #if defined(__UNIX__) && !defined(__CYGWIN__)
1266 return wxKill(pid, sig);
1267 #elif defined(__WXMSW__)
1268 return wxNewKill(pid, sig);
1275 #include <tlhelp32.h>
1277 WXHINSTANCE wxProcessKiller::hInstLib1 = VER_PLATFORM_WIN32_NT==wxProcessKiller::GetPlatform()? (WXHINSTANCE) LoadLibrary(_T("PSAPI.DLL")) : (WXHINSTANCE) LoadLibrary(_T("Kernel32.DLL")) ;
1278 WXHINSTANCE wxProcessKiller::hInstLib2 = VER_PLATFORM_WIN32_NT==wxProcessKiller::GetPlatform()? (WXHINSTANCE) LoadLibrary(_T("NTDLL.DLL")): (WXHINSTANCE) NULL;
1282 const unsigned int wxProcessKiller::PROCESS_KILL_EXIT_CODE=0xCCFFCCFF;
1284 wxProcessKiller::wxProcessKiller(int pid):
1290 m_hProcess = (WXHANDLE) ::OpenProcess(SYNCHRONIZE |
1292 PROCESS_QUERY_INFORMATION,
1293 FALSE, // not inheritable
1294 (DWORD) m_idProcess);
1298 wxProcessKiller::~wxProcessKiller()
1303 ::CloseHandle((HANDLE) m_hProcess);
1308 bool wxProcessKiller::Kill(bool bRecurse)
1310 wxPInfoArray arPinfo;
1312 if(m_idProcess && -1!=m_idProcess){
1313 // Start of with the easy one:
1315 // Need to gather this information before we orphan our grandchildren:
1322 rc=(TRUE==::TerminateProcess((HANDLE) m_hProcess,PROCESS_KILL_EXIT_CODE));
1323 // dtor's (or subsequent Run's) responsibility to close the handle
1327 rc=(0==kill(m_idProcess,SIGTERM));
1329 waitpid(m_idProcess,&status,WNOHANG);
1333 // kill process *and* its children
1334 // FIXME: needs to be top-down
1335 for(int i=0;i<(signed)arPinfo.size();i++){
1336 if(arPinfo[i].IsChildOf(m_idProcess)){
1341 const wxString strName(Name(arPinfo[i].PID));
1342 if(_tcsstr(strName,_T("eCosTest")) || _tcsstr(strName,_T("cmd.EXE")) || _tcsstr(strName,_T("CMD.EXE")) || arPinfo[i].PID==(signed)GetCurrentProcessId()){
1346 HANDLE hProcess=::OpenProcess(PROCESS_TERMINATE,false,arPinfo[i].PID);
1348 rc&=(TRUE==::TerminateProcess(hProcess,PROCESS_KILL_EXIT_CODE));
1349 CloseHandle(hProcess);
1354 rc&=(0==kill(arPinfo[i].PID,SIGTERM));
1356 waitpid(arPinfo[i].PID,&status,WNOHANG);
1366 bool wxProcessKiller::PSExtract(wxProcessKiller::wxPInfoArray &arPinfo)
1371 switch(GetPlatform()) {
1372 case VER_PLATFORM_WIN32_NT:
1375 // Get procedure addresses.
1376 static BOOL (WINAPI *lpfEnumProcesses)( DWORD *, DWORD cb, DWORD * ) = (BOOL(WINAPI *)(DWORD *,DWORD,DWORD*))GetProcAddress( (HINSTANCE) hInstLib1, "EnumProcesses" ) ;
1377 if( lpfEnumProcesses) {
1381 static DWORD (WINAPI *lpfNtQueryInformationProcess)( HANDLE, int, void *, DWORD, LPDWORD ) =
1382 (DWORD(WINAPI *)(HANDLE, int, void *, DWORD, LPDWORD)) GetProcAddress( (HINSTANCE) hInstLib2,"NtQueryInformationProcess" ) ;
1384 if(lpfNtQueryInformationProcess){
1385 DWORD dwMaxPids=256;
1387 DWORD *arPids = NULL ;
1390 arPids=new DWORD[dwMaxPids];
1391 } while(lpfEnumProcesses(arPids, dwMaxPids, &dwPidSize) && dwPidSize/sizeof(DWORD)==dwMaxPids) ;
1393 if(dwPidSize/sizeof(DWORD)<dwMaxPids){
1395 for( DWORD dwIndex = 0 ; (signed)dwIndex < dwPidSize/sizeof(DWORD); dwIndex++ ) {
1396 // Regardless of OpenProcess success or failure, we
1397 // still call the enum func with the ProcID.
1398 DWORD pid=arPids[dwIndex];
1399 HANDLE hProcess=::OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, pid );
1402 DWORD ExitStatus; // receives process termination status
1403 DWORD PebBaseAddress; // receives process environment block address
1404 DWORD AffinityMask; // receives process affinity mask
1405 DWORD BasePriority; // receives process priority class
1406 ULONG UniqueProcessId; // receives process identifier
1407 ULONG InheritedFromUniqueProcessId; // receives parent process identifier
1409 memset( &pbi, 0, sizeof(pbi));
1411 __int64 ftCreation,ftExit,ftKernel,ftUser;
1412 if(lpfNtQueryInformationProcess(hProcess, 0 /*ProcessBasicInformation*/, &pbi, sizeof(pbi), &retLen)>=0 &&
1413 TRUE==::GetProcessTimes (hProcess,(FILETIME *)&ftCreation,(FILETIME *)&ftExit,(FILETIME *)&ftKernel,(FILETIME *)&ftUser)){
1414 // The second test is important. It excludes orphaned processes who appear to have been adopted by virtue of a new
1415 // process having been created with the same ID as their original parent.
1418 p.PPID=pbi.InheritedFromUniqueProcessId;
1419 p.tCreation=ftCreation;
1420 p.tCpu=Time((ftKernel+ftUser)/10000);
1421 arPinfo.push_back(p);
1424 CloseHandle(hProcess);
1435 case VER_PLATFORM_WIN32_WINDOWS:
1439 static HANDLE (WINAPI *lpfCreateToolhelp32Snapshot)(DWORD,DWORD)=
1440 (HANDLE(WINAPI *)(DWORD,DWORD))GetProcAddress( (HINSTANCE) hInstLib1,"CreateToolhelp32Snapshot" ) ;
1441 static BOOL (WINAPI *lpfProcess32First)(HANDLE,LPPROCESSENTRY32)=
1442 (BOOL(WINAPI *)(HANDLE,LPPROCESSENTRY32))GetProcAddress( (HINSTANCE) hInstLib1, "Process32First" ) ;
1443 static BOOL (WINAPI *lpfProcess32Next)(HANDLE,LPPROCESSENTRY32)=
1444 (BOOL(WINAPI *)(HANDLE,LPPROCESSENTRY32))GetProcAddress( (HINSTANCE) hInstLib1, "Process32Next" ) ;
1445 if( lpfProcess32Next && lpfProcess32First && lpfCreateToolhelp32Snapshot) {
1447 // Get a handle to a Toolhelp snapshot of the systems
1449 HANDLE hSnapShot = lpfCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) ;
1450 if(INVALID_HANDLE_VALUE != hSnapShot) {
1451 // Get the first process' information.
1452 PROCESSENTRY32 procentry;
1453 procentry.dwSize = sizeof(PROCESSENTRY32) ;
1454 if(lpfProcess32First( hSnapShot, &procentry )){
1458 p.PID=procentry.th32ProcessID;
1459 p.PPID=procentry.th32ParentProcessID;
1460 arPinfo.push_back(p);
1461 } while(lpfProcess32Next( hSnapShot, &procentry ));
1463 CloseHandle(hSnapShot);
1472 SetParents(arPinfo);
1475 wxLogError(_T("Couldn't get process information!\n"));
1482 bool wxProcessKiller::PSExtract(wxProcessKiller::wxPInfoArray &arPinfo)
1486 FILE *f=popen("ps -l",_T("r") MODE_TEXT);
1489 while(fgets(buf,sizeof(buf)-1,f)){
1492 // Output is in the form
1493 // F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
1494 //100 S 490 877 876 0 70 0 - 368 wait4 pts/0 00:00:00 bash
1495 int F,UID,C,PRI,NI,SZ,HH,MM,SS;
1496 bool rc=(15==_stscanf(buf,_T("%d %s %d %d %d %d %d %d %s %d %s %s %d:%d:%d"),&F,discard,&UID,&p.PID,&p.PPID,&C,&PRI,&NI,discard,&SZ,discard,discard,&HH,&MM,&SS));
1498 p.tCpu=1000*(SS+60*(60*HH+MM));
1499 arPinfo.push_back(p);
1503 for(i=0;i<(signed)arPinfo.size();i++){
1504 int pid=arPinfo[i].PPID;
1505 arPinfo[i].pParent=0;
1506 for(int j=0;j<(signed)arPinfo.size();j++){
1507 if(i!=j && arPinfo[j].PID==pid){
1508 arPinfo[i].pParent=&arPinfo[j];
1514 wxLogError(_T("Failed to run ps -l\n"));
1516 return true; //FIXME
1521 void wxProcessKiller::SetParents(wxProcessKiller::wxPInfoArray &arPinfo)
1524 for(i=0;i<(signed)arPinfo.size();i++){
1525 wxPInfo &p=arPinfo[i];
1527 for(int j=0;j<(signed)arPinfo.size();j++){
1528 if(arPinfo[j].PID==p.PPID
1530 && arPinfo[j].tCreation<p.tCreation
1534 arPinfo[i].pParent=&arPinfo[j];
1540 // Check for circularity
1541 bool bCircularity=false;
1542 for(i=0;i<(signed)arPinfo.size();i++){
1543 wxPInfo *p=&arPinfo[i];
1544 for(int j=0;j<(signed)arPinfo.size() && p;j++){
1547 // If all is well, p should be NULL here. Otherwise we have a loop.
1549 // Make sure it can't foul things up:
1550 arPinfo[i].pParent=0;
1556 wxLogError(_T("!!! Circularly linked process list at index %d\n"),i);
1557 for(int k=0;k<(signed)arPinfo.size();k++){
1558 const wxPInfo &p=arPinfo[k];
1559 wxLogError(_T("%d: %s ppid=%4d\n"),k,(LPCTSTR)Name(p.PID),p.PPID);
1564 bool wxProcessKiller::wxPInfo::IsChildOf(int pid) const
1566 for(wxPInfo *p=pParent;p && p!=this;p=p->pParent) { // guard against circular linkage
1574 const wxString wxProcessKiller::Name(int pid)
1577 str.Printf(_T("id=%d"),pid);
1580 if(VER_PLATFORM_WIN32_NT==GetPlatform() && hInstLib1){
1581 static BOOL (WINAPI *lpfEnumProcessModules)( HANDLE, HMODULE *, DWORD, LPDWORD ) =
1582 (BOOL(WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) GetProcAddress( (HINSTANCE) hInstLib1,"EnumProcessModules" ) ;
1583 static DWORD (WINAPI *lpfGetModuleFileNameEx)( HANDLE, HMODULE, LPTSTR, DWORD )=
1584 (DWORD (WINAPI *)(HANDLE, HMODULE,LPTSTR, DWORD )) GetProcAddress( (HINSTANCE) hInstLib1,"GetModuleFileNameExA" ) ;
1585 if( lpfEnumProcessModules && lpfGetModuleFileNameEx ) {
1586 HANDLE hProcess=::OpenProcess(PROCESS_ALL_ACCESS,false,pid);
1590 if(lpfEnumProcessModules( hProcess, &hMod, sizeof(HMODULE), &dwSize ) ){
1591 // Get Full pathname:
1592 TCHAR buf[1+MAX_PATH];
1593 lpfGetModuleFileNameEx( hProcess, hMod, buf, MAX_PATH);
1597 CloseHandle(hProcess);
1607 long wxProcessKiller::GetPlatform()
1609 OSVERSIONINFO osver;
1610 osver.dwOSVersionInfoSize = sizeof( osver ) ;
1611 return GetVersionEx( &osver ) ? (long) osver.dwPlatformId : (long)-1;
1615 const wxString wxProcessKiller::ErrorString() const
1620 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
1623 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
1630 return strerror(errno);