Solved

Urgent!!!!!  External Command completion Notification

Posted on 2003-11-21
13
753 Views
Last Modified: 2008-02-01
Hi,

I am running a external command "PKZIP" to zip some files that is dumped at some perticuar location. PKZIP is fired from a Times event using "Shell" command.

Following is the method called from Timer event
***************
Public Sub AddFile(sZipFileName As String, sFileName As String)
    Dim iVal as long
    iVal = Shell("pkzip " & sZipFileName & " " & sFileName, vbHide)
    DoEvents
    Dim i As Long, j As Long
    For i = 0 To 100000
        j = i
        DoEvents
    Next
End Sub
*************

What I have found that, if do not use loop of i=- to 100000 then the zip is not created ot updated. But I do not want to use the loop to adjust the time to allow PKZIP to complete it's task.

I want the Timer to wait till the PKZIP finishes it's task.

In other words, How can I come to know the task of PKZIP or any other external command is completed and with success/fail status.

One more thing, Even though the loop is there, some files are also missed from zipping. THis happens even when I have just VB only opened after restarting.

I seen help of ShellExecute, but i do not think it will solve the purpose.

Very difficult!!!!!
but sure u guys will help me.


Thx
Anand



0
Comment
Question by:anand2k
  • 5
  • 2
  • 2
  • +3
13 Comments
 
LVL 43

Expert Comment

by:TimCottee
ID: 9796028
Hi anand2k,

You need to use the following method:

'This program needs a common dialog box, named CDBox
'  (To add the Common Dialog Box to your tools menu, go to Project->Components (or press CTRL-T)
'   and select Microsoft Common Dialog control)
Const INFINITE = &HFFFF
Const STARTF_USESHOWWINDOW = &H1
Private Enum enSW
    SW_HIDE = 0
    SW_NORMAL = 1
    SW_MAXIMIZE = 3
    SW_MINIMIZE = 6
End Enum
Private Type PROCESS_INFORMATION
    hProcess As Long
    hThread As Long
    dwProcessId As Long
    dwThreadId As Long
End Type
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 Byte
    hStdInput As Long
    hStdOutput As Long
    hStdError As Long
End Type
Private Type SECURITY_ATTRIBUTES
    nLength As Long
    lpSecurityDescriptor As Long
    bInheritHandle As Long
End Type
Private Enum enPriority_Class
    NORMAL_PRIORITY_CLASS = &H20
    IDLE_PRIORITY_CLASS = &H40
    HIGH_PRIORITY_CLASS = &H80
End Enum
Private Declare Function CreateProcess Lib "kernel32" Alias "CreateProcessA" (ByVal lpApplicationName As String, ByVal lpCommandLine As String, lpProcessAttributes As SECURITY_ATTRIBUTES, lpThreadAttributes As SECURITY_ATTRIBUTES, ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, lpEnvironment As Any, ByVal lpCurrentDriectory As String, lpStartupInfo As STARTUPINFO, lpProcessInformation As PROCESS_INFORMATION) As Long
Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
Private Function SuperShell(ByVal App As String, ByVal WorkDir As String, dwMilliseconds As Long, ByVal start_size As enSW, ByVal Priority_Class As enPriority_Class) As Boolean
    Dim pclass As Long
    Dim sinfo As STARTUPINFO
    Dim pinfo As PROCESS_INFORMATION
    'Not used, but needed
    Dim sec1 As SECURITY_ATTRIBUTES
    Dim sec2 As SECURITY_ATTRIBUTES
    'Set the structure size
    sec1.nLength = Len(sec1)
    sec2.nLength = Len(sec2)
    sinfo.cb = Len(sinfo)
    'Set the flags
    sinfo.dwFlags = STARTF_USESHOWWINDOW
    'Set the window's startup position
    sinfo.wShowWindow = start_size
    'Set the priority class
    pclass = Priority_Class
    'Start the program
    If CreateProcess(vbNullString, App, sec1, sec2, False, pclass, _
    0&, WorkDir, sinfo, pinfo) Then
        'Wait
        WaitForSingleObject pinfo.hProcess, dwMilliseconds
        SuperShell = True
    Else
        SuperShell = False
    End If
