Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
Home
Discussion GroupsVB SyntaxEnterprise DevelopmentDatabase AccessControlsCOMWin APICrystal ReportDeploymentGeneralGeneral 2
Related Topics
VB.NET / ASP.NETMS SQL ServerMS AccessOther Database ProductsMore Topics ...

VB Forum / COM / December 2007



Tip: Looking for answers? Try searching our database.

IStream, IPicture and ADODB.Stream

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Alexander Mueller - 25 Nov 2007 13:45 GMT
Hi

from what I have read from the docs, IPicture implements
IPersistentStream and thus IStream, with its Read/Write
methods.
I want to save a StdPicture-object into a MSSQL-Server-
BLOB, with as little memory-copying as possible.
If it is possible, what i don't believe, the best solution is
to somehow make the buffer location of the ADODB-Stream point
to the buffer of the IPicture-object, which will probaly not work
because both have ther own buffer which cannot be 'redirected'
in a pointer operation.

Does anyone know, if the ADODB.Stream-object also implements
the OLE-IStream interface and if there is way to directly
write the Picture data into a ADODB-Strwam object.

Something like:
 oAdodbStream.Write oPictureStream.Read()

I need to know how i can call 'Read' from the StdPicture-object.
In C++  QueryInterface should do the trick, but I don't have a defintion
of IStream in VB, nor do I know how to call QueryInterface in VB.

Is there a way to do this or at least to do some kind of memcopy
from the Picture to the ADOB.Stream without file/disc-Access?

Any hints very much appreciated.

MfG,
Alex

Sorry for x-posting to
 m.p.vb.winapi
 m.p.vb.winapi.graphics
 m.p.vb.com
 m.p.vb.general.discussion

Fup goes to
 m.p.vb.com
Schmidt - 25 Nov 2007 18:41 GMT
> I want to save a StdPicture-object into a MSSQL-Server-
> BLOB, with as little memory-copying as possible.

Why, is something like this not fast enough?

Public Sub SavePicture(SP as StdPicture, Fld as ADODB.Field)
Dim PB as New PropertyBag
   PB.WriteProperty "StdPic", SP
   Fld.Value = PB.Content
End Sub

Olaf
Alexander Mueller - 25 Nov 2007 22:55 GMT
Schmidt schrieb:

Hi Olaf

thx for your reply

>> I want to save a StdPicture-object into a MSSQL-Server-
>> BLOB, with as little memory-copying as possible.
[quoted text clipped - 6 lines]
>     Fld.Value = PB.Content
> End Sub

I only tested it the other way around, reading the
bytes of a blob into a stdpicture with a propbag,
and it didn't work, for unknown reasons.

'did not work for me...:
Public Function BytesToPicture(Bytes() As Byte) As StdPicture

  With New PropertyBag
    .Contents = Bytes
    Set BytesToPicture = .ReadProperty("StdPic")
  End With

End Function

So i didn't test the solution you proposed.
But i will give a try now, its pretty straight forward.
Results will follow tomorrow.

MfG,
Alex
Schmidt - 26 Nov 2007 02:41 GMT
> I only tested it the other way around, reading the
> bytes of a blob into a stdpicture with a propbag,
> and it didn't work, for unknown reasons.
The reasons are, that you will have to convert this
"original content" into "bytes of a known format"
that *you* define in a first step.
e.g. the Image-bytes inside the Blobs of Northwind-DB
have to be converted without using VBs PropertyBag.
After that conversion (whatever it takes, to bring this
bytes into a form wich is useful with VBs Image-Objects)
you are free to define your own "format".
Be it the Property-Bag-approach, or be it another approach
using DIB-Bytes (bot may be coupled with your own
Byte-Array-compression - e.g. using zlib) or saving the
bytes directly in a known Image-Format with losless
compression (e.g. *.gif or *.png) or with lossy compression
(e.g. *.jpg). It's all up to you.

In my dhSQLite-Samples I've included a method - how
to convert the Nwind.mdb-Image-Blobs to StdPicture
in a first step using temporary Bitmap-Files, but with
a bit more effort you could also convert them without
using the disk.

In short: simply create your own Byte-Format for your
Image-Blobs. Don't try to be compatible to a "mysterious
MS-Image-Blob-standard".
Losless compression for your own Image-Byte-Format is also
a good idea,  because it helps, to keep the Blob-Content the
DB will have to manage as low as possible and this would
also help, to fill up the appropriate Recordsets in a DB-request
more quickly (not to mention their transfer-times over a network).

