Rick Strahl's Weblog
Rick Strahl's FoxPro and Web Connection Weblog
White Papers | Products | Message Board | News |

Last 50 comments


Re: Slow SET PROCEDURE TO and NEWOBJECT()



Rick Strahl
22 days ago

@Mike - That might work for you, but it doesn't work for me. I never run an EXE in development, so your project inclusion loading would not work for me. Plus the fact that you have to add your non-direct referenced dependencies explicitly into the project, which is a pain in the ass.

My approach is every class declares its dependencies at the top:

*** Dependencies
SET PROCEDURE TO wwUtils ADDITIVE
SET PROCEDURE TO wwApi ADDITIVE
SET PROCEDURE TO wwSql ADDITIVE

*** this library
SET PROCEDURE TO wwBusinessObject ADDITIVE

Then to load the library I can simply do:

*** At app startup - or in `MyApp_Load.prg`
DO wwBusinessObject
DO wwDotnetBridge 

*** Now use any class declared

The benefit is you have code based configuration - you can easily tell what dependencies your app has by looking at MyApp_Load.prg and as a bonus all your dependencies automatically get puled into the project. If you start a new project you can copy/customize the list without manually adding files to your project file.

This works both for compiled and PRG files and you can run the PRG from the Command Window both running the app or loading only the libraries.

Re: Slow SET PROCEDURE TO and NEWOBJECT()



Mike Yearwood
23 days ago

I suggest avoiding set procedure. Put customer.prg in a folder in your development path and add it to the exe. Just call it like this:

loCustomer=Customer(1,2,3)

Customer.prg lparameters one, two, three RETURN CreateObject('Customer',one,two,three)

define class customer procedure init lparameters one, two, three endproc enddefine

Re: Making Web Connection Work with Response Output Greater than 16mb



SalvaHig
1 month ago

Loved the article. Compression is a great quick win here. I've used GZip myself and it really cuts down on the output size, especially for JSON. Definitely worth implementing if you’re worried about hitting that limit or just want to reduce the overall load.

Re: Launching FoxPro in a Project Folder



Micky Khan
4 months ago

Fortunately I define them with a startup prg to establish configuration and directories to be used by the current system...

Re: API Declarations in Performance Sensitive FoxPro Code



Mike Yearwood
5 months ago

The advantage of Drew's technique is that the DECLARE is only in one place, the FoxPro UDF of the same name as the Windows API. That also means if the API was released, it will be automatically re-installed at the next call to the API.

SLEEP.PRG lparameters m.tnMilliseconds declare Sleep in Win32API integer dwMilliseconds return sleep(m.tnMilliseconds)

The above runs once. Every subsequent call to sleep is very fast because the API reacts instead. If you use the alias, then you must name the UDF the same as the alias to gain these advantages.

Re: Watch out for 64 bit Incompatibility using the Visual FoxPro OleDb Provider



Paul
11 months ago

Some of my applications were regenerated using Chen's VFPA10 (64-bit), but one thing makes this experience unhappy: there is no VFPOleDB @64bit, making certain options like automation to Excel much more complicated. Will we one day have 64-bit VFPoleDB?

Re: Custom Manifest Files in Visual FoxPro EXEs



Boudewijn Lutgerink
August 11, 2023

Just what I was looking for. Tx for writing this out. Very useful.

Re: Building and Consuming REST API Services with FoxPro



viorel from romania
August 09, 2023

I read your blog and the light came on in my head. Thank you very much sir.

Re: Launching FoxPro in a Project Folder



Steve
May 05, 2023

Thanks Rick, this is very helpful.

I normally write utility programs for my own use in ad hoc data manipulation/cleanup. I am now tasked with creating an app for someone in another dept so was looking for help exactly like this.

Aloha! Steve

Re: Launching FoxPro in a Project Folder



Rick Strahl
April 18, 2023

@Marco - that's cool. Glad I'm not the only one thinking along these lines - this seems almost address the identical points I'm addressing in this post.

Nice!

Re: Launching FoxPro in a Project Folder



Marco Plaza
April 18, 2023

Hello Rick!

Some weeks ago I shared a little helper ( nfCustomEnvHelper.prg ) that automates all the steps you describe here.

You can give it a try at https://github.com/nfoxdev/nfCustomEnvHelper

Re: Watch out for 64 bit Incompatibility using the Visual FoxPro OleDb Provider



David M
March 01, 2023

