Correct handling of execution errors

This forum is for eXpress++ general support.
Post Reply
Message
Author
User avatar
Eugene Lutsenko
Posts: 1649
Joined: Sat Feb 04, 2012 2:23 am
Location: Russia, Southern federal district, city of Krasnodar
Contact:

Correct handling of execution errors

#1 Post by Eugene Lutsenko »

When executing the

DLLFUNCTION InternetGetConnectedState( @nFlags, nReserved ) USING STDCALL FROM WinInet.Dll

command, an execution error occurs if the Eidos system is already running. How would I handle this error and give the correct message to the user in this case?

Is it possible to apply the execution error handling block in case of a database access conflict when launching modes from the menu?

Code: Select all

   ****** Обработка ошибки ******************
   bError := ErrorBlock( {|e| Break(e)} )     // установить новый кодовый блок обработки ошибок
   BEGIN SEQUENCE                                   // код нормального исполнения
         *** код нормального исполнения
         
           DCMENUBAR oMenuBar OWNERDRAW BARBITMAP 'Checkers.bmp'

    DCSUBMENU oMenu1 PROMPT L('1. Администрирование') PARENT oMenuBar MESSAGE L('Подсистема администрирования')

*     DCMENUITEM SEPARATOR PARENT oMenu1
      DCMENUITEM L('1.1. Авторизация                                 ') PARENT oMenu1 ACTION {|| IF( !Running(), F1_1(),LB_Warning(sms,cmc))    } MESSAGE L('Авторизация сисадмина, администратора приложения или пользователя')
      DCMENUITEM L('1.2. Регистрация администратора приложения       ') PARENT oMenu1 ACTION {|| IF( !Running(), F1_2(),LB_Warning(sms,cmc))    } MESSAGE L('Регистрация и удаление регистрации администраторов приложений и задание паролей пользователей. Этот режим доступен только системному администратору и администраторам приложений')

         ***
         ***
   RECOVER                                          // код обработки ошибки
         aMess := {}
         AADD(aMess, L('При распознавании была попытка превышения максимального допустимого объема БД 2 Гб.'))   // НАПРИМЕР
         AADD(aMess, L('Необходимо уменьшить количество классов или/и объектов распознаваемой выборки !!!  '))
         AADD(aMess, L('Можно также исключить из результатов распознавания наименее достоверные (режим 3.5)'))
         LB_Warning(aMess)
*        EXIT
   ENDSEQUENCE 
   ErrorBlock( bError )                                       // переустановить старый кодовый 
   ******************************************
Attachments
Безымянный.jpg
Безымянный.jpg (40.35 KiB) Viewed 5611 times

User avatar
Auge_Ohr
Posts: 1422
Joined: Wed Feb 24, 2010 3:44 pm

Re: Correct handling of execution errors

#2 Post by Auge_Ohr »

hi Eugene,

Code: Select all

   RECOVER                                          // код обработки ошибки
         aMess := {}
you need to "restore" ErrorBlock( bError ) after RECOVER (and ENDSEQUENCE)
Eugene Lutsenko wrote: Wed Oct 26, 2022 8:08 pm ... an execution error occurs if the Eidos system is already running.
so why do you not "check" if already running :?:
use this

Code: Select all

PROCEDURE APPSYS()
LOCAL cTitle  := "Aidos" 
LOCAL hWndDlg := DllCall( "User32.dll", DLL_STDCALL, "FindWindowA", 0, cTitle )

   IF !( hWndDlg == 0 )
      DllCall( "User32.dll", DLL_STDCALL, "SetForegroundWindow", hWndDlg )
      DllCall( "User32.dll", DLL_STDCALL, "BringWindowToTop", hWndDlg )
      DllCall( "User32.dll", DLL_STDCALL, "ShowWindow", hWndDlg, 1 )
      DllCall( "User32.dll", DLL_STDCALL, "UpdateWindow", hWndDlg )
      *** It is a second instance....  Bye Bye
      QUIT
   ENDIF

   // now DBE Settings 
   IF !DbeLoad( "DBFDBE", .T. )
      ...
RETURN

Code: Select all

PROCEDURE MAIN()
   ...
   oDlg := XbpDialog() :New( APPDESKTOP(),, aPos, aSize, aPres )
   oDlg:title := "Aidos"
the "Title" must be exact "same"
greetings by OHR
Jimmy

User avatar
rdonnay
Site Admin
Posts: 4775
Joined: Wed Jan 27, 2010 6:58 pm
Location: Boise, Idaho USA
Contact:

Re: Correct handling of execution errors

#3 Post by rdonnay »

