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

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 Problems

$
0
0
Hi every one

Mary Christmas and Happy New Year

I hade most komplex problem to solve with VB6-

Using a Hp probook 64 bit and win7pro

After serveral try then I figure out how to do it.

Here comes how I did it.

Install Visual Basic Enterprise

'(Install Visual Studio 8) option

Start Menu go to Microsoft Visual Studio

look for Microsoft Visual Visual Studio 6 Tools

go to Activex control test container

open it

File Menu

go to

Register Controls

new form come up an there you can reg all
ocx or unreg or reg again
after I have done that
my old VB6 and VB5 programs works fine

Hope somone can use it

Best Regards Bonzo 2008

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: 57
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 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

VB6 - Scan file (text format) in Server and Print it to Printer Directly

$
0
0
Dear All,

Can you share the programme for scaning text file in Server folder and continue with print it (the contain of file) to printer

Thanks:)

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

VB6 Base-Widget for tree-like (nested) Query-Design

$
0
0
A small Base-Demo (dependent on vbRichClient5), to show how a seemingly complex,
hierarchical Control can be implemented with only two Base-Widgets.

The visual appearance is quite similar to the jQuery-based implementation here:
http://mistic100.github.io/jQuery-QueryBuilder/

But the Codebase is much smaller (about 250 lines currently, whereas the jQuery-
implementation is about 1700 lines ... when fully completed with the yet missing ComboBoxes
and Field-Value-Widgets, I guess that the VB6-version will end up with about 550 lines).

Here's a ScreenShot what it currently looks like:


- cwQueryGroup (about 160 lines of code - this is the red-bordered Widget with the Buttons)
- cwQueryRule (about 70 lines of code - this is the "Stripe-Widget" with the green Border)

What remains is now only the introducion of 2 cwDropDown-Widgets (one for the FieldNames
and one for the logic-Operators) - and a Handler-Widget for the comparison-value -
which in the simplest case could be a cwTextBox) - the Demo as it currently is, depends only
on RC5 (to make it easier for a first fast test) - the just mentioned additional Widgets for the
Field-Comparison-Logic are located in vbWidgets.dll, which is available as a Zip-Download on:
http://vbrichclient.com/#/en/Downloads.htm
(3rd section - Zip-Download from the GitHub-Repo).

Let me know when there's interest, to complete the current Base-implementation (e.g. later handing over
the Field-List and Field-Types of an ADO- or SQLite-Recordset, then dynamically creating the DropDown-Contents
and dynamically adding the appropriate Field-Value-Input-Widgets, which are matching the selected Fields Type)...

I could help with suggestions and code-snippets, where to plug the missing functionality in, and with
general "how-to-do-RC5-Widgets"... :)

Here's the Download for the Demo-Code:
QueryDesigner.zip

Hoping this Base-Implemenation is nice and encouraging enough for others, to complete what was
started here - (the Demo already does the nested Tree-Rendering, adding, removing, MouseHovering,
and MouseWheel-based Scrolling when the Widgets run out of Space of their Root-Container -
so the heavy lifting with regards to the graphics-rendering is already "out of the way")...

Olaf
Attached Files

[VB6] Read SMBIOS info w/o WMI

$
0
0
Summary

WMI is a bulky service with a COM-based API that was meant to help computer technicians write administrative maintenance scripts. It isn't meant for application use and if a user stops the service for security reasons relying on it can leave your program high and dry.

One of the things people often fall back on WMI for is system information, particularly information retrieved from the SMBIOS data block. That's usually just fine, since it seldom makes sense for applications to use such information anyway, so WMI admin scripts usually more than suffice.

But some people still want to do this, as unreliable as the SMBIOS info is. So here is an approach that bypasses WMI to get the same information.


The Code

