Solved

CreateProcess API

Posted on 2001-07-31
19
1,092 Views
Last Modified: 2008-02-01
hi experts,
i am using VB6 and i have an application with more than 10 separate EXEs. from one main exe all other exes are called. after calling an EXE from main exe user doesnt want to use main exe untill he closes the other one. this i was able to do using CreateProcess and WaitforSingleObject APIS. but this is giving two problems.

First problem is if i move the form displayed by second EXE the area occupied by this form is not getting refreshed.

Second problem is if i click on any of the buttons on the form in Main EXE all these click events are fired in the same sequence after closing second EXE.

for information the OS i am using is Win 9X (Japaneese).
the simillar function written in VB4 is working fine but the only difference is in the old function using API CreateProcessbyNum. i couldn't find documentation of this API.

any solution?

RAO
0
Comment
Question by:appari
  • 4
  • 4
  • 3
  • +5
19 Comments
 
LVL 5

Expert Comment

by:KDivad
Comment Utility
Why not hide the form before calling the exe? Or .Enabled = False before calling?
0
 
LVL 39

Author Comment

by:appari
Comment Utility
by the time we call second exe more than one form is visible from the calling exe (few are Modal forms) so i can't hide.

i forget to mention that i tried .enabled =false also still same problems.

RAO
0
 
LVL 5

Expert Comment

by:KDivad
Comment Utility
That is a curious problem. I'm not sure what else to try.
0
 
LVL 5

Expert Comment

by:KDivad
Comment Utility
Is something wierd going on? I could have sworn this would make my third post for this question!
0
 
LVL 5

Expert Comment

by:KDivad
Comment Utility
'Scuse me. That should have read fourth and make this the fifth...
0
 
LVL 1

Expert Comment

by:mcbeth
Comment Utility
maybe -if i understood your problem- you have to search the processlist (see taskmanager) for running exe files.

if exe file will be found in processlist you can exit sub/funktion with a msgbox ??

If you want to do so here is some code :
in bas modul :
Public Const MAX_PATH& = 260
Type PROCESSENTRY32
    dwSize As Long
    cntUsage As Long
    th32ProcessID As Long
    th32DefaultHeapID As Long
    th32ModuleID As Long
    cntThreads As Long
    th32ParentProcessID As Long
    pcPriClassBase As Long
    dwFlags As Long
    szexeFile As String * MAX_PATH
End Type
Private Declare Function ProcessFirst Lib "kernel32" Alias "Process32First" (ByVal hSnapshot As Long, uProcess As PROCESSENTRY32) As Long
Private Declare Function ProcessNext Lib "kernel32" Alias "Process32Next" (ByVal hSnapshot As Long, uProcess As PROCESSENTRY32) As Long
Private Declare Function CreateToolhelpSnapshot Lib "kernel32" Alias "CreateToolhelp32Snapshot" (ByVal lFlags As Long, lProcessID As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long

Public Function IsProgRunning(pzFilename as string) As Boolean
Const PROCESS_ALL_ACCESS = 0
Const TH32CS_SNAPPROCESS As Long = 2&

Dim uProcess As PROCESSENTRY32
Dim bolFound As Boolean
Dim rProcessFound As Long
Dim hSnapshot As Long
Dim szExeName As String
Dim lpExitCode As Long
Dim appCount As Integer
Dim i As Integer

appCount = 0
bolFound = False
uProcess.dwSize = Len(uProcess)
hSnapshot = CreateToolhelpSnapshot(TH32CS_SNAPPROCESS, 0&)
rProcessFound = ProcessFirst(hSnapshot, uProcess)
Do While rProcessFound
    i = InStr(1, uProcess.szexeFile, Chr(0))
    szExeName = LCase(Left(uProcess.szexeFile, i - 1))
    If szExeName = pzfilename Then
        bolFound = True
        Exit Do
    End If
    rProcessFound = ProcessNext(hSnapshot, uProcess)
Loop
Call CloseHandle(hSnapshot)
IsProgRunning = bolFound
End Function

the filename you want to search for are in lowercase..

To prevent main exe to start twice or more use
 If App.PrevInstance = True Then

hope thie will help you
0
 
LVL 43

Expert Comment

by:TimCottee
Comment Utility
appari, I think that what you need to do is find the handle of the original exe with FindWindow API call or similar and then use RedrawWindow API:

Const RDW_INVALIDATE = &H1

Private Declare Function RedrawWindow Lib "user32" (ByVal hwnd As Long, lprcUpdate As Any, ByVal hrgnUpdate As Long, ByVal fuRedraw As Long) As Long

    RedrawWindow hwnd, ByVal 0&, ByVal 0&,
RDW_INVALIDATE

where hwnd is the window handle of the previous call to FindWindow.
0
 
LVL 38

Expert Comment

by:PaulHews
Comment Utility
Here is a version of ExecCmd that keeps the calling app responsive using a DoEvents loop to wait for the called app to return.
Option Explicit

      Private Type STARTUPINFO
         cb As Long
         lpReserved As String
         lpDesktop As String
         lpTitle As String
         dwX As Long
         dwY As Long
         dwXSize As Long
         dwYSize As Long
         dwXCountChars As Long
         dwYCountChars As Long
         dwFillAttribute As Long
         dwFlags As Long
         wShowWindow As Integer
         cbReserved2 As Integer
         lpReserved2 As Long
         hStdInput As Long
         hStdOutput As Long
         hStdError As Long
      End Type

      Private Type PROCESS_INFORMATION
         hProcess As Long
         hThread As Long
         dwProcessID As Long
         dwThreadID As Long
      End Type

      Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal _
         hHandle As Long, ByVal dwMilliseconds As Long) As Long

      Private Declare Function CreateProcessA Lib "kernel32" (ByVal _
         lpApplicationName As Long, ByVal lpCommandLine As String, ByVal _
         lpProcessAttributes As Long, ByVal lpThreadAttributes As Long, _
         ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, _
         ByVal lpEnvironment As Long, ByVal lpCurrentDirectory As Long, _
         lpStartupInfo As STARTUPINFO, lpProcessInformation As _
         PROCESS_INFORMATION) As Long

      Private Declare Function CloseHandle Lib "kernel32" _
         (ByVal hObject As Long) As Long

      Private Declare Function GetExitCodeProcess Lib "kernel32" _
         (ByVal hProcess As Long, lpExitCode As Long) As Long

      Private Const NORMAL_PRIORITY_CLASS = &H20&
      Private Const INFINITE = -1&
      Private Const WAIT_TIMEOUT& = &H102&
    Private Const WAIT_ABANDONED& = &H80&
    Private Const WAIT_ABANDONED_0& = &H80&
    Private Const WAIT_FAILED& = -1&
    Private Const WAIT_IO_COMPLETION& = &HC0&
    Private Const WAIT_OBJECT_0& = 0


