Hi,

I'm trying to start a VFP application through automation. So I created
OLEPUBLIC class. This class displays application's main form in Init code.
Application is compiled as out-of-process EXE.

In VB code I create instance of my COM Server:

set oApp = createobject("Myapp.App")
oApp.DoSomething()

The main form appears and the application is working. But when VB code
finishes and oApp variable is cleared, my VFP application is also closed!

Q: How to preserve vfp automation server in case of releasing referencing
variable in client code?

Look at MS Excel. If I run following code written in VB:

set oEx = createobject("Excel.Application")
oEx.Workbooks.Add
oEx.Visible = true

After releasing oEx variable from memory, Excel is still visible and
working! How do that in VFP?


Thanks in advance,

Janusz Czudek
WORD Software
www.wordsoft.com.pl

Re: Persistent VFP COM Server with GUI by Paul

Paul
Fri Mar 24 13:25:23 CST 2006

Don't know whether this appropriate to your problem or not but if you need
the application to act as a separate entity then I think you should start it
that way. Then the problem becomes how to communicate with it. Check out
winsock or DDE.



Re: Persistent VFP COM Server with GUI by Janusz

Janusz
Sat Mar 25 00:55:50 CST 2006

Paul,

All what I need is:
- start the application from another one (through code)
- call some methods and fill some properties of that application
- and finally present it to the user
From now on the user works with this prepared application, as with "normally
started" one.

Look at automating an Excel. Using COM you can start it, create new
spreadsheet, fill in data, do some formatting and, finally, show it to the
user. That is what I need!

I have considered starting application using RUN command and provide it
command-line parameters, but unfortunately, this is only one-way. After
starting this application I need check some of its properties and collect
results of its methods.

DDE is the option, but its really old technlogy ;) and needs a lot of work.
Winsock relies on TCP/IP stuck and I don't know how it works if user has,
for instance, no network adapter. And it also requres a lot of coding.

COM technology is supported naturally in VFP and I just thought that
creating COM/OLE Automation application will be a piece of cake :) But
things appeared more complicated...

Janusz Czudek
WORD Software
http://www.wordsoft.com.pl


U¿ytkownik "Paul Hemans" <pauln.o.s.p.a.m@laberg.com.au> napisa³ w
wiadomo¶ci news:%231tw0i3TGHA.1572@tk2msftngp13.phx.gbl...
> Don't know whether this appropriate to your problem or not but if you need
> the application to act as a separate entity then I think you should start
> it that way. Then the problem becomes how to communicate with it. Check
> out winsock or DDE.
>



Re: Persistent VFP COM Server with GUI by Imaginecorp

Imaginecorp
Sat Mar 25 08:46:18 CST 2006

Hello Janusz;
> - start the application from another one (through code)
Do you want to start the application, I am assuming a VFP, from within
another VFP application or from word, excel etc?
If its VFP -> VFP , its easy, and you don't need Run, COM etc let us know
this first...
Mohammed
www.imaginecorp.com/whatwedo.htm

"Janusz Czudek" <jczudek@wordsoft.com.pl> wrote in message
news:%23lAjjl9TGHA.4384@tk2msftngp13.phx.gbl...
> Paul,
>
> All what I need is:

> - call some methods and fill some properties of that application
> - and finally present it to the user
> From now on the user works with this prepared application, as with
> "normally started" one.
>
> Look at automating an Excel. Using COM you can start it, create new
> spreadsheet, fill in data, do some formatting and, finally, show it to the
> user. That is what I need!
>
> I have considered starting application using RUN command and provide it
> command-line parameters, but unfortunately, this is only one-way. After
> starting this application I need check some of its properties and collect
> results of its methods.
>
> DDE is the option, but its really old technlogy ;) and needs a lot of
> work. Winsock relies on TCP/IP stuck and I don't know how it works if user
> has, for instance, no network adapter. And it also requres a lot of
> coding.
>
> COM technology is supported naturally in VFP and I just thought that
> creating COM/OLE Automation application will be a piece of cake :) But
> things appeared more complicated...
>
> Janusz Czudek
> WORD Software
> http://www.wordsoft.com.pl
>
>
> U¿ytkownik "Paul Hemans" <pauln.o.s.p.a.m@laberg.com.au> napisa³ w
> wiadomo¶ci news:%231tw0i3TGHA.1572@tk2msftngp13.phx.gbl...
>> Don't know whether this appropriate to your problem or not but if you
>> need the application to act as a separate entity then I think you should
>> start it that way. Then the problem becomes how to communicate with it.
>> Check out winsock or DDE.
>>
>
>



