Solved

Capture output of ISAPI filter

Posted on 2001-08-06
15
276 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
Comment Utility
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
Comment Utility
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
Comment Utility
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
 
LVL 14

Expert Comment

by:AvonWyss
Comment Utility
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
Comment Utility
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 300 total points
Comment Utility
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
Comment Utility
sxh see: www.matlus.com
ziolko.
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 1

Author Comment

by:sxh
Comment Utility
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
Comment Utility
thanks ziolko for the link, this will take me some time to get through.

regards

sxh
0
 
LVL 1

Author Comment

by:sxh
Comment Utility
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
Comment Utility
why can't i increase the points??

sxh
0
 
LVL 14

Expert Comment

by:AvonWyss
Comment Utility
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
Comment Utility
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
Comment Utility
thanks avonwys
0
 
LVL 14

Expert Comment

by:AvonWyss
Comment Utility
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

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

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…
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…
You have products, that come in variants and want to set different prices for them? Watch this micro tutorial that describes how to configure prices for Magento super attributes. Assigning simple products to configurable: We assigned simple products…

771 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

Need Help in Real-Time?

Connect with top rated Experts

14 Experts available now in Live!

Get 1:1 Help Now