Just ran into this problem on new Win11 computer. The latest OLE and ODBC installers on https://github.com/VFPX/VFPInstallers resolved the issue for me. Thank you!

Re: Deploying and Configuring West Wind Web Connection Applications



Harvey Mushman
August 08, 2022

The article is a good starting point for anyone new to Web Connect or like me, for someone that is setting up my first cloud server. Thank you Rick for taking the time to teach me through these writings.

Re: Weird Performance Differences of PRG vs. EXE vs. COM Object in Large Apps



Mike Yearwood
June 01, 2022

Sorry to dredge up this old thread, but I recently made a discovery that affects performance. If you have a single prg with a define class, add code at the top of that prg to return the createobject of that class. That way there is no set procedure required. When the class is a subclass

dsoInventoryItems.prg IF NOT "\MYDATAOBJECT"$set("procedure") set procedure to mydataobject.prg additive endif return createobject("dsoInventoryItems")

define class dsoInventoryItems as MyDataObject

That means the set procedure is increased by only 1, and the individual data object subclasses can be instantiated directly like so:

lodsoInventoryItems=dsoInventoryItems()

I believe that should give as good EXE performance as having everything in one .PRG.

Re: API Declarations in Performance Sensitive FoxPro Code



Joel Leach
July 12, 2021

This reminded me of a trick I learned years ago at Eric Selje's Southwest Fox 2010 session on VFP2C32. This technique should survive a CLEAR DLLS. From Eric's whitepaper:

*Here’s a tip I remember Drew Speedie mentioning a few years back. Because API functions with the same name as FoxPro functions take precedence in the calling heirarchy, you can dynamically load API functions on-demand by wrapping them in a VFP function of the same name. The first time you call it, the VFP function will be called, the API function will load and get called, but on subsequent calls the API function will be called directly. *

? getActiveWindow() 

FUNCTION getActiveWindow 
DECLARE INTEGER GetActiveWindow IN user32 
RETURN GetActiveWindow()

Re: Should we add Bootstrap 5.0 Support to Web Connection?



Kevin Ragsdale
June 29, 2021

Thanks for the write-up! I've been using Bootstrap 3 - had planned to go to 4 but never did. Definitely want to move to 5 (primarily for the floating labels more than anything, but also to do a better job of keeping up with the latest version).

I haven't used the HTMLHelpers much, so I personally don't need an upgrade for those. Though I'd suspect there's a lot of use of them out in the real world.

Really appreciate the link to the git commit for the upgrade. Very easy to see the types of changes needed in my apps.

Re: Testing a Web Connection COM Server with FoxPro or PowerShell



Michael Birnholz
December 17, 2020

Where has powershell been all my life? Love this Rick.

Re: Enhancing Web Applications with VueJs



Tom Green
October 16, 2020

Thanks, Rick. This is a great article. Much appreciated!. I'm still working my way through it as I learn ES5 and ES6 at the same time.

By the way, I missed you as the Virtual Fox Fest 2020.

Re: Using CreateProcess API instead of the FoxPro ! RUN command



Rick Strahl
September 16, 2020

@Mattias - good catch.

Actually a more recent version of this code already has that in it.

IF VARTYPE(lnShowWindow) # "N"
  lnShowWindow = 1
ENDIF

Re: Using CreateProcess API instead of the FoxPro ! RUN command



Matthias
August 18, 2020

There's a bug in your code, in GetStartupInfo() you are checking for:

IF EMPTY(lnShowWindow) lnShowWindow = 1 ENDIF

But lnShowWindow = 0 (and therefore EMPTY) is a valid value! With lnShowWindow = 0 you can start a process "hidden", invisible in task bar and invisible in gui.

So you should replace it with IF VARTYPE(lnShowWindow) != "N" or something like that...

  • SW_HIDE (0) = Hides the window and activates another window.
  • SW_MAXIMIZE (3) = Maximizes the specified window.
  • SW_MINIMIZE (6) = Minimizes the specified window and activates the next top-level window in the z-order.
  • SW_RESTORE (9) = Activates and displays the window. If the window is minimized or maximized, Windows restores it to its original size and position. An application should specify this flag when restoring a minimized window.
  • SW_SHOW (5) = Activates the window and displays it in its current size and position.
  • SW_SHOWDEFAULT (10) = Sets the show state based on the SW_ flag specified in the STARTUPINFO structure passed to the CreateProcess function by the program that started the application. An application should call ShowWindow with this flag to set the initial show state of its main window.
  • SW_SHOWMAXIMIZED (3) = Activates the window and displays it as a maximized window.
  • SW_SHOWMINIMIZED (2) = Activates the window and displays it as a minimized window.
  • SW_SHOWMINNOACTIVE (7) = Displays the window as a minimized window. The active window remains active.
  • SW_SHOWNA (8) = Displays the window in its current state. The active window remains active.
  • SW_SHOWNOACTIVATE (4) = Displays a window in its most recent size and position. The active window remains active.
  • SW_SHOWNORMAL (1) = Activates and displays a window. If the window is minimized or maximized, Windows restores it to its original size and position. An application should specify this flag when displaying the window for the first time.