This is a VB6 collection class SmbiosInformation and a small item class SmbiosItem. It requires no 3rd party libraries and makes use of GetSystemFirmwareTable() in Kernel32.dll to retrieve the raw data. Once retrieved it browses (some would say "parses" but we really aren't) the compound structure for data items.

It is important to note that this API entrypoint did not become available until Windows Server 2003 SP1 and Windows XP Professional 64-bit SP3. So effectively none of this applies to pre-Vista versions of Windows, all of which are officially unsupported now anyway.


Limitations, Opportunity

SmbiosInformation is not exhaustive in its browsing and reporting, returning only a subset of the available information.

You could choose to add more items, delete items you do not care about, or change the way some data items are reported. For example the "ChassisType" item is currently reported as a Byte value from 0-127 as stored in the raw data block, but you could translate those to friendly String values instead.

None of this seems very close to "perfect." Depending on the machine you might get various serial number values or you might get an empty String or a String of all 0 characters. You might get "BaseBoardxxxx" items or you might get none of them if the machine doesn't provide them. There is a theoretical way to detect HyperThreading capability, but it fails on some systems, probably because the BIOS is reporting many values according to how it has them set during boot. On some machines the BIOS version comes back as 0.0, which isn't correct.

Lots of String items come back as "To Be Filled By O.E.M." instead of a useful value, others come back as empty Strings.

Some kinds of data can be complex. CPUs are reported by socket, and a given machine may have more than one socket and CPU chip, so SmbiosInformation reports those as sub-collections of data, one per socket. There can be multiple Memory Array entries in the raw data, so SmbiosInformation just sums them.


Helpful References

I found SMBIOS Demystified helpful but really ended up even more confused. It could have been written far better, but the topic really is confusing so I can't fault the author too much. I'm sure not volunteering to do so!

But he did provide a link to System Management BIOS where you can download PDFs of different versions of the actual specs. This is critical information if you want to expand on what the provided code does.


Demo

I have attached a ZIP archive containing these classes and a simple Project1 program that uses them.

The demo gets the information, and then reports results two ways:

  • An initial MsgBox presenting a few values retrieved by key (Name).
  • A full dump in a sortable ListView, retrieved by enumeration.


Name:  sshot.png
Views: 40
Size:  23.4 KB

Full Dump


Useful?

You be the judge. Results are highly variable from machine to machine that I tested. If it is any comfort, if you can't get it this way you can't get it via WMI either.

Of course WMI covers lots of other things too - such as letting people get remote access to your machine! It is not a safe thing to have running at all, but Windows itself is becoming more and more dependent on it. Even some of the administrative Control Panel applets need the WMI Service running to work now.
Attached Images
 
Attached Files

[VB6] Working with Libraries (Win7+)

$
0
0

Windows 7 introduced the Library to the filesystem. But it's no ordinary folder. There are a few reasons you'd want to be able to work directly with these objects in VB... the issue first came up for me when I was writing a search program, and wanted to let the user select a library to search and then automatically search all folders in the library. Another time I came across the issue was for saving... if you pick a library from a save box, what folder should it go to? You need the library default save location. Further down the road, it's possible to actually write a program to manage libaries and even create new ones in VB. For that, I'll create a complete wrapper of IShellLibrary in a class module.

For now, however, I wanted to share a small sample program illustrating the basics of interacting with Library objects through the IShellLibrary interface. This program shows how to display basic Library information, and how to add a folder to an existing library.

As a bonus, it shows how to use a couple of important interfaces in VB- IShellItem and IEnumShellItems.

Note: You'll need to update the project reference to whereever you extract olelib.tlb to.
Alternative: Create a new project, add the reference, then add Form1.frm and modLib.bas.
(although I've never heard of a .tlb capable of being used as a malware vector since it's not executable per-se, the paranoid among you will find the source code that can be put through MKTYPLIB to create a hash-identical olelib.tlb)

Preview function - Getting all folders included in a library:
Code:

Public Function Library_GetFolders(pidlLib As Long, sout() As String) As Long
'WINDOWS 7 AND ABOVE ONLY:
'Given the fully qualified pidl for a library (including new ones besides music/videos/docs/pics)
'returns an array of the folders that are included in the library
Dim isi As IShellItem, isiChild As IShellItem, isiDef As IShellItem
Dim isl As IShellLibrary
Dim iesi As IEnumShellItems
Dim isia As IShellItemArray
Dim sinpt As Long, sinsz As String
Dim sinpt2 As Long, sinsz2 As String
Dim objClsid As GUIDA
Dim hRes As Long, hr As Long
Dim i As Long
ReDim sout(0)


hRes = SHCreateShellItem(0, 0, pidlLib, isi)
  'create a GUID from each CLSID string
  Call CLSIDFromString(StrPtr(CLSID_ShellLibrary), objClsid)
   
  'obtain an interface pointer for idClsid
  hr = CoCreateInstanceISL(objClsid, 0&, _
                      CLSCTX_INPROC_SERVER, _
                      IID_IShellLibrary, _
                      isl)

    Call isl.LoadLibraryFromItem(isi, STGM_READ)

        isl.GetFolders LFF_ALLITEMS, IID_IShellItemArray, isia
       
        isia.EnumItems iesi

        Do While (iesi.Next(1, isiChild, 0) = 0)
            ReDim Preserve sout(i)
            isiChild.GetDisplayName SIGDN_FILESYSPATH, sinpt
            sinsz = BStrFromLPWStr(sinpt, True)
            If sinsz <> "" Then
                sout(i) = sinsz
                i = i + 1
            End If
           
            Set isiChild = Nothing

        Loop
       
If sinpt Then Call CoTaskMemFree(sinpt)
Set isl = Nothing
Set isi = Nothing
Set isia = Nothing
Set iesi = Nothing

End Function

Attached Files

Image Carousel Class [vbRichClient]

$
0
0
Here's a class that you can use to create Image Carousel controls as either standard VB6 User Controls or vbRichClient widgets. This demo shows how to do the former; the UC is just a small wrapper around the class in order to implement the classes functionality and (of course) display it to the user.

This project has a dependency on Olaf's vbRichClient5 dll (http://www.vbrichclient.com)





Note: The demo contains an Icons sub-folder which is empty due to the size of its would-be contents being too large to include in the above zip. You can get all the icons that should be in that folder from here:

http://www.veehive.x10.mx/CarouselDemoIcons.zip

A screenshot:
Attached Images
 
Attached Files

VB6 - Netgear Telnet

$
0
0
I upgraded my Internet connection and discovered that my old Netgear router just didn't have the capacity to keep up with it. I kept that old one around because I had several, and I really appreciated the command mode via Telnet. After some research, I purchased a new Netgear router (WNDR3400). When I checked for open ports, I discovered that port 23 was active on the LAN interface, but when I connected with Telnet, I got nothing. With a little more research, I found that Netgear allows you to enable the Telnet interface by sending it a special packet via a small program called "TelnetEnable.exe". The description given is that it takes the MAC address of the LAN Interface and combines it with the UserID and Password. It then does an MD5 Hash on it along with some byte swapping, and encrypts it all using Blowfish and the key "AMBIT_TELNET_ENABLE+".

I was tempted to try and duplicate the encryption, but Blowfish isn't supported by Microsoft and it is quite an old standard. As well, Telnet is not enabled by default on all modern Microsoft Operating Systems. So I created a small program to duplicate the Telnet Interface called TelNetgear. The TelnetEnable program requires the MAC address of the LAN interface, so the program automatically sends an ARP request to the configured IP address to determine the MAC address residing at that address. This is only good for IPv4, as ARP is not used in IPv6. Instead of a broadcast IP address, IPv6 uses a multicast MAC address (33:33:00:01:00:02).

When TelNetgear attempts to connect with the router, it first uses ShellExecute to call the "TelnetEnable" program. If successful, it will then connect with port 23. The router should respond with the "#" prompt as illustrated below. This Netgear router uses Unix type commands, and is very powerful for it's compact size. You can enter those commands in the lower Textbox, or you can use the commands listed in the yellow Listbox. Those commands are loaded from a text file called "Commands.txt", which can be edited with any standard Text Editor. I have included only a few of the many commands available. My knowledge of the Unix commands is quite limited. The "help" command lists a few, and the "busybox" command lists a few more. But there are more than that (eg. RouterInfo), and viewers are free to offer suggestions.

Some routers require UserID/Password after enabling Telnet, so that logic will have to be added if required. My particular router does not, and that means there is no restriction to access on the local network. If there is any doubt about the security of your local network (for example WiFi access on the same subnet), you should reboot the router after accessing, as this reverts the Telnet interface back to the default condition.

J.A. Coutts
Attached Images
 
Attached Files

[VB6] Common Dialog Replacement - IFileDialog Vista+

$
0
0
Attached is a working example of using the IFileDialog interface introduced in Vista. It is the replacement for the common dialog used for opening/saving files and browsing for folders. This code is not compatible with XP and lower. You should ensure your project has needed logic to verify system is Vista or better. This version does not currently support enhancements provided by Win7 and above. I do plan on adding them in the near future.

The classes are plug & play. No TLB references are required. The main class is the FileDialog class and can be used-as is. The optional IFileDialogEvents class is provided so that you can receive callbacks while the FileDialog is displayed. Before Vista, this would have required subclassing the dialog, but Vista provided a way to do this through simple callback events. This optional events class is not required to display the dialog. But that class is required if you want callbacks, wish to filter what is displayed in the dialog, or want to add your own controls to the dialog. That class must be implemented if used. This means adding a line of code in your declarations section: Implements IFileDialogEvents. Lets talk about the three types of events. You can opt to have any of them or none of them.

Each event sent from the class includes a reference to the Dialog, a user-defined key for the instance of the Dialog, and appropriate event-driven parameters. Some events expect an answer back from you. Though all events will be added when you Implement the class, you only have to code for the ones you asked for & want to respond to.

1. Standard Callback Events. The FileDialog can forward events to whatever is displaying the dialog. The most common events are: DialogOnInit, OnFolderChanging, OnSelectionChange, OnFieOk. The OnFileOk event occurs just before the user is about to close the dialog and offers you a chance to prevent closing the dialog and/or cache any custom control properties set by the user while the dialog was displayed. The OnFolderChanging event offers you a way to prevent the user from navigating to what they clicked on. There are a few other events that are forwarded and can be reviewed on MSDN. Note: DialogOnInit is a custom event the class sends. It is intended for you to finalize any custom controls you may have added, i.e., setting an option button, selecting a combobox item, etc, before the dialog is displayed. Any actions you take will not be forwarded back through events until DialogOnInit returns. Should you need to actually subclass the dialog, you can do it at this time since the hWnd of the dialog is known.

2. Filter Events. We all know we can assign filters to a file dialog like *.exe, *.txt, *.dll, etc. The dialog offers a more advanced filter where you can individually choose whether what is returned during navigation is actually displayed. When the filter is active, Windows sends you, one by one, every item that would be displayed. You can opt to say yes or no. Note: This was removed in Win7 & may not be added back.

3. Custom Control Events. You have the option to add controls to the dialog. These include combo/check/text boxes, option/command buttons, labels, & menu-like controls. There is little point in adding controls if you have no way of knowing if the user is clicking on them. So the dialog can send you some events. However, these events are lacking in my opinion. They do offer basic stuff, like something was clicked, something was selected, but little else. Any added textbox controls, for example, have no events passed. There are no got/lost focus events for the controls. Locating these controls for manual subclassing will be a challenge.

Here's the gotcha. As mentioned, this is not compatible with anything lower than Vista. But you also must get outside of your comfort zone a bit too. Where the older common dialog returned file & folder names, this new version returns objects as IShellItems and IShellItemArrays (when multi-selecting items). That's really not a bad thing. Not only can you have these items give you the file/folder name and 'display' name, you can ask it to give you that name as plain text or as a URL or a few other formats. You can have it give you attributes of the object. Since no TLBs are used, the FileDialog class has methods that will allow you to query the returned object for those things.

What I don't like about this new implementation of the dialog? The folder browsing is too limited in my opinion. The older version allowed several flags to restrict what was displayed. This new version has very little options for folders. Win7 added the ability to restrict browsing to the local domain, but other than that, not much. The lack of options from previous version lends to possibility of needing custom filters (#2 above). Additionally, the previous version allowed files to be displayed with folders when browsing for folders. The new version doesn't have that ability. Matter of learning to adjust I guess, but I feel code for the older version of folder browsing may still be worth keeping around.

There is no sample project included. I think that the FileDialog class is fairly straightforward to use and has lots of comments. A vast majority of the code is needed to simply to offer the wide range of options and provide methods to be called during events. The IFileDialogEvents class is to be implemented only, you will never create this class as a stand-alone object. I'm sure that there will be questions and we can address them here as needed.

These classes don't have all the dummy-proofing I tend to add in. It's a work-in-progress. But it is important you become familiar with it before attempting to use it for any serious projects. And come back occasionally to look for updates.

Edited:
Well that's embarrassing. Thought I'd get the Filter events without having to create FileDialogEvents. Wrong. Quick modification to include FileDialogEvents if either Filter or Control events are wanted.
Attached Files

[VB6] Creating/Using COM Interfaces without TLBs

$
0
0
This idea was something I just wondered if I could do. So, when I figured it out, wasn't too difficult to create a mostly generic template that could be used & re-used as needed. And that's what we have here.

With VB we may have to jump through hoops trying to declare and use a Windows COM interface that doesn't inherit from IDispatch. Typically, we would add a type library (TLB) to our project that contains the interfaces we plan on using. That works pretty well and is the preferred option.

With this code/idea, you can create these interfaces with pure VB code and without using any TLBs. If you're not the type that enjoys low-level coding, run away now, don't look back, just keep running ;)

