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 Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

FoxPro 9.0 - Build .exe 1

Status
Not open for further replies.

MajklPan

Programmer
Jan 11, 2023
74
CZ
Hi,
I don't know how to correctly create the installation file of the project, because if I create only an exe file (see picture) and replace it in the project, it no longer works correctly.
1_neotor.png


How should I create an installation file so that the user can just install the program and it works?

I tried this procedure and it doesn't work, I just keep getting a pjx file (picture 2)
2_jjm6gv.png

In FoxPro, you can create an installation file using the "Setup Wizard" or "Save As" tool.

1.Launch the FoxPro program.
2.From the main menu, select "File" and then "Save As".
3.Choose "Setup" as the file type.
4.Enter a name for the installation file and the location where you want to save it.
5.Click on the "Save" button and then the "Setup Wizard" window will appear or the saving process will begin.
In the Setup Wizard, click on the "Next" button and select the files that you want to include in the installation file.
6.Click on the "Next" button and set up the installation options, such as the target folder or installation preferences.
7.Click on the "Next" button and create informational pages that will be displayed during the installation.
8. Click on the "Finish" button to create the installation file.
Note: It's important that you have write access to the location where you want to save the installation file.

This guide explains how to create an installation file in FoxPro that includes all necessary files, settings, and instructions for installation.

thank you for the advice
 
Hi,

The MESSAGEBOX(SYS(5)+SYS(2003)) isn't of any value here. It simply shows the drive and the path

You may want to add a simple ERROR handler to your main program SPOUSTECI_PROGRAM e.g. (from the Help file) and see which errors are thrown.

Code:
ON ERROR DO errHandler WITH ;

   ERROR( ), MESSAGE( ), MESSAGE(1), PROGRAM( ), LINENO( )

USE nodatabase  

ON ERROR  && Restores system error handler.



PROCEDURE errHandler

   PARAMETER merror, mess, mess1, mprog, mlineno

   CLEAR

   ? 'Error number: ' + LTRIM(STR(merror))

   ? 'Error message: ' + mess

   ? 'Line of code with error: ' + mess1

   ? 'Line number of error: ' + LTRIM(STR(mlineno))

   ? 'Program with error: ' + mprog

ENDPROC

hth

MarK
 
Hi,
sorry, I'm an amateur in this RDBMS.
In which part of the code in "spousteci_program.prg" should I insert this code?
I put in 2 parts and it says syntax error.

Thanks for the advice [upsidedown]
 
Hi,

You may want to put both parts before the PUBLIC statement. You have to remove of course the statement USE nodatabase. Sorry for misleading you

Code:
ON ERROR DO errHandler WITH ;

   ERROR( ), MESSAGE( ), MESSAGE(1), PROGRAM( ), LINENO( )

ON ERROR  && Restores system error handler.



PROCEDURE errHandler

   PARAMETER merror, mess, mess1, mprog, mlineno

   CLEAR

   ? 'Error number: ' + LTRIM(STR(merror))

   ? 'Error message: ' + mess

   ? 'Line of code with error: ' + mess1

   ? 'Line number of error: ' + LTRIM(STR(mlineno))

   ? 'Program with error: ' + mprog

ENDPROC

hth

MarK
 
I'm probably doing something wrong because it keeps throwing me a syntax error.
I pasted it here:
Sn%C3%ADmek_obrazovky_2023-01-24_115650_aqgvos.png



The ON ERROR DO errHandler WITH; ERROR( ), MESSAGE( ), MESSAGE(1), PROGRAM( ), LINENO( ) statement is a command in the FoxPro programming language that sets an error handler for the entire program. This statement sets that if an error occurs in the program, instead of the program ending, the "errHandler" procedure will be run with the parameters listed after the WITH. These parameters contain information about the error that occurred.

The PROCEDURE errHandler is a procedure that runs when an error occurs in the program. This procedure has several parameters: "merror", "mess", "mess1", "mprog" and "mlineno" which contain information about the error that occurred.