Re: Workaround for horrendously slow SUBSTR Character Parsing in FoxPro



Rick Strahl
July 06, 2020

@Christof - that's great! Another great solution - looks like roughly on par with Marco's improvement.

Re: Workaround for horrendously slow SUBSTR Character Parsing in FoxPro



Christof Wollenhaupt
July 05, 2020

It'll be faster if you copy the string into memory and then use SYS(2600) to read byte by byte.

LOCAL lnX, lcString
lcString = REPLICATE("1234567890",100000)

	Declare Integer HeapAlloc in Win32Api Integer, Integer, Integer
	Declare Integer HeapFree in Win32APi Integer, Integer, Integer
	Declare Long GetProcessHeap in Win32API
      
lnLength = LEN(lcString)
TRANSFORM(lnLength,"9,999,999")

IF .T.
lnSecs = SECONDS()

lnBase = HeapAlloc( GetProcessHeap(), 0, m.lnLength )
Sys(2600, m.lnBase, m.lnLength, m.lcString)
FOR lnX = 1 TO lnLength
	lcVal = Sys(2600,m.lnBase-1+m.lnX,1)
ENDFOR
HeapFree( GetProcessHeap(), 0, m.lnBase )

? "SYS(2600): " +  TRANSFORM(SECONDS() - lnSecs )

ENDIF

That's 0.33 seconds on my machine vs 37 seconds with SUBSTR().

Re: Troubleshooting Asynchronous Callbacks into FoxPro Code



Rick Strahl
May 24, 2020

Thanks @Christof for the additional info!

Re: Troubleshooting Asynchronous Callbacks into FoxPro Code



Christof Wollenhaupt
May 03, 2020

There's one more async operation that is native to FoxPro and great source of frustration. Dynamic properties in grids. VFP executes these expressions which can call methods or user-defined functions seemingly randomly. Mouse pointer movement and the window placement of other applications impact when a dynamic expression are triggered.

In one application we have one nasty problem that appears to be related to dynamic expressions, although we are not entirely sure yet. VFP switches the data session of one complex form to the default data session at random lines in a form methods for some customers. We have added debug code to every single SET DATASESSION command and know that none of them are executing. Same for any timer event. So frustrating.

DOEVENTS works well in EXEs. Unfortunately, it's one of those commands that are not supported in an MTDLL, because VFP doesn't own the UI thread there. This leads to all kind of strange behavior with callbacks and kernel wait states when the VFP9T runtime is used. In AFP I've mitigated this issue by implementing my own event loop using GetMessage, TranslateMessage, DispatchMessage.

VFP interrupting after a line can occur in unexpected circumstances:

  • SQL statements that have user defined functions
  • While reports are generated
  • Right at the beginning of an error handler

When VFP executes other code outside a wait state (READ EVENTS, MessageBox, etc.) it's in my experience more likely to do so upon entering or returning from a subprocedure. It appears that the code that manages DO levels also performs some checks.

The code interrupting the SCAN loop can be hard to debug because it also depends on the optimization state of SCAN expressions and filters. VFP will not reevaluate optimized expressions in SCAN loops, but it does so with non-optimizable expressions. If one of the side effects of the code that was called asynchronously impacts the filter condition, you suddenly see errors when adding or dropping an index, even when the code in neither the handler nor the SCAN loop has changed at all.

Re: Visual FoxPro and Multi-Threading



Sued Jorge Nassar
March 15, 2020

Hello Rick.

We have a problem to solve and I ask you if has some routine or API that do something like threads.

The atual cenario:

we must use three timers to execute differents routines in different times. Example:

Timer1 -> routine A -> at each 30 seconds

Timer2 -> routine B -> At each 60 seconds

Timer3 -> routine C -> at each 10 seconds

This cenario cause many problems because one timer in execution stops the others, creating a fila. So, the 10 seconds timer stops the others that never executes.