This is pretty low-level stuff. The code creates a memory only VTable and thunks for the interface methods. But in order to do this, YOU have to research the interface. You need to know the IID (GUID) and the order of the methods in the interface (not the order posted on MSDN). Then you have to create each of the interface's methods as VB functions. Honestly, it's not that bad after you've done a few of them. I can generally whip up a working sample in about 5-10 minutes after I've found the IID and VTable order. MSDN is extremely useful in describing each method's parameters & return values.

FYI: IID is only needed should whatever you are passing this interface to asks it to identify itself. You want it to be able to say it is what it is pretending to be. In reality, and depending on what the interface is being used for, it's not often asked. But why risk it. The IID is the easiest thing to find. The VTable order is often more challenging.

Any how. As I said, low level. Because there are no TLBs to access these interfaces, we have to call them by their pointer and VTable function address offsets. Again, pretty easy really with the code provided and knowing the VTable order. But it does take some getting used to. For example, many times you may create or receive pointers to interfaces which you are required to add or remove a reference to. VB does this for us automatically. VB does not help here. You have to know when/if you must up the ref count or release the reference. Code is available to do that for you once you know those answers.

This is in no way an attempt to code without TLBs. However, it is kinda neat to know that you can create a class-only object that can be moved from project to project without requiring a TLB. I think that is about the only true advantage. The disadvantage, obviously, it's harder to do this manually.

