Compressed SQL doc opens with .NET FileStream as a page of squares
-
sexta-feira, 9 de março de 2012 22:01
We have some documents (.doc) that were saved into a SQL database as compressed images.
I wrote a vb.net program that can view the documents. It uses a reader and decompresses the sql blob to an outputStream and displays the document after a Response.Flush. We sent the code and databases to another group to host this website themselves. They can run the website but when they view the documents the documents open with a page full of small squares. I believe the data is not getting decompressed. Their SQL server has a 64 bit Operating System and we have a 32 bit Operating System. Can a compressed document stored in a 32 bit server be successfully opened in a 64 bit server? We have the same version of Word, .Net Framework and the exact same data and code. Any help, or suggestions would be greatly appreciated!
- Editado mpls_bren sexta-feira, 9 de março de 2012 22:08
Todas as Respostas
-
segunda-feira, 12 de março de 2012 07:52Moderador
Hi Mpls_bren,
Welcome to the MSDN forum.
The DOC format varies among Microsoft Office Word Formats. It’s not related to your OS version. So I think there may be something wrong with the compressing and decompressing. I’d appreciate it if you could provide detailed information about the codes of compressing and decompressing.
Have a nice day!
Shanks Zen
MSDN Community Support | Feedback to us
-
segunda-feira, 12 de março de 2012 07:53
The blob format is not related to the internal processor type of the server.
However, if an end user sees square blocks, it has almost forever to do with the way the encoding has done related to the used code page or format.
See the top of this page for better understanding and the rest for more knowledge in depth.
http://msdn.microsoft.com/en-us/library/system.text.encoding(v=vs.100).aspx
This can also happen if a certain code page is not available.
Success
Cor- Editado Cor LigthertMVP segunda-feira, 12 de março de 2012 08:00
-
terça-feira, 13 de março de 2012 17:53Thank you both for the information. I will try to gather the code to post it and will read the link provided above. I guess I'm still confused because the documents decompress just fine for everyone here but not for the people we sent the code to and I don't have access to their system. I know it's hard to help me unless I post the code so I will get that soon. We are using zlibwapi.dll for the decompression and I believe that is how the documents were compressed originally as well.
-
terça-feira, 13 de março de 2012 20:13
Here is the code that decompresses and opens the .doc documents. I have included the first part here because it was too large to include all of it.
[code language=VB]
Private Sub SetupView(ByVal textDocID As Object, ByVal textOriginName As Object, ByVal textImaged As Object, ByVal textOrd As Object)
'textDocID is the document id from the database
'textOriginName is the app the doc originated from so I know the table to get the images from
'textImaged is a flag from a table
'textORD is the order number
Dim viewReader As Data.SqlClient.SqlDataReader
Dim strDocType As String
Dim textSite As String
Dim documentView As New DocumentGetByORDocumentRID()
documentView.ORDocumentRID = textDocID
documentView.ConnectionString = ConfigurationManager.ConnectionStrings("myConnectionString").ConnectionString
documentView.ORDataApp = "myDatabase"
documentView.ORStoredProc = "[dbo].[usp_Document_GetByORDocumentRID]"
viewReader = documentView.ExecuteReader()
Try
If (Object.Equals(documentView.ReturnValue, SqlInt32.Null) = False) Then
'*************************************************
'Get document properties data
'*************************************************
While viewReader.Read()
Dim contentType As String = viewReader("DocumentContentType")
Select Case Trim(contentType)
Case ".DOC"
strDocType = "application/msword"
Case ".XML"
strDocType = "application/xml"
Case ".PDF"
strDocType = "application/pdf"
Case ".RTF"
strDocType = "application/rtf"
Case ".ZIP"
strDocType = "application/zip"
Case ".TIF", ".TIFF"
strDocType = "image/tif"
Case ".TXT"
strDocType = "application/octet-stream"
Case Else
strDocType = "application/octet-stream"
End Select
'Instantiate the new object here, deallocate it
'When the form closes
objZLib = New clszlib
'Uncompress any text that is in the compression buffer
Dim intResult As Integer 'result from function call
Dim DocumentData() As Byte = CType(viewReader("Document"), Byte())
objZLib.m_arbytCompressionBuffer = DocumentData
objZLib.lngOriginalSize = viewReader("LENGTH")
'Check to make sure there is something in the buffer
If UBound(objZLib.m_arbytCompressionBuffer) > 0 Then
'Check to make sure that the original size of
'The uncompressed data is still held
If objZLib.lngOriginalSize > 0 Then
'Decompress the buffer which is holding the compressed data
Try
intResult = objZLib.intDeCompressByteArray(objZLib.m_arbytCompressionBuffer)
Catch ex As Exception
ex.Message.ToString()
End Try
Response.Buffer = True
'Opens in WORD which is not controlled by web, but by word.
Response.AddHeader("content-disposition", "attachment;filename=" & viewReader("DocumentName"))
Response.AddHeader("Content-Length", viewReader("Length"))
Response.ContentType = strDocType
Response.Cache.SetExpires(DateTime.Now.AddSeconds(60))
Response.Cache.SetCacheability(HttpCacheability.Public)
Response.Cache.SetSlidingExpiration(True)
Response.OutputStream.Write(CType(objZLib.m_arbytDeCompressionBuffer, Byte()), 0, CType(viewReader("Length"), Integer))
Else
Response.Write("The file size is zero")
End If
Response.Flush()
Response.Close()
End If
'Deallocate the zlib object that was instantiated
'When the form was loaded
objZLib = Nothing
End While
viewReader.Close()
End If
Catch ex As Exception
Throw New ApplicationException("Error in page: ViewDocs.vb Module: Execute() As Collection")
Finally
viewReader.Close()
End Try
End Sub
[/code]
- Editado mpls_bren terça-feira, 13 de março de 2012 20:17
-
terça-feira, 13 de março de 2012 20:36
This is the zlib.dll wrapper
[code language=VB]
'********************************************************************************
'general purpose zlib.dll wrapper for compressing text, files, byte arrays, etc.
'
'December 12, 2004
'
'MS VB.NET 2003 (v7.1.3088), option explicit=on, option strict=on '
'Kevin Pisarsky (http://www.pisarsky.com) (kevin@pisarsky.com) '
'for usage see the demo application that should have been packed with this code '
'********************************************************************************
Imports System
Imports System.Data
Imports System.Data.SqlTypes
Imports System.IO
Imports System.Runtime.InteropServices
Namespace myName.my.Utilities
Public Class clszlib
'the version of zlib used is zlibwapi.dll, v1.2.2.0, which was downloaded from the
'official zlib page at http://www.gzip.org/zlib/
'
'this dll is the one compiled for windows9x/nt/2000/xp usage and is win32 compatible.
'The dll was used without compiling from source, and without any modifications.
'
'class level constants
Public Const Z_NO_FLUSH As Integer = 0
'partial flush deprecated, use Z_SYNC_FLUSH instead
Public Const Z_PARTIAL_FLUSH As Integer = 1
Public Const Z_SYNC_FLUSH As Integer = 2
Public Const Z_FULL_FLUSH As Integer = 3
Public Const Z_FINISH As Integer = 4
'allowed flush values ; see deflate() for details */
Public Const Z_OK As Integer = 0
Public Const Z_STREAM_END As Integer = 1
Public Const Z_NEED_DICT As Integer = 2
Public Const Z_ERRNO As Integer = -1
Public Const Z_STREAM_ERROR As Integer = -2
Public Const Z_DATA_ERROR As Integer = -3
Public Const Z_MEM_ERROR As Integer = -4
Public Const Z_BUF_ERROR As Integer = -5
Public Const Z_VERSION_ERROR As Integer = -6
'return codes for the compression/decompression functions. Negative
'values are errors, positive values are used for special but normal events.
Public Const Z_NO_COMPRESSION As Integer = 0
Public Const Z_BEST_SPEED As Integer = 1
Public Const Z_BEST_COMPRESSION As Integer = 9
Public Const Z_DEFAULT_COMPRESSION As Integer = -1
'compression levels
Public Const Z_FILTERED As Integer = 1
Public Const Z_HUFFMAN_ONLY As Integer = 2
Public Const Z_DEFAULT_STRATEGY As Integer = 0
'compression strategy
Public Const Z_BINARY As Integer = 0
Public Const Z_ASCII As Integer = 1
Public Const Z_UNKNOWN As Integer = 2
'possible values of the data_type field
Public Const Z_DEFLATED As Integer = 8
'the deflate compression method (the only one supported in this version)
'for initializing zalloc, zfree, opaque
Public Const Z_NULL As Integer = 0
'class level variables
'this is the file handle type
Private gzFile As Long
'this is the buffer used by intCompressByteArray to store
'an array of compressed bytes - it is public so that the calling
'application can have access to it if necessary
Public m_arbytCompressionBuffer As Byte()
'this is the buffer used by intDeCompressByteArray to store
'an array of decompressed bytes - it is public so that the calling
'application can have access to it if necessary
Public m_arbytDeCompressionBuffer As Byte()
'the original size of the data being compressed, whether it is
'a buffer, file size or whatever. this number is set when you compress
'something, and used when you uncompress it
Private m_lngOriginalSize As Long
'this is the zlib function for compressing a byte array
<DllImport("zlibwapi.dll", EntryPoint:="compress")> Private Shared Function CompressByteArray(ByVal dest As Byte(), ByRef destLen As Integer, ByVal src As Byte(), ByVal srcLen As Integer) As Integer
'leave function empty - DLLImport attribute forwards calls to CompressByteArray to compress in zlib.dLL
End Function
'this is the zlib function for decompressing a byte array
'Private Declare Function uncompress Lib "zlibwapi.dll" (ByVal dest As Byte(), ByRef destLen As Integer, ByVal src As Byte(), ByVal srcLen As Integer) As Integer
<DllImport("zlibwapi.dll", EntryPoint:="uncompress")> Private Shared Function UncompressByteArray(ByVal dest As Byte(), ByRef destLen As Integer, ByVal src As Byte(), ByVal srcLen As Integer) As Integer
'leave function empty - DLLImport attribute forwards calls to UnCompressByteArray to Uncompress in zlib.dLL
End Function
'zlib function for opening a file for writing
<DllImport("zlibwapi.dll", EntryPoint:="gzopen")> Private Shared Function OpenWrite(ByVal strPath As String, ByVal strMode As String) As Long
'leave empty
End Function
Public Property lngOriginalSize() As Long
'this property holds the original size of data being compressed. it is necessary to
'keep the original size of the data in order to uncompress it. whenever possible this
'property is automatically set by the compression procedures; it may be necessary for
'your application to set the property if the application is shut down or this class is
'deallocated between compression and decompression procedures.
Get
lngOriginalSize = m_lngOriginalSize
End Get
Set(ByVal lngValue As Long)
m_lngOriginalSize = lngValue
End Set
End Property
'compress a byte array into a buffer, return value:
' the size of the compressed buffer if the operation was successful
' return -1 if the operation was unsuccessful but no specific error is provided
' return -4 if there was not enough memory to complete the operation
' return -5 if there was not enough room in the output buffer (intBufferSize not large enough)
Public Function intCompressByteArray(ByRef arbytData() As Byte, Optional ByRef TempBuffer() As Byte = Nothing) As Integer
'parameters: arbytData is a one dimensional array of bytes
Dim intResult As Integer 'result of the call to zlibwapi.dll
Dim intBufferSize As Integer 'size of the uncompressed byte array being passed in
'set the original size of the data, this is used when the data is to be
'uncompressed
m_lngOriginalSize = UBound(arbytData) + 1
'set the size of the buffer for the data to be compressed into; the buffer size
'must be at least 0.1% larger than the uncompressed data, plus 12 bytes. after
'the function is successful, intBufferSize will be the actual size of the
'compressed buffer
intBufferSize = CInt(m_lngOriginalSize)
intBufferSize = CInt(intBufferSize + (intBufferSize * 0.015) + 12)
'redimension the compression buffer to the correct size
'for this operation
ReDim m_arbytCompressionBuffer(intBufferSize)
'call the zlibwapi.dll function "compress" to actually compress the bytes
intResult = CompressByteArray(m_arbytCompressionBuffer, intBufferSize, arbytData, UBound(arbytData) + 1)
'set the function result
Select Case intResult
Case Z_OK : Return intBufferSize 'size of compressed buffer
Case Z_MEM_ERROR : Return -4 'not enough memory
Case Z_BUF_ERROR : Return -5 'output buffer (m_arbytCompressionBuffer) too small
Case Else
Return -1 'unknown error
End Select
End Function 'intCompressByteArray
'decompress a byte array into an uncompressed buffer, return value:
' the size of the compressed buffer if the operation was successful
' return -1 if the operation was unsuccessful but no specific error is provided
' return -4 if there was not enough memory to complete the operation
' return -5 if there was not enough room in the output buffer (intBufferSize not large enough)
Public Function intDeCompressByteArray(ByRef arbytData() As Byte) As Integer
'parameters: arbytData is a one dimensional array of bytes that have been compressed
' note: you need to set the value of m_lngOriginalSize before calling this
' function, it requires the original size of the data before compression
Dim intResult As Integer 'result of the call to zlibwapi.dll
Dim intBufferSize As Integer 'size of the uncompressed byte array being passed in
'set the size of the buffer for the data to be uncompressed into; the buffer size
'must be at least the uncompressed data, plus 12 bytes. after
'the function is successful, intBufferSize will be the actual size of the
'uncompressed buffer
intBufferSize = CInt(m_lngOriginalSize)
'redimension the decompression buffer to the correct size
'for this operation
ReDim m_arbytDeCompressionBuffer(intBufferSize)
'call the zlibwapi.dll function "compress" to actually compress the bytes
'intResult = uncompress(m_arbytDeCompressionBuffer, intBufferSize, arbytData, UBound(arbytData) + 1)
intResult = UncompressByteArray(m_arbytDeCompressionBuffer, intBufferSize, arbytData, UBound(arbytData) + 1)
'set the function result
Select Case intResult
Case Z_OK : Return intBufferSize 'size unof compressed buffer
Case Z_MEM_ERROR : Return -4 'not enough memory
Case Z_BUF_ERROR : Return -5 'output buffer (m_arbytCompressionBuffer) too small
Case Else
Return -1 'unknown error
End Select
End Function 'intDeCompressByteArray
End Class
End Namespace
[/code]
-
quarta-feira, 14 de março de 2012 01:40
Apart from having Option Strict Off, the only problem I see at first glance are the lines
Catch ex As Exception ex.Message.ToString()because exceptions are just swallowed. Are you sure no exception occurs?
However I haven't had a closer look yet.
Armin
- Marcado como Resposta Shanks ZenMicrosoft Contingent Staff, Moderator quarta-feira, 28 de março de 2012 08:34
- Não Marcado como Resposta mpls_bren sexta-feira, 30 de março de 2012 18:16
-
sexta-feira, 30 de março de 2012 18:17
Armin is correct, and if my exception handling had done something with the exception, I could have found the true cause of the error much sooner. 2 bad coding mistakes - not handling the exception and then continuting on when there was an exception. The application continued on even though the decompression never happened. Thankfully through the help of Microsoft support we got an answer that fixed the problem. IT was this: On the IIS go to “Application Pools” for this application and change “Enable 32 bit applications” to TRUE. Now they can view the documents!

