[vb6] Enhancing VB's StdPicture Object to Support GDI+
This is my second version of the logic first introduced here. That version will no longer be supported.
In short, this is a stand-alone class. It can enable VB image controls, forms, picture boxes, etc to display other image formats VB cannot support. It can display images with higher quality scaling and lots of options. This class even has the ability to treat an image control like a picture box -- draw whatever you want, wherever you want, within the image control. For those that only need to load images for simple display, the call is as easy as the following, not much different than VB's LoadPicture. The class can load files, arrays, Windows image handles and more.
Code:
Dim cLoader As New StdPicEx2
Set Image1.Picture = cLoader.LoadPictureEx([source])
This second attempt offers so much more than the previous one:
1. GDI+ can be used for improved scaling for all image formats
2. Better (far more complex) thunk used for managing stdPictures
3. Callbacks can be requested so you can respond to the entire rendering process
4. Can attach GDI+ image attributes (grayscaling/blending) to managed images
5. Can modify GDI+ graphics object during callbacks, i.e., rotation (sample in attached zip)
6. Can cache original image format and retrieve for saving to file
7. Can create resized, high quality scaled bitmaps and/or icons via CopyStdPicture
8. Can return embedded image DPI value
9. Written to address backward and future version compatibility
10. Only affects those stdPicture objects that are managed
As with the previous version of this class, many image formats are supported:
- BMP. Those with valid alpha channels can be rendered with transparency. VB-unsupported formats are supported and include: those with v4/v5 bitmap headers and those with JPG/PNG compression
- JPG. CMYK color-space supported via GDI+. Camera-orientation correction supported
- ICO. Alphablended and PNG-encoded icons are supported
- CUR. Same as icons and also color cursors can be returned while in IDE, unlike VB
- WMF/EMF. Not directly managed, no need. Non-placeable WMFs are supported
- PNG. Supported via GDI+, APNG is now supported
- TIF. Supported via GDI+, multi-page navigation supported
- GIF. Rendering of individual frames (animated GIF) supported via GDI+
- For any other format, if you can convert it to bitmap (alpha channel or not), then supported
The enclosed class offers several methods for managing stdPictures, among those:
- LoadPictureEx creates a new stdPicture object by file, array or handle and supports unicode file names
- LoadResPictureEx is a slightly extended version of VB's LoadResPicture function
- UnmanageStdPicture removes existing stdPicture objects from management
- CopyStdPicture can copy/create/convert icons and bitmaps with/without alpha channels
- PaintPictureEx is a substitute for VB's PaintPicture, BitBlt, StretchBlt, AlphaBlend
- SetCallBacks enables receiving one or more of the 4 available callbacks
- SetImageAttributesHandle associates user-provided GDI+ attributes with a managed image
- PictureTypeEx can return the actual image format, i.e., PNG, JPG, TIF, etc
- SetFrameGifPng/GetGifPngAnimationInfo applies for animated GIF/PNG when managed
- SetPageTIF applies for muliti-page TIFs when managed
- GetFramePageCount will return count for managed GIF/TIF
- several other methods are available for optional settings
--------------------------------------------------------------------------
The attachments below are the sample project (all in one zip exceeds forum limits mostly due to sample images). The 1st three below must be unzipped in same folder. The stdPicEx2 class is a stand-alone class included in the zips. The rest of the files are to show-off some of its capabilities. The 4th one below is documentation that you may be interested in. It also includes the thunk raw source before I compiled it with NASM.
Project not guaranteed to be compatible with systems lower than XP (GDI+ required), but XP/Win2K and above should be supported. GDI+ v1.0 can be redistributed to those older systems.
The sample project includes GIF/APNG animation, PNG/TIF support, alphablended icon support, JPG camera-orientation correction, zoom/pan example, GDI+ attribute usage, and more. Just FYI: If the StdPicEx2 class is ever included as its own attachment below, it will be an updated version that may not be in the sample project.
Latest changes... 25 April 2018
Many changes made. See posts #29 & #30 for more information. Previous version should not be used.
Last edited by LaVolpe; Apr 25th, 2020 at 12:59 PM.
Reason: updated project
Insomnia is just a byproduct of, "It can't be done"
This class has no real effect on pictures, with 2 exceptions, that will be used by VB that are not displayed on a form/container. For example, Form.Icon, Form.MouseIcon, and CommandButton.Picture properties, etc. If the picture object does not get drawn from a call to its Render method, the class has no effect on it after picture is loaded. The properties just mentioned are basically bitmap/icon handles used by Windows; they are not "rendered" to the form. The two exceptions
a. If you will also be using PaintPicture to render the image elsewhere, the class can be used to ensure transparency and higher quality scaling.
b. If your app is DPI aware, VB doesn't scale images (except metafiles) to DPI. Class can be used to scale these images and extract DPI-appropriate icons from your res file if those icons contain multiple images.
Managed. This term is used quite often in the project. Managed simply means that the picture object is not controlled completely by VB. Enhanced is the highest level of management and the thunk can control image rendering and offer you the option also. VbPlus/OwnerDrawn are styles that are not manipulated by the thunk but offer events that allow you to manipulate the rendering process. The AutoSelect style sets these as it deems as the best option, per image format. GIF/APNG/TIF frame/page navigation. The default AutoSelect management supports navigation. Read the LoadPictureEx comments for details regarding AutoSelect.
GIF enhanced scaling and animation. The absolute requirement for this is that original GIF bytes are needed when enhancing them. When you load a GIF directly into an image control, from file, and play around in the IDE runtime (scaling, animating), all works well. But if you compile the project, it no longer works. Why? Original bytes are not kept when compiled. Just the way VB works. It caches original bytes in IDE to save to your form's frx file. But when compiled, VB doesn't need to save the source to any frx files any longer; it just doesn't need to keep them for its purposes. What happens? The GIF is a bitmap that only VB can render properly via MaskBlt or other methods. The thunk only knows it as a bitmap with no transparency. Bottom line, always keep GIFs in a resource file and load them from there. Plenty of examples in the sample project of loading from a resource file.
KeepOriginalFormat. This is a parameter in the LoadPictureEx function and plays a huge role regarding transparency for PNG/TIF. If this parameter is passed False, then PNG,TIF may be converted to bitmap and, if so, transparency is lost forever depending on selected management style. PNG/TIF, unsupported by VB, will not have transparency honored unless KeepOriginalFormat is True. The default AutoSelect management style will support transparency for all formats, but may also convert formats. The advantage with AutoSelect is that you don't need to know the format in advance to ensure transparency is rendered correctly.
The CopyStdPicture routine could be used to convert all formats to icons or valid alpha-bitmaps. When your project is manifested for common controls version 6, some things are made available to you. For example, at runtime you can add alpha-bitmaps (premultiplied) to menu items via API SetMenuBitmaps. You can add a bitmap (standard alpha) or icon (standard alpha) to buttons, while keeping them themed, via SendMessage & BM_SetImage
If the class is declared using WithEvents, you have an event that is triggered during LoadPictureEx. In that event, you will be passed the image format being loaded along with some of its properties. You will also be passed the parameters you sent to LoadPictureEx. Based on that information, you can make a final decision on those parameters, changing them as needed. Typically, the AutoSelect management style is easiest to use if your main intent is for display only. If wanting to be able to save an image in its original format, i.e., JPG, PNG, TIFF, etc then you will want to customize those parameters to ensure the original format is cached. AutoSelect does not typically cache original format.
APNG support. This support is accomplished with a multi-page TIFF, behind the scenes, since GDI+ doesn't do APNG. This workaround does the job. When AutoSelect management style is chosen, the original APNG format is discarded to reduce memory usage. If you opt to select Enhanced style and keeping original format, that does increase memory usage a bit: both the APNG and TIFF source will be in use plus a VB stream that we have no real control over. Avoid keeping original format unless absolutely needed, especially if the source is already in your resource file.
Image controls for the advanced user. If you plan on using the image control as generic canvas, drawing what you want, then always ensure the control's Stretch property is True. Why? If property is False, VB clips the control to the size of the image. If the image is smaller than the control, you can't easily draw within the entire bounds of the control when False. In most of the project examples where custom drawing occurs, you will see that property set to True.
Tip: Once the class is first created, GDI+ is available to your app until the app closes. It doesn't matter if the class is subsequently released/closed. Therefore, you never have to start/stop GDI+
If you are a GDI+ veteran, you may be creating your own GDI+ images and want to manage them as stdPictures for placing into an image control possibly. In that case, here is a method that you can use to do the job. Note that I wrote it not as Public but as Friend. This allows it to be exposed from the class and also prevents having to modify the class COUNT_PUBLIC constant (which should only be done with caution)...
Code:
Friend Function ManageGDIpImage(ByVal hImage As Long) As StdPicture
' do not pass GDI+ images based on metafiles
' if function fails dispose of passed hImage else class owns the hImage
Dim hBmp As Long, lFlags As Long, tPic As StdPicture
lFlags = zzQueryFormat(hImage)
Select Case lFlags
Case picWMF, picEMF, 0& ' class/thunk not written for these - don't do it
Case Else
If zzSafeThunkAddress() Then
If lFlags = picICO Then lFlags = picBMP ' GDI+ "icon" is a bitmap
' set thunk flags: picture type, mgmt style, scaling, GDI+ image & alpha usage
lFlags = lFlags * tfShiftPicType Or tfMgmtFull Or _
tfScaleBicubic Or tfGDIpImage Or zzValidateAlphaChannel(hImage, 0&)
' create stdPicture object
If (lFlags And tfMaskTransp) Then
zzFillImage hImage, hBmp, -1&
Else
GdipCreateHBITMAPFromBitmap hImage, hBmp, -1&
End If
If hBmp Then ' manage the picture and associate the GDI+ image
Set tPic = zzHandleToStdPicture(hBmp, vbPicTypeBitmap)
If zzAddClient(tPic, lFlags, hImage) = True Then Set ManageGDIpImage = tPic
End If
End If
End Select
End Function
Tip: You may have bitmaps where a defined color is to be rendered as transparent, typically vbMagenta. Here is sample code to create a GDI+ image attributes handle. Assign the handle via the SetImageAttributesHandle function. Note: If doing this to an existing visible Image control after it has been displayed, you are introducing transparency that didn't exist before. In that case, refresh the control's parent object afterwards; else VB won't show the transparency until that is done.
Code:
Private Declare Function GdipCreateImageAttributes Lib "GdiPlus.dll" (ByRef imgAttr As Long) As Long
Private Declare Function GdipSetImageAttributesColorKeys Lib "GdiPlus.dll" (ByVal mImageattr As Long, ByVal mType As Long, ByVal mEnableFlag As Long, ByVal mColorLow As Long, ByVal mColorHigh As Long) As Long
Private Declare Function GdipDisposeImageAttributes Lib "GdiPlus.dll" (ByVal imgAttr As Long) As Long
Dim hAttr As Long, lColor As Long
lColor = vbMagenta ' what will be transparent color
' convert VB RGB to GDI+ BGR & include alpha byte
lColor = (lColor And &HFF) * &H10000 Or (lColor And &HFF00&) Or (lColor And &HFF0000) \ &H10000 Or &HFF000000
If GdipCreateImageAttributes(hAttr) = 0& Then
GdipSetImageAttributesColorKeys hAttr, 1&, 1&, lColor, lColor
' assign handle to managed stdPicture object, then destroy original; copy was made by the class
GdipDisposeImageAttributes hAttr
End If
Last edited by LaVolpe; Jun 9th, 2018 at 11:12 AM.
Insomnia is just a byproduct of, "It can't be done"
Re: [vb6] Enhancing VB's StdPicture Object to Support GDI+
Originally Posted by xxdoc123
can not load gif or png and tiff in xp sp3...
Sounds like GDI+ is not loading. Could you verify that? The class has a GDIplusVersion property and if it returns zero, that would certainly explain things. But GDI+ is also used to load everything but ico/cur/bmp and you didn't mention any issues with JPG (the scaling sample in the zips). Also, there is a class-level variable m_Debug. Set that to true and maybe report back what's printed to the immediate window. That might help narrow down the problem.
I tried to ensure I didn't use any non-XP API declarations, but maybe I missed one? If interested in helping troubleshoot the problem, PM me and we can walk through it. Don't really want to use this thread for what could be lengthy back & forth while troubleshooting.
Edited: I don't have real access to XP any longer, so my input if working together will be mostly questions and suggestions.
Last edited by LaVolpe; Mar 20th, 2018 at 03:42 PM.
Insomnia is just a byproduct of, "It can't be done"
Re: [vb6] Enhancing VB's StdPicture Object to Support GDI+
Originally Posted by DEXWERX
would you ever consider rewriting all the thunks to a .Bas module?
or using DispCallFunc instead of CallWindowProc.
Should be doable via use of faux-VTables as bas methods. I like the class structure with its terminate/initialize event and ability to be declared WithEvents. Whether I will do this or not is up in the air. I'll consider it. Callbacks would still require either a class or forced public/friend method to forward from the bas to the requesting form/class/uc.
Insomnia is just a byproduct of, "It can't be done"
Re: [vb6] Enhancing VB's StdPicture Object to Support GDI+
Originally Posted by LaVolpe
Sounds like GDI+ is not loading. Could you verify that? The class has a GDIplusVersion property and if it returns zero, that would certainly explain things. But GDI+ is also used to load everything but ico/cur/bmp and you didn't mention any issues with JPG (the scaling sample in the zips). Also, there is a class-level variable m_Debug. Set that to true and maybe report back what's printed to the immediate window. That might help narrow down the problem.
I tried to ensure I didn't use any non-XP API declarations, but maybe I missed one? If interested in helping troubleshoot the problem, PM me and we can walk through it. Don't really want to use this thread for what could be lengthy back & forth while troubleshooting.
Edited: I don't have real access to XP any longer, so my input if working together will be mostly questions and suggestions.
i found not load png gif in my win7 32 Chinese system too.
Code:
' sanity check. Difference in VTable addresses MUST always be 96
CopyMemory nIPicVtable, ByVal lIPicPtr, 4&
CopyMemory p, ByVal lStdPicPtr, 4&
If Not ((nIPicVtable - p) = 96&) Then Exit Function 'this not true ,(nIPicVtable - p)=100<>96 so end
Code:
If zzAddClient(tPic, lFlags Or (ManageStyle - 1&) * &H1000, hImage, hGlobal, lSize) = False Then
If hImage Then GdipDisposeImage hImage ' clean up, stdPicture/stream released on exit....
Set tPic = Nothing ....... tpic is nothing ..
ElseIf hGlobal Then
Re: [vb6] Enhancing VB's StdPicture Object to Support GDI+
Originally Posted by xxdoc123
i found not load png gif in my win7 32 Chinese system too.
Code:
' sanity check. Difference in VTable addresses MUST always be 96
If Not ((nIPicVtable - p) = 96&) Then Exit Function 'this not true ,(nIPicVtable - p)=100<>96 so end
Well, that explains everything. I created that sanity check to prevent crashes if the interface VTable signature was different than I expected. From what you've posted, either the StdPicture interface has an extra function pointer than what is expected or an extra 4 byte value VB is using to track something. In any case, this will require me rethinking how to handle this scenario. It will ultimately require me to tweak the thunk.
P.S. I wonder if it has something to do with non-US systems? I've even tested this in MS Access and the 96-byte offset rule applied there too, so I thought it was a standard VB/VBA thing. Thanx for the bug report. I'll mess with an updated thunk and post that back to this thread just for your testing.
Follow up... Here's a substitute class. When you have the time, let me know if it works now. Also look at the next posting below. Since you have XP, you'll likely have problems with frmIcons loading initially.
*** attachment removed
Last edited by LaVolpe; Mar 22nd, 2018 at 10:13 PM.
Insomnia is just a byproduct of, "It can't be done"
Re: [vb6] Enhancing VB's StdPicture Object to Support GDI+
Keith: frmIcons has a problem with Image2
LogFile: Line 59: Property Picture in Image2 could not be set.
Code:
Begin VB.Image Image2
Height = 570
Index = 1
Left = 3555
Top = 1830
Width = 960
End
Begin VB.Image Image2
Height = 720
Index = 0
Left = 2595
Picture = "frmIcons.frx":04F2
Top = 1830
Width = 720
End
Re: [vb6] Enhancing VB's StdPicture Object to Support GDI+
Originally Posted by VBClassic04
Keith: frmIcons has a problem with Image2
LogFile: Line 59: Property Picture in Image2 could not be set.
Sounds like the frx file wasn't found. Were all zips extracted into the same folder?
I don't have access to VB right now, can't recall if that is an XP-style icon. If it is, and on pre-Vista. That is likely the problem because XP didn't support adding those in design: Invalid Picture error. If so, you could probably still run the sample project but that icon example will not work of course (just remove the "Picture" line from the form you posted above). Regardless, when I update the project, I'll move that icon into the res file to prevent that problems with systems that can't load XP-icons at design time.
Last edited by LaVolpe; Mar 21st, 2018 at 05:32 PM.
Insomnia is just a byproduct of, "It can't be done"
Re: [vb6] Enhancing VB's StdPicture Object to Support GDI+
Originally Posted by LaVolpe
Well, that explains everything. I created that sanity check to prevent crashes if the interface VTable signature was different than I expected. From what you've posted, either the StdPicture interface has an extra function pointer than what is expected or an extra 4 byte value VB is using to track something. In any case, this will require me rethinking how to handle this scenario. It will ultimately require me to tweak the thunk.
P.S. I wonder if it has something to do with non-US systems? I've even tested this in MS Access and the 96-byte offset rule applied there too, so I thought it was a standard VB/VBA thing. Thanx for the bug report. I'll mess with an updated thunk and post that back to this thread just for your testing.
Follow up... Here's a substitute class. When you have the time, let me know if it works now. Also look at the next posting below. Since you have XP, you'll likely have problems with frmIcons loading initially.
thanks
but i test in my win7 .....vb6 crashes
Last edited by xxdoc123; Mar 22nd, 2018 at 02:38 AM.
Re: [vb6] Enhancing VB's StdPicture Object to Support GDI+
Originally Posted by xxdoc123
thanks
but i test in my win7 .....vb6 crashes
Ugh, and sorry. Kinda hard to code for something I can't see or test myself.
In the zzCreateRedirection routine, you will find a line: nBuffer = nBuffer - 96&
If you change that line to: nBuffer = (nBuffer - 96&) \ 4, that may resolve the crash
Insomnia is just a byproduct of, "It can't be done"
Re: [vb6] Enhancing VB's StdPicture Object to Support GDI+
Test from Win 7 in IDE
Alpha-blended Icons -> OK
Scaling -> OK
GIF Animation -> 'Hmmm, Something went....'
PaintPicture Issues -> Do not show picture
PNG/TIF & Alpha Bitmaps -> Sample.tiff not found in project folder
-> Set tPic = cRenderer.LoadPictureEx(App.Path & "\sample.tiff", mgtEnhanced, , lDPI)
Owner-Drawn Example -> Error 91
Re: [vb6] Enhancing VB's StdPicture Object to Support GDI+
Originally Posted by darjeeling
Test from Win 7 in IDE
Alpha-blended Icons -> OK
Scaling -> OK
GIF Animation -> 'Hmmm, Something went....'
PaintPicture Issues -> Do not show picture
PNG/TIF & Alpha Bitmaps -> Sample.tiff not found in project folder
-> Set tPic = cRenderer.LoadPictureEx(App.Path & "\sample.tiff", mgtEnhanced, , lDPI)
Owner-Drawn Example -> Error 91
This definitely sounds like all the zip contents were not moved into the same folder and/or you didn't activate the project from that folder. Otherwise this error cannot occur: Sample.tiff not found in project folder. It would be helpful, when bugs reported, to indicate O/S and maybe even whether or not this is not a US-based O/S (i.e., China, etc)?
Insomnia is just a byproduct of, "It can't be done"
Re: [vb6] Enhancing VB's StdPicture Object to Support GDI+
Originally Posted by LaVolpe
This definitely sounds like all the zip contents were not moved into the same folder and/or you didn't activate the project from that folder. Otherwise this error cannot occur: Sample.tiff not found in project folder. It would be helpful, when bugs reported, to indicate O/S and maybe even whether or not this is not a US-based O/S (i.e., China, etc)?
Sorry LaVolpe but all the zip content were moved first in the project folder.
I've also wrote 'Test from Win 7 in IDE'
The only difference is my localisation -> French (i use VB6FR.dll)
Last edited by darjeeling; Mar 22nd, 2018 at 10:30 AM.
Re: [vb6] Enhancing VB's StdPicture Object to Support GDI+
Originally Posted by darjeeling
The only difference is my localisation -> French (i use VB6FR.dll)
This may be a similar issue trying to work through in post 8. The tiff not being found could be due to unicode. The sample project used VB's App.Path value (not unicode-aware?) and may have garbled the path? If you want to play, you can try the other class version in post 22 below. The tiff not found will likely still happen in that case, but hopefully the rest of the project will run?
If I can't get this working reliably on non-US locales, at least Vista and above, then I'll abandon the project.
Last edited by LaVolpe; Mar 22nd, 2018 at 10:25 PM.
Insomnia is just a byproduct of, "It can't be done"
Re: [vb6] Enhancing VB's StdPicture Object to Support GDI+
Originally Posted by LaVolpe
This may be a similar issue trying to work through in posts 8 and 12 above. The tiff not being found could be due to unicode. The sample project used VB's App.Path value (not unicode-aware?) and may have garbled the path? If you want to play, you can try the other class version in post 8 and fix the one line mentioned in post 12. The tiff not found will likely still happen in that case, but hopefully the rest of the project will run?
If I can't get this working reliably on non-US locales, at least Vista and above, then I'll abandon the project.
thanks.i test nBuffer = (nBuffer - 96&) \ 4, that resolve the crash....
but load gif may have a error msgbox
Code:
' sanity checks in case gif failed to load with navigation
If Not (cRenderer.PictureTypeEx(Image1(0).Picture) = picGIF And cRenderer.PictureTypeEx(Image1(1).Picture) = picGIF) Then
MsgBox "Hmmm, something went wrong while loading the sample GIF file", vbExclamation + vbOKOnly
Command1.Enabled = False
End If
Re: [vb6] Enhancing VB's StdPicture Object to Support GDI+
Originally Posted by xxdoc123
thanks.i test nBuffer = (nBuffer - 96&) \ 4, that resolve the crash....
but load gif may have a error msgbox
Cool. The unexpected 100 vs 96 byte offset may be solved. Now what's up with GIFs? It seems as if the GIF or its VB picture object failed somewhere in the process. Is this another non-US locale issue?
Please set that m_Debug variable back to true. Can only think of two things that may help narrow it down.
1. The thunk is not updating its client count, but that would be hard to believe. In that PictureTypeEx routine, you can add this to validate that:
Code:
Dim nCount As Long
If zzSafeThunkAddress() Then
CopyMemory nCount, ByVal p_ThunkAddr, 4: MsgBox "Client Count is " & nCount
2. The thunk could not find the passed picture in its records. If so, this line in that routine will return < 1:
CallThunk(f_MsgAddr, lObjPtr, msgObjPtrIndex)
Edited: Do the other sample forms appear to be working correctly?
Last edited by LaVolpe; Mar 22nd, 2018 at 08:17 PM.
Insomnia is just a byproduct of, "It can't be done"
Re: [vb6] Enhancing VB's StdPicture Object to Support GDI+
No, it may not be crashing but either the redirection of the stdPicture/picture objects is not taking affect or something else is going on. This is what that sample form should look like: notice the blue in the cursor, the alphablended icon correctly drawn and could be hard to see, but the bottom right icon has smoother edges than the one to the left of it. I think this also, somehow, explains the GIF
If you can turn on the m_Debug variable, the printout may help a bit.
** screenshot removed
Last edited by LaVolpe; Mar 22nd, 2018 at 11:33 PM.
Insomnia is just a byproduct of, "It can't be done"
Re: [vb6] Enhancing VB's StdPicture Object to Support GDI+
Originally Posted by LaVolpe
No, it may not be crashing but either the redirection of the stdPicture/picture objects is not taking affect or something else is going on. This is what that sample form should look like: notice the blue in the cursor, the alphablended icon correctly drawn and could be hard to see, but the bottom right icon has smoother edges than the one to the left of it. I think this also, somehow, explains the GIF
If you can turn on the m_Debug variable, the printout may help a bit.
Re: [vb6] Enhancing VB's StdPicture Object to Support GDI+
Gotta admit, getting kinda confused here. If the GIF animation sample form is only shown, here's what triggers for me
thunk already exists << occurs when frmStdPicExTest is shown
thunk already exists << occurs when frmAnimate is shown
initializing arrays, no clients << occurs in zzCreateRedirection when client count = 0 (zzCreateRedirection is called from zzAddClient)
image managed with flags: 0x18001703 << occurs at end of zzAddClient (1st GIF)
image managed with flags: 0x18001703 << occurs at end of zzAddClient (2nd GIF)
So, based on the above, it appears the zzAddClient is not being called, or if it is then it is failing to return True. This could be because that routine also calls zzCreateRedirection (which can return False & abort zzAddClient). If you put a break-point on this line in zzAddClient, either the code never stops there or if it does, is the value zero?
Code:
If lRedirect = 0& Then
You can give me a complete modified stdPicEx2.cls
** attachment removed, project updated in post #1 with applicable changes
Last edited by LaVolpe; Mar 25th, 2018 at 01:27 PM.
Insomnia is just a byproduct of, "It can't be done"
Re: [vb6] Enhancing VB's StdPicture Object to Support GDI+
Originally Posted by xxdoc123
ooooo. i'm sorry.now work fine.
I modified the wrong place
now run good in my win7 ...
Really!!!! The alpha-bitmaps all work and the GIF and that owner-drawn example too? In that animated GIF you sent me, the alpha-bitmaps weren't drawn correctly and the PNG appeared to be filled, no transparency. So all is good?
Insomnia is just a byproduct of, "It can't be done"
Re: [vb6] Enhancing VB's StdPicture Object to Support GDI+
Originally Posted by LaVolpe
Really!!!! The alpha-bitmaps all work and the GIF and that owner-drawn example too? In that animated GIF you sent me, the alpha-bitmaps weren't drawn correctly and the PNG appeared to be filled, no transparency. So all is good?
all run ok
Code:
thunk being created
thunk already exists
initializing arrays, no clients
new redirection table begin created for vTable 1974744600
image managed with flags: 0x2500130A
image managed with flags: 0x2500130A
thunk already exists
initializing arrays, no clients
new redirection table begin created for vTable 1974744600
image managed with flags: 0x06001700
image managed with flags: 0x06001700
image managed with flags: 0x01001300
image managed with flags: 0x01001300
thunk already exists
thunk already exists
initializing arrays, no clients
new redirection table begin created for vTable 1974744600
image managed with flags: 0x18001703
image managed with flags: 0x18001703
thunk already exists
initializing arrays, no clients
new redirection table begin created for vTable 1974744600
image managed with flags: 0x21001302
thunk already exists
thunk already exists
initializing arrays, no clients
new redirection table begin created for vTable 1974744600
image managed with flags: 0x41001302
image managed with flags: 0x21001302
image managed with flags: 0x27001703
image managed with flags: 0x01001300
thunk already exists
thunk already exists
initializing arrays, no clients
new redirection table begin created for vTable 1974744600
image managed with flags: 0x27001703
image managed with flags: 0x01002000
image managed with flags: 0x01002000
image managed with flags: 0x01002000
image managed with flags: 0x01002000
Re: [vb6] Enhancing VB's StdPicture Object to Support GDI+
Fantastic, now I can post the patch this weekend and update a couple other small things. Hopefully I'll hear from darjeeling that the updated class worked there too (french install).
Thanx a bunch for helping troubleshoot this. If you didn't mention that 100 byte gap between the VTables, I don't think I would have ever figured this out, not in such short time anyway. Really appreciate the effort you gave. Have a good day/night.
Insomnia is just a byproduct of, "It can't be done"
Re: [vb6] Enhancing VB's StdPicture Object to Support GDI+
The project has been modified and re-uploaded. Summary of key changes:
1. Thunk and class modified to prevent problems associated with VTable layout in non-US VB installs. In short, expected a 96 byte offset between the start of 2 VTables. That offset can differ and the class modified to allow a reasonable difference between offsets. Since the offset is dynamic, the thunk was modified to cache both VTable locations vs caching just one and using simple math to determine the other's location.
2. Added new management style: mgtAutoSelect. It is now the default management style. This default style is used to favor transparency support and lower overall memory usage. When this style is chosen, the KeepOriginalFormat parameter in LoadPictureEx is ignored and set automatically. Also, depending on image format, the following summary applies:
WMF/EMF: original bytes not kept, VbOnly style chosen
BMP: Enhanced style chosen, PNG converted to alpha-supported bitmap, original bytes not kept
ICO, CUR: Enhanced style chosen, original bytes not kept
GIF: Enhanced style chosen, original bytes kept, can navigate frames
TIF/PNG: Enhanced, no original format kept. Single image format is converted to alpha-supported bitmap else navigation is enabled
JPG: Processed as enhanced (orientation-correction/CMYK supported), then converted to bitmap, original bytes not kept
3. The ManageStdPicture and LoadPictureEx were both using similar code with variations unique to their needs. Reworked the class to organize management into separate functions, one for each image format, i.e., zzManageBMP, zzManagePNG, etc. Easier to debug/modify.
Just FYI: The thunk appears to be crash proof. Therefore, if anyone experiences crashing due to this class, please let me know. It likely will not be the thunk, instead will be a logic flaw in the class that is not correctly tracking stream and/or GDI+ object references/use during user-defined toggling of different management styles. I honestly believe I got all that correct, but project is complex and ...
Last edited by LaVolpe; Apr 23rd, 2018 at 03:27 PM.
Insomnia is just a byproduct of, "It can't be done"
Re: [vb6] Enhancing VB's StdPicture Object to Support GDI+
To all. I've updated the project originally to just tweak a thunk logic error, but as usual, kept enhancing the stdPicEx2 class...
1. Thunk logic error corrected. During optional rendering events, user may change the destination coordinates and the thunk was creating a GDI+ clipping region based on those coords, when applicable. This was wrong. Those coords may result in rendering outside of an image control which flows over to the control's parent. The clipping region is now correct, using original coords, not user-modified coords.
2. Removed the ManageStdPicture function. That function's intent was to change management properties after LoadPictureEx returned with your picture. I wanted a proactive method instead. So, a new event was added. That event is called while LoadPictureEx is loading the image. The event allows you to modify the parameters you sent to LoadPictureEx. In that event, you are also provided the image's format/type, dimensions and other related data to better adjust/choose management style and options before the image is committed to management. This event's name is PreLoadPicture.
3. Added UnmanageStdPicture method. The removed ManageStdPicture function enabled that option. So, needed a replacement option.
4. The LoadPictureEx function was tweaked for two purposes:
a. The Source parameter can now accept a VB stdPicture object. This allows managing an existing unmanaged picture.
b. An optional parameter was provided for your use. That parameter is sent to the new PreLoadPicture event
5. Added a GDIplusImage public property. This will return a GDI+ image based on the passed picture. The image is for your use and must be disposed of by you.
6. Added APNG support. Its key public property is: EnableAPNGSupport. By default, APNG is not supported & the new property will enable support. Reason not supported by default is because APNG detection/validation requires manually parsing the PNG source. Since APNG is not common in the wild, didn't want to parse every PNG source for another sub-format that may not be used. Simply activate the property as needed.
FYI: VB & GDI+ cannot support APNG natively. How does the class do it then? It does use GDI+ but converts the APNG frames to a multi-page TIFF. During animation, the class is really navigating the TIFF pages behind the scenes.
Edited.
7. For those using the previous version, two public functions were renamed when APNG support was added:
- renamed GetGIFAnimationInfo to GetGifPngAnimationInfo
- renamed SetFrameGIF to SetFrameGifPng
In the stdPicEx2 class, jump to bottom of class for a more detailed change history
Last edited by LaVolpe; Apr 24th, 2018 at 09:41 AM.
Insomnia is just a byproduct of, "It can't be done"
Re: [vb6] Enhancing VB's StdPicture Object to Support GDI+
Found a major problem with the logic used to redirect VB picture objects to a custom VTable. Bottom line, assumption was that the 2 key VTables were always stacked on each other with/without a small gap in bytes. In my tests, this assumption held true for years until yesterday. On the same machine I've used countless times, the VTables were stacked in reverse. This prevented the class in redirecting pictures, in effect, defaulting to VB for rendering. Good news was that the class is well-written and did not cause crashes, it simply recognized a problem and defaulted to VB handling only. Bad news, no transparency was rendered.
This problem has been fixed. Backward compatibility, however, is lost. In the screenshot below you can see how one sample form is correctly rendered (on the left) vs. only VB handling the picture (on the right). If you don't see transparency rendered correctly, please post a bug report in this thread.
Last edited by LaVolpe; Apr 25th, 2018 at 11:57 AM.
Insomnia is just a byproduct of, "It can't be done"
Re: [vb6] Enhancing VB's StdPicture Object to Support GDI+
Hello LaVolpe,
quick side information:
I have quickly tested the class within MS Excel 2016 VBA .
VBA can (unfortionally) use only VBE7.DLL and not msvbvm60.dll.
since IPicture is limited to VB6 (msvbvm60.dll) i stopped to use workarounds (like custom enums for PictureTypeConstants or ugly variant variables)
but your class / logic (within a vb6 compiled active X DLL) work properly with MS Excel forms / the MSForm2 Image control.
The handling within a floating image control (used on a spread sheet) is as expected not optimal. (works only once focused)
But as mentioned - this was just for testing purpose.
You have posted again a a very solid solution - which is likewise quite small.
Re: [vb6] Enhancing VB's StdPicture Object to Support GDI+
Hi LaVolpe! Two things, first thank you for this amazing class and always sharing your knowledge!!! Second, I found a way to do what I want but wanna know if this is the correct way or I missed something.
I draw a few lines to a picture box and then copy the resulting image to another picturebox but scaled down ( your class offers a better antialiased downscaling than paintpicture)
My code is this:
Code:
'Draw a few lines in Picture1 Picture1.DrawWidth = 2
For i = 1 To 15
Picture1.Line (0, 0)-(Rnd() * 300, Rnd() * 300), RGB(Rnd() * 255, Rnd() * 255, Rnd() * 255)
Next i
'Copy picture1 scaled down to picture2
Dim cRenderer As New stdPicEx2
Dim p1 As StdPicture
Set p1 = cRenderer.CopyStdPicture(Picture1.Image, 0, 0)
cRenderer.PaintPictureEx Picture2, p1, 0, 0, 150, 150
Picture2.Refresh
Re: [vb6] Enhancing VB's StdPicture Object to Support GDI+
If it works for you then should be ok. However, instead of returning the picture and painting it at a scaled dimension, couldn't you just request the copy in the scaled size? Then set it to Picture2? The assumption is that nothing else is painted on Picture2 or Picture2 doesn't already have a picture assigned.
Just thinking out loud...
Code:
'Copy picture1 scaled down to picture2
Dim cRenderer As New stdPicEx2
' Dim p1 As StdPicture
Set Picture2.Picture = cRenderer.CopyStdPicture(Picture1.Image, 150, 150)
' cRenderer.PaintPictureEx Picture2, p1, 0, 0, 150, 150
' Picture2.Refresh
Insomnia is just a byproduct of, "It can't be done"
Re: [vb6] Enhancing VB's StdPicture Object to Support GDI+
Originally Posted by LaVolpe
If it works for you then should be ok. However, instead of returning the picture and painting it at a scaled dimension, couldn't you just request the copy in the scaled size? Then set it to Picture2? The assumption is that nothing else is painted on Picture2 or Picture2 doesn't already have a picture assigned.
Just thinking out loud...
Code:
'Copy picture1 scaled down to picture2
Dim cRenderer As New stdPicEx2
' Dim p1 As StdPicture
Set Picture2.Picture = cRenderer.CopyStdPicture(Picture1.Image, 150, 150)
' cRenderer.PaintPictureEx Picture2, p1, 0, 0, 150, 150
' Picture2.Refresh
That's exactly the correction I expected! I knew I was doing something that can be avoided. Thanks master LaVolpe!
Re: [vb6] Enhancing VB's StdPicture Object to Support GDI+
Hi LaVolpe!
First thanks for making this class and example project, this is some really great work. I'm a long time VB6 user and I've recently started using the language again.
I have been working on a fairly simple game using this class for all of the drawing, specifically the owner drawn sample. For the most part it's been fairly easy to get going with this as a basis, but I am running into difficulties debugging the code due to IDE crashes.
I just reloaded the test project from the first post and was able to recreate what typically happens to me:
1. Open the test project
2. Go to frmOD.cStdPicEx_OwnerDrawn event handler
3. Insert an invalid symbol at the top of the function -- like TestTestTest
4. Run the project, open the owner drawn example
5. IDE stops on the invalid symbol
6. Press Stop button in debug toolbar
7. IDE crashes
Is there any way to adjust the project so that it can cleanup when the debug Stop command is used? So far while working on my game I've had dozens of crashes per day and have to resort to Debug.Print "debugging" methods (which I'm not all that unfamiliar with, having done a lot of PHP in the early days as well when that was the only option, ugh).
Anyway, just wanted to see if this is something that can be fixed or worked around.
Re: [vb6] Enhancing VB's StdPicture Object to Support GDI+
Don't hit STOP, never hit STOP or END while in a callback procedure.
1. If an error occurs, click the Debug button to highlight the error.
2. Now, see that yellow arrow in the margin? Click and drag it to the End Sub or somewhere else in the routine to skip past the line with the error. The highlight will change to the line you dragged the arrow. You must drag the arrow on an executable line, not a comment, not a label, not a Dim statement.
3. Place an Exit Sub at top of routine. You want to prevent the error from occurring again before you can safely close your form.
4. Press F5 to continue
5. Close the form, go back to the problem and fix it. Remove that "Exit Sub" if you added it in step 3
Your other choice is to use error trapping. Debug.Print the error and fix errors when they occur.
To answer your question. Yes it is possible to prevent crashes when user hits Stop or End while in the callback. But it would require a massive redesign. Don't want to do that if simple error-trapping can be used to limit the problem.
Last edited by LaVolpe; Apr 25th, 2020 at 12:47 PM.
Insomnia is just a byproduct of, "It can't be done"
Re: [vb6] Enhancing VB's StdPicture Object to Support GDI+
That does seem to work well for runtime errors, thanks for that.
For compiler errors it seems that I can't move the execution pointer using this technique, which I guess makes sense since the code isn't "running" yet.
In this case (which happens if I have a typo in the code), is there any other way to escape the debugger without crashing that you can think of? I tried running CodeSMART's analysis but there's quite a bit of noise in the report so I can't easily rely on that before hitting run when I've written a bunch of new code. Looking for a simpler pre-run "sanity check" type add-in, but so far haven't found one.
Re: [vb6] Enhancing VB's StdPicture Object to Support GDI+
Do you use Option Explicit at the top of your forms, classes, modules, etc? If not, do it. And always start your project using Ctrl+F5 (Start with Full Compile). That will catch all undeclared variables and typos like you are describing. Every serious coder would consider those as basic good habits. No offense, but I won't try to code around that. If anything, by being stubborn about it, I'm helping you -- whether you know it or not
P.S. In your IDE options (menu: Tools > Options), on the Editor tab, select "Require Variable Declaration". In every new form, class, module, etc that you create thereafter, Option Explicit will automatically be added. For all existing code files, you will need to manually include it. You can customize your toolbar and add the "Start With Full Compile" button to it. I always do on VB installs, sits right next to my standard "Run" button
Last edited by LaVolpe; Apr 25th, 2020 at 01:30 PM.
Insomnia is just a byproduct of, "It can't be done"
Re: [vb6] Enhancing VB's StdPicture Object to Support GDI+
Ah, Ctrl+F5. I feel like I knew this 10 years ago, sorry for the remedial advice being needed. Option Explicit is definitely something I remember and have been doing once I re-learned the lesson there.
I guess I've gotten a little pampered by Visual Studio (I do mostly C and C# programming for my "day job"), which of course does a full compile by default.
Thanks for the tips, I think I'm back on track. And thanks again for writing this library.
Re: [vb6] Enhancing VB's StdPicture Object to Support GDI+
> I guess I've gotten a little pampered by Visual Studio (I do mostly C and C# programming for my "day job"), which of course does a full compile by default.
In Options dialog on the General tab (it's the 3-rd one, don't ask) just uncheck Compile on demand checkbox and both F5 and Ctrl+F5 in VB6 will do the full compile (no need for extra toolbar button too).