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 John Tel on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

CLSIDFromString problem - function or sub?

Status
Not open for further replies.

tedsmith

Programmer
Nov 23, 2000
1,762
AU
I am having troubles with an example in a previous post thread222-1335999 (now closed).
This is a routine to convert BMP to JPG in memory.
The CLSIDFromString function is asking for a second variable (ipcisid as UUID) which is what happens if used as a Sub instead of a Function.
If I rem the above line, further down the GdipSaveImageToStream function says myStream is a method or data member not found yet it is earlier dimensioned and set.
I have referenced GDI+ type library 1.05 (dseaman@aol.com.br) file GDIplus060203.tlb and Edanmo's OLE Interfaces & Functions v1.81. file olelib.tlb
Have I selected the wrong references or the original ones been overwritten? Any ideas?
 
The problem is kind of my fault Ted. When I advised in that thread to use Edanmo's OLE Interfaces & Functions I forgot to say that you would probably then need to be explicit in your declaration of of CLSIDs, because both the GDI+ library AND Edanmo's library contain CLSIDFromString, and they differ from each other.

Now, the one you want is the GDI+ version, so simply change

CLSIDFromString(EncoderQuality)

wherever it occurs to

gdiplus.CLSIDFromString(EncoderQuality)
 
Thanks - nearly there!
however I still get a "Method or data member not found" error on myStream where it is included:-

GdipSaveImageToStream(gdiImage, myStream, myCLSID, VarPtr(myEncoderParameters))
and
GdipLoadImageFromStream myStream, gdiImageTarget
The drop down list indicate a stream should be there, but is it looking for a different type of stream?

 
It's probably a related issue, but I'm nowhere near a development machine today, so I can't really look at this in any detail for a bit
 