Re: Persistent VFP COM Server with GUI by Janusz

Janusz
Sat Mar 25 11:08:54 CST 2006

Hi Mohammed,

Yes, I need to start my vfp app from Word, Excel, VB Script, custom
applications written in e.g. Delphi etc. Even if it would be VFP -> VFP, the
task is not easy one! Keep in mind that both applications are compiled to
EXE.

Janusz Czudek
WORD Software
http://www.wordsoft.com.pl

U¿ytkownik "Imaginecorp" <imaginecorp@msn.com> napisa³ w wiadomo¶ci
news:uquGhrBUGHA.1576@tk2msftngp13.phx.gbl...
> Hello Janusz;
>> - start the application from another one (through code)
> Do you want to start the application, I am assuming a VFP, from within
> another VFP application or from word, excel etc?
> If its VFP -> VFP , its easy, and you don't need Run, COM etc let us know
> this first...
> Mohammed
> www.imaginecorp.com/whatwedo.htm
>
> "Janusz Czudek" <jczudek@wordsoft.com.pl> wrote in message
> news:%23lAjjl9TGHA.4384@tk2msftngp13.phx.gbl...
>> Paul,
>>
>> All what I need is:
>
>> - call some methods and fill some properties of that application
>> - and finally present it to the user
>> From now on the user works with this prepared application, as with
>> "normally started" one.
>>
>> Look at automating an Excel. Using COM you can start it, create new
>> spreadsheet, fill in data, do some formatting and, finally, show it to
>> the user. That is what I need!
>>
>> I have considered starting application using RUN command and provide it
>> command-line parameters, but unfortunately, this is only one-way. After
>> starting this application I need check some of its properties and collect
>> results of its methods.
>>
>> DDE is the option, but its really old technlogy ;) and needs a lot of
>> work. Winsock relies on TCP/IP stuck and I don't know how it works if
>> user has, for instance, no network adapter. And it also requres a lot of
>> coding.
>>
>> COM technology is supported naturally in VFP and I just thought that
>> creating COM/OLE Automation application will be a piece of cake :) But
>> things appeared more complicated...
>>
>> Janusz Czudek
>> WORD Software
>> http://www.wordsoft.com.pl
>>
>>
>> U¿ytkownik "Paul Hemans" <pauln.o.s.p.a.m@laberg.com.au> napisa³ w
>> wiadomo¶ci news:%231tw0i3TGHA.1572@tk2msftngp13.phx.gbl...
>>> Don't know whether this appropriate to your problem or not but if you
>>> need the application to act as a separate entity then I think you should
>>> start it that way. Then the problem becomes how to communicate with it.
>>> Check out winsock or DDE.
>>>
>>
>>
>
>



Re: Persistent VFP COM Server with GUI by Christian

Christian
Sat Mar 25 13:07:43 CST 2006

Hello,

the lifetime of a COM object is controlled by a reference count on it's
interfaces.

You can increment this reference count with SYS(3097)

Unfortunatly SYS(3097) cannot handle the THIS keyword
inside a COM object to reference itself.
(VFP creates an exception when you pass THIS to SYS(3097) )

That's why you're forced to pass in the object reference from the outside.

e.g.

DEFINE CLASS Application AS Session OLEPUBLIC

loRef = .NULL.
Visible = .F.

FUNCTION Init()
DO FORM yourmainform
ENDFUNC

FUNCTION Destroy
IF TYPE('THIS.loRef') = 'O'
SYS(3098,THIS.loRef)
ENDIF
ENDFUNC

FUNCTION Error(nError, cMethod, nLine)
LOCAL lcMessage
lcMessage = TRANSFORM(nError) + CHR(13) + ;
TRANSFORM(cMethod) + CHR(13) + ;
TRANSFORM(nLine)
COMRETURNERROR('Object',lcMessage)
ENDFUNC

FUNCTION Lock(loObject)
IF TYPE('THIS.loRef') != 'O'
THIS.loRef = loObject
SYS(3097,loObject)
ENDIF
ENDFUNC