Olaf
Alexander Mueller - 26 Nov 2007 14:04 GMT
Schmidt schrieb:

Hi Olaf

thx again for your most valuable reply.

> "Alexander Mueller" <millerax@hotmail.com> schrieb:
>
>> I only tested it the other way around, reading the
>> bytes of a blob into a stdpicture with a propbag,
>> and it didn't work, for unknown reasons.

> The reasons are, that you will have to convert this
> "original content" into "bytes of a known format"
> that *you* define in a first step.

The byte-format that i defined is actually a 1:1 image of
the picture-file as saved on disk.
No conversion / compression / reinterpretation in between.
I read a file in binary mode and AppendChunk it to the blob
and that's it. Seems The PropertyBag-approach expects
different kind of data.

> e.g. the Image-bytes inside the Blobs of Northwind-DB
> have to be converted without using VBs PropertyBag.
[quoted text clipped - 7 lines]
> compression (e.g. *.gif or *.png) or with lossy compression
> (e.g. *.jpg). It's all up to you.

Sounds intersting and also a bit complicated.
Compression is of course worth looking at when it comes to saving large
amounts of bin-data. However in first approach i'd prefer to
save and load the data "as is", e.g. exactly the same way as
saved on disk.

> In my dhSQLite-Samples I've included a method - how
> to convert the Nwind.mdb-Image-Blobs to StdPicture
> in a first step using temporary Bitmap-Files, but with
> a bit more effort you could also convert them without
> using the disk.

I already managed this using OLE-API calls
CreateStreamOnHGlobal and OleLoadPicture
see news:<47477bcf$0$13112$9b4e6d93@newsspool2.arcor-online.net>

What i am looking for is the way back.
CreateStreamOnHGlobal receives the adress of a byte-array
and creates a IStream-object out of it.
OleCreatePicture receives a IStream and makes it a
StdPicture.

I need something that retrieves an IStream from
a StdPicture and then gets the bytes from the IStream.
Or directly the bytes from StdPicture, in the same format
and alignment, as if the they were saved to disk.

> In short: simply create your own Byte-Format for your
> Image-Blobs. Don't try to be compatible to a "mysterious
> MS-Image-Blob-standard".

How do I create such a Byte-Format?

> Losless compression for your own Image-Byte-Format is also
> a good idea,  because it helps, to keep the Blob-Content the
> DB will have to manage as low as possible and this would
> also help, to fill up the appropriate Recordsets in a DB-request
> more quickly (not to mention their transfer-times over a network).

Surely lossless compression sound like a very good idea, but any client
that reads the blob must know the compression algorithm / codec used
and be able to decode it.
Anyway i am not the  one that decides, I'll tell it my boss, replication
is also an important feature of his software, and reducing bandwidth
needs is always welcome, so may be he's interested in.

Thx for your reply again

MfG,
Alex
Alexander Mueller - 26 Nov 2007 19:24 GMT
Schmidt schrieb:

>> I only tested it the other way around, reading the
>> bytes of a blob into a stdpicture with a propbag,
>> and it didn't work, for unknown reasons.

> The reasons are, that you will have to convert this
> "original content" into "bytes of a known format"
> that *you* define in a first step.

Sorry for not directly replying to your proposals.
I have  another question related to this subject and I think you
know the answer since I've seen and been using your implementations of
IEnumVariant.
The question is:

 How can I implement a COM-Interface with VB?

Do I have to declare a Type that has the same layout as the VTable of
the interface and then link the methods to the types members
using AdressOf?

Back to the IStream-stuff:
The first scenario was not actually correct, IPicture
does not inherit from IStream, but it allows to be saved into
an IStream by its SaveAsFile-method, where File actually means
IStream-object. The C-syteld Signature is:

 HRESULT SaveAsFile(
   IStream * pstream, //Pointer to stream where picture writes its data
   BOOL fSaveMemCopy , //Indicates whether to save the picture in memory
   LONG* pcbSize  //Receives a pointer to the number of bytes written
                 //to stream
 );

The help also says:

"IPicture::SaveAsFile

Saves the picture's data into a stream in the same format that it would
save itself into a file. Bitmaps use the BMP file format, metafiles the
WMF format, and icons the ICO format."

