Asynchronous Pluggable Protocols and embedded ActiveX controls (e.g. PDF)

  • Thread starter Thread starter igarrison
  • Start date Start date
I

igarrison

I have an APP that reads from a file on disk and decrypts the raw data
into the memory stream that then gets passed to the client. This works
great for any text or image files, but I can't seem to get it working
at all for PDF files. I checked the stream, and the decrypted data is
written properly to the MemoryStream (I can dump the memory stream to
disk in the APP and open it fine), but I can't even get the Acrobat
activeX control to open in the browser window. The browser displays
the 'downloading from site' in the status bar while the data is
decrypted, then just sits there (not frozen) afterward, without
displaying any errors or any content.

I figured this had something to do with needing to set the MIME type,
which I tried several times, at different points in the process, but
that doesn't seem to do anything. If I try to hardcode a MIME type of
'application/pdf', everything still displays as it always does, leading
me to believe that I'm doing something wrong. (Shouldn't any file
typed as 'application/pdf' cause the Acrobat reader to open, then throw
an error when the reader see that it's not a valid pdf?) What am I
missing?

I can post my code if that will help. Any suggestions will be greatly
appreciated and probably save my head from a lot of banging against a
wall. Thanks.
 
I have an APP that reads from a file on disk and decrypts the raw data
into the memory stream that then gets passed to the client. This
works great for any text or image files, but I can't seem to get it
working at all for PDF files. I checked the stream, and the
decrypted data is written properly to the MemoryStream (I can dump
the memory stream to disk in the APP and open it fine), but I can't
even get the Acrobat activeX control to open in the browser window.

Do you honor BINDF_NEEDFILE flag? When the client specifies this flag,
you must provide a name of the file on hard drive containing the
response. Some clients, Actobat Reader among them, don't work without
such a file.
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925
 
Igor,

Thanks for your quick reply, I see your name all over the posts I've
been looking at.

I'm pretty sure that's the problem (would that also affect saving the
file to disk using 'save target as'?) but I haven't been able to figure
out how to handle that flag. Where can I check to see if it's set, and
then return the location of the file on disk?

The files I'm getting are already stored locally in an encrypted
format. Would I be able to simply pass the path to the file as is, or
do I have to create a cached, unencrypted version for Acrobat Reader to
handle? More generally, will the cached objects be processed through
the protocol or read as a regular file by the opening client?

Thanks,

Ian Garrison
 
I'm pretty sure that's the problem (would that also affect saving the
file to disk using 'save target as'?) but I haven't been able to
figure out how to handle that flag. Where can I check to see if it's
set, and then return the location of the file on disk?

The flag is returned by IInternetBindInfo::GetBindInfo, together with
other flags and BINDINFO structure. An APP normally calls it first thing
in Start.

You report the file name with
IInternetProtocolSink::ReportProgress(BINDSTATUS_CACHEFILENAMEAVAILABLE).
The file does not have to be in the browser cache, it can be anywhere in
the file system.
The files I'm getting are already stored locally in an encrypted
format. Would I be able to simply pass the path to the file as is, or
do I have to create a cached, unencrypted version for Acrobat Reader
to handle?

The latter. It doesn't have to be "cached", whatever that means.
More generally, will the cached objects be processed
through the protocol or read as a regular file by the opening client?

Read as regular file. That's the whole point of BINDF_NEEDFILE. A client
that is content with using IInternetProtocol::Read exclusively won't set
this flag. Only clients that want to access the file directly set it.
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925
 
Ok, I called the reportprogress and now I'm getting a download dialog,
but it's telling me I can't find the server. I also tried explicitly
setting the MIME type, but that didn't help. I'm reporting the cache
like so:

IInternetProtocolSink::ReportProgress(BINDSTATUS_CACHEFILENAMEAVAILABLE,"C:\test\test2\test.pdf");

It seems that the cache file name may be getting appended to the base
URL, and that would definitely cause a problem, but I'm not sure why
that would be happening. It is also entirely possible that my flag
does not have the proper value, since I had to implement the BINDSTATUS
enum manually since I'm working in C#. I set it as:

public enum BINDSTATUS : uint
{
BINDSTATUS_FINDINGRESOURCE = 0,
BINDSTATUS_CONNECTING = BINDSTATUS_FINDINGRESOURCE + 1,
BINDSTATUS_REDIRECTING = BINDSTATUS_CONNECTING + 1,
BINDSTATUS_BEGINDOWNLOADDATA = BINDSTATUS_REDIRECTING + 1,
BINDSTATUS_DOWNLOADINGDATA = BINDSTATUS_BEGINDOWNLOADDATA + 1,
BINDSTATUS_ENDDOWNLOADDATA = BINDSTATUS_DOWNLOADINGDATA + 1,
BINDSTATUS_BEGINDOWNLOADCOMPONENTS = BINDSTATUS_ENDDOWNLOADDATA + 1,
BINDSTATUS_INSTALLINGCOMPONENTS =
BINDSTATUS_BEGINDOWNLOADCOMPONENTS + 1,
BINDSTATUS_ENDDOWNLOADCOMPONENTS = BINDSTATUS_INSTALLINGCOMPONENTS +
1,
BINDSTATUS_USINGCACHEDCOPY = BINDSTATUS_ENDDOWNLOADCOMPONENTS + 1,
BINDSTATUS_SENDINGREQUEST = BINDSTATUS_USINGCACHEDCOPY + 1,
BINDSTATUS_CLASSIDAVAILABLE = BINDSTATUS_SENDINGREQUEST + 1,
BINDSTATUS_MIMETYPEAVAILABLE = BINDSTATUS_CLASSIDAVAILABLE + 1,
BINDSTATUS_CACHEFILENAMEAVAILABLE = BINDSTATUS_MIMETYPEAVAILABLE +
1,
BINDSTATUS_BEGINSYNCOPERATION = BINDSTATUS_CACHEFILENAMEAVAILABLE +
1,
BINDSTATUS_ENDSYNCOPERATION = BINDSTATUS_BEGINSYNCOPERATION + 1,
BINDSTATUS_BEGINUPLOADDATA = BINDSTATUS_ENDSYNCOPERATION + 1,
BINDSTATUS_UPLOADINGDATA = BINDSTATUS_BEGINUPLOADDATA + 1,
BINDSTATUS_ENDUPLOADINGDATA = BINDSTATUS_UPLOADINGDATA + 1,
BINDSTATUS_PROTOCOLCLASSID = BINDSTATUS_ENDUPLOADINGDATA + 1,
BINDSTATUS_ENCODING = BINDSTATUS_PROTOCOLCLASSID + 1,
BINDSTATUS_VERFIEDMIMETYPEAVAILABLE = BINDSTATUS_ENCODING + 1,
BINDSTATUS_CLASSINSTALLLOCATION =
BINDSTATUS_VERFIEDMIMETYPEAVAILABLE + 1,
BINDSTATUS_DECODING = BINDSTATUS_CLASSINSTALLLOCATION + 1,
BINDSTATUS_LOADINGMIMEHANDLER = BINDSTATUS_DECODING + 1,
BINDSTATUS_CONTENTDISPOSITIONATTACH = BINDSTATUS_LOADINGMIMEHANDLER
+ 1,
BINDSTATUS_FILTERREPORTMIMETYPE =
BINDSTATUS_CONTENTDISPOSITIONATTACH + 1,
BINDSTATUS_CLSIDCANINSTANTIATE = BINDSTATUS_FILTERREPORTMIMETYPE +
1,
BINDSTATUS_IUNKNOWNAVAILABLE = BINDSTATUS_CLSIDCANINSTANTIATE + 1,
BINDSTATUS_DIRECTBIND = BINDSTATUS_IUNKNOWNAVAILABLE + 1,
BINDSTATUS_RAWMIMETYPE = BINDSTATUS_DIRECTBIND + 1,
BINDSTATUS_PROXYDETECTING = BINDSTATUS_RAWMIMETYPE + 1,
BINDSTATUS_ACCEPTRANGES = BINDSTATUS_PROXYDETECTING + 1,
BINDSTATUS_COOKIE_SENT = BINDSTATUS_ACCEPTRANGES + 1,
BINDSTATUS_COMPACT_POLICY_RECEIVED = BINDSTATUS_COOKIE_SENT + 1,
BINDSTATUS_COOKIE_SUPPRESSED = BINDSTATUS_COMPACT_POLICY_RECEIVED +
1,
BINDSTATUS_COOKIE_STATE_UNKNOWN = BINDSTATUS_COOKIE_SUPPRESSED + 1,
BINDSTATUS_COOKIE_STATE_ACCEPT = BINDSTATUS_COOKIE_STATE_UNKNOWN +
1,
BINDSTATUS_COOKIE_STATE_REJECT = BINDSTATUS_COOKIE_STATE_ACCEPT +
1,
BINDSTATUS_COOKIE_STATE_PROMPT = BINDSTATUS_COOKIE_STATE_REJECT +
1,
BINDSTATUS_COOKIE_STATE_LEASH = BINDSTATUS_COOKIE_STATE_PROMPT + 1,
BINDSTATUS_COOKIE_STATE_DOWNGRADE = BINDSTATUS_COOKIE_STATE_LEASH +
1,
BINDSTATUS_POLICY_HREF = BINDSTATUS_COOKIE_STATE_DOWNGRADE + 1,
BINDSTATUS_P3P_HEADER = BINDSTATUS_POLICY_HREF + 1,
BINDSTATUS_SESSION_COOKIE_RECEIVED = BINDSTATUS_P3P_HEADER + 1,
BINDSTATUS_PERSISTENT_COOKIE_RECEIVED =
BINDSTATUS_SESSION_COOKIE_RECEIVED + 1,
BINDSTATUS_SESSION_COOKIES_ALLOWED =
BINDSTATUS_PERSISTENT_COOKIE_RECEIVED + 1,
BINDSTATUS_CACHECONTROL = BINDSTATUS_SESSION_COOKIES_ALLOWED + 1,
BINDSTATUS_CONTENTDISPOSITIONFILENAME = BINDSTATUS_CACHECONTROL + 1,
BINDSTATUS_MIMETEXTPLAINMISMATCH =
BINDSTATUS_CONTENTDISPOSITIONFILENAME + 1,
BINDSTATUS_PUBLISHERAVAILABLE = BINDSTATUS_MIMETEXTPLAINMISMATCH +
1,
BINDSTATUS_DISPLAYNAMEAVAILABLE = BINDSTATUS_PUBLISHERAVAILABLE + 1
}

