Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Start external .exe from Vfp .exe

Status
Not open for further replies.

thetempuser

Programmer
Jan 14, 2013
10
0
0
RO
Hi,

I am using Vfp 8 on a Windows XP.

My goal is to create a VFP .exe that can start an external .exe. This external .exe (among other executables) will be located in the \plugins subfolder, in the folder of my VFP .exe.

VFP .exe location : C:\Test
External .exe location :C:\Test\plugins\create.exe

I tried this approach: an array with all the files from \plugins folder, loaded in a listbox on a form:

form.init

Code:
SET DATE TO dmy
PUBLIC plugpath
plugpath=Sys(5)+Sys(2003) &&gets current path
PUBLIC array MyFiles[1,5]
nFilesFound = ADIR( MyFiles, plugpath+"\plugins\*.exe","S",1)

On the properties windows of the listbox:

colomncount=ALEN(MyFiles,2)
numberofelements=ALEN(MyFiles)
rowsource=MyFiles
rowsourcetype=5

The first problem appears when I run the form. It loads the files list in the listbox, but only the names, not the size, and the date. If I close the form and re-launch it, the whole information shown, name.exe, size and date. If I close VFP and open it, the same problem. The info is shown only after a second launch.

Now, the second problem is the way I launch the external exe.
The user double clicks on one of the exe from the listbox.
listbox1.dblclick
Code:
a = ALLTRIM(thisform.list1.DisplayValue) 
DECLARE INTEGER ShellExecute IN shell32.dll ; 
  INTEGER hndWin, ; 
  STRING cAction, ; 
  STRING cFileName, ; 
  STRING cParams, ;  
  STRING cDir, ; 
  INTEGER nShowWin
cFileName = a 
cAction = "open" 
ShellExecute(0,cAction,cFileName,"","",1)
This code works if I run the form from VFP. If I build the VFP .exe it doesn't work. Nothing happens if I double click an .exe from the listbox.

It works if I use this code:
listbox1.dblclick

Code:
a = plugpath+"\plugins\"+ALLTRIM(thisform.list1.DisplayValue)
run_command = [RUN /N]+a
&run_command

Thank you for your help.
 
1. listbow.columnwidths must be set to display multiple columns, not only columncount
2. Well, as you did with RUN, set cFileName to the full file name:

Code:
a = ALLTRIM(thisform.list1.DisplayValue) 
DECLARE INTEGER ShellExecute IN shell32.dll ; 
  INTEGER hndWin, ; 
  STRING cAction, ; 
  STRING cFileName, ; 
  STRING cParams, ;  
  STRING cDir, ; 
  INTEGER nShowWin
cFileName = plugpath+"\plugins\"+a 
cAction = "open" 
ShellExecute(0,cAction,cFileName,"","",1)

ShellExecute won't know the VFP current path, so it won't find just ALLTRIM(thisform.list1.DisplayValue). ShellExeecute also returns a vlaue, which can be an error, so check the returnvalue, too:

Code:
lnRetVal = ShellExecute(0,cAction,cFileName,"","",1)
If lnRetVal<=32
   Messagebox("failed to call "+a)
Endif

See the Return Value section of Error constant names are also listed there. The values of these constants is defined in Shellapi.h, which you only will have, if you have a msdn library installed. But you can also find such header files in Wine repositories, eg at lines 264 to 274.

Bye, Olaf.
 
I'll just add that it's better not to use a public array for the listbox. Subclass the listbox class and add an array property and use that. Or add an array property to the form and use that. Subclassing the listbox is the better way.

Tamar
 
Thank you both for your help.
There were already values to the columncount
.columncount=215,80,85,120,110
I found that adding on form.init
Code:
thisform.list1.ColumnCount=ALEN(MyFiles,2)
fixes my problem.

Your suggestion did the trick:
Code:
cFileName =plugpath+"\plugins\"+ALLTRIM(thisform.list1.DisplayValue)


Tamar, your approach intrigues me, but unfortunnetly I am not such an advanced programmer (always eager to learn).
If you could point me to an example, I have never created a subclass.


Should I use a property (like .T. or .F.) or add a new method so that I could write code into?


Thank you.








 
Well, ALEN(MyFiles,2) is always 5, as that is the number of columns ADIR creates in it's output array, also your columnwidth setting is having the five widths 215,80,85,120,and 110. So simply set ColumnCount = 5, when columnwidths has 5 widths.

Tamar talks of an array property, which mainly is a property, not a method. The difference in adding an array property to a normal property is, that you include the number of elements to the property name. So use "New Property" from the Class menu, and as the name enter MyArray[2,5] instead of a name like MyProperty.

Merely adding the [2,5] makes it a 2-dimensional array property, dimensioned to 2 rows with 5 columns.

Also try this:

Code:
_screen.addproperty("myFiles[1]")
ADir(_screen.myFiles)

This demonstrates 1. how you add an array to the _screen (which also is a form) with code and 2. how it's not necessary to set it to the right dimensions, ADIR does redimention and fill that array with file info.

Do this with THISFORM instead of screen, and you can set your rowsource to Thisform.myFiles.

Tamar's intention witht his is, to limit the scope of the array. Why is that so important? Imagine you would want to display contents of two directories in two identical forms. You could simply reuse your code, set plugpath to another directory and the MyFiles array would then contain the files from that directory. Fine, almost, as the ADIR creates the same array, both of your form will display the new directory, as you don't have two seperate arrays.

Making the array a property of the form, means changing the scope of the array to the form. You can start a form twice, the array name within each of the two forms is identical (thisfrom.myfiles), but it's two seperate forms and therefore two seperate arrays and they don't influence each other.

Now take this one step further and see what it would do, if you put two listboxes for file listing into one form, then the scope of the array as form property would again make it only one array for both listboxes. Therefore the best scope for the array is to be a property of the listbox.

Keep things close together, which belong close together.

You also don't spill milk for your cornflakes into the kitchen or onto the kitchen table, but into the cornflakes* bowl on the kitchen table in the kitchen.

Bye, Olaf.
 
To create a subclass, in the Command Window, type:

CREATE CLASS

A dialog appears. You specify the name of your new class, what class it's based on, and where to store it. Then, the Class Designer opens. Rather than recreate it, I'll point you to the "Class Designer" topic in Help. Follow the links there.

You'll also want to read "How to: Add Properties to Classes"

To learn more about combos and listboxes, try my article:
Tamar
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top