My question: any routine or API to generate independ threads or something to simulate my cenario?

Thanks a Lot

Re: UTC Time in FoxPro



Rick Strahl
March 02, 2020

@Matthias - GetUtcTime() uses GetTimeZone() to get the time offset?

Re: UTC Time in FoxPro



Matthias
October 24, 2019

Sorry, but this functions are NOT working correctly! Especially the GetUtcTime() is incorrect. Your function GetTimeZone() checks for daylight-savings-time, but GetUtcTime() does not! When passing a datetime as parameter to the GetUtcTime() function, you have to check, if the given datetime is in daylight-savings-time or standard-time. If you run that function in winter, it gives a different result compared to if you run it in summer!

Re: Drive Mapping in Web Applications



Emin Kazok
August 06, 2019

Mapping as part of startup in group policy did the trick. Thank you very much.

Re: Calling JSON REST Services with FoxPro and wwJsonServiceClient



Rick
May 13, 2019

@Phil - you can use wwDotnetBridge to call that .NET Component to encode your message.

Re: Calling JSON REST Services with FoxPro and wwJsonServiceClient



Will
May 13, 2019

Rick,

Great app and nice (though somewhat cryptic) descriptions of what can be done with it.

PLEASE, PLEASE address the OAUTH 2 signature question posed by Phil on Feb 26. I am trying to accomplish the exact same thing, and I'm an absolute noob when it comes to API/JSON services.

Many thanks, Will

re: Fixing wwDotnetBridge "Unable to load Clr Instance" Errors



Chris B
October 24, 2018

Rick-

We are getting a similar "Clr Instance..." error but with a different hash identifier as follows:

Unable to load wwDotNetBridge: Unable to load Clr instance.0x8007000e:

We are using the WW library v.6.15 DtNetBridge DLL with a custom VFP v.09x enterprise platform on our LAN. VFP and the enterprise platform is running on Windows 2012 R12 Server and have .met v4.7 running as well.

The error is odd as it is occasional/intermittent and does not always occur. It just started occurring today.

Any ideas?

Chris

re: Web Connection and TLS 1.2 Support



Rick Strahl
September 14, 2018

@Darko - if you're going to use an EXE maybe you should just shell out and use curl instead. It has a lot of capabilities and it too can work just fine without the Windows TLS stack and it's a well known interface that works for all sorts of things beyond just HTTP.

re: Using CreateProcess API instead of the FoxPro ! RUN command



Robert
August 09, 2018

Rick,

Sorry I forgot to mention that I'm running a VFP compiled exe with createprocess()

Rob

re: Using CreateProcess API instead of the FoxPro ! RUN command



Robert
August 09, 2018

Rick,

I can get start a process using createprocess() but the lhProcess number is different to the PID listed in the TaskManager.

So when I use OpenProcess(PROCESS_QUERY_INFORMATION+PROCESS_VM_READ,0,lhProcess) it fails to open the handle.

Is there a way to get the correct pid back or is enumerating all the processes the only way to go?

Rob

re: Web Connection and TLS 1.2 Support



Darko Kezic
July 05, 2018

Hi, thanks for sharing this.

I used in my various VFP applications directly Windows AJAX with l_oHttp = CREATEOBJECT("MSXML2.ServerXMLHTTP") ... and was biten with TLS 1.2 issue on various client PCs.

At the end, I created small EXE with Golang which only connects to server and returns result. Then I called this EXE instead of MSXML2.ServerXMLHTTP with l_oShell = CREATEOBJECT("Wscript.Shell") ...

Yes, it looks silly to call another EXE for every HTTP request, but this was only secure way to do it on older Windows.

re: Visual FoxPro and Multi-Threading



David Phillips
May 29, 2018

Thank you Rick you a legend. FoxPro is so good with handling data it will be hard to find an alternative in the future unless someone reinvents it in a multithreaded form. Hopefully we can keep it going for another 20yrs or so. There is still Cobol Code out there that is 58yrs old and still running.

re: Web Connection and TLS 1.2 Support



Jon
May 17, 2018

Thanks, Rick--great information, as always!

re: Web Connection and TLS 1.2 Support



Michael Birnholz
April 11, 2018

Rick - discovered a few minutes ago that another issue when trying to resolve this is the default settings for IE Enhanced Security Settings Configuration. If these are both active you will not be able to open this url https://api.authorize.net/xml/v1/request.api if you are running Windows 2012 R2. If you deactivate for both administrators and users the page will open.