so why do you not "check" if already running :?:
Use the function DC_IsAppRunning().
The eXpress train is coming - and it has more cars.

User avatar
Eugene Lutsenko
Posts: 1649
Joined: Sat Feb 04, 2012 2:23 am
Location: Russia, Southern federal district, city of Krasnodar
Contact:

Re: Correct handling of execution errors

#4 Post by Eugene Lutsenko »

rdonnay wrote: Thu Oct 27, 2022 8:36 am
so why do you not "check" if already running :?:
Use the function DC_IsAppRunning().

Code: Select all

   IF DC_IsAppRunning('XbpDialog', '(C) Система "Эйдос"', '__aidos-x.exe',.T.)
      QUIT
   ENDIF
For some reason it doesn't work. Immediately there is an error that I have given, and always in the same line 1037

User avatar
unixkd
Posts: 575
Joined: Thu Feb 11, 2010 1:39 pm

Re: Correct handling of execution errors

#5 Post by unixkd »

Try this, work for me. DC_IsAppRunning() did not work for me

Code: Select all

#include "dll.ch"
#include "WinAPI.Ch"
#include "ot4xb.ch"
       
#DEFINE SW_RESTORE 9

FUNCTION IsAppRunning(cExe,cTitle,lRestore,lExactTitle)
/*
   Developed on Windows 98 2nd Edition using XBase++ 1.7

   Tested on Windows 98, 2000, and NT 4.0

   Richard Pulliam
   Richard@ClipperSolutions.com
*/
LOCAL nSearchColumn,aRunningTasks,i,nWinHandleLast,nWinHandleForeground,;
nFindId,nWinHandleFind,nForeGroundId,cColumnContents,nPos,nLenRunTasks