End Function
Private Sub Form_Load()
    Dim strApplication As String
    Dim strAppDir As String
    strAppDir = App.Path 'Or wherever the work folder is for the application
    strApplication = "pkzip MyZipFile.zip myFiletoAdd.txt"
    SuperShell strApplication, strAppDir, 0, SW_NORMAL, HIGH_PRIORITY_CLASS
    End
End Sub

You need to fiddle with the path and application strings but in principle this is exactly what you want. The application is launched and VB will wait until it is completed before continuing.


Tim Cottee MCSD, MCDBA, CPIM
Brainbench MVP for Visual Basic
http://www.brainbench.com
0
 
LVL 1

Author Comment

by:anand2k
ID: 9796089
Hi Tim,

Thx 4 super express response,

But, I am getting following error dialog box with 2 buttons - CLose and Ignore. The heading of Dialog is '16 bit MS-DOS Subsystem'.

"d:\MyApp\pkzip.exe
%SystemRoot%\System32\CONFIG.NT The system file is not suitable for running MS-DOS and Microsoft Windows applications. Choose 'Close' to terminate the application"

And whatever I press nothing happens.

And I do not want these kind of User Interaction while zipping like VBhide of 'Shell' works.!!!!

Thx
Anand
0
 
LVL 1

Author Comment

by:anand2k
ID: 9796100
Tim, This might help u,

I m running on Win2K Professionl with PIII 500 MHz machine with 196 MB Ram.

Thx
Anand
0
 
LVL 43

Expert Comment

by:TimCottee
ID: 9796141
If you are zipping files then you might like to consider an alternative approach:

http://codeguru.earthweb.com/vb/articles/1854.shtml

Shows how you can use the infozip libraries to zip and unzip from VB without having to shell out to a seperate process.
0
 
LVL 1

Author Comment

by:anand2k
ID: 9796307

THx for the help.   The utelity u suggested is amazing and works compatible with Winzip.    ..... THx.

But Tim, after testing it i found that , I can not unzip any perticular file as a single file.

After reading the coments below it, i found that there is some problem with Bigger files and the no of files to be zipped in a single file is limited to around 100-110 file only.

If u have used this utelity before, then pls advice me how to achive it.

THx
Anand
0
 
LVL 4

Expert Comment

by:bhermer
ID: 9796663
If you look at this link it will show you how to 'Shell and wait' this will allow your program to stop execution until the pkzip has finished execution.

http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=8349&lngWId=1

Here is another exampl of 'shell and wait' using API's

http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=6071&lngWId=1

Hope this helps

Ben
0
What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 9797329
If your PKZip is an old 16 bit version, you may have to use this method:

http://support.microsoft.com/default.aspx?scid=kb;EN-US;96844

Idle_Mind
0
 
LVL 2

Expert Comment

by:eagle1357
ID: 9798186
Here is something I found a while back that I use all the time. I don't remember where I got it from, but it works a lot better than the Tasks thing I had to use in Word. Paste the below code and use a loop in your code to pause the execution of code like so:

    Const strProcess as String = "pkzip.exe"

    'First wait for the program to run
    Do While Not ProcessRunning(strProcess)
        DoEvents
    Loop
   
    'Now wait for it to finish
    Do While ProcessRunning(strProcess)
        DoEvents
    Loop



***********Begin copy/paste*********
''The following code is copied from the Microsoft Support web site.
''All it does is check to see if a program is running or not.

Public Declare Function Process32First Lib "kernel32" ( _
   ByVal hSnapshot As Long, lppe As PROCESSENTRY32) As Long

Public Declare Function Process32Next Lib "kernel32" ( _
   ByVal hSnapshot As Long, lppe As PROCESSENTRY32) As Long

Public Declare Function CloseHandle Lib "Kernel32.dll" _
   (ByVal Handle As Long) As Long

Public Declare Function OpenProcess Lib "Kernel32.dll" _
  (ByVal dwDesiredAccessas As Long, ByVal bInheritHandle As Long, _
      ByVal dwProcId As Long) As Long

Public Declare Function EnumProcesses Lib "psapi.dll" _
   (ByRef lpidProcess As Long, ByVal cb As Long, _
      ByRef cbNeeded As Long) As Long