FUNCTION Visible_Assign(bVisible)
_SCREEN.Visible = bVisible
ENDFUNC

ENDDEFINE


client code:

loApp = CREATEOBJECT('YourApp.Application')
loApp.Dosomestuff()
loApp.Visible = .T.

&& pass object a reference to itself - cumbersome but
&& the only possible way cause of the inability of SYS(3097) to handle
the THIS reference
loApp.Lock(loApp)

loApp = null

Regards
Christian

Re: Persistent VFP COM Server with GUI by Imaginecorp

Imaginecorp
Sat Mar 25 23:52:52 CST 2006

Hello Janusz:
Sorry cant be of help. I am sure given time somebody will be of help,
otherwise post it on the Universal Thread etc.
Good luck
Mohammed

"Janusz Czudek" <jczudek@wordsoft.com.pl> wrote in message
news:eqivD8CUGHA.5044@TK2MSFTNGP09.phx.gbl...
> Hi Mohammed,
>
> Yes, I need to start my vfp app from Word, Excel, VB Script, custom
> applications written in e.g. Delphi etc. Even if it would be VFP -> VFP,
> the task is not easy one! Keep in mind that both applications are compiled
> to EXE.
>
> Janusz Czudek
> WORD Software
> http://www.wordsoft.com.pl
>
> U¿ytkownik "Imaginecorp" <imaginecorp@msn.com> napisa³ w wiadomo¶ci
> news:uquGhrBUGHA.1576@tk2msftngp13.phx.gbl...
>> Hello Janusz;
>>> - start the application from another one (through code)
>> Do you want to start the application, I am assuming a VFP, from within
>> another VFP application or from word, excel etc?
>> If its VFP -> VFP , its easy, and you don't need Run, COM etc let us know
>> this first...
>> Mohammed
>> www.imaginecorp.com/whatwedo.htm
>>
>> "Janusz Czudek" <jczudek@wordsoft.com.pl> wrote in message
>> news:%23lAjjl9TGHA.4384@tk2msftngp13.phx.gbl...
>>> Paul,
>>>
>>> All what I need is:
>>
>>> - call some methods and fill some properties of that application
>>> - and finally present it to the user
>>> From now on the user works with this prepared application, as with
>>> "normally started" one.
>>>
>>> Look at automating an Excel. Using COM you can start it, create new
>>> spreadsheet, fill in data, do some formatting and, finally, show it to
>>> the user. That is what I need!
>>>
>>> I have considered starting application using RUN command and provide it
>>> command-line parameters, but unfortunately, this is only one-way. After
>>> starting this application I need check some of its properties and
>>> collect results of its methods.
>>>
>>> DDE is the option, but its really old technlogy ;) and needs a lot of
>>> work. Winsock relies on TCP/IP stuck and I don't know how it works if
>>> user has, for instance, no network adapter. And it also requres a lot of
>>> coding.
>>>
>>> COM technology is supported naturally in VFP and I just thought that
>>> creating COM/OLE Automation application will be a piece of cake :) But
>>> things appeared more complicated...
>>>
>>> Janusz Czudek
>>> WORD Software
>>> http://www.wordsoft.com.pl
>>>
>>>
>>> U¿ytkownik "Paul Hemans" <pauln.o.s.p.a.m@laberg.com.au> napisa³ w
>>> wiadomo¶ci news:%231tw0i3TGHA.1572@tk2msftngp13.phx.gbl...
>>>> Don't know whether this appropriate to your problem or not but if you
>>>> need the application to act as a separate entity then I think you
>>>> should start it that way. Then the problem becomes how to communicate
>>>> with it. Check out winsock or DDE.
>>>>
>>>
>>>
>>
>>
>
>



Re: Persistent VFP COM Server with GUI by Olaf

Olaf
Mon Mar 27 05:48:21 CST 2006

Hi,

> Unfortunatly SYS(3097) cannot handle the THIS keyword
> inside a COM object to reference itself.
> (VFP creates an exception when you pass THIS to SYS(3097) )
Is it really THIS, that is or would be the correct IDispatch
Objektreference?
Wouldn't _VFP be appropriate?

Hmmm, how about:
SYS(3097,SYS(3096,SYS(3095,_VFP)))