Public Function ExecCmd2(cmdline$)
    Dim proc As PROCESS_INFORMATION
    Dim start As STARTUPINFO
    Dim ret As Long
   
    On Error GoTo errExit
   
    ' Initialize the STARTUPINFO structure:
    start.cb = Len(start)
   
    ' Start the shelled application:
    ret = CreateProcessA(0&, cmdline$, 0&, 0&, 1&, _
    NORMAL_PRIORITY_CLASS, 0&, 0&, start, proc)
   
    ' Wait for the shelled application to finish:
    ret = WaitForSingleObject(proc.hProcess, 100)
    Do While ret = WAIT_TIMEOUT
        DoEvents
        ret = WaitForSingleObject(proc.hProcess, 100)
    Loop
   
    Call CloseHandle(proc.hProcess)
    ExecCmd2 = ret&
    Exit Function
errExit:

   
End Function
0
 
LVL 39

Author Comment

by:appari
Comment Utility
TimCottee,
i tried with redraw API but it was not working.

PaulHews,
Doevents also not working and once we change the 2 nd parameter WaitForSingleObject(proc.hProcess, 100) to any value other than INFINITE we can go back to the original calling application.

any other solution?

RAO




   
0
Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

 
LVL 39

Author Comment

by:appari
Comment Utility
hi experts,
if you are not missing the other problem specified in my question,

"Second problem is if i click on any of the buttons on the form in Main EXE all these click events are
fired in the same sequence after closing second EXE."

why this is happening?

Rao
0
 
LVL 38

Expert Comment

by:PaulHews
Comment Utility
>>
Doevents also not working and once we change the 2 nd parameter WaitForSingleObject(proc.hProcess, 100)
to any value other than INFINITE we can go back to the original calling application.

any other solution?
<<

Have you tried my code?  The reason the second parameter is not set to INFINITE is because we *want* the program to return control to the calling program, otherwise it will never repaint, no matter what messages you send it.  Setting it to 100, means the function times out after 100 ms.  When this happens, the return value is WAIT_TIMEOUT, so we loop using WaitForSingleObject again, until it no longer times out.  This allows your program to respond to events while the other program is executing.  After it no longer times out, ExecCmd2 can exit returning control to the calling sub.  If you need to disable the gui so that the user can't fool with it while the second program is shelled, then just use frmMain.Enabled = False.  The second program will appear to be modal and you set it true again after.

The second problem is caused by not disabling the GUI using the method I suggested (disabling form.)  The program still queues messages from the mouse, even tho' no code is being executed.  Then when it is responsive again, you get all the queued events.  Disable the form, and the events are discarded.  Use ExecCmd2 and your main form can repaint.
0
 
LVL 38

Accepted Solution

by:
PaulHews earned 75 total points
Comment Utility
Complete example fully tested:

Option Explicit


     Private Type STARTUPINFO
        cb As Long
        lpReserved As String
        lpDesktop As String
        lpTitle As String
        dwX As Long
        dwY As Long
        dwXSize As Long
        dwYSize As Long
        dwXCountChars As Long
        dwYCountChars As Long
        dwFillAttribute As Long
        dwFlags As Long
        wShowWindow As Integer
        cbReserved2 As Integer
        lpReserved2 As Long
        hStdInput As Long
        hStdOutput As Long
        hStdError As Long
     End Type

     Private Type PROCESS_INFORMATION
        hProcess As Long
        hThread As Long
        dwProcessID As Long
        dwThreadID As Long
     End Type

     Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal _
        hHandle As Long, ByVal dwMilliseconds As Long) As Long

     Private Declare Function CreateProcessA Lib "kernel32" (ByVal _
        lpApplicationName As Long, ByVal lpCommandLine As String, ByVal _
        lpProcessAttributes As Long, ByVal lpThreadAttributes As Long, _
        ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, _
        ByVal lpEnvironment As Long, ByVal lpCurrentDirectory As Long, _
        lpStartupInfo As STARTUPINFO, lpProcessInformation As _
        PROCESS_INFORMATION) As Long

     Private Declare Function CloseHandle Lib "kernel32" _
        (ByVal hObject As Long) As Long

     Private Declare Function GetExitCodeProcess Lib "kernel32" _
        (ByVal hProcess As Long, lpExitCode As Long) As Long

     Private Const NORMAL_PRIORITY_CLASS = &H20&
     Private Const INFINITE = -1&
     Private Const WAIT_TIMEOUT& = &H102&
   Private Const WAIT_ABANDONED& = &H80&
   Private Const WAIT_ABANDONED_0& = &H80&
   Private Const WAIT_FAILED& = -1&
   Private Const WAIT_IO_COMPLETION& = &HC0&
   Private Const WAIT_OBJECT_0& = 0


Public Function ExecCmd2(cmdline$)
   Dim proc As PROCESS_INFORMATION
   Dim start As STARTUPINFO
   Dim ret As Long
   
   On Error GoTo errExit
   
   ' Initialize the STARTUPINFO structure:
   start.cb = Len(start)
   
   ' Start the shelled application:
   ret = CreateProcessA(0&, cmdline$, 0&, 0&, 1&, _
   NORMAL_PRIORITY_CLASS, 0&, 0&, start, proc)
   
   ' Wait for the shelled application to finish:
   ret = WaitForSingleObject(proc.hProcess, 100)
   Do While ret = WAIT_TIMEOUT
       DoEvents
       ret = WaitForSingleObject(proc.hProcess, 100)
   Loop
   
   Call CloseHandle(proc.hProcess)
   ExecCmd2 = ret&
   Exit Function
errExit:

   
End Function

Private Sub Command1_Click()
Me.Enabled = False
ExecCmd2 "notepad"
Me.Enabled = True

End Sub

Private Sub Command2_Click()
    MsgBox "Hi"
End Sub
0
 
LVL 39

Author Comment

by:appari
Comment Utility
PaulHews,
thank you for your help.
this works fine for application with one form or the calling form is displayed as modal. but in case if the 1 st application have MDI form and we are calling the 2 nd application from a MDI Child then i need to disable all the forms opened so far including MDI Form. otherwise i can click on toolbars or menus available in MDI. And moreover if i click on any window displayed by the 1 st application that window gets focus and the second application goes behind. so its behaviour is not same as a modal window.

any other idea?

Rao

0
 
LVL 43

Expert Comment

by:TimCottee
Comment Utility
Lunchy, shouldn't you be posting under your real name?
0
 
LVL 2

Expert Comment

by:Lunchy
Comment Utility
Thanks Tim, I deleted my previous comment.  If appari found it useful, good.  Otherwise ignore.  I slipped up and thought I was in my expert identity.
0
 
LVL 43

Expert Comment

by:TimCottee
Comment Utility
Just didn't want you to "out" yourself inadvertently by returning under your real name.
0
 
LVL 2

Expert Comment

by:Lunchy
Comment Utility
I appreciate that thought, Tim.  8*)
0
 
LVL 12

Expert Comment

by:guidway
Comment Utility
This question appears to have been abandoned. A Moderator will be asked
to close this question after seven days, with the following recommended disposition:

PAQ/refund points

If you have any comment or objection to the recommendation, please leave
it here.

guidway
EE Cleanup Volunteer
0
 
LVL 5

Expert Comment

by:Netminder
Comment Utility
Force-accepted.

Netminder
CS Moderator
0

Featured Post

Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

Join & Write a Comment

Introduction While answering a recent question (http://www.experts-exchange.com/Q_27402310.html) in the VB classic zone, I wrote some VB code in the (Office) VBA environment, rather than fire up my older PC.  I didn't post completely correct code o…
If you have ever used Microsoft Word then you know that it has a good spell checker and it may have occurred to you that the ability to check spelling might be a nice piece of functionality to add to certain applications of yours. Well the code that…
Get people started with the process of using Access VBA to control Outlook using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Microsoft Outlook. Using automation, an Access applic…
Get people started with the process of using Access VBA to control Excel using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Excel. Using automation, an Access application can laun…

763 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

6 Experts available now in Live!

Get 1:1 Help Now