That attached zip file has a sample project and the IFauxInterface template. That template has lots of comments, in fact, more comments than code. The sample project's IBindStatusCallback class was created from that template. The form in the project creates a pointer only interface and uses low-level access to manipulate it. Enjoy

Regarding the thunks. No malicious code in there. The thunks basically do this:
- store the stack
- set up the stack for the callback: add the class' object pointer and the parameters
- call the VB class private function
- restore/adjust/pop the stack as needed & set the VB function return address
48 bytes used per thunk, 4 bytes per VTable entry, 8 bytes per Interface pointer

Just another FYI. The VTable and thunk structure used can be visualized with this image. The entire structure is one block of contiguous memory.
Name:  vtable.png
Views: 6
Size:  17.9 KB

Edited: If you don't see the progress bar dialog before the download finishes. The download was too quick or used cached data. The progress dialog is created in the form. The IBindStatusCallback class is what pushes that progress bar to be updated from the events it sends. What is giving us those progress events is the URLmon.dll via the interface we created from the template.
Attached Images
 
Attached Files

[VB6] Common Dialog Replacement - IFileDialog Vista+ (No TLBs)

$
0
0
Updated/Revamped a bit: 17 Jan 2015

Attached is a working example of using the IFileDialog interface introduced in Vista. It is the replacement for the common dialog used for opening/saving files and browsing for folders. This code is not compatible with XP and lower. You should ensure your project has needed logic to verify system is Vista or better. This version does not currently support enhancements provided by Win7 and above. I do plan on adding them in the near future. This class-only solution is based off of my project: Creating COM Interfaces without TLBs