Didn't try that, just a guess, because of:

SYS(3095,_VFP) -> IDispatch pointer
SYS(3096,SYS(3095,_VFP)) ->IDispatch object reference from pointer
SYS(3097,SYS(3096,SYS(3095,_VFP))) -> increase object reference counter

In command window of a VFP IDE this works and returns 2.

And SYS(3098,SYS(3096,SYS(3095,_VFP))) quits the IDE.
..although it should have only decreased the count to 1...?

Bye, Olaf.




Re: Persistent VFP COM Server with GUI by Olaf

Olaf
Mon Mar 27 05:56:57 CST 2006


> And SYS(3098,SYS(3096,SYS(3095,_VFP))) quits the IDE.
> ..although it should have only decreased the count to 1...?
retried with the much simpler:
? SYS(3097,_VFP) && 4
? SYS(3097,_VFP) && 5

? SYS(3098,_VFP) && 4
? SYS(3098,_VFP) && 3
? SYS(3098,_VFP) && 2
? SYS(3098,_VFP) && 1
? SYS(3098,_VFP) && 0 -> QUIT

Using VFP7 SP1 for that exercise.

Bye, Olaf.



Re: Persistent VFP COM Server with GUI by Olaf

Olaf
Mon Mar 27 07:50:27 CST 2006

> loApp.Lock(loApp)
=> will increase reference counter +1, resulting in 2
> loApp = null
=> will decrease reference counter -2, -1 from SYS(3098) and -1 from
Destroy()
=> Quits loApp nevertheless

Shouldn't one put SYS(3098) in an Unlock()/Quit() method?
When done in .Destroy, isn't SYS(3098) pointless?

Bye, Olaf.



Re: Persistent VFP COM Server with GUI by Christian

Christian
Mon Mar 27 09:20:43 CST 2006

Hi Olaf,

>>loApp.Lock(loApp)
> => will increase reference counter +1, resulting in 2
>>loApp = null
> => will decrease reference counter -2, -1 from SYS(3098) and -1 from
> Destroy()
> => Quits loApp nevertheless

worked for me on VFP9 SP1 .. the executable was not released after
loApp = null

DEFINE CLASS loApp AS Session OLEPUBLIC

loRef = .NULL.
Visible = .F.

FUNCTION Error(nError, cMethod, nLine)
LOCAL lcMessage
lcMessage = TRANSFORM(nError) + CHR(13) + ;
TRANSFORM(cMethod) + CHR(13) + ;
TRANSFORM(nLine)
COMRETURNERROR('Object',lcMessage)
ENDFUNC

FUNCTION Unlock()
THIS.loRef = .NULL.
ENDFUNC

FUNCTION Lock(loObject AS Object)
IF ISNULL(THIS.loRef)
THIS.loRef = loObject
ENDIF
ENDFUNC

FUNCTION RefCount(loObject AS Object)
SYS(3097,loObject)
RETURN SYS(3098,loObject)
ENDFUNC

FUNCTION IDispatchOfVFP()
RETURN SYS(3095,_VFP)
ENDFUNC

FUNCTION IDispatchOfObject(loObject AS Object)
RETURN SYS(3095,loObject)
ENDFUNC

FUNCTION Visible_Assign(bVisible)
_SCREEN.Visible = bVisible
ENDFUNC

ENDDEFINE

storing a reference to itself in the loRef property will also hold the
object
alive .. no need for SYS(3097) at all ..

loApp.IDispatchOfVFP() & loApp.IDispatchOfObject(loApp) are different,
so the below class does NOT work, on can imcrement the reference count
of the _VFP object a hundred times .. but the lifetime of the EXE is not
affected.

DEFINE CLASS loAppVFP AS Session OLEPUBLIC

FUNCTION Error(nError, cMethod, nLine)
LOCAL lcMessage
lcMessage = TRANSFORM(nError) + CHR(13) + ;
TRANSFORM(cMethod) + CHR(13) + ;
TRANSFORM(nLine)
COMRETURNERROR('Object',lcMessage)
ENDFUNC

FUNCTION Unlock()
SYS(3098,_VFP)
ENDFUNC

FUNCTION Lock()
SYS(3097,_VFP)
ENDFUNC

ENDDEFINE