Thanks
Maybe you have different references set or are a different version or in a different priority order to yours?
Mine are
Visual Basic For Applications (msvbvm60.dll)
Visual Basic runtime objects and procedures (msvbvm60.dll\3)
Visual Basic objects and procedures (vb6.olb)
Edanmo's OLE interfaces & functions v1.81 (olelib.tlb)
GDI+ Type Library 1.05(dseaman@uol.com.br (GDIplus060203.tlb)
OLE Automation (stdole2.tlb)

 
Hi I wondered if you had a chance to see if your refs = mine possibly causing the error when myStream is encountered?
 
OK, try changing

Dim myStream As IStream

to

Dim myStream As gdiplus.IStream
 
Thanks, it works -at last!
However I had to change my GDI reference version from
GDIplus060203.tlb 6/2/2003
to
Gdiplus110903.tlb 11/9/2003
and remove the old file.

There is another version about called GDIplus.tlb 7/2/2003 that doesnt have IStream either.

VB crashes when you close it. Is there a close API routine that I should be doing?
 
Ah, no, that's due to my original GDI+ cleanup code not actually cleaning up properly. I've worked on that since I posted the example, but don't yet have my dev PC back in action to dig it out.

>change my GDI reference version from
>GDIplus060203.tlb 6/2/2003
>to
>Gdiplus110903.tlb 11/9/2003

Er, the 11/09/2003 version is the one I specifically reference and provide direct links for in thread222-1335999, so I'm not sure how you got the 060203 version. Oh, unless you had been working with one of my earlier, non-stream GDI+ examples and download an original library at that time (althougn I do specifically point out in the thread we currently are talking about that one would need to update to the 110903 version if you wanted to work with streams)
 
Sorry to be a nuisance but have you had any luck with the cleanup routine?
When I rub it in the IDE it crashes after I stop the app then restart again. Reloading the IDE fixes it but -
When I compile the app it runs OK but if when I close and start it again, the app instantly closes when I try to convert again. Only rebooting the computer fixes it!

No error messages show.

Another interesting thing is how can the value of Token can be seen when it is a value pass TO a function???
 
>cleanup routine

If the version of the code you have includes:

' Clean up
GdipDisposeImage gdiImage
GdipDisposeImage gdiImageTarget
GdipDeleteGraphics myGraphics
GdiplusShutdown Token

then you've already got the 'better' version.
 
Yes I have these cleanup statements included.
When I put a break in the routine before the stream=nothing even moving the cursor over mystream causes the editor to freeze.
Any attempt to step through the conversion routine also crashes the editor.

I was really wanting to convert the original BMP into a signal that could be sent to another computer via a propertybag, not displayed in a local picture box.
I have tried many ways to do this without success.

Is there any way of sending the converted JPG to a propertybag instead of using GDI to display it in a local picture box?
Code:
'2 picture boxes one with a .bmp, 1 command button
Option Explicit

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private Declare Function lstrlen Lib "kernel32" Alias "lstrlenW" (lpString As Any) As Long
Private Declare Function IsBadStringPtrByLong Lib "kernel32" Alias "IsBadStringPtrW" (ByVal lpsz As Long, ByVal ucchMax As Long) As Long



Private Sub Command1_Click()
    Dim GpInput As GdiplusStartupInput
    'Dim Token As Long
    Dim myCLSID As CLSID
    Dim myEncoderParameters As EncoderParameters
    Dim myEncoder(0) As EncoderParameter
    Dim gdiImage As Long
    Dim gdiImageTarget As Long
    Dim Quality As Long
    Dim myGraphics As Long
    Dim Token As Long
     ' New declarations compared to original file-based version of this code
    Dim myStream As GdiPlus.IStream   ' Use the GDI+ type library's IStream interface
    Dim b(4096000) As Byte ' for this example hardcode in a max available stream size of 4Mb
On Error GoTo XXX
    ' Get and check we have a CLSID for a jpeg codec
    If GetEncoderCLSID("image/jpeg", myCLSID) Then
        GpInput.GdiplusVersion = 1
        If GdiplusStartup(Token, GpInput) <> Ok Then
            MsgBox "Error loading GDI+!", vbCritical
        Else
            myEncoderParameters.Count = 1
            myEncoder(0).Guid = GdiPlus.CLSIDFromString(EncoderQuality)
            myEncoder(0).Type = EncoderParameterValueTypeLong
            myEncoder(0).NumberOfValues = 1
            Quality = 25 ' 0 to 100%
            myEncoder(0).ValuePtr = VarPtr(Quality)
            myEncoderParameters.Parameter = myEncoder(0)
            GdipCreateBitmapFromHBITMAP Picture1.Picture.Handle, Picture1.Picture.hPal, gdiImage
         
            Set myStream = CreateStreamOnHGlobal(b(0), True)
            
             ' OK save image as a compressed JPG into a stream
            GdipSaveImageToStream gdiImage, myStream, myCLSID, VarPtr(myEncoderParameters) ' one change from my previous example, to save to a stream instead of a file
            
            ' Extra stuff to show loading the stream into a target picturebox
            GdipLoadImageFromStream myStream, gdiImageTarget
            ' OK we can dispose of stream
            Set myStream = Nothing
            ' Now display, letting GDI+ do all the hard work
            GdipCreateFromHDC Picture2.hDC, myGraphics
            GdipDrawImage myGraphics, gdiImageTarget, 0, 0
YYY:
            ' Clean up
            GdipDisposeImage gdiImage
            GdipDisposeImage gdiImageTarget
            GdipDeleteGraphics myGraphics
            GdiplusShutdown Token
            Set myStream = Nothing
        End If

    End If

On Error GoTo 0
Exit Sub

XXX:
MsgBox Error & " Fault in Converting", vbCritical, "ERROR"
Resume YYY
End Sub

' helper function to get CLSID of output codec
Private Function GetEncoderCLSID(ByVal strMimeType As String, outCLSID As CLSID) As Long
    Dim GpInput As GdiplusStartupInput
    'Dim Token As Long
    Dim lEncoders As Long
    Dim lEncodersBuffer As Long
    Dim lp As Long
    Dim arrEncoders() As ImageCodecInfo
    Dim Token As Long
    GpInput.GdiplusVersion = 1

    If GdiplusStartup(Token, GpInput) <> Ok Then
        MsgBox "Error loading GDI+!", vbCritical
    Else
        GdipGetImageEncodersSize lEncoders, lEncodersBuffer
        ReDim arrEncoders(lEncoders - 1) As ImageCodecInfo
        GdipGetImageEncoders lEncoders, lEncodersBuffer, arrEncoders(0)

        GdiplusShutdown Token
        
        GetEncoderCLSID = False
        For lp = LBound(arrEncoders) To UBound(arrEncoders)
            If StringFromPointer(arrEncoders(lp).MimeTypePtr) = strMimeType Then
                outCLSID = arrEncoders(lp).CLSID
                GetEncoderCLSID = True
                Exit For
            End If
        Next
    End If
    
End Function

' Works for strings that are nullchar terminated
Public Function StringFromPointer(lpString As Long) As String
    Dim sRet As String
    Dim lret As Long
    Dim lMaxLength As Long
    Dim lCodec
    
    If lpString = 0 Then
        StringFromPointer = ""
        Exit Function
    End If
    
    lMaxLength = lstrlen(ByVal lpString) * 2
    
    If IsBadStringPtrByLong(lpString, lMaxLength) Then
        StringFromPointer = ""
        Exit Function
    End If
    
    sRet = Space$(lMaxLength)
    CopyMemory ByVal sRet, ByVal lpString, Len(sRet)
    
    StringFromPointer = StrConv(sRet, vbFromUnicode) 'sRet
End Function



Private Sub Form_Unload(Cancel As Integer)
Set Form1 = Nothing
End Sub
 
>I was really wanting to convert the original BMP into a signal that could be sent to another computer via a propertybag, not displayed in a local picture box.


I am aware of your goals, ted. I was the one that suggested a propertybag solution to you. But we moved on because of performance issues you ahd when the image got too large, and replaced it with a stream implementation.

We showed you how to use a stream.

And my GDI+ code shows how to convert the image into a jpeg and put it into a stream. For the sake of keeping the example of this base technique simple it only uses the stream locally to finally display in a picture box. But that code would actually sit on the client PC for your real solution.
 
Thanks but as I said any attempt to intercept the stream causes the editor to freeze so I cant work out how to put the GDI stream into the propertybag to send it.
Even moving the mouse over the word MyStream causes the editor to freeze!
The GDI Mystream seems to be different to an ADODB stream previously used but I cant tell for sure.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top