The classes are plug & play. No TLB references are required. The main class is the IFileDialog class and can be used-as is. The optional IFileDialogEvents class is provided so that you can receive callbacks while the IFileDialog is displayed. Before Vista, this would have required subclassing the dialog, but Vista provided a way to do this through simple callback events. This optional events class is not required to display the dialog. But that class is required if you want callbacks, wish to filter what is displayed in the dialog, or want to add your own controls to the dialog. That class must be implemented if used. This means adding a line of code in your declarations section: Implements IFileDialogEvents. Lets talk about the three types of events. You can opt to have any of them or none of them.

Each event sent from the class includes a reference to the Dialog, a user-defined key for the instance of the Dialog, and appropriate event-driven parameters. Some events expect an answer back from you. Though all events will be added when you Implement the class, you only have to code for the ones you asked for & want to respond to.

1. Standard Callback Events. The IFileDialog can forward events to whatever is displaying the dialog. The most common events are: DialogOnInit, OnFolderChanging, OnSelectionChange, OnFieOk. The OnFileOk event occurs just before the user is about to close the dialog and offers you a chance to prevent closing the dialog and/or cache any custom control properties set by the user while the dialog was displayed. The OnFolderChanging event offers you a way to prevent the user from navigating to what they clicked on. There are a few other events that are forwarded and can be reviewed on MSDN. Note: DialogOnInit is a custom event the class sends. It is intended for you to finalize any custom controls you may have added, i.e., setting an option button, selecting a combobox item, etc, before the dialog is displayed. Any actions you take will not be forwarded back through events until DialogOnInit returns. Should you need to actually subclass the dialog, you can do it at this time since the hWnd of the dialog is known.

