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!

Determine what program has called a form 3

Status
Not open for further replies.

Rajesh Karunakaran

Programmer
Sep 29, 2016
535
0
16
MU
Dear Team!

I have a form which is supposed to call from another form (a bill entry form) or directly from menu. The form is for maintaining a master data. When the form is run I have to do different actions based of if the form was called by another form or by the menu. I know if I pass a parameter to the form indicating the caller, I can manage it. But, I need to pass a value (the parameter) wherever I call this form. I thought of comparing PROGRAM(0) and PROGRAM(PROGRAM(-1)). But, when I call the form from a parent form, it seems it gives me only the last run form's name (or, do I miss something?)

So, is there a direct way to determine this so that I can make a more of generic manner.

Thank you in advance.
Rajesh
 
Have you tried using ASTACKINFO()? As far as I can see from the Help, it should return either the PRG name or the "object" name (which I take to mean the form).

I'm not sure about this, but it might be worth a try.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Here's another possible approach.

1. In the called form, create a custom property. Let's call it oCaller.

2. In the Load event, add this code:

Code:
TRY 
  loForm = _screen.ActiveForm
CATCH 
  loForm = NULL
ENDTRY 

THISFORM.oCaller = loForm

3. At any point in the called form, to find the calling form or program, look at [tt]THISFORM.oCaller[/tt]. If it is NULL, you were called from a PRG (or, more precisely, you were called when no form was active). Otherwise, it will contain an object reference to the calling form.

This is based on the fact that, during the Load, [tt]_screen.ActiveForm[/tt] still contains an object reference to the calling form. But if there was no active form, then you get an error, hence the need for the TRY/ENDTRY.

But I'm not sure what happens if you are called from a menu while a form is active. I guess you will have to experiment with that.

Mike



__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
[tt]PROGRAM(PROGRAM(-1) - 1)[/tt] gives you the name of the caller.

Anyway, I might have understood your requirements incorrectly, but what is preventing you to use a second parameter to the called form, with the reference to the caller?
 
I agree with atlopes, nothing hinders you to specify the caller in a second or whatever new parameter. of the init, no matter if you already pass in a parameter value, PARMETERS or LPARAMETERS (depends on your taste about PRIVATE/LOCAL variable scope) can take in 27 parameters at max. To skip the first parameter and only pass in a reference simply make the call pass in 0 or NULL or skip it, that parameter will then be 0 or NULL or .F., and you can react to that, too, as if nothing was passed in.

Bye, Olaf.
 
I think LPARAMETERS only accepts 26

Regards

Griff
Keep [Smile]ing

There are 10 kinds of people in the world, those who understand binary and those who don't.

I'm trying to cut down on the use of shrieks (exclamation marks), I'm told they are !good for you.
 
The FoxPro help says 26 for both PARAMETERS/LPARAMETERS and also in system capacities, but this seems to be a help bug.

I have memorized 27, and that works:
Code:
=f(1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,27)

FUNCTION f()
    PARAMETERS a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,aa
    ? aa, PCOUNT()
Even adding a 28th parameter ab within the function definition doesn't error, but passing in the 28th value errors with "Too many artguments". On the other side: remove the aa parameter and you get the error "Must specify additional parameters", which is addressing the PARAMETERS line then having too few parameters.

Anyway, enough parameters.