In this procedure, several actions are performed:

"CLEAR" clears all errors
Using the "?" command, information about the error is displayed: error number, error message, line of code with error, line number of error and program where the error occurred
ENDPROC ends the procedure
This code serves to record information about the error that occurred in the program, and thus helps in debugging and fixing errors.
 
Hi,

Delete the empty line

ON ERROR DO errHandler WITH ;
ERROR( ), MESSAGE( ), MESSAGE(1), PROGRAM( ), LINENO( )

hth

MarK
 
Okay, I'll try.
Logically, I would implement this code like this:
ssss_tyhydv.png

Unfortunately, that doesn't work either.
thank you for your patience
 
If I removed the space, the syntax error went away, but the program didn't run, it just compiled.
It immediately gave me a lot of errors.
Sn%C3%ADmek_obrazovky_2023-01-24_124142_n4rbxq.png
 
Hi,

That should work. However make sure that there is no empty line between

... WITH ;
ERROR(), ...​


hth

MarK
 
The MESSAGEBOX(SYS(5)+SYS(2003)) isn't of any value here. It simply shows the drive and the path

Mark,

That's correct. But the point was that, when you get a difference between IDE and runtime, it's often caused by some sort of pathing issue. That's why Chris suggested the message box. We can now see that it is not relevant in this case, but it's always useful to check the pathing, if only to eliminate it.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
I removed like this:
Sn%C3%ADmek_obrazovky_2023-01-24_132704_f7rflo.png

Unfortunately it doesn't work.
 
Mike,
Yes thank you, I checked in the IDE and in the created EXE file, the paths match.
There will be no problem here.
 
Hi,

You may want to put

Code:
PROCEDURE errHandler

   PARAMETER merror, mess, mess1, mprog, mlineno

   CLEAR

   ? 'Error number: ' + LTRIM(STR(merror))

   ? 'Error message: ' + mess

   ? 'Line of code with error: ' + mess1

   ? 'Line number of error: ' + LTRIM(STR(mlineno))

   ? 'Program with error: ' + mprog

ENDPROC

after you READ EVENTS

and put ON ERROR right before CLEAR EVENTS, in order to keep the error handler active during the whole program execution

hth

MarK
 
...

and a demo how ON ERROR works

Code:
PUBLIC goForm

goForm = CREATEOBJECT("MyForm")
goForm.Show()

READ EVENTS

ON ERROR DO errHandler WITH ;
   ERROR( ), MESSAGE( ), MESSAGE(1), PROGRAM( ), LINENO( )


CLOSE ALL
CLEAR ALL 

**********

PROCEDURE errHandler
   PARAMETER merror, mess, mess1, mprog, mlineno

   WAIT WINDOW + "Error number: " + ALLTRIM(STR(merror)) + " Error message: " + mess + CHR(13) ;
		+ " Line of code with error: " + mess1 + " Line number of error: " + ALLTRIM(STR(mlineno)) + CHR(13) ;
		+ " Program with error: " + mprog
ENDPROC 

DEFINE CLASS MyForm as Form
	Width = 540
	Height = 360
	MinWidth = This.Width
	MinHeight = This.Height
	MaxWidth = This.Width
	Caption = "Sorting data in grid"
	AutoCenter = .T.
	ShowTips = .T.
	Themes = .F.


	ADD OBJECT grdNames as grdBase WITH ;
		RecordSource = "csrNames"
		
		PROCEDURE grdNames.Init()
			WITH This
				.Column1.Header1.Caption = "N°"
				.Column2.Header1.Caption = "Name"
				.Column3.Header1.Caption = "Age"
				.Column4.Header1.Caption = "G°"
				.Column5.Header1.Caption = "City"
				
			ENDWITH 
			
		ENDPROC 
		
		PROCEDURE grdNames.Refresh()
			LOCAL lcDBClick as String, lcClick as String
			
			lcDBClick = "DoubleClick header to reset order"
			lcClick = "Click header to sort by "
			
			DODEFAULT()

			WITH This
				.Column1.Header1.ToolTipText = IIF(ORDER() = "TNUMBER", lcDBClick, lcClick + "Number")
				.Column2.Header1.ToolTipText = IIF(ORDER() = "TNAME", lcDBClick, lcClick + "Name")
				.Column3.Header1.ToolTipText = IIF(ORDER() = "TAGE", lcDBClick, lcClick + "Age")
				.Column4.Header1.ToolTipText = "Sort by Gender not available"
				.Column5.Header1.ToolTipText = IIF(ORDER() = "TCITY", lcDBClick, lcClick + "City")
				
			ENDWITH 
		
		ENDPROC 
	
	PROCEDURE Load()
		CREATE CURSOR csrNames (iRNumber I,cName C(20), iAge I, cGender C(1), cCity C(20))
		
			INSERT INTO csrNames VALUES (3,'Sahra', 31, "F", "Bruxelles")
			INSERT INTO csrNames VALUES (4,'Jeoffrey', 20, "M", "Paris")
			INSERT INTO csrNames VALUES (6,'Jenny', 53, "F", "Den Haag")
			INSERT INTO csrNames VALUES (1,'Toni', 44, "M", "Rome")
			INSERT INTO csrNames VALUES (2,'Sophie', 76, "F", "Berlin")
			INSERT INTO csrNames VALUES (7,'Jeremy', 67, "M", "New York")
			INSERT INTO csrNames VALUES (8,'John', 19, "M", "Chicago")
			INSERT INTO csrNames VALUES (9,'Marie-Josée', 28, "F", "Quebec")
			INSERT INTO csrNames VALUES (10,'Karen', 62, "F", "Toronto")
			INSERT INTO csrNames VALUES (11,'Abi', 56, "M", "Zurich")
			INSERT INTO csrNames VALUES (12,'Bernhard', 42, "M", "Basel")
			INSERT INTO csrNames VALUES (13,'Christiane', 26, "F", "Marseille")
			INSERT INTO csrNames VALUES (14,'Doris', 29, "F", "Munich")
			INSERT INTO csrNames VALUES (15,'Fred', 58, "M", "Wien")
			INSERT INTO csrNames VALUES (16,'Georges', 40, "M", "Budapest")
			INSERT INTO csrNames VALUES (17,'Juanita', 36, "F", "Mexico")
			INSERT INTO csrNames VALUES (18,'Jhemp', 52, "M", "Luxembourg")
			INSERT INTO csrNames VALUES (19,'Jan', 57, "M", "Amsterdam")
			INSERT INTO csrNames VALUES (20,'Henrietta', 41, "F", "Baton Rouge")
			INSERT INTO csrNames VALUES (5,'Mark', 54, "M", "Bern")
			
		INDEX on iRNumber TAG TNumber
		INDEX on cName TAG TName
		INDEX on iAge TAG TAge
		INDEX on cCity TAG TCity
		
		SET ORDER TO
		
		LOCATE
		 
	ENDPROC

	PROCEDURE Init()
		DODEFAULT() 
		This.DoBinds()
		
	ENDPROC
	
	PROCEDURE DoBinds()
		LOCAL loCol, loObj

		FOR EACH loCol IN This.grdNames.Columns
			IF loCol.BaseClass = "Column"
				UNBINDEVENTS(loCol)
				BINDEVENT(loCol,"MouseMove", This,"GetColumnToolTipText")
			ENDIF 
						
			FOR EACH loObj IN loCol.Objects
				IF loObj.Baseclass == "Header"
					UNBINDEVENTS(loObj)
					BINDEVENT(loObj,"Click",This,"HeaderClick")
					BINDEVENT(loObj,"DblClick",This,"HeaderTwiceClick")
					BINDEVENT(loObj,"MouseMove", This,"GetHeaderToolTipText")

				ENDIF
			NEXT 
		NEXT
		
	ENDPROC

	PROCEDURE HeaderClick()
		LOCAL ARRAY laEvents[1]
		LOCAL lcOrderBy, loObject
		
		AEVENTS(laEvents, 0)