So this stream-data will have the same byte-format, as when writing the
picture to a file with VB SavePicture (which is proably a wrapper around
SaveAsFile i write into the blob when saving a file.

And IStream has a Read method that returns the data:

HRESULT Read(
  [out]  void* pv, //pointer to the buffer stream data is read into.
  [in]   ULONG cb,
  [out]  ULONG* pcbRead
);

So all i have to do is to either implement IStream or find an
existing implementation. Do you or anyone else know if there is
an default OLE-implementation in one of the OLE-DLLs?

MfG,
Alex
Schmidt - 03 Dec 2007 22:18 GMT
>   How can I implement a COM-Interface with VB?
>
> Do I have to declare a Type that has the same layout as
> the VTable of the interface and then link the methods
> to the types members using AdressOf?
No, the Type in LightWeight-COM-Objects is only
needed to store a *pointer* to the VTable (together
with Private Var-stuff), not the VTable-Entries itself

Finally time to get "The Curland-Book" I'd say. ;-)

> Back to the IStream-stuff:
>...
> So all i have to do is to either implement IStream or find an
> existing implementation. Do you or anyone else know if there is
> an default OLE-implementation in one of the OLE-DLLs?

Here's an example, wich is based on code of Eduardo Morcillo
(just google for his website) and wich also depends on his
great OleLib.tlb (wich BTW also contains the IStream-Interface).

The Code demonstrates, what is basically going on under
the hood of VBs PropertyBag - and it shows you how to
use the OleLib-defined Types (e.g. IStream).

'***Into a form
Option Explicit

Private Sub Form_Load()
Dim B() As Byte
 'let's serialize a Test-(Std-)Picture (loaded from disk)
 B = WriteObject(LoadPicture("c:\sometest.bmp"))
 Debug.Print "Obj serialized into: " & UBound(B) + 1 & " Bytes."

 'now the opposite direction
 Set Me.Picture = ReadObject(B)
End Sub

Public Function WriteObject(ByVal Obj As Object) As Byte()
Dim CLSID As UUID, oPSI As IPersistStreamInit, oPS As IPersistStream
Dim oStrm As olelib.IStream, Stat As STATSTG, B() As Byte, Bytes&
 If Obj Is Nothing Then
   WriteClassStm oStrm, CLSID ' Write the empty CLSID
 Else
   On Error Resume Next
   Set oStrm = CreateStreamOnHGlobal(0, True)
   If Err Then
     On Error GoTo 0
     Err.Raise vbObjectError, , "Cannot create Stream-Object"
   End If
   Set oPS = Obj 'Query for IPersistStream
   If Err.Number = 0 Then
     oPS.GetClassID CLSID
     WriteClassStm oStrm, CLSID
     oPS.Save oStrm, 0
   Else
     Err.Clear
     Set oPSI = Obj 'Query for IPersistStreamInit
     If Err.Number = 0 Then
       oPSI.GetClassID CLSID
       WriteClassStm oStrm, CLSID
       oPSI.Save oStrm, 0
     Else
       On Error GoTo 0
       Err.Raise 5, , "Oject class isn't persistable: " & TypeName(Obj)
     End If
   End If
 End If

 If Err Then
   On Error GoTo 0
   Err.Raise vbObjectError Or 1, , "The object can't be saved."
 Else
   oStrm.Stat Stat
   Bytes = Stat.cbSize * 10000
   If Bytes > 0 Then
     ReDim B(0 To Bytes - 1)
     oStrm.Seek 0, 0
     oStrm.Read B(0), Bytes
     WriteObject = B
   End If
 End If
End Function

Public Function ReadObject(B() As Byte) As Object
Dim CLSID As UUID, IID_Null As UUID, IID_IUnknown As UUID
Dim oPSI As IPersistStreamInit, oPS As IPersistStream, lRes As Long
Dim Bytes&, IU As olelib.IUnknown, oStrm As olelib.IStream
 On Error Resume Next
 Bytes = UBound(B) - LBound(B) + 1
 If Bytes = 0 Then Err.Clear: Exit Function

 Set oStrm = CreateStreamOnHGlobal(0, True)
 If Err Then
   On Error GoTo 0
   Err.Raise vbObjectError, , "Cannot create Stream-Object"
 End If
 oStrm.Write B(LBound(B)), Bytes
 oStrm.Seek 0, 0
 ReadClassStm oStrm, CLSID ' Read the CLSID

 If IsEqualGUID(CLSID, IID_Null) Then Exit Function

 IID_IUnknown.Data4(0) = &HC0: IID_IUnknown.Data4(7) = &H46 'init
 lRes = CoCreateInstance(CLSID, Nothing, CLSCTX_INPROC_HANDLER Or _
 CLSCTX_INPROC_SERVER Or CLSCTX_LOCAL_SERVER Or CLSCTX_REMOTE_SERVER, _
 IID_IUnknown, IU)

 If lRes = S_OK Then
   Set oPS = IU ' Query for IPersistStream
   If Err.Number = 0 Then
     oPS.Load oStrm
   Else
     Err.Clear
     Set oPSI = IU ' Query for IPersistStreamInit
     If Err.Number = 0 Then
       oPSI.Load oStrm 'Load the object data
     End If
   End If
   Set ReadObject = IU
 Else
   Err.Raise 429
 End If
End Function

Olaf
Alexander Mueller - 14 Dec 2007 00:50 GMT
Schmidt schrieb:

>>   How can I implement a COM-Interface with VB?
>>
[quoted text clipped - 20 lines]
> the hood of VBs PropertyBag - and it shows you how to
> use the OleLib-defined Types (e.g. IStream).

Hi Olaf

You are my hero!
Thank you so much for your code.
It works great with bmp jpg and gif.

A problem I had to solve on my own is that I need
the bytes returned to fully equal the bytes of the
pic-file read into a byte-array (because that is the way
all pix are saved in our DB..)

The byte-array returned by WriteObject is somewhat different
(slightly more bytes then the org-file and different data)
so if I write them to file, the file is not a valid pic.

I finally got the code that i originally thought of to work that uses
IPicture.SaveToFile (which actually saves into a Stream not a file)

Here's my code (based on your example, also using emorcillos olelib.tlb)

Thx once again,
Alex

Private Sub Form_Load()
Dim B() As Byte

  Dim f%

  'let's serialize a Test-(Std-)Picture (loaded from disk)
  B = WriteObjectFB(LoadPicture("D:\Media\Bilder\Deix\weekly23.bmp"))
  Debug.Print "Obj serialized into: " & UBound(B) + 1 & " Bytes."

  'Create TestFile to check the byte format
  f = FreeFile
  Open "C:\testcopy.bmp" For Binary Access Write As #f
  Put #f, , B
  Close #f

  'now the opposite direction
  Set Me.Picture = ReadObjectFB(B)

End Sub

'FB == FileBytes (same binary format as file on disk)
Public Function WriteObjectFB(oIPic As IPicture) As Byte()

Dim oStrm As olelib.IStream, B() As Byte, Bytes&

    If oIPic Is Nothing Then
        On Error GoTo 0
        Err.Raise vbObjectError, , "Picture is empty"
    End If

    On Error Resume Next
    Set oStrm = CreateStreamOnHGlobal(hGlobal, True)

    If Err Then
        On Error GoTo 0
        Err.Raise vbObjectError, , "Cannot create Stream-object"
    End If

   
    oIPic.SaveAsFile ByVal ObjPtr(oStrm), True, Bytes

    If Err.Number = 0 Then

        If Bytes > 0 Then
            ReDim B(0 To Bytes - 1)
            oStrm.Seek 0, 0
            oStrm.Read B(0), Bytes
            WriteObjectFB = B
        End If

    Else

        On Error GoTo 0
        Err.Raise 5, , "Cannot save picture to stream"

    End If

End Function

Public Function ReadObjectFB(PictureData() As Byte) As StdPicture

    Dim IID_IPicture As UUID
    Dim oStream As IStream

    Call CLSIDFromString(IIDSTR_IPicture, IID_IPicture)

    'CreateStreamOnHGlobal from oletlb
    Set oStream = CreateStreamOnHGlobal(VarPtr(PictureData(0)), 1)
    If Not oStream Is Nothing Then

        ' OLE IPicture-Objekt erstellen
        Set ReadObjectFB = _
            OleLoadPicture(oStream, 0, 0, IID_IPicture)

    Else

        On Error GoTo 0
        Err.Raise vbObjectError, , _
        "Cannot create stream-object from picture-data"
    End If

End Function

> '***Into a form
> Option Explicit
[quoted text clipped - 97 lines]
>
> Olaf
Schmidt - 14 Dec 2007 13:35 GMT
> Thank you so much for your code.
> It works great with bmp jpg and gif.
Glad you found your own way from it - and as said,
the credits should go to Eduardo Morcillo, my example
was mainly based on his PropertyBag-Demo-Code.

Olaf
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2009 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.