Quantcast
Channel: VBForums - CodeBank - Visual Basic 6 and earlier
Viewing all 1321 articles
Browse latest View live

[VB6] Lickety - an alternative to Slurp'n'Split

$
0
0
We're in a time of PCs with vast amounts of RAM and little going on in the background, despite money being spent on multi-core CPUs. What was once considered a crude and naive practice of slurping entire text files into a String and then calling Split() to make an array is now actually touted by many programmers.

But much as the practice of Slurp'n'Split was impractical when far smaller amounts of RAM were available, it can break down when you deal with large files.

First you have the problem of an ANSI text file doubling in size in RAM as soon as your slurp it. Then you double that again by calling the Split() function, at least until you discard the original intact String. Both of these together conspire against you for the maximum file size you can process no matter how much RAM you bought on Mommy's credit card: VB6 programs can only use just so much due to 32-bit and other design limitations.

To add insult to injury, Split() was taken over almost without modification from VBScript and never designed for high performance on large amounts of data. That just wasn't one of its design goals.


So What's A Slurp'n'Splitter To Do?

VB5 didn't get a Split() function, and this led the fans at VBspeed to create several alternative equivalents. And of course being VBspeed they worked out some clever optimizations.


Lickety Class

My Lickety.cls was based on some of those Split() alternatives, adding in the reading of the file in chunks for better memory efficiency.

The performance is pretty good, and as soon as your input file is much over 10KB of ANSI text it quickly overtakes a Split() call in both performance and memory requirements. This advantage just grows with the size of the input file.

It has options to read ANSI or Unicode (UTF-16LE) files, optionally skip the Unicode BOM, and whatever line delimiter you choose.

It also takes care of discarding the "dangler" empty line at the end of the file, unlike a Split() call.

I haven't looked it over to be sure but it may work in VB5 as well if you work around the returning of the array (VB5 can't have array-valued functions).


Demo

The demo runs through several rounds of using Lickety and Split() to load the text lines from files of several record lengths and record counts, reporting elapsed time for each test.

Name:  sshot.png
Views: 33
Size:  7.7 KB

Your mileage may vary.
Attached Images
 
Attached Files

[VB6] Clipboard/DataObject Extension Class

$
0
0
The attached class extends VB's Clipboard and Data objects. Change its extension from .txt to .cls after downloading.

1) Support for dragging and pasting virtual files. Virtual files exist in Windows compressed folders. They also can be transfered from any application that wishes to use the registered clipboard format. Outlook, for example, uses it when dragging emails & attachments. VB does not natively support this format

2) Support for unicode file names. The clipboard's & data object's Files collection is not unicode compatible. This class replicates the Files collection that is unicode compatible.

3) Adding custom formats and standard formats to the clipboard that VB does not support natively. This class offers two methods to add data to the clipboard and data object.

The attached class also includes, for convenience, all the methods of VB's clipboard and data objects. If you use this class, you should not need to call some mehtods from it and some methods from VB's objects. However, you are not prevented from using VB's methods for its objects.

Virtual files used here, do not refer to files dragged out of a WinZip file. WinZip extracts the file to a temporary folder and then provides the full path/file name of the file. The dragged data was unzipped and written to file. Windows compressed folders do not do this.

How does the class enable virtual file access? It uses a low-level API to communicate with VB's IDataObject. That object allows us to ask the source for specific information that VB doesn't expose. No existing APIs, that I'm aware of, expose that data either. With this IDataObject, we have full control for retrieval of anything pasted to the clipboard or dropped via OLE.

One more note about virtual files. As mentioned above, don't think of these as actual files. Think of them as simply blobs of data. The file names provided by the source application should be considered for information only. Do not consider those actual file names, they may not be. Could be an Outlook attachment name. Do not assume they do not contain invalid file name characters. To view or save these data blobs, the class includes methods for saving the blobs to file or array.

Examples of a few "file names" dragged out of a Windows compressed folder follows. Notice there is no qualified path. These are not traditional files, just blobs of data.
Code:

license.txt
readme.txt
inc\jpegdecoder.h  << sub-folder items in compressed folder
inc\jpegdecoder.inl
inc\main.h

And here's an email dragged out of Outlook Express:
Code:

Welcome to Outlook Express 6.eml
Will update the class from time to time to repair errors and/or enhance.

The code is well commented. Take the time to read thru the comments at the top of the class and those comments provided with the public methods/properties.
Attached Files

mistaken post

$
0
0
please save my sorry dumb butt from this and allow us to delete our own threads

VB6 Mercator-Projection (or - how to handle lots of small objects on a Picturebox)

$
0
0
Just a small Demo, which demonstrates a Mapping for Latitude/Longitude based Coords into
a Mercator-Projected MapImage (the Background-image of a VB-PictureBox).

What's often preferred (in case one has to handle a lot of "Sub-Objects" or "Sub-Regions"
on such a Container-Control) - is normal VB-Labels or VB-Shape-Objects - usually "inherited"
from an Index-Zero Member of VBs Control-Arrays.

Though Control-Arrays behave a bit clumsy as far as dynamic removing/adding in-between
an existing List of Objects goes... so - that's the reason why I made this post, to break a lance
for a Collection-based approach which takes up and holds the instances of small alternative
ShapeClasses (any of VBs Shape-Like Controls can be replaced by a Class and a few Drawing-Commands).

Here's the complete Class-Code for the alternative Label-Shape which is used in the Demo.
Code:

Option Explicit

Private Declare Function Rectangle& Lib "gdi32" (ByVal hDC&, ByVal X1&, ByVal Y1&, ByVal X2&, ByVal Y2&)

Public Key As String                          'a unique Key for identification (we are added into a Collection under it)
Public Longitude As Single, Latitude As Single 'centerpoint of the Label in Lat/Lng-coords
Public cx As Single, cy As Single              'Pixel-centerpoint of the Label on the PicBox
Public Radius As Long, Color As Long, ToolTipText As String, Hovered As Boolean

Friend Sub Init(Key, cx, cy, Lat, Lng, Optional ByVal Radius& = 3, Optional ByVal Color&, Optional ToolTipText$)
  Me.Key = Key
  Me.cx = cx: Longitude = Lng
  Me.cy = cy: Latitude = Lat
 
  Me.Radius = Radius
  Me.Color = Color
  Me.ToolTipText = ToolTipText
End Sub

Public Sub DrawOn(Cont As PictureBox)
  Cont.ForeColor = vbYellow
  Cont.FillColor = IIf(Hovered, vbCyan, Color)
  Rectangle Cont.hDC, cx - Radius, cy - Radius, cx + Radius, cy + Radius 'GDI is a bit faster than VBs Line-Method
End Sub

The approach in the Zip below is fast, behaves flickerfree - it reports the current MousePos
in both Coord-Systems (Pixels - and Lat/Lng) - it supports hovered highlighting of the current
Shape-Object under the Cursor - as well as dynamic ToolTips for each of the Shape-Objects separately.

