Solved

Capture output of ISAPI filter

Posted on 2001-08-06
15
282 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
 
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 300 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
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 
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

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

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

Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
This Micro Tutorial will teach you how to censor certain areas of your screen. The example in this video will show a little boy's face being blurred. This will be demonstrated using Adobe Premiere Pro CS6.
With the power of JIRA, there's an unlimited number of ways you can customize it, use it and benefit from it. With that in mind, there's bound to be things that I wasn't able to cover in this course. With this summary we'll look at some places to go…

920 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

16 Experts available now in Live!

Get 1:1 Help Now