2. Filter Events. We all know we can assign filters to a file dialog like *.exe, *.txt, *.dll, etc. The dialog offers a more advanced filter where you can individually choose whether what is returned during navigation is actually displayed. When the filter is active, Windows sends you, one by one, every item that would be displayed. You can opt to say yes or no. Note: This was deprecated in Win7 & may not be added back.

3. Custom Control Events. You have the option to add controls to the dialog. These include combo/check/text boxes, option/command buttons, labels, & menu-like controls. There is little point in adding controls if you have no way of knowing if the user is clicking on them. So the dialog can send you some events. However, these events are lacking in my opinion. They do offer basic stuff, like something was clicked, something was selected, but little else. Any added textbox controls, for example, have no events passed. There are no got/lost focus events for the controls. Locating these controls for manual subclassing will be a challenge.

Here's the gotcha. As mentioned, this is not compatible with anything lower than Vista. But you also must get outside of your comfort zone a bit too. Where the older common dialog returned file & folder names, this new version returns objects as IShellItems and IShellItemArrays (when multi-selecting items). That's really not a bad thing. Not only can you have these items give you the file/folder name and 'display' name, you can ask it to give you that name as plain text or as a URL or a few other formats. You can have it give you file attributes of the object. Since no TLBs are used, the IFileDialog class has methods that will allow you to query the returned object for those things.

What I don't like about this new implementation of the dialog? The folder browsing is too limited in my opinion. The older version allowed several flags to restrict what was displayed. This new version has very little options for folders. Win7 added the ability to restrict browsing to the local domain, but other than that, not much. The lack of options from previous version lends to possibility of needing custom filters (#2 above). Additionally, the previous version allowed files to be displayed with folders when browsing for folders. The new version doesn't have that ability. Matter of learning to adjust I guess, but I feel code for the older version of folder browsing may still be worth keeping around.

