Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
?
Solved

Capture output of ISAPI filter

Posted on 2001-08-06
15
Medium Priority
?
332 Views
Last Modified: 2010-04-06
hi

I have an isapi dll plugged into iis5.0 that converts word documents to html as the docs are requested. The ddl app also has an administration interface and cache's docs.

What i need from you guys and gals is ideas and delphi code for ways in which I can capture the output of this dll e.g. the html, parse this html and add my own html into the result that gets put back to the user.

I don't have the source code of the original conversion dll, so i'm guessing i need some kind of 'wrapper' dll to do this.

many thanks

sxh
0
Comment
Question by:sxh
  • 9
  • 5
15 Comments
 
LVL 14

Expert Comment

by:AvonWyss
ID: 6358521
I think you're on the right track. Actually, your DLL will be the only one running directly in IIS. It will act like a proxy, that is, do the call to the original DLL itself and return the enhanced output back to the server.

Are you sure it's a filter DLL? Custom filters are VERY rare, what you usually have are just extension DLL's.
0
 
LVL 1

Author Comment

by:sxh
ID: 6358795
thanks avonwyss

You're probably right about the operation of the dll. It is the only isapi extension on the web site.
0
 
LVL 1

Author Comment

by:sxh
ID: 6358807
to clarify requirements a bit further:

The dll returns html code from the converted word document. What I need to do initially, is add ALT tags to any image tags as this can not be acheived in the word document in word. There is an alternative text tab in format picture, but this does not appear in the final conversion.

So what I need to do is let the isapi dll do it's stuff but before handing back to the server, interupt it and add my own ALT tags by parsing the html stream/string.

regards

sxh
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
LVL 14

Expert Comment

by:AvonWyss
ID: 6359241
sxh, do you have some experience in DLL programming? If yes, I think it may be easiest to write an intermediate extension DLL which in turn calls the original one and makes the needed modifications to the output.

Web server <-> Your DLL <-> Original DLL

How extension DLLs work and are developed you can read here:
http://msdn.microsoft.com/library/en-us/iisref/html/psdk/asp/isgu1ecz.asp

THe ISAPI "header" files are included with Delphi.

To debug ISAPI, this link may give you some hints:
http://support.microsoft.com/support/kb/articles/Q183/4/80.ASP

0
 
LVL 1

Author Comment

by:sxh
ID: 6359597
hi avonwyss

I have'nt written isapi extensions before which is why i asked for code. Microsoft are geared toward c++ dev for isapi stuff which I do not have, which is why it is posted here.

Your'e right in defining I need a wrapper dll but how do I do this using delphi? Is there a function for calling and capturing the output of the original dll?

regards

sxh
0
 
LVL 14

Accepted Solution

by:
AvonWyss earned 900 total points
ID: 6361092
The basic idea doesn't change whether you're using C++ or Delphi; in fact, it's just the way the code is written which is different, but all the declarations and such stay valid for both C and Delphi.

