Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Binary Stream from Unicode String - ADODB.Stream arguments wrong 1

Status
Not open for further replies.

ESquared

Programmer
Dec 23, 2003
6,129
US
I am trying to return a binary file through ASP (it will be created from a database query) and am having trouble with the conversion to binary data (ascii string instead of unicode). If in fact there's a better way then this I'd love to hear it (I know this method can have a problem with large files but I won't be reaching anywhere near that size).

I am getting an error:

[ul]ADODB.Stream (0x800A0BB9)
Arguments are of the wrong type, are out of acceptable range, or are in conflict with one another.[/ul]

with the following code (pared down to bare minimum). Erroring line is in blue. I've done web searches on this error but what turned up was unhelpful.

Code:
<HTML><HEAD></HEAD>
<BODY></BODY>
</HTML>
<%@LANGUAGE="VBSCRIPT" CODEPAGE="1252"%>
<%
Function StringToMultiByte(S)
  Dim i, MultiByte
  For i=1 To Len(S)
    MultiByte = MultiByte & ChrB(Asc(Mid(S,i,1)))
  Next
  StringToMultiByte = MultiByte
End Function

Sub WriteStream(TheStream, TheText)
[blue]   TheStream.Write StringToMultiByte(TheText)[/blue]
End Sub

Dim oStream

Set oStream = Server.CreateObject("ADODB.Stream")
oStream.Open
oStream.Type = 1 ' 1=binary 2=text

WriteStream oStream, "<html xmlns:x=""urn:schemas-microsoft-com:office:excel""><head><meta http-equiv=Content-Type content=""text/html; charset=us-ascii"">"
WriteStream oStream, "{more excel html document building code which works fine}"
WriteStream oStream, "</html>"
oStream.Position = 0

Response.Clear
Response.AddHeader "Content-Disposition", "attachment; filename=MyFileName.xls"
Response.AddHeader "Content-Length", oStream.Size
Response.ContentType = "application/octet-stream"
Response.CharSet = "UTF-8"
Response.BinaryWrite oStream.Read
Response.Flush

oStream.Close
Set oStream = Nothing
%>
I could do this as text, but I felt it was better to do it as binary, since I cannot guarantee that the data I'll get from the database will never be above 127. For that matter, I'd be interested to know how to do unicode, but I suppose that's another question entirely.

I've searched many a web site for help on this and I haven't been able to find where I'm going wrong. The StringToMultiByte function is lifted intact from some page or other online. The response clearing, writing, content type and header stuff works fine.
 
... a better way then this ..."

shameful.
 
Try setting the mode on your stream when you open it:
Out of curiosity, why is it necessary to use the stream at all? Couldn't you just:
Code:
Dim myData
myData = "<html xmlns:x=""urn:schemas-microsoft-com:office:excel""><head><meta http-equiv=Content-Type content=""text/html; charset=us-ascii"">{more excel html document building code which works fine}</html>"

Response.BinaryWrite StringToMultiBye(myData)

Another question, why not just Response.Write the text? If you have already set the character type and so on, I would think it shouldn't be necessary to write the data in binary.

 
Specifying mode when I open the stream doesn't seem to work. It just throws errors on the open line:

oStream.Open , 3
oStream.Open , 3, 1

I also tried moving the oStream.Type setting ahead of Open.

The point is that I wanted the client to know how many bytes it could be expecting (Content-Length) so the download window would show progress correctly. In order to do that I have to "materialize" the bytes into a stream that isn't sent, then I know the length, then I can send it.

The second reason for how I'm doing it is that I do want speed and it is my understanding that concatenation is far slower than repeated response or stream writes.

I am eventually going to rewrite the StringToMultiByte function so it works in chunks using Mid() instead of concatenating. But I want to get it WORKING first, then I can fiddle.

If I use text mode for the stream everything works fine. It's only in binary mode that I get errors.




 
I just noticed all of that HTML above your ASP file. While your Response.Clear will clear that content out, it would probably be a lot better to just remove it yourself and get rid of the Response.Clear. That HTML and Clear are just extra work for the system.

Another option, to keep the stream and it's size capability, would be to let the stream object do the conversion from text to binary for you. This way you still get the size for your headers, but you don't have to worry about doing the conversion in VBScript, which doesn't handle binary data well.

It's easier to show then to describe:
Code:
<%
Dim oStream
Set oStream = Server.CreateObject("ADODB.Stream")

'--- initially open as text for writing
oStream.Type = 2 ' 1=binary 2=text
oStream.Open

'--- write text data
oStream.WriteText "<html xmlns:x=""urn:schemas-microsoft-com:office:excel""><head><meta http-equiv=Content-Type content=""text/html; charset=us-ascii"">"
oStream.WriteText "{more excel html document building code which works fine}"
oStream.WriteText "</html>"

'--- change stream to binary for reading
oStream.Position = 0
oStream.Type = 1

'--- output content
'Response.Clear
Response.AddHeader "Content-Disposition", "attachment; filename=MyFileName.xls"
Response.AddHeader "Content-Length", oStream.Size
Response.ContentType = "application/octet-stream"
Response.CharSet = "UTF-8"
Response.BinaryWrite oStream.Read
Response.Flush

oStream.Close
Set oStream = Nothing
%>

So basically what i am doing is opening the stream as text to begin with. Then I write the data as text into the stream. At this point I change it to binary and read that data back out. Basically treating the stream as a text-to-binary transformer.

Hope this was what you were looking for,
-T

 
Tarwn,

Thanks for the help. I was in fact late yesterday getting an inkling that my problem was trying to use a binary array with a stream object, when in the web pages I saw they were using it with the response object.

Just chalk it up to having minimal ASP experience, I suppose! I love getting good at things, but it's not always as fast as I'd like.

Have a star.
 
Oh... and the extra HTML exists because I was thinking about putting some message like "creating file.
 
Unfortunately you would need two pages to do that. You can only push data for a single file at a time, whether it be HTML to display on the browser or binary data for an excel file.
However, it would not be too difficult to write a little HTML file that has some javascript embedded in it that displayed a "please wait message" and then redirect client-side to the excel downloader.
Even better, you could use the onClick for whatever button or link the user is pressing to get to this page to display a div that has the please wait message. That way you don't have to build an intermediary page.

-T

 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top