Re: Persistent VFP COM Server with GUI by Olaf

Olaf
Mon Mar 27 09:45:44 CST 2006

> loApp.IDispatchOfVFP() & loApp.IDispatchOfObject(loApp) are different,
> so the below class does NOT work, on can imcrement the reference count of
> the _VFP object a hundred times .. but the lifetime of the EXE is not
> affected.
>
> DEFINE CLASS loAppVFP AS Session OLEPUBLIC
...
> ENDDEFINE

Shouldn't we make a difference here between DLL COM-Server and
EXE Comserver? Of course you can compile an OLEPUBLIC Session
as EXE, But I'd base an automation COM server on a Form class, and
doesn't this behave slightly different? For example you get _Screen with
an Olepublic Form. Do you get a _Screen reference with a DLL COM
server?

I think locking _VFP can help for such an EXE COM Server, though I
didn't experiment yet. (For Creating a COM-Server I'd need to log out
and in again, so I just experimented with the IDE itself now, at home I
have more freedom).

Bye, Olaf.



Re: Persistent VFP COM Server with GUI by Janusz

Janusz
Mon Mar 27 09:59:21 CST 2006

Hi Cristian,

I have played with SYS(309x) functions a bit and with your sample code. And
here is what I found:

After run client code
> loApp = CREATEOBJECT('YourApp.Application')
> loApp.Lock(loApp)
> loApp = null
reference count is 2 (not 1)!

- after CREATEOBJECT RefCount is 1.
- calling loApp.Lock(loApp) references loApp as a parameter and stores it in
object property loRef and that adds additional increment - RefCount is now 2
- SYS(3097) in Lock method increment RefCount by one, so RefCount is 3
- releasing reference (loApp = null) decrement RefCount, so finally we have
RefCount=2

and server stays running :)

But I find a problem with releasing the server. I implemented Quit method in
Application class with SYS(3098,THIS.loRef) and call this method in forms
unload event. But server was still there! So I add in Quit methos second
call to SYS(3098) and... get message "Cannot quit FoxPro!". Only explicit
call to QUIT command releases server. Not very elegant, is it? But it works
for me.

Maybe there is another way to stop server?

How to release Application object from forms method? I store a reference to
Application object in forms property (oApp) but a call in Unload event
"release Thisform.oApp" generates an error. Any other idea?

Btw, there should be a way to get reference to IDispatch interface from
within COM server. Maybe new additional _VFP property?

Thanks for you idea.

Janusz Czudek
WORD Software
http://www.wordosft.com.pl



Uzytkownik "Christian Ehlscheid" <christian@vfp2c.com> napisal w wiadomosci
news:ejwkk9DUGHA.2444@TK2MSFTNGP14.phx.gbl...
> Hello,
>
> the lifetime of a COM object is controlled by a reference count on it's
> interfaces.
>
> You can increment this reference count with SYS(3097)
>
> Unfortunatly SYS(3097) cannot handle the THIS keyword
> inside a COM object to reference itself.
> (VFP creates an exception when you pass THIS to SYS(3097) )
>
> That's why you're forced to pass in the object reference from the outside.
>
> e.g.
>
> DEFINE CLASS Application AS Session OLEPUBLIC
>
> loRef = .NULL.
> Visible = .F.
>
> FUNCTION Init()
> DO FORM yourmainform ENDFUNC
>
> FUNCTION Destroy
> IF TYPE('THIS.loRef') = 'O'
> SYS(3098,THIS.loRef)
> ENDIF
> ENDFUNC
>
> FUNCTION Error(nError, cMethod, nLine)
> LOCAL lcMessage
> lcMessage = TRANSFORM(nError) + CHR(13) + ;
> TRANSFORM(cMethod) + CHR(13) + ;
> TRANSFORM(nLine)
> COMRETURNERROR('Object',lcMessage)
> ENDFUNC
>
> FUNCTION Lock(loObject)
> IF TYPE('THIS.loRef') != 'O'
> THIS.loRef = loObject
> SYS(3097,loObject)
> ENDIF
> ENDFUNC
>
> FUNCTION Visible_Assign(bVisible)
> _SCREEN.Visible = bVisible
> ENDFUNC
>
> ENDDEFINE
>
>
> client code:
>
> loApp = CREATEOBJECT('YourApp.Application')
> loApp.Dosomestuff()
> loApp.Visible = .T.
>
> && pass object a reference to itself - cumbersome but
> && the only possible way cause of the inability of SYS(3097) to handle the
> THIS reference
> loApp.Lock(loApp)
>
> loApp = null
>
> Regards
> Christian