Public Declare Function GetModuleFileNameExA Lib "psapi.dll" _
   (ByVal hProcess As Long, ByVal hModule As Long, _
      ByVal ModuleName As String, ByVal nSize As Long) As Long

Public Declare Function EnumProcessModules Lib "psapi.dll" _
   (ByVal hProcess As Long, ByRef lphModule As Long, _
      ByVal cb As Long, ByRef cbNeeded As Long) As Long

Public Declare Function CreateToolhelp32Snapshot Lib "kernel32" ( _
   ByVal dwFlags As Long, ByVal th32ProcessID As Long) As Long

Public Declare Function GetVersionExA Lib "kernel32" _
   (lpVersionInformation As OSVERSIONINFO) As Integer

Public Type PROCESSENTRY32
   dwSize As Long
   cntUsage As Long
   th32ProcessID As Long           ' This process
   th32DefaultHeapID As Long
   th32ModuleID As Long            ' Associated exe
   cntThreads As Long
   th32ParentProcessID As Long     ' This process's parent process
   pcPriClassBase As Long          ' Base priority of process threads
   dwFlags As Long
   szExeFile As String * 260       ' MAX_PATH
End Type

Public Type OSVERSIONINFO
   dwOSVersionInfoSize As Long
   dwMajorVersion As Long
   dwMinorVersion As Long
   dwBuildNumber As Long
   dwPlatformId As Long           '1 = Windows 95.
                                  '2 = Windows NT

   szCSDVersion As String * 128
End Type

Public Const PROCESS_QUERY_INFORMATION = 1024
Public Const PROCESS_VM_READ = 16
Public Const MAX_PATH = 260
Public Const STANDARD_RIGHTS_REQUIRED = &HF0000
Public Const SYNCHRONIZE = &H100000
'STANDARD_RIGHTS_REQUIRED Or SYNCHRONIZE Or &HFFF
Public Const PROCESS_ALL_ACCESS = &H1F0FFF
Public Const TH32CS_SNAPPROCESS = &H2&
Public Const hNull = 0

Function StrZToStr(s As String) As String
   StrZToStr = Left$(s, Len(s) - 1)
End Function

Public Function getVersion() As Long
   Dim osinfo As OSVERSIONINFO
   Dim retvalue As Integer
   osinfo.dwOSVersionInfoSize = 148
   osinfo.szCSDVersion = Space$(128)
   retvalue = GetVersionExA(osinfo)
   getVersion = osinfo.dwPlatformId
End Function

Public Function ProcessRunning(FileName As String) As Boolean
   ProcessRunning = False
   Select Case getVersion()
   
   Case 1 'Windows 95/98
       
       Dim f As Long, sname As String
       Dim hSnap As Long, proc As PROCESSENTRY32
       
       hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
       If hSnap = hNull Then Exit Function
       
       proc.dwSize = Len(proc)
       ' Iterate through the processes
       f = Process32First(hSnap, proc)
       Do While f
           sname = StrZToStr(proc.szExeFile)
           If (InStr(1, sname, FileName) > 0) Then
               ProcessRunning = True
               Exit Function
           End If
           f = Process32Next(hSnap, proc)
       Loop
   
   Case 2 'Windows NT
   
       Dim cb As Long
       Dim cbNeeded As Long
       Dim NumElements As Long
       Dim ProcessIDs() As Long
       Dim cbNeeded2 As Long
       Dim NumElements2 As Long
       Dim Modules(1 To 200) As Long
       Dim lRet As Long
       Dim ModuleName As String
       Dim nSize As Long
       Dim hProcess As Long
       Dim i As Long
       
       'Get the array containing the process id's for each process object
       cb = 8
       cbNeeded = 96
       
       Do While cb <= cbNeeded
           cb = cb * 2
           ReDim ProcessIDs(cb / 4) As Long
           lRet = EnumProcesses(ProcessIDs(1), cb, cbNeeded)
       Loop
       
       NumElements = cbNeeded / 4
       
       For i = 1 To NumElements
           'Get a handle to the Process
           hProcess = OpenProcess(PROCESS_QUERY_INFORMATION _
                                   Or PROCESS_VM_READ, 0, ProcessIDs(i))
           'Got a Process handle
           If hProcess <> 0 Then
               'Get an array of the module handles for the specified
               'process
               lRet = EnumProcessModules(hProcess, Modules(1), 200, _
               cbNeeded2)
               'If the Module Array is retrieved, Get the ModuleFileName
               If lRet <> 0 Then
                   ModuleName = Space(MAX_PATH)
                   nSize = 500
                   lRet = GetModuleFileNameExA(hProcess, Modules(1), _
                   ModuleName, nSize)
                   If (InStr(1, Left(ModuleName, lRet), FileName) > 0) Then
                       ProcessRunning = True
                       Exit Function
                   End If
               End If
           End If
           'Close the handle to the process
           lRet = CloseHandle(hProcess)
       Next
       
   End Select