lRestore:=IF(lRestore==NIL,.T.,lRestore) // default to restore running app
nSearchColumn:=IF(cExe#NIL,2,3) // what column to do search on, title or exe?
cExe:=IF(cExe==NIL,"",ALLTRIM(UPPER(cExe)))
cTitle:=IF(cTitle==NIL,"",ALLTRIM(UPPER(cTitle)))
lExactTitle:=IF(lExactTitle==NIL,.T.,lExactTitle)

aRunningTasks := GetRunningTasks() // returns a multidimensional array
                                 // of row form {nHandle,ExeName,Title}
IF WinNT() .AND. !EMPTY(cExe)
   // this is because API function GetModuleBaseNameA does not return
   // a full path and equivalent commands like GetModuleFileName
   // did not work properly
   cExe:=IF((nPos:=RAT("\",cExe))>0,SUBSTR(cExe,nPos+1),cExe)
ENDIF

nLenRunTasks:=LEN(aRunningTasks)  // figure it out only one time!
FOR i:=1 TO nLenRunTasks
   cColumnContents:=ALLTRIM(UPPER(aRunningTasks[i,nSearchColumn]))
   IF (lExactTitle .AND. !EMPTY(cTitle) .AND. cTitle==cColumnContents) .OR. ;
   (!lExactTitle .AND. !EMPTY(cTitle) .AND. AT(cTitle,cColumnContents)>0) .OR. ;
   (!EMPTY(cExe) .AND. cExe==cColumnContents) // Is running!
      IF !lRestore
         RETURN(.T.)
      ELSE
         nWinHandleFind:=aRunningTasks[i,1]
         nWinHandleForeground := @USER32:GetForegroundWindow()
         nForeGroundId := @USER32:GetWindowThreadProcessId(nWinHandleForeground,0)
         nFindId := @USER32:GetWindowThreadProcessId(nWinHandleFind,0)
         IF !(nForeGroundId==nFindId) .or. !(@USER32:IsIconic(nWinHandleFind)==0)
           nWinHandleLast:=@USER32:GetLastActivePopup(nWinHandleFind)
           IF !(@USER32:IsIconic(nWinHandleLast)==0)
             @USER32:ShowWindow(nWinHandleLast,SW_RESTORE)
           ENDIF
           @USER32:BringWindowToTop(nWinHandleLast)
           @USER32:SetForegroundWindow(nWinHandleLast)
         ENDIF
         RETURN(.T.)
      ENDIF
   ENDIF
NEXT
RETURN(.F.)

/* ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ */
STATIC FUNCTION GetRunningTasks()
LOCAL aSize:={0,0},aPos:={0,0},oDlg,aList

// This is so this program will have a window to get the handle on
oDlg:=XbpDialog():new(AppDesktop(),,aPos,aSize,,.F.)
oDlg:clipSiblings:=.T.
oDlg:drawingArea:ClipChildren:=.T.
oDlg:create()
aList:=GetTaskList(oDlg:gethWnd( )) // Get a list of all running programs
oDlg:destroy()
RETURN(aList)

/* ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ */
#DEFINE GW_HWNDNEXT 2

STATIC FUNCTION GetTaskList( nWinHandle )
LOCAL aList:={},cWindowName,nVisible,nSize:=256,nBytes,cFileName,aProcesses,;
nPos,nId

IF WinNT()
   aProcesses:=GetNTProcesses()
ENDIF

WHILE(nWinHandle#0)
   cWindowName:=SPACE(nSize)
   nBytes:=@USER32:GetWindowTextA(nWinHandle,@cWindowName,nSize)
   IF nBytes#0
      cWindowName:=LEFT(cWindowName,nBytes)
      nVisible := @USER32:IsWindowVisible(nWinHandle)
      IF nVisible==1
         IF !WinNT() // Win 95 or 98
            cFileName:=SPACE(nSize)
            nBytes:=@USER32:GetWindowModuleFileNameA(nWinHandle,@cFileName,nSize)
            AADD(aList,{nWinHandle,LEFT(cFileName,nBytes-1),cWindowName})
         ELSE // executing in NT family.  This is necessary because
              // API command @USER32:GetWindowModuleFileName does not work on NT
            nId:=0
            @USER32:GetWindowThreadProcessId(nWinHandle,@nId)
            IF (nPos:=ASCAN(aProcesses,nId))>0
               AADD(aList,{nWinHandle,aProcesses[nPos,2],cWindowName})
            ENDIF
         ENDIF
      ENDIF
   ENDIF
   nWinHandle:=@USER32:GetWindow(nWinHandle,GW_HWNDNEXT)
ENDDO
RETURN(aList)

/* ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ */
#DEFINE PROCESS_ALL_ACCESS 2035711 // hex 1F0FFF

DLLFUNCTION OpenProcess(nDesiredAccess,lInheritHandle,nProcessId) ;
   USING STDCALL FROM KERNEL32.DLL

DLLFUNCTION GetModuleBaseNameW(hProcess,hModule,@lpFileName,@nSize) ;
   USING STDCALL FROM PSAPI.DLL

DLLFUNCTION CloseHandle(nProcessHandle) USING STDCALL FROM KERNEL32.DLL

STATIC FUNCTION GetNTProcesses()
LOCAL aProcessIds,i,nProcessHandle,aRetVal:={},naHandleForProcess,;
cFileName,nSize:=0,nBytes,j,nLenIds,nLenHandles

aProcessIds:=EnumerateProcesses()
nLenIds:=LEN(aProcessIds)
FOR i:=1 TO nLenIds
   // get a handle to the process
   nProcessHandle:=OpenProcess(PROCESS_ALL_ACCESS,0,aProcessIds[i])
   IF nProcessHandle>0
      // get an array of the module handles for the specified process
      naHandleForProcess:=EnumerateProcessModules(nProcessHandle)
      IF (nLenHandles:=LEN(naHandleForProcess))>0
         FOR j:=1 TO nLenHandles
            cFileName:=SPACE(256)
            // GetModuleBaseName and GetModuleBaseNameA do not work here
            // GetModuleFileName .and GetModuleFileNameA do not work here
            nBytes:=GetModuleBaseNameW(nProcessHandle,naHandleForProcess[j],;
               @cFileName,@nSize)
            IF nBytes>0
               AADD(aRetVal,{aProcessIds[i],CleanFileName(cFileName)})
            ENDIF
         NEXT
      ENDIF
      CloseHandle(nProcessHandle)
   ENDIF
NEXT
RETURN(aRetVal)

/* ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ */
STATIC FUNCTION CleanFileName(cFileName)

cFileName:=ALLTRIM(STRTRAN(cFileName,CHR(0),""))
RETURN(cFileName)

/* ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ */
DLLFUNCTION EnumProcesses(@cProcesses,nSize,@nBytesNeeded) ;
   USING STDCALL FROM PSAPI.DLL

STATIC FUNCTION EnumerateProcesses()
LOCAL cProcesses,nSize:=1024,nBytesNeeded:=0,nRetVal:=0,nElements,i,;
naProcessIds:={}

cProcesses:=SPACE(nSize)
nRetVal:=EnumProcesses(@cProcesses,nSize,@nBytesNeeded)
IF nRetVal#0
   nElements:=nBytesNeeded/4  // 4 is size of double word
   FOR i:=1 TO nElements
      AADD(naProcessIds,BIN2U(SUBSTR(cProcesses,4*(i-1)+1,4)))
   NEXT
ENDIF

return(naProcessIds)

/* ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ */
DLLFUNCTION EnumProcessModules(hProcess,@hMod,nSizeOf,@nBytesNeeded) ;
   USING STDCALL FROM PSAPI.DLL

STATIC FUNCTION EnumerateProcessModules(nProcessHandle)
LOCAL nSize:=4096,nBytesNeeded:=0,nRetVal:=0,cModuleHandles,;
naHandleForProcess:={},nElements,i

cModuleHandles:=SPACE(nSize)
nRetVal:=EnumProcessModules(nProcessHandle,@cModuleHandles,nSize,@nBytesNeeded)
IF nRetVal#0
   nElements:=nBytesNeeded/4  // 4 is size of double word
   FOR i:=1 TO nElements
      AADD(naHandleForProcess,BIN2U(SUBSTR(cModuleHandles,4*(i-1)+1,4)))
   NEXT
ENDIF

RETURN(naHandleForProcess)

/* ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ */
#INCLUDE "OS.CH" // part of xbase++ includes

STATIC FUNCTION WinNT()

RETURN(OS(OS_FAMILY)=="WINNT")

User avatar
Eugene Lutsenko
Posts: 1649
Joined: Sat Feb 04, 2012 2:23 am
Location: Russia, Southern federal district, city of Krasnodar
Contact:

Re: Correct handling of execution errors

#6 Post by Eugene Lutsenko »

This is the right idea. I did something similar elsewhere in the system, but easier: http://lc.kubagro.ru/__AidosALL.txt. Search for: "task"

Code: Select all

   ***************************************************************************************************************
   ***** Если система Эйдос уже запущена выдать сообщение об этом и выйти ****************************************
   ***** Предотвращение повторного запуска __aidos-x.exe *********************************************************

   RunShell('/C c:\Windows\System32\TaskList.exe /V /FO CSV > TaskList.csv',,.F.,.T.)       // .F. - чтобы программа не продожалась дальше, пока не закончится перевод

   aTaskList := {}                                         // Все программы, запущенные на компьютере
   nHandle := DC_txtOpen( 'TaskList.csv' )
   DO WHILE !DC_TxtEOF( nHandle )                          // Начало цикла по строкам
      mLine = DC_TxtLine( nHandle )                        // Выделить строку из текстового файла
      mPosExe = AT('.exe', mLine)
      IF mPosExe > 0
         mPos = AT('","', mLine)
         mModName = SUBSTR(mLine,2,mPos-2)
*        MsgBox(ConvToOemCP(mLine))
*        MsgBox(mModName)
         IF ASCAN(aTaskList, mModName) = 0                 // Каждая программа запоминается только один раз
            AADD (aTaskList, mModName)
         ENDIF
      ENDIF
      DC_TxtSkip( nHandle, 1 )
   ENDDO
   DC_TxtClose( nHandle )
*  LB_Warning(aTaskList, '(C°) Система "Эйдос-Х++"')

   mFlagAidos = .F.                                        // Система Эйдос не  запущена
*  MsgBox(STR(ASCAN(aTaskList, '__aidos-x.exe')))
   IF ASCAN(aTaskList, '__aidos-x.exe') > 0                // Система Эйдос уже запущена
      mFlagAidos = .T.                     
   ENDIF

*  IF DC_IsAppRunning('XbpDialog', '(C) Система "Эйдос"', '__aidos-x.exe',.T.)
   IF mFlagAidos
      aMess := {}
      AADD(aMess, 'Система "Эйдос" уже запущена в папке: "'+ConvToOemCP(ALLTRIM(Disk_dir))+'\"'  )
      AADD(aMess, 'Нельзя запускать исполнимый модуль системы: "_aidos-x.exe"')
      AADD(aMess, 'несколько раз, т.к. система будет пытаться одновременно   ')
      AADD(aMess, 'обращаться к одним и тем же базам данных, что вызывает    ')
      AADD(aMess, 'ошибку исполнения.                                        ')
      LB_Warning(aMess, '(C°) Система "Эйдос"')
      QUIT
   ENDIF 
   ***** Если система Эйдос уже запущена в данной папке выдать сообщение об этом и выйти *************************
   ***************************************************************************************************************

User avatar
Eugene Lutsenko
Posts: 1649
Joined: Sat Feb 04, 2012 2:23 am
Location: Russia, Southern federal district, city of Krasnodar
Contact:

Re: Correct handling of execution errors

#7 Post by Eugene Lutsenko »

I'm trying to make a menu that will give an error message in the function being called. It's not working out very well yet
Attachments
4.zip
(12.96 KiB) Downloaded 423 times

Post Reply