Re: Persistent VFP COM Server with GUI by Janusz

Janusz
Mon Mar 27 10:44:27 CST 2006

Hi Olaf,

> Shouldn't we make a difference here between DLL COM-Server and
> EXE Comserver? Of course you can compile an OLEPUBLIC Session
> as EXE, But I'd base an automation COM server on a Form class, and
> doesn't this behave slightly different? For example you get _Screen with
> an Olepublic Form. Do you get a _Screen reference with a DLL COM
> server?


All we talking about here is only out-of-process EXE com server! DLL server
resides in parent process memory and its life ends with closing hosting
process. We are trying to keep COM Server running after closing client
application.


> I think locking _VFP can help for such an EXE COM Server, though I
> didn't experiment yet. (For Creating a COM-Server I'd need to log out
> and in again, so I just experimented with the IDE itself now, at home I
> have more freedom).

I have checked it. Increasing _VFP RefCount doesn't help in keeping com
server running, but decreasing it can shutdown com server!

Best,

Janusz Czudek
WORD Software
http://www.wordsoft.com.pl



Re: Persistent VFP COM Server with GUI by Olaf

Olaf
Mon Mar 27 11:15:50 CST 2006

Hi Janusz,

> - after CREATEOBJECT RefCount is 1.
> - calling loApp.Lock(loApp) references loApp as a parameter and stores it
> in object property loRef and that adds additional increment - RefCount is
> now 2
> - SYS(3097) in Lock method increment RefCount by one, so RefCount is 3
> - releasing reference (loApp = null) decrement RefCount, so finally we
> have RefCount=2
>
> and server stays running :)

Because of that Christian already said, it would be sufficient to store the
reference. So it would also be sufficient to store THIS to some object
property in Init() and not call SYS(3097) at all, wouldn't it? As simple as

Define Class myApplication as Form Olepublic
ShowWindow = 2 && top level Form

AlwaysonTop = .t.
WindowType = 1
Desktop = .t.

Autocenter = .t.

Procedure Init()
This.Addobject("Application",This)
Endproc

Procedure Destroy()
This.RemoveObject("Application")
Endproc
EndDefine

Hmm, looks familiar:
loWord = Createobject("Word.Application")
Afterwards loWord.Application is a clone of
loWord, isn't it?

Try this example, then play around, using a predefined property
"Application" or "oApp" instead of Add-/Removeobject() as
originally suggested by Christian and perhaps try the QueryUnload()
instead of Destroy().

Bye, Olaf.



Re: Persistent VFP COM Server with GUI by Olaf

Olaf
Mon Mar 27 12:50:51 CST 2006

> Procedure Init()
> This.Addobject("Application",This)
> Endproc
Aargh, of course not.

AddProperty() does not work either, it seems to
not increase the reference count.

Bye, Olaf.



Re: Persistent VFP COM Server with GUI by Olaf

Olaf
Mon Mar 27 13:34:17 CST 2006

Hi Janusz,

I finally got it to work: To automate the locking process
Christian outlined, we simply need a helper DLL, that
does the SYS(3097) call:

So the application comserver could be this class
definition saved as a prg of a project "myexe.pjx":

Define Class Application as Form Olepublic
ShowWindow = 2 && top level Form
AlwaysonTop = .t.
WindowType = 1
Desktop = .t.
Autocenter = .t.

Procedure Init()
Local loLockCom
loLockCom = CreateObject("mydll.LockCOM")
loLockCom.LockApp(Thisform)
Endproc
EndDefine

Compile as EXE.

And then we need a second project "mydll.pjx" with
this LockCOM class:

Define Class LockCOM As Session Olepublic
Procedure LockApp()
Lparameters toApp
Sys(3097,toApp)
Endproc
EndDefine

Compile as DLL.

Now this works:
loApp = CreateObject("myexe.Application")
loApp.Show()
loApp = .null.

I first tried to have the LockCOM class in the same project,
compiled to the same EXE, but that didn't work out.

Bye, Olaf.