It does that in a quite small CodeBase, so for those who have Label-based approaches out there -
compare carefully if that's not something to switch over - even if it's a bit out of your comfort-zone. ;)


Mercator.zip


Edit: As suggested by Pekko further down...
To Newbies who are surprised by the reported timing-results as "-1", "0" or "15" -
that's just the imprecise 15msec-granularity of VBs Timer-Function at play there -
to get more precise results, switch to a better timing-function (which this example doesn't provide).

But as said, the timing is only in this demo, to give a clue that it doesn't take "ages" to re-render
1000 Label-Shapes in a loop. When it's 15msec or lower (as the VB.Timer-based results suggest),
then it's already fast enough.


Olaf
Attached Files

VB6 Render PDF-Files directly (and generate a Preview from the same DrawingRoutine)

$
0
0
Since the PDF-Printing-Topic comes up occasionally - sometimes with recommendations and links to
VB-Modules which try to write a PDF-file directly - the PDF-support of the cairo-lib (wrapped conveniently
in vbRichClient5.dll) is "miles ahead" of all these approaches in terms of functionality (the supported
Drawing-Commands) - and reliability (correctness of the generated PDF-Output).

So here's a small VB6-Demo which shows how to use a vbRichClient5.cCairoSurface instance, which
can also be created as "being of cairo-SurfaceType PDF" instead of the usual "ImgSurface-Type" which
is pixelbased and used for OnScreen-Output (BTW, another true VectorSurface-type is e.g. SVG,
which other than PDF can not only be written directly, but also read).

Anyways, in the end we are able to perform the very same Drawing-Commands against a CairoSurface
of type PDF, the same way as we are wont, when we take a CairoSurface of Type "Image" (which then
just renders antialiased against a Pixel-area to bring out the results of the VectorDrawing-Commands).

That transparently usable multi-surface-support of Cairo is one of the greatest advantages of this library IMO.

The demo will print two Pages (only the first one is currently rendered and shown as an OnScreen-Preview) -
but in the PDF-Document we will end up with a Portrait-Page - followed by a Landscape-Page with somewhat
different (simpler) content ( just wanted to show how to handle the swapping of Page-Orientations "on the go",
so that's the purpose of the simpler Landscape-Page).

Ok, here's the Demo-Code (which references the vbRichClient5 dependency, you will
have to download and install first, to be able to run the Example... from vbRichClient.com).
SimplePDF.zip

And here's a ScreenShot of the VB-OnScreen-Preview of the first Page - accompanied to the right
with the Preview of the PDF-Viewer (adjusted to show the two contained PDF-Document-Pages).



Edit: added a missing info to the RichClient-Library, this PDF-Demo depends on.

Olaf
Attached Files

VB6 Regfree-Usage of your own VB- and other COM-Dlls per DirectCOM-Helper

$
0
0
Think, that this topic is an important one - and deserves its own article.

Hmm, how to begin...

Once there was a time,
in the dark ages,
long before "Manifestos" became available to human beings,
that VB-Developers fought all kinds of Dll-Hell...


Erm, all of them? ...No... ;)

So this is about an approach which is an alternative to the Manifest-triggered SxS-Services
we can use today, reliably and succesfully in usage for nearly two decades now (it was working
already on Win95/Win98 - and still works up to the recent Win8.1 or Win10).

It is IMO the more flexible approach - and relative easy to incorporate into your Apps,
by dropping-in a simple *.bas Module which can remain constant, codewise (no Manifests
to keep in sync with your COM-Dlls TypeLib-informations, in case one recompiles these
Dlls without Binary-Compatibility).

Ok, let's come to the point:
(will try to roll this out a bit, in a style which is hopefully more Newbie-friendly to read).

You plan, to ship your own 'MyActiveX.dll' alongside your 'MyApp.exe' -
in addition to 'ForeignActiveX.dll', which you made use of in your App too.

Well, first thing I would suggest when you plan to ship your App regfree is, to do it "orderly" - by
ensuring a certain Folder-Structure (in your Zip, or whatever you will use for packaging in the end).

What I usually go with is a Folder-Structure as:
\MyApp\
.... \Bin\
.... \Res\
.... MyApp.exe

Aside from MyApp.exe (and maybe a MyAppSettings.ini) not much more in the Apps Root-Folder.

This way the user (after unpacking your regfree deployed App into his own Target-Foder)
can immediately see, "where the Startup-Point is" (and what to click).

Well, forgot to congratulate you first, because when you read this article, you already did the mental step from:
"I need to compile everything into a single Executable"
to:
"I'm far more flexible, when I have certain things in my own, dedicated Dll-Binaries"
accompanied hopefully by:
"I'm also more efficient, when I re-use good work of others, avoiding re-inventions of the wheel"

So, what would reside in your relative Subfolder \Bin\ now? All the Dlls of course:
\MyApp\
.... \Bin\
........ MyActiveX.dll
........ ForeignActiveX.dll
.... \Res\
.... MyApp.exe

To make the approach I'm talking about work, what you need in addition is a Helper-Dll, which is a
Standard-Dll that needs no registering: DirectCOM.dll - so, adding it - your Folder-Structure should look then:
\MyApp\
.... \Bin\
........ DirectCOM.dll
........ MyActiveX.dll
........ ForeignActiveX.dll
.... \Res\
.... MyApp.exe

With such a Folder-Structure in place (and the Bin-Folder filled with the right Binaries),
what you need now in your App is a *.bas Module with the following content:

(in my Demo-Zip for this article, I named this Module: modRegfreeDlls.bas
Code:

'A readymade "PlugIn-Module" you can include into your Projects, to be able to load Classes from COM-Dlls
'without registering them priorily - and just to be clear - there is no "dynamic re-registering" involved -
'DirectCOM.dll will load the appropriate Class-Instances without touching the Systems Registry in any way...
'
'There's 3 Functions exposed from this Module:
'- GetInstanceFromBinFolder ... loads Classes from Dlls located in a SubFolder, relative to your Exe-Path
'- GetInstance              ... same as above - but allowing absolute Dll-Paths (anywhere in the FileSystem)
'- GetExePath              ... just a small helper, to give the correct Exe-Path, even when called from within Dlls
'
'the approach is *very* reliable (in use for nearly two decades now, it works from Win98 to Windows-10)
'So, happy regfree COM-Dll-loading... :-) (Olaf Schmidt, in Dec. 2014)

Option Explicit

'we need only two exports from the small DirectCOM.dll Helper here
Private Declare Function GetInstanceEx Lib "DirectCOM" (spFName As Long, spClassName As Long, Optional ByVal UseAlteredSearchPath As Boolean = True) As Object
Private Declare Function GETINSTANCELASTERROR Lib "DirectCOM" () As String

Private Declare Function LoadLibraryW& Lib "kernel32" (ByVal lpLibFileName&)
Private Declare Function GetModuleFileNameW& Lib "kernel32" (ByVal hMod&, ByVal lpFileName&, ByVal nSize&)
 
'a convenience-function which loads Classes from Dlls (residing in a SubFolder below your Exe-Path)
'just adjust the Optional RelBinFolderName-Param to your liking (currently specified as "Bin")
Public Function GetInstanceFromBinFolder(ByVal ShortDllFileName As String, ClassName As String, _
                                        Optional RelBinFolderName$ = "Bin") As Object
  Select Case LCase$(Right$(ShortDllFileName, 4))
    Case ".dll", ".ocx" 'all fine, nothing to do
    Case Else: ShortDllFileName = ShortDllFileName & ".dll" 'expand the ShortFileName about the proper file-ending when it was left out
  End Select

  Set GetInstanceFromBinFolder = GetInstance(GetExePath & RelBinFolderName & "\" & ShortDllFileName, ClassName)
End Function

'the generic Variant, which needs a full (user-provided), absolute Dll-PathFileName in the first Param
Public Function GetInstance(FullDllPathFileName As String, ClassName As String) As Object
  If Len(FullDllPathFileName) = 0 Or Len(ClassName) = 0 Then Err.Raise vbObjectError, , "Empty-Param(s) were passed to GetInstance"
 
  EnsureDirectCOMDllPreLoading FullDllPathFileName 'will raise an Error, when DirectCOM.dll was not found in "relative Folders"
 
  On Error Resume Next
    Set GetInstance = GetInstanceEx(StrPtr(FullDllPathFileName), StrPtr(ClassName), True)
  If Err Then
    On Error GoTo 0: Err.Raise vbObjectError, Err.Source & ".GetInstance", Err.Description
  ElseIf GetInstance Is Nothing Then
    On Error GoTo 0: Err.Raise vbObjectError, Err.Source & ".GetInstance", GETINSTANCELASTERROR()
  End If
End Function

'always returns the Path to the Executable (even when called from within COM-Dlls, which resolve App.Path to their own location)
Public Function GetExePath(Optional ExeName As String) As String
Dim S As String, Pos As Long: Const MaxPath& = 260
Static stExePath As String, stExeName As String
  If Len(stExePath) = 0 Then 'resolve it once
    S = Space$(MaxPath)
    S = Left$(S, GetModuleFileNameW(0, StrPtr(S), Len(S)))
    Pos = InStrRev(S, "\")
   
    stExeName = Mid$(S, Pos + 1)
    stExePath = Left$(S, Pos) 'preserve the BackSlash at the end
    Select Case UCase$(stExeName) 'when we run in the VB-IDE, ...
      Case "VB6.EXE", "VB5.EXE": stExePath = App.Path & "\" 'we resolve to the App.Path instead
    End Select
  End If
 
  ExeName = stExeName
  GetExePath = stExePath
End Function

Private Sub EnsureDirectCOMDllPreLoading(FullDllPathFileName As String)
Static hDirCOM As Long
  If hDirCOM Then Exit Sub  'nothing to do, DirectCOM.dll was already found and pre-loaded
  If hDirCOM = 0 Then hDirCOM = LoadLibraryW(StrPtr(GetExePath & "DirectCOM.dll"))
  If hDirCOM = 0 Then hDirCOM = LoadLibraryW(StrPtr(GetExePath & "Bin\DirectCOM.dll"))
  If hDirCOM = 0 Then hDirCOM = LoadLibraryW(StrPtr(GetExePath & "RC5Bin\DirectCOM.dll"))
  If hDirCOM = 0 Then hDirCOM = LoadLibraryW(StrPtr(App.Path & "\DirectCOM.dll"))
  If hDirCOM = 0 Then hDirCOM = LoadLibraryW(StrPtr(Left$(FullDllPathFileName, InStrRev(FullDllPathFileName, "\")) & "DirectCOM.dll"))
  If hDirCOM = 0 Then Err.Raise vbObjectError, Err.Source & ".GetInstance", "Couldn't pre-load DirectCOM.dll"
End Sub

With that module in place, you have now two globally reachable (Public) Functions available:
- GetInstanceFromBinFolder(...)
- GetInstance(...)

The first one is the more conveniently usable one, because it saves you from giving
"Full explicit Paths to your Dll-Binaries", so for ActiveX-Dlls in your own Bin-Folder,
all you need to instantiate a Class from one of them is e.g.:

Code:

Dim oMyClass
Set oMyClass = GetInstanceFromBinFolder("MyActiveX", "cMyClass")
    oMyClass.DoSomething

Note, how the above Form resembles the well-known ProgID-based instancing per CreateObject:
Code:

Dim oMyClass
Set oMyClass = CreateObject("MyActiveX.cMyClass")
    oMyClass.DoSomething

And in fact, both versions accomplish the same thing - both create a new Object-Instance - just that
CreateObject needs a registered version of 'MyActiveX.dll', whilst GetInstanceFromBinFolder does not.

The second available Function from the *.bas Module (GetInstance) is just the explicit form,
which you can give a full absolute path into the FileSystem, to specify a certain Dll ...
otherwise the behaviour (and results) are the same as those from GetInstanceFromBinFolder.

Well, that's it already - a Helper-*.bas Module (in conjunction with a Helper-Dll in your Bin-Folder)
can ensure regfree loading, over a relative easy to use function (GetInstanceFromBinFolder).

You have to make sure though, that you use this Function now consequently throughout
your whole App, when it comes to the instantiation of Classes from your regfree shipped Dlls.

To ensure that, you should scan through your whole App, using a project-wide Code-search for
the String: [New ] (.... leaving out the brackets of course - but include the space-char at the end).

This will stop at all code-lines where you do an Object-Instantiation - change all New MyClass
occurences then into the appropriate GetInstanceFromBinFolder(...) replacements - of course
only for Classes which are defined in those Dlls - one doesn't need to replace the instantiation
of a normal VB-Collection - or an ADO-Recordset, since those are always available directly
(contained in the VB-Runtime or in case of ADO - coming preinstalled on a given System).

I know - if your Project is not a small one, this is quite a boring "Identify-And-Paste"-task
but not that time-consuming as one might think (I never needed more than 3-10 minutes for
those replacements, even in larger projects and with "double-checking").

So, that's it with regards to describing the usage of a regfree-alternative to SxS-Manifests.

The latest version of DirectCOM.dll is contained in the vbRichClient5-BaseDlls package on:
http://vbrichclient.com/#/en/Downloads.htm

What remains is a few words to the following Demo, in case you want to use this as a first
Code-base for your own tests:RegfreeDeployment.zip

I've tried to make it a real-world example, which involves also your own compiled ActiveX-Dll.

So, before starting the Demo Project-File: RegfreeDeploymentOfDlls.vbp ...
You should go one Folder-Deeper into: \TestDllProject\ ...
Start-up the ActiveX-Dll-Project: MyTest.vbp there ...
And compile the appropriate Dll from it into the \Bin\ Folder we already talked about above.

What this Demo shows in addition, is a scenario including some these "ForeignActiveX.dlls" which
were mentioned earlier already (using the 3 Base-Dlls of the vbRichClient-framework as an example -
since one of these Dlls, DirectCOM.dll, is needed anyways for the approach to work).

So, after downloading the vbRC5BaseDlls.zip - make sure you copy all 3 Dlls it contains:
DirectCOM.dll
vbRichClient5.dll
vb_cairo_sqlite.dll
Into the Demos \Bin\ Folder too.

So, what you will need to end up with, before starting the Main-Project: RegfreeDeploymentOfDlls.vbp
is the following FolderStructure (reusing the Schema I've introduced above):

\RegfreeDeployment\
.... \Bin\
........ DirectCOM.dll
........ MyTest.dll
........ vbRichClient5.dll
........ vb_cairo_sqlite.dll
.... \Res\
........ BackGround.jpg
........ SomeSvgIcon.svg
........ SomePngIcon.png
.... RegfreeDeploymentOfDlls.vbp
.... modRegfreeDlls.bas
.... modMain.bas
.... fTest.frm

If that above Folder-Structure is given, then you will succeed in running the Demo, which
then should come up this way:



Olaf
Attached Files

WinpkFilter VB6 Samples

$
0
0
The WinpkFilter development kit no longer includes VB6 samples. Version 3.2.3 has added support for IPv6, resulting in a number of changes to the data formats. I have taken the liberty to update the older samples to support the newer formats, and with permission, I am posting them here.

Unfortunately I still have not got the low level filter table to load, but I will post the results upon completion.

J.A. Coutts
Attached Files

VB6 Handling of Alpha-Layered Windows with vbRichClient5

$
0
0
Since it was asked in another thread, if there is an easy way to deal with Layered-Windows
in conjunction with the cairo-Drawing of the RC5....

Yes, of course there is - not provided by cairo itself, but by the new Form-Engine (Classes of type cWidgetForm).

If the task is, to use a Layered-Window in conjunction with a VB-Form (on top of a hosted Control on that
VB-Form, which could be e.g. a Video-Control which is playing a Stream or something), then one would
have to provide a synchronizing between the current VBForm- or VB-Control-Position - and the Position of the
Layered Window (the System doesn't support Child-Windows for layering - they currently need to be TopLevel ones).

In this Demo (to avoid SubClassing - thus making it a bit more robust) I've used a Timer, to keep the layered
Window following the desired position on top of the VB-Form (which acts as the "leading Mother-Goose").

Ok, so the following code-snippet shows already, what we need exactly (within a normal VB-Form):
- fOverlay (of type cWidgetForm)
- wOverlay (a small User-Widget, which renders the Png-Images (and a small Animation)
- and the timer for the Position-Syncing

Code:

Private WithEvents fOverlay As cWidgetForm, wOverlay As cwOverlay, WithEvents tmrPosSync As cTimer
 
Private Sub Form_Load()
  Cairo.ImageList.AddImage "P1", App.Path & "\P1.png"
  Cairo.ImageList.AddImage "P2", App.Path & "\P2.png"
 
  Set fOverlay = Cairo.WidgetForms.CreateChild(Me.hWnd, True, False)
  Set wOverlay = fOverlay.Widgets.Add(New cwOverlay, "Overlay")
      wOverlay.Init "P1", "P2"

  Set tmrPosSync = New_c.Timer(20, True)
End Sub

At the top of the above Form-Load procedure, we loaded and stored two Png-Images in the global Imagelist.
These are the two "Bubbles", you see at the left and right ends in the following ScreenShot:



And aside from the Reposition-Code...:
Code:

Private Sub Reposition(Optional ByVal IsResize As Boolean)
Dim x&: x = Left / Screen.TwipsPerPixelX - 56
Dim y&: y = (Top + Height / 2) / Screen.TwipsPerPixelY - 56

  fOverlay.Move x, y, Width / Screen.TwipsPerPixelX + wOverlay.ImgWidth - 7, wOverlay.ImgHeight
 
  With wOverlay.Widget
    If Not IsResize And GetActiveWindow = hWnd And .Alpha < 1 Then .Alpha = .Alpha + 0.03: .Refresh
    If Not IsResize And GetActiveWindow <> hWnd And .Alpha > 0 Then .Alpha = .Alpha - 0.08: .Refresh
  End With
End Sub

There's not much more in our hosting VB-Form.

That we deal with a real Top-Level-Window here, becomes more apparent when you look at this Shot:


Ok, so the RC5-cWidgetForm-Classes (when hosting a TopLevel-Window) can handle Layering without
any problem - the philosophy there being, that "anything you don't draw is truly invisible".

So, that something *became* visible was ensured by the small cwOverlay-Widget (less than 30 lines of code):

Code:

Option Explicit
 
Public ImgWidth As Long, ImgHeight As Long, wAnim As cwAnimation
Private mImgKey1 As String, mImgKey2 As String

'****---- Start of cwImplementation-Conventions ----****
Private WithEvents W As cWidgetBase

Private Sub Class_Initialize()
  Set W = Cairo.WidgetBase '<- this is required in each cwImplementation...
  Set wAnim = Widgets.Add(New cwAnimation, "Anim")
End Sub

Public Property Get Widget() As cWidgetBase: Set Widget = W: End Property
Public Property Get Widgets() As cWidgets:  Set Widgets = W.Widgets: End Property
'****---- End of cwImplementation-Conventions ----****
 
Public Sub Init(ImgKey1, ImgKey2)
  mImgKey1 = ImgKey1: ImgWidth = Cairo.ImageList(mImgKey1).Width
  mImgKey2 = ImgKey2: ImgHeight = Cairo.ImageList(mImgKey2).Height
End Sub

Private Sub W_ContainerResize()
  W.Alpha = 0
  W.Move 0, 0, W.Parent.Width, W.Parent.Height
  wAnim.Widget.Move 0.8 * ImgWidth, 0, W.Width - 1.77 * ImgWidth, W.Height * 0.9
End Sub

Private Sub W_Paint(CC As cCairoContext, ByVal xAbs As Single, ByVal yAbs As Single, ByVal dx_Aligned As Single, ByVal dy_Aligned As Single, UserObj As Object)
  CC.RenderSurfaceContent mImgKey1, 0, 0, , , , W.Alpha
  CC.RenderSurfaceContent mImgKey2, dx_Aligned - ImgWidth, 0, , , , W.Alpha
End Sub

The above Widget is itself Parent of an additional Widget (the one which ensures the "Sinuid Animation").
But I will leave out the 40 lines of Code for that Widget here - just take a look at the Zip, which contains
the complete Demo: AlphaLayering.zip

Happy layering... :)

Olaf
Attached Files

Simple "Clone Stamp Tool" Demo

$
0
0
Put 2 PictureBoxes on your form. Make sure they both have these properties:
Appearance = Flat
AutoRedraw = True
Border Style = None
Picture = a picture that is small enough to fit in a picture box that is relatively small (320x240 is good for this demo)
ScaleMode = Pixel

Set these properties on your form:
ScaleMode = Pixel


Put a command button on your form.

Put all this code in your form:
Code:

Dim a As ImgObj
Dim StartX As Long
Dim StartY As Long


Private Sub Command1_Click()
Set a = Nothing
End Sub

Private Sub Picture1_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
If Button <> 1 Then Exit Sub
If (a Is Nothing) = False Then Exit Sub
Set a = New ImgObj
StartX = X
StartY = Y
End Sub

Private Sub Picture1_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
Dim X0 As Long
Dim X1 As Long
Dim Y0 As Long
Dim Y1 As Long
If Button <> 1 Then Exit Sub
If a Is Nothing Then Exit Sub
If a.ImageInited Then Exit Sub
If X > StartX Then
    X0 = StartX
    X1 = X
Else
    X0 = X
    X1 = StartX
End If
If Y > StartY Then
    Y0 = StartY
    Y1 = Y
Else
    Y0 = Y
    Y1 = StartY
End If
If a.InitImage(X1 - X0 + 1, Y1 - Y0 + 1) = False Then
    Set a = Nothing
    Exit Sub
End If
a.BltFromDC Picture1.hDC, X0, Y0
End Sub

Private Sub Picture2_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
If Button <> 1 Then Exit Sub
If a Is Nothing Then Exit Sub
If a.ImageInited = False Then Exit Sub
a.BltToDC Picture2.hDC, X, Y
Picture2.Refresh
End Sub





Create a class, and call it ImgObj. Then put this code in that class:
Code:

Private Declare Function GetDC Lib "user32.dll" (ByVal hwnd As Long) As Long
Private Declare Function ReleaseDC Lib "user32.dll" (ByVal hwnd As Long, ByVal hDC As Long) As Long
Private Declare Function CreateCompatibleDC Lib "gdi32.dll" (ByVal hDC As Long) As Long
Private Declare Function DeleteDC Lib "gdi32.dll" (ByVal hDC As Long) As Long
Private Declare Function CreateCompatibleBitmap Lib "gdi32.dll" (ByVal hDC As Long, ByVal nWidth As Long, ByVal nHeight As Long) As Long
Private Declare Function SelectObject Lib "gdi32.dll" (ByVal hDC As Long, ByVal hObject As Long) As Long
Private Declare Function DeleteObject Lib "gdi32.dll" (ByVal hObject As Long) As Long
Private Declare Function BitBlt Lib "gdi32.dll" (ByVal hDestDC As Long, ByVal X As Long, ByVal Y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long



Dim ImageHandle As Long
Dim DCHandle As Long
Dim OldImageHandle As Long
Dim ImgInited As Boolean

Dim PicW As Long
Dim PicH As Long

Public Event GetImageParams(ByRef Width As Long, ByRef Height As Long)

Public Property Get hImage()
hImage = ImageHandle
End Property

Public Property Get hDC()
hDC = DCHandle
End Property

Public Property Get Width()
Width = PicW
End Property

Public Property Get Height()
Height = PicH
End Property

Public Property Get ImageInited() As Boolean
ImageInited = ImgInited
End Property


Private Sub Class_Initialize()
Dim tempDC As Long
tempDC = GetDC(0)
DCHandle = CreateCompatibleDC(tempDC)
ReleaseDC 0, tempDC
End Sub

Public Function InitImage(ByVal Width As Long, ByVal Height As Long) As Boolean
Dim tempDC As Long
If (PicW > 0) Or (PicH > 0) Then Exit Function
If Width <= 0 Then Exit Function
If Height <= 0 Then Exit Function
PicW = Width
PicH = Height
tempDC = GetDC(0)
ImageHandle = CreateCompatibleBitmap(tempDC, PicW, PicH)
ReleaseDC 0, tempDC
OldImageHandle = SelectObject(DCHandle, ImageHandle)
InitImage = True
ImgInited = True
End Function


Private Sub Class_Terminate()
SelectObject DCHandle, OldImageHandle
DeleteObject ImageHandle
DeleteObject OldImageHandle
DeleteDC DCHandle
End Sub


Public Sub BltToDC(ByVal DestDC As Long, Optional ByVal X As Long, Optional ByVal Y As Long)
BitBlt DestDC, X, Y, PicW, PicH, DCHandle, 0, 0, vbSrcCopy
End Sub

Public Sub BltFromDC(ByVal SrcDC As Long, Optional ByVal X As Long, Optional ByVal Y As Long)
BitBlt DCHandle, 0, 0, PicW, PicH, SrcDC, X, Y, vbSrcCopy
End Sub

[VB6] Faster RTB Code Formatting

$
0
0
The scenario here is a program that allows user scripting in VBScript. This program needs a script IDE to make it easier for users to write, test, and modify their scripts. Instead of a simple text editor, we want to format entered VBScript code in a manner similar to the way VB6.EXE does it. This means more than simple "colorization" but also includes correction of whitespace and punctuation as well as re-formatting statements as they are manually altered.

Performance is a factor because in the real code far more is going on and it occurs during user editing as well as upon loading.


Demo

Stripped down implementation for illustration. Only about 5% of the real thing is included here.

Does not take into account predefined constants, comments, line continuations, or string literals. Does not attempt to correct whitespace and punctuation usage. Also does not include the logic to handle statement by statement user edits.

Merely does some one-pass simplified colorizing of the entire script after loading. Just enough to look interesting.

This is done using four different methods in four different Forms varying only as needed to add optimizations in steps:

  1. RTB.Visible = True (default).
  2. Let RTB.Visble = False at start of formatting, then True again when done. Flawed, see MS KB 189483.
  3. Let RTB.Visible = False at start and make ShowWindow calls per KB article.
  4. Use TOM with Freeze and ITextRange objects.


The four Forms are MDI child Forms within a parent Form. They are run in sequence and timings are displayed for each child Form upon completion. They all use the same large sample script (testcase.txt).


Name:  sshot-sm.png
Views: 78
Size:  16.4 KB


Name:  sshot-timings.png
Views: 52
Size:  2.0 KB


Requirements

To use TOM with the VB6 RichTextBox, Windows 2000 or later is required. This causes RichTextBox to use Riched20.dll in Microsoft Rich Edit 1.0 emulation mode, thus giving us the TOM interfaces to use. TOM is not supported by Riched32.dll.


Links

BUG: Cannot Set RichTextBox Visible Property to False

Text Object Model
Attached Images
  
Attached Files

VB6 how to capture Sound, using CoreAudio (Vista and onwards)

$
0
0
Here's a simple Demo, which is using the CoreAudio-Interface wrapper-classes of the vbRichClient5-framework,
to select a Capture-Device - followed by entering "Stream-Capture-Mode".

Whilst the Stream_Data is rolling in continously - we use an Event of the Class cAudioCaptureClient,
to retrieve Peak- and FFT-Data only... (no MP3-conversion of the SoundData, nor any FileWriting is done,
only visualizing takes place)

Here's what's needed in a normal VB-Form:

Code:

Option Explicit
 
Private CapDev As cMMDevice, WithEvents ACC As cAudioCaptureClient, PeakAndFFT As New cDrawPeakAndFFT

Private Sub Form_Load()
  ScaleMode = vbPixels
 
  Set CapDev = New_c.MMDeviceEnumerator.GetDefaultAudioEndpoint(eCapture, eCommunications)
  Caption = CapDev.OpenPropertyStore.GetDevice_FriendlyName & " (" & CapDev.GetStateName & ")"
 
  Set ACC = New_c.AudioCaptureClient
      ACC.InitOn CapDev, 44100
      ACC.RaiseMeterEvents = True
      ACC.RaiseFFTEvents = True
      ACC.FFTInputLevelFac = 0.8
      ACC.StartStream
End Sub

Private Sub ACC_MeterInfo(ByVal LeftPeak As Single, ByVal RightPeak As Single, LeftFFT() As Single, RightFFT() As Single)
  'let's give the Peak-Values a logarithmic scaling (also between 0 and 1), before passing them on...
  LeftPeak = Log(1.00000000000001 + LeftPeak * 9) / 2.303
  RightPeak = Log(1.00000000000001 + RightPeak * 9) / 2.303

  PeakAndFFT.Draw LeftPeak, RightPeak, LeftFFT, RightFFT
  PeakAndFFT.Srf.DrawToDC hDC, 0, 0, ScaleWidth, ScaleHeight
End Sub
 
Private Sub Form_Unload(Cancel As Integer)
  If Not ACC Is Nothing Then ACC.StopStream: Set ACC = Nothing
  Set CapDev = Nothing
  Set PeakAndFFT = Nothing
End Sub

Private Sub Form_Terminate()
  If Forms.Count = 0 Then New_c.CleanupRichClientDll
End Sub

In Form_Load above, the line:
... MMDeviceEnumerator.GetDefaultAudioEndpoint(eCapture, eCommunications)

will usually resolve to the Microphone-Device which is built into your NoteBook or Tablet
(or connected over Mike-In).

There's different combinations of the Enums (the first one responsible for the direction, the second for the "Role") as e.g.:
- (eCapture, eMultimedia) ... will typically resolve to a device on your LineIn-port, if connected
- (eRender, eConsole) typically resolves to the Default-SoundOutput (Speakers or Phones)
- (eRender, eMultimedia) often resolving to (digital) 5.1 Output-Ports e.g. when watching Video over HDMI

The Roles are (since Win7) supported in a way, that the User can define different devices for
those different "Role-Tasks".

However, it's also possible to enumerate Devices, to select one later - e.g. using this code:
Code:

Dim i As Long, Dev As cMMDevice
 Debug.Print "Capture-Devices"
 With New_c.MMDeviceEnumerator.EnumAudioEndpoints(eCapture, DEVICE_STATEMASK_ALL)
  For i = 0 To .GetCount - 1
    Set Dev = .Item(i)
    Debug.Print , Dev.GetStateName, Dev.OpenPropertyStore.GetDevice_FriendlyName
  Next
 End With
 Debug.Print vbLf; "Render-Devices"
 With New_c.MMDeviceEnumerator.EnumAudioEndpoints(eRender, DEVICE_STATEMASK_ALL)
  For i = 0 To .GetCount - 1
    Set Dev = .Item(i)
    Debug.Print , Dev.GetStateName, Dev.OpenPropertyStore.GetDevice_FriendlyName
  Next
 End With

I got the following output here on my Machine:
Code:

Capture-Devices
              ACTIVE        Mikrofon (High Definition Audio-Gerät)
              NOTPRESENT    CD-Audio (2- High Definition Audio-Gerät)
              NOTPRESENT    Mikrofon (Sennheiser USB Headset)
              NOTPRESENT    Mikrofon (2- High Definition Audio-Gerät)
              NOTPRESENT    Mikrofon (Sennheiser USB Headset)

Render-Devices
              NOTPRESENT    Lautsprecher (Sennheiser USB Headset)
              ACTIVE        Lautsprecher (High Definition Audio-Gerät)
              NOTPRESENT    Kopfhörer (2- High Definition Audio-Gerät)
              NOTPRESENT    Lautsprecher (2- High Definition Audio-Gerät)
              NOTPRESENT    Lautsprecher (2- Logitech USB Speaker)

The interfaces are (in comparison to the old Mixer/WaveIn/WaveOut-APIs) quite clear -
but nevertheless would require some learning on your part, here's the MSDN-link to the
CoreAudio-Interface-List in all its glory - you will find the most important ones in the RC5,
prefixed with a small 'c' instead of an 'I': http://msdn.microsoft.com/en-us/libr...=vs.85%29.aspx

Here's the complete Demo, which visualizes Peak- as well as "FFTed"-Spectrum-Values (containing,
in addition to the Form-Code above only one additional small Drawing-Class, cDrawPeakAndFFT...

AudioCapture.zip

Here's a screenshot, what the Demo will put out with the help of the Drawing-Class:


Olaf
Attached Files

VB6 a simple wrapper for the VBA.Collection with (much) faster Indexed-Access

$
0
0
The title says it all - this is a simple Collection-Wrapper which can act as a compatible
Replacement for the VBA.Collection - the fast Hash-Access of the VBA.Collection is used further -
but all the disadvantages with indexed access are avoided for the most typical use-cases.

At this occasion there were also some other enhancements made as:
- an Exists Method to check for Keys
- a RemoveAll-method
- can hand out Value- and Key-Arrays in appropriate Variant- or String-Arrays (with userdefinable LBound)
- in addition to the compatible Item-Method we have ItemByIndex and KeyByIndex too
- The unnerving behaviour to not allow Add(..., BeforeIndex) with an Index at constantly 1 (in case of Count=0) is gone

It should be also possible, to implement the Item-property also in Write-Direction (with Property Let/Set),
but I leave that for interested colleagues to explore - currently the internally used Collection-Instance-Types,
which were pointed out to me in this thread for the first time (structs posted by jbarnett74 - then refined with a few more
explanations by Bonnie West) - these Structures are currently only used within this wrapper in "safe-read-only-fashion".

Those who try themselves at implementing Write-Access for the Values over the Item-Property,
should test this accordingly (back and forward), because these Structs contain quite a few
"still unknown members", which partly are used for the Hashing-functionality of the VB-Collection,
but some of them could also store additional information, which is related to the Value-member
of the Element-Struct - so changing the Value-Member is alluringly simple - since it seems easily
accessible also for the Write-Direction - but one doesn't know yet, if changing its Value requires
also changes in a few so far unknown members (which the Add-Method of the VB-Collection might
automatically ensure under the covers).

So, as the implementation comes currently - it is "playing things safe" - no real risk in using it, especially
when you compile it into a dedicated ActiveX-Dll-Binary, to give the Class more IDE-safety with regards
to cleanup, even when the Stop-Button was pressed in the IDE (it needs to run over its Class_Terminate-
Event to clear things up properly).

Ok, so here is the Implementation- and Demo-Code (with a small performance-test):
CollectionEx.zip

And here the appropriate ScreenShot:


An additional advice for those who plan to compile it into an ActiveX-Dll-Binary,
all extended native Compiler-Options are allowed *aside* from the "Aliasing-Option"
(which should remain unchecked in this case of SafeArray-Pointer-usage).

Olaf
Attached Files

Tooltips, Balloon Tips, Tray Notofications [vbRichClient]

$
0
0
Here's a dll I've created that provides visually nicer and enhanced (functionality-wise) tooltips. It is dependent on Olaf's vbRichClient (the nice drawing comes via Cairo functionality) but is intended for use with regular VB6 projects, as illustrated in the demo.

Features:
- Regular tooltips (can be mult-line so that's an improvement right there!)
- Balloon Tips (Caps Lock is on kind of information)
- Tray Notifications (the pop-up kind)
- Custom Content (display anything you like; pictures, drawings, text, etc)

All the features above are illustrated in the demo. Here's a few images:

Name:  custom.JPG
Views: 36
Size:  53.0 KBName:  balloons.JPG
Views: 34
Size:  26.4 KBName:  tray.JPG
Views: 29
Size:  10.2 KB

The demo is uploaded as a Project Group; just compile the dll for use in your own projects.

Attachment 121873
Attached Images
   
Attached Files

VB6 - Packet Ananlyzer

$
0
0
PacketVB Version 2 is a Network Packet Analyzer. It utilizes Windows Packet Filter Kit 3.2.3 from NT Kernel Resources, which is available for download free of charge for personal use. This version of the Filter Kit supports IPv6, and loads on all supported versions of Windows (including 64 bit). After upgrading Version 1 to work with this latest version of "NDISRD.sys", I discovered that it did not work properly on Win 8.1. The data view window requires a fixed width font, for which I chose the Terminal Font due to it's limited width. This font exists on Win 8.1 (dosapp.fon), but is not enabled by default. The font that Windows chose to use in it's place exceeded the width allowed for in the data view window.

So I chose to use the Courier New Font instead. This caused a major rewrite of the program because I had to change all the allowances for width.

PacketVB also uses COMDLG32.OCX, MSFLXGRD.OCX, and mscomctl.ocx, which the user must have available.

PacketVB supports IPv6, but as usual it has undergone very limited testing for this particular protocol because of the lack of a native IPv6 network other than local. If someone has access to such a Wide Area Network, I would appreciate feedback.

J.A. Coutts
Attached Images
 
Attached Files

VB6 create DDL-Schema-instructions from JET-MDBs (to apply to a new created *.mdb)

$
0
0
As the title says - the Demo will show, how to create DDL-SQL-instructions from a given *.mdb-File,
using two small Classes (cJETDDL and cJETDDLTable).

The DDL is created for existing:
- Table-Definitions
- Index-Definitions
- Foreign-Key relations
- Views and Queries

In the example I'm using (also coming included in the Demo-Zip) the "official JET-Demo-DB" (NWind.mdb).

There's a little GUI around the functionality of the two above mentioned Classes, which shows
the Text-Output they did produce for the different kinds of DDL-Statements.

Here's a ScreenShot:


And here is the Demo-zip.

I think the whole thing is educational for those who want to learn DDL, to define - or alter
their DB-Schemas "per Code".

Olaf

VB6 - Math Utility: Clipping polygons including degenerate cases

$
0
0
This is an implementation of Kim & Kim's extension of the Greiner-Hormann's polygon clipping algorithm to include degenerate cases.

Degenerate cases occur e.g. when a polygon's vertex lies on an edge or vertex of the other polygon.

The method works based on linked lists -implemented in the vertex, contour and polygon classes- and follows the guidelines given in this paper (used to be available in the web and I have a pdf copy):

Dae Hyun Kim and Myoung-Jun Kim
"An extension of polygon clipping to resolve degenerate cases"
Computer-Aided Design and Applications, Vol. 3, pp 447–456 (2006)

The 2 polygons are referred to as the subject and the clipping polygon. Either one can have more than one branch (contour). Contours can be nested and the points constituting them may be given in any orientation, clockwise or counterclockwise.

However, the contours must be not self intersecting.

In this demo, the user can input new polygons or load a number of convenient demo cases provided.
Attached Files

Using Line Input for Unicode (UTF-8 included), the fast way

$
0
0
For some days ago I was involved in the word count routines. I realize that a speed contest for some extra ms was not what we call productive. Productive can be a searching utility for those words. So I decide to make a search utility.
For that task I make some functions. One set of functions used for loading the text. Olaf’s Schmidt routine ReadUnicodeOrANSI was perfect to read any kind of text (as that text follows some rules). But I want the old fashion Line Input to fill my document class. So I make a combination. I use line input, for ANSI and Unicode LE16, BE16, UTF8, with my own buffer. I realize that using LOF or SEEK in each reading cost a huge delay. For using BINARY files VB didn’t give buffers, and that is right if you have to read and write in one session. But here we use binary file for read only, so we need a buffer. But this buffer maybe not as those from vb. We can use buffers with more length, here I use 327680 bytes for buffer.
For ANSI reading we need to read one byte from buffer. For LE16 or BE16 we need to read one word (2 bytes). For UTF8 is a little complicated, but we can found the end of line without parse the code that define if a char has one or two or more bytes length. Exactly we use a small parser that read bit 8 (&h80). If that is clear then this is a one byte char. Any other byte from any multi byte char has this bit set to 1. Because we have to get bytes and translate them to LE16, we place any char to a second buffer, and then we do the translation.
The second set of functions is for INSTR and INSTRREV with any LCID (locale ID). Because we want to use VBtextcompare with any LCID, we have to make our own routines (For OS better from Windows XP there are API for that but we can easy make what we want…as you can see in the source)

You need the bible13.txt, (it is in ANSI fromat but you can open it and save again from notepad, using any unicode fromat)
Info for other wordcount routines here

Name:  find.jpg
Views: 49
Size:  41.3 KB

In the text box we see a preview of a maximum of 9 lines (we don't feed textbox with all text)

A docpara = 0 needed if we want to place new document in the doc object
So change this Sub in Document object
Quote:

Sub EmptyDoc()
delDocPara = 0
docpara = 0
docmax = 20 '
ReDim para(1 To docmax)
ReDim DocParaBack(0 To docmax)
ReDim DocParaNext(0 To docmax)
End Sub
Attached Images
 
Attached Files

VB6 - DNS Monitor

$
0
0
DNS Monitor Version 2.5 is a DNS query capture and display utility. It utilizes Windows Packet Filter Kit 3.2.3 from NT Kernel Resources, which is available for download free of charge for personal use. This version of the Filter Kit supports IPv6, and loads on all current versions of Windows (including 64 bit). Upgrading Version 1 to work with this latest version of "NDISRD.sys" required a fair amount of change, so I have posted this latest version separately. This version has a few more options, including the ability to filter out all but IPv4 or IPv6 DNS queries. Like version 1, it also has the abilty to examine all packets and display both IPv4 and IPv6 queries. This mode is of course quite a bit more resource hungry.

DNS Monitor also uses MSCOMCTL.OCX, which the user must have available. This version does not include the service component, as the demand for that component was very low and involved a substantial amount of rework.

DNS Monitor supports IPv6, but as usual it has undergone very limited testing for this particular protocol because of the lack of a native IPv6 network other than local. If someone has access to such a Wide Area Network, I would appreciate feedback.

J.A. Coutts
Attached Images
 
Attached Files

How to add a System Tray icon to your program

$
0
0
This won't let you click (or double click) on the system tray (aka notification area) icon to restore your program from a minimized state. It won't let you right click on it to bring up a context menu to access various features of your program. Those are things that I haven't figured out how to implement yet. But it will let you cause an icon to appear down there, and a bit more. That bit more is that it will display a notification bubble with a customizable title and content (which you can click on to make the bubble go away), when the icon first appears, and will also display a "tool tip" when you hover your cursor over the icon.

Here's the code for this:
Code:

Private Declare Function Shell_NotifyIcon Lib "shell32" Alias "Shell_NotifyIconA" (ByVal dwMessage As Long, lpData As NOTIFYICONDATA) As Long
Private Declare Function LoadImage Lib "user32" Alias "LoadImageA" (ByVal hInst As Long, ByVal lpszName As String, ByVal uType As Long, ByVal cxDesired As Long, ByVal cyDesired As Long, ByVal fuLoad As Long) As Long
Private Declare Function DestroyIcon Lib "user32" (ByVal hIcon As Long) As Long

Private Type NOTIFYICONDATA
    cbSize As Long
    hWnd As Long
    uID As Long
    uFlags As Long
    uCallbackMessage As Long
    hIcon As Long
    szTip As String * 128
    dwState As Long
    dwStateMask As Long
    szInfo As String * 256
    uVersion As Long
    szInfoTitle As String * 64
    dwInfoFlags As Long
    guidItem(3) As Long
    hBalloonIcon As Long
End Type

Private Const NOTIFYICON_VERSION As Long = 3
Dim hIcon As Long
Dim a As NOTIFYICONDATA

Private Const IcoFile As String = "Path To Icon File Goes Here"

Private Sub Form_Load()
hIcon = LoadImage(0, IcoFile, 1, 16, 16, 16)
a.cbSize = Len(a)
a.uFlags = 2 + 4 + 16
a.uVersion = NOTIFYICON_VERSION
a.szInfo = "Test Message"
a.szInfoTitle = "Test"
a.hIcon = hIcon
a.hBalloonIcon = hIcon
a.dwInfoFlags = 4
a.hWnd = Me.hWnd
a.szTip = "Test Tip"
GetNullPaddedString a.szInfo
GetNullPaddedString a.szInfoTitle
GetNullPaddedString a.szTip
Shell_NotifyIcon 0, a
End Sub

Private Sub Form_Unload(Cancel As Integer)
Shell_NotifyIcon 2, a
DestroyIcon hIcon
End Sub

Private Sub GetNullPaddedString(ByRef Text As String)
Dim Text2 As String
Text2 = RTrim$(Text)
Text = Text2 & String$(Len(Text) - Len(Text2), vbNullChar)
End Sub

Note that where it says Private Const IcoFile As String = "Path To Icon File Goes Here" you will have to change the text "Path To Icon File Goes Here" to an actual path to an ICO file.

VB - Change color of font in ListView Row when highlighted

$
0
0
Hi, in the below script I have changed the font of the ListView row based on an expiration date. How can I keep the color of the font when the row is highlighted? For example, if my font is red for a specific row it turns to white when that row is selected.

Thanks for any help!

'Loop through records and see if colors need to be changed due to expiration date
For Counter = 1 To lstUser.ListItems.Count
Set Item = lstUser.ListItems.Item(Counter)

If CDate(Item.SubItems(11)) <= Date Then
If Item.Selected Then
lstUser.SelectedItem.ForeColor = vbRed
End If
Item.ForeColor = vbRed
Item.ListSubItems(1).ForeColor = vbRed
Item.ListSubItems(2).ForeColor = vbRed
Item.ListSubItems(3).ForeColor = vbRed
Item.ListSubItems(4).ForeColor = vbRed
Item.ListSubItems(5).ForeColor = vbRed
Item.ListSubItems(6).ForeColor = vbRed
Item.ListSubItems(7).ForeColor = vbRed
Item.ListSubItems(8).ForeColor = vbRed
Item.ListSubItems(9).ForeColor = vbRed
Item.ListSubItems(10).ForeColor = vbRed
Item.ListSubItems(11).ForeColor = vbRed
Item.ListSubItems(12).ForeColor = vbRed
ElseIf CDate(Item.SubItems(11)) < Date + 30 Then
lstUser.Item(Counter).ForeColor = RGB(255, 153, 0)
lstUser.Item(Counter).ListSubItems(1).ForeColor = RGB(255, 153, 0)
lstUser.Item(Counter).ListSubItems(2).ForeColor = RGB(255, 153, 0)
lstUser.Item(Counter).ListSubItems(3).ForeColor = RGB(255, 153, 0)
lstUser.Item(Counter).ListSubItems(4).ForeColor = RGB(255, 153, 0)
lstUser.Item(Counter).ListSubItems(5).ForeColor = RGB(255, 153, 0)
lstUser.Item(Counter).ListSubItems(6).ForeColor = RGB(255, 153, 0)
lstUser.Item(Counter).ListSubItems(7).ForeColor = RGB(255, 153, 0)
lstUser.Item(Counter).ListSubItems(8).ForeColor = RGB(255, 153, 0)
lstUser.Item(Counter).ListSubItems(9).ForeColor = RGB(255, 153, 0)
lstUser.Item(Counter).ListSubItems(10).ForeColor = RGB(255, 153, 0)
lstUser.Item(Counter).ListSubItems(11).ForeColor = RGB(255, 153, 0)
lstUser.Item(Counter).ListSubItems(12).ForeColor = RGB(255, 153, 0)
End If

Next Counter
Viewing all 1321 articles
Browse latest View live




Latest Images