Another Handy VB Port

| | Comments (4)

It's been a while since I've done an RB Gem, so here's one for you. In VB, there's a built-in function called Shell which launches a command line process and then returns a process identifier for you to use. A lot of times this is used in conjunction with the AppActivate to bring the app to the front, and the SendKeys to modify the application.

Now you may be thinking "why can't I just use the Shell class in REALbasic?" You're absolutely correct, you can use that. But if you're porting your VB app over to RB, then you may not want to go thru the hassle of the Shell class when the only purpose is to launch an application.[rbcode]
Protected Function Shell(pathname as String, style as Integer = 1) As Integer
// We want to launch the application given by the path name, and
// we need to return the application's PID if the launch was successful
#if TargetWin32
Soft Declare Function CreateProcessW Lib "Kernel32" ( appName as Integer, params as WString, _
procAttribs as Integer, threadAttribs as Integer, inheritHandles as Boolean, flags as Integer, _
env as Integer, curDir as Integer, startupInfo as Ptr, procInfo as Ptr ) as Boolean

Soft Declare Function CreateProcessA Lib "Kernel32" ( appName as Integer, params as CString, _
procAttribs as Integer, threadAttribs as Integer, inheritHandles as Boolean, flags as Integer, _
env as Integer, curDir as Integer, startupInfo as Ptr, procInfo as Ptr ) as Boolean

dim startupInfo, procInfo as MemoryBlock

startupInfo = new MemoryBlock( 17 * 4 )
procInfo = new MemoryBlock( 16 )

dim unicodeSavvy as Boolean = System.IsFunctionAvailable( "CreateProcessW", "Kernel32" )

startupInfo.Long( 0 ) = startupInfo.Size

// Create the application
dim ret as Boolean
if unicodeSavvy then
ret = CreateProcessW( 0, pathname, 0, 0, false, 0, 0, 0, startupInfo, procInfo )
else
ret = CreateProcessA( 0, pathname, 0, 0, false, 0, 0, 0, startupInfo, procInfo )
end if

// If we couldn't make it, then we're stuck
if not ret then return 0

// We want to return the process identifier for the application
dim retVal as Integer = procInfo.Long( 8 )

// We should wait for the input idle so that we can switch to the app
Declare Function WaitForInputIdle Lib "User32" ( handle as Integer, wait as Integer ) as Integer
dim wait as Integer = WaitForInputIdle( procInfo.Long( 0 ), 2500 )

// Clean the application up
Declare Sub CloseHandle Lib "Kernel32" ( handle as Integer )
CloseHandle( procInfo.Long( 0 ) )
CloseHandle( procInfo.Long( 4 ) )

return retVal
#endif
End Function[/rbcode]
The really neat part of this is the call to WaitForInputIdle. What this handy API does is wait for the application to finish launching before returning control back to you (or 2500 milliseconds to pass, whichever happens first). So if you have an application which has a non-negligible startup time, then this will wait for it to finish starting up before returning back to you. It makes it ideal for passing the PID off to AppActivate to bring it to the front, or use SendKeys to control the application.

4 Comments

Cool, I didn't know that you could pass the pID to AppActivate. After some reading on some of the VB6 Discussion sites I see that you're right. Wish I had known that back when I was using SendKeys.

Great tip, Aaron. Thanks a bunch.

Welcome! Trying to think of other tips to put in. :-P

Nice!
One question: what is "style as integer = 1" doing? It seems is never used on the function ;)

It's there because VB declares an optional style parameter. I've yet to really figure out what it is supposed to be used for, but I put it in so that people porting VB code can do so without getting compile errors.

Leave a comment

Disclaimer

I'm currently an employee of REAL Software. My blog is mine. The opinions represented in this blog are mine as well and may not represent my employer's opinions. All original material is copyrighted and property of the author.

REALbasic® is a registered trademark of REAL Software, Inc. REAL SQL Server™ and Lingua™ are pending trademarks of REAL Software, Inc. All rights reserved.