Určitě jste již někdy potřebovali spustit externí program a čekat,až skončí. VFP sice má příkaz RUN, ale jaksi to není ono.
Tento článek by nevznikl nebýt dvou věcí:
1) mailu Maroše Klempy ze dne 19.3.2001 v
konferenci FoxPro
2) a
mé nutné potřeby to taky konečně vyřešit
BOOL CreateProcess( LPCTSTR lpApplicationName, // ukazatel na název spouštěného modulu LPTSTR lpCommandLine, // ukazatel na řetězec příkazového řádku LPSECURITY_ATTRIBUTES lpProcessAttributes, // bezpečnostní atributy procesu LPSECURITY_ATTRIBUTES lpThreadAttributes, // bezpečnostní atributy threadu BOOL bInheritHandles, // handle inheritance flag DWORD dwCreationFlags, // příznak vytvoření procesu LPVOID lpEnvironment, // ukazatel na nový blok prostředí LPCTSTR lpCurrentDirectory, // ukazatel na název startovacího adresáře LPSTARTUPINFO lpStartupInfo, // ukazatel na STARTUPINFO LPPROCESS_INFORMATION lpProcessInformation // ukazatel na PROCESS_INFORMATION );
typedef struct _STARTUPINFO { // si
DWORD cb;
LPTSTR lpReserved;
LPTSTR lpDesktop;
LPTSTR lpTitle;
DWORD dwX;
DWORD dwY;
DWORD dwXSize;
DWORD dwYSize;
DWORD dwXCountChars;
DWORD dwYCountChars;
DWORD dwFillAttribute;
DWORD dwFlags;
WORD wShowWindow;
WORD cbReserved2;
LPBYTE lpReserved2;
HANDLE hStdInput;
HANDLE hStdOutput;
HANDLE hStdError;
} STARTUPINFO, *LPSTARTUPINFO;
Hodnota | Popis |
STARTF_USESHOWWINDOW | Pokud tato hodnota není specifikována, člen wShowWindow je ignorován. |
STARTF_USEPOSITION | Pokud tato hodnota není specifikována, členové dwX a dwY jsou ignorovány. |
STARTF_USESIZE | Pokud tato hodnota není specifikována, členové dwXSize a dwYSize jsou ignorovány. |
STARTF_USECOUNTCHARS | Pokud tato hodnota není specifikována, členové dwXCountChars a dwYCountChars jsou ignorovány. |
STARTF_USEFILLATTRIBUTE | Pokud tato hodnota není specifikována, člen dwFillAttribute je ignorován. |
STARTF_FORCEONFEEDBACK | |
STARTF_FORCEOFFFEEDBACK | |
STARTF_USESTDHANDLES |
typedef struct _PROCESS_INFORMATION { // pi
HANDLE hProcess;
HANDLE hThread;
DWORD dwProcessId;
DWORD dwThreadId;
} PROCESS_INFORMATION;
* Použití funkce WaitForSingleObject() DO WHILE WaitForSingleObject(loProcessInfo.hProcess, 100 ) = WAIT_TIMEOUT ENDDO * Použití funkce GetExitCodeProcess() liExitCode=STILL_ACTIVE DO WHILE liExitCode=STILL_ACTIVE =Sleep(100) =GetExitCodeProcess(loProcessInfo.hProcess,@liExitCode) ENDDO
DEFINE CLASS _cpTimer AS timer Enabled=.F. Interval=250 hProcess=0 && Handle procesu PROCEDURE Timer * Použití funkce WaitForSingleObject() IF WaitForSingleObject(This.hProcess, 100 ) = WAIT_TIMEOUT * Proces zatím běží, dělěj si co chceš This.Process_Active() ELSE =CloseHandle(This.hProcess) && Zavři handle This.Enabled=.F. This.Process_Close() ENDIF * Použití funkce GetExitCodeProcess() *liExitCode=0 *=GetExitCodeProcess(This.hProcess,@liExitCode) *IF liExitCode=STILL_ACTIVE * * Proces zatím běží, dělěj si co chceš * This.Process_Active() *ELSE * =CloseHandle(This.hProcess) && Zavři handle * This.Enabled=.F. * This.Process_Close() *ENDIF ENDPROC * Proces stále běží PROCEDURE Process_Active ENDPROC * Proces je ukončen PROCEDURE Process_Close ENDPROC ENDDEFINE
DECLARE INTEGER CreateProcess IN kernel32.DLL ; STRING lpApplicationName, ; STRING lpCommandLine, ; INTEGER lpProcessAttributes, ; INTEGER lpThreadAttributes, ; INTEGER bInheritHandles, ; INTEGER dwCreationFlags, ; INTEGER lpEnvironment, ; STRING @lpCurrentDirectory, ; STRING @lpStartupInfo, ; STRING @lpProcessInformation DECLARE INTEGER WaitForSingleObject IN kernel32.DLL ; INTEGER hHandle, INTEGER dwMilliseconds DECLARE INTEGER CloseHandle IN kernel32.DLL INTEGER hObject DECLARE INTEGER GetLastError IN kernel32.DLL DECLARE INTEGER GetExitCodeProcess IN kernel32.dll INTEGER,INTEGER @
* (INTEGER) LPTSTR lpReserved * (INTEGER) LPTSTR lpDesktop * (INTEGER) LPTSTR lpTitle * (INTEGER) DWORD dwX * (INTEGER) DWORD dwY * (INTEGER) DWORD dwXSize * (INTEGER) DWORD dwYSize * (INTEGER) DWORD dwXCountChars * (INTEGER) DWORD dwYCountChars * (INTEGER) DWORD dwFillAttribute * (INTEGER) DWORD dwFlags * (INTEGER) WORD wShowWindow * (INTEGER) WORD cbReserved2 * (INTEGER) LPBYTE lpReserved2 (??? vynecháno ???) * (INTEGER) HANDLE hStdInput * (INTEGER) HANDLE hStdOutput * (INTEGER) HANDLE hStdError DEFINE CLASS _struc_STARTUPINFO AS DataEnvironment PROTECT lpReserved,lpDesktop,lpTitle,cbReserved2,lpReserved2 lpReserved=.NULL. lpDesktop=.NULL. lpTitle=.NULL. dwX=0 dwY=0 dwXSize=0 dwYSize=0 dwXCountChars=0 dwYCountChars=0 dwFillAttribute=0 dwFlags=0 wShowWindow=0 cbReserved2=0 lpReserved2=.NULL. hStdInput=0 hStdOutput=0 hStdError=0 PROCEDURE SizeOf() RETURN 68 ENDPROC * Vytvoří string PROCEDURE CreateString() RETURN IToC4(This.SizeOf())+; IToC4(IIF(ISNULL(This.lpReserved),0,0))+; IToC4(IIF(ISNULL(This.lpDesktop),0,0))+; IToC4(IIF(ISNULL(This.lpTitle),0,0))+; IToC4(This.dwX)+; IToC4(This.dwY)+; IToC4(This.dwXSize)+; IToC4(This.dwYSize)+; IToC4(This.dwXCountChars)+; IToC4(This.dwYCountChars)+; IToC4(This.dwFillAttribute)+; IToC4(This.dwFlags)+; IToC4(This.wShowWindow)+; IToC4(This.cbReserved2)+; IToC4(IIF(ISNULL(This.lpReserved2),0,0))+; IToC4(This.hStdInput)+; IToC4(This.hStdOutput)+; IToC4(This.hStdError) ENDPROC ENDDEFINE * (INTEGER) HANDLE hProcess * (INTEGER) HANDLE hThread * (INTEGER) DWORD dwProcessId * (INTEGER) DWORD dwThreadId DEFINE CLASS _struc_PROCESS_INFORMATION AS DataEnvironment hProcess=0 hThread=0 dwProcessId=0 dwThreadId=0 * Vytvoří string PROCEDURE CreateString() RETURN IToC4(This.hProcess)+; IToC4(This.hThread)+; IToC4(This.dwProcessId)+; IToC4(This.dwThreadId) ENDPROC * Ze stringu načte zpět informace PROCEDURE ReadString(lcStruc) This.hProcess=C4ToI(LEFT(lcStruc,4)) This.hThread=C4ToI(SUBST(lcStruc,5,4)) This.dwProcessId=C4ToI(SUBST(lcStruc,9,4)) This.dwThreadId=C4ToI(RIGHT(lcStruc,4)) ENDPROC ENDDEFINE
********************************** PROCEDURE C4ToI(lcInt) && Číslo v řetězcovém tvaru WINAPI 32 bitů RETURN ASC(LEFT(lcInt,1))+; ASC(SUBS(lcInt,2,1))*256+; ASC(SUBS(lcInt,3,1))*65536+; ASC(RIGHT(lcInt,1))*256*65536 && Vrať číslo v decimálním tvaru ********************************** PROCEDURE IToC4(liVal) && převede číslo na 4 bajtový řetězec LOCAL lcVal,lii lii=INT(liVal/256) && Vyděl 256 lcVal=CHR(liVal-lii*256) && Převeď rozdíl na znak a přičti ho liVal=lii && Zapiš novou hodnotu pro převod lii=INT(liVal/256) && Vyděl 256 lcVal=lcVal+CHR(liVal-lii*256) liVal=lii && Zapiš novou hodnotu pro převod lii=INT(liVal/256) && Vyděl 256 lcVal=lcVal+CHR(liVal-lii*256) liVal=lii && Zapiš novou hodnotu pro převod lii=INT(liVal/256) && Vyděl 256 RETURN lcVal+CHR(liVal-lii*256) && Převeď rozdíl na znak a přičti ho
* Funkce CreateProcess() #DEFINE CREATE_DEFAULT_ERROR_MODE 0x04000000 #DEFINE CREATE_NEW_CONSOLE 0x00000010 #DEFINE CREATE_NEW_PROCESS_GROUP 0x00000200 #DEFINE CREATE_SEPARATE_WOW_VDM 0x00000800 #DEFINE CREATE_SHARED_WOW_VDM 0x00001000 #DEFINE CREATE_SUSPENDED 0x00000004 #DEFINE CREATE_UNICODE_ENVIRONMENT 0x00000400 #DEFINE DEBUG_PROCESS 0x00000001 #DEFINE DEBUG_ONLY_THIS_PROCESS 0x00000002 #DEFINE DETACHED_PROCESS 0x00000008 #DEFINE NORMAL_PRIORITY_CLASS 0x00000020 #DEFINE IDLE_PRIORITY_CLASS 0x00000040 #DEFINE HIGH_PRIORITY_CLASS 0x00000080 #DEFINE REALTIME_PRIORITY_CLASS 0x00000100 * Nastavení členů pro strukturu STARTUPINFO #DEFINE STARTF_USESHOWWINDOW 0x00000001 #DEFINE STARTF_USESIZE 0x00000002 #DEFINE STARTF_USEPOSITION 0x00000004 #DEFINE STARTF_USECOUNTCHARS 0x00000008 #DEFINE STARTF_USEFILLATTRIBUTE 0x00000010 #DEFINE STARTF_FORCEONFEEDBACK 0x00000040 #DEFINE STARTF_FORCEOFFFEEDBACK 0x00000080 #DEFINE STARTF_USESTDHANDLES 0x00000100 * Konstanty pro člen wShowWindow ve struktuře STARTUPINFO #DEFINE SW_HIDE 0 #DEFINE SW_SHOWNORMAL 1 #DEFINE SW_NORMAL 1 #DEFINE SW_SHOWMINIMIZED 2 #DEFINE SW_SHOWMAXIMIZED 3 #DEFINE SW_MAXIMIZE 3 #DEFINE SW_SHOWNOACTIVATE 4 #DEFINE SW_SHOW 5 #DEFINE SW_MINIMIZE 6 #DEFINE SW_SHOWMINNOACTIVE 7 #DEFINE SW_SHOWNA 8 #DEFINE SW_RESTORE 9 #DEFINE SW_SHOWDEFAULT 10 #DEFINE SW_MAX 10 * Funkce WaitForSingleObject() #DEFINE WAIT_TIMEOUT 0x00000102 #DEFINE INFINITE 0xFFFFFFFF && Infinite timeout * Funkce GetExitCodeProcess() #DEFINE STILL_ACTIVE 0x00000103
* Vytvoř objekty pro vygenerování struktur loStartupInfo=CREATEOBJECT("_struc_STARTUPINFO") loProcessInfo=CREATEOBJECT("_struc_PROCESS_INFORMATION") * Nastav aby se okno skrylo loStartupInfo.dwFlags=STARTF_USESHOWWINDOW loStartupInfo.wShowWindow=SW_HIDE * Nastav aby se okno zobrazilo na pozicích 10,20 *loStartupInfo.dwFlags=STARTF_USESHOWWINDOW + STARTF_USEPOSITION *loStartupInfo.wShowWindow=SW_NORMAL *loStartupInfo.dwX=10 *loStartupInfo.dwY=20 * Vytvoř řetězce lcStartupInfo=loStartupInfo.CreateString() lcProcessInfo=loProcessInfo.CreateString() lcDir="c:\temp\" lcProgram="explorer /select,c:\windows\calc.exe" IF CreateProcess(.NULL., lcProgram, 0, 0, 1, NORMAL_PRIORITY_CLASS, 0, @lcDir, @lcStartupInfo, @lcProcessInfo)#0 * Výborně neselhalo to loProcessInfo.ReadString(@lcProcessInfo) DO WHILE WaitForSingleObject(loProcessInfo.hProcess, 100 ) = WAIT_TIMEOUT ENDDO =CloseHandle(loProcessInfo.hProcess) && Uzavři handle * Pokud se použije timer *loTim=CREATEOBJECT("_ExcpTimer") *loTim.hProcess=loProcessInfo.hProcess *loTim.Enabled=.T. ELSE * Selhalo spuštění procesu ENDIF DEFINE CLASS _ExcpTimer AS _cpTimer PROCEDURE Process_Close =MESSAGEBOX("Explorer spuštěn") ENDPROC ENDDEFINE
1) | Jelikož VFP nativně nepodporuje struktury, je ze strany VFP naplňování řetězců do struktur velmi obtížné. Z toho důvodu je zakázáno vyplňovat vlastnosti lpDesktop, lpTitle ve třídě _struc_STARTUPINFO. Pokud by jste chtěli používat tyto členy, pak by jste museli museli použít knihovnu struct.vcx, která slouží pro vytvoření různých struktur pro práci s API funkcemi. |
2) | RUN - není to ono především z toho důvodu,že je jako první spuštěn foxrun.pif se všemi specifikacemi a pak teprve vlastní externí program.Foxrun.pif ovšem volá služby MS-DOS a jeho použití pak vyvolává problémy především pod Windows NT,kde je DOS jen další programovou konzolou. |
Použité zdroje:
konference Foxpro na Pandoře.Z nějakých neznámých příčin, se mi nepodařilo najít tento mail jak na Pandoře, tak v Archívu :-( . | |
MSDN | MSDN - Processes and Threads |
Jazyková korektura: | Paul Arleth | gw4@volny.cz |
Odborná korektura: | Roman Procházka | rprochazka@acedesign.cz |