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

HttpSendRequest takes a long time

Status
Not open for further replies.

wgcs

Programmer
Mar 31, 2002
2,056
EC
I'm using code essentially like this to download an XML file:
Code:
lhInternetSession = InternetOpen( lcAgent, INTERNET_OPEN_TYPE_PRECONFIG, '', '', SYNCHRONOUS )
  InternetSetOption( lhInternetSession, INTERNET_OPTION_USERNAME, @lcUser, len(lcUser) )
  InternetSetOption( lhInternetSession, INTERNET_OPTION_PASSWORD, @lcPwd,  len(lcPwd)  )
  lhConnect = InternetConnect( lhInternetSession, lcHost, 0, lcUser, lcPwd, INTERNET_SERVICE_HTTP, 0, 0 )
  lhUrlFile = HttpOpenRequest( lhConnect, 'GET', lcObj, 0, 0, 0, ;
    bitor( INTERNET_FLAG_KEEP_CONNECTION, INTERNET_FLAG_RELOAD ), 0 )
  lnRet = HttpSendRequest( lhUrlFile, 0, 0, 0, 0 )

DO WHILE llOK and NOT llCancel
   * set aside a big buffer
   lcReadBuffer = SPACE(10000)
   lnBytesRead = 0
   lnOK = InternetReadFile( lhUrlFile, @lcReadBuffer, LEN(lcReadBuffer), @lnBytesRead)

   if ( lnBytesRead > 0 ) 
      if type('pcOptOutputFile')='C'
        StrToFile(left(lcReadBuffer,lnBytesRead),pcOptOutputFile,.T.) && Add to file.
      else
        lcRetVal = lcRetVal + left( lcReadBuffer, lnBytesRead )
      endif
   endif
   
   * error trap - either a read failure or read past eof()
   llOk = ( lnOK = 1 ) and ( lnBytesRead > 0 )
   
   lnBytesAvail = 0
   lnRes1       = 0
   lnRes2       = 0
   lnOk = InternetQueryDataAvailable( lhUrlFile, @lnBytesAvail, @lnRes1, @lnRes2 ) 
ENDDO

The call to HttpSendRequest can take a long time, especially when the server it's trying to connect to isn't responding (eg: when it's very busy). In the mean time, VFP is completely unresponsive, and looks like it hung up. (it won't minimize, or redraw itself as other windows are moved in front of it)

Anyone have any ideas on how to give better feedback to the user during a simple HTTP download (with user/pwd authentication)?


- Bill

Get the best answers to your questions -- See FAQ481-4875.
 
In situations like this I will sometimes make a COM server exe. Moves code to another process and VFP responds better as Windows allows it a few more trips to it's message queue while the command is running.

boyd.gif

 
I've been thinking about doing that, but I can't make it seem to work in my head.

Can you really make a VFP COM server, and call it from a main VFP program, and have that COM server execute in its own thread? How do you synchronise them? Through events? How do you make the COM server start its processing (spawn the thread/ "Fork") without the main VFP program simply "hanging" until the COM server method returns?

Does the COM server need to be EXE (out-of-process) to accomplish this? What about an MTDLL? (I thought an MTDLL needs to be hosted from a multi-threaded environment, and was simply "multi-thread safe")

- Bill

Get the best answers to your questions -- See FAQ481-4875.
 
Yes, COM Server EXE and use events for synchronization. You can use API Sleep function (short interval) within a loop while waiting back at the VFP side for the COM server to finish if needed. Yes, it will run in it's own thread.

Example: I use this approach with a progressbar class I created, I was frustrated with the lack of smoothness in the progress bar movement I would get during single line commands that were resource intensive, so I created a COM Server EXE. Now progress bar runs really smooth even if VFP is crunching away on a single line. Both processes get enough access to the message queue that there isn't any apparent stall.

boyd.gif

 
Can you really make a VFP COM server, and call it from a main VFP program, and have that COM server execute in its own thread?

Craig is right. I use it all the time for dowloading files with WinHTTP and FTP. All COMs that run in their own "space" and the user can continue to work with the app.


Mike Gagnon

If you want to get the best response to a question, please check out FAQ184-2483 first.
 
This really opens up the possibilities:

Could either of you outline the way the pieces fit together?
Something like:

Vfp Main App (VMA): Shows A form with a button
User (U): Clicks the button "Download"
VMA: instantiates the Vfp Com Server (VCS)
VCS: starts the download -- I would think VCS would block here and not return to VMA till it finishes this entire process, since other COM servers finish running the method you call on them before the next vfp command executes...
VMA: gets control back quickly, somehow. A timer can poll VCS to see the status of the download, or VCS events can be bound to in order to give feed back on VMA's form.
U: Is happy, because VMA continues to draw its windows, and responds to his clicking on stuff.

- Bill

Get the best answers to your questions -- See FAQ481-4875.
 
Yeah, I'll outline it sometime tonight if someone doesn't beat me to it... busy doing an install and testing remotely up in Canada right now, which is why my responses so far have been somewhat cryptic and short on details.

boyd.gif

 
Just one possible scenario that works:

VCS is created consisting of:
parameters statement in the init event (receives the info necessary to download - username, password, host, remote file local file or whatever is needed)

Some properties to hold these passed parameters, one to be used to hold whether the download was cancelled, others for various bells and whistles

Method(s) that will do the actual downloading and will be used to give feedback to VMA (downloadfile, downloadcancelled, downloadcomplete, beforegetchunk, getchunk, aftergetchunk, etc)

Timer class that will fire a single time after being class is instantiated (last call in the class's init event is to set the timer's interval to something very small and the timer has code in the timer event to call the download method(s)

Vfp Main App (VMA): Shows A form with a button

User (U): Clicks the button "Download"

VMA: instantiates the Vfp Com Server (VCS) and processing is returned after instantiation

VCS: Timer event fires and download is started in this process

VMA: gets control back quickly. Either a timer is polling VCS via one of VCS methods (not the best way to do it) or VCS events can be bound to in order to give feed back on VMA's form (this is what I'd do wgcs)

U: Is happy, because VMA continues to draw its windows, and responds to his clicking on stuff.

VCS: is firing events as each chunk is downloaded and this is picked up on by VMA if events were bound...checks a property to see if the user cancelled the download

VMA: Displays the download's progress in the status bar of the VMA application or in a modeless form that has a cancel button on it... while the user can still click around and start doing other things, even starting another download (spawns as many processes as there are resources to handle via NewObject() or CreateObject() and the VCS)

VCS: Fires final method saying download is complete or download was cancelled and releases itself

VMA: Continues on it's merry way quite sure that wgcs is pleased with his handywork [smile]


boyd.gif

 
Thanks so much, Craig.

I've used a timer within a single VFP app (no COM dll), and I hadn't connected the thought that the timer could decouple the COM dll from the main app.

Do you (or anyone else) know if building an MTDLL (multi-threaded) has any impact on this? I guess there's no reason not to BUILD MTDLL instead of BUILD DLL... but does it have to be an out-of-process BUILD EXE?

- Bill

Get the best answers to your questions -- See FAQ481-4875.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top