These classes don't have all the dummy-proofing I tend to add in. It's a work-in-progress. But it is important you become familiar with it before attempting to use it for any serious projects. And come back occasionally to look for updates.

What advantage does this have over TLBs? Only one I can think of: can create a class that can be added to any project without needing to carry over TLBs into the target application.

The sample project does not touch all the properties the IFileDialog class offers. Explore a bit.
Attached Files

[VB6] Using the new IFileDialog interface for customizable Open/Save (TLB, Vista+)

$
0
0
LaVolpe put out an excellent class module that implements these interfaces, but I've been working on using them through a different approach for some time and wanted to post it as well since, while requiring a TLB, it offers advantages like having IShellItem as a declarable type used all over projects, interfaces, and APIs.

IFileDialog / IFileOpenDialog / IFileSaveDialog

IFileSaveDialog and IFileOpenDialog were introduced in Windows Vista to supersede the GetOpenFileName/GetSaveFileName API, and offer several advantages (although certainly some drawbacks). Windows provides a default implementation, so they're fairly easy to use in VB. Among the advantages is easy addition of custom controls, something that was not previously possible in VB (or at least so hard no one bothered).

The typelib:
This project uses oleexp.tlb, which is my own expansion of olelib.tlb. Originally I just had a modified olelib, but now for compatibility reasons I've split off my additions so that there's minimal changes to olelib to maximize compatibility. See the olechanges.txt file for details. This project MIGHT work with an unmodified olelib.tlb since it doesn't use any of the changed interfaces, but I strongly advise using my upgraded olelib, as the only code-breaking changes are turning a few subs into functions since the return value is important (and only on IShellFolder/2 and IEnumIDList).
Full source code for both the upgraded olelib.tlb and oleexp.tlb is included and can be compiled into a hash-identical copy with VS6.0's MKTYPLIB.
This project uses oleexp.tlb version 1.1, if you have an earlier version from my other projects please upgrade it (fully backwards compatible, no code changes to other projects will be needed).

IShellItem:
For modern Windows, IShellItem is becoming more and more important. This project will familiarize you with using this object. The typelib based approach to this offers the advantage of being able to use IShellItem and related types project-wide, and pass them around easily, both within the project and to APIs and interfaces that use them. The sample project has helper functions that show how to create and manipulate IShellItem and related functions.
--

The attached ZIP includes olelib and oleexp, as well as a sample project illustrating the use of the dialogs. There's examples for a very simple Open, a typical Open dialog, a simple Save dialog, a multi-file-open dialog, and a highly customized open dialog.

In Your Own Project
To use IFileDialog-based Open/Save, your project needs to add a reference to olelib and oleexp. cFileDialogEvents.cls is required only if you want to receive feedback while the dialog is open (including from added custom controls).

-----------------------------------
Here's how simple a basic Open File dialog is with this tlb:

Code:

Dim fodSimple As FileOpenDialog
Dim isiRes As IShellItem
Dim lPtr As Long

Set fodSimple = New FileOpenDialog

With fodSimple
    .SetTitle "Simple File Open"
    .Show Me.hWnd
   
    .GetResult isiRes
    isiRes.GetDisplayName SIGDN_FILESYSPATH, lPtr
    Text1.Text = BStrFromLPWStr(lPtr, True)
End With
Set isiRes = Nothing
Set fodSimple = Nothing

That's all it takes to get the very simplest Open File dialog going, and shows how the class is used.

Events
While previously subclassing was required to receive event notifications while the dialog was displayed, this is now accomplished simply by adding the optional cFileDialogEvents class and calling the .Advise method.
This same class also receives events from any custom controls added.

Customization
I thought that even with this approach, it was going to be hard. But the class is set up to make this a very easy process.
To add a simple label and a button,
Code:


Dim fdc As IFileDialogCustomize
Set fdc = pDlg 'pDlg is the FileOpenDialog object

pDlg.Advise cFDE, 0 'the events class

fdc.AddText 1000, "This is a test label."
fdc.AddPushButton 1001, "New Button"