Rajesh Karunakaran said:
I know if I pass [highlight #FCE94F]a[/highlight] parameter to the form indicating the caller, I can manage it. But, I need to pass [highlight #FCE94F]a[/highlight] value ([highlight #FCE94F]the parameter[/highlight]) wherever I call this form.
You seem to think of a limit of 1 parameter only, that's surely not the case.

I need to lie about what maximum number of parameters I ever used, but I am sure it was far below 20, so one more or less won't matter in that respect. On many occasions I just pass an object reference, that can hold as many properties as you like, or an alias name, that can be seen as a table containing a set of parameters in each record, so even becoming a "batch call."

What can become "ugly" is, you add a parameter after optional parameters. For example, your usual calls just use one parameter and a second and third is optional, which you only use for some cases. Then adding a fourth non optional parameter you always need to pass in means adjusting all calls, even the ones now only using the first parameter would need to call f(1,,,4), parameters 2 and 3 skipped. But that's not your problem here because the new toCaller reference parameter will be optional itself, only passed in, if the form is called by a form and not via the menu. You can check whether toCaller was passed in by checking PCOUNT() or whether the Type o toCaller is "O" or whether EMPTY(toCaller) is true. Every parameter you add to (L)PARAMETERS is optional and doesn't cause the need to adjust all calls. Only passing in more parameters than are accepted causes an error.

Bye, Olaf.
 
lPARAMETERS only accepts 26 according to the help file:
help file said:
LPARAMETERS ParameterList
Specifies one or more local variable or array names to assign data from the calling program. Use commas to separate multiple parameters in ParameterList. You can pass a maximum of 26 parameters.

Parameters apparently will sometimes accept 27, again according to the help file
help file said:
PARAMETERS ParameterList
Specifies one or more variable or array names to assign data to. Use commas to separate multiple parameters in ParameterList. Generally, you can pass a maximum of 26 parameters; however, in some circumstances, you can pass 27 parameters.

Regards

Griff
Keep [Smile]ing

There are 10 kinds of people in the world, those who understand binary and those who don't.

I'm trying to cut down on the use of shrieks (exclamation marks), I'm told they are !good for you.
 
OK, I take notice of that and can confirm. Still, it's not the main point, you can pass in many more than one parameter and likely will never reach the limit of 26.

Bye, Olaf.
 
You can always use an array to make it virtually limitless

Regards

Griff
Keep [Smile]ing

There are 10 kinds of people in the world, those who understand binary and those who don't.

I'm trying to cut down on the use of shrieks (exclamation marks), I'm told they are !good for you.
 
Sure, arrays are another idea.

Besides that I confirmed to early, LPARAMETERS has the same "some curcumstances" exception, I can pass in 27 paraemters, there, too.

Since Rajesh talked of the (one) parameter, it's surely not a problem to add a second parameter.

Bye, Olaf.
 
An interesting discussion, but aren't we getting off the point here. The main point is that he can ignore the passing of parameters when calling the form from another form. He only has to specify trhe parameter when calling from the the menu. In that case, he passes .T., and the called form receives .T. In all other cases, he passes nothing, and the form receives .F.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
You're right about getting of topic, but I would suggest simply adding a second parameter to whatever parameter is passed in already and call that toCaller. then that can be passed in or not. Menu calls won't need to change, calls from forms will pass in the current value and THISFORM to let themselves be known as the caller form.

I thought you suggested that, but you suggested reading _SCREEN.ACTIVEFORM in the Load(). That way there also is a "caller", if just some form is active, while the menu item starts this form. I'd always rather opt for the Init parameter, that makes it more obvious and also might be used to specify a third form as "caller", even though it isn't the active one, so its more versatile.

Bye, Olaf.

 
Dear team!

My apologies for this delayed response.

I just wanted to explain the scenario a bit more elaborately.

The form in question is a Vehicle master data maintenance module. My menu has an entry to call this form when a new vehicle comes and user wants to add it in the data table or to make any modification of existing vehicle. Now, my Invoice and Billing forms also have provision to call this form if the user finds that the vehicle he needs to mention in the Invoice or Billing is a new one and wants to add it. In this case, he can directly call the form from within the Invoice or Billing form; doesn't have to go to menu and call the form from there. In these different cases, I have some actions or decisions to be performed on the basis of from where the vehicle master form was called. Yes, I can have a parameter in the vehicle master form, in its INIT, indicating the caller program. But then, I have to pass a pre-defined value whenever/wherever I call this vehicle master form to determine the caller. Instead, I was thinking that if there is way to auto detect if the form was called directly from the menu or it was called from a form.


1. Mike, I checked 'ASTACKINFO()', it works. I think your '_screen.ActiveForm' also is a good idea. Will check which way gives me maximum benefits and in a generalised manner.
2. Olaf, I was not confused of the number of parameters I can pass. It was only a matter whether there is a way without using any parameters at all.

By the way, as a test I made 2 forms. When I called FormB from FormA, the ASTACKINFO() gave 2 records when checked from FormB's LOAD method. But, when checked from the FormB's RELEASE method, it gave only 1 record and no reference to the first form (FormA), as if it ignored the execution chain. I am not sure, if I was looking at it wrongly. Need to check again.

Thank you all for your inputs. It was a good discussion!

Rajesh
 
Olaf,

I think you're right when you say opting for a parameter to be passed for this purpose is more obvious, strict and maintainable. On the other hand, I don't think I would have a situation where the vehicle master form is called from menu when another form is already active. In fact, I have to ENSURE that such a thing never happens!

Let me check which way is better.

Thanks
Rajesh
 
Rajesh said:
when checked from the FormB's RELEASE method, it gave only 1 record and no reference to the first form (FormA), as if it ignored the execution chain.
You expect the form call to stay on stack until the called form is released, but that's only the case for modal forms. Normal forms have their init and several more events until activate running, but surely after that the call chain is reduced by returning to the caller starting the form. When this caller form method then ends (eg a button click) the callstack is empty again. The callstack will just have the READ EVENTS (if you have one) in its only element, both caller and called form are now objects merely waiting for events to happen, nothing sits on the call stack.

So ASTACKINFO only is an option right at the form init to see where that came from. Since you only get textual information about where a call originated from you don't get an object reference from that. You might not need it, but to get at that information in the form release you surely will need to store it somewhere at init time.

Bye, Ola.
 
Olaf said:
I thought you suggested that, but you suggested reading _SCREEN.ACTIVEFORM in the Load(). That way there also is a "caller", if just some form is active, while the menu item starts this form.

Yes, I understand that. It's why I mentioned that I wasn't sure if the solution was appropriate when called from a menu, and the need to experiment.

But having now read the rest of this thread, I am inclining towards the solution of passing a value of .T. from the menu, and not passing anything from other places, as I mentioned in my post of 17 Oct 17 07:54.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Rajesh said:
I don't think I would have a situation where the vehicle master form is called from menu when another form is already active. In fact, I have to ENSURE that such a thing never happens!

Well, you can detect _SCREEN.ACTIVEFORM is an object and RETURN .F. from Load if you want your form to only run as the only form.

But it's rather normal a form isn't the first form started and users start multiple forms in parallel. Maybe you have a misunderstanding about _SCREEN.ACTIVEFORM? It will also be a reference to whatever currently active form, if a menu item is used, _SCREEN ACTIVEFORM merely is the active form, not the active code object or caller, it just often is that, but not always. And clicking a menu item also doesn't inactivate the active form.

Mike thought of accompanying info via parameter .T. you only pass in when starting the form from the menu, so it knows its started from the menu and can ignore what Load saw in _SCREEN.ACTIVEFORM.

That might mean less work, as you only need to adjust one menu item and the init parameters, say "tlCalledFromMenu" being .T. only when the menu item command/procedure passes .T., but I don't know how general you develop your forms with base classes so a form call from another form also only needs an adjustment in one method of one base class, eg a callform button class. OOP is really also helpful to minimize necessary changes.

Bye, Olaf.

 
Just a side comment about the parameters limit being 26. Years ago, back in the VFP6 days, we would successfully send over 30 parameters to a VFP COM application on a web server. (It was data on 30 data fields plus another couple values.) That was how I found it when I was hired. Even when we added fields and sent over 40 parameters it still worked. But when we tried going higher, somewhere around 46 parameters, then it failed. I never did get a good explanation for that, must have been something with the COM design. Thereafter we rewrote the process so the data was combined in fewer parameters and we observed the 26 parameter limit everywhere.
 
Astonishing. In the back of my mind I think I experienced some other behavior for the parameters coming from starting an EXE, which you can also get via (L)PARAMETERS in the main.prg of your project, but also via Windows API function GetCommandLine(). Since that gives you the full call, you can see more than may come in within PCOUNT parameters of your code so you could always parse out more parameters.

This could make me experiment a bit if it wasn't so unnecessary.

When I would design a COM interface for a database where this COM server acts as kind of the stored procedures of a server and allows you to act more comfortably on the data than via an ODBC or OLEDB provider plus SQL queries, I'd rather think about an interface not needing a parameter per field or atomic value early on in the design phase. Even if you had unlimited parameters, it's not at all beautiful or elegant to ask for data that way. That interface would change with each structural database change.

You can receive arrays and objects and XML strings, of which even just one can hold a whole hierarchy of data, the interface should make use of one of these possibilities to avoid the necessity of an exhaustive number of parameters.

Take the Visual Foxpro Functions as a reference, the most number of nonoptional parameters is 4. The maximum number of 26 parameters is used, but only as self-reference, if that maximum would be reduced the functions offering 26 mostly optional parameters then could also offer fewer. For example, EXECSCRIPT() offers you to parameterize the script you execute and so obviously offers you at least as many parameters as VFP supports to enable a long parameter set in the script you call. Same goes for CREATEOBJECT() in this case for the parameters passed to the Init.

The next highest number aside of that limit is 8 parameters of CURSORTOXML, and that's a complex topic because of XML.

If you think as SQL Inserts as parameterized, then just realize even in the case of parameterized statements in the literal sense of not just boiling it down to one SQL string you pass in and let itself unfold only within the SQL server, you pass those parameters of a statement including ?var as a side parameter in the form of an array - or the ODBC driver does so building up from the names you provide as parameter names.

You can verify that VFPs language is constructed that way via this code:
Code:
CREATE CURSOR crsFunctions (cFunction varchar(128), nMinparam I, nMaxparam I)
FOR lnIndex = 1 TO ALANGUAGE(laFunctions,2)
   IF "-" $ laFunctions[lnIndex,2]
      INSERT INTO crsFunctions VALUES (laFunctions[lnIndex,1], val(GETWORDNUM(laFunctions[lnIndex,2],1,"-")), val(GETWORDNUM(laFunctions[lnIndex,2],2,"-")))
   ELSE
      INSERT INTO crsFunctions VALUES (laFunctions[lnIndex,1], val(laFunctions[lnIndex,2]), 0)
   ENDIF
ENDFOR 

SELECT cFunction, nMinParam From crsFunctions ORDER BY 2 DESC INTO CURSOR crsMaxNonoptional
SELECT cFunction, nMaxParam From crsFunctions ORDER BY 2 DESC INTO CURSOR crsMaxOptional

The first result cursor crsMaxNonoptional will show the max nonoptional parameter number is 4, the second will list a variety of maxed out functions, of which you also normally only use the nonoptional parameters anyway, e.g., did you even know you can pass in more than one line separator to ALINES()? It's not new to me, but I never needed it anyway. Even the first function CURSORTOXML maxed out to less than the VFP limit has fewer than four parameters, it yet has 0 nonoptional parameters, as it can also work with default on the currently selected workarea, as so many functions and commands do.

Four is a reasonable limit. While records undoubtedly often have more than four fields, you can always summarize them as one record object and even multiple records then just become an object collection or simpler an array or a string of XML or CSV or "passed" separate as a file name to a file.

Now, this could be expanded into parameterizations of native classes methods and events. I expect raised numbers also since you have no hint on which of them is optional or not, but no method or event will have 26 parameters. The last thing you need in this case is named parameters, to make code readable and maintainable and even then it only would be, if most of more than a handful of parameters are almost all optional.

Bye, Olaf.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top