re: Writing to the Windows Console from Visual FoxPro



Randy H
April 04, 2018

I know we all hate flashing command windows, but:

STRTOFILE("systeminfo >systeminfo.txt","runsysteminfo.bat") RUN /n runsysteminfo.bat sysitext= FILETOSTR("systeminfo.txt")

I do like simple solutions.

re: Calling JSON REST Services with FoxPro and wwJsonServiceClient



Phil
February 26, 2018

Hi Rick,

I'm trying to figure out how to use wwJsonServiceClient to generate an OAUTH 2.0 signature.

Their API docs have an example: The signature is sent in a header named BDXAPI_NAME.

MessageDigestPasswordEncoder encoder = new MessageDigestPasswordEncoder("SHA-1"); StringBuilder sb = new StringBuilder(); sb.append("bdxapikey").append("=").append(bdxApiKey).append("&"); sb.append("bdxapiClientId").append("=").append(clientId).append("&"); sb.append("bdxapisecret").append("=").append(bdxApiSecret); model.setSignature(encoder.encodePassword(sb.toString(), null)); return model;

re: FoxPro EXE DCOM Configuration on 64 Bit Systems



Mandie
February 16, 2018

Stejpan,

Did you ever find a resolve for this? We are migrating our website over to a new Windows 2012 Server and are not able to get the foxpro dlls to work even when we have registered them successfully?

Thanks.

re: Calling JSON REST Services with FoxPro and wwJsonServiceClient



Rick Strahl
February 09, 2018

Yes you can call CreatewwHttp() which returns a wwHttp instance once which you can set any wwHttp settings. That instance is then used in the request:

oProxy = CREATEOBJECT("wwJsonServiceClient")

*** Create custom Http Object for Authentication
loHttp = CREATEOBJECT("wwHttp")
loHttp.cUsername = "ricks"
loHttp.cPassword = "seekrit22"
loHttp.AddHeader("user_token","3241231")

*** Pass it to the proxy to use
loProxy.CreatewwHttp(loHttp)

loArtist = loProxy.CallService("http://albumviewerswf.west-wind.com/api/artist",loArtist,"PUT")

IF  loProxy.lError
   ? loProxy.cErrorMsg
   RETURN
ENDIF

? loArtist.Albums.Count

re: Calling JSON REST Services with FoxPro and wwJsonServiceClient



Christian
February 09, 2018

I like the idea using the wwJsonServiceClient, however is this also possible with headers? Using HTTP call I would normally so something like that: loHTTP = CREATEOBJECT("wwHTTP") loHTTP.AppendHeader("user_session", lcUserSession) lcHTML = loHTTP.HTTPGet("http://192.168.168.155:7564/api/v1/projekte")

re: Doing HTTP Headers right in Web Connection 5.0



Rick Strahl
August 13, 2017

Easy:

Response.Redirect("~/default.wcs",.T.)

The .T. parameter makes a permanent redirect.

re: Doing HTTP Headers right in Web Connection 5.0



Michael Hogan
August 13, 2017

Very helpful - but how would I return a 301 redirect? In my 5.x app, I do this: Response.Clear() Response.Status = "404 File not found" Response.Write("Page was not found")

TIA

re: UTC Time in FoxPro



Michael B
July 23, 2017

I am working on a delivery routing module for my application and I decided to use javascript to pass the users browser time to vfp. I then convert the hex value to a fox datetime() easily. Javascript returns the time in hex starting from 1/1/1970 (aka "epoch time).

lnUnixEpochTime = 1500847437204 ? lnUnixEpochTime/(6060606060*60) + DATETIME()

This returns: 07/23/2017 05:16:29 PM

re: Persisting Static Objects in Web Connection Applications



Thierry Nivelet
June 08, 2017

Using addproperty() in .Init() works around the COM signature issue.

Also, using state persistence the way you describe applied more to single server applications (logical servers such as COM objects)

re: IIS 7 Default Request Filtering and Web Connection



faa
May 31, 2017

Hello, i am facing the issue while using request filtering option. My website didn't work until I add '.' in allowed list. I am unable to find which particular extension I am missing. Thanks in advance.

re: Handling Multiple Screens in Visual FoxPro Desktop Applications



P.C.
April 27, 2017

Yes, the _screen.top and _screen.left can obtain value -32000 which is hard to find on any monitor...

This can happen when the main FoxPro window is minimized.

© Rick Strahl, West Wind Technologies, 2003 - 2024