End Function
0
 
LVL 2

Expert Comment

by:eagle1357
ID: 9798201
Oh, I'd paste it into its own module.
0
 
LVL 1

Author Comment

by:anand2k
ID: 9817159
HI

Sorry for delay in response!
I tried with all the 3 Friends information eagle1357,Idle_Mind,bhermer.
Comments below.


eagle1357,
------------------------
I tried ur code but many times, but it is not working.
First of all, I changed
from
  Const strProcess as String = "pkzip.exe"
to
  dim strProcess as String
  strProcess = "pkzip.exe myZip.zip anand.txt"

because This is what i needed. And On line
If (InStr(1, Left(ModuleName, lRet), FileName) > 0) Then
i changed FileName to strProcess or "pkzip.exe" but it is not working.
And add to that, I did not find the process named "pkzip.exe" in process enum.

Might be pkzip is 16 bit version and the process enum is not detecting 16 bit processes.
Your openion are expected.


Idle_Mind,
------------------------
I read ur URl from Microsoft.
When I tried to use API declaration

Private Declare Function GetModuleUsage% Lib "Kernel" (ByVal hModule%)

But problem is that, Kernal file is not found on Windows 98/2000/NT machines.
I think It is just for 16 bit programs like Win 3.1 (The only Prog I know)

Would pls guide me how to use it in 32 Bit windows program.
I m using 16 bit pkzip.exe to zip the files from VB 6 with SP5.


bhermer,
----------------------------
I tried ur both URL's examples.
For first with Windows Script, It did not run with me, on development machine.
Second one with fWait function works very fine with me on Win2K machine i.e. on all NT Platform machines, but failed to run on Win98/95 machines.
    I found that it did not get 'GetExitCodeProcess' ID.

Any suggestion on Win98/95 machines. We are very near to solution,  


---------------------

Very big reply

Together we can do it, Yes!!!!

THx
Anand




0
 
LVL 1

Author Comment

by:anand2k
ID: 9817245

friends,

I am basically confused for, If shell command runs the application asynchronously with VB then why I have to wait till that application finished.
Ref - http://support.microsoft.com/default.aspx?scid=kb;EN-US;96844 (Summary Paragraph)

I my case, I have continuously created images are dumped in one specific folder (approx one BMP per 2 sec) and I have to zip in a single file. I have used timer (with Interval set to 2000 miliSec) to look for any image added and call Zipping.

Any ideas why I needed to wait till pkzip finishes else the zip file is not created or updtaed.

Any comments/suggestions/guidlines/ref urls  

PLs PLs

ANAND
0
 

Accepted Solution

by:
SpazMODic earned 0 total points
ID: 9878252
PAQed, with points refunded (100)

SpazMODic
EE Moderator
0

Featured Post

Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

The debugging module of the VB 6 IDE can be accessed by way of the Debug menu item. That menu item can normally be found in the IDE's main menu line as shown in this picture.   There is also a companion Debug Toolbar that looks like the followin…
When designing a form there are several BorderStyles to choose from, all of which can be classified as either 'Fixed' or 'Sizable' and I'd guess that 'Fixed Single' or one of the other fixed types is the most popular choice. I assume it's the most p…
As developers, we are not limited to the functions provided by the VBA language. In addition, we can call the functions that are part of the Windows operating system. These functions are part of the Windows API (Application Programming Interface). U…
This lesson covers basic error handling code in Microsoft Excel using VBA. This is the first lesson in a 3-part series that uses code to loop through an Excel spreadsheet in VBA and then fix errors, taking advantage of error handling code. This l…

743 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

11 Experts available now in Live!

Get 1:1 Help Now