*!*			= MESSAGEBOX("Clicked: " + SYS(1272, laEvents[1]), 64, "Clicked Object", 10000)
			
		loObject = laEvents[1]

		lcOrderBy = SUBSTR(RIGHT(SYS(1272, loObject),9),1,1)

		IF INLIST(lcOrderBy, "1", "2", "3", "5")
			WITH This.grdNames
				.SetAll("FontBold", .F., "Header")
				.SetAll("FontItalic", .F., "Header")
				.SetAll("BackColor", RGB(228, 228, 228), "Header")
			ENDWITH 

			WITH loObject
				.FontBold = .T.
				.FontItalic = .T.
				.Backcolor = RGB(0, 201, 201)
			ENDWITH 
		ENDIF 

		DO CASE 
			CASE lcOrderBy = "1"
				SET ORDER TO TNumber
					
			CASE lcOrderBy = "2"
				SET ORDER TO TName
					
			CASE lcOrderBy = "3"
				SET ORDER TO TAge
				
			CASE lcOrderBy = "4"
				= MESSAGEBOX("Sorting by Gender is not available", 64, "Setting Order", 2000)

			CASE lcOrderBy = "5"
				SET ORDER TO TCity

			OTHERWISE
				= MESSAGEBOX("Call developper", 16, "Setting Order", 5000)

		ENDCASE

		LOCATE
		 
		This.Refresh()
		
	ENDPROC

	PROCEDURE HeaderTwiceClick()
			WITH This.grdNames
				.SetAll("FontBold", .F., "Header")
				.SetAll("FontItalic", .F., "Header")
				.SetAll("BackColor", RGB(228, 228, 228), "Header")
			ENDWITH 
			
			SET ORDER TO
			LOCATE
			This.Refresh()

	ENDPROC 

	PROCEDURE GetHeaderToolTipText(nButton, nShift, nXCoord, nYCoord)
		LOCAL laEvents[1]
		LOCAL loObject
		
		AEVENTS(laEvents,0)
		
		loObject = laEvents[1]
		
		This.grdNamess.cToolTipText = loObject.ToolTipText 
		
*!*			throws an error - should read This.grdNames.cToolTipText with one "s" only
*!*			you may want to correct the typo and run the program again
		
	ENDPROC
	
*!*	The procedure below AVOIDS the TTT to show when the mouse is hovering over columns	
	
	PROCEDURE GetColumnToolTipText(nButton, nShift, nXCoord, nYCoord)
*!*			LOCAL laEvents[1]
*!*			LOCAL loObject
*!*			
*!*			AEVENTS(laEvents,0)
*!*			
*!*			loObject = laEvents[1]
*!*			
*!*			This.grdNames.cToolTipText = loObject.Name

		This.grdNames.cToolTipText = ""
		
	ENDPROC
	
	PROCEDURE Destroy()
		ThisForm.Release()
		ON ERROR  && Restores system error handler.
		CLEAR EVENTS

	ENDPROC
ENDDEFINE 

**********

DEFINE CLASS grdBase as Grid 
	cToolTipText = ""

	Top = 6
	Left = 6
	Width = 540 - 12
	Height = 360 - 12
	ReadOnly = .T.
	Anchor = 15
	BackColor = RGB(0, 246, 246)
	ColumnCount = -1
	
	PROCEDURE ToolTipText_Access()
		RETURN This.cToolTipText
	ENDPROC

ENDDEFINE 

**********

hth

MarK
 
Mark, you are wrong in that MESSAGEBOX(SYS(5)+SYS(2003)) aka the current path is of no value.

It can make a difference in finding files or not, all files that are outside of the EXE like DBFs and more.
And it is very common to set the default path in the main program and make it the path of the EXE, which also seems to be the case here.

