<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/">
	<channel>
		<title><![CDATA[Save-Point - Direct Compilable Code]]></title>
		<link>https://www.save-point.org/</link>
		<description><![CDATA[Save-Point - https://www.save-point.org]]></description>
		<pubDate>Thu, 09 Apr 2026 22:29:41 +0000</pubDate>
		<generator>MyBB</generator>
		<item>
			<title><![CDATA[The PNG (Portable Network Graphics) Class]]></title>
			<link>https://www.save-point.org/thread-13388.html</link>
			<pubDate>Sun, 18 Jan 2026 04:29:39 +0000</pubDate>
			<dc:creator><![CDATA[<a href="https://www.save-point.org/member.php?action=profile&uid=5">DerVVulfman</a>]]></dc:creator>
			<guid isPermaLink="false">https://www.save-point.org/thread-13388.html</guid>
			<description><![CDATA[<div style="text-align: center;" class="mycode_align"><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">The PNG (Portable Network Graphics) Class</span></span><br />
<span style="font-size: medium;" class="mycode_size">Version: 1.0˃</span><br />
<span style="font-size: small;" class="mycode_size">Based upon work by Elroy of VBForums (June 22, 2022)</span></div>
<br />
<br />
<span style="font-size: medium;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Introduction</span></span><br />
<br />
Permits the loading of standard RGBA type (32bpp).PNG graphics  into a  Visual Basic 6 environment.  Due to their similarities with the format, both .TIF and TIFF graphics files are also usable.<br />
<br />
The code has been cleaned up since its original iteration, and provides a more detailed error message system if issues arise.  It also bypasses a false positive error  with certain png files  based on their color indexing.  This false error had halt class processing, now resolved.<br />
<br />
<br />
<span style="font-size: medium;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Features</span></span><ul class="mycode_list"><li>Supports loading of .png files within the Visual Basic 6 environment.<br />
</li>
<li>Supports .tif / .tiff images due to format similarities.<br />
</li>
<li>Able to define image opacity and scaling on .png file load.<br />
</li>
<li>Transparent background support<br />
</li>
<li>An updated error message system in the event issues arise.<br />
</li>
<li>Easy to use method/command.<br />
</li>
</ul>
<br />
<br />
<span style="font-size: medium;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Limitations</span></span><ul class="mycode_list"><li>Does not adapt/update the default LoadPicture command, but uses its own.<br />
</li>
<li>LoadPNG (the command/method) does not have palette nor custom size definition properties.<br />
</li>
</ul>
<br />
<br />
<span style="font-size: medium;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Code</span></span><br />
<div class="tborder">
  			<div class="thead" style="padding:4px; margin:1px;"><input type="button" class="button" value="+" style="font-family:Monospace; padding:0px" onclick="if (this.parentNode.parentNode.getElementsByTagName('div')[1].style.display=='none'){ this.parentNode.parentNode.getElementsByTagName('div')[1].style.display='';this.value='-';} else {this.parentNode.parentNode.getElementsByTagName('div')[1].style.display='none';this.value='+';}"/> Code</div>
  			<div class="trow2" style="display:none; padding:4px; margin:1px;">
<div class="codeblock"><div class="title">Code:</div><div class="body" dir="ltr"><code>' ==============================================================================<br />
' ** The PNG (Portable Network Graphics) Class<br />
' ------------------------------------------------------------------------------<br />
'&nbsp;&nbsp;&nbsp;&nbsp;by DerVVulfman<br />
'&nbsp;&nbsp;&nbsp;&nbsp;version 1.0<br />
'&nbsp;&nbsp;&nbsp;&nbsp;01-17-2026 (mm/dd/yyyy)<br />
'&nbsp;&nbsp;&nbsp;&nbsp;Based upon work by Elroy of VBForums (June 22, 2022)<br />
' ==============================================================================<br />
'<br />
' INTRODUCTION:<br />
' -------------<br />
'<br />
' Permits the loading of standard RGBA type (32bpp).PNG graphics&nbsp;&nbsp;into a&nbsp;&nbsp;Visual<br />
' Basic 6 environment.&nbsp;&nbsp;Due to their similarities with the format, both .TIF and<br />
' TIFF graphics files are also usable.<br />
'<br />
' The code has been cleaned up since its original iteration, and provides a more<br />
' detailed error message system if issues arise.&nbsp;&nbsp;It also bypasses a false posi-<br />
' tive error&nbsp;&nbsp;with certain png files&nbsp;&nbsp;based on their color indexing.&nbsp;&nbsp;This false<br />
' error had halt class processing, now resolved.<br />
'<br />
'<br />
' ==============================================================================<br />
'<br />
' CLASS INSTALLATION:<br />
' -------------------<br />
'<br />
' * In the form where used, define this class before any other action.<br />
'&nbsp;&nbsp;&nbsp;&nbsp;-- Example:&nbsp;&nbsp;Private clsPNG As New Class_PNG<br />
'<br />
'&nbsp;&nbsp; The 'clsPNG' (or like) will direct you to commands within this class.<br />
'&nbsp;&nbsp;&nbsp;&nbsp;-- Example:&nbsp;&nbsp;clsPNG.LoadPNG<br />
'<br />
' * Ensure the class instance (or instances) removed from memory upon exit.<br />
'&nbsp;&nbsp; This is done within the form's&nbsp;&nbsp;"Form_Unload" private subroutine.<br />
'&nbsp;&nbsp; -- Example:&nbsp;&nbsp;Set clsPNG = Nothing<br />
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;End<br />
'<br />
'<br />
' ==============================================================================<br />
'<br />
' METHODS:<br />
' --------<br />
'<br />
' There is only one.&nbsp;&nbsp;This method acts in place of the LoadPicture command,&nbsp;&nbsp;but<br />
' with different optional parameters:<br />
'<br />
' LOADPNG:&nbsp;&nbsp;Loads a PNG file into a supported form object (such as&nbsp;&nbsp;apicture box,<br />
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; image box, etc.).<br />
' * SYNTAX: &lt;target&gt;.picture = LoadPng(Filename [,opacity [,scaling]] )<br />
'<br />
'&nbsp;&nbsp;* Target&nbsp;&nbsp; : the image or picturebox that will contain the graphic<br />
'&nbsp;&nbsp;* Filename : the image file<br />
'&nbsp;&nbsp;* Opacity&nbsp;&nbsp;: (Optional) In byte format. IE &amp;HFF is 255 solid and &amp;H00 is 0.<br />
'&nbsp;&nbsp;* scaling&nbsp;&nbsp;: (Optional) in Single Precision floating (1 is default).<br />
'<br />
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-------------------------------------------------------------------<br />
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FOR REFERENCE:<br />
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--------------<br />
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The default LoadPicture used by VBasic 6 has the following syntax:<br />
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LoadPicture(Filename [,Size [,Colordepth [,x [,y]]]])<br />
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* Filename :&nbsp;&nbsp;&nbsp;&nbsp;The image file<br />
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* Size :&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(0-4) defines if icon, cursor, etc.<br />
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* Color Depth : (0-3): default, monochrome, 16 colors, 256 colors<br />
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* X &amp; Y :&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Custom Icon size if above Size setting is 4<br />
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Size: (0) - System Small Icon<br />
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(1) - System Large-size Icon<br />
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(2) - Caption-button size setting<br />
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(3) - Icon Size setting on the Appearance Tab<br />
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(4) - Custom Size based on further X/Y settings<br />
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-------------------------------------------------------------------<br />
'<br />
'<br />
' ==============================================================================<br />
'<br />
' ERROR MESSAGES:<br />
' ---------------<br />
'<br />
' Based on the original code by Elroy, the Graphics Error Test Subroutine (GErr)<br />
' is a private subroutine that exists throughout the LoadPng method. If there is<br />
' an issue with the .png file loading, a basic popup window will show the error.<br />
' These error messages may be a simple "Generic Error", "File Not Found", or any<br />
' of the 20+ tracable errors.<br />
'<br />
' There are six different innstances within the LoadPng method&nbsp;&nbsp;where this error<br />
' message system may be called. Unlike the original code of 2022, the error mes-<br />
' sage will now indicate what stage (loading the GDI system, accessing the file,<br />
' etc) the error occurs.<br />
'<br />
' Being able to track which stage was taking place&nbsp;&nbsp;when a .png file was loading<br />
' was more of&nbsp;&nbsp;a development tool, but left within&nbsp;&nbsp;the error message system for<br />
' possible further debugging if ever needed.<br />
'<br />
'<br />
' ==============================================================================<br />
<br />
<br />
<br />
<br />
Option Explicit<br />
<br />
' Constant Declarations<br />
' ==============================================================================<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Const ImageLockModeRead As Long = &amp;H1&amp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Const PixelFormat32bppPARGB As Long = &amp;HE200B<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Const DIB_RGB_COLORS As Long = 0&amp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Const AC_SRC_ALPHA As Byte = 1<br />
<br />
<br />
<br />
<br />
' Structure Type Declarations<br />
' ==============================================================================<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Type GdiplusStartupInput<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GdiplusVersion&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DebugEventCallback&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SuppressBackgroundThread&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SuppressExternalCodecs&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;End Type<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Type BitmapData<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Width&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Height&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Stride&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PixelFormat&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Scan0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Reserved&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;End Type<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Type BITMAPINFOHEADER<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;biSize&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;biWidth&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;biHeight&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;biPlanes&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Integer<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;biBitCount&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Integer<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;biCompression&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;biSizeImage&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;biXPelsPerMeter&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;biYPelsPerMeter&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;biClrUsed&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;biClrImportant&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;End Type<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Type SIZEL<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cx&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cy&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;End Type<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Type RECT<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Left&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Top&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Right&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Bottom&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;End Type<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Type BLENDFUNCTION<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BlendOp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Byte<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BlendFlags&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Byte<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SourceConstantAlpha&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Byte<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AlphaFormat&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Byte<br />
&nbsp;&nbsp;&nbsp;&nbsp;End Type<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Type PictDesc<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cbSize&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;picType&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hgdiObj&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hPalOrXYExt&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Reserved&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;End Type<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Type ENHMETAHEADER<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;iType&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nSize&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rclBounds&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As RECT<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rclFrame&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As RECT<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dSignature&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nVersion&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nBytes&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nRecords&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nHandles&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Integer<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sReserved&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Integer<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nDescription&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;offDescription&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nPalEntries&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;szlDevice&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As SIZEL<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;szlMillimeters&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As SIZEL<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cbPixelFormat&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;offPixelFormat&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bOpenGL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;szlMicrometers&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As SIZEL<br />
&nbsp;&nbsp;&nbsp;&nbsp;End Type<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Type IID<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Data1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Data2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Integer<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Data3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Integer<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Data4(7&amp;)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Byte<br />
&nbsp;&nbsp;&nbsp;&nbsp;End Type<br />
<br />
<br />
<br />
<br />
' API Function Declarations<br />
' ==============================================================================<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Function GdiplusStartup Lib "gdiplus" _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByRef token As Long, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByRef lpInput As GdiplusStartupInput, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Optional ByRef lpOutput As Long) As Long<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Function GdipLoadImageFromFile Lib "gdiplus" _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByVal sFilename As Long, hImage As Long) As Long<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Function GdipBitmapLockBits Lib "gdiplus" _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByVal hBitmap As Long, lpRect As Any, ByVal lFlags As Long, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal lPixelFormat As Long, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;uLockedBitmapData As BitmapData) As Long<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Function CreateCompatibleDC Lib "gdi32" _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByVal hDC As Long) As Long<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Function CreateDIBSection Lib "gdi32" _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByVal hDC As Long, lpBitsInfo As BITMAPINFOHEADER, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal wUsage As Long, lpBitsOut As Long, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal hSection As Long, ByVal offset As Long) As Long<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Function GdipBitmapUnlockBits Lib "gdiplus" _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByVal hBitmap As Long, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;uLockedBitmapData As BitmapData) As Long<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Function GdipDisposeImage Lib "gdiplus" _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByVal image As Long) As Long<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Function SelectObject Lib "gdi32" (ByVal hDC As Long, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal hObject As Long) As Long<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Function CreateEnhMetaFileW Lib "gdi32" _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByVal hdcRef As Long, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal lpFileName As Long, lpRect As Any, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal lpDescription As Long) As Long<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Function GetDeviceCaps Lib "gdi32" (ByVal hDC As Long, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal nIndex As Long) As Long<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Function GetMem4 Lib "msvbvm60" (ByRef Source As Any, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByRef Dest As Any) As Long ' Ignore the returned value. It's useless.<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Function GdiAlphaBlend Lib "gdi32" (ByVal hdcDest As Long, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal xoriginDest As Long, ByVal yoriginDest As Long, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal wDest As Long, ByVal hDest As Long, ByVal hdcSrc As Long, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal xoriginSrc As Long, ByVal yoriginSrc As Long, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal wSrc As Long, ByVal hSrc As Long, ByVal ftn As Long) As Long<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Function DeleteDC Lib "gdi32" (ByVal hDC As Long) As Long<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Function DeleteObject Lib "gdi32" _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByVal hObject As Long) As Long<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Function CloseEnhMetaFile Lib "gdi32" _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByVal hDC As Long) As Long<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Function GetEnhMetaFileHeader Lib "gdi32" _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByVal hEmf As Long, ByVal cbBuffer As Long, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByRef lpemh As ENHMETAHEADER) As Long<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Function DeleteEnhMetaFile Lib "gdi32" _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByVal hEmf As Long) As Long<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Function OleCreatePictureIndirect Lib "oleaut32" _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(lpPictDesc As PictDesc, riid As IID, ByVal fOwn As Boolean, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lplpvObj As Object) As Long<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Function IIDFromString Lib "ole32" (ByVal lpsz As Long, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByRef clsid As IID) As Long<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Function GdiplusShutdown Lib "gdiplus" _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByVal token As Long) As Long<br />
<br />
<br />
<br />
<br />
' API Subroutine Declarations<br />
' ==============================================================================<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(Destination As Any, Source As Any, ByVal Length As Long)<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Sub AtlPixelToHiMetric Lib "atl" (lpSizeInPix As SIZEL, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lpSizeInHiMetric As SIZEL)<br />
<br />
<br />
<br />
<br />
' Variable Declarations<br />
' ==============================================================================<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private mlGdipToken&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private gdiTestID&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Integer<br />
<br />
<br />
<br />
<br />
' ==============================================================================<br />
' = CLASS FUNCTIONS ============================================================<br />
' ==============================================================================<br />
<br />
<br />
' The Initialization routine<br />
'===============================================================================<br />
Private Sub Class_Initialize()<br />
<br />
End Sub<br />
<br />
<br />
<br />
<br />
' ==============================================================================<br />
' = GENERAL FUNCTIONS ==========================================================<br />
' ==============================================================================<br />
<br />
<br />
' LOADPNG Function<br />
' ==============================================================================<br />
Public Function LoadPng(sFilename As String, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Optional ByVal bbOverallOpacity As Byte = &amp;HFF, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Optional ByVal dScalingFactor As Single = 1!) As IPicture<br />
&nbsp;&nbsp;&nbsp;&nbsp;'&nbsp;&nbsp; ========================================================================<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' --------------------------------------------------------------------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;' The sFilename should be a valid PNG file.<br />
&nbsp;&nbsp;&nbsp;&nbsp;' We can put the return of this directly into a PictureBox.Picture or an<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Image.Picture, and it will correctly show any alpha channel.<br />
&nbsp;&nbsp;&nbsp;&nbsp;' --------------------------------------------------------------------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Create BLENDFUNCTION structure for an Alpha Blend.<br />
&nbsp;&nbsp;&nbsp;&nbsp;Const AC_SRC_OVER&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Byte = 0<br />
&nbsp;&nbsp;&nbsp;&nbsp;Const AC_SRC_ALPHA&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Byte = 1<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Initialize function variables<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim StartupInput&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As GdiplusStartupInput<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim hGdipImage&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim uData&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As BitmapData<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim hMemDC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim uHdr&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As BITMAPINFOHEADER<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim hDib&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim lpBits&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim hPrevDib&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim hEmfDC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim Xscale&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Double<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim Yscale&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Double<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim bf&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As BLENDFUNCTION<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim ftn&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim hEmf&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim uDesc&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As PictDesc<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Get the GDI+ going.<br />
&nbsp;&nbsp;&nbsp;&nbsp;StartupInput.GdiplusVersion = 1&amp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;gdiTestID = 0<br />
&nbsp;&nbsp;&nbsp;&nbsp;GErr GdiplusStartup(mlGdipToken, StartupInput, 0&amp;)<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Open the file into hGdipImage.<br />
&nbsp;&nbsp;&nbsp;&nbsp;gdiTestID = 1<br />
&nbsp;&nbsp;&nbsp;&nbsp;GErr GdipLoadImageFromFile(StrPtr(sFilename), hGdipImage)<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Creates a temporary buffer of the hGdipImage's or hGdipBitmap's bits.<br />
&nbsp;&nbsp;&nbsp;&nbsp;' The bits in this temp buffer don't have to be the same format as the ori-<br />
&nbsp;&nbsp;&nbsp;&nbsp;' ginal bits format. The uData can be both an input and output, but only out-<br />
&nbsp;&nbsp;&nbsp;&nbsp;' put here because uData flag is zero. Also PNG files aren't pre-multiplied,<br />
&nbsp;&nbsp;&nbsp;&nbsp;' but we let this function do that for us, as that's what we need.<br />
&nbsp;&nbsp;&nbsp;&nbsp;gdiTestID = 2<br />
&nbsp;&nbsp;&nbsp;&nbsp;GErr GdipBitmapLockBits(hGdipImage, ByVal 0&amp;, ImageLockModeRead, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PixelFormat32bppPARGB, uData)<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Get screen compatible DC.<br />
&nbsp;&nbsp;&nbsp;&nbsp;hMemDC = CreateCompatibleDC(0&amp;)<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Fill the BITMAPINFOHEADER header for making DIB.<br />
&nbsp;&nbsp;&nbsp;&nbsp;uHdr.biSize = Len(uHdr)<br />
&nbsp;&nbsp;&nbsp;&nbsp;uHdr.biPlanes = 1<br />
&nbsp;&nbsp;&nbsp;&nbsp;uHdr.biBitCount = 32<br />
&nbsp;&nbsp;&nbsp;&nbsp;uHdr.biWidth = uData.Width&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;' Pixels.<br />
&nbsp;&nbsp;&nbsp;&nbsp;uHdr.biHeight = -uData.Height&nbsp;&nbsp; ' Pixels.<br />
&nbsp;&nbsp;&nbsp;&nbsp;uHdr.biSizeImage = uData.Stride * uData.Height<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Create an EMPTY buffer associated with the DC for image (DIB) bits, and<br />
&nbsp;&nbsp;&nbsp;&nbsp;' return pointer to the buffer (lpBits). CreateDIBSection does not use the<br />
&nbsp;&nbsp;&nbsp;&nbsp;' BITMAPINFOHEADER biXPelsPerMeter or biYPelsPerMeter and will not provide<br />
&nbsp;&nbsp;&nbsp;&nbsp;' resolution information in the BITMAPINFO structure.<br />
&nbsp;&nbsp;&nbsp;&nbsp;hDib = ApiZ(CreateDIBSection(hMemDC, uHdr, DIB_RGB_COLORS, lpBits, 0&amp;, 0&amp;))<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Copy the actual image (PARGB bits) from uData (uData.Scan0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;' into our DIBs bits (lpBits).<br />
&nbsp;&nbsp;&nbsp;&nbsp;Call CopyMemory(ByVal lpBits, ByVal uData.Scan0, uData.Stride * uData.Height)<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Cleanup - Done with the uData buffer as well as the hGdipImage.<br />
&nbsp;&nbsp;&nbsp;&nbsp;gdiTestID = 3<br />
&nbsp;&nbsp;&nbsp;&nbsp;GErr GdipBitmapUnlockBits(hGdipImage, uData)<br />
&nbsp;&nbsp;&nbsp;&nbsp;gdiTestID = 4<br />
&nbsp;&nbsp;&nbsp;&nbsp;GErr GdipDisposeImage(hGdipImage)<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Put our DIB into our memory DC.<br />
&nbsp;&nbsp;&nbsp;&nbsp;hPrevDib = ApiZ(SelectObject(hMemDC, hDib))<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Create an EMPTY EMF in a primary monitor DC with no initial size.<br />
&nbsp;&nbsp;&nbsp;&nbsp;' The DC returned by CreateEnhMetaFile can be passed to any GDI function.<br />
&nbsp;&nbsp;&nbsp;&nbsp;' It actually returns an EMF DC.<br />
&nbsp;&nbsp;&nbsp;&nbsp;hEmfDC = ApiZ(CreateEnhMetaFileW(0&amp;, 0&amp;, ByVal 0&amp;, 0&amp;))<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Calculate the EMF scaling factors from its DC, so we can use it in<br />
&nbsp;&nbsp;&nbsp;&nbsp;' GdiAlphaBlend, as GdiAlphaBlend scales based on the hEmfDC.<br />
&nbsp;&nbsp;&nbsp;&nbsp;Const HORZSIZE&nbsp;&nbsp; As Long = 4&amp;:&nbsp;&nbsp;Const VERTSIZE&nbsp;&nbsp; As Long = 6&amp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;Const HORZRES&nbsp;&nbsp;&nbsp;&nbsp;As Long = 8&amp;:&nbsp;&nbsp;Const VERTRES&nbsp;&nbsp;&nbsp;&nbsp;As Long = 10&amp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;Const LOGPIXELSX As Long = 88&amp;: Const LOGPIXELSY As Long = 90&amp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;Xscale = CDbl(GetDeviceCaps(hEmfDC, HORZRES)) / _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CDbl(GetDeviceCaps(hEmfDC, HORZSIZE)) * 25.4 / _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CDbl(GetDeviceCaps(hEmfDC, LOGPIXELSX))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;Yscale = CDbl(GetDeviceCaps(hEmfDC, VERTRES)) / _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CDbl(GetDeviceCaps(hEmfDC, VERTSIZE)) * 25.4 / _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CDbl(GetDeviceCaps(hEmfDC, LOGPIXELSY))<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Use BLENDFUNCTION structure for an Alpha Blend.<br />
&nbsp;&nbsp;&nbsp;&nbsp;bf.BlendOp = AC_SRC_OVER<br />
&nbsp;&nbsp;&nbsp;&nbsp;bf.AlphaFormat = AC_SRC_ALPHA<br />
&nbsp;&nbsp;&nbsp;&nbsp;bf.SourceConstantAlpha = bbOverallOpacity<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Must put into a Long so we can pass it ByVal.<br />
&nbsp;&nbsp;&nbsp;&nbsp;GetMem4 bf, ftn<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Copy our DIB that's in memory into our EMF+ using its DC, and scale.<br />
&nbsp;&nbsp;&nbsp;&nbsp;ApiZ GdiAlphaBlend(hEmfDC, 0&amp;, 0&amp;, CLng((CDbl(uData.Width)) * Xscale * _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dScalingFactor) + 1&amp;, CLng((CDbl(uData.Height)) * Yscale * _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dScalingFactor) + 1&amp;, hMemDC, 0&amp;, 0&amp;, uData.Width, uData.Height, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ftn), "AlphaBlend"<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Done with hMemDC and hDib, so clean them up.<br />
&nbsp;&nbsp;&nbsp;&nbsp;ApiZ SelectObject(hMemDC, hPrevDib)<br />
&nbsp;&nbsp;&nbsp;&nbsp;ApiZ DeleteDC(hMemDC)<br />
&nbsp;&nbsp;&nbsp;&nbsp;ApiZ DeleteObject(hDib)<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Clean the hEmfDC and save into the hEmf<br />
&nbsp;&nbsp;&nbsp;&nbsp;hEmf = ApiZ(CloseEnhMetaFile(hEmfDC), "CloseEnhMetaFile")<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Setup PictDesc with EMF type.<br />
&nbsp;&nbsp;&nbsp;&nbsp;uDesc.cbSize = Len(uDesc)<br />
&nbsp;&nbsp;&nbsp;&nbsp;uDesc.picType = vbPicTypeEMetafile<br />
&nbsp;&nbsp;&nbsp;&nbsp;uDesc.hgdiObj = hEmf<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Return the function by wrapping our EMF (uDesc) into the iPicture object.<br />
&nbsp;&nbsp;&nbsp;&nbsp;ApiE OleCreatePictureIndirect(uDesc, IPictureIID, 1&amp;, LoadPng)<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Shutdown the GDI+.<br />
&nbsp;&nbsp;&nbsp;&nbsp;gdiTestID = 5<br />
&nbsp;&nbsp;&nbsp;&nbsp;GErr GdiplusShutdown(mlGdipToken)<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
End Function<br />
<br />
<br />
<br />
<br />
' ==============================================================================<br />
' = PRIVATE FUNCTIONS ==========================================================<br />
' ==============================================================================<br />
<br />
<br />
' GRAPHICS ERROR TEST SUBROUTINE: Used to check for errors during execution<br />
' ==============================================================================<br />
Private Sub GErr(ByVal GdipReturn As Long)<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Initialize subroutine variables<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim sErr&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As String<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim InIDE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Boolean: Debug.Assert MakeTrue(InIDE)<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;If GdipReturn = 0&amp; Then Exit Sub ' All is well.<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Exit if the error is after a shutdown of the GDI+<br />
&nbsp;&nbsp;&nbsp;&nbsp;If GdipReturn = 1&amp; Then<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;If gdiTestID = 5 Then<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Exit Sub<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;End If<br />
&nbsp;&nbsp;&nbsp;&nbsp;End If<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Branch on returned error to get message<br />
&nbsp;&nbsp;&nbsp;&nbsp;Select Case GdipReturn<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 1&amp;:&nbsp;&nbsp;&nbsp;&nbsp;sErr = "Generic Error"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 2&amp;:&nbsp;&nbsp;&nbsp;&nbsp;sErr = "Invalid Parameter/Argument"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 3&amp;:&nbsp;&nbsp;&nbsp;&nbsp;sErr = "Out Of Memory"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 4&amp;:&nbsp;&nbsp;&nbsp;&nbsp;sErr = "Object Busy, already in use in another thread"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 5&amp;:&nbsp;&nbsp;&nbsp;&nbsp;sErr = "Insufficient Buffer, buffer specified as an argument in the API call is not large enough"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 6&amp;:&nbsp;&nbsp;&nbsp;&nbsp;sErr = "Method Not Implemented"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 7&amp;:&nbsp;&nbsp;&nbsp;&nbsp;sErr = "Win32 Error"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 8&amp;:&nbsp;&nbsp;&nbsp;&nbsp;sErr = "Wrong State"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 9&amp;:&nbsp;&nbsp;&nbsp;&nbsp;sErr = "Method Aborted"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 10&amp;:&nbsp;&nbsp; sErr = "File Not Found"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 11&amp;:&nbsp;&nbsp; sErr = "Value Overflow, arithmetic operation that produced a numeric overflow"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 12&amp;:&nbsp;&nbsp; sErr = "Access Denied"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 13&amp;:&nbsp;&nbsp; sErr = "Unknown Image Format"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 14&amp;:&nbsp;&nbsp; sErr = "Font Family Not Found"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 15&amp;:&nbsp;&nbsp; sErr = "Font Style Not Found"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 16&amp;:&nbsp;&nbsp; sErr = "Not TrueType Font"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 17&amp;:&nbsp;&nbsp; sErr = "Unsupported Gdiplus Version"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 18&amp;:&nbsp;&nbsp; sErr = "Gdiplus Not Initialized"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 19&amp;:&nbsp;&nbsp; sErr = "Property Not Found, does not exist in the image"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 20&amp;:&nbsp;&nbsp; sErr = "Property Not Supported, not supported by the format of the image"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 21&amp;:&nbsp;&nbsp; sErr = "Profile Not Found, color profile required to save an image in CMYK format was not found"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case Else:&nbsp;&nbsp;sErr = "Error Not Specified": GdipReturn = 99&amp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;End Select<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Branch on Test ID to relay which GDI+ command caused the error<br />
&nbsp;&nbsp;&nbsp;&nbsp;Select Case gdiTestID<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 1:&nbsp;&nbsp;&nbsp;&nbsp;sErr = "1 LoadImage: " &amp; sErr<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 2:&nbsp;&nbsp;&nbsp;&nbsp;sErr = "2 LockBits: " &amp; sErr<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 3:&nbsp;&nbsp;&nbsp;&nbsp;sErr = "3 UnlockBits: " &amp; sErr<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 4:&nbsp;&nbsp;&nbsp;&nbsp;sErr = "4 DisposeImage: " &amp; sErr<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 5:&nbsp;&nbsp;&nbsp;&nbsp;sErr = "5 Shutdown: " &amp; sErr<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case Else: sErr = "0 Startup: " &amp; sErr<br />
&nbsp;&nbsp;&nbsp;&nbsp;End Select<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Include GDI+ Error notification<br />
&nbsp;&nbsp;&nbsp;&nbsp;sErr = "GDI+ Error:&nbsp;&nbsp;" &amp; sErr<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Display message in Debug or pass as Raised<br />
&nbsp;&nbsp;&nbsp;&nbsp;If InIDE Then<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Debug.Print sErr<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Stop<br />
&nbsp;&nbsp;&nbsp;&nbsp;Else<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Err.Raise vbObjectError + 1147221504 - GdipReturn, , sErr<br />
&nbsp;&nbsp;&nbsp;&nbsp;End If<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
End Sub<br />
<br />
<br />
' Convert a string from the StringFromID back to original IID<br />
' ==============================================================================<br />
Private Function IPictureIID() As IID<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;ApiE IIDFromString(StrPtr("{7BF80980-BF32-101A-8BBB-00AA00300CAB}"), _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IPictureIID)<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
End Function<br />
<br />
<br />
<br />
' Api Zero:&nbsp;&nbsp;Processes messages when the error report system returns ZERO<br />
' ==============================================================================<br />
Private Function ApiZ(ApiReturn As Long, Optional sApiCall As String) As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Initialize subroutine variables<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim sErr&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As String<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim InIDE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Boolean: Debug.Assert MakeTrue(InIDE)<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Set function to passed value and exit if no Zero return<br />
&nbsp;&nbsp;&nbsp;&nbsp;If ApiReturn &lt;&gt; 0&amp; Then<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ApiZ = ApiReturn<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Exit Function<br />
&nbsp;&nbsp;&nbsp;&nbsp;End If<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Create error message based on API Call<br />
&nbsp;&nbsp;&nbsp;&nbsp;If Len(sApiCall) Then<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sErr = sApiCall &amp; " error"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Else<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sErr = "API Error"<br />
&nbsp;&nbsp;&nbsp;&nbsp;End If<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Display message in Debug or pass as Raised<br />
&nbsp;&nbsp;&nbsp;&nbsp;If InIDE Then<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Debug.Print sErr<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Stop<br />
&nbsp;&nbsp;&nbsp;&nbsp;Else<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Err.Raise vbObjectError + 1147221504, , sErr<br />
&nbsp;&nbsp;&nbsp;&nbsp;End If<br />
End Function<br />
<br />
<br />
' Api Error:&nbsp;&nbsp;A General error processing prodcedure for Non-GDI+ errors.<br />
' ==============================================================================<br />
Private Sub ApiE(ApiReturn As Long, Optional sApiCall As String)<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Initialize subroutine variables<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim sErr&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As String<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim InIDE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Boolean: Debug.Assert MakeTrue(InIDE)<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Exit if no errors<br />
&nbsp;&nbsp;&nbsp;&nbsp;If ApiReturn = 0&amp; Then Exit Sub<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Create error message based on API Call<br />
&nbsp;&nbsp;&nbsp;&nbsp;If Len(sApiCall) Then<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sErr = sApiCall &amp; " error " &amp; CStr(ApiReturn)<br />
&nbsp;&nbsp;&nbsp;&nbsp;Else<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sErr = "API Error " &amp; CStr(ApiReturn)<br />
&nbsp;&nbsp;&nbsp;&nbsp;End If<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Display message in Debug or pass as Raised<br />
&nbsp;&nbsp;&nbsp;&nbsp;If InIDE Then<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Debug.Print sErr<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Stop<br />
&nbsp;&nbsp;&nbsp;&nbsp;Else<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Err.Raise vbObjectError + 1147221504 - ApiReturn, , sErr<br />
&nbsp;&nbsp;&nbsp;&nbsp;End If<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
End Sub<br />
<br />
<br />
' Make True - Ensures a passed value is set to boolean/true by ref or otherwise.<br />
' ==============================================================================<br />
Private Function MakeTrue(ByRef b As Boolean) As Boolean<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;b = True<br />
&nbsp;&nbsp;&nbsp;&nbsp;MakeTrue = True<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
End Function</code></div></div></div>
		</div>
Or within the actual <span style="font-weight: bold;" class="mycode_b">Class_PNG.cls</span> format: 
<br />
<img src="https://www.save-point.org/images/attachtypes/zip.gif" title="ZIP File" border="0" alt=".zip" />
&nbsp;&nbsp;<a href="attachment.php?aid=3045" target="_blank" title="">Class_Png.zip</a> (Size: 6.35 KB / Downloads: 72)
<br />
<br />
<br />
<span style="font-size: medium;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Instructions</span></span><br />
Plenty... in the code itself.<br />
<br />
<br />
<span style="font-size: medium;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">FAQ</span></span><br />
The original code was not in the forum of a class, but as a basic module. It has since been streamlined while the error message system upgraded.<br />
<br />
<br />
<span style="font-size: medium;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Credits and Thanks</span></span><br />
Thanks to Elroy of VBForums who wrote the base code in 2022<br />
<br />
<br />
<span style="font-size: medium;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Terms and Conditions</span></span><br />
Use as you see fit.  No requirements other than due credit for both Elroy and myself.]]></description>
			<content:encoded><![CDATA[<div style="text-align: center;" class="mycode_align"><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">The PNG (Portable Network Graphics) Class</span></span><br />
<span style="font-size: medium;" class="mycode_size">Version: 1.0˃</span><br />
<span style="font-size: small;" class="mycode_size">Based upon work by Elroy of VBForums (June 22, 2022)</span></div>
<br />
<br />
<span style="font-size: medium;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Introduction</span></span><br />
<br />
Permits the loading of standard RGBA type (32bpp).PNG graphics  into a  Visual Basic 6 environment.  Due to their similarities with the format, both .TIF and TIFF graphics files are also usable.<br />
<br />
The code has been cleaned up since its original iteration, and provides a more detailed error message system if issues arise.  It also bypasses a false positive error  with certain png files  based on their color indexing.  This false error had halt class processing, now resolved.<br />
<br />
<br />
<span style="font-size: medium;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Features</span></span><ul class="mycode_list"><li>Supports loading of .png files within the Visual Basic 6 environment.<br />
</li>
<li>Supports .tif / .tiff images due to format similarities.<br />
</li>
<li>Able to define image opacity and scaling on .png file load.<br />
</li>
<li>Transparent background support<br />
</li>
<li>An updated error message system in the event issues arise.<br />
</li>
<li>Easy to use method/command.<br />
</li>
</ul>
<br />
<br />
<span style="font-size: medium;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Limitations</span></span><ul class="mycode_list"><li>Does not adapt/update the default LoadPicture command, but uses its own.<br />
</li>
<li>LoadPNG (the command/method) does not have palette nor custom size definition properties.<br />
</li>
</ul>
<br />
<br />
<span style="font-size: medium;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Code</span></span><br />
<div class="tborder">
  			<div class="thead" style="padding:4px; margin:1px;"><input type="button" class="button" value="+" style="font-family:Monospace; padding:0px" onclick="if (this.parentNode.parentNode.getElementsByTagName('div')[1].style.display=='none'){ this.parentNode.parentNode.getElementsByTagName('div')[1].style.display='';this.value='-';} else {this.parentNode.parentNode.getElementsByTagName('div')[1].style.display='none';this.value='+';}"/> Code</div>
  			<div class="trow2" style="display:none; padding:4px; margin:1px;">
<div class="codeblock"><div class="title">Code:</div><div class="body" dir="ltr"><code>' ==============================================================================<br />
' ** The PNG (Portable Network Graphics) Class<br />
' ------------------------------------------------------------------------------<br />
'&nbsp;&nbsp;&nbsp;&nbsp;by DerVVulfman<br />
'&nbsp;&nbsp;&nbsp;&nbsp;version 1.0<br />
'&nbsp;&nbsp;&nbsp;&nbsp;01-17-2026 (mm/dd/yyyy)<br />
'&nbsp;&nbsp;&nbsp;&nbsp;Based upon work by Elroy of VBForums (June 22, 2022)<br />
' ==============================================================================<br />
'<br />
' INTRODUCTION:<br />
' -------------<br />
'<br />
' Permits the loading of standard RGBA type (32bpp).PNG graphics&nbsp;&nbsp;into a&nbsp;&nbsp;Visual<br />
' Basic 6 environment.&nbsp;&nbsp;Due to their similarities with the format, both .TIF and<br />
' TIFF graphics files are also usable.<br />
'<br />
' The code has been cleaned up since its original iteration, and provides a more<br />
' detailed error message system if issues arise.&nbsp;&nbsp;It also bypasses a false posi-<br />
' tive error&nbsp;&nbsp;with certain png files&nbsp;&nbsp;based on their color indexing.&nbsp;&nbsp;This false<br />
' error had halt class processing, now resolved.<br />
'<br />
'<br />
' ==============================================================================<br />
'<br />
' CLASS INSTALLATION:<br />
' -------------------<br />
'<br />
' * In the form where used, define this class before any other action.<br />
'&nbsp;&nbsp;&nbsp;&nbsp;-- Example:&nbsp;&nbsp;Private clsPNG As New Class_PNG<br />
'<br />
'&nbsp;&nbsp; The 'clsPNG' (or like) will direct you to commands within this class.<br />
'&nbsp;&nbsp;&nbsp;&nbsp;-- Example:&nbsp;&nbsp;clsPNG.LoadPNG<br />
'<br />
' * Ensure the class instance (or instances) removed from memory upon exit.<br />
'&nbsp;&nbsp; This is done within the form's&nbsp;&nbsp;"Form_Unload" private subroutine.<br />
'&nbsp;&nbsp; -- Example:&nbsp;&nbsp;Set clsPNG = Nothing<br />
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;End<br />
'<br />
'<br />
' ==============================================================================<br />
'<br />
' METHODS:<br />
' --------<br />
'<br />
' There is only one.&nbsp;&nbsp;This method acts in place of the LoadPicture command,&nbsp;&nbsp;but<br />
' with different optional parameters:<br />
'<br />
' LOADPNG:&nbsp;&nbsp;Loads a PNG file into a supported form object (such as&nbsp;&nbsp;apicture box,<br />
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; image box, etc.).<br />
' * SYNTAX: &lt;target&gt;.picture = LoadPng(Filename [,opacity [,scaling]] )<br />
'<br />
'&nbsp;&nbsp;* Target&nbsp;&nbsp; : the image or picturebox that will contain the graphic<br />
'&nbsp;&nbsp;* Filename : the image file<br />
'&nbsp;&nbsp;* Opacity&nbsp;&nbsp;: (Optional) In byte format. IE &amp;HFF is 255 solid and &amp;H00 is 0.<br />
'&nbsp;&nbsp;* scaling&nbsp;&nbsp;: (Optional) in Single Precision floating (1 is default).<br />
'<br />
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-------------------------------------------------------------------<br />
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FOR REFERENCE:<br />
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--------------<br />
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The default LoadPicture used by VBasic 6 has the following syntax:<br />
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LoadPicture(Filename [,Size [,Colordepth [,x [,y]]]])<br />
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* Filename :&nbsp;&nbsp;&nbsp;&nbsp;The image file<br />
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* Size :&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(0-4) defines if icon, cursor, etc.<br />
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* Color Depth : (0-3): default, monochrome, 16 colors, 256 colors<br />
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* X &amp; Y :&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Custom Icon size if above Size setting is 4<br />
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Size: (0) - System Small Icon<br />
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(1) - System Large-size Icon<br />
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(2) - Caption-button size setting<br />
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(3) - Icon Size setting on the Appearance Tab<br />
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(4) - Custom Size based on further X/Y settings<br />
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-------------------------------------------------------------------<br />
'<br />
'<br />
' ==============================================================================<br />
'<br />
' ERROR MESSAGES:<br />
' ---------------<br />
'<br />
' Based on the original code by Elroy, the Graphics Error Test Subroutine (GErr)<br />
' is a private subroutine that exists throughout the LoadPng method. If there is<br />
' an issue with the .png file loading, a basic popup window will show the error.<br />
' These error messages may be a simple "Generic Error", "File Not Found", or any<br />
' of the 20+ tracable errors.<br />
'<br />
' There are six different innstances within the LoadPng method&nbsp;&nbsp;where this error<br />
' message system may be called. Unlike the original code of 2022, the error mes-<br />
' sage will now indicate what stage (loading the GDI system, accessing the file,<br />
' etc) the error occurs.<br />
'<br />
' Being able to track which stage was taking place&nbsp;&nbsp;when a .png file was loading<br />
' was more of&nbsp;&nbsp;a development tool, but left within&nbsp;&nbsp;the error message system for<br />
' possible further debugging if ever needed.<br />
'<br />
'<br />
' ==============================================================================<br />
<br />
<br />
<br />
<br />
Option Explicit<br />
<br />
' Constant Declarations<br />
' ==============================================================================<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Const ImageLockModeRead As Long = &amp;H1&amp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Const PixelFormat32bppPARGB As Long = &amp;HE200B<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Const DIB_RGB_COLORS As Long = 0&amp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Const AC_SRC_ALPHA As Byte = 1<br />
<br />
<br />
<br />
<br />
' Structure Type Declarations<br />
' ==============================================================================<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Type GdiplusStartupInput<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GdiplusVersion&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DebugEventCallback&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SuppressBackgroundThread&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SuppressExternalCodecs&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;End Type<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Type BitmapData<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Width&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Height&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Stride&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PixelFormat&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Scan0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Reserved&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;End Type<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Type BITMAPINFOHEADER<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;biSize&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;biWidth&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;biHeight&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;biPlanes&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Integer<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;biBitCount&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Integer<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;biCompression&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;biSizeImage&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;biXPelsPerMeter&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;biYPelsPerMeter&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;biClrUsed&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;biClrImportant&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;End Type<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Type SIZEL<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cx&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cy&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;End Type<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Type RECT<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Left&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Top&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Right&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Bottom&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;End Type<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Type BLENDFUNCTION<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BlendOp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Byte<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BlendFlags&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Byte<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SourceConstantAlpha&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Byte<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AlphaFormat&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Byte<br />
&nbsp;&nbsp;&nbsp;&nbsp;End Type<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Type PictDesc<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cbSize&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;picType&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hgdiObj&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hPalOrXYExt&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Reserved&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;End Type<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Type ENHMETAHEADER<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;iType&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nSize&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rclBounds&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As RECT<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rclFrame&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As RECT<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dSignature&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nVersion&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nBytes&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nRecords&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nHandles&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Integer<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sReserved&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Integer<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nDescription&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;offDescription&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nPalEntries&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;szlDevice&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As SIZEL<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;szlMillimeters&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As SIZEL<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cbPixelFormat&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;offPixelFormat&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bOpenGL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;szlMicrometers&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As SIZEL<br />
&nbsp;&nbsp;&nbsp;&nbsp;End Type<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Type IID<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Data1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Data2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Integer<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Data3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Integer<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Data4(7&amp;)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Byte<br />
&nbsp;&nbsp;&nbsp;&nbsp;End Type<br />
<br />
<br />
<br />
<br />
' API Function Declarations<br />
' ==============================================================================<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Function GdiplusStartup Lib "gdiplus" _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByRef token As Long, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByRef lpInput As GdiplusStartupInput, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Optional ByRef lpOutput As Long) As Long<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Function GdipLoadImageFromFile Lib "gdiplus" _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByVal sFilename As Long, hImage As Long) As Long<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Function GdipBitmapLockBits Lib "gdiplus" _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByVal hBitmap As Long, lpRect As Any, ByVal lFlags As Long, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal lPixelFormat As Long, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;uLockedBitmapData As BitmapData) As Long<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Function CreateCompatibleDC Lib "gdi32" _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByVal hDC As Long) As Long<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Function CreateDIBSection Lib "gdi32" _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByVal hDC As Long, lpBitsInfo As BITMAPINFOHEADER, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal wUsage As Long, lpBitsOut As Long, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal hSection As Long, ByVal offset As Long) As Long<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Function GdipBitmapUnlockBits Lib "gdiplus" _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByVal hBitmap As Long, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;uLockedBitmapData As BitmapData) As Long<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Function GdipDisposeImage Lib "gdiplus" _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByVal image As Long) As Long<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Function SelectObject Lib "gdi32" (ByVal hDC As Long, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal hObject As Long) As Long<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Function CreateEnhMetaFileW Lib "gdi32" _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByVal hdcRef As Long, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal lpFileName As Long, lpRect As Any, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal lpDescription As Long) As Long<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Function GetDeviceCaps Lib "gdi32" (ByVal hDC As Long, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal nIndex As Long) As Long<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Function GetMem4 Lib "msvbvm60" (ByRef Source As Any, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByRef Dest As Any) As Long ' Ignore the returned value. It's useless.<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Function GdiAlphaBlend Lib "gdi32" (ByVal hdcDest As Long, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal xoriginDest As Long, ByVal yoriginDest As Long, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal wDest As Long, ByVal hDest As Long, ByVal hdcSrc As Long, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal xoriginSrc As Long, ByVal yoriginSrc As Long, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal wSrc As Long, ByVal hSrc As Long, ByVal ftn As Long) As Long<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Function DeleteDC Lib "gdi32" (ByVal hDC As Long) As Long<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Function DeleteObject Lib "gdi32" _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByVal hObject As Long) As Long<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Function CloseEnhMetaFile Lib "gdi32" _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByVal hDC As Long) As Long<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Function GetEnhMetaFileHeader Lib "gdi32" _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByVal hEmf As Long, ByVal cbBuffer As Long, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByRef lpemh As ENHMETAHEADER) As Long<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Function DeleteEnhMetaFile Lib "gdi32" _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByVal hEmf As Long) As Long<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Function OleCreatePictureIndirect Lib "oleaut32" _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(lpPictDesc As PictDesc, riid As IID, ByVal fOwn As Boolean, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lplpvObj As Object) As Long<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Function IIDFromString Lib "ole32" (ByVal lpsz As Long, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByRef clsid As IID) As Long<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Function GdiplusShutdown Lib "gdiplus" _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByVal token As Long) As Long<br />
<br />
<br />
<br />
<br />
' API Subroutine Declarations<br />
' ==============================================================================<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(Destination As Any, Source As Any, ByVal Length As Long)<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private Declare Sub AtlPixelToHiMetric Lib "atl" (lpSizeInPix As SIZEL, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lpSizeInHiMetric As SIZEL)<br />
<br />
<br />
<br />
<br />
' Variable Declarations<br />
' ==============================================================================<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private mlGdipToken&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;Private gdiTestID&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Integer<br />
<br />
<br />
<br />
<br />
' ==============================================================================<br />
' = CLASS FUNCTIONS ============================================================<br />
' ==============================================================================<br />
<br />
<br />
' The Initialization routine<br />
'===============================================================================<br />
Private Sub Class_Initialize()<br />
<br />
End Sub<br />
<br />
<br />
<br />
<br />
' ==============================================================================<br />
' = GENERAL FUNCTIONS ==========================================================<br />
' ==============================================================================<br />
<br />
<br />
' LOADPNG Function<br />
' ==============================================================================<br />
Public Function LoadPng(sFilename As String, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Optional ByVal bbOverallOpacity As Byte = &amp;HFF, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Optional ByVal dScalingFactor As Single = 1!) As IPicture<br />
&nbsp;&nbsp;&nbsp;&nbsp;'&nbsp;&nbsp; ========================================================================<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' --------------------------------------------------------------------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;' The sFilename should be a valid PNG file.<br />
&nbsp;&nbsp;&nbsp;&nbsp;' We can put the return of this directly into a PictureBox.Picture or an<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Image.Picture, and it will correctly show any alpha channel.<br />
&nbsp;&nbsp;&nbsp;&nbsp;' --------------------------------------------------------------------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Create BLENDFUNCTION structure for an Alpha Blend.<br />
&nbsp;&nbsp;&nbsp;&nbsp;Const AC_SRC_OVER&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Byte = 0<br />
&nbsp;&nbsp;&nbsp;&nbsp;Const AC_SRC_ALPHA&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Byte = 1<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Initialize function variables<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim StartupInput&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As GdiplusStartupInput<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim hGdipImage&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim uData&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As BitmapData<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim hMemDC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim uHdr&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As BITMAPINFOHEADER<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim hDib&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim lpBits&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim hPrevDib&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim hEmfDC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim Xscale&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Double<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim Yscale&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Double<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim bf&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As BLENDFUNCTION<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim ftn&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim hEmf&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim uDesc&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As PictDesc<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Get the GDI+ going.<br />
&nbsp;&nbsp;&nbsp;&nbsp;StartupInput.GdiplusVersion = 1&amp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;gdiTestID = 0<br />
&nbsp;&nbsp;&nbsp;&nbsp;GErr GdiplusStartup(mlGdipToken, StartupInput, 0&amp;)<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Open the file into hGdipImage.<br />
&nbsp;&nbsp;&nbsp;&nbsp;gdiTestID = 1<br />
&nbsp;&nbsp;&nbsp;&nbsp;GErr GdipLoadImageFromFile(StrPtr(sFilename), hGdipImage)<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Creates a temporary buffer of the hGdipImage's or hGdipBitmap's bits.<br />
&nbsp;&nbsp;&nbsp;&nbsp;' The bits in this temp buffer don't have to be the same format as the ori-<br />
&nbsp;&nbsp;&nbsp;&nbsp;' ginal bits format. The uData can be both an input and output, but only out-<br />
&nbsp;&nbsp;&nbsp;&nbsp;' put here because uData flag is zero. Also PNG files aren't pre-multiplied,<br />
&nbsp;&nbsp;&nbsp;&nbsp;' but we let this function do that for us, as that's what we need.<br />
&nbsp;&nbsp;&nbsp;&nbsp;gdiTestID = 2<br />
&nbsp;&nbsp;&nbsp;&nbsp;GErr GdipBitmapLockBits(hGdipImage, ByVal 0&amp;, ImageLockModeRead, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PixelFormat32bppPARGB, uData)<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Get screen compatible DC.<br />
&nbsp;&nbsp;&nbsp;&nbsp;hMemDC = CreateCompatibleDC(0&amp;)<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Fill the BITMAPINFOHEADER header for making DIB.<br />
&nbsp;&nbsp;&nbsp;&nbsp;uHdr.biSize = Len(uHdr)<br />
&nbsp;&nbsp;&nbsp;&nbsp;uHdr.biPlanes = 1<br />
&nbsp;&nbsp;&nbsp;&nbsp;uHdr.biBitCount = 32<br />
&nbsp;&nbsp;&nbsp;&nbsp;uHdr.biWidth = uData.Width&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;' Pixels.<br />
&nbsp;&nbsp;&nbsp;&nbsp;uHdr.biHeight = -uData.Height&nbsp;&nbsp; ' Pixels.<br />
&nbsp;&nbsp;&nbsp;&nbsp;uHdr.biSizeImage = uData.Stride * uData.Height<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Create an EMPTY buffer associated with the DC for image (DIB) bits, and<br />
&nbsp;&nbsp;&nbsp;&nbsp;' return pointer to the buffer (lpBits). CreateDIBSection does not use the<br />
&nbsp;&nbsp;&nbsp;&nbsp;' BITMAPINFOHEADER biXPelsPerMeter or biYPelsPerMeter and will not provide<br />
&nbsp;&nbsp;&nbsp;&nbsp;' resolution information in the BITMAPINFO structure.<br />
&nbsp;&nbsp;&nbsp;&nbsp;hDib = ApiZ(CreateDIBSection(hMemDC, uHdr, DIB_RGB_COLORS, lpBits, 0&amp;, 0&amp;))<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Copy the actual image (PARGB bits) from uData (uData.Scan0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;' into our DIBs bits (lpBits).<br />
&nbsp;&nbsp;&nbsp;&nbsp;Call CopyMemory(ByVal lpBits, ByVal uData.Scan0, uData.Stride * uData.Height)<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Cleanup - Done with the uData buffer as well as the hGdipImage.<br />
&nbsp;&nbsp;&nbsp;&nbsp;gdiTestID = 3<br />
&nbsp;&nbsp;&nbsp;&nbsp;GErr GdipBitmapUnlockBits(hGdipImage, uData)<br />
&nbsp;&nbsp;&nbsp;&nbsp;gdiTestID = 4<br />
&nbsp;&nbsp;&nbsp;&nbsp;GErr GdipDisposeImage(hGdipImage)<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Put our DIB into our memory DC.<br />
&nbsp;&nbsp;&nbsp;&nbsp;hPrevDib = ApiZ(SelectObject(hMemDC, hDib))<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Create an EMPTY EMF in a primary monitor DC with no initial size.<br />
&nbsp;&nbsp;&nbsp;&nbsp;' The DC returned by CreateEnhMetaFile can be passed to any GDI function.<br />
&nbsp;&nbsp;&nbsp;&nbsp;' It actually returns an EMF DC.<br />
&nbsp;&nbsp;&nbsp;&nbsp;hEmfDC = ApiZ(CreateEnhMetaFileW(0&amp;, 0&amp;, ByVal 0&amp;, 0&amp;))<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Calculate the EMF scaling factors from its DC, so we can use it in<br />
&nbsp;&nbsp;&nbsp;&nbsp;' GdiAlphaBlend, as GdiAlphaBlend scales based on the hEmfDC.<br />
&nbsp;&nbsp;&nbsp;&nbsp;Const HORZSIZE&nbsp;&nbsp; As Long = 4&amp;:&nbsp;&nbsp;Const VERTSIZE&nbsp;&nbsp; As Long = 6&amp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;Const HORZRES&nbsp;&nbsp;&nbsp;&nbsp;As Long = 8&amp;:&nbsp;&nbsp;Const VERTRES&nbsp;&nbsp;&nbsp;&nbsp;As Long = 10&amp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;Const LOGPIXELSX As Long = 88&amp;: Const LOGPIXELSY As Long = 90&amp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;Xscale = CDbl(GetDeviceCaps(hEmfDC, HORZRES)) / _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CDbl(GetDeviceCaps(hEmfDC, HORZSIZE)) * 25.4 / _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CDbl(GetDeviceCaps(hEmfDC, LOGPIXELSX))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;Yscale = CDbl(GetDeviceCaps(hEmfDC, VERTRES)) / _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CDbl(GetDeviceCaps(hEmfDC, VERTSIZE)) * 25.4 / _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CDbl(GetDeviceCaps(hEmfDC, LOGPIXELSY))<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Use BLENDFUNCTION structure for an Alpha Blend.<br />
&nbsp;&nbsp;&nbsp;&nbsp;bf.BlendOp = AC_SRC_OVER<br />
&nbsp;&nbsp;&nbsp;&nbsp;bf.AlphaFormat = AC_SRC_ALPHA<br />
&nbsp;&nbsp;&nbsp;&nbsp;bf.SourceConstantAlpha = bbOverallOpacity<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Must put into a Long so we can pass it ByVal.<br />
&nbsp;&nbsp;&nbsp;&nbsp;GetMem4 bf, ftn<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Copy our DIB that's in memory into our EMF+ using its DC, and scale.<br />
&nbsp;&nbsp;&nbsp;&nbsp;ApiZ GdiAlphaBlend(hEmfDC, 0&amp;, 0&amp;, CLng((CDbl(uData.Width)) * Xscale * _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dScalingFactor) + 1&amp;, CLng((CDbl(uData.Height)) * Yscale * _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dScalingFactor) + 1&amp;, hMemDC, 0&amp;, 0&amp;, uData.Width, uData.Height, _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ftn), "AlphaBlend"<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Done with hMemDC and hDib, so clean them up.<br />
&nbsp;&nbsp;&nbsp;&nbsp;ApiZ SelectObject(hMemDC, hPrevDib)<br />
&nbsp;&nbsp;&nbsp;&nbsp;ApiZ DeleteDC(hMemDC)<br />
&nbsp;&nbsp;&nbsp;&nbsp;ApiZ DeleteObject(hDib)<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Clean the hEmfDC and save into the hEmf<br />
&nbsp;&nbsp;&nbsp;&nbsp;hEmf = ApiZ(CloseEnhMetaFile(hEmfDC), "CloseEnhMetaFile")<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Setup PictDesc with EMF type.<br />
&nbsp;&nbsp;&nbsp;&nbsp;uDesc.cbSize = Len(uDesc)<br />
&nbsp;&nbsp;&nbsp;&nbsp;uDesc.picType = vbPicTypeEMetafile<br />
&nbsp;&nbsp;&nbsp;&nbsp;uDesc.hgdiObj = hEmf<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Return the function by wrapping our EMF (uDesc) into the iPicture object.<br />
&nbsp;&nbsp;&nbsp;&nbsp;ApiE OleCreatePictureIndirect(uDesc, IPictureIID, 1&amp;, LoadPng)<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Shutdown the GDI+.<br />
&nbsp;&nbsp;&nbsp;&nbsp;gdiTestID = 5<br />
&nbsp;&nbsp;&nbsp;&nbsp;GErr GdiplusShutdown(mlGdipToken)<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
End Function<br />
<br />
<br />
<br />
<br />
' ==============================================================================<br />
' = PRIVATE FUNCTIONS ==========================================================<br />
' ==============================================================================<br />
<br />
<br />
' GRAPHICS ERROR TEST SUBROUTINE: Used to check for errors during execution<br />
' ==============================================================================<br />
Private Sub GErr(ByVal GdipReturn As Long)<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Initialize subroutine variables<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim sErr&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As String<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim InIDE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Boolean: Debug.Assert MakeTrue(InIDE)<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;If GdipReturn = 0&amp; Then Exit Sub ' All is well.<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Exit if the error is after a shutdown of the GDI+<br />
&nbsp;&nbsp;&nbsp;&nbsp;If GdipReturn = 1&amp; Then<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;If gdiTestID = 5 Then<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Exit Sub<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;End If<br />
&nbsp;&nbsp;&nbsp;&nbsp;End If<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Branch on returned error to get message<br />
&nbsp;&nbsp;&nbsp;&nbsp;Select Case GdipReturn<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 1&amp;:&nbsp;&nbsp;&nbsp;&nbsp;sErr = "Generic Error"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 2&amp;:&nbsp;&nbsp;&nbsp;&nbsp;sErr = "Invalid Parameter/Argument"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 3&amp;:&nbsp;&nbsp;&nbsp;&nbsp;sErr = "Out Of Memory"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 4&amp;:&nbsp;&nbsp;&nbsp;&nbsp;sErr = "Object Busy, already in use in another thread"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 5&amp;:&nbsp;&nbsp;&nbsp;&nbsp;sErr = "Insufficient Buffer, buffer specified as an argument in the API call is not large enough"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 6&amp;:&nbsp;&nbsp;&nbsp;&nbsp;sErr = "Method Not Implemented"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 7&amp;:&nbsp;&nbsp;&nbsp;&nbsp;sErr = "Win32 Error"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 8&amp;:&nbsp;&nbsp;&nbsp;&nbsp;sErr = "Wrong State"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 9&amp;:&nbsp;&nbsp;&nbsp;&nbsp;sErr = "Method Aborted"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 10&amp;:&nbsp;&nbsp; sErr = "File Not Found"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 11&amp;:&nbsp;&nbsp; sErr = "Value Overflow, arithmetic operation that produced a numeric overflow"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 12&amp;:&nbsp;&nbsp; sErr = "Access Denied"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 13&amp;:&nbsp;&nbsp; sErr = "Unknown Image Format"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 14&amp;:&nbsp;&nbsp; sErr = "Font Family Not Found"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 15&amp;:&nbsp;&nbsp; sErr = "Font Style Not Found"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 16&amp;:&nbsp;&nbsp; sErr = "Not TrueType Font"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 17&amp;:&nbsp;&nbsp; sErr = "Unsupported Gdiplus Version"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 18&amp;:&nbsp;&nbsp; sErr = "Gdiplus Not Initialized"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 19&amp;:&nbsp;&nbsp; sErr = "Property Not Found, does not exist in the image"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 20&amp;:&nbsp;&nbsp; sErr = "Property Not Supported, not supported by the format of the image"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 21&amp;:&nbsp;&nbsp; sErr = "Profile Not Found, color profile required to save an image in CMYK format was not found"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case Else:&nbsp;&nbsp;sErr = "Error Not Specified": GdipReturn = 99&amp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;End Select<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Branch on Test ID to relay which GDI+ command caused the error<br />
&nbsp;&nbsp;&nbsp;&nbsp;Select Case gdiTestID<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 1:&nbsp;&nbsp;&nbsp;&nbsp;sErr = "1 LoadImage: " &amp; sErr<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 2:&nbsp;&nbsp;&nbsp;&nbsp;sErr = "2 LockBits: " &amp; sErr<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 3:&nbsp;&nbsp;&nbsp;&nbsp;sErr = "3 UnlockBits: " &amp; sErr<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 4:&nbsp;&nbsp;&nbsp;&nbsp;sErr = "4 DisposeImage: " &amp; sErr<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case 5:&nbsp;&nbsp;&nbsp;&nbsp;sErr = "5 Shutdown: " &amp; sErr<br />
&nbsp;&nbsp;&nbsp;&nbsp;Case Else: sErr = "0 Startup: " &amp; sErr<br />
&nbsp;&nbsp;&nbsp;&nbsp;End Select<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Include GDI+ Error notification<br />
&nbsp;&nbsp;&nbsp;&nbsp;sErr = "GDI+ Error:&nbsp;&nbsp;" &amp; sErr<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Display message in Debug or pass as Raised<br />
&nbsp;&nbsp;&nbsp;&nbsp;If InIDE Then<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Debug.Print sErr<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Stop<br />
&nbsp;&nbsp;&nbsp;&nbsp;Else<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Err.Raise vbObjectError + 1147221504 - GdipReturn, , sErr<br />
&nbsp;&nbsp;&nbsp;&nbsp;End If<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
End Sub<br />
<br />
<br />
' Convert a string from the StringFromID back to original IID<br />
' ==============================================================================<br />
Private Function IPictureIID() As IID<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;ApiE IIDFromString(StrPtr("{7BF80980-BF32-101A-8BBB-00AA00300CAB}"), _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IPictureIID)<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
End Function<br />
<br />
<br />
<br />
' Api Zero:&nbsp;&nbsp;Processes messages when the error report system returns ZERO<br />
' ==============================================================================<br />
Private Function ApiZ(ApiReturn As Long, Optional sApiCall As String) As Long<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Initialize subroutine variables<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim sErr&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As String<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim InIDE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Boolean: Debug.Assert MakeTrue(InIDE)<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Set function to passed value and exit if no Zero return<br />
&nbsp;&nbsp;&nbsp;&nbsp;If ApiReturn &lt;&gt; 0&amp; Then<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ApiZ = ApiReturn<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Exit Function<br />
&nbsp;&nbsp;&nbsp;&nbsp;End If<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Create error message based on API Call<br />
&nbsp;&nbsp;&nbsp;&nbsp;If Len(sApiCall) Then<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sErr = sApiCall &amp; " error"<br />
&nbsp;&nbsp;&nbsp;&nbsp;Else<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sErr = "API Error"<br />
&nbsp;&nbsp;&nbsp;&nbsp;End If<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Display message in Debug or pass as Raised<br />
&nbsp;&nbsp;&nbsp;&nbsp;If InIDE Then<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Debug.Print sErr<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Stop<br />
&nbsp;&nbsp;&nbsp;&nbsp;Else<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Err.Raise vbObjectError + 1147221504, , sErr<br />
&nbsp;&nbsp;&nbsp;&nbsp;End If<br />
End Function<br />
<br />
<br />
' Api Error:&nbsp;&nbsp;A General error processing prodcedure for Non-GDI+ errors.<br />
' ==============================================================================<br />
Private Sub ApiE(ApiReturn As Long, Optional sApiCall As String)<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Initialize subroutine variables<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim sErr&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As String<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim InIDE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; As Boolean: Debug.Assert MakeTrue(InIDE)<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Exit if no errors<br />
&nbsp;&nbsp;&nbsp;&nbsp;If ApiReturn = 0&amp; Then Exit Sub<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Create error message based on API Call<br />
&nbsp;&nbsp;&nbsp;&nbsp;If Len(sApiCall) Then<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sErr = sApiCall &amp; " error " &amp; CStr(ApiReturn)<br />
&nbsp;&nbsp;&nbsp;&nbsp;Else<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sErr = "API Error " &amp; CStr(ApiReturn)<br />
&nbsp;&nbsp;&nbsp;&nbsp;End If<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;' Display message in Debug or pass as Raised<br />
&nbsp;&nbsp;&nbsp;&nbsp;If InIDE Then<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Debug.Print sErr<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Stop<br />
&nbsp;&nbsp;&nbsp;&nbsp;Else<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Err.Raise vbObjectError + 1147221504 - ApiReturn, , sErr<br />
&nbsp;&nbsp;&nbsp;&nbsp;End If<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
End Sub<br />
<br />
<br />
' Make True - Ensures a passed value is set to boolean/true by ref or otherwise.<br />
' ==============================================================================<br />
Private Function MakeTrue(ByRef b As Boolean) As Boolean<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
&nbsp;&nbsp;&nbsp;&nbsp;b = True<br />
&nbsp;&nbsp;&nbsp;&nbsp;MakeTrue = True<br />
&nbsp;&nbsp;&nbsp;&nbsp;'<br />
End Function</code></div></div></div>
		</div>
Or within the actual <span style="font-weight: bold;" class="mycode_b">Class_PNG.cls</span> format: 
<br />
<img src="https://www.save-point.org/images/attachtypes/zip.gif" title="ZIP File" border="0" alt=".zip" />
&nbsp;&nbsp;<a href="attachment.php?aid=3045" target="_blank" title="">Class_Png.zip</a> (Size: 6.35 KB / Downloads: 72)
<br />
<br />
<br />
<span style="font-size: medium;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Instructions</span></span><br />
Plenty... in the code itself.<br />
<br />
<br />
<span style="font-size: medium;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">FAQ</span></span><br />
The original code was not in the forum of a class, but as a basic module. It has since been streamlined while the error message system upgraded.<br />
<br />
<br />
<span style="font-size: medium;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Credits and Thanks</span></span><br />
Thanks to Elroy of VBForums who wrote the base code in 2022<br />
<br />
<br />
<span style="font-size: medium;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Terms and Conditions</span></span><br />
Use as you see fit.  No requirements other than due credit for both Elroy and myself.]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[The MCISendString Multimedia Class]]></title>
			<link>https://www.save-point.org/thread-13375.html</link>
			<pubDate>Sat, 03 Jan 2026 17:46:08 +0000</pubDate>
			<dc:creator><![CDATA[<a href="https://www.save-point.org/member.php?action=profile&uid=5">DerVVulfman</a>]]></dc:creator>
			<guid isPermaLink="false">https://www.save-point.org/thread-13375.html</guid>
			<description><![CDATA[<div style="text-align: center;" class="mycode_align"><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">The MCISendString Multimedia Class</span></span><br />
<span style="font-size: medium;" class="mycode_size">Version: 1.0</span><br />
<span style="font-size: small;" class="mycode_size">Based upon work by Mark Thesing (July 18, 2002)</span></div>
<br />
<br />
<br />
<span style="font-size: medium;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Introduction</span></span><br />
Permits the loading, playback, and various other actions on a multimedia file.<br />
<br />
Since its original creation in 2002, the ability to present video content in a picturebox object has been added. Along with that, more multimedia file extensions are now recognized.<br />
<br />
Do note,  the class will only load and play one multimedia file at a time.  In order for a project  to play multiple files,  multiple instances of this class need to be defined.<br />
<br />
LOOPING:<br />
Using the MCISendstring system,  there is always a millisecond break as the MCISendstring attempts to loop back  to the start,  even with the built-in repeat function.<br />
<br />
<br />
<span style="font-size: medium;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Features</span></span><ul class="mycode_list"><li>Supports playback of the following Audio formats:  aiff, amr, flac, m4a, midi, mp2, mp3, wav, wma<br />
</li>
<li>Supports playback of the following Video formats:  avi, mpg, mpeg, mp4, m4v, asf, wmv<br />
</li>
<li>Allows custom loop position<br />
</li>
</ul>
<br />
<br />
<span style="font-size: medium;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Limitations</span></span><ul class="mycode_list"><li>Video footage does not have stretch-to-fit nor any resizing<br />
</li>
<li>Avi footage 'still' has no audio playback<br />
</li>
<li>Geared for Visual Basic 6 <br />
</li>
</ul>
<br />
<br />
<span style="font-size: medium;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Code</span></span><br />
<div class="tborder">
  			<div class="thead" style="padding:4px; margin:1px;"><input type="button" class="button" value="+" style="font-family:Monospace; padding:0px" onclick="if (this.parentNode.parentNode.getElementsByTagName('div')[1].style.display=='none'){ this.parentNode.parentNode.getElementsByTagName('div')[1].style.display='';this.value='-';} else {this.parentNode.parentNode.getElementsByTagName('div')[1].style.display='none';this.value='+';}"/> Code</div>
  			<div class="trow2" style="display:none; padding:4px; margin:1px;">
<div class="codeblock"><div class="title">Code:</div><div class="body" dir="ltr"><code>' ==============================================================================<br />
' ** The MCISendString Multimedia Class<br />
' ------------------------------------------------------------------------------<br />
'    by DerVVulfman<br />
'    version 1.0<br />
'    01-03-2026 (mm/dd/yyyy)<br />
'    Based upon work by Mark Thesing (July 18, 2002)<br />
' ==============================================================================<br />
'<br />
' INTRODUCTION:<br />
' -------------<br />
'<br />
' Permits the loading, playback, and various other actions on a multimedia file.<br />
'<br />
' Since its original creation in 2002, the ability to present video content in a<br />
' picturebox object has been added. Along with that, more multimedia file exten-<br />
' tions are now recognized.<br />
'<br />
' Do note,  the class will only load and play one multimedia file at a time.  In<br />
' order for a project  to play multiple files,  multiple instances of this class<br />
' need to be defined.<br />
'<br />
' LOOPING:  Using the MCISendstring system,  there is always a millisecond break<br />
'           as the MCISendstring attempts to loop back  to the start,  even with<br />
'           the built-in repeat function.<br />
'<br />
'<br />
' ==============================================================================<br />
'<br />
' CLASS INSTALLATION:<br />
' -------------------<br />
'<br />
' * In the form where used, define this class before any other action.<br />
'    -- Example:  Private clsMM As New Class_MSS<br />
'<br />
' * If you need two or more files playing, define multiple instances like so.<br />
'    -- Example:  Private clsMMOne As New Class_MSS<br />
'                 Private clsMMTwo As New Class_MSS<br />
'<br />
'   The 'clsMM' (or like) will direct you to commands within this class.<br />
'    -- Example:  clsMM.mmPlay<br />
'<br />
' * Ensure the class instance (or instances) removed from memory upon exit.<br />
'   It is also recommended to end any multimedia playback being executed.<br />
'   This is done within the form's  "Form_Unload" private subroutine.<br />
'   -- Example:  clsIni.mmStop<br />
'                Set clsIni = Nothing<br />
'                End<br />
'<br />
'<br />
' ==============================================================================<br />
'<br />
' MULTIMEDIA FORMATS:<br />
' -------------------<br />
'<br />
' Audio:  aiff, amr, flac, m4a, midi, mp2, mp3, wav, wma<br />
' Video:  avi, mpg, mpeg, mp4, m4v, asf, wmv<br />
'<br />
' * Amr format not recommended; playback sounds low quality<br />
' * Avi format has no audio playback<br />
'<br />
' * Formerly, only wav, mid, mp3, avi, mpg and mpeg were supported.<br />
'<br />
'<br />
' ==============================================================================<br />
'<br />
' METHODS:<br />
' --------<br />
'<br />
' CLOSE:    Closes the currently loaded file.<br />
' * SYNTAX: &lt;classname&gt;.mmClose<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' OPEN:     Opens the desired file. Optionally sets a window for video display.<br />
' * SYNTAX: &lt;classname&gt;.mmOpen filename [, object]<br />
'           * filename: The full filename (with path) to be loaded for playback.<br />
'           * object:   (Optional) The hwnd supported form object for video use.<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' PAUSE:    Pauses the file or resumes playback.<br />
' * SYNTAX: &lt;classname&gt;.mmPause<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' PLAY:     Plays the loaded file. Optionally accepts whether the file loops.<br />
' * SYNTAX: &lt;classname&gt;.mmPlay [, repeat]<br />
'           * repeat:   (Optional) True/False if the multimedia file loops.<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' SEEK:     Sets current playback to a specific position within the file.<br />
' * SYNTAX: &lt;classname&gt;.mmSeek location<br />
'           * location: The point within the file (in millisecond) to advance<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' SEEK INCREMENT: Sets playback to a position based on 1/1000th of its length.<br />
' * SYNTAX: &lt;classname&gt;.mmSeekIncr value<br />
'           * value: (Range 0-1000) The point based on 1/100th of its length.<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' STOP:     Ends playback of the loaded file. Sets the reader to the file's end.<br />
' * SYNTAX: &lt;classname&gt;.mmStop<br />
'<br />
' ------------------------------------------------------------------------------<br />
'<br />
'<br />
' ------------------------------------------------------------------------------<br />
'<br />
' PROPERTIES:<br />
' -----------<br />
'<br />
' FILENAME: Retrieves the name of the currently loaded file.<br />
' * SYNTAX: returned = &lt;classname&gt;.Filename<br />
'           * returned: (String) The name of the currently loaded file<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' FILENAME: Opens a specified filename. Does not define a window like OPEN.<br />
' * SYNTAX: &lt;classname&gt;.Filename filename<br />
'           * filename: The full filename (with path) to be loaded for playback.<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' LENGTH:   Retrieves the length/duration of the current file in milliseconds.<br />
' * SYNTAX: returned = &lt;classname&gt;.Length<br />
'           * returned: (Single) The file's playback duration in milliseconds<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' PAUSED:   Retrieves if media playback was temporarily halted.<br />
' * SYNTAX: returned = &lt;classname&gt;.Paused<br />
'           * returned: (Boolean) Returns True/False on pause status<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' PERCENT:  Retrieves the percent of the file played to one decimal position.<br />
' * SYNTAX: returned = &lt;classname&gt;.percent<br />
'           * returned: (Single: Range of 0.0-100.0) Current amount played.<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' POSITION: Retrieves the current playback position of the current file.<br />
' * SYNTAX: returned = &lt;classname&gt;.Position<br />
'           * returned: The full filename (with path) to be loaded for playback.<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' POSITION: (as Seek) Sets playback to a specified position of the current file.<br />
' * SYNTAX: &lt;classname&gt;.Position location<br />
'           * location: The point within the file (in millisecond) to advance.<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' TO_BEGIN: Retrives (in milliseconds) where media playback will begin or resume<br />
' * SYNTAX: returned = &lt;classname&gt;.To_Begin<br />
'           * returned: (Single) The position where media playback starts.<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' TO_BEGIN: Defines where playback begins, or where to return if set to repeat.<br />
' * SYNTAX: &lt;classname&gt;.To_Begin location<br />
'           * location: The point within the file (in millisecond) to start.<br />
'           NOTE:  It must be called 'after' [To_Reloop] if both are used together.<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' TO_END:   Retrives (in milliseconds) where media playback is set to end.<br />
' * SYNTAX: returned = &lt;classname&gt;.To_End<br />
'           * returned: (Single) The position where media playback ends.<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' TO_END:   Defines where playback ends if not at the end of the current file.<br />
' * SYNTAX: &lt;classname&gt;.To_End location<br />
'           * location: The point within the file (in millisecond) to end.<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' TO_RELOOP: Defines where playback ends if not at the end of the current file.<br />
' * SYNTAX:  &lt;classname&gt;.To_ReLoop location<br />
'            * location: The point in the file (in millisecond) to restart loop.<br />
'            NOTE:  If used in tandem with [To_Begin], it must be called first.<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' VOLUME:   Gets the playback volume.<br />
' * SYNTAX: returned = &lt;classname&gt;.Volume<br />
'           * returned: (Long) The volume amplitude (generally 0-100)<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' VOLUME:   Sets the playback volume.<br />
' * SYNTAX: &lt;classname&gt;.Volume amplitude<br />
'           * amplitude: The volume of audio playback.<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' VOLUME LEFT:  Sets the playback volume for the left volume channel<br />
' * SYNTAX:     &lt;classname&gt;.VolumeL amplitude<br />
'               * amplitude: The volume of the left channel playback.<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' VOLUME RIGHT: Sets the playback volume for the right volume channel.<br />
' * SYNTAX:     &lt;classname&gt;.VolumeR amplitude<br />
'               * amplitude: The volume of the right channel playback.<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
<br />
' ------------------------------------------------------------------------------<br />
'<br />
'<br />
' ==============================================================================<br />
<br />
<br />
<br />
<br />
Option Explicit<br />
<br />
' API Function Declarations<br />
' ==============================================================================<br />
Private Declare Function mciSendString Lib "winmm.dll" Alias "mciSendStringA" _<br />
            (ByVal lpstrCommand As String, ByVal lpstrReturnString As String, _<br />
            ByVal uReturnLength As Long, ByVal hwndCallback As Long) As Long<br />
<br />
<br />
<br />
<br />
' Private Variable Declarations<br />
' ==============================================================================<br />
    Private strAlias                As String           ' Mmedia resource name<br />
    Private strFileName             As String           ' Current filename<br />
    Private strFrom                 As String           ' Defined Playback start<br />
    Private strTo                   As String           ' Defined Playback end<br />
    ' --------------------------------------------------------------------------<br />
    Private sngLength               As Single           ' Playback length<br />
    Private sngIncrement            As Single           ' Length divided by 1000<br />
    Private sngPosition             As Single           ' Current position<br />
    Private sngToSkip               As Single           ' Loop flourish skip<br />
    Private sngSeekFrom             As Single           ' Loop starting point<br />
    Private sngSeekTo               As Single           ' Loop ending point<br />
    ' --------------------------------------------------------------------------<br />
    Private strStatus               As String           ' Current playing status<br />
    Private bPlaying                As Boolean          ' If file is playing<br />
    Private bPaused                 As Boolean          ' If paused or not<br />
    Private bRepeat                 As Boolean          ' If loops<br />
    ' --------------------------------------------------------------------------<br />
    Private lngVolume               As Long             ' Current volume<br />
    Private lngVolumeL              As Long             ' (above) Left Volume<br />
    Private lngVolumeR              As Long             ' (above) Right Volume<br />
<br />
<br />
<br />
<br />
' ==============================================================================<br />
' = CLASS FUNCTIONS ============================================================<br />
' ==============================================================================<br />
<br />
<br />
' The Initialization routine<br />
'===============================================================================<br />
Private Sub Class_Initialize()<br />
    '<br />
    strAlias = ""                                       ' Set empty Alias name<br />
    strFileName = ""                                    ' Set empty filename<br />
    bPlaying = False                                    ' No playing at start<br />
    bPaused = False                                     ' No pause at start<br />
    sngToSkip = 0                                       ' Clear loop points<br />
    sngSeekFrom = 0                                     ' Clear loop points<br />
    sngSeekTo = 0                                       ' Clear loop points<br />
    lngVolume = 0                                       ' Clear volume values<br />
    lngVolumeL = 0                                      ' Clear volume values<br />
    lngVolumeR = 0                                      ' Clear volume values<br />
    '<br />
End Sub<br />
<br />
<br />
<br />
<br />
' ==============================================================================<br />
' = GENERAL FUNCTIONS ==========================================================<br />
' ==============================================================================<br />
<br />
<br />
' CLOSE FILE<br />
' Close the currently open multimedia file<br />
' ==============================================================================<br />
Public Sub mmClose()<br />
    '      ---------------------------------------------------------------------<br />
    '<br />
    ' Initialize function variables<br />
    Dim lngReturn       As Long                         ' mciSendString return<br />
    Dim strCmd          As String                       ' Sets the MCI commands<br />
    '<br />
    If strAlias = "" Then Exit Sub                      ' Exit if no file open<br />
    '<br />
    strCmd = "Close " &amp; strAlias                        ' Make MCI Close Command<br />
    lngReturn = mciSendString(strCmd, "", 0, 0)         ' Pass MCI command<br />
    '<br />
    strAlias = ""                                       ' Clear opened file<br />
    strFileName = ""                                    ' Clear filename<br />
    bPlaying = False                                    ' Flag not playing<br />
    '<br />
End Sub<br />
<br />
<br />
' OPEN FILE<br />
' Open the specified multimedia file and close any others that may be open<br />
' ==============================================================================<br />
Public Sub mmOpen(ByVal strTheFile As String, _<br />
    Optional ByVal objPic As Object = Nothing)<br />
    '      ---------------------------------------------------------------------<br />
    '<br />
    ' Initialize function variables<br />
    Dim lngReturn       As Long                         ' mciSendString return<br />
    Dim strCmd          As String                       ' Sets the MCI commands<br />
    Dim strLen          As String * 255                 ' Gets the file length<br />
    Dim strType         As String                       ' Holds the file type<br />
    Dim intLength       As Integer                      ' Returned data's length<br />
    Dim bVideo          As Boolean                      ' Defined video window<br />
    '<br />
    ' Initialize subroutine constant<br />
    Const WS_CHILD As Long = &amp;H40000000                 ' Define child window<br />
    '<br />
    bPlaying = False                                    ' Flag not playing<br />
    bPaused = False                                     ' Turn off paused flag<br />
    '<br />
    If strAlias &lt;&gt; "" Then mmClose                      ' Close if previous open<br />
    '<br />
    ' Determine playback mode based on file extension<br />
    ' --------------------------------------------------------------------------<br />
    Select Case UCase(Right(strTheFile, 4))             ' Branch on extension<br />
        ' -- AUDIO FORMATS -----------------------------------------------------<br />
        Case ".WAV"                                     ' For Wav extension<br />
            strType = "Waveaudio"                       ' ... assume wave audio<br />
            bVideo = False                              ' ... set no-video usage<br />
        Case ".MID"                                     ' For mid extension<br />
            strType = "Sequencer"                       ' ... assume sequencer<br />
            bVideo = False                              ' ... set no-video usage<br />
        Case "AIFF", ".AMR", "FLAC"                     ' For AIFF, AMR and FLAC<br />
            strType = "MPEGVideo"                       ' ... Mpeg system use<br />
            bVideo = False                              ' ... set no-video usage<br />
        Case ".M4A", ".MP2", ".MP3"                     ' For MP2/3 extensions<br />
            strType = "MPEGVideo"                       ' ... Mpeg system use<br />
            bVideo = False                              ' ... set no-video usage<br />
        Case ".WMA"                                     ' For flaky WMAs<br />
            strType = "MPEGVideo"                       ' ... Mpeg system use<br />
            bVideo = False                              ' ... set no-video usage<br />
        ' -- VIDEO FORMATS -----------------------------------------------------<br />
        Case ".AVI"                                     ' For Avi extension<br />
            strType = "AviVideo"                        ' ... assume avi video<br />
            bVideo = True                               ' ... set video usage<br />
        Case "MPEG", ".MPG", ".MP4"                     ' For MPG, MPEG or MP4<br />
            strType = "MPEGVideo"                       ' ... Mpeg system use<br />
            bVideo = True                               ' ... set video usage<br />
        Case ".ASF", ".M4V"                             ' For ASF or M4V<br />
            strType = "MPEGVideo"                       ' ... Mpeg system use<br />
            bVideo = True                               ' ... set video usage<br />
        Case ".WMV"                                     ' For flaky WMVs<br />
            strType = "MPEGVideo"                       ' ... Mpeg system use<br />
            bVideo = True                               ' ... set video usage<br />
        ' -- NO VALID FORMAT FOUND ---------------------------------------------<br />
        Case Else                                       ' -- otherwise --<br />
            Exit Sub                                    ' Exit if unrecognized<br />
    End Select<br />
    ' --------------------------------------------------------------------------<br />
    '<br />
    strAlias = Right(strTheFile, 3) &amp; Minute(Now)       ' Make unique alias name<br />
    '<br />
    If InStr(strTheFile, " ") Then                      ' If filename has spaces<br />
        strTheFile = Chr(34) &amp; strTheFile &amp; Chr(34)     ' ... wrap in quotes<br />
    End If<br />
    '<br />
    If pvt_ObjExist(objPic) = False Then                ' If no picture object<br />
        bVideo = False                                  ' Force no video usage<br />
    End If<br />
    '<br />
    ' Create the Open MCISendString command<br />
    ' --------------------------------------------------------------------------<br />
    strCmd = "Open " &amp; strTheFile                       ' Make MCI Open command<br />
    strCmd = strCmd &amp; " alias " &amp; strAlias              ' Include alias name<br />
    If bVideo = True Then<br />
        strCmd = strCmd &amp; " parent "                    ' Set target window use<br />
        strCmd = strCmd &amp; CStr(objPic.hWnd)             ' Set actual target<br />
        strCmd = strCmd &amp; " style " &amp; CStr(WS_CHILD)    ' Set as child window<br />
    Else<br />
        strCmd = strCmd &amp; " Type " &amp; strType            ' Add audio type<br />
    End If<br />
    strCmd = strCmd &amp; " WAIT"                           ' Force wait till play<br />
    ' --------------------------------------------------------------------------<br />
    '<br />
    lngReturn = mciSendString(strCmd, "", 0, 0)         ' Pass MCI command<br />
    '<br />
    ' Ensure file set to start position and increments<br />
    ' --------------------------------------------------------------------------<br />
    strCmd = "Status " &amp; strAlias &amp; " length"           ' Make MCI Length cmd<br />
    lngReturn = mciSendString(strCmd, strLen, 255, 0)   ' Pass MCI command<br />
    intLength = InStr(strLen, Chr(0))                   ' Get end of length<br />
    sngLength = Val(Left(strLen, intLength - 1))        ' Set to class variable<br />
    sngIncrement = sngLength / 1000<br />
    '<br />
    ' Define loop start and end defaults<br />
    ' --------------------------------------------------------------------------<br />
    sngToSkip = 0                                       ' Loop flourish point<br />
    sngSeekFrom = 0                                     ' Loop starting point<br />
    sngSeekTo = sngLength                               ' Loop ending point<br />
    ' --------------------------------------------------------------------------<br />
    '<br />
    ' Ensure file set to start position<br />
    ' --------------------------------------------------------------------------<br />
    strCmd = "Seek " &amp; strAlias &amp; " to 0"               ' Make MCI Seek Command<br />
    lngReturn = mciSendString(strCmd, "", 0, 0)         ' Pass MCI command<br />
    ' --------------------------------------------------------------------------<br />
    '<br />
End Sub<br />
<br />
<br />
' PAUSE PLAYBACK<br />
' Pause playback of the file<br />
' ==============================================================================<br />
Public Sub mmPause()<br />
    '      ---------------------------------------------------------------------<br />
    '<br />
    ' Initialize function variables<br />
    Dim lngReturn       As Long                         ' mciSendString return<br />
    Dim strCmd          As String                       ' Sets the MCI commands<br />
    '<br />
    If strAlias = "" Then Exit Sub                      ' Exit if no file open<br />
    '<br />
    If bPlaying = False Then Exit Sub                   ' Exit if not playing<br />
    '<br />
    If bPaused = False Then                             ' If already paused<br />
        bPaused = True                                  ' ... set flag n pause<br />
        strCmd = "Pause " &amp; strAlias                    ' Make MCI Pause Command<br />
    Else<br />
        bPaused = False                                 ' ... set flag n play<br />
        strCmd = "Resume " &amp; strAlias                   ' Make MCI Resume Cmnd<br />
    End If<br />
    '<br />
    lngReturn = mciSendString(strCmd, "", 0, 0)         ' Pass MCI command<br />
    '<br />
End Sub<br />
<br />
<br />
' PLAY FILE<br />
' Plays the currently open file from the current position<br />
' ==============================================================================<br />
Public Sub mmPlay()<br />
    '      ---------------------------------------------------------------------<br />
    '<br />
    ' Initialize function variables<br />
    Dim lngReturn       As Long                         ' mciSendString return<br />
    Dim strCmd          As String                       ' Sets the MCI commands<br />
    Dim strTo2 As String<br />
    '<br />
    If strAlias = "" Then Exit Sub                      ' Exit if no file open<br />
    '<br />
    bPlaying = True                                     ' Flag IS playing<br />
    bPaused = False                                     ' Playing, not paused<br />
    '<br />
    strCmd = "Play " &amp; strAlias                         ' Make MCI Play Command<br />
    strFrom = " from " &amp; Trim(Str(sngSeekFrom))         ' Set start position<br />
    strCmd = strCmd &amp; strFrom                           ' Add to Play command<br />
    '<br />
    If pvt_LoopCheck = False Then                       ' If no custom loops<br />
        If bRepeat = True Then                          ' If set to repeat<br />
            strCmd = strCmd &amp; " Repeat"                 ' Add repeat to command<br />
        End If<br />
    End If<br />
    '<br />
    lngReturn = mciSendString(strCmd, "", 0, 0)         ' Pass MCI command<br />
    '<br />
    If bRepeat = False Then Exit Sub                    ' Exit if no repeating<br />
    If pvt_LoopCheck = False Then Exit Sub              ' Exit if no loop spot<br />
    '<br />
    pvt_LoopExecute                                     ' Perform repeat loop<br />
    '<br />
End Sub<br />
<br />
<br />
' SEEK TO PLAYBACK LOCATION<br />
' Seek a specific position within the file<br />
' ==============================================================================<br />
Public Sub mmSeek(ByVal sngPosition As Single)<br />
    '      ---------------------------------------------------------------------<br />
    '<br />
    ' Initialize function variables<br />
    Dim lngReturn       As Long                         ' mciSendString return<br />
    Dim strCmd          As String                       ' Sets the MCI commands<br />
    '<br />
    strCmd = "Seek " &amp; strAlias                         ' Make MCI Seek Command<br />
    strCmd = strCmd &amp; " to " &amp; Trim(Str(sngPosition))   ' Define seek position<br />
    lngReturn = mciSendString(strCmd, "", 0, 0)         ' Pass MCI command<br />
    '<br />
End Sub<br />
<br />
<br />
' SEEK TO LOCATION ON INCREMENTAL VALUE<br />
' Seek a specific position within the file based on value<br />
' ==============================================================================<br />
Public Sub mmSeekIncr(ByVal intIncrement As Integer)<br />
    '      ---------------------------------------------------------------------<br />
    '<br />
    ' Initialize function variables<br />
    Dim lngReturn       As Long                         ' mciSendString return<br />
    Dim strCmd          As String                       ' Sets the MCI commands<br />
    Dim sngPosition     As Long<br />
    '<br />
    If intIncrement &lt; 0 Then Exit Sub                   ' Exit if out of range<br />
    If intIncrement &gt; 1000 Then Exit Sub                ' Exit if out of range<br />
    '<br />
    sngPosition = intIncrement * sngIncrement           ' Math based on range<br />
    '<br />
    strCmd = "Seek " &amp; strAlias                         ' Make MCI Seek Command<br />
    strCmd = strCmd &amp; " to " &amp; Trim(Str(sngPosition))   ' Define seek position<br />
    lngReturn = mciSendString(strCmd, "", 0, 0)         ' Pass MCI command<br />
    <br />
    If bPlaying = False Then Exit Sub                   ' Exit if not playing<br />
    If bPaused = True Then Exit Sub                     ' Exit if paused<br />
    '<br />
    strCmd = "Play " &amp; strAlias                         ' Make MCI Play Command<br />
    '<br />
    If pvt_LoopCheck = False Then                       ' If no custom loops<br />
        If bRepeat = True Then                          ' If set to repeat<br />
            strCmd = strCmd &amp; " Repeat"                 ' Add repeat to command<br />
        End If<br />
    End If<br />
    '<br />
    lngReturn = mciSendString(strCmd, "", 0, 0)         ' Pass MCI command<br />
    '<br />
End Sub<br />
<br />
<br />
' STOP PLAYBACK<br />
' Stop using a file totally. Running or not.<br />
' ==============================================================================<br />
Public Sub mmStop()<br />
    '      ---------------------------------------------------------------------<br />
    '<br />
    ' Initialize function variables<br />
    Dim lngReturn       As Long                         ' mciSendString return<br />
    Dim strCmd          As String                       ' Sets the MCI commands<br />
    Dim sngLength       As Single                       ' Sets playback length<br />
    '<br />
    If strAlias = "" Then Exit Sub                      ' Exit if no file open<br />
    '<br />
    bPlaying = False                                    ' Flag not playing<br />
    '<br />
    strCmd = "Stop " &amp; strAlias                         ' Make MCI Stop Command<br />
    lngReturn = mciSendString(strCmd, "", 0, 0)         ' Pass MCI command<br />
    '<br />
    sngLength = Length                                  ' Get playback length<br />
    '<br />
    strCmd = "Seek " &amp; strAlias                         ' Make MCI Seek Command<br />
    strCmd = strCmd &amp; " to " &amp; Trim(Str(sngLength))     ' Define seek end<br />
    lngReturn = mciSendString(strCmd, "", 0, 0)         ' Pass MCI command<br />
    '<br />
End Sub<br />
<br />
<br />
<br />
<br />
' ==============================================================================<br />
' = PROPERTY SETTINGS ==========================================================<br />
' ==============================================================================<br />
<br />
<br />
' FILENAME (GET)<br />
' Returns the object FileName Property<br />
' ==============================================================================<br />
Public Property Get Filename() As String<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    Filename = strFileName                              ' Get value from class<br />
    '<br />
End Property<br />
<br />
<br />
' FILENAME (LET)<br />
' Sets the objects FileName property.<br />
' ==============================================================================<br />
Public Property Let Filename(ByVal New_FileName As String)<br />
    '           ----------------------------------------------------------------<br />
'   Sets the objects FileName property. This also implies<br />
'   that you also want to open the file so control is passed<br />
'   to the mmOpen method<br />
    '<br />
    strFileName = New_FileName<br />
    mmOpen New_FileName<br />
    '<br />
End Property<br />
<br />
<br />
' PLAYBACK LENGTH (GET)<br />
' Returns the length of the file, the value acquired when file was opened<br />
' ==============================================================================<br />
Public Property Get Length() As Single<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    If strAlias = "" Then                               ' If no file is open<br />
        Length = 0                                      ' Set zero length<br />
        Exit Property                                   ' and Exit<br />
    End If<br />
    '<br />
    Length = sngLength                                  ' Get value from class<br />
    '<br />
End Property<br />
<br />
<br />
' PAUSED (GET)<br />
' Returns the status of being paused (using in-class variables)<br />
' ==============================================================================<br />
Public Property Get Paused() As Boolean<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    Paused = bPaused                                    ' Get value from class<br />
    '<br />
End Property<br />
<br />
<br />
<br />
' PERCENT (GET)<br />
' Returns the relative position in the media relative to its size in 0-100 range<br />
' ==============================================================================<br />
Public Property Get Percent() As Single<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    ' Initialize property variables<br />
    Dim fLength         As Single                       ' Media file duration<br />
    Dim fPosition       As Single                       ' Current play position<br />
    Dim fPercent        As Single                       ' Percent value as float<br />
    Dim iPercent        As Integer                      ' Integer in deciseconds<br />
    '<br />
    ' Initialize function variables<br />
    If strAlias = "" Then                               ' If no file is open<br />
        Percent = 0                                     ' Set zero length<br />
        Exit Property                                   ' and Exit<br />
    End If<br />
    '<br />
    fLength = Length                                    ' Get media duration<br />
    fPosition = Position                                ' Get current position<br />
    '<br />
    fPercent = fPosition / fLength                      ' Get increment<br />
    iPercent = fPercent * 1000                          ' Get range 0-1000<br />
    Percent = iPercent / 10                             ' Set to range 0.0-100.0<br />
    '<br />
End Property<br />
<br />
<br />
' PLAYBACK POSITION (GET)<br />
' Returns the current position in the file if a file is open<br />
' ==============================================================================<br />
Public Property Get Position() As Single<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    ' Initialize function variables<br />
    Dim lngReturn       As Long                         ' mciSendString return<br />
    Dim strCmd          As String                       ' Sets the MCI commands<br />
    Dim strPos          As String * 255                 ' Returned pos buffer<br />
    Dim intLength       As Integer                      ' Returned data's length<br />
    '<br />
    If strAlias = "" Then                               ' If no file is open<br />
        Position = 0                                    ' Set zero position<br />
        Exit Property                                   ' and Exit<br />
    End If<br />
    '<br />
    strCmd = "Status " &amp; strAlias &amp; " position"         ' Make MCI Position cmd<br />
    lngReturn = mciSendString(strCmd, strPos, 255, 0)   ' Pass MCI command<br />
    '<br />
    intLength = InStr(strPos, Chr(0))                   ' Get end of position<br />
    Position = Val(Left(strPos, intLength - 1))         ' Set to function<br />
    '<br />
End Property<br />
<br />
<br />
' PLAYBACK LENGTH (LET)<br />
' Set the position property by seeking<br />
' ==============================================================================<br />
Public Property Let Position(ByVal New_Position As Single)<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    sngPosition = New_Position                          ' Get value from class<br />
    mmSeek New_Position                                 ' Pass into mmSeek<br />
    '<br />
End Property<br />
<br />
<br />
' REPEAT (GET)<br />
' Returns the objects Repeat property<br />
' ==============================================================================<br />
Public Property Get Repeat() As Boolean<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    Repeat = bRepeat                                    ' Get value from class<br />
    '<br />
End Property<br />
<br />
<br />
' REPEAT (LET)<br />
' Sets the value of the object Repeat property<br />
' ==============================================================================<br />
Public Property Let Repeat(ByVal New_Repeat As Boolean)<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    bRepeat = New_Repeat                                ' Set into class value<br />
    '<br />
End Property<br />
<br />
<br />
' PLAYBACK STATUS (GET)<br />
' Return the playback/record status of the current file<br />
' ==============================================================================<br />
Public Property Get Status() As String<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    ' Initialize function variables<br />
    Dim lngReturn       As Long                         ' mciSendString return<br />
    Dim strCmd          As String                       ' Sets the MCI commands<br />
    Dim strStat         As String * 255                 ' Returned status buffer<br />
    Dim intLength       As Integer                      ' Returned data's length<br />
    '<br />
    If strAlias = "" Then Exit Property                 ' Exit if no file open<br />
    '<br />
    strCmd = "Status " &amp; strAlias &amp; " mode"             ' Make MCI Status cmd<br />
    lngReturn = mciSendString(strCmd, strStat, 255, 0)  ' Pass MCI command<br />
    '<br />
    intLength = InStr(strStat, Chr(0))                  ' Get end of status<br />
    Status = Left(strStat, intLength - 1)               ' Set to function<br />
    '<br />
End Property<br />
<br />
<br />
' PLAYBACK BEGIN LOOP (GET)<br />
' Retrieves the position (in milliseconds) where the media playback begins<br />
' ==============================================================================<br />
Public Property Get To_Begin() As Single<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    To_Begin = sngSeekFrom                              ' Get value from class<br />
    '<br />
End Property<br />
<br />
<br />
' PLAYBACK BEGIN LOOP (LET)<br />
' Sets the position(in milliseconds) media playback is to begin or resume<br />
' ==============================================================================<br />
Public Property Let To_Begin(ByVal New_Begin As Single)<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    If New_Begin &lt; 0 Then Exit Property                 ' Exit if invalid point<br />
    If New_Begin &gt; sngLength Then Exit Property         ' Exit if invalid point<br />
    If New_Begin &gt;= sngToSkip Then Exit Property        ' Exit if past To_Skip<br />
    If New_Begin &gt;= sngSeekTo Then Exit Property        ' Exit if past the end<br />
    ' --------------------------------------------------------------------------<br />
    If New_Begin = sngSeekFrom Then Exit Property       ' Exit if already set<br />
    ' --------------------------------------------------------------------------<br />
    sngSeekFrom = New_Begin                             ' Set playback start<br />
    '<br />
End Property<br />
<br />
<br />
' PLAYBACK BEGIN LOOP (GET)<br />
' Retrieves (in milliseconds) the start position of a loop.<br />
' ==============================================================================<br />
Public Property Get To_End() As Single<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    To_End = sngSeekTo                                  ' Get value from class<br />
    '<br />
End Property<br />
<br />
<br />
' PLAYBACK BEGIN LOOP (LET)<br />
' Sets the position(in milliseconds) media playback ends, to possibly loop back<br />
' ==============================================================================<br />
Public Property Let To_End(ByVal New_End As Single)<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    If New_End &lt; 0 Then Exit Property                   ' Exit if invalid point<br />
    If New_End &gt; sngLength Then Exit Property           ' Exit if invalid point<br />
    If New_End &lt;= sngToSkip Then Exit Property          ' Exit if before To_Skip<br />
    If New_End &lt;= sngSeekFrom Then Exit Property        ' Exit if before start<br />
    ' --------------------------------------------------------------------------<br />
    If New_End = sngSeekTo Then Exit Property           ' Exit if already set<br />
    ' --------------------------------------------------------------------------<br />
    sngSeekTo = New_End                                 ' Set playback end<br />
    '<br />
End Property<br />
<br />
<br />
' PLAYBACK RELOOP TO (Let)<br />
' Sets the position(in milliseconds) playback is to resume if it began earlier<br />
' ==============================================================================<br />
Public Property Let To_ReLoop(ByVal New_To_Skip As Single)<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    If New_To_Skip &lt; 0 Then Exit Property               ' Exit if invalid position<br />
    If New_To_Skip &gt; sngLength Then Exit Property       ' Exit if invalid position<br />
    If New_To_Skip &gt;= sngSeekTo Then Exit Property      ' Exit if past loop end<br />
    ' --------------------------------------------------------------------------<br />
    If New_To_Skip = sngToSkip Then Exit Property       ' Exit if already set<br />
    ' --------------------------------------------------------------------------<br />
    sngToSkip = New_To_Skip                             ' Set To_Skip Point<br />
    sngSeekFrom = 0                                     ' Reset start point<br />
    '<br />
End Property<br />
<br />
<br />
' PLAYBACK VOLUME (GET)<br />
' Return the playback volume of the current file<br />
' ==============================================================================<br />
Public Property Get Volume() As Long<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    ' Initialize function variables<br />
    Dim lngReturn       As Long                         ' mciSendString return<br />
    Dim strCmd          As String                       ' Sets the MCI commands<br />
    Dim strStat         As String * 255                 ' Returned status buffer<br />
    Dim intLength       As Integer                      ' Returned data's length<br />
    '<br />
    If strAlias = "" Then                               ' If no file is open<br />
        Volume = 0                                      ' Set zero volume<br />
        Exit Property                                   ' and Exit<br />
    End If<br />
    '<br />
    strCmd = "Status " &amp; strAlias &amp; " volume"           ' Make MCI Status cmd<br />
    lngReturn = mciSendString(strCmd, strStat, 255, 0)  ' Pass MCI command<br />
    '<br />
    intLength = InStr(strStat, Chr(0))                  ' Get end of status<br />
    Volume = Val(Left(strStat, intLength - 1)) / 10     ' Set to function<br />
    '<br />
End Property<br />
<br />
<br />
' PLAYBACK VOLUME (LET)<br />
' Sets the playback volume<br />
' ==============================================================================<br />
Public Property Let Volume(ByVal New_Volume As Long)<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    ' Initialize function variables<br />
    Dim lngReturn       As Long                         ' mciSendString return<br />
    Dim strCmd          As String                       ' Sets the MCI commands<br />
    '<br />
    If strAlias = "" Then Exit Property                 ' Exit if no file open<br />
    '<br />
    If New_Volume &lt; 0 Or New_Volume &gt; 100 Then          ' If volume is invalid<br />
        Exit Property                                   ' Exit<br />
    End If<br />
    '<br />
    lngVolume = New_Volume * 10                         ' Set the volume<br />
    '<br />
    strCmd = "setaudio " &amp; strAlias                     ' Make MCI command<br />
    strCmd = strCmd &amp; " Volume to "                     ' Define for volume<br />
    strCmd = strCmd &amp; lngVolume                         ' Define volume level<br />
    lngReturn = mciSendString(strCmd, "", 0, 0&amp;)        ' Pass MCI command<br />
    '<br />
End Property<br />
<br />
<br />
' PLAYBACK LEFT VOLUME LET)<br />
' Sets the playback volume for the left channel<br />
' ==============================================================================<br />
Public Property Let VolumeL(ByVal New_Volume As Integer)<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    ' Initialize function variables<br />
    Dim lngReturn       As Long                         ' mciSendString return<br />
    Dim strCmd          As String                       ' Sets the MCI commands<br />
    '<br />
    If strAlias = "" Then Exit Property                 ' Exit if no file open<br />
    '<br />
    If New_Volume &lt; 0 Or New_Volume &gt; 100 Then          ' If volume is invalid<br />
        Exit Property                                   ' Exit<br />
    End If<br />
    '<br />
    lngVolumeL = New_Volume * 10                        ' Set the volume<br />
    '<br />
    strCmd = "setaudio " &amp; strAlias                     ' Make MCI command<br />
    strCmd = strCmd &amp; " left volume to "                ' Define left volume<br />
    strCmd = strCmd &amp; lngVolumeL                        ' Define volume level<br />
    lngReturn = mciSendString(strCmd, "", 0, 0&amp;)        ' Pass MCI command<br />
    '<br />
End Property<br />
<br />
<br />
' PLAYBACK RIGHT VOLUME LET)<br />
' Sets the playback volume for the right channel<br />
' ==============================================================================<br />
Public Property Let VolumeR(ByVal New_Volume As Integer)<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    ' Initialize function variables<br />
    Dim lngReturn       As Long                         ' mciSendString return<br />
    Dim strCmd          As String                       ' Sets the MCI commands<br />
    '<br />
    If strAlias = "" Then Exit Property                 ' Exit if no file open<br />
    '<br />
    If New_Volume &lt; 0 Or New_Volume &gt; 100 Then          ' If volume is invalid<br />
        Exit Property                                   ' Exit<br />
    End If<br />
    '<br />
    lngVolumeR = New_Volume * 10                        ' Set the volume<br />
    '<br />
    strCmd = "setaudio " &amp; strAlias                     ' Make MCI command<br />
    strCmd = strCmd &amp; " right volume to "               ' Define left volume<br />
    strCmd = strCmd &amp; lngVolumeR                        ' Define volume level<br />
    lngReturn = mciSendString(strCmd, "", 0, 0&amp;)        ' Pass MCI command<br />
    '<br />
End Property<br />
<br />
<br />
<br />
<br />
' ==============================================================================<br />
' = PRIVATE FUNCTIONS ==========================================================<br />
' ==============================================================================<br />
<br />
<br />
' CHECK FOR CUSTOM LOOP<br />
' Runs constantly when envoked to repeat media based on custom start/stop points<br />
' ==============================================================================<br />
Private Function pvt_LoopCheck() As Boolean<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    pvt_LoopCheck = False                               ' Set function false<br />
    If sngSeekTo &lt;&gt; sngLength Then pvt_LoopCheck = True ' Set true if loop end<br />
    If sngSeekFrom &lt;&gt; 0 Then pvt_LoopCheck = True       ' Set true if start<br />
    If sngToSkip &lt;&gt; 0 Then pvt_LoopCheck = True         ' Set true if To_Skip<br />
    '<br />
End Function<br />
<br />
<br />
' EXECUTE CUSTOM LOOP<br />
' Runs constantly when envoked to repeat media based on custom start/stop points<br />
' ==============================================================================<br />
Private Sub pvt_LoopExecute()<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    If bRepeat = False Then Exit Sub                    ' Exit if repeat is OFF<br />
    '<br />
    Do While bPlaying = True                            ' Loop only if playing<br />
        DoEvents                                        ' Permit other functions<br />
        If bRepeat = False Then Exit Do                 ' Exit if repeat is OFF<br />
        If Position &gt;= sngSeekTo Then                   ' If loop end point found<br />
            If sngToSkip &gt; 0 Then                       ' -- if To_Skip exists<br />
                sngSeekFrom = sngToSkip                 ' -- ... replace start<br />
            End If<br />
            mmPlay                                      ' Re-start play<br />
        End If<br />
    Loop<br />
    '<br />
End Sub<br />
<br />
<br />
' OBJECT EXISTS?<br />
' Returns whether a defined object exists or not<br />
' ==============================================================================<br />
Private Function pvt_ObjExist(objParm As Object) As Boolean<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    pvt_ObjExist = IIf(objParm Is Nothing, False, True)<br />
    '<br />
End Function</code></div></div></div>
		</div>
Or within the actual<span style="font-weight: bold;" class="mycode_b"> Class_MSS.cls </span>format: 
<br />
<img src="https://www.save-point.org/images/attachtypes/zip.gif" title="ZIP File" border="0" alt=".zip" />
&nbsp;&nbsp;<a href="attachment.php?aid=3038" target="_blank" title="">Class_MSS.zip</a> (Size: 6.93 KB / Downloads: 77)
<br />
<br />
<br />
<br />
<span style="font-size: medium;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Instructions</span></span><br />
Plenty... in the code itself.<br />
<br />
<br />
<br />
<span style="font-size: medium;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">FAQ</span></span><br />
The original code which this was based had no set-up for video playback, no pointing to any hwnd  supported objects.  This was one of the main additions I included<br />
<br />
<br />
<br />
<span style="font-size: medium;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Credits and Thanks</span></span><br />
Thanks to Mark Thesing who wrote the base code in 2002<br />
<br />
<br />
<br />
<span style="font-size: medium;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Terms and Conditions</span></span><br />
Use as you see fit.  No requirements other than due credit for both Mr. Thesing and myself.]]></description>
			<content:encoded><![CDATA[<div style="text-align: center;" class="mycode_align"><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">The MCISendString Multimedia Class</span></span><br />
<span style="font-size: medium;" class="mycode_size">Version: 1.0</span><br />
<span style="font-size: small;" class="mycode_size">Based upon work by Mark Thesing (July 18, 2002)</span></div>
<br />
<br />
<br />
<span style="font-size: medium;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Introduction</span></span><br />
Permits the loading, playback, and various other actions on a multimedia file.<br />
<br />
Since its original creation in 2002, the ability to present video content in a picturebox object has been added. Along with that, more multimedia file extensions are now recognized.<br />
<br />
Do note,  the class will only load and play one multimedia file at a time.  In order for a project  to play multiple files,  multiple instances of this class need to be defined.<br />
<br />
LOOPING:<br />
Using the MCISendstring system,  there is always a millisecond break as the MCISendstring attempts to loop back  to the start,  even with the built-in repeat function.<br />
<br />
<br />
<span style="font-size: medium;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Features</span></span><ul class="mycode_list"><li>Supports playback of the following Audio formats:  aiff, amr, flac, m4a, midi, mp2, mp3, wav, wma<br />
</li>
<li>Supports playback of the following Video formats:  avi, mpg, mpeg, mp4, m4v, asf, wmv<br />
</li>
<li>Allows custom loop position<br />
</li>
</ul>
<br />
<br />
<span style="font-size: medium;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Limitations</span></span><ul class="mycode_list"><li>Video footage does not have stretch-to-fit nor any resizing<br />
</li>
<li>Avi footage 'still' has no audio playback<br />
</li>
<li>Geared for Visual Basic 6 <br />
</li>
</ul>
<br />
<br />
<span style="font-size: medium;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Code</span></span><br />
<div class="tborder">
  			<div class="thead" style="padding:4px; margin:1px;"><input type="button" class="button" value="+" style="font-family:Monospace; padding:0px" onclick="if (this.parentNode.parentNode.getElementsByTagName('div')[1].style.display=='none'){ this.parentNode.parentNode.getElementsByTagName('div')[1].style.display='';this.value='-';} else {this.parentNode.parentNode.getElementsByTagName('div')[1].style.display='none';this.value='+';}"/> Code</div>
  			<div class="trow2" style="display:none; padding:4px; margin:1px;">
<div class="codeblock"><div class="title">Code:</div><div class="body" dir="ltr"><code>' ==============================================================================<br />
' ** The MCISendString Multimedia Class<br />
' ------------------------------------------------------------------------------<br />
'    by DerVVulfman<br />
'    version 1.0<br />
'    01-03-2026 (mm/dd/yyyy)<br />
'    Based upon work by Mark Thesing (July 18, 2002)<br />
' ==============================================================================<br />
'<br />
' INTRODUCTION:<br />
' -------------<br />
'<br />
' Permits the loading, playback, and various other actions on a multimedia file.<br />
'<br />
' Since its original creation in 2002, the ability to present video content in a<br />
' picturebox object has been added. Along with that, more multimedia file exten-<br />
' tions are now recognized.<br />
'<br />
' Do note,  the class will only load and play one multimedia file at a time.  In<br />
' order for a project  to play multiple files,  multiple instances of this class<br />
' need to be defined.<br />
'<br />
' LOOPING:  Using the MCISendstring system,  there is always a millisecond break<br />
'           as the MCISendstring attempts to loop back  to the start,  even with<br />
'           the built-in repeat function.<br />
'<br />
'<br />
' ==============================================================================<br />
'<br />
' CLASS INSTALLATION:<br />
' -------------------<br />
'<br />
' * In the form where used, define this class before any other action.<br />
'    -- Example:  Private clsMM As New Class_MSS<br />
'<br />
' * If you need two or more files playing, define multiple instances like so.<br />
'    -- Example:  Private clsMMOne As New Class_MSS<br />
'                 Private clsMMTwo As New Class_MSS<br />
'<br />
'   The 'clsMM' (or like) will direct you to commands within this class.<br />
'    -- Example:  clsMM.mmPlay<br />
'<br />
' * Ensure the class instance (or instances) removed from memory upon exit.<br />
'   It is also recommended to end any multimedia playback being executed.<br />
'   This is done within the form's  "Form_Unload" private subroutine.<br />
'   -- Example:  clsIni.mmStop<br />
'                Set clsIni = Nothing<br />
'                End<br />
'<br />
'<br />
' ==============================================================================<br />
'<br />
' MULTIMEDIA FORMATS:<br />
' -------------------<br />
'<br />
' Audio:  aiff, amr, flac, m4a, midi, mp2, mp3, wav, wma<br />
' Video:  avi, mpg, mpeg, mp4, m4v, asf, wmv<br />
'<br />
' * Amr format not recommended; playback sounds low quality<br />
' * Avi format has no audio playback<br />
'<br />
' * Formerly, only wav, mid, mp3, avi, mpg and mpeg were supported.<br />
'<br />
'<br />
' ==============================================================================<br />
'<br />
' METHODS:<br />
' --------<br />
'<br />
' CLOSE:    Closes the currently loaded file.<br />
' * SYNTAX: &lt;classname&gt;.mmClose<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' OPEN:     Opens the desired file. Optionally sets a window for video display.<br />
' * SYNTAX: &lt;classname&gt;.mmOpen filename [, object]<br />
'           * filename: The full filename (with path) to be loaded for playback.<br />
'           * object:   (Optional) The hwnd supported form object for video use.<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' PAUSE:    Pauses the file or resumes playback.<br />
' * SYNTAX: &lt;classname&gt;.mmPause<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' PLAY:     Plays the loaded file. Optionally accepts whether the file loops.<br />
' * SYNTAX: &lt;classname&gt;.mmPlay [, repeat]<br />
'           * repeat:   (Optional) True/False if the multimedia file loops.<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' SEEK:     Sets current playback to a specific position within the file.<br />
' * SYNTAX: &lt;classname&gt;.mmSeek location<br />
'           * location: The point within the file (in millisecond) to advance<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' SEEK INCREMENT: Sets playback to a position based on 1/1000th of its length.<br />
' * SYNTAX: &lt;classname&gt;.mmSeekIncr value<br />
'           * value: (Range 0-1000) The point based on 1/100th of its length.<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' STOP:     Ends playback of the loaded file. Sets the reader to the file's end.<br />
' * SYNTAX: &lt;classname&gt;.mmStop<br />
'<br />
' ------------------------------------------------------------------------------<br />
'<br />
'<br />
' ------------------------------------------------------------------------------<br />
'<br />
' PROPERTIES:<br />
' -----------<br />
'<br />
' FILENAME: Retrieves the name of the currently loaded file.<br />
' * SYNTAX: returned = &lt;classname&gt;.Filename<br />
'           * returned: (String) The name of the currently loaded file<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' FILENAME: Opens a specified filename. Does not define a window like OPEN.<br />
' * SYNTAX: &lt;classname&gt;.Filename filename<br />
'           * filename: The full filename (with path) to be loaded for playback.<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' LENGTH:   Retrieves the length/duration of the current file in milliseconds.<br />
' * SYNTAX: returned = &lt;classname&gt;.Length<br />
'           * returned: (Single) The file's playback duration in milliseconds<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' PAUSED:   Retrieves if media playback was temporarily halted.<br />
' * SYNTAX: returned = &lt;classname&gt;.Paused<br />
'           * returned: (Boolean) Returns True/False on pause status<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' PERCENT:  Retrieves the percent of the file played to one decimal position.<br />
' * SYNTAX: returned = &lt;classname&gt;.percent<br />
'           * returned: (Single: Range of 0.0-100.0) Current amount played.<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' POSITION: Retrieves the current playback position of the current file.<br />
' * SYNTAX: returned = &lt;classname&gt;.Position<br />
'           * returned: The full filename (with path) to be loaded for playback.<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' POSITION: (as Seek) Sets playback to a specified position of the current file.<br />
' * SYNTAX: &lt;classname&gt;.Position location<br />
'           * location: The point within the file (in millisecond) to advance.<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' TO_BEGIN: Retrives (in milliseconds) where media playback will begin or resume<br />
' * SYNTAX: returned = &lt;classname&gt;.To_Begin<br />
'           * returned: (Single) The position where media playback starts.<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' TO_BEGIN: Defines where playback begins, or where to return if set to repeat.<br />
' * SYNTAX: &lt;classname&gt;.To_Begin location<br />
'           * location: The point within the file (in millisecond) to start.<br />
'           NOTE:  It must be called 'after' [To_Reloop] if both are used together.<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' TO_END:   Retrives (in milliseconds) where media playback is set to end.<br />
' * SYNTAX: returned = &lt;classname&gt;.To_End<br />
'           * returned: (Single) The position where media playback ends.<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' TO_END:   Defines where playback ends if not at the end of the current file.<br />
' * SYNTAX: &lt;classname&gt;.To_End location<br />
'           * location: The point within the file (in millisecond) to end.<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' TO_RELOOP: Defines where playback ends if not at the end of the current file.<br />
' * SYNTAX:  &lt;classname&gt;.To_ReLoop location<br />
'            * location: The point in the file (in millisecond) to restart loop.<br />
'            NOTE:  If used in tandem with [To_Begin], it must be called first.<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' VOLUME:   Gets the playback volume.<br />
' * SYNTAX: returned = &lt;classname&gt;.Volume<br />
'           * returned: (Long) The volume amplitude (generally 0-100)<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' VOLUME:   Sets the playback volume.<br />
' * SYNTAX: &lt;classname&gt;.Volume amplitude<br />
'           * amplitude: The volume of audio playback.<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' VOLUME LEFT:  Sets the playback volume for the left volume channel<br />
' * SYNTAX:     &lt;classname&gt;.VolumeL amplitude<br />
'               * amplitude: The volume of the left channel playback.<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
'<br />
' VOLUME RIGHT: Sets the playback volume for the right volume channel.<br />
' * SYNTAX:     &lt;classname&gt;.VolumeR amplitude<br />
'               * amplitude: The volume of the right channel playback.<br />
'<br />
'         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br />
<br />
' ------------------------------------------------------------------------------<br />
'<br />
'<br />
' ==============================================================================<br />
<br />
<br />
<br />
<br />
Option Explicit<br />
<br />
' API Function Declarations<br />
' ==============================================================================<br />
Private Declare Function mciSendString Lib "winmm.dll" Alias "mciSendStringA" _<br />
            (ByVal lpstrCommand As String, ByVal lpstrReturnString As String, _<br />
            ByVal uReturnLength As Long, ByVal hwndCallback As Long) As Long<br />
<br />
<br />
<br />
<br />
' Private Variable Declarations<br />
' ==============================================================================<br />
    Private strAlias                As String           ' Mmedia resource name<br />
    Private strFileName             As String           ' Current filename<br />
    Private strFrom                 As String           ' Defined Playback start<br />
    Private strTo                   As String           ' Defined Playback end<br />
    ' --------------------------------------------------------------------------<br />
    Private sngLength               As Single           ' Playback length<br />
    Private sngIncrement            As Single           ' Length divided by 1000<br />
    Private sngPosition             As Single           ' Current position<br />
    Private sngToSkip               As Single           ' Loop flourish skip<br />
    Private sngSeekFrom             As Single           ' Loop starting point<br />
    Private sngSeekTo               As Single           ' Loop ending point<br />
    ' --------------------------------------------------------------------------<br />
    Private strStatus               As String           ' Current playing status<br />
    Private bPlaying                As Boolean          ' If file is playing<br />
    Private bPaused                 As Boolean          ' If paused or not<br />
    Private bRepeat                 As Boolean          ' If loops<br />
    ' --------------------------------------------------------------------------<br />
    Private lngVolume               As Long             ' Current volume<br />
    Private lngVolumeL              As Long             ' (above) Left Volume<br />
    Private lngVolumeR              As Long             ' (above) Right Volume<br />
<br />
<br />
<br />
<br />
' ==============================================================================<br />
' = CLASS FUNCTIONS ============================================================<br />
' ==============================================================================<br />
<br />
<br />
' The Initialization routine<br />
'===============================================================================<br />
Private Sub Class_Initialize()<br />
    '<br />
    strAlias = ""                                       ' Set empty Alias name<br />
    strFileName = ""                                    ' Set empty filename<br />
    bPlaying = False                                    ' No playing at start<br />
    bPaused = False                                     ' No pause at start<br />
    sngToSkip = 0                                       ' Clear loop points<br />
    sngSeekFrom = 0                                     ' Clear loop points<br />
    sngSeekTo = 0                                       ' Clear loop points<br />
    lngVolume = 0                                       ' Clear volume values<br />
    lngVolumeL = 0                                      ' Clear volume values<br />
    lngVolumeR = 0                                      ' Clear volume values<br />
    '<br />
End Sub<br />
<br />
<br />
<br />
<br />
' ==============================================================================<br />
' = GENERAL FUNCTIONS ==========================================================<br />
' ==============================================================================<br />
<br />
<br />
' CLOSE FILE<br />
' Close the currently open multimedia file<br />
' ==============================================================================<br />
Public Sub mmClose()<br />
    '      ---------------------------------------------------------------------<br />
    '<br />
    ' Initialize function variables<br />
    Dim lngReturn       As Long                         ' mciSendString return<br />
    Dim strCmd          As String                       ' Sets the MCI commands<br />
    '<br />
    If strAlias = "" Then Exit Sub                      ' Exit if no file open<br />
    '<br />
    strCmd = "Close " &amp; strAlias                        ' Make MCI Close Command<br />
    lngReturn = mciSendString(strCmd, "", 0, 0)         ' Pass MCI command<br />
    '<br />
    strAlias = ""                                       ' Clear opened file<br />
    strFileName = ""                                    ' Clear filename<br />
    bPlaying = False                                    ' Flag not playing<br />
    '<br />
End Sub<br />
<br />
<br />
' OPEN FILE<br />
' Open the specified multimedia file and close any others that may be open<br />
' ==============================================================================<br />
Public Sub mmOpen(ByVal strTheFile As String, _<br />
    Optional ByVal objPic As Object = Nothing)<br />
    '      ---------------------------------------------------------------------<br />
    '<br />
    ' Initialize function variables<br />
    Dim lngReturn       As Long                         ' mciSendString return<br />
    Dim strCmd          As String                       ' Sets the MCI commands<br />
    Dim strLen          As String * 255                 ' Gets the file length<br />
    Dim strType         As String                       ' Holds the file type<br />
    Dim intLength       As Integer                      ' Returned data's length<br />
    Dim bVideo          As Boolean                      ' Defined video window<br />
    '<br />
    ' Initialize subroutine constant<br />
    Const WS_CHILD As Long = &amp;H40000000                 ' Define child window<br />
    '<br />
    bPlaying = False                                    ' Flag not playing<br />
    bPaused = False                                     ' Turn off paused flag<br />
    '<br />
    If strAlias &lt;&gt; "" Then mmClose                      ' Close if previous open<br />
    '<br />
    ' Determine playback mode based on file extension<br />
    ' --------------------------------------------------------------------------<br />
    Select Case UCase(Right(strTheFile, 4))             ' Branch on extension<br />
        ' -- AUDIO FORMATS -----------------------------------------------------<br />
        Case ".WAV"                                     ' For Wav extension<br />
            strType = "Waveaudio"                       ' ... assume wave audio<br />
            bVideo = False                              ' ... set no-video usage<br />
        Case ".MID"                                     ' For mid extension<br />
            strType = "Sequencer"                       ' ... assume sequencer<br />
            bVideo = False                              ' ... set no-video usage<br />
        Case "AIFF", ".AMR", "FLAC"                     ' For AIFF, AMR and FLAC<br />
            strType = "MPEGVideo"                       ' ... Mpeg system use<br />
            bVideo = False                              ' ... set no-video usage<br />
        Case ".M4A", ".MP2", ".MP3"                     ' For MP2/3 extensions<br />
            strType = "MPEGVideo"                       ' ... Mpeg system use<br />
            bVideo = False                              ' ... set no-video usage<br />
        Case ".WMA"                                     ' For flaky WMAs<br />
            strType = "MPEGVideo"                       ' ... Mpeg system use<br />
            bVideo = False                              ' ... set no-video usage<br />
        ' -- VIDEO FORMATS -----------------------------------------------------<br />
        Case ".AVI"                                     ' For Avi extension<br />
            strType = "AviVideo"                        ' ... assume avi video<br />
            bVideo = True                               ' ... set video usage<br />
        Case "MPEG", ".MPG", ".MP4"                     ' For MPG, MPEG or MP4<br />
            strType = "MPEGVideo"                       ' ... Mpeg system use<br />
            bVideo = True                               ' ... set video usage<br />
        Case ".ASF", ".M4V"                             ' For ASF or M4V<br />
            strType = "MPEGVideo"                       ' ... Mpeg system use<br />
            bVideo = True                               ' ... set video usage<br />
        Case ".WMV"                                     ' For flaky WMVs<br />
            strType = "MPEGVideo"                       ' ... Mpeg system use<br />
            bVideo = True                               ' ... set video usage<br />
        ' -- NO VALID FORMAT FOUND ---------------------------------------------<br />
        Case Else                                       ' -- otherwise --<br />
            Exit Sub                                    ' Exit if unrecognized<br />
    End Select<br />
    ' --------------------------------------------------------------------------<br />
    '<br />
    strAlias = Right(strTheFile, 3) &amp; Minute(Now)       ' Make unique alias name<br />
    '<br />
    If InStr(strTheFile, " ") Then                      ' If filename has spaces<br />
        strTheFile = Chr(34) &amp; strTheFile &amp; Chr(34)     ' ... wrap in quotes<br />
    End If<br />
    '<br />
    If pvt_ObjExist(objPic) = False Then                ' If no picture object<br />
        bVideo = False                                  ' Force no video usage<br />
    End If<br />
    '<br />
    ' Create the Open MCISendString command<br />
    ' --------------------------------------------------------------------------<br />
    strCmd = "Open " &amp; strTheFile                       ' Make MCI Open command<br />
    strCmd = strCmd &amp; " alias " &amp; strAlias              ' Include alias name<br />
    If bVideo = True Then<br />
        strCmd = strCmd &amp; " parent "                    ' Set target window use<br />
        strCmd = strCmd &amp; CStr(objPic.hWnd)             ' Set actual target<br />
        strCmd = strCmd &amp; " style " &amp; CStr(WS_CHILD)    ' Set as child window<br />
    Else<br />
        strCmd = strCmd &amp; " Type " &amp; strType            ' Add audio type<br />
    End If<br />
    strCmd = strCmd &amp; " WAIT"                           ' Force wait till play<br />
    ' --------------------------------------------------------------------------<br />
    '<br />
    lngReturn = mciSendString(strCmd, "", 0, 0)         ' Pass MCI command<br />
    '<br />
    ' Ensure file set to start position and increments<br />
    ' --------------------------------------------------------------------------<br />
    strCmd = "Status " &amp; strAlias &amp; " length"           ' Make MCI Length cmd<br />
    lngReturn = mciSendString(strCmd, strLen, 255, 0)   ' Pass MCI command<br />
    intLength = InStr(strLen, Chr(0))                   ' Get end of length<br />
    sngLength = Val(Left(strLen, intLength - 1))        ' Set to class variable<br />
    sngIncrement = sngLength / 1000<br />
    '<br />
    ' Define loop start and end defaults<br />
    ' --------------------------------------------------------------------------<br />
    sngToSkip = 0                                       ' Loop flourish point<br />
    sngSeekFrom = 0                                     ' Loop starting point<br />
    sngSeekTo = sngLength                               ' Loop ending point<br />
    ' --------------------------------------------------------------------------<br />
    '<br />
    ' Ensure file set to start position<br />
    ' --------------------------------------------------------------------------<br />
    strCmd = "Seek " &amp; strAlias &amp; " to 0"               ' Make MCI Seek Command<br />
    lngReturn = mciSendString(strCmd, "", 0, 0)         ' Pass MCI command<br />
    ' --------------------------------------------------------------------------<br />
    '<br />
End Sub<br />
<br />
<br />
' PAUSE PLAYBACK<br />
' Pause playback of the file<br />
' ==============================================================================<br />
Public Sub mmPause()<br />
    '      ---------------------------------------------------------------------<br />
    '<br />
    ' Initialize function variables<br />
    Dim lngReturn       As Long                         ' mciSendString return<br />
    Dim strCmd          As String                       ' Sets the MCI commands<br />
    '<br />
    If strAlias = "" Then Exit Sub                      ' Exit if no file open<br />
    '<br />
    If bPlaying = False Then Exit Sub                   ' Exit if not playing<br />
    '<br />
    If bPaused = False Then                             ' If already paused<br />
        bPaused = True                                  ' ... set flag n pause<br />
        strCmd = "Pause " &amp; strAlias                    ' Make MCI Pause Command<br />
    Else<br />
        bPaused = False                                 ' ... set flag n play<br />
        strCmd = "Resume " &amp; strAlias                   ' Make MCI Resume Cmnd<br />
    End If<br />
    '<br />
    lngReturn = mciSendString(strCmd, "", 0, 0)         ' Pass MCI command<br />
    '<br />
End Sub<br />
<br />
<br />
' PLAY FILE<br />
' Plays the currently open file from the current position<br />
' ==============================================================================<br />
Public Sub mmPlay()<br />
    '      ---------------------------------------------------------------------<br />
    '<br />
    ' Initialize function variables<br />
    Dim lngReturn       As Long                         ' mciSendString return<br />
    Dim strCmd          As String                       ' Sets the MCI commands<br />
    Dim strTo2 As String<br />
    '<br />
    If strAlias = "" Then Exit Sub                      ' Exit if no file open<br />
    '<br />
    bPlaying = True                                     ' Flag IS playing<br />
    bPaused = False                                     ' Playing, not paused<br />
    '<br />
    strCmd = "Play " &amp; strAlias                         ' Make MCI Play Command<br />
    strFrom = " from " &amp; Trim(Str(sngSeekFrom))         ' Set start position<br />
    strCmd = strCmd &amp; strFrom                           ' Add to Play command<br />
    '<br />
    If pvt_LoopCheck = False Then                       ' If no custom loops<br />
        If bRepeat = True Then                          ' If set to repeat<br />
            strCmd = strCmd &amp; " Repeat"                 ' Add repeat to command<br />
        End If<br />
    End If<br />
    '<br />
    lngReturn = mciSendString(strCmd, "", 0, 0)         ' Pass MCI command<br />
    '<br />
    If bRepeat = False Then Exit Sub                    ' Exit if no repeating<br />
    If pvt_LoopCheck = False Then Exit Sub              ' Exit if no loop spot<br />
    '<br />
    pvt_LoopExecute                                     ' Perform repeat loop<br />
    '<br />
End Sub<br />
<br />
<br />
' SEEK TO PLAYBACK LOCATION<br />
' Seek a specific position within the file<br />
' ==============================================================================<br />
Public Sub mmSeek(ByVal sngPosition As Single)<br />
    '      ---------------------------------------------------------------------<br />
    '<br />
    ' Initialize function variables<br />
    Dim lngReturn       As Long                         ' mciSendString return<br />
    Dim strCmd          As String                       ' Sets the MCI commands<br />
    '<br />
    strCmd = "Seek " &amp; strAlias                         ' Make MCI Seek Command<br />
    strCmd = strCmd &amp; " to " &amp; Trim(Str(sngPosition))   ' Define seek position<br />
    lngReturn = mciSendString(strCmd, "", 0, 0)         ' Pass MCI command<br />
    '<br />
End Sub<br />
<br />
<br />
' SEEK TO LOCATION ON INCREMENTAL VALUE<br />
' Seek a specific position within the file based on value<br />
' ==============================================================================<br />
Public Sub mmSeekIncr(ByVal intIncrement As Integer)<br />
    '      ---------------------------------------------------------------------<br />
    '<br />
    ' Initialize function variables<br />
    Dim lngReturn       As Long                         ' mciSendString return<br />
    Dim strCmd          As String                       ' Sets the MCI commands<br />
    Dim sngPosition     As Long<br />
    '<br />
    If intIncrement &lt; 0 Then Exit Sub                   ' Exit if out of range<br />
    If intIncrement &gt; 1000 Then Exit Sub                ' Exit if out of range<br />
    '<br />
    sngPosition = intIncrement * sngIncrement           ' Math based on range<br />
    '<br />
    strCmd = "Seek " &amp; strAlias                         ' Make MCI Seek Command<br />
    strCmd = strCmd &amp; " to " &amp; Trim(Str(sngPosition))   ' Define seek position<br />
    lngReturn = mciSendString(strCmd, "", 0, 0)         ' Pass MCI command<br />
    <br />
    If bPlaying = False Then Exit Sub                   ' Exit if not playing<br />
    If bPaused = True Then Exit Sub                     ' Exit if paused<br />
    '<br />
    strCmd = "Play " &amp; strAlias                         ' Make MCI Play Command<br />
    '<br />
    If pvt_LoopCheck = False Then                       ' If no custom loops<br />
        If bRepeat = True Then                          ' If set to repeat<br />
            strCmd = strCmd &amp; " Repeat"                 ' Add repeat to command<br />
        End If<br />
    End If<br />
    '<br />
    lngReturn = mciSendString(strCmd, "", 0, 0)         ' Pass MCI command<br />
    '<br />
End Sub<br />
<br />
<br />
' STOP PLAYBACK<br />
' Stop using a file totally. Running or not.<br />
' ==============================================================================<br />
Public Sub mmStop()<br />
    '      ---------------------------------------------------------------------<br />
    '<br />
    ' Initialize function variables<br />
    Dim lngReturn       As Long                         ' mciSendString return<br />
    Dim strCmd          As String                       ' Sets the MCI commands<br />
    Dim sngLength       As Single                       ' Sets playback length<br />
    '<br />
    If strAlias = "" Then Exit Sub                      ' Exit if no file open<br />
    '<br />
    bPlaying = False                                    ' Flag not playing<br />
    '<br />
    strCmd = "Stop " &amp; strAlias                         ' Make MCI Stop Command<br />
    lngReturn = mciSendString(strCmd, "", 0, 0)         ' Pass MCI command<br />
    '<br />
    sngLength = Length                                  ' Get playback length<br />
    '<br />
    strCmd = "Seek " &amp; strAlias                         ' Make MCI Seek Command<br />
    strCmd = strCmd &amp; " to " &amp; Trim(Str(sngLength))     ' Define seek end<br />
    lngReturn = mciSendString(strCmd, "", 0, 0)         ' Pass MCI command<br />
    '<br />
End Sub<br />
<br />
<br />
<br />
<br />
' ==============================================================================<br />
' = PROPERTY SETTINGS ==========================================================<br />
' ==============================================================================<br />
<br />
<br />
' FILENAME (GET)<br />
' Returns the object FileName Property<br />
' ==============================================================================<br />
Public Property Get Filename() As String<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    Filename = strFileName                              ' Get value from class<br />
    '<br />
End Property<br />
<br />
<br />
' FILENAME (LET)<br />
' Sets the objects FileName property.<br />
' ==============================================================================<br />
Public Property Let Filename(ByVal New_FileName As String)<br />
    '           ----------------------------------------------------------------<br />
'   Sets the objects FileName property. This also implies<br />
'   that you also want to open the file so control is passed<br />
'   to the mmOpen method<br />
    '<br />
    strFileName = New_FileName<br />
    mmOpen New_FileName<br />
    '<br />
End Property<br />
<br />
<br />
' PLAYBACK LENGTH (GET)<br />
' Returns the length of the file, the value acquired when file was opened<br />
' ==============================================================================<br />
Public Property Get Length() As Single<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    If strAlias = "" Then                               ' If no file is open<br />
        Length = 0                                      ' Set zero length<br />
        Exit Property                                   ' and Exit<br />
    End If<br />
    '<br />
    Length = sngLength                                  ' Get value from class<br />
    '<br />
End Property<br />
<br />
<br />
' PAUSED (GET)<br />
' Returns the status of being paused (using in-class variables)<br />
' ==============================================================================<br />
Public Property Get Paused() As Boolean<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    Paused = bPaused                                    ' Get value from class<br />
    '<br />
End Property<br />
<br />
<br />
<br />
' PERCENT (GET)<br />
' Returns the relative position in the media relative to its size in 0-100 range<br />
' ==============================================================================<br />
Public Property Get Percent() As Single<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    ' Initialize property variables<br />
    Dim fLength         As Single                       ' Media file duration<br />
    Dim fPosition       As Single                       ' Current play position<br />
    Dim fPercent        As Single                       ' Percent value as float<br />
    Dim iPercent        As Integer                      ' Integer in deciseconds<br />
    '<br />
    ' Initialize function variables<br />
    If strAlias = "" Then                               ' If no file is open<br />
        Percent = 0                                     ' Set zero length<br />
        Exit Property                                   ' and Exit<br />
    End If<br />
    '<br />
    fLength = Length                                    ' Get media duration<br />
    fPosition = Position                                ' Get current position<br />
    '<br />
    fPercent = fPosition / fLength                      ' Get increment<br />
    iPercent = fPercent * 1000                          ' Get range 0-1000<br />
    Percent = iPercent / 10                             ' Set to range 0.0-100.0<br />
    '<br />
End Property<br />
<br />
<br />
' PLAYBACK POSITION (GET)<br />
' Returns the current position in the file if a file is open<br />
' ==============================================================================<br />
Public Property Get Position() As Single<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    ' Initialize function variables<br />
    Dim lngReturn       As Long                         ' mciSendString return<br />
    Dim strCmd          As String                       ' Sets the MCI commands<br />
    Dim strPos          As String * 255                 ' Returned pos buffer<br />
    Dim intLength       As Integer                      ' Returned data's length<br />
    '<br />
    If strAlias = "" Then                               ' If no file is open<br />
        Position = 0                                    ' Set zero position<br />
        Exit Property                                   ' and Exit<br />
    End If<br />
    '<br />
    strCmd = "Status " &amp; strAlias &amp; " position"         ' Make MCI Position cmd<br />
    lngReturn = mciSendString(strCmd, strPos, 255, 0)   ' Pass MCI command<br />
    '<br />
    intLength = InStr(strPos, Chr(0))                   ' Get end of position<br />
    Position = Val(Left(strPos, intLength - 1))         ' Set to function<br />
    '<br />
End Property<br />
<br />
<br />
' PLAYBACK LENGTH (LET)<br />
' Set the position property by seeking<br />
' ==============================================================================<br />
Public Property Let Position(ByVal New_Position As Single)<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    sngPosition = New_Position                          ' Get value from class<br />
    mmSeek New_Position                                 ' Pass into mmSeek<br />
    '<br />
End Property<br />
<br />
<br />
' REPEAT (GET)<br />
' Returns the objects Repeat property<br />
' ==============================================================================<br />
Public Property Get Repeat() As Boolean<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    Repeat = bRepeat                                    ' Get value from class<br />
    '<br />
End Property<br />
<br />
<br />
' REPEAT (LET)<br />
' Sets the value of the object Repeat property<br />
' ==============================================================================<br />
Public Property Let Repeat(ByVal New_Repeat As Boolean)<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    bRepeat = New_Repeat                                ' Set into class value<br />
    '<br />
End Property<br />
<br />
<br />
' PLAYBACK STATUS (GET)<br />
' Return the playback/record status of the current file<br />
' ==============================================================================<br />
Public Property Get Status() As String<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    ' Initialize function variables<br />
    Dim lngReturn       As Long                         ' mciSendString return<br />
    Dim strCmd          As String                       ' Sets the MCI commands<br />
    Dim strStat         As String * 255                 ' Returned status buffer<br />
    Dim intLength       As Integer                      ' Returned data's length<br />
    '<br />
    If strAlias = "" Then Exit Property                 ' Exit if no file open<br />
    '<br />
    strCmd = "Status " &amp; strAlias &amp; " mode"             ' Make MCI Status cmd<br />
    lngReturn = mciSendString(strCmd, strStat, 255, 0)  ' Pass MCI command<br />
    '<br />
    intLength = InStr(strStat, Chr(0))                  ' Get end of status<br />
    Status = Left(strStat, intLength - 1)               ' Set to function<br />
    '<br />
End Property<br />
<br />
<br />
' PLAYBACK BEGIN LOOP (GET)<br />
' Retrieves the position (in milliseconds) where the media playback begins<br />
' ==============================================================================<br />
Public Property Get To_Begin() As Single<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    To_Begin = sngSeekFrom                              ' Get value from class<br />
    '<br />
End Property<br />
<br />
<br />
' PLAYBACK BEGIN LOOP (LET)<br />
' Sets the position(in milliseconds) media playback is to begin or resume<br />
' ==============================================================================<br />
Public Property Let To_Begin(ByVal New_Begin As Single)<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    If New_Begin &lt; 0 Then Exit Property                 ' Exit if invalid point<br />
    If New_Begin &gt; sngLength Then Exit Property         ' Exit if invalid point<br />
    If New_Begin &gt;= sngToSkip Then Exit Property        ' Exit if past To_Skip<br />
    If New_Begin &gt;= sngSeekTo Then Exit Property        ' Exit if past the end<br />
    ' --------------------------------------------------------------------------<br />
    If New_Begin = sngSeekFrom Then Exit Property       ' Exit if already set<br />
    ' --------------------------------------------------------------------------<br />
    sngSeekFrom = New_Begin                             ' Set playback start<br />
    '<br />
End Property<br />
<br />
<br />
' PLAYBACK BEGIN LOOP (GET)<br />
' Retrieves (in milliseconds) the start position of a loop.<br />
' ==============================================================================<br />
Public Property Get To_End() As Single<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    To_End = sngSeekTo                                  ' Get value from class<br />
    '<br />
End Property<br />
<br />
<br />
' PLAYBACK BEGIN LOOP (LET)<br />
' Sets the position(in milliseconds) media playback ends, to possibly loop back<br />
' ==============================================================================<br />
Public Property Let To_End(ByVal New_End As Single)<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    If New_End &lt; 0 Then Exit Property                   ' Exit if invalid point<br />
    If New_End &gt; sngLength Then Exit Property           ' Exit if invalid point<br />
    If New_End &lt;= sngToSkip Then Exit Property          ' Exit if before To_Skip<br />
    If New_End &lt;= sngSeekFrom Then Exit Property        ' Exit if before start<br />
    ' --------------------------------------------------------------------------<br />
    If New_End = sngSeekTo Then Exit Property           ' Exit if already set<br />
    ' --------------------------------------------------------------------------<br />
    sngSeekTo = New_End                                 ' Set playback end<br />
    '<br />
End Property<br />
<br />
<br />
' PLAYBACK RELOOP TO (Let)<br />
' Sets the position(in milliseconds) playback is to resume if it began earlier<br />
' ==============================================================================<br />
Public Property Let To_ReLoop(ByVal New_To_Skip As Single)<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    If New_To_Skip &lt; 0 Then Exit Property               ' Exit if invalid position<br />
    If New_To_Skip &gt; sngLength Then Exit Property       ' Exit if invalid position<br />
    If New_To_Skip &gt;= sngSeekTo Then Exit Property      ' Exit if past loop end<br />
    ' --------------------------------------------------------------------------<br />
    If New_To_Skip = sngToSkip Then Exit Property       ' Exit if already set<br />
    ' --------------------------------------------------------------------------<br />
    sngToSkip = New_To_Skip                             ' Set To_Skip Point<br />
    sngSeekFrom = 0                                     ' Reset start point<br />
    '<br />
End Property<br />
<br />
<br />
' PLAYBACK VOLUME (GET)<br />
' Return the playback volume of the current file<br />
' ==============================================================================<br />
Public Property Get Volume() As Long<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    ' Initialize function variables<br />
    Dim lngReturn       As Long                         ' mciSendString return<br />
    Dim strCmd          As String                       ' Sets the MCI commands<br />
    Dim strStat         As String * 255                 ' Returned status buffer<br />
    Dim intLength       As Integer                      ' Returned data's length<br />
    '<br />
    If strAlias = "" Then                               ' If no file is open<br />
        Volume = 0                                      ' Set zero volume<br />
        Exit Property                                   ' and Exit<br />
    End If<br />
    '<br />
    strCmd = "Status " &amp; strAlias &amp; " volume"           ' Make MCI Status cmd<br />
    lngReturn = mciSendString(strCmd, strStat, 255, 0)  ' Pass MCI command<br />
    '<br />
    intLength = InStr(strStat, Chr(0))                  ' Get end of status<br />
    Volume = Val(Left(strStat, intLength - 1)) / 10     ' Set to function<br />
    '<br />
End Property<br />
<br />
<br />
' PLAYBACK VOLUME (LET)<br />
' Sets the playback volume<br />
' ==============================================================================<br />
Public Property Let Volume(ByVal New_Volume As Long)<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    ' Initialize function variables<br />
    Dim lngReturn       As Long                         ' mciSendString return<br />
    Dim strCmd          As String                       ' Sets the MCI commands<br />
    '<br />
    If strAlias = "" Then Exit Property                 ' Exit if no file open<br />
    '<br />
    If New_Volume &lt; 0 Or New_Volume &gt; 100 Then          ' If volume is invalid<br />
        Exit Property                                   ' Exit<br />
    End If<br />
    '<br />
    lngVolume = New_Volume * 10                         ' Set the volume<br />
    '<br />
    strCmd = "setaudio " &amp; strAlias                     ' Make MCI command<br />
    strCmd = strCmd &amp; " Volume to "                     ' Define for volume<br />
    strCmd = strCmd &amp; lngVolume                         ' Define volume level<br />
    lngReturn = mciSendString(strCmd, "", 0, 0&amp;)        ' Pass MCI command<br />
    '<br />
End Property<br />
<br />
<br />
' PLAYBACK LEFT VOLUME LET)<br />
' Sets the playback volume for the left channel<br />
' ==============================================================================<br />
Public Property Let VolumeL(ByVal New_Volume As Integer)<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    ' Initialize function variables<br />
    Dim lngReturn       As Long                         ' mciSendString return<br />
    Dim strCmd          As String                       ' Sets the MCI commands<br />
    '<br />
    If strAlias = "" Then Exit Property                 ' Exit if no file open<br />
    '<br />
    If New_Volume &lt; 0 Or New_Volume &gt; 100 Then          ' If volume is invalid<br />
        Exit Property                                   ' Exit<br />
    End If<br />
    '<br />
    lngVolumeL = New_Volume * 10                        ' Set the volume<br />
    '<br />
    strCmd = "setaudio " &amp; strAlias                     ' Make MCI command<br />
    strCmd = strCmd &amp; " left volume to "                ' Define left volume<br />
    strCmd = strCmd &amp; lngVolumeL                        ' Define volume level<br />
    lngReturn = mciSendString(strCmd, "", 0, 0&amp;)        ' Pass MCI command<br />
    '<br />
End Property<br />
<br />
<br />
' PLAYBACK RIGHT VOLUME LET)<br />
' Sets the playback volume for the right channel<br />
' ==============================================================================<br />
Public Property Let VolumeR(ByVal New_Volume As Integer)<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    ' Initialize function variables<br />
    Dim lngReturn       As Long                         ' mciSendString return<br />
    Dim strCmd          As String                       ' Sets the MCI commands<br />
    '<br />
    If strAlias = "" Then Exit Property                 ' Exit if no file open<br />
    '<br />
    If New_Volume &lt; 0 Or New_Volume &gt; 100 Then          ' If volume is invalid<br />
        Exit Property                                   ' Exit<br />
    End If<br />
    '<br />
    lngVolumeR = New_Volume * 10                        ' Set the volume<br />
    '<br />
    strCmd = "setaudio " &amp; strAlias                     ' Make MCI command<br />
    strCmd = strCmd &amp; " right volume to "               ' Define left volume<br />
    strCmd = strCmd &amp; lngVolumeR                        ' Define volume level<br />
    lngReturn = mciSendString(strCmd, "", 0, 0&amp;)        ' Pass MCI command<br />
    '<br />
End Property<br />
<br />
<br />
<br />
<br />
' ==============================================================================<br />
' = PRIVATE FUNCTIONS ==========================================================<br />
' ==============================================================================<br />
<br />
<br />
' CHECK FOR CUSTOM LOOP<br />
' Runs constantly when envoked to repeat media based on custom start/stop points<br />
' ==============================================================================<br />
Private Function pvt_LoopCheck() As Boolean<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    pvt_LoopCheck = False                               ' Set function false<br />
    If sngSeekTo &lt;&gt; sngLength Then pvt_LoopCheck = True ' Set true if loop end<br />
    If sngSeekFrom &lt;&gt; 0 Then pvt_LoopCheck = True       ' Set true if start<br />
    If sngToSkip &lt;&gt; 0 Then pvt_LoopCheck = True         ' Set true if To_Skip<br />
    '<br />
End Function<br />
<br />
<br />
' EXECUTE CUSTOM LOOP<br />
' Runs constantly when envoked to repeat media based on custom start/stop points<br />
' ==============================================================================<br />
Private Sub pvt_LoopExecute()<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    If bRepeat = False Then Exit Sub                    ' Exit if repeat is OFF<br />
    '<br />
    Do While bPlaying = True                            ' Loop only if playing<br />
        DoEvents                                        ' Permit other functions<br />
        If bRepeat = False Then Exit Do                 ' Exit if repeat is OFF<br />
        If Position &gt;= sngSeekTo Then                   ' If loop end point found<br />
            If sngToSkip &gt; 0 Then                       ' -- if To_Skip exists<br />
                sngSeekFrom = sngToSkip                 ' -- ... replace start<br />
            End If<br />
            mmPlay                                      ' Re-start play<br />
        End If<br />
    Loop<br />
    '<br />
End Sub<br />
<br />
<br />
' OBJECT EXISTS?<br />
' Returns whether a defined object exists or not<br />
' ==============================================================================<br />
Private Function pvt_ObjExist(objParm As Object) As Boolean<br />
    '           ----------------------------------------------------------------<br />
    '<br />
    pvt_ObjExist = IIf(objParm Is Nothing, False, True)<br />
    '<br />
End Function</code></div></div></div>
		</div>
Or within the actual<span style="font-weight: bold;" class="mycode_b"> Class_MSS.cls </span>format: 
<br />
<img src="https://www.save-point.org/images/attachtypes/zip.gif" title="ZIP File" border="0" alt=".zip" />
&nbsp;&nbsp;<a href="attachment.php?aid=3038" target="_blank" title="">Class_MSS.zip</a> (Size: 6.93 KB / Downloads: 77)
<br />
<br />
<br />
<br />
<span style="font-size: medium;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Instructions</span></span><br />
Plenty... in the code itself.<br />
<br />
<br />
<br />
<span style="font-size: medium;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">FAQ</span></span><br />
The original code which this was based had no set-up for video playback, no pointing to any hwnd  supported objects.  This was one of the main additions I included<br />
<br />
<br />
<br />
<span style="font-size: medium;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Credits and Thanks</span></span><br />
Thanks to Mark Thesing who wrote the base code in 2002<br />
<br />
<br />
<br />
<span style="font-size: medium;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Terms and Conditions</span></span><br />
Use as you see fit.  No requirements other than due credit for both Mr. Thesing and myself.]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[Audio Module]]></title>
			<link>https://www.save-point.org/thread-8457.html</link>
			<pubDate>Sun, 23 Jan 2022 13:47:46 +0000</pubDate>
			<dc:creator><![CDATA[<a href="https://www.save-point.org/member.php?action=profile&uid=99">Kain Nobel</a>]]></dc:creator>
			<guid isPermaLink="false">https://www.save-point.org/thread-8457.html</guid>
			<description><![CDATA[<span style="font-weight: bold;" class="mycode_b"><span style="font-size: xx-large;" class="mycode_size">Audio Module (C++ / SFML)</span></span><br />
<span style="font-weight: bold;" class="mycode_b"><span style="font-size: large;" class="mycode_size">Version 0.2</span></span><br />
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="text-decoration: underline;" class="mycode_u"><span style="font-size: x-large;" class="mycode_size">Description</span></span></span><br />
<br />
This is a <span style="font-weight: bold;" class="mycode_b">C++</span> rewrite of the RPG Maker <span style="font-weight: bold;" class="mycode_b">Audio</span> module implemented with <span style="font-weight: bold;" class="mycode_b">Simple and Fast Multimedia Library</span> by <span style="font-weight: bold;" class="mycode_b">Laurent Gomilla</span> and team.<br />
<br />
The end user is responsible for <span style="font-weight: bold;" class="mycode_b">compiling</span> and <span style="font-weight: bold;" class="mycode_b">deploying</span> this in their project. I may provide a plug-n-play DLL <span style="font-style: italic;" class="mycode_i">later </span>but for now its all on <span style="font-style: italic;" class="mycode_i">you </span>to figure it out.<br />
<br />
The system is written to <span style="font-weight: bold;" class="mycode_b">RGSS3</span> specifications (and should be backwards compatible with <span style="font-weight: bold;" class="mycode_b">RGSS</span> and <span style="font-weight: bold;" class="mycode_b">RGSS2</span> since all it does is <span style="font-style: italic;" class="mycode_i">add features</span> and doesn't change fundamentals.) <span style="color: #e82a1f;" class="mycode_color">I have not implemented this in <span style="font-weight: bold;" class="mycode_b">Ruby </span>or any of the <span style="font-weight: bold;" class="mycode_b">RPG Maker </span>systems. It might be awhile but I will get back to that at a later date.</span><br />
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="text-decoration: underline;" class="mycode_u"><span style="font-size: x-large;" class="mycode_size">Features</span></span></span><br />
<ul class="mycode_list"><li>Supports multiple filetypes; <span style="font-weight: bold;" class="mycode_b">wav</span>, <span style="font-weight: bold;" class="mycode_b">ogg</span>, <span style="font-weight: bold;" class="mycode_b">flac</span>, probably others.<br />
</li>
<li>Play 1 <span style="font-weight: bold;" class="mycode_b">Background Music</span><br />
</li>
<li>Play 1 <span style="font-weight: bold;" class="mycode_b">Background Sound</span><br />
</li>
<li>Play 1 <span style="font-weight: bold;" class="mycode_b">Music Effect</span><br />
</li>
<li>Play multiple <span style="font-weight: bold;" class="mycode_b">Sound Effects</span><br />
</li>
<li>Adjust fade in/fade out timing of <span style="font-weight: bold;" class="mycode_b">Music Effects</span><br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">Available Functions</span> : Play, Pause, Stop, Fade In/Out, Replay, Volume=, Pitch=<br />
</li>
<li>Please see <span style="font-weight: bold;" class="mycode_b">SFML/Audio</span> for more information.<br />
</li>
</ul>
<br />
(<span style="font-weight: bold;" class="mycode_b">NOTE:</span> Lack of <span style="font-weight: bold;" class="mycode_b">mp3</span> support is a <span style="font-style: italic;" class="mycode_i">legal issue</span>, apparently. This is outside the scope of my script and more related to <span style="font-weight: bold;" class="mycode_b">SFML</span>. End user is responsible for implementing their own <span style="font-weight: bold;" class="mycode_b">mp3</span> support, if desired. (I find <span style="font-weight: bold;" class="mycode_b">ogg</span> to be a better format, personally. <span style="font-weight: bold;" class="mycode_b">Ogg</span> BGM and BGS seem to loop <span style="font-style: italic;" class="mycode_i">better</span> than <span style="font-weight: bold;" class="mycode_b">mp3</span> so I actually <span style="font-style: italic;" class="mycode_i">encourage</span> people to switch formats.))<br />
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="text-decoration: underline;" class="mycode_u"><span style="font-size: x-large;" class="mycode_size">Requirements</span></span></span><br />
<ul class="mycode_list"><li><span style="font-weight: bold;" class="mycode_b">SFML (Simple and Fast Multimedia Library)</span><br />
</li>
<li>Should only require <span style="font-weight: bold;" class="mycode_b">SFML/Audio</span> (for audio) and <span style="font-weight: bold;" class="mycode_b">SFML/System</span> (for sf::Time functionality). See header file for more details.<br />
</li>
<li>Working knowledge of <span style="font-weight: bold;" class="mycode_b">C++</span> and the build tools required to compile and run it.<br />
</li>
</ul>
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="text-decoration: underline;" class="mycode_u"><span style="font-size: x-large;" class="mycode_size">Instructions</span></span></span><br />
<br />
<span style="color: #e82a1f;" class="mycode_color">This is <span style="font-weight: bold;" class="mycode_b">NOT</span> a plug-n-play <span style="font-weight: bold;" class="mycode_b">RPG Maker</span> <span style="font-style: italic;" class="mycode_i">script</span>, you'd need to compile it yourself with <span style="font-weight: bold;" class="mycode_b">C++</span> and configure it to your needs.</span><br />
<span style="color: #e82a1f;" class="mycode_color">While this is designed to be <span style="font-weight: bold;" class="mycode_b">RGSS compliant</span>, it has <span style="font-weight: bold;" class="mycode_b">not</span> been implemented in <span style="font-weight: bold;" class="mycode_b">Ruby/RPG Maker</span>.</span><br />
<span style="color: #e82a1f;" class="mycode_color">I'm just sharing it for anybody who can do <span style="font-style: italic;" class="mycode_i">something</span> with it.</span><br />
<span style="color: #e82a1f;" class="mycode_color">If I get the <span style="font-weight: bold;" class="mycode_b">C++</span> and <span style="font-weight: bold;" class="mycode_b">Ruby</span> to communicate, I will return with a <span style="font-style: italic;" class="mycode_i">full plug-in-play implementation</span> anyone can use.</span><br />
<br />
<div class="tborder">
  			<div class="thead" style="padding:4px; margin:1px;"><input type="button" class="button" value="+" style="font-family:Monospace; padding:0px" onclick="if (this.parentNode.parentNode.getElementsByTagName('div')[1].style.display=='none'){ this.parentNode.parentNode.getElementsByTagName('div')[1].style.display='';this.value='-';} else {this.parentNode.parentNode.getElementsByTagName('div')[1].style.display='none';this.value='+';}"/> Content Hidden</div>
  			<div class="trow2" style="display:none; padding:4px; margin:1px;"><span style="font-weight: bold;" class="mycode_b">Assuming you have a C++ build environment...</span><br />
<ul class="mycode_list"><li>Place <span style="font-weight: bold;" class="mycode_b">RGL/Audio.hpp</span> in <span style="font-weight: bold;" class="mycode_b">*/include/RGL/</span><br />
</li>
<li>Place the <span style="font-weight: bold;" class="mycode_b">RGL/Audio.cpp</span> in <span style="font-weight: bold;" class="mycode_b">*/src/RGL/</span><br />
</li>
</ul>
<br />
<span style="font-weight: bold;" class="mycode_b">(NOT INCLUDED : RGL module. This is more tailored to my personal project than anything. You can write your own module and change the "RGL" to whatever you find appropriate. I use namespace "rgl" (ie rgl::Audio) to separate it from SFML's implementation (sf::Audio). My RGL module has nothing to do with the functionality of this system other than as a directory/namespace.)</span><br />
<br />
You could probably compile yourself a nice little <span style="font-weight: bold;" class="mycode_b">libaudio.dll</span> and include it with your game project, but then you'd have to write C++/Ruby extensions. I haven't got that far nor do I know (yet) how to do all that. I'd assume you can probably do it via <span style="font-weight: bold;" class="mycode_b">Win32API</span> <span style="font-style: italic;" class="mycode_i">(or <span style="font-weight: bold;" class="mycode_b">Win32::API </span>for <span style="font-weight: bold;" class="mycode_b">Ruby &gt;= 1.9.2</span>)</span> if you're running an <span style="font-weight: bold;" class="mycode_b">RPG Maker</span> game on <span style="font-weight: bold;" class="mycode_b">Windows</span>. How it would work on other platforms? I don't have the EXP yet to know how that all works. Until then, I will only be providing <span style="font-style: italic;" class="mycode_i"><span style="color: #ff4136;" class="mycode_color">very limited support</span></span>.</div>
		</div>
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="text-decoration: underline;" class="mycode_u"><span style="font-size: x-large;" class="mycode_size">Differences from Original RGSS</span></span></span><br />
<br />
There are <span style="font-style: italic;" class="mycode_i">minor</span> differences between this and the vanilla <span style="font-weight: bold;" class="mycode_b">RGSS</span>, <span style="font-weight: bold;" class="mycode_b">RGSS2</span> and <span style="font-weight: bold;" class="mycode_b">RGSS3</span> implementations (personal taste)...<br />
<ul class="mycode_list"><li>When playing <span style="font-weight: bold;" class="mycode_b">Music Effects</span>, all other audio (BGM, BGS, SE) fade out in <span style="font-style: italic;" class="mycode_i">2 seconds</span> instead of instant.<br />
</li>
<li>When playing <span style="font-weight: bold;" class="mycode_b">Music Effects</span>, the volume of all other audio is <span style="font-style: italic;" class="mycode_i">reduced to 10 instead of 0</span>.<br />
</li>
<li>When playing <span style="font-weight: bold;" class="mycode_b">Music Effects</span>, the volume fades in approximately <span style="font-style: italic;" class="mycode_i">4 seconds</span>. Adjustable.<br />
</li>
<li>These timing features should be easily adjustable by changing the member variable values in the <span style="font-style: italic;" class="mycode_i">header</span> file.<br />
</li>
<li>NOTE: The Fade Out for music effects should be a minimum of <span style="font-weight: bold;" class="mycode_b">1.0f </span>or it won't fade out at all. Of course, you can edit the script yourself if you're trying to do, say, a half second.<br />
</li>
</ul>
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="text-decoration: underline;" class="mycode_u"><span style="font-size: x-large;" class="mycode_size">Source Files</span></span></span><br />
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="text-decoration: underline;" class="mycode_u">RGL/Audio.hpp</span></span><br />
<div class="tborder">
  			<div class="thead" style="padding:4px; margin:1px;"><input type="button" class="button" value="+" style="font-family:Monospace; padding:0px" onclick="if (this.parentNode.parentNode.getElementsByTagName('div')[1].style.display=='none'){ this.parentNode.parentNode.getElementsByTagName('div')[1].style.display='';this.value='-';} else {this.parentNode.parentNode.getElementsByTagName('div')[1].style.display='none';this.value='+';}"/> Content Hidden</div>
  			<div class="trow2" style="display:none; padding:4px; margin:1px;">
<div class="codeblock"><div class="title">Code:</div><div class="body" dir="ltr"><code>/*=============================================================================*/<br />
// ** rgl::Audio<br />
/*-----------------------------------------------------------------------------*/<br />
// Public Members<br />
// ==============<br />
// sf::Music &nbsp;&nbsp;&nbsp;&nbsp;m_BGM<br />
// sf::Music &nbsp;&nbsp;&nbsp;&nbsp;m_BGS<br />
// sf::Sound&nbsp;&nbsp;&nbsp;&nbsp;m_ME<br />
// sf::Vector   m_VectorSE<br />
//<br />
// Public Functions<br />
// ================<br />
// Audio.playBGM()<br />
// Audio.playBGM(name)<br />
// Audio.playBGM(name, volume, pitch)<br />
// Audio.replayBGM()<br />
// Audio.pauseBGM()<br />
// Audio.stopBGM()<br />
// Audio.playBGS()<br />
// Audio.playBGS(name)<br />
// Audio.playBGS(name, volume, pitch)<br />
// Audio.replayBGS()<br />
// Audio.pauseBGS()<br />
// Audio.stopBGS()<br />
// Audio.playME()<br />
// Audio.playME(name)<br />
// Audio.playME(name, volume, pitch)<br />
// Audio.replayME()<br />
// Audio.pauseME()<br />
// Audio.stopME()<br />
// Audio.playSE()<br />
// Audio.playSE(name)<br />
// Audio.playSE(name, volume, pitch)<br />
// Audio.replaySE()<br />
// Audio.pauseSE()<br />
// Audio.stopSE()<br />
// Audio.update()<br />
//<br />
// Private Members<br />
// ===============<br />
// bool &nbsp;&nbsp;&nbsp;&nbsp;m_waitME<br />
/*=============================================================================*/<br />
<br />
#ifndef RGL_AUDIO_H<br />
#define RGL_AUDIO_H<br />
<br />
#include &lt;RGL.hpp&gt;<br />
#include &lt;RGL/Audio.hpp&gt;<br />
#include &lt;RGL/AudioFile.hpp&gt;<br />
#include &lt;SFML/Audio.hpp&gt;<br />
#include &lt;SFML/Audio/Sound.hpp&gt;<br />
#include &lt;SFML/Audio/SoundBuffer.hpp&gt;<br />
#include &lt;SFML/System/Time.hpp&gt;<br />
#include &lt;deque&gt;<br />
#include &lt;stdlib.h&gt;<br />
#include &lt;iostream&gt;<br />
#include &lt;istream&gt;<br />
<br />
/*============================================================================*/<br />
// ** rgl<br />
/*============================================================================*/<br />
<br />
namespace rgl {<br />
<br />
static const int NUM_OF_SE = 16;<br />
//template&lt;typename S&gt; sf::Sound;<br />
//template&lt;typename B&gt; sf::SoundBuffer;<br />
class Audio {<br />
    public:<br />
        // Construct and Destruct<br />
        Audio();<br />
        virtual ~Audio();<br />
        // Public Members<br />
        bool m_OutOfFocus = false;<br />
        // Public Functions : BGM<br />
        bool playBGM(const sf::String&amp; l_name, float volume, float pitch);<br />
        bool playBGM(const sf::String&amp; l_name);<br />
        bool playBGM();<br />
        bool replayBGM();<br />
        void pauseBGM();<br />
        void stopBGM();<br />
        void fadeBGM(float volume, float duration);<br />
        // Public Functions : BGS<br />
        bool playBGS(const sf::String&amp; l_name, float volume, float pitch);<br />
        bool playBGS(const sf::String&amp; l_name);<br />
        bool playBGS();<br />
        bool replayBGS();<br />
        void pauseBGS();<br />
        void stopBGS();<br />
        void fadeBGS(float volume, float duration);<br />
        // Public Functions : ME<br />
        bool playME(const sf::String&amp; l_name, float volume, float pitch);<br />
        bool playME(const sf::String&amp; l_name);<br />
        bool playME();<br />
        bool replayME();<br />
        void pauseME();<br />
        void stopME();<br />
        void fadeME(float volume, float duration);<br />
        // Public Functions : SE<br />
        bool playSE(const sf::String&amp; l_name, float volume, float pitch);<br />
        bool playSE(const sf::String&amp; l_name);<br />
        bool playSE();<br />
        bool replaySE();<br />
        void pauseSE();<br />
        void stopSE();<br />
        void fadeSE(float volume, float duration);<br />
        // Public Functions : Update<br />
        void update();<br />
        void reset();<br />
        void fadeAll(float volume, float duration);<br />
    protected:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// ...<br />
    private:<br />
        // Private Member Constants<br />
        const float m_MEFadeOutT = 2.0f;<br />
        const float m_MEFadeInT  = 4.0f;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Private Member Variables<br />
        sf::Music m_BGM;        // Background Music<br />
        sf::Music m_BGS;        // Background Sound<br />
        sf::Music m_ME;         // Music Effect<br />
        sf::Sound m_SE;         // Sound Effect<br />
        std::deque&lt;sf::Sound&gt; m_SoundV;<br />
        std::deque&lt;sf::SoundBuffer&gt; m_BufferV;<br />
        int       m_phaseME = 0;// Music Effect phase (0 None, 1 Fade in, 2 Play, 3 Fade Out)<br />
        sf::Clock m_timeME;     // Music effect clock<br />
        sf::Clock m_timeSE;     // Sound effect clock<br />
        sf::Time  m_timeSEMax = sf::seconds(3.0);<br />
        float     m_BGMFadeV    = 0.0; // BGM Fade Volume<br />
        float     m_BGSFadeV    = 0.0; // BGS Fade Volume<br />
        float     m_MEFadeV     = 0.0; // ME Fade Volume<br />
        float     m_SEFadeV     = 0.0; // SE Fade Volume<br />
        float     m_BGMFadeD    = 0.0f; // BGM Fade Duration<br />
        float     m_BGSFadeD    = 0.0f; // BGS Fade Duration<br />
        float     m_MEFadeD     = 0.0f; // ME Fade Duration<br />
        float     m_SEFadeD     = 0.0f; // SE Fade Duration<br />
        float     m_BGMLastV    = 0.0;// BGM Last Volume<br />
        float     m_BGSLastV    = 0.0;// BGS Last Volume<br />
        //float     m_MELastV     = 0.0;// ME Last Volume (Not used/needed)<br />
        float     m_SELastV     = 0.0;// ME Last Volume<br />
        // Private Functions<br />
        void updateBGM();<br />
        void updateBGS();<br />
        void updateME();<br />
        void updateSE();<br />
        void updateSE(int i);<br />
        void updateBuffers();<br />
        void updateMusicEffect();<br />
        // ...Need to add limited vector for sound queue<br />
};<br />
<br />
}<br />
#endif //RGL_AUDIO_H</code></div></div></div>
		</div>
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="text-decoration: underline;" class="mycode_u">RGL/Audio.cpp</span></span><br />
<div class="tborder">
  			<div class="thead" style="padding:4px; margin:1px;"><input type="button" class="button" value="+" style="font-family:Monospace; padding:0px" onclick="if (this.parentNode.parentNode.getElementsByTagName('div')[1].style.display=='none'){ this.parentNode.parentNode.getElementsByTagName('div')[1].style.display='';this.value='-';} else {this.parentNode.parentNode.getElementsByTagName('div')[1].style.display='none';this.value='+';}"/> Content Hidden</div>
  			<div class="trow2" style="display:none; padding:4px; margin:1px;">
<div class="codeblock"><div class="title">Code:</div><div class="body" dir="ltr"><code>/*=============================================================================*/<br />
// ** rgl::Audio<br />
/*-----------------------------------------------------------------------------*/<br />
// Public Members<br />
// ==============<br />
// sf::Music &nbsp;&nbsp;&nbsp;&nbsp;m_BGM<br />
// sf::Music &nbsp;&nbsp;&nbsp;&nbsp;m_BGS<br />
// sf::Sound&nbsp;&nbsp;&nbsp;&nbsp;m_ME<br />
// sf::Vector   m_VectorSE<br />
//<br />
// Public Functions<br />
// ================<br />
// Audio.playBGM()<br />
// Audio.playBGM(name)<br />
// Audio.playBGM(name, volume, pitch)<br />
// Audio.pauseBGM()<br />
// Audio.stopBGM()<br />
// Audio.fadeBGM(volume, duration)<br />
// Audio.playBGS()<br />
// Audio.playBGS(name)<br />
// Audio.playBGS(name, volume, pitch)<br />
// Audio.pauseBGS()<br />
// Audio.stopBGS()<br />
// Audio.fadeBGS(volume, duration)<br />
// Audio.playME()<br />
// Audio.playME(name)<br />
// Audio.playME(name, volume, pitch)<br />
// Audio.pauseME()<br />
// Audio.stopME()<br />
// Audio.fadeME(volume, duration)<br />
// Audio.playSE()<br />
// Audio.playSE(name)<br />
// Audio.playSE(name, volume, pitch)<br />
// Audio.fadeSE(volume, duration)<br />
// Audio.pauseSE()<br />
// Audio.stopSE()<br />
// Audio.fadeSE(volume, duration)<br />
// Audio.reset()<br />
// Audio.fadeAll(duration)<br />
// Audio.update()<br />
//<br />
// Private Members<br />
// ===============<br />
// bool &nbsp;&nbsp;&nbsp;&nbsp;m_waitME<br />
// float&nbsp;&nbsp;&nbsp;&nbsp;m_bgmVolB4ME<br />
// float &nbsp;&nbsp;&nbsp;&nbsp;m_bgsVolB4ME<br />
// float &nbsp;&nbsp;&nbsp;&nbsp;m_bgmFade<br />
// float &nbsp;&nbsp;&nbsp;&nbsp;m_bgsFade<br />
/*=============================================================================*/<br />
<br />
#include &lt;SFML/Audio.hpp&gt;<br />
#include &lt;SFML/System/Time.hpp&gt;<br />
#include &lt;RGL.hpp&gt;<br />
#include &lt;RGL/Audio.hpp&gt;<br />
#include &lt;istream&gt;<br />
<br />
//#include &lt;RGL/AudioFile.hpp&gt;<br />
<br />
/*============================================================================*/<br />
// ** rgl<br />
/*============================================================================*/<br />
namespace rgl {<br />
<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio() [Constructor]<br />
/*----------------------------------------------------------------------------*/<br />
Audio::Audio() {}<br />
/*----------------------------------------------------------------------------*/<br />
// ** ~Audio() [Destructor]<br />
/*----------------------------------------------------------------------------*/<br />
Audio::~Audio() {}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.playBGM(name, volume, pitch)<br />
/*----------------------------------------------------------------------------*/<br />
bool Audio::playBGM(const sf::String&amp; l_name, float volume, float pitch) {<br />
    // If name is empty<br />
    if (l_name.isEmpty()) {<br />
        // Stop the BGM<br />
        m_BGM.stop();<br />
        // Nothing wrong with stopping the BGM<br />
        return true;<br />
    }<br />
    // If unable to open from file<br />
    if (!m_BGM.openFromFile(l_name)) {<br />
        // Error opening file<br />
        return false;<br />
    }<br />
    // Set volume, pitch and loop<br />
    m_BGM.setVolume(volume);<br />
    m_BGM.setPitch(pitch);<br />
    m_BGM.setLoop(true);<br />
    // Play the BGM<br />
    m_BGM.play();<br />
    // Opened file successfully<br />
    return true;<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.playBGM(name)<br />
/*----------------------------------------------------------------------------*/<br />
bool Audio::playBGM(const sf::String&amp; l_name) {<br />
    // Play BGM by name<br />
    return playBGM(l_name, 80.0, 1.0);<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.playBGM()<br />
/*----------------------------------------------------------------------------*/<br />
bool Audio::playBGM() {<br />
    // Ensure BGM loops<br />
    m_BGM.setLoop(true);<br />
    // Play BGM without any arguments<br />
    m_BGM.play();<br />
    // Return true<br />
    return true;<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.replayBGM()<br />
/*----------------------------------------------------------------------------*/<br />
bool Audio::replayBGM() {<br />
    m_BGM.stop();<br />
    m_BGM.play();<br />
    // Return true<br />
    return true;<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.pauseBGM()<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::pauseBGM() {<br />
    // Pause BGM<br />
    m_BGM.pause();<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.fadeBGM(volume, duration, memorize = false)<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::fadeBGM(float volume, float duration) {<br />
    // Set BGM fade volume and duration<br />
    m_BGMFadeV = volume;<br />
    m_BGMFadeD = sf::seconds(duration).asSeconds();<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.stopBGM()<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::stopBGM() {<br />
    // Stop BGM<br />
    m_BGM.stop();<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.playBGS(name, volume, pitch)<br />
/*----------------------------------------------------------------------------*/<br />
bool Audio::playBGS(const sf::String&amp; l_name, float volume, float pitch) {<br />
    // If name is empty<br />
    if (l_name.isEmpty()) {<br />
        // Stop the BGS<br />
        m_BGS.stop();<br />
        // Nothing wrong with stopping the BGS<br />
        return true;<br />
    }<br />
    // If unable to open from file<br />
    if (!m_BGS.openFromFile(l_name)) {<br />
        // Error opening file<br />
        return false;<br />
    }<br />
    // Set volume, pitch and loop<br />
    m_BGS.setVolume(volume);<br />
    m_BGS.setPitch(pitch);<br />
    m_BGS.setLoop(true);<br />
    // Play the BGS<br />
    m_BGS.play();<br />
    // Opened file successfully<br />
    return true;<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.playBGS(name)<br />
/*----------------------------------------------------------------------------*/<br />
bool Audio::playBGS(const sf::String&amp; l_name) {<br />
    // Play BGS by name<br />
    return playBGS(l_name, 80.0, 1.0);<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.playBGS()<br />
/*----------------------------------------------------------------------------*/<br />
bool Audio::playBGS() {<br />
    // Ensure BGS loops<br />
    m_BGS.setLoop(true);<br />
    // Play BGS without any arguments<br />
    m_BGS.play();<br />
    // Return true<br />
    return true;<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.replayBGS()<br />
/*----------------------------------------------------------------------------*/<br />
bool Audio::replayBGS() {<br />
    // Restart BGS<br />
    m_BGS.stop();<br />
    m_BGS.play();<br />
    // Return true<br />
    return true;<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.pauseBGS()<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::pauseBGS() {<br />
    // Pause BGS<br />
    m_BGS.pause();<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.stopBGS()<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::stopBGS() {<br />
    // Stop BGS<br />
    m_BGS.stop();<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.fadeBGS(volume, duration, memorize = false)<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::fadeBGS(float volume, float duration) {<br />
    // Set BGS fade volume and duration<br />
    m_BGSFadeV = volume;<br />
    m_BGSFadeD = duration;<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.playME(name, volume, pitch)<br />
/*----------------------------------------------------------------------------*/<br />
bool Audio::playME(const sf::String&amp; l_name, float volume, float pitch) {<br />
    // If name is empty<br />
    if (l_name.isEmpty()) {<br />
        // Ensure phase is 0<br />
        m_phaseME = 0;<br />
        // Stop the ME<br />
        m_ME.stop();<br />
        // Nothing wrong with stopping the ME<br />
        return true;<br />
    }<br />
    // If unable to open from file<br />
    if (!m_ME.openFromFile(l_name)) {<br />
        // Print to console<br />
        cout &lt;&lt; "Error loading file" &lt;&lt; endl;;<br />
        // Error opening file<br />
        return false;<br />
    }<br />
    // Set phase to 1<br />
    m_phaseME = 1;<br />
    // Set volume, pitch and loop<br />
    m_ME.setVolume(volume);<br />
    m_ME.setPitch(pitch);<br />
    m_ME.setLoop(false);<br />
    // Play the ME<br />
    m_ME.play();<br />
    // Opened file successfully<br />
    return true;<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.playME(name)<br />
/*----------------------------------------------------------------------------*/<br />
bool Audio::playME(const sf::String&amp; l_name) {<br />
    // Play ME by name<br />
    return playME(l_name, 80.0, 1.0);<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.playME()<br />
/*----------------------------------------------------------------------------*/<br />
bool Audio::playME() {<br />
    // Ensure ME does not loop<br />
    m_ME.setLoop(false);<br />
    // Play ME without any arguments<br />
    m_ME.play();<br />
    // Return true<br />
    return true;<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.replayME()<br />
/*----------------------------------------------------------------------------*/<br />
bool Audio::replayME() {<br />
    // Restart ME<br />
    m_ME.stop();<br />
    m_ME.play();<br />
    // Return true<br />
    return true;<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.pauseME()<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::pauseME() {<br />
    // Pause ME<br />
    m_ME.pause();<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.stopME()<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::stopME() {<br />
    // Stop ME<br />
    m_ME.stop();<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.fadeME(volume, duration, memorize = false)<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::fadeME(float volume, float duration) {<br />
    // Set ME fade volume and duration<br />
    m_MEFadeV = volume;<br />
    m_MEFadeD = duration;<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.playSE(name, volume, pitch)<br />
/*----------------------------------------------------------------------------*/<br />
bool Audio::playSE(const sf::String&amp; l_name, float volume, float pitch) {<br />
    // End function doing nothing if no name given<br />
    if (l_name.isEmpty()) { return true; }<br />
    // Create sound and sound buffer<br />
    sf::Sound sound;<br />
    sf::SoundBuffer buffer;<br />
    // If unable to open from file<br />
    if (!buffer.loadFromFile(l_name)) {<br />
        // Print to console<br />
        cout &lt;&lt; "Unable to load Sound Effect" &lt;&lt; endl;<br />
        // Error opening file<br />
        return false;<br />
    }<br />
    // Set volume, pitch and loop<br />
    sound.setVolume(volume);<br />
    sound.setPitch(pitch);<br />
    sound.setLoop(false);<br />
    // If sound duration is more than current max time<br />
    if (buffer.getDuration() &gt; m_timeSEMax) {<br />
        // Restart timer and set time max duration<br />
        m_timeSE.restart();<br />
        m_timeSEMax = (buffer.getDuration());<br />
        m_timeSEMax += (buffer.getDuration());<br />
    }<br />
    // Add to vectors<br />
    m_SoundV.push_back(sound);<br />
    m_BufferV.push_back(buffer);<br />
    // Set the last buffer on the stack<br />
    m_SoundV[m_SoundV.size() - 1].setBuffer(m_BufferV[m_BufferV.size() - 1]);<br />
    // Play the sound<br />
    m_SoundV[m_SoundV.size() - 1].play();<br />
    cout &lt;&lt; "Playing SE : " &lt;&lt; m_SoundV.size() &lt;&lt; endl;<br />
    // Opened file successfully<br />
    return true;<br />
}<br />
<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.playSE(name)<br />
/*----------------------------------------------------------------------------*/<br />
bool Audio::playSE(const sf::String&amp; l_name) {<br />
    // Play SE by name<br />
    return playSE(l_name, 80.0, 1.0);<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.playSE()<br />
/*----------------------------------------------------------------------------*/<br />
bool Audio::playSE() {<br />
    // Ensure SE does not loop<br />
    m_SE.setLoop(false);<br />
    // Play SE without any arguments<br />
    m_SE.play();<br />
    // Return true<br />
    return true;<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.replaySE()<br />
/*----------------------------------------------------------------------------*/<br />
bool Audio::replaySE() {<br />
    // Restart SE<br />
    m_SE.stop();<br />
    m_SE.play();<br />
    // Return true<br />
    return true;<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.pauseSE()<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::pauseSE() {<br />
    // Pause SE<br />
    m_SE.pause();<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.stopSE()<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::stopSE() {<br />
    // Stop SE<br />
    m_SE.stop();<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.fadeSE(volume, duration, memorize = false)<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::fadeSE(float volume, float duration) {<br />
    // Set SE fade volume and duration<br />
    m_SEFadeV = volume;<br />
    m_SEFadeD = duration;<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.reset()<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::reset() {<br />
    m_BGM.stop();<br />
    m_BGS.stop();<br />
    m_ME.stop();<br />
    m_SE.stop();<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.fadeAll(duration)<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::fadeAll(float volume, float duration) {<br />
    fadeBGM(volume, duration);<br />
    fadeBGS(volume, duration);<br />
    fadeME(volume, duration);<br />
    fadeSE(volume, duration);<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.update()<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::update() {<br />
    // End method unless a second has passed<br />
    if (m_timeME.getElapsedTime() &lt; sf::seconds(0.1f)) { return; }<br />
    // Update audio<br />
    updateBGM();<br />
    updateBGS();<br />
    updateME();<br />
    updateSE();<br />
    // Update buffers<br />
    updateBuffers();<br />
    // Restart tick<br />
    m_timeME.restart();<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.updateBGM()<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::updateBGM() {<br />
    // End method if no music is playing<br />
    if (m_BGM.getStatus() == sf::Music::Stopped) { return;}<br />
    // End method if not fading<br />
    if (m_BGMFadeD &lt;= 0.0) { return; }<br />
    // Decrease wait duration<br />
    m_BGMFadeD -= 0.1f;<br />
    // If duration is 0<br />
    if (m_BGMFadeD &lt;= 0.0) {<br />
        // Reset fade to 0<br />
        m_BGMFadeV = m_BGMFadeD = 0.0;<br />
        // End function<br />
        return;<br />
    }<br />
    // If fade volume is more than ME volume<br />
    if (m_BGMFadeV &gt; m_BGM.getVolume()) {<br />
        // Get volume increment<br />
        float vol = (abs(m_BGMFadeV - m_BGM.getVolume()) / m_BGMFadeD);<br />
        // Increase volume<br />
        m_BGM.setVolume(m_BGM.getVolume() + vol);<br />
    // If fade volume is less than ME volume<br />
    } else if (m_BGMFadeV &lt; m_BGM.getVolume()) {<br />
        // Get volume increment<br />
        float vol = (abs(m_BGM.getVolume() - m_BGMFadeV) / m_BGMFadeD);<br />
        // Decrease volume<br />
        m_BGM.setVolume(m_BGM.getVolume() - vol);<br />
    } else if (m_BGMFadeD &lt;= 0.0) {<br />
        // Reset fade to 0<br />
        m_BGMFadeV = m_BGMFadeD = 0.0;<br />
        // End function<br />
        return;<br />
    }<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.updateBGS()<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::updateBGS() {<br />
    // End method if no music is playing<br />
    if (m_BGS.getStatus() == sf::Music::Stopped) { return;}<br />
    // End method if not fading<br />
    if (m_BGSFadeD &lt;= 0.0) { return; }<br />
    // Decrease wait duration<br />
    m_BGSFadeD -= 0.1f;<br />
    // If duration is 0<br />
    if (m_BGSFadeD &lt;= 0.0) {<br />
        // Reset fade to 0<br />
        m_BGSFadeV = m_BGSFadeD = 0.0;<br />
        // End function<br />
        return;<br />
    }<br />
    // If fade volume is more than ME volume<br />
    if (m_BGSFadeV &gt; m_BGS.getVolume()) {<br />
        // Get volume increment<br />
        float vol = (abs(m_BGSFadeV - m_BGS.getVolume()) / m_BGSFadeD);<br />
        // Increase volume<br />
        m_BGS.setVolume(m_BGS.getVolume() + vol);<br />
    // If fade volume is less than ME volume<br />
    } else if (m_BGSFadeV &lt; m_BGS.getVolume()) {<br />
        // Get volume increment<br />
        float vol = (abs(m_BGS.getVolume() - m_BGSFadeV) / m_BGSFadeD);<br />
        // Decrease volume<br />
        m_BGS.setVolume(m_BGS.getVolume() - vol);<br />
    } else if (m_BGSFadeD &lt;= 0.0) {<br />
        // Reset fade to 0<br />
        m_BGSFadeV = m_BGSFadeD = 0.0;<br />
        // End function<br />
        return;<br />
    }<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.updateME()<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::updateME() {<br />
    // End method if no music is playing<br />
    if (m_ME.getStatus() == sf::Music::Stopped) { return;}<br />
    // Do internal music effect update<br />
    updateMusicEffect();<br />
    //if (m_MEFadeD &lt;= 0.0) { return; }<br />
    // Decrease wait duration<br />
    m_MEFadeD -= 0.1f;<br />
    // If duration is 0<br />
    if (m_MEFadeD &lt;= 0.0) {<br />
        // Reset fade to 0<br />
        m_MEFadeV = m_MEFadeD = 0.0;<br />
        // End function<br />
        return;<br />
    }<br />
    // If fade volume is more than ME volume<br />
    if (m_MEFadeV &gt; m_ME.getVolume()) {<br />
        // Get volume increment<br />
        float vol = (abs(m_MEFadeV - m_ME.getVolume()) / m_MEFadeD);<br />
        // Increase volume<br />
        m_ME.setVolume(m_ME.getVolume() + vol);<br />
    // If fade volume is less than ME volume<br />
    } else if (m_MEFadeV &lt; m_ME.getVolume()) {<br />
        // Get volume increment<br />
        float vol = (abs(m_ME.getVolume() - m_MEFadeV) / m_MEFadeD);<br />
        // Decrease volume<br />
        m_ME.setVolume(m_ME.getVolume() - vol);<br />
    } else if (m_MEFadeD &lt;= 0.0) {<br />
        // Reset fade to 0<br />
        m_MEFadeV = m_MEFadeD = 0.0;<br />
        // End function<br />
        return;<br />
    }<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.updateMusicEffect()<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::updateMusicEffect() {<br />
    // Get current and total duration<br />
    float sec = m_ME.getPlayingOffset().asSeconds();<br />
    float all = m_ME.getDuration().asSeconds();<br />
    // If phase 1 : Fade Out<br />
    if (m_phaseME == 1 &amp;&amp; sec &lt; 1.0) {<br />
        // Memorize volumes<br />
        m_BGMLastV = m_BGM.getVolume();<br />
        m_BGSLastV = m_BGS.getVolume();<br />
        m_SELastV = ((m_SoundV.size() &gt; 0) ? m_SoundV[0].getVolume() : 80.0 );<br />
        // Trigger a rolling fade out of audio assets<br />
        fadeBGM(10.0, m_MEFadeOutT);<br />
        fadeBGS(10.0, m_MEFadeOutT);<br />
        fadeSE(10.0, m_MEFadeOutT);<br />
        // Set next phase : play the body of the music effect<br />
        m_phaseME = 2;<br />
        // End function<br />
        return;<br />
    // If phase 2 : Play Body<br />
    } else if (m_phaseME == 2 &amp;&amp;<br />
    (sec &gt; 1.0 &amp;&amp; sec &lt; (all * 0.9))) {<br />
        // Set next phase : fade back in<br />
        m_phaseME = 3;<br />
        // End function<br />
        return;<br />
    // If phase 3 : Fade In<br />
    } else if (m_phaseME == 3 &amp;&amp; sec &gt; (all * 0.9)) {<br />
        // Trigger a rolling fade in of audio assets<br />
        fadeBGM(m_BGMLastV, m_MEFadeInT);<br />
        fadeBGS(m_BGSLastV, m_MEFadeInT);<br />
        fadeSE(m_SELastV, m_MEFadeInT);<br />
        // Set next phase : DONE<br />
        m_phaseME = 0;<br />
        // End function<br />
        return;<br />
    }<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.updateSE()<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::updateSE() {<br />
    // Update each sound<br />
    for(unsigned int i = 0; i &lt; m_SoundV.size() ; i++){ updateSE(i);}<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.updateSE()<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::updateSE(int i) {<br />
    // End method if no music is playing<br />
    if (m_SoundV[i].getStatus() == sf::Sound::Stopped) {<br />
        // Erase sound at iterator position<br />
        m_SoundV.erase(m_SoundV.begin()+i);<br />
        // Print to console<br />
        return;<br />
    }<br />
    // End method if not fading<br />
    if (m_SEFadeD &lt;= 0.0) { return; }<br />
    // Decrease wait duration<br />
    m_SEFadeD -= 0.1f;<br />
    // If duration is 0<br />
    if (m_SEFadeD &lt;= 0.0) {<br />
        // Reset fade to 0<br />
        m_SEFadeV = m_SEFadeD = 0.0;<br />
        // End function<br />
        return;<br />
    }<br />
    // If fade volume is more than SE volume<br />
    if (m_SEFadeV &gt; m_SoundV[i].getVolume()) {<br />
        // Get volume increment<br />
        float vol = (abs(m_SEFadeV - m_SoundV[i].getVolume()) / m_SEFadeD);<br />
        // Increase volume<br />
        m_SoundV[i].setVolume(m_SoundV[i].getVolume() + vol);<br />
    // If fade volume is less than SE volume<br />
    } else if (m_SEFadeV &lt; m_SoundV[i].getVolume()) {<br />
        // Get volume increment<br />
        float vol = (abs(m_SoundV[i].getVolume() - m_SEFadeV) / m_SEFadeD);<br />
        // Decrease volume<br />
        m_SoundV[i].setVolume(m_SoundV[i].getVolume() - vol);<br />
    // If fade duration is less than or equal to 0 seconds<br />
    } else if (m_SEFadeD &lt;= 0.0) {<br />
        // Reset fade and volume to 0<br />
        m_SEFadeV = m_SEFadeD = 0.0;<br />
        // End function<br />
        return;<br />
    }<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.updateBuffers();<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::updateBuffers() {<br />
    // End function if no buffers<br />
    if (m_BufferV.empty()) { return; }<br />
    // Clear buffers if enough time has passed by<br />
    if (m_timeSE.getElapsedTime() &gt;= m_timeSEMax) {<br />
        // Clear buffers and restart timer<br />
        m_BufferV.clear();<br />
        m_timeSE.restart();<br />
    }<br />
}<br />
} // End of rgl::Audio</code></div></div></div>
		</div>
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="text-decoration: underline;" class="mycode_u"><span style="font-size: x-large;" class="mycode_size">Author's Notes</span></span></span><br />
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="text-decoration: underline;" class="mycode_u">Notes : Classes and Memory</span></span><br />
<br />
<div class="tborder">
  			<div class="thead" style="padding:4px; margin:1px;"><input type="button" class="button" value="+" style="font-family:Monospace; padding:0px" onclick="if (this.parentNode.parentNode.getElementsByTagName('div')[1].style.display=='none'){ this.parentNode.parentNode.getElementsByTagName('div')[1].style.display='';this.value='-';} else {this.parentNode.parentNode.getElementsByTagName('div')[1].style.display='none';this.value='+';}"/> Content Hidden</div>
  			<div class="trow2" style="display:none; padding:4px; margin:1px;">Since it was built to RGSS standards, the system uses <span style="font-weight: bold;" class="mycode_b">2x sf::Music (1 BGM, 1 BGS)</span> and <span style="font-weight: bold;" class="mycode_b">1x sf::Sound (1 ME).</span> Plus <span style="font-weight: bold;" class="mycode_b">2x sf::Clocks</span> for internal timing. These are always loaded in memory so long as the <span style="font-weight: bold;" class="mycode_b">rgl::Audio</span> class exists in your project.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Sound Effects (SE)</span> use <span style="font-weight: bold;" class="mycode_b">sf::Sound</span> and <span style="font-weight: bold;" class="mycode_b">sf::SoundBuffers </span>which are dynamically created and destroyed within an <span style="font-weight: bold;" class="mycode_b">std::deque</span> class. The sound buffers are automatically cleared after the maximum <span style="font-weight: bold;" class="mycode_b">(sound.getDuration() * 2)</span>. The length of the latest, and longest, sound effect is doubled and then the buffers are cleared after that if <span style="font-weight: bold;" class="mycode_b">Audio.play_se</span> hasn't been called again.<br />
<br />
A better memory protocol could probably be implemented in the future but it is important that, by hook or by crook, sounds and buffers are removed when not in use because they <span style="font-style: italic;" class="mycode_i">take up memory.</span><br />
If you shorten the duration, some sound effects may not play all the way though. I double it to give the sounds room to run (it takes the time of the longest sound and doubles it.)<br />
Lengthening the duration of time between a buffer creation and destruction probably wouldn't hurt, as buffers are meant to be reused. I keep my buffers on a short leash.</div>
		</div>
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="text-decoration: underline;" class="mycode_u">Notes : What Could Be Improved?</span></span><br />
<br />
<div class="tborder">
  			<div class="thead" style="padding:4px; margin:1px;"><input type="button" class="button" value="+" style="font-family:Monospace; padding:0px" onclick="if (this.parentNode.parentNode.getElementsByTagName('div')[1].style.display=='none'){ this.parentNode.parentNode.getElementsByTagName('div')[1].style.display='';this.value='-';} else {this.parentNode.parentNode.getElementsByTagName('div')[1].style.display='none';this.value='+';}"/> Content Hidden</div>
  			<div class="trow2" style="display:none; padding:4px; margin:1px;">This is an early implementation so I'm sure it's not <span style="font-style: italic;" class="mycode_i">perfect</span>. I'm not a master C++ wizard so I'm still learning.<br />
<br />
First thing that could be improved is applying DRY <span style="font-style: italic;" class="mycode_i">(Don't Repeat Yourself)</span> and standardizing the functionality. I'll probably write a new version using <span style="font-weight: bold;" class="mycode_b"><span style="color: #419dc1;" class="mycode_color">templates</span></span> or <span style="font-weight: bold;" class="mycode_b"><span style="color: #419dc1;" class="mycode_color">typedef</span></span> calls in the future because I can't stand redundant repetition but, for now, it should work fine <span style="font-style: italic;" class="mycode_i">I think</span>.<br />
<br />
There is not support for multiple BGM/BGS. I tried to keep it as close to original RGSS* specification as possible but I may add that support in the future. You'd have to change the single member variables to <span style="font-weight: bold;" class="mycode_b">std::vector</span> or <span style="font-weight: bold;" class="mycode_b">std::list</span> or some other C++ container style. I would like to add that but it's not exactly high on my priority list at the moment.<br />
<br />
For anybody aiming for cross-platform compatibility I would avoid using Win32API / Win32::API and do a direct C++/Ruby FFI (Foreign Function Interface). I don't know how to set these things up <span style="font-style: italic;" class="mycode_i">yet </span>but that's probably going to be the next step...<br />
<br />
(NOTE: You can probably do it with RbInline or RICE or some other system. I'm still studying this stuff so I won't pretend to know the details - YET.)</div>
		</div>
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="text-decoration: underline;" class="mycode_u">Notes : About (lack of) rbSFML Bindings</span></span><br />
<br />
I am well aware that there is a <span style="font-weight: bold;" class="mycode_b">SFML</span> bindings for <span style="font-weight: bold;" class="mycode_b">Ruby (rbSFML)</span>. It doesn't look like it has been updated in 6 years and I don't know if anybody still uses or supports it, nor do I know how stable it is. The SFML forum doesn't have a sub-forum for it in their bindings so I can only assume rbSFML may not be a stable library? I made the personal choice to do this without rbSFML. I would like to learn for myself how to extend Ruby with C++ so it was a personal choice to do it in C++.<br />
<br />
<span style="color: #17b529;" class="mycode_color"><span style="font-size: large;" class="mycode_size">Thank you for checking it out, feel free to lend me a hand if you know anything about this stuff.</span></span><br />
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="text-decoration: underline;" class="mycode_u">Terms and Conditions</span></span><br />
<br />
End user is responsible for figuring out how to compile and use this <span style="font-style: italic;" class="mycode_i">themselves</span>. I will only be providing <span style="color: #e82a1f;" class="mycode_color">limited support</span> and future updates.<br />
Free to use in <span style="font-weight: bold;" class="mycode_b">commercial</span> and <span style="font-weight: bold;" class="mycode_b">non-commercial projects</span>, you don't even have to credit me (but I do like <span style="font-weight: bold;" class="mycode_b">credits</span> -_^).<br />
<span style="font-weight: bold;" class="mycode_b">SFML</span> has its own terms under the <span style="font-weight: bold;" class="mycode_b">ZLIB/PNG License</span>. <span style="font-weight: bold;" class="mycode_b">SFML</span> is an open source multimedia library written by <span style="font-weight: bold;" class="mycode_b">Laurent Gomilla</span> and a team of programming ninjas.]]></description>
			<content:encoded><![CDATA[<span style="font-weight: bold;" class="mycode_b"><span style="font-size: xx-large;" class="mycode_size">Audio Module (C++ / SFML)</span></span><br />
<span style="font-weight: bold;" class="mycode_b"><span style="font-size: large;" class="mycode_size">Version 0.2</span></span><br />
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="text-decoration: underline;" class="mycode_u"><span style="font-size: x-large;" class="mycode_size">Description</span></span></span><br />
<br />
This is a <span style="font-weight: bold;" class="mycode_b">C++</span> rewrite of the RPG Maker <span style="font-weight: bold;" class="mycode_b">Audio</span> module implemented with <span style="font-weight: bold;" class="mycode_b">Simple and Fast Multimedia Library</span> by <span style="font-weight: bold;" class="mycode_b">Laurent Gomilla</span> and team.<br />
<br />
The end user is responsible for <span style="font-weight: bold;" class="mycode_b">compiling</span> and <span style="font-weight: bold;" class="mycode_b">deploying</span> this in their project. I may provide a plug-n-play DLL <span style="font-style: italic;" class="mycode_i">later </span>but for now its all on <span style="font-style: italic;" class="mycode_i">you </span>to figure it out.<br />
<br />
The system is written to <span style="font-weight: bold;" class="mycode_b">RGSS3</span> specifications (and should be backwards compatible with <span style="font-weight: bold;" class="mycode_b">RGSS</span> and <span style="font-weight: bold;" class="mycode_b">RGSS2</span> since all it does is <span style="font-style: italic;" class="mycode_i">add features</span> and doesn't change fundamentals.) <span style="color: #e82a1f;" class="mycode_color">I have not implemented this in <span style="font-weight: bold;" class="mycode_b">Ruby </span>or any of the <span style="font-weight: bold;" class="mycode_b">RPG Maker </span>systems. It might be awhile but I will get back to that at a later date.</span><br />
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="text-decoration: underline;" class="mycode_u"><span style="font-size: x-large;" class="mycode_size">Features</span></span></span><br />
<ul class="mycode_list"><li>Supports multiple filetypes; <span style="font-weight: bold;" class="mycode_b">wav</span>, <span style="font-weight: bold;" class="mycode_b">ogg</span>, <span style="font-weight: bold;" class="mycode_b">flac</span>, probably others.<br />
</li>
<li>Play 1 <span style="font-weight: bold;" class="mycode_b">Background Music</span><br />
</li>
<li>Play 1 <span style="font-weight: bold;" class="mycode_b">Background Sound</span><br />
</li>
<li>Play 1 <span style="font-weight: bold;" class="mycode_b">Music Effect</span><br />
</li>
<li>Play multiple <span style="font-weight: bold;" class="mycode_b">Sound Effects</span><br />
</li>
<li>Adjust fade in/fade out timing of <span style="font-weight: bold;" class="mycode_b">Music Effects</span><br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">Available Functions</span> : Play, Pause, Stop, Fade In/Out, Replay, Volume=, Pitch=<br />
</li>
<li>Please see <span style="font-weight: bold;" class="mycode_b">SFML/Audio</span> for more information.<br />
</li>
</ul>
<br />
(<span style="font-weight: bold;" class="mycode_b">NOTE:</span> Lack of <span style="font-weight: bold;" class="mycode_b">mp3</span> support is a <span style="font-style: italic;" class="mycode_i">legal issue</span>, apparently. This is outside the scope of my script and more related to <span style="font-weight: bold;" class="mycode_b">SFML</span>. End user is responsible for implementing their own <span style="font-weight: bold;" class="mycode_b">mp3</span> support, if desired. (I find <span style="font-weight: bold;" class="mycode_b">ogg</span> to be a better format, personally. <span style="font-weight: bold;" class="mycode_b">Ogg</span> BGM and BGS seem to loop <span style="font-style: italic;" class="mycode_i">better</span> than <span style="font-weight: bold;" class="mycode_b">mp3</span> so I actually <span style="font-style: italic;" class="mycode_i">encourage</span> people to switch formats.))<br />
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="text-decoration: underline;" class="mycode_u"><span style="font-size: x-large;" class="mycode_size">Requirements</span></span></span><br />
<ul class="mycode_list"><li><span style="font-weight: bold;" class="mycode_b">SFML (Simple and Fast Multimedia Library)</span><br />
</li>
<li>Should only require <span style="font-weight: bold;" class="mycode_b">SFML/Audio</span> (for audio) and <span style="font-weight: bold;" class="mycode_b">SFML/System</span> (for sf::Time functionality). See header file for more details.<br />
</li>
<li>Working knowledge of <span style="font-weight: bold;" class="mycode_b">C++</span> and the build tools required to compile and run it.<br />
</li>
</ul>
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="text-decoration: underline;" class="mycode_u"><span style="font-size: x-large;" class="mycode_size">Instructions</span></span></span><br />
<br />
<span style="color: #e82a1f;" class="mycode_color">This is <span style="font-weight: bold;" class="mycode_b">NOT</span> a plug-n-play <span style="font-weight: bold;" class="mycode_b">RPG Maker</span> <span style="font-style: italic;" class="mycode_i">script</span>, you'd need to compile it yourself with <span style="font-weight: bold;" class="mycode_b">C++</span> and configure it to your needs.</span><br />
<span style="color: #e82a1f;" class="mycode_color">While this is designed to be <span style="font-weight: bold;" class="mycode_b">RGSS compliant</span>, it has <span style="font-weight: bold;" class="mycode_b">not</span> been implemented in <span style="font-weight: bold;" class="mycode_b">Ruby/RPG Maker</span>.</span><br />
<span style="color: #e82a1f;" class="mycode_color">I'm just sharing it for anybody who can do <span style="font-style: italic;" class="mycode_i">something</span> with it.</span><br />
<span style="color: #e82a1f;" class="mycode_color">If I get the <span style="font-weight: bold;" class="mycode_b">C++</span> and <span style="font-weight: bold;" class="mycode_b">Ruby</span> to communicate, I will return with a <span style="font-style: italic;" class="mycode_i">full plug-in-play implementation</span> anyone can use.</span><br />
<br />
<div class="tborder">
  			<div class="thead" style="padding:4px; margin:1px;"><input type="button" class="button" value="+" style="font-family:Monospace; padding:0px" onclick="if (this.parentNode.parentNode.getElementsByTagName('div')[1].style.display=='none'){ this.parentNode.parentNode.getElementsByTagName('div')[1].style.display='';this.value='-';} else {this.parentNode.parentNode.getElementsByTagName('div')[1].style.display='none';this.value='+';}"/> Content Hidden</div>
  			<div class="trow2" style="display:none; padding:4px; margin:1px;"><span style="font-weight: bold;" class="mycode_b">Assuming you have a C++ build environment...</span><br />
<ul class="mycode_list"><li>Place <span style="font-weight: bold;" class="mycode_b">RGL/Audio.hpp</span> in <span style="font-weight: bold;" class="mycode_b">*/include/RGL/</span><br />
</li>
<li>Place the <span style="font-weight: bold;" class="mycode_b">RGL/Audio.cpp</span> in <span style="font-weight: bold;" class="mycode_b">*/src/RGL/</span><br />
</li>
</ul>
<br />
<span style="font-weight: bold;" class="mycode_b">(NOT INCLUDED : RGL module. This is more tailored to my personal project than anything. You can write your own module and change the "RGL" to whatever you find appropriate. I use namespace "rgl" (ie rgl::Audio) to separate it from SFML's implementation (sf::Audio). My RGL module has nothing to do with the functionality of this system other than as a directory/namespace.)</span><br />
<br />
You could probably compile yourself a nice little <span style="font-weight: bold;" class="mycode_b">libaudio.dll</span> and include it with your game project, but then you'd have to write C++/Ruby extensions. I haven't got that far nor do I know (yet) how to do all that. I'd assume you can probably do it via <span style="font-weight: bold;" class="mycode_b">Win32API</span> <span style="font-style: italic;" class="mycode_i">(or <span style="font-weight: bold;" class="mycode_b">Win32::API </span>for <span style="font-weight: bold;" class="mycode_b">Ruby &gt;= 1.9.2</span>)</span> if you're running an <span style="font-weight: bold;" class="mycode_b">RPG Maker</span> game on <span style="font-weight: bold;" class="mycode_b">Windows</span>. How it would work on other platforms? I don't have the EXP yet to know how that all works. Until then, I will only be providing <span style="font-style: italic;" class="mycode_i"><span style="color: #ff4136;" class="mycode_color">very limited support</span></span>.</div>
		</div>
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="text-decoration: underline;" class="mycode_u"><span style="font-size: x-large;" class="mycode_size">Differences from Original RGSS</span></span></span><br />
<br />
There are <span style="font-style: italic;" class="mycode_i">minor</span> differences between this and the vanilla <span style="font-weight: bold;" class="mycode_b">RGSS</span>, <span style="font-weight: bold;" class="mycode_b">RGSS2</span> and <span style="font-weight: bold;" class="mycode_b">RGSS3</span> implementations (personal taste)...<br />
<ul class="mycode_list"><li>When playing <span style="font-weight: bold;" class="mycode_b">Music Effects</span>, all other audio (BGM, BGS, SE) fade out in <span style="font-style: italic;" class="mycode_i">2 seconds</span> instead of instant.<br />
</li>
<li>When playing <span style="font-weight: bold;" class="mycode_b">Music Effects</span>, the volume of all other audio is <span style="font-style: italic;" class="mycode_i">reduced to 10 instead of 0</span>.<br />
</li>
<li>When playing <span style="font-weight: bold;" class="mycode_b">Music Effects</span>, the volume fades in approximately <span style="font-style: italic;" class="mycode_i">4 seconds</span>. Adjustable.<br />
</li>
<li>These timing features should be easily adjustable by changing the member variable values in the <span style="font-style: italic;" class="mycode_i">header</span> file.<br />
</li>
<li>NOTE: The Fade Out for music effects should be a minimum of <span style="font-weight: bold;" class="mycode_b">1.0f </span>or it won't fade out at all. Of course, you can edit the script yourself if you're trying to do, say, a half second.<br />
</li>
</ul>
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="text-decoration: underline;" class="mycode_u"><span style="font-size: x-large;" class="mycode_size">Source Files</span></span></span><br />
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="text-decoration: underline;" class="mycode_u">RGL/Audio.hpp</span></span><br />
<div class="tborder">
  			<div class="thead" style="padding:4px; margin:1px;"><input type="button" class="button" value="+" style="font-family:Monospace; padding:0px" onclick="if (this.parentNode.parentNode.getElementsByTagName('div')[1].style.display=='none'){ this.parentNode.parentNode.getElementsByTagName('div')[1].style.display='';this.value='-';} else {this.parentNode.parentNode.getElementsByTagName('div')[1].style.display='none';this.value='+';}"/> Content Hidden</div>
  			<div class="trow2" style="display:none; padding:4px; margin:1px;">
<div class="codeblock"><div class="title">Code:</div><div class="body" dir="ltr"><code>/*=============================================================================*/<br />
// ** rgl::Audio<br />
/*-----------------------------------------------------------------------------*/<br />
// Public Members<br />
// ==============<br />
// sf::Music &nbsp;&nbsp;&nbsp;&nbsp;m_BGM<br />
// sf::Music &nbsp;&nbsp;&nbsp;&nbsp;m_BGS<br />
// sf::Sound&nbsp;&nbsp;&nbsp;&nbsp;m_ME<br />
// sf::Vector   m_VectorSE<br />
//<br />
// Public Functions<br />
// ================<br />
// Audio.playBGM()<br />
// Audio.playBGM(name)<br />
// Audio.playBGM(name, volume, pitch)<br />
// Audio.replayBGM()<br />
// Audio.pauseBGM()<br />
// Audio.stopBGM()<br />
// Audio.playBGS()<br />
// Audio.playBGS(name)<br />
// Audio.playBGS(name, volume, pitch)<br />
// Audio.replayBGS()<br />
// Audio.pauseBGS()<br />
// Audio.stopBGS()<br />
// Audio.playME()<br />
// Audio.playME(name)<br />
// Audio.playME(name, volume, pitch)<br />
// Audio.replayME()<br />
// Audio.pauseME()<br />
// Audio.stopME()<br />
// Audio.playSE()<br />
// Audio.playSE(name)<br />
// Audio.playSE(name, volume, pitch)<br />
// Audio.replaySE()<br />
// Audio.pauseSE()<br />
// Audio.stopSE()<br />
// Audio.update()<br />
//<br />
// Private Members<br />
// ===============<br />
// bool &nbsp;&nbsp;&nbsp;&nbsp;m_waitME<br />
/*=============================================================================*/<br />
<br />
#ifndef RGL_AUDIO_H<br />
#define RGL_AUDIO_H<br />
<br />
#include &lt;RGL.hpp&gt;<br />
#include &lt;RGL/Audio.hpp&gt;<br />
#include &lt;RGL/AudioFile.hpp&gt;<br />
#include &lt;SFML/Audio.hpp&gt;<br />
#include &lt;SFML/Audio/Sound.hpp&gt;<br />
#include &lt;SFML/Audio/SoundBuffer.hpp&gt;<br />
#include &lt;SFML/System/Time.hpp&gt;<br />
#include &lt;deque&gt;<br />
#include &lt;stdlib.h&gt;<br />
#include &lt;iostream&gt;<br />
#include &lt;istream&gt;<br />
<br />
/*============================================================================*/<br />
// ** rgl<br />
/*============================================================================*/<br />
<br />
namespace rgl {<br />
<br />
static const int NUM_OF_SE = 16;<br />
//template&lt;typename S&gt; sf::Sound;<br />
//template&lt;typename B&gt; sf::SoundBuffer;<br />
class Audio {<br />
    public:<br />
        // Construct and Destruct<br />
        Audio();<br />
        virtual ~Audio();<br />
        // Public Members<br />
        bool m_OutOfFocus = false;<br />
        // Public Functions : BGM<br />
        bool playBGM(const sf::String&amp; l_name, float volume, float pitch);<br />
        bool playBGM(const sf::String&amp; l_name);<br />
        bool playBGM();<br />
        bool replayBGM();<br />
        void pauseBGM();<br />
        void stopBGM();<br />
        void fadeBGM(float volume, float duration);<br />
        // Public Functions : BGS<br />
        bool playBGS(const sf::String&amp; l_name, float volume, float pitch);<br />
        bool playBGS(const sf::String&amp; l_name);<br />
        bool playBGS();<br />
        bool replayBGS();<br />
        void pauseBGS();<br />
        void stopBGS();<br />
        void fadeBGS(float volume, float duration);<br />
        // Public Functions : ME<br />
        bool playME(const sf::String&amp; l_name, float volume, float pitch);<br />
        bool playME(const sf::String&amp; l_name);<br />
        bool playME();<br />
        bool replayME();<br />
        void pauseME();<br />
        void stopME();<br />
        void fadeME(float volume, float duration);<br />
        // Public Functions : SE<br />
        bool playSE(const sf::String&amp; l_name, float volume, float pitch);<br />
        bool playSE(const sf::String&amp; l_name);<br />
        bool playSE();<br />
        bool replaySE();<br />
        void pauseSE();<br />
        void stopSE();<br />
        void fadeSE(float volume, float duration);<br />
        // Public Functions : Update<br />
        void update();<br />
        void reset();<br />
        void fadeAll(float volume, float duration);<br />
    protected:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// ...<br />
    private:<br />
        // Private Member Constants<br />
        const float m_MEFadeOutT = 2.0f;<br />
        const float m_MEFadeInT  = 4.0f;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Private Member Variables<br />
        sf::Music m_BGM;        // Background Music<br />
        sf::Music m_BGS;        // Background Sound<br />
        sf::Music m_ME;         // Music Effect<br />
        sf::Sound m_SE;         // Sound Effect<br />
        std::deque&lt;sf::Sound&gt; m_SoundV;<br />
        std::deque&lt;sf::SoundBuffer&gt; m_BufferV;<br />
        int       m_phaseME = 0;// Music Effect phase (0 None, 1 Fade in, 2 Play, 3 Fade Out)<br />
        sf::Clock m_timeME;     // Music effect clock<br />
        sf::Clock m_timeSE;     // Sound effect clock<br />
        sf::Time  m_timeSEMax = sf::seconds(3.0);<br />
        float     m_BGMFadeV    = 0.0; // BGM Fade Volume<br />
        float     m_BGSFadeV    = 0.0; // BGS Fade Volume<br />
        float     m_MEFadeV     = 0.0; // ME Fade Volume<br />
        float     m_SEFadeV     = 0.0; // SE Fade Volume<br />
        float     m_BGMFadeD    = 0.0f; // BGM Fade Duration<br />
        float     m_BGSFadeD    = 0.0f; // BGS Fade Duration<br />
        float     m_MEFadeD     = 0.0f; // ME Fade Duration<br />
        float     m_SEFadeD     = 0.0f; // SE Fade Duration<br />
        float     m_BGMLastV    = 0.0;// BGM Last Volume<br />
        float     m_BGSLastV    = 0.0;// BGS Last Volume<br />
        //float     m_MELastV     = 0.0;// ME Last Volume (Not used/needed)<br />
        float     m_SELastV     = 0.0;// ME Last Volume<br />
        // Private Functions<br />
        void updateBGM();<br />
        void updateBGS();<br />
        void updateME();<br />
        void updateSE();<br />
        void updateSE(int i);<br />
        void updateBuffers();<br />
        void updateMusicEffect();<br />
        // ...Need to add limited vector for sound queue<br />
};<br />
<br />
}<br />
#endif //RGL_AUDIO_H</code></div></div></div>
		</div>
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="text-decoration: underline;" class="mycode_u">RGL/Audio.cpp</span></span><br />
<div class="tborder">
  			<div class="thead" style="padding:4px; margin:1px;"><input type="button" class="button" value="+" style="font-family:Monospace; padding:0px" onclick="if (this.parentNode.parentNode.getElementsByTagName('div')[1].style.display=='none'){ this.parentNode.parentNode.getElementsByTagName('div')[1].style.display='';this.value='-';} else {this.parentNode.parentNode.getElementsByTagName('div')[1].style.display='none';this.value='+';}"/> Content Hidden</div>
  			<div class="trow2" style="display:none; padding:4px; margin:1px;">
<div class="codeblock"><div class="title">Code:</div><div class="body" dir="ltr"><code>/*=============================================================================*/<br />
// ** rgl::Audio<br />
/*-----------------------------------------------------------------------------*/<br />
// Public Members<br />
// ==============<br />
// sf::Music &nbsp;&nbsp;&nbsp;&nbsp;m_BGM<br />
// sf::Music &nbsp;&nbsp;&nbsp;&nbsp;m_BGS<br />
// sf::Sound&nbsp;&nbsp;&nbsp;&nbsp;m_ME<br />
// sf::Vector   m_VectorSE<br />
//<br />
// Public Functions<br />
// ================<br />
// Audio.playBGM()<br />
// Audio.playBGM(name)<br />
// Audio.playBGM(name, volume, pitch)<br />
// Audio.pauseBGM()<br />
// Audio.stopBGM()<br />
// Audio.fadeBGM(volume, duration)<br />
// Audio.playBGS()<br />
// Audio.playBGS(name)<br />
// Audio.playBGS(name, volume, pitch)<br />
// Audio.pauseBGS()<br />
// Audio.stopBGS()<br />
// Audio.fadeBGS(volume, duration)<br />
// Audio.playME()<br />
// Audio.playME(name)<br />
// Audio.playME(name, volume, pitch)<br />
// Audio.pauseME()<br />
// Audio.stopME()<br />
// Audio.fadeME(volume, duration)<br />
// Audio.playSE()<br />
// Audio.playSE(name)<br />
// Audio.playSE(name, volume, pitch)<br />
// Audio.fadeSE(volume, duration)<br />
// Audio.pauseSE()<br />
// Audio.stopSE()<br />
// Audio.fadeSE(volume, duration)<br />
// Audio.reset()<br />
// Audio.fadeAll(duration)<br />
// Audio.update()<br />
//<br />
// Private Members<br />
// ===============<br />
// bool &nbsp;&nbsp;&nbsp;&nbsp;m_waitME<br />
// float&nbsp;&nbsp;&nbsp;&nbsp;m_bgmVolB4ME<br />
// float &nbsp;&nbsp;&nbsp;&nbsp;m_bgsVolB4ME<br />
// float &nbsp;&nbsp;&nbsp;&nbsp;m_bgmFade<br />
// float &nbsp;&nbsp;&nbsp;&nbsp;m_bgsFade<br />
/*=============================================================================*/<br />
<br />
#include &lt;SFML/Audio.hpp&gt;<br />
#include &lt;SFML/System/Time.hpp&gt;<br />
#include &lt;RGL.hpp&gt;<br />
#include &lt;RGL/Audio.hpp&gt;<br />
#include &lt;istream&gt;<br />
<br />
//#include &lt;RGL/AudioFile.hpp&gt;<br />
<br />
/*============================================================================*/<br />
// ** rgl<br />
/*============================================================================*/<br />
namespace rgl {<br />
<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio() [Constructor]<br />
/*----------------------------------------------------------------------------*/<br />
Audio::Audio() {}<br />
/*----------------------------------------------------------------------------*/<br />
// ** ~Audio() [Destructor]<br />
/*----------------------------------------------------------------------------*/<br />
Audio::~Audio() {}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.playBGM(name, volume, pitch)<br />
/*----------------------------------------------------------------------------*/<br />
bool Audio::playBGM(const sf::String&amp; l_name, float volume, float pitch) {<br />
    // If name is empty<br />
    if (l_name.isEmpty()) {<br />
        // Stop the BGM<br />
        m_BGM.stop();<br />
        // Nothing wrong with stopping the BGM<br />
        return true;<br />
    }<br />
    // If unable to open from file<br />
    if (!m_BGM.openFromFile(l_name)) {<br />
        // Error opening file<br />
        return false;<br />
    }<br />
    // Set volume, pitch and loop<br />
    m_BGM.setVolume(volume);<br />
    m_BGM.setPitch(pitch);<br />
    m_BGM.setLoop(true);<br />
    // Play the BGM<br />
    m_BGM.play();<br />
    // Opened file successfully<br />
    return true;<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.playBGM(name)<br />
/*----------------------------------------------------------------------------*/<br />
bool Audio::playBGM(const sf::String&amp; l_name) {<br />
    // Play BGM by name<br />
    return playBGM(l_name, 80.0, 1.0);<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.playBGM()<br />
/*----------------------------------------------------------------------------*/<br />
bool Audio::playBGM() {<br />
    // Ensure BGM loops<br />
    m_BGM.setLoop(true);<br />
    // Play BGM without any arguments<br />
    m_BGM.play();<br />
    // Return true<br />
    return true;<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.replayBGM()<br />
/*----------------------------------------------------------------------------*/<br />
bool Audio::replayBGM() {<br />
    m_BGM.stop();<br />
    m_BGM.play();<br />
    // Return true<br />
    return true;<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.pauseBGM()<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::pauseBGM() {<br />
    // Pause BGM<br />
    m_BGM.pause();<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.fadeBGM(volume, duration, memorize = false)<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::fadeBGM(float volume, float duration) {<br />
    // Set BGM fade volume and duration<br />
    m_BGMFadeV = volume;<br />
    m_BGMFadeD = sf::seconds(duration).asSeconds();<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.stopBGM()<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::stopBGM() {<br />
    // Stop BGM<br />
    m_BGM.stop();<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.playBGS(name, volume, pitch)<br />
/*----------------------------------------------------------------------------*/<br />
bool Audio::playBGS(const sf::String&amp; l_name, float volume, float pitch) {<br />
    // If name is empty<br />
    if (l_name.isEmpty()) {<br />
        // Stop the BGS<br />
        m_BGS.stop();<br />
        // Nothing wrong with stopping the BGS<br />
        return true;<br />
    }<br />
    // If unable to open from file<br />
    if (!m_BGS.openFromFile(l_name)) {<br />
        // Error opening file<br />
        return false;<br />
    }<br />
    // Set volume, pitch and loop<br />
    m_BGS.setVolume(volume);<br />
    m_BGS.setPitch(pitch);<br />
    m_BGS.setLoop(true);<br />
    // Play the BGS<br />
    m_BGS.play();<br />
    // Opened file successfully<br />
    return true;<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.playBGS(name)<br />
/*----------------------------------------------------------------------------*/<br />
bool Audio::playBGS(const sf::String&amp; l_name) {<br />
    // Play BGS by name<br />
    return playBGS(l_name, 80.0, 1.0);<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.playBGS()<br />
/*----------------------------------------------------------------------------*/<br />
bool Audio::playBGS() {<br />
    // Ensure BGS loops<br />
    m_BGS.setLoop(true);<br />
    // Play BGS without any arguments<br />
    m_BGS.play();<br />
    // Return true<br />
    return true;<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.replayBGS()<br />
/*----------------------------------------------------------------------------*/<br />
bool Audio::replayBGS() {<br />
    // Restart BGS<br />
    m_BGS.stop();<br />
    m_BGS.play();<br />
    // Return true<br />
    return true;<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.pauseBGS()<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::pauseBGS() {<br />
    // Pause BGS<br />
    m_BGS.pause();<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.stopBGS()<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::stopBGS() {<br />
    // Stop BGS<br />
    m_BGS.stop();<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.fadeBGS(volume, duration, memorize = false)<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::fadeBGS(float volume, float duration) {<br />
    // Set BGS fade volume and duration<br />
    m_BGSFadeV = volume;<br />
    m_BGSFadeD = duration;<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.playME(name, volume, pitch)<br />
/*----------------------------------------------------------------------------*/<br />
bool Audio::playME(const sf::String&amp; l_name, float volume, float pitch) {<br />
    // If name is empty<br />
    if (l_name.isEmpty()) {<br />
        // Ensure phase is 0<br />
        m_phaseME = 0;<br />
        // Stop the ME<br />
        m_ME.stop();<br />
        // Nothing wrong with stopping the ME<br />
        return true;<br />
    }<br />
    // If unable to open from file<br />
    if (!m_ME.openFromFile(l_name)) {<br />
        // Print to console<br />
        cout &lt;&lt; "Error loading file" &lt;&lt; endl;;<br />
        // Error opening file<br />
        return false;<br />
    }<br />
    // Set phase to 1<br />
    m_phaseME = 1;<br />
    // Set volume, pitch and loop<br />
    m_ME.setVolume(volume);<br />
    m_ME.setPitch(pitch);<br />
    m_ME.setLoop(false);<br />
    // Play the ME<br />
    m_ME.play();<br />
    // Opened file successfully<br />
    return true;<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.playME(name)<br />
/*----------------------------------------------------------------------------*/<br />
bool Audio::playME(const sf::String&amp; l_name) {<br />
    // Play ME by name<br />
    return playME(l_name, 80.0, 1.0);<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.playME()<br />
/*----------------------------------------------------------------------------*/<br />
bool Audio::playME() {<br />
    // Ensure ME does not loop<br />
    m_ME.setLoop(false);<br />
    // Play ME without any arguments<br />
    m_ME.play();<br />
    // Return true<br />
    return true;<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.replayME()<br />
/*----------------------------------------------------------------------------*/<br />
bool Audio::replayME() {<br />
    // Restart ME<br />
    m_ME.stop();<br />
    m_ME.play();<br />
    // Return true<br />
    return true;<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.pauseME()<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::pauseME() {<br />
    // Pause ME<br />
    m_ME.pause();<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.stopME()<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::stopME() {<br />
    // Stop ME<br />
    m_ME.stop();<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.fadeME(volume, duration, memorize = false)<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::fadeME(float volume, float duration) {<br />
    // Set ME fade volume and duration<br />
    m_MEFadeV = volume;<br />
    m_MEFadeD = duration;<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.playSE(name, volume, pitch)<br />
/*----------------------------------------------------------------------------*/<br />
bool Audio::playSE(const sf::String&amp; l_name, float volume, float pitch) {<br />
    // End function doing nothing if no name given<br />
    if (l_name.isEmpty()) { return true; }<br />
    // Create sound and sound buffer<br />
    sf::Sound sound;<br />
    sf::SoundBuffer buffer;<br />
    // If unable to open from file<br />
    if (!buffer.loadFromFile(l_name)) {<br />
        // Print to console<br />
        cout &lt;&lt; "Unable to load Sound Effect" &lt;&lt; endl;<br />
        // Error opening file<br />
        return false;<br />
    }<br />
    // Set volume, pitch and loop<br />
    sound.setVolume(volume);<br />
    sound.setPitch(pitch);<br />
    sound.setLoop(false);<br />
    // If sound duration is more than current max time<br />
    if (buffer.getDuration() &gt; m_timeSEMax) {<br />
        // Restart timer and set time max duration<br />
        m_timeSE.restart();<br />
        m_timeSEMax = (buffer.getDuration());<br />
        m_timeSEMax += (buffer.getDuration());<br />
    }<br />
    // Add to vectors<br />
    m_SoundV.push_back(sound);<br />
    m_BufferV.push_back(buffer);<br />
    // Set the last buffer on the stack<br />
    m_SoundV[m_SoundV.size() - 1].setBuffer(m_BufferV[m_BufferV.size() - 1]);<br />
    // Play the sound<br />
    m_SoundV[m_SoundV.size() - 1].play();<br />
    cout &lt;&lt; "Playing SE : " &lt;&lt; m_SoundV.size() &lt;&lt; endl;<br />
    // Opened file successfully<br />
    return true;<br />
}<br />
<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.playSE(name)<br />
/*----------------------------------------------------------------------------*/<br />
bool Audio::playSE(const sf::String&amp; l_name) {<br />
    // Play SE by name<br />
    return playSE(l_name, 80.0, 1.0);<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.playSE()<br />
/*----------------------------------------------------------------------------*/<br />
bool Audio::playSE() {<br />
    // Ensure SE does not loop<br />
    m_SE.setLoop(false);<br />
    // Play SE without any arguments<br />
    m_SE.play();<br />
    // Return true<br />
    return true;<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.replaySE()<br />
/*----------------------------------------------------------------------------*/<br />
bool Audio::replaySE() {<br />
    // Restart SE<br />
    m_SE.stop();<br />
    m_SE.play();<br />
    // Return true<br />
    return true;<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.pauseSE()<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::pauseSE() {<br />
    // Pause SE<br />
    m_SE.pause();<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.stopSE()<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::stopSE() {<br />
    // Stop SE<br />
    m_SE.stop();<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.fadeSE(volume, duration, memorize = false)<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::fadeSE(float volume, float duration) {<br />
    // Set SE fade volume and duration<br />
    m_SEFadeV = volume;<br />
    m_SEFadeD = duration;<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.reset()<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::reset() {<br />
    m_BGM.stop();<br />
    m_BGS.stop();<br />
    m_ME.stop();<br />
    m_SE.stop();<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.fadeAll(duration)<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::fadeAll(float volume, float duration) {<br />
    fadeBGM(volume, duration);<br />
    fadeBGS(volume, duration);<br />
    fadeME(volume, duration);<br />
    fadeSE(volume, duration);<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.update()<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::update() {<br />
    // End method unless a second has passed<br />
    if (m_timeME.getElapsedTime() &lt; sf::seconds(0.1f)) { return; }<br />
    // Update audio<br />
    updateBGM();<br />
    updateBGS();<br />
    updateME();<br />
    updateSE();<br />
    // Update buffers<br />
    updateBuffers();<br />
    // Restart tick<br />
    m_timeME.restart();<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.updateBGM()<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::updateBGM() {<br />
    // End method if no music is playing<br />
    if (m_BGM.getStatus() == sf::Music::Stopped) { return;}<br />
    // End method if not fading<br />
    if (m_BGMFadeD &lt;= 0.0) { return; }<br />
    // Decrease wait duration<br />
    m_BGMFadeD -= 0.1f;<br />
    // If duration is 0<br />
    if (m_BGMFadeD &lt;= 0.0) {<br />
        // Reset fade to 0<br />
        m_BGMFadeV = m_BGMFadeD = 0.0;<br />
        // End function<br />
        return;<br />
    }<br />
    // If fade volume is more than ME volume<br />
    if (m_BGMFadeV &gt; m_BGM.getVolume()) {<br />
        // Get volume increment<br />
        float vol = (abs(m_BGMFadeV - m_BGM.getVolume()) / m_BGMFadeD);<br />
        // Increase volume<br />
        m_BGM.setVolume(m_BGM.getVolume() + vol);<br />
    // If fade volume is less than ME volume<br />
    } else if (m_BGMFadeV &lt; m_BGM.getVolume()) {<br />
        // Get volume increment<br />
        float vol = (abs(m_BGM.getVolume() - m_BGMFadeV) / m_BGMFadeD);<br />
        // Decrease volume<br />
        m_BGM.setVolume(m_BGM.getVolume() - vol);<br />
    } else if (m_BGMFadeD &lt;= 0.0) {<br />
        // Reset fade to 0<br />
        m_BGMFadeV = m_BGMFadeD = 0.0;<br />
        // End function<br />
        return;<br />
    }<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.updateBGS()<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::updateBGS() {<br />
    // End method if no music is playing<br />
    if (m_BGS.getStatus() == sf::Music::Stopped) { return;}<br />
    // End method if not fading<br />
    if (m_BGSFadeD &lt;= 0.0) { return; }<br />
    // Decrease wait duration<br />
    m_BGSFadeD -= 0.1f;<br />
    // If duration is 0<br />
    if (m_BGSFadeD &lt;= 0.0) {<br />
        // Reset fade to 0<br />
        m_BGSFadeV = m_BGSFadeD = 0.0;<br />
        // End function<br />
        return;<br />
    }<br />
    // If fade volume is more than ME volume<br />
    if (m_BGSFadeV &gt; m_BGS.getVolume()) {<br />
        // Get volume increment<br />
        float vol = (abs(m_BGSFadeV - m_BGS.getVolume()) / m_BGSFadeD);<br />
        // Increase volume<br />
        m_BGS.setVolume(m_BGS.getVolume() + vol);<br />
    // If fade volume is less than ME volume<br />
    } else if (m_BGSFadeV &lt; m_BGS.getVolume()) {<br />
        // Get volume increment<br />
        float vol = (abs(m_BGS.getVolume() - m_BGSFadeV) / m_BGSFadeD);<br />
        // Decrease volume<br />
        m_BGS.setVolume(m_BGS.getVolume() - vol);<br />
    } else if (m_BGSFadeD &lt;= 0.0) {<br />
        // Reset fade to 0<br />
        m_BGSFadeV = m_BGSFadeD = 0.0;<br />
        // End function<br />
        return;<br />
    }<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.updateME()<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::updateME() {<br />
    // End method if no music is playing<br />
    if (m_ME.getStatus() == sf::Music::Stopped) { return;}<br />
    // Do internal music effect update<br />
    updateMusicEffect();<br />
    //if (m_MEFadeD &lt;= 0.0) { return; }<br />
    // Decrease wait duration<br />
    m_MEFadeD -= 0.1f;<br />
    // If duration is 0<br />
    if (m_MEFadeD &lt;= 0.0) {<br />
        // Reset fade to 0<br />
        m_MEFadeV = m_MEFadeD = 0.0;<br />
        // End function<br />
        return;<br />
    }<br />
    // If fade volume is more than ME volume<br />
    if (m_MEFadeV &gt; m_ME.getVolume()) {<br />
        // Get volume increment<br />
        float vol = (abs(m_MEFadeV - m_ME.getVolume()) / m_MEFadeD);<br />
        // Increase volume<br />
        m_ME.setVolume(m_ME.getVolume() + vol);<br />
    // If fade volume is less than ME volume<br />
    } else if (m_MEFadeV &lt; m_ME.getVolume()) {<br />
        // Get volume increment<br />
        float vol = (abs(m_ME.getVolume() - m_MEFadeV) / m_MEFadeD);<br />
        // Decrease volume<br />
        m_ME.setVolume(m_ME.getVolume() - vol);<br />
    } else if (m_MEFadeD &lt;= 0.0) {<br />
        // Reset fade to 0<br />
        m_MEFadeV = m_MEFadeD = 0.0;<br />
        // End function<br />
        return;<br />
    }<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.updateMusicEffect()<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::updateMusicEffect() {<br />
    // Get current and total duration<br />
    float sec = m_ME.getPlayingOffset().asSeconds();<br />
    float all = m_ME.getDuration().asSeconds();<br />
    // If phase 1 : Fade Out<br />
    if (m_phaseME == 1 &amp;&amp; sec &lt; 1.0) {<br />
        // Memorize volumes<br />
        m_BGMLastV = m_BGM.getVolume();<br />
        m_BGSLastV = m_BGS.getVolume();<br />
        m_SELastV = ((m_SoundV.size() &gt; 0) ? m_SoundV[0].getVolume() : 80.0 );<br />
        // Trigger a rolling fade out of audio assets<br />
        fadeBGM(10.0, m_MEFadeOutT);<br />
        fadeBGS(10.0, m_MEFadeOutT);<br />
        fadeSE(10.0, m_MEFadeOutT);<br />
        // Set next phase : play the body of the music effect<br />
        m_phaseME = 2;<br />
        // End function<br />
        return;<br />
    // If phase 2 : Play Body<br />
    } else if (m_phaseME == 2 &amp;&amp;<br />
    (sec &gt; 1.0 &amp;&amp; sec &lt; (all * 0.9))) {<br />
        // Set next phase : fade back in<br />
        m_phaseME = 3;<br />
        // End function<br />
        return;<br />
    // If phase 3 : Fade In<br />
    } else if (m_phaseME == 3 &amp;&amp; sec &gt; (all * 0.9)) {<br />
        // Trigger a rolling fade in of audio assets<br />
        fadeBGM(m_BGMLastV, m_MEFadeInT);<br />
        fadeBGS(m_BGSLastV, m_MEFadeInT);<br />
        fadeSE(m_SELastV, m_MEFadeInT);<br />
        // Set next phase : DONE<br />
        m_phaseME = 0;<br />
        // End function<br />
        return;<br />
    }<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.updateSE()<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::updateSE() {<br />
    // Update each sound<br />
    for(unsigned int i = 0; i &lt; m_SoundV.size() ; i++){ updateSE(i);}<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.updateSE()<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::updateSE(int i) {<br />
    // End method if no music is playing<br />
    if (m_SoundV[i].getStatus() == sf::Sound::Stopped) {<br />
        // Erase sound at iterator position<br />
        m_SoundV.erase(m_SoundV.begin()+i);<br />
        // Print to console<br />
        return;<br />
    }<br />
    // End method if not fading<br />
    if (m_SEFadeD &lt;= 0.0) { return; }<br />
    // Decrease wait duration<br />
    m_SEFadeD -= 0.1f;<br />
    // If duration is 0<br />
    if (m_SEFadeD &lt;= 0.0) {<br />
        // Reset fade to 0<br />
        m_SEFadeV = m_SEFadeD = 0.0;<br />
        // End function<br />
        return;<br />
    }<br />
    // If fade volume is more than SE volume<br />
    if (m_SEFadeV &gt; m_SoundV[i].getVolume()) {<br />
        // Get volume increment<br />
        float vol = (abs(m_SEFadeV - m_SoundV[i].getVolume()) / m_SEFadeD);<br />
        // Increase volume<br />
        m_SoundV[i].setVolume(m_SoundV[i].getVolume() + vol);<br />
    // If fade volume is less than SE volume<br />
    } else if (m_SEFadeV &lt; m_SoundV[i].getVolume()) {<br />
        // Get volume increment<br />
        float vol = (abs(m_SoundV[i].getVolume() - m_SEFadeV) / m_SEFadeD);<br />
        // Decrease volume<br />
        m_SoundV[i].setVolume(m_SoundV[i].getVolume() - vol);<br />
    // If fade duration is less than or equal to 0 seconds<br />
    } else if (m_SEFadeD &lt;= 0.0) {<br />
        // Reset fade and volume to 0<br />
        m_SEFadeV = m_SEFadeD = 0.0;<br />
        // End function<br />
        return;<br />
    }<br />
}<br />
/*----------------------------------------------------------------------------*/<br />
// ** Audio.updateBuffers();<br />
/*----------------------------------------------------------------------------*/<br />
void Audio::updateBuffers() {<br />
    // End function if no buffers<br />
    if (m_BufferV.empty()) { return; }<br />
    // Clear buffers if enough time has passed by<br />
    if (m_timeSE.getElapsedTime() &gt;= m_timeSEMax) {<br />
        // Clear buffers and restart timer<br />
        m_BufferV.clear();<br />
        m_timeSE.restart();<br />
    }<br />
}<br />
} // End of rgl::Audio</code></div></div></div>
		</div>
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="text-decoration: underline;" class="mycode_u"><span style="font-size: x-large;" class="mycode_size">Author's Notes</span></span></span><br />
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="text-decoration: underline;" class="mycode_u">Notes : Classes and Memory</span></span><br />
<br />
<div class="tborder">
  			<div class="thead" style="padding:4px; margin:1px;"><input type="button" class="button" value="+" style="font-family:Monospace; padding:0px" onclick="if (this.parentNode.parentNode.getElementsByTagName('div')[1].style.display=='none'){ this.parentNode.parentNode.getElementsByTagName('div')[1].style.display='';this.value='-';} else {this.parentNode.parentNode.getElementsByTagName('div')[1].style.display='none';this.value='+';}"/> Content Hidden</div>
  			<div class="trow2" style="display:none; padding:4px; margin:1px;">Since it was built to RGSS standards, the system uses <span style="font-weight: bold;" class="mycode_b">2x sf::Music (1 BGM, 1 BGS)</span> and <span style="font-weight: bold;" class="mycode_b">1x sf::Sound (1 ME).</span> Plus <span style="font-weight: bold;" class="mycode_b">2x sf::Clocks</span> for internal timing. These are always loaded in memory so long as the <span style="font-weight: bold;" class="mycode_b">rgl::Audio</span> class exists in your project.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Sound Effects (SE)</span> use <span style="font-weight: bold;" class="mycode_b">sf::Sound</span> and <span style="font-weight: bold;" class="mycode_b">sf::SoundBuffers </span>which are dynamically created and destroyed within an <span style="font-weight: bold;" class="mycode_b">std::deque</span> class. The sound buffers are automatically cleared after the maximum <span style="font-weight: bold;" class="mycode_b">(sound.getDuration() * 2)</span>. The length of the latest, and longest, sound effect is doubled and then the buffers are cleared after that if <span style="font-weight: bold;" class="mycode_b">Audio.play_se</span> hasn't been called again.<br />
<br />
A better memory protocol could probably be implemented in the future but it is important that, by hook or by crook, sounds and buffers are removed when not in use because they <span style="font-style: italic;" class="mycode_i">take up memory.</span><br />
If you shorten the duration, some sound effects may not play all the way though. I double it to give the sounds room to run (it takes the time of the longest sound and doubles it.)<br />
Lengthening the duration of time between a buffer creation and destruction probably wouldn't hurt, as buffers are meant to be reused. I keep my buffers on a short leash.</div>
		</div>
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="text-decoration: underline;" class="mycode_u">Notes : What Could Be Improved?</span></span><br />
<br />
<div class="tborder">
  			<div class="thead" style="padding:4px; margin:1px;"><input type="button" class="button" value="+" style="font-family:Monospace; padding:0px" onclick="if (this.parentNode.parentNode.getElementsByTagName('div')[1].style.display=='none'){ this.parentNode.parentNode.getElementsByTagName('div')[1].style.display='';this.value='-';} else {this.parentNode.parentNode.getElementsByTagName('div')[1].style.display='none';this.value='+';}"/> Content Hidden</div>
  			<div class="trow2" style="display:none; padding:4px; margin:1px;">This is an early implementation so I'm sure it's not <span style="font-style: italic;" class="mycode_i">perfect</span>. I'm not a master C++ wizard so I'm still learning.<br />
<br />
First thing that could be improved is applying DRY <span style="font-style: italic;" class="mycode_i">(Don't Repeat Yourself)</span> and standardizing the functionality. I'll probably write a new version using <span style="font-weight: bold;" class="mycode_b"><span style="color: #419dc1;" class="mycode_color">templates</span></span> or <span style="font-weight: bold;" class="mycode_b"><span style="color: #419dc1;" class="mycode_color">typedef</span></span> calls in the future because I can't stand redundant repetition but, for now, it should work fine <span style="font-style: italic;" class="mycode_i">I think</span>.<br />
<br />
There is not support for multiple BGM/BGS. I tried to keep it as close to original RGSS* specification as possible but I may add that support in the future. You'd have to change the single member variables to <span style="font-weight: bold;" class="mycode_b">std::vector</span> or <span style="font-weight: bold;" class="mycode_b">std::list</span> or some other C++ container style. I would like to add that but it's not exactly high on my priority list at the moment.<br />
<br />
For anybody aiming for cross-platform compatibility I would avoid using Win32API / Win32::API and do a direct C++/Ruby FFI (Foreign Function Interface). I don't know how to set these things up <span style="font-style: italic;" class="mycode_i">yet </span>but that's probably going to be the next step...<br />
<br />
(NOTE: You can probably do it with RbInline or RICE or some other system. I'm still studying this stuff so I won't pretend to know the details - YET.)</div>
		</div>
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="text-decoration: underline;" class="mycode_u">Notes : About (lack of) rbSFML Bindings</span></span><br />
<br />
I am well aware that there is a <span style="font-weight: bold;" class="mycode_b">SFML</span> bindings for <span style="font-weight: bold;" class="mycode_b">Ruby (rbSFML)</span>. It doesn't look like it has been updated in 6 years and I don't know if anybody still uses or supports it, nor do I know how stable it is. The SFML forum doesn't have a sub-forum for it in their bindings so I can only assume rbSFML may not be a stable library? I made the personal choice to do this without rbSFML. I would like to learn for myself how to extend Ruby with C++ so it was a personal choice to do it in C++.<br />
<br />
<span style="color: #17b529;" class="mycode_color"><span style="font-size: large;" class="mycode_size">Thank you for checking it out, feel free to lend me a hand if you know anything about this stuff.</span></span><br />
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="text-decoration: underline;" class="mycode_u">Terms and Conditions</span></span><br />
<br />
End user is responsible for figuring out how to compile and use this <span style="font-style: italic;" class="mycode_i">themselves</span>. I will only be providing <span style="color: #e82a1f;" class="mycode_color">limited support</span> and future updates.<br />
Free to use in <span style="font-weight: bold;" class="mycode_b">commercial</span> and <span style="font-weight: bold;" class="mycode_b">non-commercial projects</span>, you don't even have to credit me (but I do like <span style="font-weight: bold;" class="mycode_b">credits</span> -_^).<br />
<span style="font-weight: bold;" class="mycode_b">SFML</span> has its own terms under the <span style="font-weight: bold;" class="mycode_b">ZLIB/PNG License</span>. <span style="font-weight: bold;" class="mycode_b">SFML</span> is an open source multimedia library written by <span style="font-weight: bold;" class="mycode_b">Laurent Gomilla</span> and a team of programming ninjas.]]></content:encoded>
		</item>
	</channel>
</rss>