diff host/tools/configtool/standalone/wxwin/ecutils.cpp @ 182:f62680ef1804

Merge from eCos master repository on 2001-09-07-06:43:02-BST
author jlarmour
date Wed, 12 Sep 2001 00:59:17 +0000
parents 0d2b193a635f
children 6c2a59f5102f
line wrap: on
line diff
--- a/host/tools/configtool/standalone/wxwin/ecutils.cpp
+++ b/host/tools/configtool/standalone/wxwin/ecutils.cpp
@@ -524,11 +524,9 @@ bool ecUtils::CopyFile(LPCTSTR pszSource
 
   if(rc){
     // Files are identical
-    TRACE(wxT("Copy not necessary: '%s' to '%s'\n"),pszSource,pszDest);
   } else {
     rc=TRUE==::CopyFile(pszSource,pszDest,FALSE);
     if(rc){
-      TRACE(wxT("Copied '%s' to '%s'\n"),pszSource,pszDest);
     } else {
       MessageBoxF(wxT("Failed to copy '%s' to '%s' - %s"),pszSource,pszDest,GetLastErrorMessageString());
     }
@@ -1010,205 +1008,6 @@ bool wxWindowSettings::ApplyFontsToWindo
     return TRUE;
 }
 
-#if TODO
-
-#ifdef _WIN32
-class wxProcessInfo: public wxObject
-{
-public:
-    wxProcessInfo() {}
-
-    wxProcessInfo *pParent;
-#ifdef _WIN32
-    __int64 tCreation;
-#endif
-    Time tCpu;
-    int PID;
-    int PPID;
-    bool IsChildOf(int pid) const;
-};
-
-void wxSetProcessInfoParents(CSubprocess::PInfoArray &arPinfo)
-{
-  int i;
-  for(i=0;i<(signed)arPinfo.size();i++){
-    PInfo &p=arPinfo[i];
-    p.pParent=0;
-    for(int j=0;j<(signed)arPinfo.size();j++){
-      if(arPinfo[j].PID==p.PPID 
-#ifdef _WIN32
-        && arPinfo[j].tCreation<p.tCreation
-#endif
-        )
-      {
-        arPinfo[i].pParent=&arPinfo[j];
-        break;
-      }
-    }
-  }
-
-  // Check for circularity
-  bool bCircularity=false;
-  for(i=0;i<(signed)arPinfo.size();i++){
-    PInfo *p=&arPinfo[i];
-    for(int j=0;j<(signed)arPinfo.size() && p;j++){
-      p=p->pParent;
-    }
-    // If all is well, p should be NULL here.  Otherwise we have a loop.
-    if(p){
-      // Make sure it can't foul things up:
-      arPinfo[i].pParent=0;
-      bCircularity=true;
-    }
-  }
-  
-  if(bCircularity){
-    ERROR(_T("!!! Circularly linked process list at index %d\n"),i);
-    for(int k=0;k<(signed)arPinfo.size();k++){
-      const PInfo &p=arPinfo[k];
-      ERROR(_T("%d: %s ppid=%4d\n"),k,(LPCTSTR)Name(p.PID),p.PPID);
-    }
-  }
-}
-
-bool CSubprocess::PInfo::IsChildOf(int pid) const
-{
-  for(PInfo *p=pParent;p && p!=this;p=p->pParent) { // guard against circular linkage
-    if(p->PID==pid){
-      return true;
-    }
-  }
-  return false;
-}
-
-
-bool wxGetChildProcesses(wxList& children)
-{
-    int osVersion = wxGetOsVersion() ;
-    HINSTANCE hInstLib1 = wxWINDOWS_NT==osVersion ? LoadLibrary(_T("PSAPI.DLL")):LoadLibrary(_T("Kernel32.DLL")) ;
-    HINSTANCE hInstLib2 = wxWINDOWS_NT==osVersion ? LoadLibrary(_T("NTDLL.DLL")):NULL;
-    
-    bool rc=false;
-    children.Clear();
-    // If Windows NT:
-    switch (osVersion)
-    {
-    case wxWINDOWS_NT:
-        if(hInstLib1)
-        {
-            
-            // Get procedure addresses.
-            static BOOL (WINAPI *lpfEnumProcesses)( DWORD *, DWORD cb, DWORD * ) = (BOOL(WINAPI *)(DWORD *,DWORD,DWORD*))GetProcAddress( hInstLib1, "EnumProcesses" ) ;
-            if (lpfEnumProcesses)
-            {
-                
-                if (hInstLib2)
-                {
-                    
-                    static DWORD (WINAPI *lpfNtQueryInformationProcess)( HANDLE, int, void *, DWORD, LPDWORD ) =
-                        (DWORD(WINAPI *)(HANDLE, int, void *, DWORD, LPDWORD)) GetProcAddress( hInstLib2,"NtQueryInformationProcess" ) ;
-                    
-                    if(lpfNtQueryInformationProcess)
-                    {
-                        DWORD dwMaxPids=256;
-                        DWORD dwPidSize;
-                        DWORD *arPids = NULL ;
-                        do {
-                            delete [] arPids;
-                            arPids=new DWORD[dwMaxPids];
-                        } while(lpfEnumProcesses(arPids, dwMaxPids, &dwPidSize) && dwPidSize/sizeof(DWORD)==dwMaxPids) ;
-                        
-                        if(dwPidSize/sizeof(DWORD)<dwMaxPids)
-                        {
-                            rc=true;
-                            for ( DWORD dwIndex = 0 ; (signed)dwIndex < dwPidSize/sizeof(DWORD); dwIndex++ ) {
-                                // Regardless of OpenProcess success or failure, we
-                                // still call the enum func with the ProcID.
-                                DWORD pid=arPids[dwIndex];
-                                HANDLE hProcess=::OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, pid ); 
-                                if (hProcess ) {
-                                    struct {
-                                        DWORD ExitStatus; // receives process termination status
-                                        DWORD PebBaseAddress; // receives process environment block address
-                                        DWORD AffinityMask; // receives process affinity mask
-                                        DWORD BasePriority; // receives process priority class
-                                        ULONG UniqueProcessId; // receives process identifier
-                                        ULONG InheritedFromUniqueProcessId; // receives parent process identifier
-                                    } pbi;
-                                    memset( &pbi, 0, sizeof(pbi)); 
-                                    DWORD retLen; 
-                                    __int64 ftCreation,ftExit,ftKernel,ftUser;
-                                    if(lpfNtQueryInformationProcess(hProcess, 0 /*ProcessBasicInformation*/, &pbi, sizeof(pbi), &retLen)>=0 &&
-                                        TRUE==::GetProcessTimes (hProcess,(FILETIME *)&ftCreation,(FILETIME *)&ftExit,(FILETIME *)&ftKernel,(FILETIME *)&ftUser)){
-                                        // The second test is important.  It excludes orphaned processes who appear to have been adopted by virtue of a new
-                                        // process having been created with the same ID as their original parent.
-                                        wxProcessInfo* p = new wxProcessInfo;
-                                        p->PID=pid;
-                                        p->PPID=pbi.InheritedFromUniqueProcessId;
-                                        p->tCreation=ftCreation;
-                                        p->tCpu=Time((ftKernel+ftUser)/10000);
-                                        children.Append(p);
-                                    }
-                                    
-                                    CloseHandle(hProcess); 
-                                    
-                                }
-                            }
-                        }
-                        delete [] arPids;
-                    }          
-                }
-            }      
-        }
-        break;
-    case wxWIN95:
-        
-        if( hInstLib1) {
-            
-            static HANDLE (WINAPI *lpfCreateToolhelp32Snapshot)(DWORD,DWORD)=
-                (HANDLE(WINAPI *)(DWORD,DWORD))GetProcAddress( hInstLib1,"CreateToolhelp32Snapshot" ) ;
-            static BOOL (WINAPI *lpfProcess32First)(HANDLE,LPPROCESSENTRY32)=
-                (BOOL(WINAPI *)(HANDLE,LPPROCESSENTRY32))GetProcAddress( hInstLib1, "Process32First" ) ;
-            static BOOL (WINAPI *lpfProcess32Next)(HANDLE,LPPROCESSENTRY32)=
-                (BOOL(WINAPI *)(HANDLE,LPPROCESSENTRY32))GetProcAddress( hInstLib1, "Process32Next" ) ;
-            if( lpfProcess32Next && lpfProcess32First && lpfCreateToolhelp32Snapshot) {
-                
-                // Get a handle to a Toolhelp snapshot of the systems
-                // processes.
-                HANDLE hSnapShot = lpfCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) ;
-                if(INVALID_HANDLE_VALUE != hSnapShot) {
-                    // Get the first process' information.
-                    PROCESSENTRY32 procentry;
-                    procentry.dwSize = sizeof(PROCESSENTRY32) ;
-                    if(lpfProcess32First( hSnapShot, &procentry )){
-                        rc=true;
-                        do {
-                            PInfo p;
-                            p.PID=procentry.th32ProcessID;
-                            p.PPID=procentry.th32ParentProcessID;
-                            arPinfo.push_back(p);
-                        } while(lpfProcess32Next( hSnapShot, &procentry ));
-                    }
-                    CloseHandle(hSnapShot);
-                }
-            }
-        }
-        break;
-    default:
-        break;
-    }    
-    
-    SetParents(children);
-    
-    if(!rc){
-        wxMessageBox(_T("Couldn't get process information!\n"));
-    }
-    return rc;
-}
-#endif
-
-#endif
-
 #ifdef __WIN32__
 // This will be obsolete when we switch to using the version included
 // in wxWindows (from wxWin 2.3.1 onwards)