But if you make that Justpath(sys(16)) and your main program is in a subfolder of the project the path in IDE And EXE can differ exactly because of that and be the reason an application works in the ID and not as EXE. I've seen this very often. Even when you then also SET PATH to a list of paths, especially realtive paths, all depends in the correct default path stting to find everything necessary.

MajklPan, can you look for the usage of SYS(16) in the code? You can make use of the code references tool for that and search for SYS(16) throughout all code in the project. I would look for it in the main program of the project first.

Chriss
 
mjcmkrsr,
Thanks for the example given, I ran it and it shows me the same errors as I gave the image above.
That doesn't tell me anything is wrong.
-----------------------------------------------------------------
Chris,
In the main run of the program I found only SYS(16) here:
2_oujeq1.png

Then in the whole program I found here:
1_fburvl.png
 
From the code references search result, I see your main program is in a subfolder PROG. The EXE you build will be in the parent directory, though, and this means cCestaProgramu will differ in IDE and EXE. And it will be false in the EXE.

In the next line already, that means you find the GPT_Memo.mem file or not. And that means some variables will be set or not, that explains a lot...

Put in a MESSAGEBOX(SYS(16)+chr(13)+chr(10)+cCestaProgramu) right after cCestaProgramu is set.

The value of cCestaProgramu should always be the location of the EXE (or in the IDE the HomeDir of the PJX). And this expression using RAT('\',SYS(16),2) cuts off two \ from SYS(16), which is correct in the IDE, but not in the EXE. You should use this, instead:

Code:
IF _VFP.StartMode=0
   cCestaProgramu = JustPath(JustPath(SYS(16))
ELSE
   cCestaProgramu = JustPath(SYS(16))
ENDIF

You could always use JUstpath(sys(16)), if your main program would be in the same folder as the PJX. I'd not move it there now, though, as it might depend on being in the same folder as other PRGs, so it could mean refactoring work to get the PRG working if you move it.

I bet you, your former colleague always adjusted the RAT() expression to remove only one backslash in the EXE version and two backslashes in the IDE. But if you have no documentation about this necessary adjustment you fail to get a working EXE.

Chriss
 
Hi,

Thanks for the example given, I ran it and it shows me the same errors as I gave the image above.
That doesn't tell me anything is wrong.

Hard to believe. If you hover with the mouse over the headers of the grid the error handler should open a WAIT WINDOW in the upper right corner of your screen with the error messages.

hth

MarK
 
You put ON ERROR right after you set ON ERROR DO errHandler WITH...

That's nonsense.

You want the error handler to be set. So don't unset it right in the next line.

If you don't understand what ON ERROR sets, then please press F1 and read a little about it, it's all documented, the help has a full reference of every command and function, all classes and all their methods and events, so you also find a chapter about ON ERROR.

You're saying "In case an error happens, call errHandler with some parameters" in one line, and in the next line you say: "In case an error happens do the default system error handling". As a result of that, what do you get? Of course, you get the system error handling, that's not what you wanted. Setting back ON ERROR to nothing can be done later when you exit from the application, not right in the next line.

You just established Mark's error handling for one line of code and then reverted to the system error handling. That's not what Mark told you to do.

Chriss
 
Chris,
Yes, exactly as you write, I always had to copy the exe file to the progs folder in order to run the application.
After inserting MESSAGEBOX here:
IDE_yrcoey.png

I thought it would be related to the GPT_Memo.mem file, it would make sense.

I see, thanks for the explanation.
Most likely, he just edited the RAT() exe file when creating it, as you write.
So you suggest this code:
Code:
IF _VFP.StartMode=0
   cCestaProgramu = JustPath(JustPath(SYS(16))
ELSE
   cCestaProgramu = JustPath(SYS(16))
ENDIF
Insert location:
Code:
cCestaProgramu=LEFT(SYS(16),RAT(SYS(16),2)-1)
Or after that.

VFP is a very complicated database relational environment [bigsmile]
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top