Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
West Wind WebSurge - Rest Client and Http Load Testing for Windows

Debugging a Visual FoxPro COM object in place


:P
On this page:

Debugging COM objects in VFP in real time as an application runs is a real pain, but with a little trickery you can make this work. I’ve been working extensively on a Visual Studio .Net 2003 Add-in for Help Builder which allows you to basically right click on a method or property and import the method directly into Help Builder.

 

The Help Builder VS.Net Add-In collects all the relevant information about the Code element (Name, parameters, return type, static etc.) and sticks it into an object that is passed back to Help Builder to process using COM Interop to do so.

 

Works great, but the debugging process for this scenario is pretty hairy – you’re basically working blind when the Fox code in Help Builder gets control and receives this exported object from .Net. There's no other way to create this object, which means the only way to get there is through the Add-In.

 

Enter the VFP Automation model to help out and provide an easier way to build the VFP server code. Rather than call the method directly you can use the Visual FoxPro as an Automation Server to instantiate Visual FoxPro pass it the parameter value and then execute the code inside the VFP IDE where you can debug it.

 

Here’s a small snippet from the Add-In that is relevant for the call to VFP:

 

public void UpdateHelpBuilderMethodCSharpComment(CodeFunction element)

{

      CodeFunction func = element as CodeFunction;

 

      ObjectMethod Method = new ObjectMethod();

      Method.cName = func.Name;

      Method.bStatic = func.IsShared;

      Method.cReturnType = func.Type.AsString;

     

      if (func.Access == vsCMAccess.vsCMAccessProtected)   

            Method.cScope = "protected";

      else if (func.Access == vsCMAccess.vsCMAccessPrivate)

            Method.cScope = "private";

      else if (func.Access == vsCMAccess.vsCMAccessProject)

            Method.cScope = "internal";

      else

            Method.cScope = "public";

     

      … More code to set properties of the Method object

 

#if !VFPDebug

      wwUtils.CallMethod( this.HelpBuilder,"ImportCSharpCodeElement",Method);

#else

      Type loT = Type.GetTypeFromProgID("visualFoxpro.application.8");

      object VFP =  Activator.CreateInstance(loT);

 

      wwUtils.CallMethod(VFP,"DoCmd",@"cd d:\wwapps\wwhelp\");

      wwUtils.CallMethod(VFP,"DoCmd","_Screen.visible=.t.");

      wwUtils.CallMethod(VFP,"SetVar","goElement",Method);

      wwUtils.CallMethod(VFP,"DoCmd","do wwHelpDebug");

#endif                 

      int x = 0;

}

 

The ‘real’ COM call is using a late binding call using Reflection with some wrappers I use frequently to simplify dynamically accessing the late bound object’s properties and methods. You can see how late binding works in the #else code that instead instantiates the VFP development environment.

 

The idea is pretty simple: You instantiate VFP, and set up your environment – mainly making sure that you change path to your work directory from which to run your app. Make VFP visible and use the SetVar method to assign variables to VFP – these vars become PUBLIC vars that you can reference from VFP and they are ideal for passing objects. If you need to pass simple parameters you can expand them into a string using DoCmd and WITH parameters or .Eval() with the appropriate parameters.

 

Then I run a small stub program that I call wwHelpDebug which is simply a loader that performs code similar to what the actual method call does, but using plain VFP code:

 

SET PATH TO \wwapps\wc3\classes; \wwapps\common; \wwapps\wc3\; \wwapps\wc3\tools; .\Code

SET RESOURCE ON

 

*** Load Class Libs

DO WWHELP WITH "LOAD"

 

LOCAL oHelp as wwHelp

oHelp = CREATEOBJECT("wwhelp")

llResult = oHelp.OpenForm(goElement.cSignature,4)

oHelp.oForm.AlwaysOnTop = .f.

 

loHelp = oHelp.oForm.oHelp

 

IF !llResult

   *** For now create a new topic always - must check later

   loHelp.NewTopic()

   loHelp.oTopic.Pk = ""  

ENDIF

 

o = CREATEOBJECT("wwHelpEvents")

loTopic = o.ImportCSharpComment(goElement,oHelp.oForm.oHelp.oTopic)

 

oHelp.OFORM.SaveTopic()

 

The key for this stub program is to set up your environment – set paths, set settings, and most importantly here load any class libs and procedures.

 

When this method runs goElement will be in scope because we passed it in with the SetVar() method call from the .Net code. So we’ve efficiently moved into a debuggable VFP environment. What’s nice now is that VFP is up and running and you can step through your code and change it and even re-run the VFP portion of the application as long as you make sure that you don’t CLEAR ALL or RELEASE ALL or otherwise remove the reference for goElement.

 

This is a huge timesaver especially in a scenario like this where you cannot fake the object being passed to you any other way. The Add-In creates this object that’s passed and there’s no easy way to instantiate and populate this object any other way.


The Voices of Reason


 

Richard
September 07, 2004

# re: Debugging a Visual FoxPro COM object in place

'Using ASP
set tst = CREATEOBJECT("VisualFoxPro.Application.8")

TST.Visible = TRUE
tst.DoCmd("WAIT WIND TIMEOUT 10")
TST.QUIT()
set tst = nothing


Does nothing. ie does not make VFP visible.

Rick Strahl
September 07, 2004

# re: Debugging a Visual FoxPro COM object in place

That's because IIS runs in System context and doesn't have a console to display anything. There are a number of things that need to get set in order for it to work that way. With ASP you need to enable OutofProc COM components and you need to set the W3SVC service to allow interaction with the desktop. Bad idea, BTW.

Rick Strahl's Web Log
October 15, 2006

# Reflection to provide EVALUATE functionality - Rick Strahl's Web Log

After answering three more questions today on how to ‘dynamically’ access a property or control on a form I thought I’d post my Reflection helpers again. I’ve put these into most articles I’ve published, but this way they are easily searchable and pointable for future reference.

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024