@@ -1438,3 +1237,363 @@ int ecKill(long pid, wxSignal sig)
 #endif
 }
 
+#ifdef _WIN32
+  #include <tlhelp32.h>
+
+  WXHINSTANCE wxProcessKiller::hInstLib1 = VER_PLATFORM_WIN32_NT==wxProcessKiller::GetPlatform()? (WXHINSTANCE) LoadLibrary(_T("PSAPI.DLL")) : (WXHINSTANCE) LoadLibrary(_T("Kernel32.DLL")) ;
+  WXHINSTANCE wxProcessKiller::hInstLib2 = VER_PLATFORM_WIN32_NT==wxProcessKiller::GetPlatform()? (WXHINSTANCE) LoadLibrary(_T("NTDLL.DLL")): (WXHINSTANCE) NULL;
+
+#endif
+
+const unsigned int wxProcessKiller::PROCESS_KILL_EXIT_CODE=0xCCFFCCFF;
+
+wxProcessKiller::wxProcessKiller(int pid):
+  m_bVerbose(false),
+  m_nExitCode(-1),
+  m_idProcess(pid)
+{
+#ifdef _WIN32
+      m_hProcess = (WXHANDLE) ::OpenProcess(SYNCHRONIZE |
+          PROCESS_TERMINATE |
+          PROCESS_QUERY_INFORMATION,
+          FALSE, // not inheritable
+          (DWORD) m_idProcess);
+#endif
+}
+
+wxProcessKiller::~wxProcessKiller()
+{
+#ifdef _WIN32
+    if (m_hProcess)
+    {
+        ::CloseHandle((HANDLE) m_hProcess);
+    }
+#endif
+}
+
+bool wxProcessKiller::Kill(bool bRecurse)
+{
+    wxPInfoArray arPinfo;
+    bool rc=false;
+    if(m_idProcess && -1!=m_idProcess){
+        // Start of with the easy one:
+        if(bRecurse) {
+            // Need to gather this information before we orphan our grandchildren:
+            PSExtract(arPinfo);
+        }
+        
+#ifdef _WIN32
+        
+        if(m_hProcess){
+            rc=(TRUE==::TerminateProcess((HANDLE) m_hProcess,PROCESS_KILL_EXIT_CODE));
+            // dtor's (or subsequent Run's) responsibility to close the handle
+        }
+        
+#else
+        rc=(0==kill(m_idProcess,SIGTERM));
+        int status;
+        waitpid(m_idProcess,&status,WNOHANG);
+#endif
+        
+        if(bRecurse) {
+            // kill process *and* its children
+            // FIXME: needs to be top-down
+            for(int i=0;i<(signed)arPinfo.size();i++){
+                if(arPinfo[i].IsChildOf(m_idProcess)){
+                    
+#ifdef _WIN32
+                    // begin hack
+                    // WHY NECESSARY??
+                    const wxString strName(Name(arPinfo[i].PID));
+                    if(_tcsstr(strName,_T("eCosTest")) || _tcsstr(strName,_T("cmd.EXE")) || _tcsstr(strName,_T("CMD.EXE")) || arPinfo[i].PID==(signed)GetCurrentProcessId()){
+                        continue;
+                    }
+                    // end hack
+                    HANDLE hProcess=::OpenProcess(PROCESS_TERMINATE,false,arPinfo[i].PID);
+                    if(hProcess){
+                        rc&=(TRUE==::TerminateProcess(hProcess,PROCESS_KILL_EXIT_CODE));
+                        CloseHandle(hProcess);
+                    } else {
+                        rc=false;
+                    }
+#else
+                    rc&=(0==kill(arPinfo[i].PID,SIGTERM));
+                    int status;
+                    waitpid(arPinfo[i].PID,&status,WNOHANG);
+#endif
+                }
+            }
+        }
+    }
+    return rc;
+}
+
+#ifdef _WIN32
+bool wxProcessKiller::PSExtract(wxProcessKiller::wxPInfoArray &arPinfo)
+{
+    bool rc=false;
+    arPinfo.clear();
+    // If Windows NT:
+    switch(GetPlatform()) {
+    case VER_PLATFORM_WIN32_NT:
+        if(hInstLib1) {
+            
+            // Get procedure addresses.
+            static BOOL (WINAPI *lpfEnumProcesses)( DWORD *, DWORD cb, DWORD * ) = (BOOL(WINAPI *)(DWORD *,DWORD,DWORD*))GetProcAddress( (HINSTANCE) hInstLib1, "EnumProcesses" ) ;
+            if( lpfEnumProcesses) {
+                
+                if(hInstLib2) {
+                    
+                    static DWORD (WINAPI *lpfNtQueryInformationProcess)( HANDLE, int, void *, DWORD, LPDWORD ) =
+                        (DWORD(WINAPI *)(HANDLE, int, void *, DWORD, LPDWORD)) GetProcAddress( (HINSTANCE) hInstLib2,"NtQueryInformationProcess" ) ;
+                    
+                    if(lpfNtQueryInformationProcess){
+                        DWORD dwMaxPids=256;
+                        DWORD dwPidSize;
+                        DWORD *arPids = NULL ;
+                        do {
+                            delete [] arPids;
+                            arPids=new DWORD[dwMaxPids];
+                        } while(lpfEnumProcesses(arPids, dwMaxPids, &dwPidSize) && dwPidSize/sizeof(DWORD)==dwMaxPids) ;
+                        
+                        if(dwPidSize/sizeof(DWORD)<dwMaxPids){
+                            rc=true;
+                            for( DWORD dwIndex = 0 ; (signed)dwIndex < dwPidSize/sizeof(DWORD); dwIndex++ ) {
+                                // Regardless of OpenProcess success or failure, we
+                                // still call the enum func with the ProcID.
+                                DWORD pid=arPids[dwIndex];
+                                HANDLE hProcess=::OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, pid ); 
+                                if (hProcess ) {
+                                    struct {
+                                        DWORD ExitStatus; // receives process termination status
+                                        DWORD PebBaseAddress; // receives process environment block address
+                                        DWORD AffinityMask; // receives process affinity mask
+                                        DWORD BasePriority; // receives process priority class
+                                        ULONG UniqueProcessId; // receives process identifier
+                                        ULONG InheritedFromUniqueProcessId; // receives parent process identifier
+                                    } pbi;
+                                    memset( &pbi, 0, sizeof(pbi)); 
+                                    DWORD retLen; 
+                                    __int64 ftCreation,ftExit,ftKernel,ftUser;
+                                    if(lpfNtQueryInformationProcess(hProcess, 0 /*ProcessBasicInformation*/, &pbi, sizeof(pbi), &retLen)>=0 &&
+                                        TRUE==::GetProcessTimes (hProcess,(FILETIME *)&ftCreation,(FILETIME *)&ftExit,(FILETIME *)&ftKernel,(FILETIME *)&ftUser)){
+                                        // The second test is important.  It excludes orphaned processes who appear to have been adopted by virtue of a new
+                                        // process having been created with the same ID as their original parent.
+                                        wxPInfo p;
+                                        p.PID=pid;
+                                        p.PPID=pbi.InheritedFromUniqueProcessId;
+                                        p.tCreation=ftCreation;
+                                        p.tCpu=Time((ftKernel+ftUser)/10000);
+                                        arPinfo.push_back(p);
+                                    }
+                                    
+                                    CloseHandle(hProcess); 
+                                    
+                                }
+                            }
+                        }
+                        delete [] arPids;
+                    }          
+                }
+            }      
+        }
+        break;
+    case VER_PLATFORM_WIN32_WINDOWS:
+        
+        if( hInstLib1) {
+            
+            static HANDLE (WINAPI *lpfCreateToolhelp32Snapshot)(DWORD,DWORD)=
+                (HANDLE(WINAPI *)(DWORD,DWORD))GetProcAddress( (HINSTANCE) hInstLib1,"CreateToolhelp32Snapshot" ) ;
+            static BOOL (WINAPI *lpfProcess32First)(HANDLE,LPPROCESSENTRY32)=
+                (BOOL(WINAPI *)(HANDLE,LPPROCESSENTRY32))GetProcAddress( (HINSTANCE) hInstLib1, "Process32First" ) ;
+            static BOOL (WINAPI *lpfProcess32Next)(HANDLE,LPPROCESSENTRY32)=
+                (BOOL(WINAPI *)(HANDLE,LPPROCESSENTRY32))GetProcAddress( (HINSTANCE) hInstLib1, "Process32Next" ) ;
+            if( lpfProcess32Next && lpfProcess32First && lpfCreateToolhelp32Snapshot) {
+                
+                // Get a handle to a Toolhelp snapshot of the systems
+                // processes.
+                HANDLE hSnapShot = lpfCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) ;
+                if(INVALID_HANDLE_VALUE != hSnapShot) {
+                    // Get the first process' information.
+                    PROCESSENTRY32 procentry;
+                    procentry.dwSize = sizeof(PROCESSENTRY32) ;
+                    if(lpfProcess32First( hSnapShot, &procentry )){
+                        rc=true;
+                        do {
+                            wxPInfo p;
+                            p.PID=procentry.th32ProcessID;
+                            p.PPID=procentry.th32ParentProcessID;
+                            arPinfo.push_back(p);
+                        } while(lpfProcess32Next( hSnapShot, &procentry ));
+                    }
+                    CloseHandle(hSnapShot);
+                }
+            }
+        }
+        break;
+    default:
+        break;
+    }    
+    
+    SetParents(arPinfo);
+    
+    if(!rc){
+        wxLogError(_T("Couldn't get process information!\n"));
+    }
+    return rc;
+}
+
+#else // UNIX
+
+bool wxProcessKiller::PSExtract(wxProcessKiller::wxPInfoArray &arPinfo)
+{
+    arPinfo.clear();
+    int i;
+    FILE *f=popen("ps -l",_T("r") MODE_TEXT);
+    if(f){
+        char buf[100];
+        while(fgets(buf,sizeof(buf)-1,f)){
+            TCHAR discard[100];
+            wxPInfo p;
+            // Output is in the form
+            //  F S   UID   PID  PPID  C PRI  NI ADDR    SZ WCHAN  TTY          TIME CMD
+            //100 S   490   877   876  0  70   0    -   368 wait4  pts/0    00:00:00 bash
+            int F,UID,C,PRI,NI,SZ,HH,MM,SS; 
+            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));
+            if(rc){
+                p.tCpu=1000*(SS+60*(60*HH+MM));
+                arPinfo.push_back(p);
+            }
+        }
+        pclose(f);
+        for(i=0;i<(signed)arPinfo.size();i++){
+            int pid=arPinfo[i].PPID;
+            arPinfo[i].pParent=0;
+            for(int j=0;j<(signed)arPinfo.size();j++){
+                if(i!=j && arPinfo[j].PID==pid){
+                    arPinfo[i].pParent=&arPinfo[j];
+                    break;
+                }
+            }
+        }
+    } else {
+        wxLogError(_T("Failed to run ps -l\n"));
+    }
+    return true; //FIXME
+}
+
+#endif
+
+void wxProcessKiller::SetParents(wxProcessKiller::wxPInfoArray &arPinfo)
+{
+    int i;
+    for(i=0;i<(signed)arPinfo.size();i++){
+        wxPInfo &p=arPinfo[i];
+        p.pParent=0;
+        for(int j=0;j<(signed)arPinfo.size();j++){
+            if(arPinfo[j].PID==p.PPID 
+#ifdef _WIN32
+                && arPinfo[j].tCreation<p.tCreation
+#endif
+                )
+            {
+                arPinfo[i].pParent=&arPinfo[j];
+                break;
+            }
+        }
+    }
+    
+    // Check for circularity
+    bool bCircularity=false;
+    for(i=0;i<(signed)arPinfo.size();i++){
+        wxPInfo *p=&arPinfo[i];
+        for(int j=0;j<(signed)arPinfo.size() && p;j++){
+            p=p->pParent;
+        }
+        // If all is well, p should be NULL here.  Otherwise we have a loop.
+        if(p){
+            // Make sure it can't foul things up:
+            arPinfo[i].pParent=0;
+            bCircularity=true;
+        }
+    }
+    
+    if(bCircularity){
+        wxLogError(_T("!!! Circularly linked process list at index %d\n"),i);
+        for(int k=0;k<(signed)arPinfo.size();k++){
+            const wxPInfo &p=arPinfo[k];
+            wxLogError(_T("%d: %s ppid=%4d\n"),k,(LPCTSTR)Name(p.PID),p.PPID);
+        }
+    }
+}
+
+bool wxProcessKiller::wxPInfo::IsChildOf(int pid) const
+{
+    for(wxPInfo *p=pParent;p && p!=this;p=p->pParent) { // guard against circular linkage
+        if(p->PID==pid){
+            return true;
+        }
+    }
+    return false;
+}
+
+const wxString wxProcessKiller::Name(int pid)
+{
+    wxString str;
+    str.Printf(_T("id=%d"),pid);
+#ifdef _DEBUG
+#ifdef _WIN32
+    if(VER_PLATFORM_WIN32_NT==GetPlatform() && hInstLib1){
+        static BOOL (WINAPI *lpfEnumProcessModules)( HANDLE, HMODULE *, DWORD, LPDWORD ) =
+            (BOOL(WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) GetProcAddress( (HINSTANCE) hInstLib1,"EnumProcessModules" ) ;
+        static DWORD (WINAPI *lpfGetModuleFileNameEx)( HANDLE, HMODULE, LPTSTR, DWORD )=
+            (DWORD (WINAPI *)(HANDLE, HMODULE,LPTSTR, DWORD )) GetProcAddress( (HINSTANCE) hInstLib1,"GetModuleFileNameExA" ) ;
+        if( lpfEnumProcessModules &&  lpfGetModuleFileNameEx ) {
+            HANDLE hProcess=::OpenProcess(PROCESS_ALL_ACCESS,false,pid);
+            if(hProcess) {
+                HMODULE hMod;
+                DWORD dwSize;
+                if(lpfEnumProcessModules( hProcess, &hMod, sizeof(HMODULE), &dwSize ) ){
+                    // Get Full pathname:
+                    TCHAR buf[1+MAX_PATH];
+                    lpfGetModuleFileNameEx( hProcess, hMod, buf, MAX_PATH);
+                    str+=_TCHAR(' ');
+                    str+=buf;
+                }
+                CloseHandle(hProcess);
+            }
+        }
+    }
+#endif
+#endif
+    return str;
+}
+
+#ifdef _WIN32
+long wxProcessKiller::GetPlatform()
+{
+    OSVERSIONINFO  osver;
+    osver.dwOSVersionInfoSize = sizeof( osver ) ;
+    return GetVersionEx( &osver ) ? (long) osver.dwPlatformId : (long)-1;
+}
+#endif
+
+const wxString wxProcessKiller::ErrorString() const
+{
+#ifdef _WIN32
+    TCHAR *pszMsg;
+    FormatMessage(  
+        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+        NULL,
+        m_nErr,
+        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+        (LPTSTR)&pszMsg,
+        0,
+        NULL 
+        );
+    return pszMsg;
+#else 
+    return strerror(errno);
+#endif
+}
+