Author |
Topic |
|
Alexander N
Germany
18 Posts |
Posted - 09/29/2009 : 2:08:17 PM
|
Origin Ver. and Service Release (Select Help-->About Origin): 8.0 SR5&6 Operating System: Windows XP Pro SP3
Hi guys,
since quite a long time I try to start an external program (which has only commandline inputs, no gui) out of OriginC.
I declared the MS C++ native methods shellExecute / Winexec and CreateProcess in a header file. Then I could start the program using WinExec and shellExecute, but Origin always crashes after this command and the external program is also stopped.
With createProcess I even could not call the program since I could not imagine how to redeclare the pointers for ProcessInformation and Security_Attr in native OriginC datatypes.
I hope that someone could please explain this program breakdown or even has a snipet for using createProcess with Origin!?
My header looks like this (switching the pragma regarding the method to use):
//#pragma dll(kernel32, system)
#pragma dll(shell32, system)
#include <common.h> // must always include this
#include <string.h> // most likely you will also need strings
#include <mswin.h>
#include <Origin.h>
BOOL WINAPI CreateProcessA(
string lpApplicationName,
string lpCommandLine,
void * lpProcessAttributes,
void * lpThreadAttributes,
bool bInheritHandles,
int dwCreationFlags,
void * lpEnvironment,
string lpCurrentDirectory,
void * lpStartupInfo,
void * lpProcessInformation
);
int WinExec(
string lpCmdLine,
int uCmdShow
);
void ShellExecuteA (
void * hwnd,
string lpOperation,
string lpFile,
string lpParameters,
string lpDirectory,
int nShowCmd
);
And my code snippet for calling the method like this:
void * start;
void * info;
try {
//CreateProcessA(NULL, app, ¶ms, NULL, FALSE, 0, NULL, "", &start, &info);
//out_str(info);
//WinExec(app, 1);
ShellExecuteA(NULL, "open", "TEST.EXE", params, path, 1);
//out_str(GetLastError());
}
catch(int nErr) {
out_int("Error Calling External DLL = ", nErr);
}
Thanks in advance,
Alexander |
|
cpyang
USA
1406 Posts |
Posted - 10/02/2009 : 2:41:12 PM
|
The following has been added to mswin.h in upcoming Origin 8.1 and you can copy and paste into your own header in Origin 8. After #pragma dll(kernel32, system)
CP
//
// dwCreationFlags (Process Creation Flags) used in CreateProcess
//
#define DEBUG_PROCESS 0x00000001
#define DEBUG_ONLY_THIS_PROCESS 0x00000002
#define CREATE_SUSPENDED 0x00000004
#define DETACHED_PROCESS 0x00000008
#define CREATE_NEW_CONSOLE 0x00000010
#define NORMAL_PRIORITY_CLASS 0x00000020
#define IDLE_PRIORITY_CLASS 0x00000040
#define HIGH_PRIORITY_CLASS 0x00000080
#define REALTIME_PRIORITY_CLASS 0x00000100
#define CREATE_NEW_PROCESS_GROUP 0x00000200
#define CREATE_UNICODE_ENVIRONMENT 0x00000400
#define CREATE_SEPARATE_WOW_VDM 0x00000800
#define CREATE_SHARED_WOW_VDM 0x00001000
#define CREATE_FORCEDOS 0x00002000
#define CREATE_BREAKAWAY_FROM_JOB 0x01000000
#define CREATE_PRESERVE_CODE_AUTHZ_LEVEL 0x02000000
#define CREATE_DEFAULT_ERROR_MODE 0x04000000
#define CREATE_NO_WINDOW 0x08000000
//probably don't need these in OC
//#define PROFILE_USER 0x10000000
//#define PROFILE_KERNEL 0x20000000
//#define PROFILE_SERVER 0x40000000
//
// dwFlags in STARTUPINFO Structure
//
#define STARTF_USESHOWWINDOW 0x00000001
#define STARTF_USESIZE 0x00000002
#define STARTF_USEPOSITION 0x00000004
#define STARTF_USECOUNTCHARS 0x00000008
#define STARTF_USEFILLATTRIBUTE 0x00000010
#define STARTF_RUNFULLSCREEN 0x00000020 // ignored for non-x86 platforms
#define STARTF_FORCEONFEEDBACK 0x00000040
#define STARTF_FORCEOFFFEEDBACK 0x00000080
#define STARTF_USESTDHANDLES 0x00000100
#define STARTF_USEHOTKEY 0x00000200
typedef struct _STARTUPINFO {
DWORD cb;
LPSTR lpReserved;
LPSTR lpDesktop;
LPSTR lpTitle;
DWORD dwX;
DWORD dwY;
DWORD dwXSize;
DWORD dwYSize;
DWORD dwXCountChars;
DWORD dwYCountChars;
DWORD dwFillAttribute;
DWORD dwFlags;
WORD wShowWindow;
WORD cbReserved2;
BYTE *lpReserved2;
HANDLE hStdInput;
HANDLE hStdOutput;
HANDLE hStdError;
} STARTUPINFO, *LPSTARTUPINFO;
typedef struct _PROCESS_INFORMATION {
HANDLE hProcess;
HANDLE hThread;
DWORD dwProcessId;
DWORD dwThreadId;
} PROCESS_INFORMATION, *LPPROCESS_INFORMATION;
#define CreateProcess CreateProcessA
/**
The CreateProcess function creates a new process and its primary thread. The new process executes the specified executable file.
Remarks:
For more info please check: http://msdn.microsoft.com/en-us/library/ms682425(VS.85).aspx
Example:
void test_create_process()
{
STARTUPINFO sinfo;
PROCESS_INFORMATION pinfo;
memset(&sinfo, 0, sizeof(STARTUPINFO));
memset(&pinfo, 0, sizeof(PROCESS_INFORMATION));
// test control wShowWindow
sinfo.dwFlags = STARTF_USESHOWWINDOW;
sinfo.wShowWindow = SW_SHOWMAXIMIZED;
BOOL bSucess = CreateProcess("C:\\Windows\\notepad.exe", NULL, NULL, NULL, FALSE, CREATE_DEFAULT_ERROR_MODE, NULL, NULL, &sinfo, &pinfo);
}
*/
BOOL WINAPI CreateProcess(
LPCSTR lpApplicationName,
LPSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCSTR lpCurrentDirectory,
LPSTARTUPINFO lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);
|
|
|
Alexander N
Germany
18 Posts |
Posted - 10/05/2009 : 10:54:00 AM
|
quote: Originally posted by cpyang
BOOL WINAPI CreateProcess(
LPCSTR lpApplicationName,
LPSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCSTR lpCurrentDirectory,
LPSTARTUPINFO lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);
Here I get an compiler error regarding syntax of the variables and type of variables. I tried a debug but could not distinguish which variable is affected.
Edit: Comparing your solution with your mswin.h, I suggest, that LPSECURITY_ATTRIBUTES should be replaced with a pointer SECURITY_ATTRIBUTES * ?? Then the code compiles successfully... |
Edited by - Alexander N on 10/05/2009 11:02:28 AM |
|
|
Alexander N
Germany
18 Posts |
Posted - 10/05/2009 : 11:43:30 AM
|
Ok, now it works properly without break down. But how can I determine when the process has finished? Is it sufficient to copy all the definitions from MSDN:GetExitCodeProcess to my header and then execute GetExitCodeProcess? |
|
|
cpyang
USA
1406 Posts |
Posted - 10/05/2009 : 4:13:36 PM
|
We have modified LPSECURITY_ATTRIBUTES in the Origin 8.1 mswin.h, sorry I forgot to mention.
Sure, we will add GetExitCodeProcess to mswin.h as well, and that function is simple so you can add to yours.
CP
|
|
|
cpyang
USA
1406 Posts |
Posted - 10/05/2009 : 4:48:03 PM
|
The following added to 8.1 mswin.h
//a subset of the status values that you might see in GetExitCodeProcess
#define STATUS_TIMEOUT 0x00000102
#define STATUS_PENDING 0x00000103
#define STATUS_ACCESS_VIOLATION 0xC0000005
#define STATUS_IN_PAGE_ERROR 0xC0000006
#define STATUS_INVALID_HANDLE 0xC0000008
#define STATUS_NO_MEMORY 0xC0000017
BOOL WINAPI TerminateProcess(HANDLE hProcess, UINT uExitCode);
BOOL WINAPI GetExitCodeProcess(HANDLE hProcess, LPDWORD lpExitCode);
And the following example added as well
void create_and_terminate_process()
{
STARTUPINFO sinfo;
PROCESS_INFORMATION pinfo;
memset(&sinfo, 0, sizeof(STARTUPINFO));
memset(&pinfo, 0, sizeof(PROCESS_INFORMATION));
// test control wShowWindow
sinfo.dwFlags = STARTF_USESHOWWINDOW;
sinfo.wShowWindow = SW_SHOWMAXIMIZED;
BOOL bSucess = CreateProcess("C:\\Windows\\notepad.exe", NULL, NULL, NULL, FALSE, CREATE_DEFAULT_ERROR_MODE, NULL, NULL, &sinfo, &pinfo);
DWORD dwCode;
if(GetExitCodeProcess(pinfo.hProcess, &dwCode))
{
if(dwCode == STATUS_PENDING)
out_str("still alive");
else
printf("code = %X\n", dwCode);
}
else
out_str("Failed to get exit code");
//wait 1 sec
LT_execute("sec -p 1");
TerminateProcess(pinfo.hProcess, 2);
if(GetExitCodeProcess(pinfo.hProcess, &dwCode))
printf("After terminated, code = %X\n", dwCode);
else
out_str("Failed to get exit code");
}
If you need to wait for process to be terminated by the user, then maybe build your own loop with LT_execute("sec -p 0.2") in the loop.
CP
|
|
|
Alexander N
Germany
18 Posts |
Posted - 10/06/2009 : 03:43:31 AM
|
DWORD dwCode;
int timer = 0;
if(GetExitCodeProcess(pinfo.hProcess, &dwCode)) {
while(&dwCode == STATUS_PENDING) {
Sleep(0.1);
timer++;
if (timer > 100) {
TerminateProcess(pinfo.hProcess, 2);
printf("After terminated, code = %X\n", dwCode);
break;
}
GetExitCodeProcess(pinfo.hProcess, &dwCode);
}
}
else {
out_str("Failed to get exit code");
}
Hi, I now used a loop. It seems to work. Thanks for the improvements to the code base!
Alexander |
|
|
cpyang
USA
1406 Posts |
Posted - 10/06/2009 : 07:57:03 AM
|
you mean to use
while(dwCode == STATUS_PENDING)
right? CP
|
|
|
Alexander N
Germany
18 Posts |
Posted - 10/06/2009 : 10:14:43 AM
|
No, by reference &dwCode is possible. call by value does not exit the loop... Perhaps I'm wrong, but I thought this works. |
|
|
cpyang
USA
1406 Posts |
Posted - 10/06/2009 : 2:00:49 PM
|
How about this,
void create_and_terminate_process(int max = 100)
{
STARTUPINFO sinfo;
PROCESS_INFORMATION pinfo;
memset(&sinfo, 0, sizeof(STARTUPINFO));
memset(&pinfo, 0, sizeof(PROCESS_INFORMATION));
sinfo.dwFlags = STARTF_USESHOWWINDOW;
sinfo.wShowWindow = SW_SHOWMAXIMIZED;
BOOL bSucess = CreateProcess("C:\\Windows\\notepad.exe", NULL, NULL, NULL, FALSE, CREATE_DEFAULT_ERROR_MODE, NULL, NULL, &sinfo, &pinfo);
DWORD dwCode;
if(GetExitCodeProcess(pinfo.hProcess, &dwCode))
{
if(dwCode == STATUS_PENDING)
out_str("lunch successfully.");
else
printf("code = %X\n", dwCode);
}
else
out_str("Failed to get exit code");
if(dwCode != STATUS_PENDING)// something is wrong
return;
dwCode = 1;//init to some other values
int timer = 0;
while(GetExitCodeProcess(pinfo.hProcess, &dwCode) && dwCode == STATUS_PENDING) {
Sleep(100);//0.1 sec, Origin will be totally dead
timer++;
if (timer == max)
TerminateProcess(pinfo.hProcess, 2);
}
printf("%d:final exit code = %X\n", timer, dwCode);
}
I tested this and works by either user closing Notepad, or wait for 10 sec to terminate and you see the correct exit code for both cases.
CP
|
|
|
Alexander N
Germany
18 Posts |
Posted - 10/07/2009 : 02:25:22 AM
|
Yeap. Both seems to work. Your way could be more stable or "more right". So I followed your solution instead of call by reference. So, thanks again! |
|
|
alexander.steppke
Germany
10 Posts |
Posted - 10/19/2009 : 09:28:59 AM
|
Hi everybody,
it would be very helpful if you could summarize a complete working example, so that we know which files need to be changed to use the CreateProcess function with Origin 8 SR 6. I tried different approaches and at the end still have the error "Error, external DLL cannot find function shell32 : CreateProcess".
Thank you and greetings Alexander
|
|
|
Alexander N
Germany
18 Posts |
Posted - 10/20/2009 : 04:05:05 AM
|
Yes, that's a mistake in my upper example. This line is correct according to MSDN (error came from switching between CreateProcess and ShellExecute / WinExec):
#pragma dll(kernel32, system) // for CreateProcess
or
#pragma dll(shell32, system) // for WinExec and ShellExecute
|
|
|
|
Topic |
|
|
|