This said, have a look at http://msdn.microsoft.com/library/en-us/iisref/html/psdk/asp/isre3lrn.asp
It lists the two (or optionally three) entry functions the DLL has to export (for informations about how to write DLL's in Delphi and what exported functions are, look at the Delphi help).

GetExtensionVersion will be called upon initialization of the DLL. Here your extenmsion has to fill its proper name and version and return TRUE as result code. Actually, if you return false, the extension is not loaded; thus, you can cancel the execution of the DLL if there's something wrong (like the original DLL is missing or so).

TerminateExtension is optional and allows your DLL to know when the extension is unloaded from the web server. This function is used to clean up allocated resources and such; but probably you won't need to put code of your own in this one for this specific project.

HttpExtensionProc is the core function. It ets called everytime a request was made at the web server which is to be handled by the DLL. In the ECB (Extension Control Block) you get all the unformation about the request as well as some pointers to callback functions which you can use to communicate with the web server. The content of the page is returned via either the WriteClient callback or the ServerSupportFunction callback.

For your specfic task, you have to provide all the information unchanged to the original DLL and call its functions (specially the HttpExtensionProc). To be able to intercept and change the data written by the original DLL, you have to replace both WriteClient and ServerSupportFunction to reflect this.
0
 
LVL 21

Expert Comment

by:ziolko
ID: 6363363
sxh see: www.matlus.com
ziolko.
0
 
LVL 1

Author Comment

by:sxh
ID: 6363593
hi avonwys

I think that building a standard isapi extension would be pretty easy given the amount of samples and code available from different sites, however I need to know how to call my conversion dll, allow it to do it's stuff, capture it's output, add my stuff, and as you say return the result to the server using writeclient etc.

regards

sxh
0
 
LVL 1

Author Comment

by:sxh
ID: 6363597
thanks ziolko for the link, this will take me some time to get through.

regards

sxh
0
 
LVL 1

Author Comment

by:sxh
ID: 6363602
I have increased points to allow coders to do their stuff. Please provide code samples from now on. I will increase points upto a max of 2,500 for good working examples.

regards

sxh
0
 
LVL 1

Author Comment

by:sxh
ID: 6363603
why can't i increase the points??

sxh
0
 
LVL 14

Expert Comment

by:AvonWyss
ID: 6363618
EE has been limited to a max of 300 points per question. So if you want to award more points, you'll have to post additional "123 points for AnyOne" questions after the Q has been resolved.

If you want to offer 2500 points for a working solution, I could do the job and give you the source code. Email me at avw@gmx.ch for details.
0
 
LVL 1

Author Comment

by:sxh
ID: 6364743
I have just realised that I can do this using DOM at the page level.

Many thanks to all

sxh

0
 
LVL 1

Author Comment

by:sxh
ID: 6364751
thanks avonwys
0
 
LVL 14

Expert Comment

by:AvonWyss
ID: 6367184
sxh, thanks for the points.

Since I already started implementing the DLL, I'll just post the untested code here - maybe you or someone buying the PAQ can benefit from it someday. However, I don't expect you to give me more points for it, since your Q was solved another way around.


// PageProxy ISAPI DLL
// Allows to modify content created by another ISAPI DLL before it is returned to the server
// (C) 2001 by AvonWyss - avw@gmx.ch

library PageProxy;

uses
      Windows,
      SysUtils,
      Classes,
      ISAPI;

const
      ProducerISAPI='TEST.DLL'; // The DLL which produces the original page content

type
      TExtensionBlockList=class;
      TExtensionBlockObject=class
      private
            FOwner: TExtensionBlockList;
            FContext: PEXTENSION_CONTROL_BLOCK;
            FClone: TEXTENSION_CONTROL_BLOCK;
      public
            property Context: PEXTENSION_CONTROL_BLOCK read FContext;
            function WriteData(Buffer: Pointer; var Bytes: DWORD): Boolean;
            constructor Create(AOwner: TExtensionBlockList; ABlock: PEXTENSION_CONTROL_BLOCK);
            destructor Destroy; override;
      end;
      TExtensionBlockList=class
      private
            FList: TList;
            FLock: TRTLCriticalSection;
      public
            constructor Create;
            destructor Destroy; override;
            function LookUp(ConnID: HCONN): TExtensionBlockObject;
            function Allocate(ABlock: PEXTENSION_CONTROL_BLOCK): TExtensionBlockObject;
      end;
      TGetExtensionVersion=function(var Ver: THSE_VERSION_INFO): LongBool stdcall;
      THttpExtensionProc=function(var ECB: TEXTENSION_CONTROL_BLOCK): Cardinal stdcall;
      TTerminateExtension=function(dwFlags: DWORD): LongBool; stdcall;

var
      BlockList: TExtensionBlockList;
      ProducerInstance: THandle;
      ProducerExtensionProc: THttpExtensionProc;

{ Global functions }

function WriteDataFunc(ConnID: HCONN; Buffer: Pointer; var Bytes: DWORD; dwReserved: DWORD): LongBool; stdcall;
begin
      Result:=BlockList.LookUp(ConnID).WriteData(Buffer,Bytes);
end;

function ServerSupportFunc(ConnID: HCONN; HSERRequest: DWORD; Buffer: Pointer; var Size: DWORD; var DataType: DWORD): LongBool; stdcall;
var
      ExtensionBlock: TExtensionBlockObject;
begin
      ExtensionBlock:=BlockList.LookUp(ConnID);
      Result:=ExtensionBlock.Context.ServerSupportFunction(ConnID,HSERRequest,Buffer,Size,DataType);
      if HSERRequest=HSE_REQ_DONE_WITH_SESSION then
            ExtensionBlock.Free;
end;

function GetExtensionVersion(var Ver: THSE_VERSION_INFO): LongBool; stdcall;
begin
      ProducerInstance:=LoadLibrary(ProducerISAPI);
      if ProducerInstance<>0 then begin
            Result:=TGetExtensionVersion(GetProcAddress(ProducerInstance,'GetExtensionVersion'))(Ver);
            if Result then begin
                  ProducerExtensionProc:=GetProcAddress(ProducerInstance,'HttpExtensionProc');
                  BlockList:=TExtensionBlockList.Create;
            end else
                  FreeLibrary(ProducerInstance);
      end else
            Result:=False;
end;

function HttpExtensionProc(var ECB: TEXTENSION_CONTROL_BLOCK): Cardinal; stdcall;
var
      ContextInstance: TExtensionBlockObject;
begin
      ContextInstance:=BlockList.Allocate(@ECB);
      Result:=ProducerExtensionProc(ContextInstance.FClone);
      if Result<>HSE_STATUS_PENDING then
            ContextInstance.Free;
end;

function TerminateExtension(dwFlags: DWORD): LongBool; stdcall;
var
      Original: Pointer;
begin
      Original:=GetProcAddress(ProducerInstance,'TerminateExtension');
      if Assigned(Original) then
            TTerminateExtension(Original)(dwFlags);
      FreeLibrary(ProducerInstance);
      BlockList.Free;
      Result:=True;
end;

exports
      GetExtensionVersion,
      HttpExtensionProc,
      TerminateExtension;

{ TExtensionBlockObject }

constructor TExtensionBlockObject.Create(AOwner: TExtensionBlockList; ABlock: PEXTENSION_CONTROL_BLOCK);
begin
      FOwner:=AOwner;
      FContext:=ABlock;
      FClone:=FContext^;
      FClone.WriteClient:=WriteDataFunc;
      FClone.ServerSupportFunction:=ServerSupportFunc;
      EnterCriticalSection(FOwner.FLock);
      FOwner.FList.Add(self);
      LeaveCriticalSection(FOwner.FLock);
end;

destructor TExtensionBlockObject.Destroy;
begin
      EnterCriticalSection(FOwner.FLock);
      FOwner.FList.Remove(self);
      LeaveCriticalSection(FOwner.FLock);
end;

function TExtensionBlockObject.WriteData(Buffer: Pointer; var Bytes: DWORD): Boolean;
begin
      // process the data here and send it to Context.WriteClient()
      Result:=Context.WriteClient(Context.ConnID,Buffer,Bytes,0);
end;

{ TExtensionBlockList }

function TExtensionBlockList.Allocate(ABlock: PEXTENSION_CONTROL_BLOCK): TExtensionBlockObject;
begin
      Result:=TExtensionBlockObject.Create(self,ABlock);
end;

constructor TExtensionBlockList.Create;
begin
      InitializeCriticalSection(FLock);
      FList:=TList.Create;
end;

destructor TExtensionBlockList.Destroy;
begin
      FList.Free;
      DeleteCriticalSection(FLock);
end;

function TExtensionBlockList.LookUp(ConnID: HCONN): TExtensionBlockObject;
var
      I: Integer;
begin
      Result:=nil;
      EnterCriticalSection(FLock);
      for I:=0 to FList.Count-1 do
            if TExtensionBlockObject(FList[I]).Context.ConnID=ConnID then begin
                  Result:=FList[I];
                  Break;
            end;
      LeaveCriticalSection(FLock);
      if not Assigned(Result) then //make sure that the connection is known
            Abort;
end;

end.
0

Featured Post

[Webinar On Demand] Database Backup and Recovery

Does your company store data on premises, off site, in the cloud, or a combination of these? If you answered “yes”, you need a data backup recovery plan that fits each and every platform. Watch now as as Percona teaches us how to build agile data backup recovery plan.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
Integration Management Part 2
In a question here at Experts Exchange (https://www.experts-exchange.com/questions/29062564/Adobe-acrobat-reader-DC.html), a member asked how to create a signature in Adobe Acrobat Reader DC (the free Reader product, not the paid, full Acrobat produ…
Suggested Courses
Course of the Month10 days, 19 hours left to enroll

572 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question