I'm considering dropping the entire C# approach and trying to tackle
the APP in C++, but I don't have much experience on that front.
 
Ok, I called the reportprogress and now I'm getting a download dialog,
but it's telling me I can't find the server. I also tried explicitly
setting the MIME type, but that didn't help. I'm reporting the cache
like so:

IInternetProtocolSink::ReportProgress(BINDSTATUS_CACHEFILENAMEAVAILABLE,"C:\test\test2\test.pdf");

Should be "C:\\test\\test2\\test.pdf"

"\t" is a tab character.
It seems that the cache file name may be getting appended to the base
URL, and that would definitely cause a problem, but I'm not sure why
that would be happening. It is also entirely possible that my flag
does not have the proper value, since I had to implement the
BINDSTATUS enum manually since I'm working in C#. I set it as:

public enum BINDSTATUS : uint
{
BINDSTATUS_FINDINGRESOURCE = 0,

BINDSTATUS_FINDINGRESOURCE = 1

All your constants are off by 1. Look up the correct definition in
urlmon.h
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925
 
I really appreciate your help!

But there's a very strange problem. If i insert other activeX control
stuff in html like .avi .wmv etc. it works fine, My appserver can
successfully receive the request for downloading the media files
(IInternetProtocolRoot::Start) and I can set parameters for
ReportProgress .But when i insert a Flash Media into html,I found No
request for IInternetProtocolRoot::Start after i finished sending the
text content,so I have no chance to
IInternetProtocolSink::ReportProgress, that's really strange! I check
my system if I disabled the flash Conrol before ,but no clues, I can
play flash media in IE.

I just wondering if FlashActiveX control is different from others? I
wrote html codes in Dreamweaver ,and the html codes are like this:

<html>
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,29,0"
width="471" height="313">
<param name="movie" value="20050225b.swf">
<param name="quality" value="high">
<embed src="20050225b.swf" quality="high"
pluginspage="http://www.macromedia.com/go/getflashplayer"
type="application/x-shockwave-flash" width="471" height="313"></embed>
</object>
</html>

I sent this html text data to client IE , and found no request for
downloading.

I guess if I should set something in client IE? or I just ignored some
other request way from client.

Did you handle flash and some other activeX control use the same way?

many thanx for finish reading my letters:D you "save my head from a lot
of banging against a
wall." Thanks.
 
But there's a very strange problem. If i insert other activeX control
stuff in html like .avi .wmv etc. it works fine, My appserver can
successfully receive the request for downloading the media files
(IInternetProtocolRoot::Start) and I can set parameters for
ReportProgress .But when i insert a Flash Media into html,I found No
request for IInternetProtocolRoot::Start

I believe Flash does not use URLMon for its download needs. It goes
directly through WinInet, or even WinSock. An APP can only catch
requests made through URL monikers, naturally.
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925
 
thanx for your quick reply!

and I get another BIG problem with the mediaplayer. when I start to
play the media in the page, media player get me a warning box said file
extension is not correct according to the file stream! And if i
proceed, the media played just fine in the media player. After that no
matter how many times I press the "play" button on media player panel,I
get no warning.

I traced into the code and found this problem only happened when the
app program process the html page which containing the media. I don't
why the first time the media player said it's a wrong file extension!
Did I missed something special ? or I passed a wrong url to the media
player ? thanx a lot !

I solved the problem with flash , it's A BUG of flash activex I
believe.
flash return a mess up url for app programs as it said in Macromedia's
BBS.
Check this function
HRESULT CombineUrl( LPCWSTR pwzBaseUrl,
LPCWSTR pwzRelativeUrl,
DWORD dwCombineFlags,
LPWSTR pwzResult,
DWORD cchResult,
DWORD *pcchResult,
DWORD dwReserved
);
the parameter pwzRelativeUrl should like this
"file:///yourprotocolname:|%FyourflashfileName" when the flash calls
for downloading. so I recombined the url to correct form and it works
just fine!
sample codes ( delphi)

function TeapProtocol.CombineUrl(pwzBaseUrl, pwzRelativeUrl: PWideChar;
dwCombineFlags: DWORD; pwzResult: PWideChar; cchResult: DWORD;
out pcchResult: DWORD; dwReserved: DWORD): HResult;
var
rUrl : string;
begin
rUrl := TIdUri.URLDecode(pwzRelativeUrl);
//bugged flash format
if (pos('file:///',rUrl)<>0) and ( pos(PROTOCOL_SCHEME,rUrl)<>0) then
begin
rUrl := midbstr(rUrl,Length('file:///')+1,length(rUrl));
rUrl := StringReplace(rUrl,'|',':',[rfReplaceAll]);
stringtowidechar(rUrl,pwzResult,Length(rUrl)*2);
pcchResult := Length(rUrl)*2;
result := S_OK;
end
end;
 
and I get another BIG problem with the mediaplayer. when I start to
play the media in the page, media player get me a warning box said
file extension is not correct according to the file stream! And if i
proceed, the media played just fine in the media player. After that no
matter how many times I press the "play" button on media player
panel,I get no warning.

I traced into the code and found this problem only happened when the
app program process the html page which containing the media.

Do you report correct MIME type with
ReportProgress(BINDSTATUS_MIMETYPEAVAILABLE) ?
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925
 
Really appreciate your reply!

For example I have a html page named 1.html and it contains the 1.wmv
file.

1.at the begining IE ask my appserver for downlaoding 1.html ,I
received the request for parsing the URL (lot of times, most of time I
return the default flag INET_E_DEFAULT_ACTION).

2.After I parsed the url ,it called QueryInfo , i return S_OK most of
the time and do nothing meaningful, And then it called combineurl with
the params:
pwzBaseUrl="eapp://sitename/1.html"
pwzRelativeUrl= "1.wmv"
(here I tried to manually change the pwzResult to
"eapp://sitename/1.wmv" or let it to default process,both are failed.)
I return S_OK and let it to default process.

3. Then IE called the parseUrl again with the params pwzUrl =
"eapp://sitename/1.html";(is here a problem?)

4.I begin to read the file stream for 1.html and sent to IE and I use
this ReportProgress( BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE,
wcStatus) just like handling other htmls .After all html
content completed, IE or mediaplayer give me a warning message box to
tell me the file extension problem

5.I press yes to continue, I press the play button on media player
panel in IE . IE start to request my appserver for
"eapp://sitename/1.wmv" and this time everything works just fine.

so many thanx for your help
 
and I get another BIG problem with the mediaplayer. when I start to
play the media in the page, media player get me a warning box said
file extension is not correct according to the file stream! And if i
proceed, the media played just fine in the media player. After that no
matter how many times I press the "play" button on media player
panel,I get no warning.

What is the exact text of the error message?
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925
 
the full error message is :

the file you are attempting to play has an extension that does not
match the file format. playing the file may result in unexpected
behavior

you want play to try to play the file ?

[ ]don't ask me again for this extension

[yes] [no]

thanx~
 
the full error message is :

the file you are attempting to play has an extension that does not
match the file format. playing the file may result in unexpected
behavior

Try not implementing IInternetProtocolInfo at all. Most of the time, it
is not needed (e.g. built-in HTTP handler does not implement it). I
suspect you implement it incorrectly (it is pretty difficult to get
right) and there is some confusion as to exactly what URL you are
providing data for.
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925
 
thanx igor !

ok I comment all my codes for implementing the IInternetProtocolInfo
but the problem is still exist

my html text simplely like this :
<HTML>
<object width="400" height="300">
<embed src="1.wmv" width="400" height="300"></embed>
</object>
</html>

It is suposed to autoplay the 1.wmv when the whole page loaded.but just
after read function finished I get that warning ,and if I continue it
works fine.

have you ever expereinced the same problem before? I was totally lost
.... and try to find a way out :D
 
i found some different compare with flash object

eg.
flash steps
1.flash calls combineurl(pwzBaseUrl, pwzRelativeUrl...) with
('eapp://sitename/1.htm','1.swf')
2.calls parseurl(pwzUrl ,ParseAction,...)
with('eapp://sitename/1.swf',1);
3.call the downlaoding process as usual.

wmv steps
1. calls combineurl(pwzBaseUrl, pwzRelativeUrl...) with
('eapp://sitename/1.htm','1.wmv')
2.calls parseurl(pwzUrl ,ParseAction,...)
with('eapp://sitename/1.HTM',PARSE_DOMAIN );
3.errorbox!

should I parse the domain for it ? I use the default process return a
simple '' value.I tried to parse domain but failed it seems the problem
is not there
 
i found some different compare with flash object

eg.
flash steps
1.flash calls combineurl(pwzBaseUrl, pwzRelativeUrl...) with
('eapp://sitename/1.htm','1.swf')
2.calls parseurl(pwzUrl ,ParseAction,...)
with('eapp://sitename/1.swf',1);
3.call the downlaoding process as usual.

wmv steps
1. calls combineurl(pwzBaseUrl, pwzRelativeUrl...) with
('eapp://sitename/1.htm','1.wmv')
2.calls parseurl(pwzUrl ,ParseAction,...)
with('eapp://sitename/1.HTM',PARSE_DOMAIN );
3.errorbox!

should I parse the domain for it ? I use the default process return a
simple '' value.
 
i found some different compare with flash object

eg.
flash steps
1.flash calls combineurl(pwzBaseUrl, pwzRelativeUrl...) with
('eapp://sitename/1.htm','1.swf')
2.calls parseurl(pwzUrl ,ParseAction,...)
with('eapp://sitename/1.swf',1);
3.call the downlaoding process as usual.

wmv steps
1. calls combineurl(pwzBaseUrl, pwzRelativeUrl...) with
('eapp://sitename/1.htm','1.wmv')

What do you return at this point? You should produce
'eapp://sitename/1.wmv

Again, try not implementing IInternetProtocolInfo. Not just leave
methods unimplemented, but actually remove it from your interface map
(or whatever it is in your framework) so that QueryInterface for it
fails.
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925
 
wmv steps
1. calls combineurl(pwzBaseUrl, pwzRelativeUrl...) with
('eapp://sitename/1.htm','1.wmv')
What do you return at this point? You should produce
'eapp://sitename/1.wmv

at this point I tried two ways
1. let it to default
2.manually produced "eapp://sitename/1.wmv" to pwzResult

both are failed. the client call parseUrl function with
''eapp://sitename/1.HTM" all the time
question : if I manually changed the pwzResult to
"eapp://sitename/1.wmv" ,should the parseUrl function use the pwzResult
as pwzUrl's value next time?

and yes! I followed your instructions dissabled all of my codes for
implementing IInternetProtocolInfo using "// "
Unfortunately I failed again. After the program finished sending the
1.htm , the warning box show out.

btw: have you ever experenced the problem before? when you playing
media files using media player though app .
I just feel it was so odd that only me have this problem....
 
Back
Top