With that, the events class will have its OnButtonClicked method called when its clicked.


Here's the full sample code that produces the dialog in the above screenshot:

Code:

On Error Resume Next 'A major error is thrown when the user cancels the dialog box
List1.Clear
Dim isiRes As IShellItem

Dim isiDef As IShellItem 'default folder
Dim FOLDERID_Pictures As UUID
Dim pidlDef As Long

Dim lPtr As Long
Dim lOptions As FILEOPENDIALOGOPTIONS

'Set up filter
Dim FileFilter() As COMDLG_FILTERSPEC
ReDim FileFilter(1)

FileFilter(0).pszName = "Image Files"
FileFilter(0).pszSpec = "*.jpg;*.gif;*.bmp"

FileFilter(1).pszName = "All Files"
FileFilter(1).pszSpec = "*.*"

'set up default folder: note that this only shows the very first time
'                      after that, the last directory is default
'                      automatically. override with SetFolder.
Call CLSIDFromString(StrPtr(fidPictures), FOLDERID_Pictures)
Call SHGetKnownFolderIDList(FOLDERID_Pictures, 0, 0, pidlDef)
If pidlDef Then
    Call SHCreateShellItem(0, 0, pidlDef, isiDef)
End If

Set fod = New FileOpenDialog
Set cEvents = New cFileDialogEvents

With fod
    .Advise cEvents, 0
    .SetTitle "Select Thine File Sir"
    .GetOptions lOptions
    lOptions = lOptions Or FOS_FILEMUSTEXIST Or FOS_FORCESHOWHIDDEN 'just an example of options... shows hidden files even if they're normally not shown
    .SetOptions lOptions
    .SetOkButtonLabel "Mine File"
    .SetFileNameLabel "Look! A custom file label!!!"
   
    If (isiDef Is Nothing) = False Then
        .SetFolder isiDef
    End If
    .SetFileTypes 2, VarPtr(FileFilter(0).pszName)
   
    'Now we'll begin adding custom controls
    'First, we set up the interface
    'The control IDs can be any number, and should
    'really be stored as consts
    Set fdc = fod
   
    fdc.AddText 1000, "This is a test label."
   
    fdc.AddPushButton 1001, "New Button"
    fdc.MakeProminent 1001 'Moves to by the open button; only checkboxes, buttons, combos, menus can be made prominent
   
    fdc.AddPushButton 1002, "Some Other Button"
   
    fdc.StartVisualGroup 2000, "VG-1"
    fdc.AddCheckButton 2001, "Checkers!", 1
    fdc.AddSeparator 2002
    'For menus, and radio buttons/combos, first you add the control, then add items with AddControlItem
    fdc.AddMenu 2010, "Checkers?"
    fdc.AddControlItem 2010, 3000, "Pretty good."
    fdc.AddControlItem 2010, 3001, "Pretty bad."
    fdc.AddControlItem 2010, 3002, "Neutral!"
    fdc.AddEditBox 2003, "Other."
    fdc.EndVisualGroup
   
    fdc.StartVisualGroup 4000, "Radio station?"
    fdc.AddRadioButtonList 4001
    fdc.AddControlItem 4001, 4010, "Radio Station Alpha"
    fdc.AddControlItem 4001, 4011, "Radio Station Beta"
    fdc.EndVisualGroup
   
    fdc.AddComboBox 5000
    fdc.AddControlItem 5000, 5010, "Combo Alpha"
    fdc.AddControlItem 5000, 5011, "Combo Beta"
    fdc.AddControlItem 5000, 5012, "Combo Gamma"
    fdc.SetSelectedControlItem 5000, 5011


    .Show Me.hWnd
   
    .GetResult isiRes
    isiRes.GetDisplayName SIGDN_FILESYSPATH, lPtr
    Text1.Text = BStrFromLPWStr(lPtr, True)
End With
   
If pidlDef Then Call CoTaskMemFree(pidlDef)
Set isiRes = Nothing
Set isiDef = Nothing
Set fod = Nothing

Attached Files
Viewing all 1472 articles
Browse latest View live