How to use TClientSocket within TWebModule (CGI)?

htarnoff
htarnoff used Ask the Experts™
on
Hi,

Does anyone know the how to structure a CGI-based web server application (TWebModule) so that it can issue a TCP/IP request to a separate server and wait for a response?  

Here's some detail on what I would like to have happen:

1. A WebModule application is executed on web server A in response to an HTML form action.

2. This WebModule, invoked on web server A, needs to interact with another web server B to obtain data.  I choose to have the WebModule pass a TCP/IP request through a TClientSocket and wait for a response from the server (using the OnRead event).  The server B is running a normal Delphi application that utilizes a TServerSocket.

3. Equipped with the data from web server B, the WebModule can then complete its response to the original form action through Response (TWebResponse).

I have (1) and (3), and server B's application working fine.  It is the WebModule's TClientSocket of (2) that complicates things.  As I have come to learn, unlike a standard Delphi application (TApplication) which has message queue processing, TWebApplications do not.  Thus, the events OnConnect, OnError, OnRead, etc. do not fire.  

If I rewrite the application as a normal Delphi application (with a different user interface of course), the whole process then works fine thanks to the inherent VCL message queue processing.  Unfortunately, this is not the proper form for a web server cgi executable.

I have tried a number of things including placing the communications logic to server B in a separate thread, and even trying to write my own WndProc method, but the results are always the same - no event firing.  I know its possible because I see server requests routinely interact with other servers to form responses (such as W3C's HTML validation service at http://validator.w3.org/ - you provide a URL and it tells you what parts of an HMTL page do not meet the spec.)

Can someone help shed some light on this issue?  BTW, I am using Delphi 5 Professional.  Thank you in advance.
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
I'm prefer the blocking sockets in another thread. You may use this approach and so you don't need the window procedure

Author

Commented:
stepashka, I am not quite sure what you mean.  Would I be using TClientSocket or some other object?  I did try it a separate thread for TClientSocket, but I believe treads are "owned" by the main thread which, in this case, has no message queue and therefore no event processing.  Perhaps you could provide an example. Thank you
Commented:
Hi,

I solved my problem, but I thought to follow-up here on my own question for other programmers with a similar problem.

Looking at the VCL Source for TApplication (the application type that works fine), we notice that the hierarchy for TApplication is

TObject
       |
TPersistent
       |
TComponent

while the hierarcy of TCGIApplicaton (the application type that doesn't hear messages) is

TObject
       |
TPersistent
       |
TComponent
       |
TWebApplication

So, a TApplication and a TCGIApplication have extremly similar ancestries and should be highly compatible.  Therefore, it becomes a matter of identifying the missing ingredient in TApplication and providing it in a compatible form to TCGIApplication.  In other words, while Application.ProcessMessages exists in TApplication and not in TCGIApplication, it should be possible to construct a similar method to process Window messages in TCGIApplication.

To make a long story short, add the following AltProcessMessages method to a TCGIApplication class and call it instead of Application.ProcessMessages (which doesn't exist in a TCGIApplication).  It is possible that this solution works for TISAPIApplication and other non-standard Delphi application types.

procedure TMyThread.AltProcessMessages;
  -or-
procedure TMyWebModule.AltProcessMessages;
var
  Msg: TMsg;
  HadMessage: boolean;
begin
  { simulate Application.ProcessMessages behavior }
  repeat
    HadMessage := PeekMessage(Msg, 0, 0, 0, PM_REMOVE);
    if HadMessage and (Msg.Message <> WM_QUIT) then begin
      TranslateMessage(Msg);
      DispatchMessage(Msg);
    end;
  until not HadMessage;
end;

If you have any suggestions or improvements, I would like to hear about them.  Feel free to contact me, Harry Tarnoff, at <email address removed>
Rowby Goren Makes an Impact on Screen and Online

Learn about longtime user Rowby Goren and his great contributions to the site. We explore his method for posing questions that are likely to yield a solution, and take a look at how his career transformed from a Hollywood writer to a website entrepreneur.

I ment, I use the blocking sockets, so I don't need the message loop. But I see you find more apropriate decision for yourself so I think the question is over.
htarnoff:
This old question needs to be finalized -- accept an answer, split points, or get a refund.  For information on your options, please click here-> http:/help/closing.jsp#1 
EXPERTS:
Post your closing recommendations!  No comment means you don't care.

Commented:
Removed email address from #7491933

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial