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

VB6 Regfree Handling of AX-Plugin-Dlls per DirectCOM

$
0
0
One necessity, to make the handling of VB6-produced ActiveX-Dlls more easy,
is the regfree loading of the Classes which are contained in the Plugin-Dlls.

Once that is out of the way (we use DirectCOM.dll for that task), another
problem comes to mind, which needs to be addressed:
How to "force" the potentially "foreign" contributors to the plugin-system,
to conform to a certain set of "rules" (with regards to the functions and
their signatures - type- and parameter-wise).

One way to do that would be "by convention which is documented somewhere".
Another (more strict - and more selfexplaining) way is, to define an interface
(or a set of interfaces, as used in this Demo) in a TypeLib, and force plugin-
authors to adhere to the "contract" which is given over those COM-Interfaces.

In VB6 this is quite easy - since we can just use:
Implements ISomeInterface
... then drop down the appropriate Methods we have to implement from the
VB6-IDEs ComboBoxes (Interface-methods are reachable quite similar to Event-
handler-Methods because they are available over the very same IDE-ComboBoxes,
but in case of an Interface we cannot choose to leave such a Method out -
we have to bring them all as code into the appropriate Module - and then
"fill them out" with our own implementations).

That said, the creation of such an interface might be considered "boring stuff"
(maybe because it really is ;)) - but it's a task which (when finished and well-done) -
kind of repays for the initial trouble... (implementing existing interfaces is a bit more fun,
because this can be done pretty fast usually, since "the structure is already a given" -
and the "fill-out" quite easy in most cases.

Maybe a nice TypeLib-Editor might help in this regard - I'm using the one from
Matt-Curland for my stuff (as e.g. for the 'PluginInterfaces.tlb', which is contained in the Demo).

The Demo comes with a Main-Application, which shows the Management of the Plugin-Dlls -
and is codewise quite lean - here's the complete Form-Code:
Code:

Option Explicit

Private Declare Function LoadLibraryW Lib "kernel32" (ByVal pFileName As Long) As Long  'to preload DirectCOM.dll
Private Declare Function GetInstanceEx Lib "DirectCOM" (spFName As Long, spClassName As Long, Optional ByVal UseAlteredSearchPath As Boolean = True) As stdole.IUnknown

Private CurPlugin As PluginInterfaces.IPluginInfo

Private Sub Form_Load()
  LoadLibraryW StrPtr(App.Path & "\Bin\DirectCom.dll")
  Set picSrc.Picture = LoadPicture(App.Path & "\Res\SrcImg.jpg")
  lstPlugins.Path = App.Path & "\Plugins"
End Sub

Private Sub lstPlugins_Click()
  If lstPlugins.ListIndex < 0 Then Exit Sub
  Set CurPlugin = LoadPlugin(lstPlugins.Path & "\" & lstPlugins.FileName)
 
  txtInfo(0) = CurPlugin.GetVersion
  txtInfo(1) = CurPlugin.GetName
  txtInfo(2) = CurPlugin.GetDescription
 
  lstActionClasses.Clear
  Dim AC
  For Each AC In Split(CurPlugin.GetActionClassNames, ",")
    lstActionClasses.AddItem Trim$(AC)
  Next
End Sub

Private Function LoadPlugin(FileNameDll As String) As PluginInterfaces.IPluginInfo
  Set LoadPlugin = GetInstanceEx(StrPtr(FileNameDll), StrPtr("Info")) 'instantiate the Info-Class regfree
End Function

Private Sub lstActionClasses_Click()
  If lstActionClasses.ListIndex < 0 Then Exit Sub
  DoAction lstActionClasses.Text
End Sub

Private Sub DoAction(ClassName As String)
  Dim ActionObj As PluginInterfaces.IPluginAction, Pxl() As Long
  Set ActionObj = CurPlugin.CreateActionInstance(ClassName)
 
  GetArrFromHdl Pxl, picSrc.Picture.Handle 'copy the Pixels from the Source-Picture into the Pxl-Array
    ActionObj.ProcessImgData UBound(Pxl, 1) + 1, UBound(Pxl, 2) + 1, VarPtr(Pxl(0, 0))
  DrawArr Pxl, picDst.hDC 'now that the action is finished, draw the resulting Pixels to the Destination-PicBox
  If picDst.AutoRedraw Then picDst.Refresh
End Sub

Here's a ScreenShot, what the Plugins do (I've decided to cover a "PhotoShop-like scenario"
(Plugins which cover different ImageProcessing-Algorithms).



Don't know - besides the already mentioned "hurdles":
- Regfree-Loading
- TypeLib-Creation
- getting familiar with VBs Implements-Keyword

There's not much more to say - if there's questions left - just ask...

The code for the Demo is here:
RegfreePluginHandlingVB6.zip

Have fun...

Olaf
Attached Files

[VB6] Reg-Free COM at runtime via Microsoft.Windows.ActCtx

$
0
0
One of the slick things Microsoft developed before they pulled the plug on VB development and threw everything behind .Net was registration-free COM. Sadly, the change in direction meant that they never added tools support to VB, either in a service pack, an add-on package, or a non-"managed" VB7.

Most of this didn't see the light of day until Windows XP, though it was a bit flaky until XP SP2, and a little less so in XP SP3. But it wasn't really completed until Windows Server 2003 and then in Windows Vista and beyond.

The missing piece was the Microsoft.Windows.ActCtx object.

This never shipped in Windows XP, though at one time there was supposedly a redist Installer merge module for it. I've never seen it though and if it did exist it doesn't seem to be hosted at Microsoft Downloads anymore.


Vista and Beyond

The good news is that we do have it now. So in addition to application manifests for "normal" reg-free COM we can also use "runtime" reg-free COM in VB6 as well as 32-bit VBA and VBScript.

There is one snag: the tooling.


Tools

To create instances of classes from an unregistered DLL requires information from somewhere. The Windows answer to this is application and assembly manifests. However nothing was provided for VB6 developers except for hacks using older versions of Visual Studio .Net or the MT.exe utility from the Windows Vista and later SDKs.

There certainly are 3rd party tools out there. The famous MMM comes to mind as well as the knock-off UMMM and the commercial Side-by-Side Manifest Maker.

However as far as I know only the latter of those can make the assembly manifest files we need for use with the Microsoft.Windows.ActCtx object.


DLLAsm

With that in mind, I knocked together a quick and dirty tool for just this task.

You can run DLLAsm.exe from a command prompt and supply the name of the DLL you need a manifest for, or you can drag the DLL's icon and drop it on the DLLAsm.exe icon in Explorer.

This creates an assembly manifest "next to" the DLL (in whatever folder it is in), overwriting an existing one if any.

Just open the Project in the attached archive and compile it. All of its dependencies are standard libraries included in Windows. While useless on XP it should still compile and run there just fine.
Attached Files

Transit Time Tester

$
0
0
Users sometimes want to know how accessible a certain site is and how long it takes to get to it. The "ping" command has traditionally been used for that, but there are problems using this utility. The difficulty is created by the way that some routers handle ICMP (Internet Control Message Protocol) packets. These routers give ICMP packets the lowest priority, so the round trip time displayed is highly questionable and variable. Some sites also disable "ping" to protect against Ping Flood attacks.

"Ping", (as well as "Tracert") utilize UDP packets, which do not establish a connection with the far end. Transit Time Tester uses TCP packets, which are initiated using a 3-way handshake. The client sends a SYN request, the server responds with a SYN-ACK, and the client completes the connection with an ACK. Transit Time Tester measures the time required to receive the SYN-ACK, and terminates the connection by forcing an error. It uses a cutdown version of NewSocket.cls/mWinsock.bas.

For the domain, you can use the domain name, the domain IP Address, or just copy and paste the URL. If the URL is used, the port is automatically adjusted to 80.

J.A. Coutts
Attached Images
 
Attached Files

DrawLine function with pixel count output

$
0
0
This is a function I wrote intended to replace the built-in VB6 Line method. With the internal Line method, in addition to all the intermediate pixels of a line, the first pixel is also drawn. But there's a problem, the last pixel is never drawn. So if you want a complete line between 2 points, you will need to use both the line and pset commands. Another problem is that it doesn't draw anything if the line has no length (the first pixel is the same as the last pixel). The problem with the internal Line method, it sees a line with the first and last points being the same as having a length of 0, and a line with a length of 1 being a line who's last pixel is just adjacent to the first pixel.

My function fixes these problems. A line with the first pixel being the same as the last pixel, using my function, is seen by my function as a line with a length of 1 (though it has a length, this line has no direction, because the first and last pixels are the same), so it draws a single pixel. If the last pixel is adjacent the first pixel, then the line has a length of 2. The length is simply equal to the number of pixels drawn, by my definition. Therefore, a single pixel has a length of 1 (seems counterintuitive, because in real life, a length must also have a direction, but real life is analog, while pixels are quantized, so that's why it's different here). The return value of the function is the length of the line, which is the number of pixels drawn by the function. This is another advantage of my function over the internal built-in Line method, which has no way to return the number of pixels drawn.


Here's the code for my DrawLine function.

Code:

Private Function DrawLine(ByVal x1 As Long, ByVal y1 As Long, ByVal x2 As Long, ByVal y2 As Long) As Long
Dim x As Long
Dim y As Long
Dim m As Single
Dim PixelCount As Long


If (x2 = x1) And (y2 = y1) Then
    PSet (x1, y1)
    PixelCount = 1
Else
    If Abs(x2 - x1) > Abs(y2 - y1) Then
        m = (y2 - y1) / (x2 - x1)
        If x2 < x1 Then
            For x = x1 To x2 Step -1
                y = (x - x1) * m + y1
                PSet (x, y)
                PixelCount = PixelCount + 1
            Next x
        Else
            For x = x1 To x2
                y = (x - x1) * m + y1
                PSet (x, y)
                PixelCount = PixelCount + 1
            Next x
        End If
    Else
        m = (x2 - x1) / (y2 - y1)
        If y2 < y1 Then
            For y = y1 To y2 Step -1
                x = (y - y1) * m + x1
                PSet (x, y)
                PixelCount = PixelCount + 1
            Next y
        Else
            For y = y1 To y2
                x = (y - y1) * m + x1
                PSet (x, y)
                PixelCount = PixelCount + 1
            Next y
        End If
    End If
End If
DrawLine = PixelCount
End Function

[VB6, Vista+] List all file properties, locale/unit formatted, by modern PROPERTYKEY

$
0
0
Previous VB6 methods for listing file properties haven't used the newer methods, which are especially handy if you're already working with IShellItem. This code is a tour of the modern property system, covering PROPERTYKEY, IPropertyStore, IPropertyDescription, and propsys.dll APIs to take raw values and format them according to the system locale; e.g. adding 'pixels' or 'dpi' to image properties, showing dates/times according to system settings, changing the unreadable number representing attributes into letters, etc. It also goes on to show the raw data, exposing an important method if you do need to work with PROPVARIANT in VB.

Requirements
-Requires oleexp 1.8 or higher (released Jun 1 2015) (for IDE only, add references to olelib.tlb and oleexp.tlb)
-Only works with Windows Vista and higher

Code
Code:

Public Declare Function ILCreateFromPathW Lib "shell32" (ByVal pwszPath As Long) As Long
Public Declare Function SHCreateItemFromIDList Lib "shell32" (ByVal pidl As Long, riid As UUID, ppv As Any) As Long
Public Declare Function CoInitialize Lib "ole32.dll" (ByVal pvReserved As Long) As Long
Public Declare Sub CoTaskMemFree Lib "ole32.dll" (ByVal pv As Long) ' Frees memory allocated by the shell
Public Declare Function SysReAllocString Lib "oleaut32.dll" (ByVal pBSTR As Long, Optional ByVal pszStrPtr As Long) As Long
Public Declare Function PSGetNameFromPropertyKey Lib "propsys.dll" (PropKey As PROPERTYKEY, ppszCanonicalName As Long) As Long
Public Declare Function PSGetPropertyDescription Lib "propsys.dll" (PropKey As PROPERTYKEY, riid As UUID, ppv As Any) As Long
Public Declare Function PSFormatPropertyValue Lib "propsys.dll" (ByVal pps As Long, ByVal ppd As Long, ByVal pdff As PROPDESC_FORMAT_FLAGS, ppszDisplay As Long) As Long
Public Declare Function PropVariantToVariant Lib "propsys.dll" (ByRef propvar As Any, ByRef var As Variant) As Long

Public Sub EnumFileProperties(sPath As String)
'sPath can be a file or a folder. Other objects that you might want properties
'for, a slight re-work can be used to start from its pidl or IShellItem directly
Dim isif As IShellItem2
Dim pidlt As Long
Dim pProp As IPropertyDescription
Dim pk As PROPERTYKEY
Dim pPStore As IPropertyStore
Dim lpe As Long
Dim lpProp As Long
Dim i As Long, j As Long
Dim vProp As Variant
Dim vrProp As Variant
Dim vte As VbVarType
Dim sPrName As String
Dim sFmtProp As String

Call CoInitialize(0)

'Create a reference to IShellItem2
pidlt = ILCreateFromPathW(StrPtr(sPath))
Call SHCreateItemFromIDList(pidlt, IID_IShellItem2, isif)
Call CoTaskMemFree(pidlt)
If (isif Is Nothing) Then
    Debug.Print "Failed to get IShellItem2"
    Exit Sub
End If

'Get the IPropertyStore interface
isif.GetPropertyStore GPS_DEFAULT, IID_IPropertyStore, pPStore
If (pPStore Is Nothing) Then
    Debug.Print "Failed to get IPropertyStore"
    Exit Sub
End If

'Get the number of properties
pPStore.GetCount lpe
Debug.Print "Total number of properties=" & lpe

On Error GoTo eper
For i = 0 To (lpe - 1)
    'Loop through each property; starting with information about which property we're working with
    pPStore.GetAt i, pk
    PSGetNameFromPropertyKey pk, lpProp
    sPrName = BStrFromLPWStr(lpProp)
    Debug.Print "Property Name=" & sPrName & ",SCID={" & Hex$(pk.fmtid.Data1) & "-" & Hex$(pk.fmtid.Data2) & "-" & Hex$(pk.fmtid.Data3) & "-" & Hex$(pk.fmtid.Data4(0)) & Hex$(pk.fmtid.Data4(1)) & "-" & Hex$(pk.fmtid.Data4(2)) & Hex$(pk.fmtid.Data4(3)) & Hex$(pk.fmtid.Data4(4)) & Hex$(pk.fmtid.Data4(5)) & Hex$(pk.fmtid.Data4(6)) & Hex$(pk.fmtid.Data4(7)) & "}, " & pk.pid


   
    'Some properties don't return a name; if you don't catch that it leads to a full appcrash
    If Len(sPrName) > 1 Then
        'PSFormatPropertyValue takes the raw data and formats it according to the current locale
        'Using these APIs lets us completely avoid dealing with PROPVARIANT, a huge bonus.
        'If you don't need the raw data, this is all it takes
        PSGetPropertyDescription pk, IID_IPropertyDescription, pProp
        PSFormatPropertyValue ObjPtr(pPStore), ObjPtr(pProp), PDFF_DEFAULT, lpProp
        sFmtProp = BStrFromLPWStr(lpProp)
        Debug.Print "Formatted value=" & sFmtProp
    Else
        Debug.Print "Unknown Propkey; can't get formatted value"
    End If
   
    'Now we'll display the raw data
    isif.GetProperty pk, vProp
    PropVariantToVariant vProp, vrProp 'PROPVARIANT is exceptionally difficult to work with in VB, but at
                                      'least for file properties this seems to work for most
   
    vte = VarType(vrProp)
    If (vte And vbArray) = vbArray Then 'this always seems to be vbString and vbArray, haven't encountered other types
        For j = LBound(vrProp) To UBound(vrProp)
            Debug.Print "Value(" & j & ")=" & CStr(vrProp(j))
        Next j
    Else
    Select Case vte
        Case vbDataObject, vbObject, vbUserDefinedType
            Debug.Print "<cannot display this type>"
        Case vbEmpty, vbNull
            Debug.Print "<empty or null>"
        Case vbError
            Debug.Print "<vbError>"
        Case Else
            Debug.Print "Value=" & CStr(vrProp)
    End Select
    End If
Next i
Exit Sub
eper:
    Debug.Print "Property conversion error->" & Err.Description
    Resume Next

End Sub

'Supporting functions
Public Function IID_IShellItem2() As UUID
'7e9fb0d3-919f-4307-ab2e-9b1860310c93
Static IID As UUID
If (IID.Data1 = 0) Then Call DEFINE_UUID(IID, &H7E9FB0D3, CInt(&H919F), CInt(&H4307), &HAB, &H2E, &H9B, &H18, &H60, &H31, &HC, &H93)
IID_IShellItem2 = IID
End Function

Public Function IID_IPropertyDescription() As UUID
'(IID_IPropertyDescription, 0x6f79d558, 0x3e96, 0x4549, 0xa1,0xd1, 0x7d,0x75,0xd2,0x28,0x88,0x14
Static IID As UUID
 If (IID.Data1 = 0) Then Call DEFINE_UUID(IID, &H6F79D558, CInt(&H3E96), CInt(&H4549), &HA1, &HD1, &H7D, &H75, &HD2, &H28, &H88, &H14)
  IID_IPropertyDescription = IID
 
End Function

Public Function IID_IPropertyStore() As UUID
'DEFINE_GUID(IID_IPropertyStore,0x886d8eeb, 0x8cf2, 0x4446, 0x8d,0x02,0xcd,0xba,0x1d,0xbd,0xcf,0x99);
Static IID As UUID
 If (IID.Data1 = 0) Then Call DEFINE_UUID(IID, &H886D8EEB, CInt(&H8CF2), CInt(&H4446), &H8D, &H2, &HCD, &HBA, &H1D, &HBD, &HCF, &H99)
  IID_IPropertyStore = IID
 
End Function
Public Sub DEFINE_UUID(Name As UUID, L As Long, w1 As Integer, w2 As Integer, B0 As Byte, b1 As Byte, b2 As Byte, B3 As Byte, b4 As Byte, b5 As Byte, b6 As Byte, b7 As Byte)
  With Name
    .Data1 = L
    .Data2 = w1
    .Data3 = w2
    .Data4(0) = B0
    .Data4(1) = b1
    .Data4(2) = b2
    .Data4(3) = B3
    .Data4(4) = b4
    .Data4(5) = b5
    .Data4(6) = b6
    .Data4(7) = b7
  End With
End Sub
Public Function BStrFromLPWStr(lpWStr As Long, Optional ByVal CleanupLPWStr As Boolean = True) As String
SysReAllocString VarPtr(BStrFromLPWStr), lpWStr
If CleanupLPWStr Then CoTaskMemFree lpWStr
End Function

Sample output:
Code:

Property Name=System.FileAttributes,SCID={B725F130-47EF-101A-A5F1-2608C9EEBAC}, 13
Formatted value=A
Value=32

Also, if your user is selecting which properties to display, which is still done by column IDs, you can map a column id to a PROPERTYKEY like this, where isfPar is the IShellFolder2 the properties are selected from:
Code:

            isfPar.MapColumnToSCID lColumn, SHColEx
            pk.fmtid = SHColEx.fmtid
            pk.pid = SHColEx.pid

[VB6] Yet another simple and versatile Tray Icon code with subclassing

$
0
0
Yesterday, I didn't know what 'subclassing' is.
Today I made a complete solution to serve all your tray icon needs.

Easy to use: just create a cSysTray object in your form, pass the hWnd and you're set.
You can add and remove icons at will, change tooltips, create baloons and catch events from every icon.
Unfortunately the code needs 3 files, 2 class files and a module to do all the subclassing stuff, but it's very easy to use.
I grabbed some code from this post by Ellis Dee, hence the wrench icon on the form. And included some ideas from this post on subclassing by fafalone.

There are 2 BAS files on the zip:
modSysTray.bas uses SetWindowSubclass, RemoveWindowSubclass, DefSubclassProc
modSysTray_old.bas uses SetWindowLong, CallWindowProc
You can use any of them but the 1st one is better.


The code is not finished yet. It works perfectly on windows xp and win 7, but there are a lot of things to include like add other events, add support for baloon alternative icons, msn style baloons, and some other minor changes.
Note that I didn't include any routine to create icons from bitmaps or anything else. You need a 16x16 ICON picture. No mask creation, no scaling, no nothing.

Here's a screenshot:
Name:  pic.jpg
Views: 55
Size:  16.4 KB

And a minimal form code sample:
Code:

Option Explicit
Private WithEvents sysTray As cSysTray

Private Sub Form_Load()
    Set sysTray = New cSysTray
    sysTray.Init Me.hWnd
    sysTray.AddIcon (pic.Picture, "Hola mundo").ShowBalloon "my baloon", "baloon title", NIIF_NOSOUND Or NIIF_ERROR
    sysTray.AddIcon Me.Icon, "Hola mundo 2"
End Sub

Private Sub Form_Unload(Cancel As Integer)
    Set sysTray = Nothing
End Sub

Private Sub sysTray_DoubleClick(index As Integer)
    Debug.Print "dblclick"; index
End Sub

Private Sub sysTray_RightClick(index As Integer)
    Debug.Print "rtclick"; index
End Sub

Attached Images
 
Attached Files

VB6 - NewSocket (updated)

$
0
0
NewSocket.cls/mWinsock.bas has received several small updates.

1. All references to StrConv/vbUnicode have been removed and replaced by StrToByte/ByteToStr. This was necessitated to support some upper ANSI characters above &H7F, commonly encountered when using cryptography.

2. The code to load the assembler hex code in "Subclass_Initialize" has been simplified by introducing a routine called "HexToByte", and this routine has been made Public to allow for general use.

3. The memory allocated for the assembler code has been changed from "GlobalAlloc" to "VirtualAlloc". Most Desktop computers enable DEP (Data Exection Prevention) for essential programs and services only, but most servers and a few desktop computers will enable it for all programs. Because we are running assembler code in the data area, an abrupt and unexplained failure is experienced when running the executable using GlobalAlloc with DEP enabled for all programs. The same failure will not occur in the IDE because the IDE runs in Virtual Memory.

4. The functions "InitiateService/FinalizeService" has been eliminated and the code from them included in "InitiateProcesses/FinalizeProcesses".

5. The name for the Log File was inadvertently left at the first program that it was tested with (IPv6Chat.Log), and has been changed to "Socket.Log". This log file can be used to log debug statements while running the executable, by enabling "DbgFlg".

The ActiveX control (NewSocket.ocx) does require registration. If you previously used this control, it was automtically registered the first time you used it. To replace it, deregister the old one first using "regsvr32.exe", and delete the files "NewSocket.ocx/NewSocket.oca" from the \Windows\System32\ directory (\Windows\Syswow64\ on 64 bit systems). After compiling the control, copy the new "ocx" file to the same directory. The "oca" file will be automatically generated. Full instructions can be found in the "Readme.txt" file.

I have included 2 small test programs, as well as a simple ocxTest program to aid with the registration process. PrjTest downloads a small HTML file from our server using NewSocket.cls/mWinSock.bas. WebTest2 does the same thing using using the NewSocket Control.

J.A. Coutts
Attached Files

modZlib.bas

$
0
0
This is my module file for using zlibwapi.dll in VB6. To use this code, simply copy the text in the code box at the bottom of this post, and paste it into an empty module in VB6. Note that you must have the DLL file in question in either the windows\system32 folder (windows\syswow64 on x64 Windows), or in the folder where your VB6 project files are for the project you are working on (the same folder where your EXE file will be compiled to). Normally Zlib's only easy to use compression/decompression functions are compress, compress2, and uncompress. Unfortunately those functions expect the compressed data to exist within the a Zlib container (has a 2 byte header, and a 4 byte footer that is an Adler32 checksum of the uncompressed data). However, a number of various file formats expect raw "deflate" data to be in use (I believe that the Zip file format is one), without any Zlib container surrounding the compressed data. Deflate is the name of the algorithm that Zlib uses. Now Zlib does have functions for directly accessing raw deflate streams, but they are VERY difficult to use, and require initializing special structures associated with the streams, requiring a massive amount of overhead in any program implementing it. Zlib also has builtin functions for working with GZip files directly, but what if you want to handle an in-memory copy of a GZip container? Well once again, you can use the stream commands for that (and again use a HUGE amount of overhead in writing what could otherwise be a very simple program).

That's where my module comes in. It completely gets around the need for stream handling, by ultimately always using the compress2, uncompress, compressBound, and crc32 Zlib methods, and then handling the container formats as needed directly in VB6 code (and also using the Windows API CopyMemory method where needed). It contains methods for handling not only Zlib containers, but also raw deflate streams, and GZip containers. And it does it all using memory. The methods for the raw deflate streams work by calling the Zlib functions, and then adding or removing the Zlib container from the compressed data as needed. Of course, when it recreates the Zlib container, it doesn't have access to the uncompressed data until it decompresses it, so there's no way for it to recreate the Adler32 checksum, and without the correct checksum the Zlib decompressor returns an error, even though it does correctly decompress the data. As a result, error checking for decompression of a raw deflate stream is impossible, and therefore the Inflate method (Inflate is what they call decompressing Deflated data), is a "sub" rather than a "function", as it can't return any usable error, as otherwise it would always be signalling that it failed. I recommend that if you use raw deflate streams, that you use some other error checking method outside of the compression functions, such as storing a checksum or CRC separately (either in the header of your file, or in a separate file that your program will also load in addition to the file containing compressed data). My GZip compress and decompress functions call my Inflate and Deflate methods, and add or remove the GZip container from the data as needed. GZip uses CRC32 rather than a checksum, and since it can check for errors, the decompress method for GZip once again is a function. I have verified that my GZip compress function generates a valid GZip container, by saving it to a file and then opening it in the program 7Zip. My Zlib functions are included just to simplify the use of Zlib, as no special preprocessing or postprocessing of container formats is required here. These simplify handling of Zlib containers, by using byte arrays, rather than arbitrary data, so you don't need to know the size of the data that's being fed to it. These functions internally automatically determine the size of the input data by using the UBound VB6 function on the arrays. The only thing you will need to know is upon decompressing a Zlib stream or a raw Deflate stream, you will will need to know the original uncompressed size. This can be determined easily by your own use of the UBound function in your own code, and then this info can be saved into whatever structure or file format you use to pass information to and from this program. Only difference is with a GZip container, which already stores the original uncompressed size as part of the container (it's a 4byte Long value, which is the last 4 bytes of the 8byte footer at the end of the container, according to the official specs for GZip).

All my functions use the Boolean type for the return value, and output True for success, and False for failure. All input and output data are byte arrays. All byte arrays are to be 1D arrays, with the first index at 0 (zero). My GZip functions also handle a stored filename. For compressing, supplying a filename is optional. For decompressing, even if you don't have a filename stored, since it is passed byref, a filename variable MUST be supplied, even if it's only acting as a dummy/filler variable if you have no intent to use that info. All other optional fields that may be present in a GZip container are ignored by my decompression function, and are simply skipped if they are present. If the header indicates they exist they do get processed to find their length, but only for the purpose of skipping them to get to the deflate stream, as no info stored in them is returned by my GZip decompress function. Likewise , the only optional field that can be saved by my GZip compress function is the filename field.

Code:

Private Declare Function crc32 Lib "zlibwapi.dll" (ByVal OldCRC As Long, ByRef Data As Any, ByVal DataLen As Long) As Long
Private Declare Function compress2 Lib "zlibwapi.dll" (ByRef Dest As Byte, ByRef DestLen As Long, ByRef Src As Byte, ByVal SrcLen As Long, ByVal CompLevel As Long) As Long
Private Declare Function uncompress Lib "zlibwapi.dll" (ByRef Dest As Byte, ByRef DestLen As Long, ByRef Src As Byte, ByVal SrcLen As Long) As Long
Private Declare Function compressBound Lib "zlibwapi.dll" (ByVal SrcLen As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)



Public Function ZlibCompress(ByRef Dest() As Byte, ByRef Src() As Byte, Optional ByVal CompLevel As Long = 9) As Boolean
Dim SrcLen As Long
Dim DestLen As Long
Dim ErrorNum As Long

SrcLen = UBound(Src) + 1
DestLen = compressBound(SrcLen)
ReDim Dest(DestLen - 1)
ErrorNum = compress2(Dest(0), DestLen, Src(0), SrcLen, CompLevel)
If ErrorNum Then Exit Function
ReDim Preserve Dest(DestLen - 1)
ZlibCompress = True
End Function



Public Function ZlibDecompress(ByRef Dest() As Byte, ByRef Src() As Byte, ByVal UncompLen As Long) As Boolean
Dim SrcLen As Long
Dim DestLen As Long
Dim ErrorNum As Long

SrcLen = UBound(Src) + 1
DestLen = UncompLen
ReDim Dest(DestLen - 1)
ErrorNum = uncompress(Dest(0), DestLen, Src(0), SrcLen)
If ErrorNum Then Exit Function
ReDim Preserve Dest(DestLen - 1)
ZlibDecompress = True
End Function



Public Function Deflate(ByRef Dest() As Byte, ByRef Src() As Byte, Optional ByVal CompLevel As Long = 9) As Boolean
Dim ZlibCompData() As Byte
Dim Success As Boolean

Success = ZlibCompress(ZlibCompData, Src, CompLevel)
If Success = False Then Exit Function
ReDim Dest(UBound(ZlibCompData) - 6)
CopyMemory Dest(0), ZlibCompData(2), UBound(Dest) + 1
Deflate = True
End Function



Public Sub Inflate(ByRef Dest() As Byte, ByRef Src() As Byte, ByVal UncompLen As Long)
Dim ZlibCompData() As Byte
Dim CheckSumInput As Long
Dim n As Long
   
ReDim ZlibCompData(UBound(Src) + 6)
ZlibCompData(0) = &H78
ZlibCompData(1) = &H80
CheckSumInput = &H7880&
For n = 0 To 31
    If (CheckSumInput Or n) Mod 31 = 0 Then
        ZlibCompData(1) = ZlibCompData(1) Or n
        Exit For
    End If
Next n
CopyMemory ZlibCompData(2), Src(0), UBound(ZlibCompData) + 1
ZlibDecompress Dest(), ZlibCompData(), UncompLen
End Sub



Public Function GzipCompress(ByRef Dest() As Byte, ByRef Src() As Byte, Optional ByVal CompLevel As Long = 9, Optional ByVal FileName As String) As Boolean
Const HeaderLen As Long = 10
Const FooterLen As Long = 8
Dim DeflatedData() As Byte
Dim DeflateLen As Long
Dim FNameBytes() As Byte
Dim FNameLen As Long
Dim CRC As Long
Dim UncompLen As Long
Dim Success As Boolean

Success = Deflate(DeflatedData, Src, CompLevel)
If Success = False Then Exit Function
DeflateLen = UBound(DeflatedData) + 1
FNameBytes() = StrConv(FileName, vbFromUnicode)
FNameLen = Len(FileName)
If FNameLen > 0 Then
    FNameLen = FNameLen + 1
    ReDim Preserve FNameBytes(FNameLen - 1)
End If
UncompLen = UBound(Src) + 1
CRC = crc32(0, Src(0), UncompLen)

ReDim Dest(HeaderLen + FNameLen + DeflateLen + FooterLen - 1)
Dest(0) = 31
Dest(1) = 139
Dest(2) = 8

If FNameLen Then
    Dest(3) = 8
    CopyMemory Dest(HeaderLen), FNameBytes(0), FNameLen
End If

If CompLevel < 5 Then Dest(8) = 4 Else Dest(8) = 2
Dest(9) = 0

CopyMemory Dest(HeaderLen + FNameLen), DeflatedData(0), DeflateLen
CopyMemory Dest(HeaderLen + FNameLen + DeflateLen), CRC, 4
CopyMemory Dest(HeaderLen + FNameLen + DeflateLen + 4), UncompLen, 4

GzipCompress = True
End Function



Public Function GzipDecompress(ByRef Dest() As Byte, ByRef Src() As Byte, ByRef FileName As String) As Boolean
Const HeaderLen As Long = 10
Const ID1 As Byte = 31
Const ID2 As Byte = 139
Const CM As Byte = 8
Const FooterLen As Long = 8
Dim DataPtr As Long
Dim SrcLen As Long
Dim FLG As Byte
Dim XLEN As Integer
Dim DeflatedData() As Byte
Dim DeflateLen As Long
Dim TempStr As String
Dim FNameLen As Long
Dim FCommentLen As Long
Dim LenBeforeData As Long
Dim UncompLen As Long
Dim CRC As Long
Dim CRC2 As Long

SrcLen = UBound(Src) + 1
LenBeforeData = HeaderLen

If Src(0) <> ID1 Then Exit Function
If Src(1) <> ID2 Then Exit Function
If Src(2) <> CM Then Exit Function
FLG = Src(3)
If FLG And 2 Then LenBeforeData = LenBeforeData + 2
If FLG And 4 Then
    CopyMemory XLEN, Src(HeaderLen), 2
    LenBeforeData = LenBeforeData + 2 + XLEN
    DataPtr = HeaderLen + 2 + XLEN
Else
    DataPtr = HeaderLen
End If

If (FLG And 8) Or (FLG And 16) Then
    Do Until Src(DataPtr) = 0
        TempStr = TempStr & Chr$(Src(DataPtr))
        DataPtr = DataPtr + 1
    Loop
    If FLG And 8 Then
        FNameLen = Len(TempStr) + 1
        FileName = Left$(TempStr, FNameLen - 1)
        LenBeforeData = LenBeforeData + FNameLen
        If FLG And 16 Then
            DataPtr = DataPtr + 1
            TempStr = ""
            Do Until Src(DataPtr) = 0
                TempStr = TempStr & Chr$(Src(DataPtr))
                DataPtr = DataPtr + 1
            Loop
            FCommentLen = Len(TempStr) + 1
            LenBeforeData = LenBeforeData + FCommentLen
        End If
    Else
        FCommentLen = Len(TempStr) + 1
        LenBeforeData = LenBeforeData + FCommentLen
    End If
End If

DeflateLen = SrcLen - LenBeforeData - 8
ReDim DeflatedData(DeflateLen - 1)

CopyMemory CRC, Src(LenBeforeData + DeflateLen), 4
CopyMemory UncompLen, Src(LenBeforeData + DeflateLen + 4), 4
CopyMemory DeflatedData(0), Src(LenBeforeData), DeflateLen
ReDim Dest(UncompLen - 1)
Inflate Dest(), DeflatedData(), UncompLen
CRC2 = crc32(0, Dest(0), UncompLen)
If CRC2 <> CRC Then Exit Function

GzipDecompress = True
End Function


modCRC.bas

$
0
0
This is my code for CRC calculating. It calculates CRC32 using the standard polynomial 0x04C11DB7, and also 2 different 16bit CRCs (one uses the standard CRC16 polynomial 0x8005, and the other uses the CCITT polynomial 0x1021). Both the CRC32 and CRC16 functions allow the following parameters to be configured that affect the calculation of the CRC:
InvertInitCRC (if true, the initial CRC value has all 1 bits, otherwise it is has all 0 bits)
MirrorInputBits (if true, the bit order in each byte of input data is reversed before being used to calculate the CRC)
MirrorOutputBits (if true, the order of the bits in the output CRC is reversed, which is a 32bit reversal for CRC32 and a 16bit reversal for CRC16)
InvertFinalCRC (if true, the output bits of the CRC are all inverted, where 1 becomes 0, and 0 becomes 1)

These above parameters are all required parameters in both functions. That is, they must be explicitly set to true or false.

Also, both CRC functions have an optional parameter called SwapOutputBytes. This simply affects the "endianness" of the output CRC (the order in which the CRC's bytes are stored in memory or in a file).

The CRC16 function, has an extra required parameter called UsePolyCCITT. If true, it uses the CCITT polynomial (often used in various communications protocols), which is 0x1021. If false, it uses the standard CRC16 polynomial, which is 0x8005.

Note that for the CRC32 function to perform the standard CRC32 calculation, the 4 required parameters must be set as shown here:
InvertInitCRC = True
MirrorInputBits = True
MirrorInputBits = True
InvertFinalCRC = True

Note that for the CRC16 function to perform the standard CRC16 calculation, the 5 required parameters must be set as shown here:
UsePolyCCITT = False
InvertInitCRC = False
MirrorInputBits = True
MirrorInputBits = True
InvertFinalCRC = False




Here's the complete code for this module. Just copy and paste it into a module in VB6, and then you will be able to use the CRC32 and CRC16 functions from anywhere else in your code.

Code:

Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)



Public Function CRC32(ByRef Data() As Byte, _
                      ByVal InvertInitCRC As Boolean, _
                      ByVal MirrorInputBits As Boolean, _
                      ByVal MirrorOutputBits As Boolean, _
                      ByVal InvertFinalCRC As Boolean, _
                      Optional ByVal SwapOutputBytes As Boolean) As Long
                       
Dim ByteNumber As Long
Dim BitNumber As Long
Dim CurrentByte As Long
Dim CRC As Long
Const Poly As Long = &H4C11DB7

If InvertInitCRC Then CRC = &HFFFFFFFF Else CRC = 0

For ByteNumber = 0 To UBound(Data)
    CurrentByte = Data(ByteNumber)
    If MirrorInputBits Then CurrentByte = ReverseBits8(CurrentByte)
    CurrentByte = SwapBytes4(CurrentByte)
    CRC = CRC Xor CurrentByte
    For BitNumber = 0 To 7
        If CRC And &H80000000 Then
            CRC = ShiftLeft32(CRC) Xor Poly
        Else
            CRC = ShiftLeft32(CRC)
        End If
    Next BitNumber
Next ByteNumber
If MirrorOutputBits Then CRC = ReverseBits32(CRC)
If InvertFinalCRC Then CRC = CRC Xor &HFFFFFFFF
If SwapOutputBytes Then CRC = SwapBytes4(CRC)
CRC32 = CRC
End Function



Public Function CRC16(ByRef Data() As Byte, _
                      ByVal UsePolyCCITT As Boolean, _
                      ByVal InvertInitCRC As Boolean, _
                      ByVal MirrorInputBits As Boolean, _
                      ByVal MirrorOutputBits As Boolean, _
                      ByVal InvertFinalCRC As Boolean, _
                      Optional ByVal SwapOutputBytes As Boolean) As Integer
                     
Dim ByteNumber As Long
Dim BitNumber As Long
Dim CurrentByte As Long
Dim CRC As Integer
Dim Poly As Integer
Const PolyStandard As Integer = &H8005
Const PolyCCITT As Integer = &H1021

If UsePolyCCITT Then Poly = PolyCCITT Else Poly = PolyStandard
If InvertInitCRC Then CRC = &HFFFF Else CRC = 0

For ByteNumber = 0 To UBound(Data)
    CurrentByte = Data(ByteNumber)
    If MirrorInputBits Then CurrentByte = ReverseBits8(CurrentByte)
    CurrentByte = SwapBytes2(CurrentByte)
    CRC = CRC Xor CurrentByte
    For BitNumber = 0 To 7
        If CRC And &H8000 Then
            CRC = ShiftLeft16(CRC) Xor Poly
        Else
            CRC = ShiftLeft16(CRC)
        End If
    Next BitNumber
Next ByteNumber
If MirrorOutputBits Then CRC = ReverseBits16(CRC)
If InvertFinalCRC Then CRC = CRC Xor &HFFFF
If SwapOutputBytes Then CRC = SwapBytes2(CRC)
CRC16 = CRC
End Function



Private Function ReverseBits8(ByVal Value As Byte) As Byte
Dim Value2 As Byte
Dim n As Long

Value2 = (Value And 1) * &H80
For n = 1 To 7
    Value2 = Value2 + ShiftLeft32(ShiftRight32(Value, n) And 1, 7 - n)
Next n
ReverseBits8 = Value2
End Function



Private Function ShiftLeft32(ByVal Value As Long, Optional ByVal BitCount As Long = 1) As Long
Dim temp As Currency
Dim temp2 As Long

CopyMemory temp, Value, 4
temp = temp * (2 ^ BitCount)
CopyMemory temp2, temp, 4
ShiftLeft32 = temp2
End Function



Private Function ShiftRight32(ByVal Value As Long, Optional ByVal BitCount As Long = 1) As Long
Dim temp As Currency
Dim temp2 As Long

CopyMemory temp, Value, 4
temp = Int((temp * 10000) / (2 ^ BitCount)) / 10000
CopyMemory temp2, temp, 4
ShiftRight32 = temp2
End Function



Private Function ReverseBits32(ByVal Value As Long) As Long
Dim Value2 As Long
Dim n As Long

Value2 = (Value And 1) * &H80000000
For n = 1 To 31
    Value2 = Value2 + ShiftLeft32(ShiftRight32(Value, n) And 1, 31 - n)
Next n
ReverseBits32 = Value2
End Function



Private Function SwapBytes4(ByVal Value As Long) As Long
Dim Value2 As Long

CopyMemory ByVal VarPtr(Value2) + 0, ByVal VarPtr(Value) + 3, 1
CopyMemory ByVal VarPtr(Value2) + 1, ByVal VarPtr(Value) + 2, 1
CopyMemory ByVal VarPtr(Value2) + 2, ByVal VarPtr(Value) + 1, 1
CopyMemory ByVal VarPtr(Value2) + 3, ByVal VarPtr(Value) + 0, 1
SwapBytes4 = Value2
End Function



Private Function ShiftRight16(ByVal Value As Integer, Optional ByVal BitCount As Long = 1) As Integer
Dim temp As Long
Dim temp2 As Integer

CopyMemory temp, Value, 2
temp = temp \ (2 ^ BitCount)
CopyMemory temp2, temp, 2
ShiftRight16 = temp2
End Function



Private Function ShiftLeft16(ByVal Value As Integer, Optional ByVal BitCount As Long = 1) As Integer
Dim temp As Long
Dim temp2 As Integer

CopyMemory temp, Value, 2
temp = temp * (2 ^ BitCount)
CopyMemory temp2, temp, 2
ShiftLeft16 = temp2
End Function



Private Function ReverseBits16(ByVal Value As Integer) As Integer
Dim Value2 As Integer
Dim n As Long

Value2 = (Value And 1) * &H8000
For n = 1 To 15
    Value2 = Value2 + ShiftLeft32(ShiftRight32(Value, n) And 1, 15 - n)
Next n
ReverseBits16 = Value2
End Function



Private Function SwapBytes2(ByVal Value As Integer) As Integer
Dim Value2 As Integer

CopyMemory ByVal VarPtr(Value2) + 0, ByVal VarPtr(Value) + 1, 1
CopyMemory ByVal VarPtr(Value2) + 1, ByVal VarPtr(Value) + 0, 1
SwapBytes2 = Value2
End Function

[VB6, Vista+] Undocumented ListView feature: Footer items

$
0
0
Ran across this nifty thing on codeproject, and successfully got it working in VB.

Tested and working with 5.0 ListView and API ListView (it will also work on krool's Common Control Replacement ListView), have not tried with 6.0 ListView and presumably it wouldn't work (Windows Common Controls 5.0 is actually the more modern control due to linkage with the real comctl32.dll, and required for a lot of modern features like this and group view). The items are present and displayed the same way in all views, including tile and group view modes. It does appear you can only add up to 4 buttons, if you add more than that NONE of them appear.

This one is a little complicated to set up, but straightforward to use. First, it requires a type library with the undocumented interfaces IListViewFooter and IListViewFooterCallback, then the latter has to be implemented by a class module. From there, more undocumented goodness: LVM_SETIMAGELIST with a wParam of 4 will set the icons used in the footer, and LVM_QUERYINTERFACE retrieves an instance of IListViewFooter.
For the purposes of this code, I'll assume you have a ListView set up already. I use the system imagelist, but you can assign any imagelist (well, api imagelist):

Code:

Public Const IID_IListViewFooter = "{F0034DA8-8A22-4151-8F16-2EBA76565BCC}"
Public Const LVM_QUERYINTERFACE = (LVM_FIRST + 189)
Public Declare Function CLSIDFromString Lib "ole32" (ByVal lpszGuid As Long, pGuid As Any) As Long
Public Type GUIDA
  Data1 As Long
  Data2 As Integer
  Data3 As Integer
  Data4(7) As Byte
End Type
Public m_himlSysSmall As Long
Public Function GetFileTypeIconIndex(ext As String) As Long
  Dim sfi As SHFILEINFO
  Dim pidl As Long
If SHGetFileInfo(ext, FILE_ATTRIBUTE_NORMAL, sfi, Len(sfi), SHGFI_SYSICONINDEX Or SHGFI_SMALLICON Or SHGFI_USEFILEATTRIBUTES) Then
    GetFileTypeIconIndex = sfi.iIcon
  End If
End Function

The code to insert items can be placed wherever, but it won't show until there's items in the ListView.
Code:

  m_himlSysSmall = GetSystemImagelist(SHGFI_SMALLICON)
    Call SendMessage(ListView1.hWnd, LVM_SETIMAGELIST, 4, ByVal m_himlSysSmall)

Dim pLVF As IListViewFooter
Dim pFtrCB As cLVFooterCallback
Set pFtrCB = New cLVFooterCallback
Dim iidLVF As GUIDA
Call CLSIDFromString(StrPtr(IID_IListViewFooter), iidLVF)

Call SendMessage(hLVS, LVM_QUERYINTERFACE, VarPtr(iidLVF), pLVF)
If (pLVF Is Nothing) Then
    Debug.Print "Failed to get LV Footer interface"
    Exit Sub
End If
Dim lFtrIco As Long
lFtrIco = GetFileTypeIconIndex(".jpg") 'just an example, it's a standard index for the assigned image list.
With pLVF
    .SetIntroText "Intro text - hello!"
    .InsertButton 0, "Test Item 1", "where does this go", lFtrIco, 2000
    .Show pFtrCB
End With

'2000' - the lParam - has no special meaning, you can store whatever Long you want there. NOTE: It must not be 0, otherwise the buttonclick/buttondelete callback events won't fire.

The attached ZIP contains the typelib, the typelib source code, a batch file to compile it from a standard VS6 install, and the class module implementing the callback. I didn't bother will a full fledged example because presumably anyone interested in this would be adding it onto an already well set-up ListView, but if really needed let me know.

Coming up next in the world of undocumented ListView: subsetted groups (link for "Display all x items"), subitem label editing, and if I'm particularly ambitious.. apparently you can use groups in full virtual mode.
Attached Files

[VB6, Vista+] Undocumented ListView feature: Subsetted Groups (simple, no TLB)

$
0
0

Compatibility: Like other modern features, this should work with API-created ListView's including krools, as well as the 5.0 Common Controls ListView in an IDE and/or compiled EXE manifested for the latest comctl32.dll version; and will almost certainly not work with the VB "Common Controls 6.0" ocx. Works with Windows Vista and higher.

Subsetted groups allow you to show only a limited number of rows, and have a link at the bottom to show the hidden items. Works in any view where group view is supported (e.g. large icon and details, not list, etc). Not only is all the info needed to do it undocumented, but MSDN provides some of the constants then explicitly says it can't be done. Not sure what their deal is... I mean yeah there's some issues (see warning) but no reason they couldn't have fixed it between Vista and 10).
So I had been converting this project to VB, and after I had already implemented the full IListView class, I went back and decided to try LVM_SETGROUPSUBSETCOUNT anyway, having originally thought the project author had tried that first since it was mentioned where he got the idea from. Lo and behold, it worked. So now you can subsetted groups with just a couple lines, and no TLB, no subclassing, nothing.


Code:

Public Const LVM_FIRST = &H1000
Public Const LVM_SETGROUPSUBSETCOUNT = (LVM_FIRST + 190)
Public Const LVM_GETGROUPSUBSETCOUNT = (LVM_FIRST + 191)

 'is included in standard group def despite MSDN saying not supported:
    LVGF_SUBSET = &H8000
    LVGS_SUBSETED = &H40
    LVGS_SUBSETLINKFOCUSED = &H80

Now that you have your constants, when you're adding a group you want to be subsetted, add LVGF_SUBSET to .mask, and LVGS_SUBSETED to .State and .StateMask.
Next add the subset link text,
.pszSubsetTitle = StrPtr(sSubSetText)
.cchSubsetTitle = Len(sSubSetText) + 1 'MSDN says this needs its own flag, but this combo of flags and properties works for both me and the codeproject sample

Then, after the group has been added, to set the number of rows simply use:
Call SendMessage(hLVS, LVM_SETGROUPSUBSETCOUNT, 0, ByVal 2&)
where 2 can be anything, it's the number of rows you want. Note that in VB programs, all groups will have the link if one does, even without the style set. The link doesn't seem to go away, although in the c++ sample is does, so it might vary.

And that's all it takes!

WARNING:
Note that this is an undocumented message, and as such has SERIOUS issues: MSDN explicitly says subset text cannot be set. They lied, but changing the variable holding it after running your program without restarting the IDE can cause damage your project, leading to crashes and having to re-enter control settings. If Group View is not enabled, or no groups are added, or no groups are marked as subsetted, the ListView window will lock up and nothing can be drawn to that area of the screen until the program is ended.

[VB6, XP+] Code snippet: Show combined file properties window- SHMultiFileProperties

$
0
0
It's easy to show the file property window for a single file with ShellExecuteEx, but what if you wanted to also show a property window for multiple files in multiple paths as you can do in Explorer? The ShellExecuteEx method provides no option to pass an array of files. So you have to turn to SHMultiFileProperties. The reason this has never been done in VB before (at least as far as I could find with Google), is that it requires an IDataObject to describe the files, and that's traditionally been a tough thing to do. But thanks to some shell32 API's, it's not as bad as you'd think.

There's two APIs we can use to get the needed IDataObject, SHCreateDataObject and SHCreateFileDataObject. The former is only available on Vista and higher, and the latter is undocumented and exported by ordinal only. However, it's been at the same ordinal from XP through 8.1 (haven't checked 10), so I'll use that in the sample code. If you don't need to support XP, switch it out- they're extremely similar.

Requirements
Windows XP or higher
For the IDE only, a type library containing the definition for IDataObject. Some versions of OLEGuids might work, but I recommend using my Modern Interfaces Type Library, although just the original version of olelib would be sufficient. Simply download and add a reference to olelib.tlb to your project.

Code
Code:

Public Declare Function SHCreateFileDataObject Lib "shell32" Alias "#740" (ByVal pidlFolder As Long, ByVal cidl As Long, ByVal apidl As Long, pDataInner As Any, ppDataObj As olelib.IDataObject) As Long
'For Vista+ if you wanted:
'Public Declare Function SHCreateDataObject Lib "shell32" (ByVal pidlFolder As Long, ByVal cidl As Long, ByVal apidl As Long, pdtInner As Any, riid As UUID, ppv As Any) As Long
Public Declare Function SHMultiFileProperties Lib "shell32" (ByVal pdtobj As Long, ByVal dwFlags As Long) As Long
Public Declare Function ILCreateFromPathW Lib "shell32" (ByVal pwszPath As Long) As Long
Public Declare Sub ILFree Lib "shell32" (ByVal pidl As Long)

Public Sub ShowMultiFileProperties(sFiles() As String)
'Displays merged file properties window
'Will also display normal property window if a single file is passed
'Unicode is supported

Dim pData As olelib.IDataObject 'always explicitly type this with the parent
Dim apidl() As Long
Dim cpidl As Long
Dim i As Long
ReDim apidl(UBound(sFiles))

If (UBound(sFiles) = 0) And (sFiles(0) = "") Then Exit Sub

For i = 0 To UBound(sFiles)
    apidl(i) = ILCreateFromPathW(StrPtr(sFiles(i))) 'create a fully qualified pidl for each file
Next i
cpidl = UBound(apidl) + 1
Call SHCreateFileDataObject(VarPtr(0), cpidl, VarPtr(apidl(0)), ByVal 0&, pData) 'VarPtr(0) is always equal to the desktop's pidl
If (pData Is Nothing) Then
    Debug.Print "ShowMultiFileProperties: Could not create data object"
    Exit Sub
End If

Call SHMultiFileProperties(ObjPtr(pData), 0) 'passing IDataObject ByRef like you'd think from MSDN results in a crash, so the declare is changed to Long and we send the object pointer

Set pData = Nothing
For i = 0 To UBound(apidl)
    ILFree apidl(i) 'never forget to set your pidls free
Next i
End Sub

Duktape JS engine for vb6

$
0
0
Hi guys, thought i would share a project I have been working on.

I wanted to find a newer javascript engine that I could use with vb6. All in all the MS script control is very capable and easy to use, but it has some nuances that makes it not work with some javascript and does not support all newer constructs. Also there is no built in debugging support unless you try to host the IActiveScript interfaces yourself. (i never could get the debug interfaces working with vb6 either)

I started looking around and found the duktape javascript engine and got it working with vb6. I also devised a way to give the scripts access to COM objects.

An example use could be as simple as:
Code:

  Dim duk As New CDukTape
  msgbox duk.Eval("1+2")

Below are my current supported test cases:

Code:

'    js = "1+2"
'    js = "alert(1+2)"
'    js = "while(1){;}"                'timeout test
'    js = "prompt('text')"
'    js = "a='testing';alert(a[0]);"

'------------- vbdevkit tests ---------------------
'    js = "fso2.ReadFile('c:\\lastGraph.txt')"
'    js = "alert(dlg.OpenDialog(4))"
'    js = "pth = dlg.OpenDialog(4,'title','c:\\',0); fso2.ReadFile(pth)"
'--------------------------------------------------

'    js = "form.Text1.Text = 'test'"
'    js = "form.Text1.Text + ' read back in from javascript!'"
'    js = "form.caption = 'test!';alert(form.caption)"
'    js = "for(i=0;i<10;i++)form.List2.AddItem('item:'+i);alert('clearing!');form.List2.Clear()"
'    js = "var ts = fso.OpenTextFile('c:\\lastGraph.txt',1,true,0);v = ts.ReadAll(); v"        'value of v is returned from eval..
'    js = "var ts = fso.OpenTextFile('c:\\lastGraph.txt',1); v = ts.ReadAll();alert(v)"        '(default args test)

Its not as automatic as the MS script control, you do have to generate JS class wrappers for the COM object you want to use, but there is also a generator for it. In the future this stage could be automated but not yet.

This project is at a good point right now and generally usable so thought I would share at this point.

https://github.com/dzzie/duk4vb

The duktape engine also supports a debugger protocol, which is going to be my next step.

[VB6, Vista+] Host Windows Explorer on your form: navigation tree and/or folder

$
0
0
IExplorerBrowser

IExplorerBrowser is an easy to use, more complete version of IShellView that lets you have a complete Explorer frame on your form, with very little code. You can either have just a plain file view, or with a navigation tree and toolbar. It uses all the same settings and does all the same things as Explorer, and your program can interact with those actions to do things like browse for files, or be the basis of a namespace extension.
The only complication is that there's no event notifying of an individual file selection within the view, and getting a list of selected files is fairly complex- however there is a function to do it in the demo project.
Here's how it looks if you're just using folder view without the frames:


INamespaceTreeControl

If all you want is the navigation tree, you have the INamespaceTreeControl. It's got a decent amount of options for however you want to display things, including checkboxes. There is a wide range of events that you're notified of via the event sink, and most of these use IShellItem- the demo project does show to to convert that into a path, but it's a very useful interface to learn if you're going to be doing shell programming. The selection is reported through IShellItemArray, which is slightly easier than IDataObject.
It's got one little quirk though... you have the option to set the folder icons yourself, but if you don't want to do that and just use the default icon that you see in Explorer, you have to return -1, which requires a v-table swap. The demo project shows how to go both ways, no thanks to MSDN and their complete lack of documentation of this.
But this is by far the easiest to create way of having a full-featured Explorer-like navigation- I've made a regular TreeView into this, and it took hundreds of lines and heavy subclassing. This is a simple object. (Note that it does support some advanced features through related interfaces, like custom draw, drop handling, and accessibility... these interfaces are included in oleexp, but have not been brought to the sample project here, perhaps in the future I'll do a more in-depth one if there's any interest)

Requirements
Windows Vista or higher required as these interfaces did not exist in earlier OS versions
oleexp.tlb: Modern Interfaces Type Library v2.0 or higher (17 Jun 2015) - Only required in the IDE. Add/fix in demo references to olelib.tlb and oleexp.tlb.

These 'controls' create themselves- all you need is a blank form, and here's the creation code for a basic idea of how these things work (code to initialize some variables omitted):
Code:

Set pNST = New NamespaceTreeControl
pNST.Initialize Me.hWnd, prc, lFlag
Set pAdv = New cNSTEvents
Set pUnkAdv = pAdv
pNST.TreeAdvise pUnkAdv, lpck
pNST.InsertRoot 0, isiDesk, SHCONTF_FOLDERS, NSTCRS_EXPANDED Or NSTCRS_VISIBLE, pif

Attached Files

[vbRichClient] - How to create tabs ?

$
0
0
Hi,

I would like to avoid to use the tabstrip control or the bugged SStabs. So I was looking for a code example of tabs with vbRichClient and I don't find exactly what I looking for.

I'm about to use the vbRichClient Toolbar demo like tabs. Is it a good idea or there is something more adapted ?


Thank you.

Register/Unregister both DLLs and OCXs with RightClick

$
0
0
I used a vbscript provided by Olaf to register vbRichClient5, changed it a bit, and added 4 entries to registry.
Now I'm able to register/unregister both DLLs and OCXs with a simple RightMouse click over the file.

This probably worth less than nothing, but it works for me, and might be useful for somebody else.
Just copy Register.vbs to C:\Windows and execute the file Register.reg

Register.zip
Attached Files

[VB6] - Module for working with COM-Dll without registration.

$
0
0
Hello. I give my module for working with COM-DLL without registration in the registry.
The module has several functions:
  1. GetAllCoclasses - returns to the list of classes and unique identifiers are extracted from a type library.
  2. CreateIDispatch - creates IDispatch implementation by reference to the object and the name of the interface.
  3. CreateObjectEx2 - creates an object by name from a type library.
  4. CreateObjectEx - creates an object by CLSID.
  5. UnloadLibrary - unloads the DLL if it is not used.

vb Code:
  1. ' The module modTrickUnregCOM.bas - for working with COM libraries without registration.
  2. ' © Krivous Anatolii Anatolevich (The trick), 2015
  3.  
  4. Option Explicit
  5.  
  6.  D E C L A R A T I O N
  7.  
  8. Dim iidClsFctr      As GUID
  9. Dim iidUnk          As GUID
  10. Dim isInit          As Boolean
  11.  
  12. ' // Get all co-classes described in type library.
  13. Public Function GetAllCoclasses( _
  14.                 ByRef path As String, _
  15.                 ByRef listOfClsid() As GUID, _
  16.                 ByRef listOfNames() As String, _
  17.                 ByRef countCoClass As Long) As Boolean
  18.                
  19.     Dim typeLib As IUnknown
  20.     Dim typeInf As IUnknown
  21.     Dim ret     As Long
  22.     Dim count   As Long
  23.     Dim index   As Long
  24.     Dim pAttr   As Long
  25.     Dim tKind   As Long
  26.    
  27.     ret = LoadTypeLibEx(StrPtr(path), REGKIND_NONE, typeLib)
  28.    
  29.     If ret Then
  30.         Err.Raise ret
  31.         Exit Function
  32.     End If
  33.    
  34.     count = ITypeLib_GetTypeInfoCount(typeLib)
  35.     countCoClass = 0
  36.    
  37.     If count > 0 Then
  38.    
  39.         ReDim listOfClsid(count - 1)
  40.         ReDim listOfNames(count - 1)
  41.        
  42.         For index = 0 To count - 1
  43.        
  44.             ret = ITypeLib_GetTypeInfo(typeLib, index, typeInf)
  45.                        
  46.             If ret Then
  47.                 Err.Raise ret
  48.                 Exit Function
  49.             End If
  50.            
  51.             ITypeInfo_GetTypeAttr typeInf, pAttr
  52.            
  53.             GetMem4 ByVal pAttr + &H28, tKind
  54.            
  55.             If tKind = TKIND_COCLASS Then
  56.            
  57.                 memcpy listOfClsid(countCoClass), ByVal pAttr, Len(listOfClsid(countCoClass))
  58.                 ret = ITypeInfo_GetDocumentation(typeInf, -1, listOfNames(countCoClass), vbNullString, 0, vbNullString)
  59.                
  60.                 If ret Then
  61.                     ITypeInfo_ReleaseTypeAttr typeInf, pAttr
  62.                     Err.Raise ret
  63.                     Exit Function
  64.                 End If
  65.                
  66.                 countCoClass = countCoClass + 1
  67.                
  68.             End If
  69.            
  70.             ITypeInfo_ReleaseTypeAttr typeInf, pAttr
  71.            
  72.             Set typeInf = Nothing
  73.            
  74.         Next
  75.        
  76.     End If
  77.    
  78.     If countCoClass Then
  79.        
  80.         ReDim Preserve listOfClsid(countCoClass - 1)
  81.         ReDim Preserve listOfNames(countCoClass - 1)
  82.    
  83.     Else
  84.    
  85.         Erase listOfClsid()
  86.         Erase listOfNames()
  87.        
  88.     End If
  89.    
  90.     GetAllCoclasses = True
  91.    
  92. End Function
  93.  
  94. ' // Create IDispach implementation described in type library.
  95. Public Function CreateIDispatch( _
  96.                 ByRef obj As IUnknown, _
  97.                 ByRef typeLibPath As String, _
  98.                 ByRef interfaceName As String) As Object
  99.                
  100.     Dim typeLib As IUnknown
  101.     Dim typeInf As IUnknown
  102.     Dim ret     As Long
  103.     Dim retObj  As IUnknown
  104.     Dim pAttr   As Long
  105.     Dim tKind   As Long
  106.    
  107.     ret = LoadTypeLibEx(StrPtr(typeLibPath), REGKIND_NONE, typeLib)
  108.    
  109.     If ret Then
  110.         Err.Raise ret
  111.         Exit Function
  112.     End If
  113.    
  114.     ret = ITypeLib_FindName(typeLib, interfaceName, 0, typeInf, 0, 1)
  115.    
  116.     If typeInf Is Nothing Then
  117.         Err.Raise &H80004002, , "Interface not found"
  118.         Exit Function
  119.     End If
  120.    
  121.     ITypeInfo_GetTypeAttr typeInf, pAttr
  122.     GetMem4 ByVal pAttr + &H28, tKind
  123.     ITypeInfo_ReleaseTypeAttr typeInf, pAttr
  124.    
  125.     If tKind = TKIND_DISPATCH Then
  126.         Set CreateIDispatch = obj
  127.         Exit Function
  128.     ElseIf tKind <> TKIND_INTERFACE Then
  129.         Err.Raise &H80004002, , "Interface not found"
  130.         Exit Function
  131.     End If
  132.  
  133.     ret = CreateStdDispatch(Nothing, obj, typeInf, retObj)
  134.    
  135.     If ret Then
  136.         Err.Raise ret
  137.         Exit Function
  138.     End If
  139.    
  140.     Set CreateIDispatch = retObj
  141.  
  142. End Function
  143.  
  144. ' // Create object by Name.
  145. Public Function CreateObjectEx2( _
  146.                 ByRef pathToDll As String, _
  147.                 ByRef pathToTLB As String, _
  148.                 ByRef className As String) As IUnknown
  149.                
  150.     Dim typeLib As IUnknown
  151.     Dim typeInf As IUnknown
  152.     Dim ret     As Long
  153.     Dim pAttr   As Long
  154.     Dim tKind   As Long
  155.     Dim clsid   As GUID
  156.    
  157.     ret = LoadTypeLibEx(StrPtr(pathToTLB), REGKIND_NONE, typeLib)
  158.    
  159.     If ret Then
  160.         Err.Raise ret
  161.         Exit Function
  162.     End If
  163.    
  164.     ret = ITypeLib_FindName(typeLib, className, 0, typeInf, 0, 1)
  165.    
  166.     If typeInf Is Nothing Then
  167.         Err.Raise &H80040111, , "Class not found in type library"
  168.         Exit Function
  169.     End If
  170.  
  171.     ITypeInfo_GetTypeAttr typeInf, pAttr
  172.    
  173.     GetMem4 ByVal pAttr + &H28, tKind
  174.    
  175.     If tKind = TKIND_COCLASS Then
  176.         memcpy clsid, ByVal pAttr, Len(clsid)
  177.     Else
  178.         Err.Raise &H80040111, , "Class not found in type library"
  179.         Exit Function
  180.     End If
  181.    
  182.     ITypeInfo_ReleaseTypeAttr typeInf, pAttr
  183.            
  184.     Set CreateObjectEx2 = CreateObjectEx(pathToDll, clsid)
  185.    
  186. End Function
  187.                
  188. ' // Create object by CLSID and path.
  189. Public Function CreateObjectEx( _
  190.                 ByRef path As String, _
  191.                 ByRef clsid As GUID) As IUnknown
  192.                
  193.     Dim hLib    As Long
  194.     Dim lpAddr  As Long
  195.    
  196.     hLib = GetModuleHandle(StrPtr(path))
  197.    
  198.     If hLib = 0 Then
  199.    
  200.         hLib = LoadLibrary(StrPtr(path))
  201.         If hLib = 0 Then
  202.             Err.Raise 53, , Error(53) & " " & Chr$(34) & path & Chr$(34)
  203.             Exit Function
  204.         End If
  205.        
  206.     End If
  207.    
  208.     lpAddr = GetProcAddress(hLib, "DllGetClassObject")
  209.    
  210.     If lpAddr = 0 Then
  211.         Err.Raise 453, , "Can't find dll entry point DllGetClasesObject in " & Chr$(34) & path & Chr$(34)
  212.         Exit Function
  213.     End If
  214.  
  215.     If Not isInit Then
  216.         CLSIDFromString StrPtr(IID_IClassFactory), iidClsFctr
  217.         CLSIDFromString StrPtr(IID_IUnknown), iidUnk
  218.         isInit = True
  219.     End If
  220.    
  221.     Dim ret     As Long
  222.     Dim out     As IUnknown
  223.    
  224.     ret = DllGetClassObject(lpAddr, clsid, iidClsFctr, out)
  225.    
  226.     If ret = 0 Then
  227.  
  228.         ret = IClassFactory_CreateInstance(out, 0, iidUnk, CreateObjectEx)
  229.  
  230.     Else: Err.Raise ret: Exit Function
  231.     End If
  232.    
  233.     Set out = Nothing
  234.    
  235. End Function
  236.  
  237. ' // Unload DLL if not used.
  238. Public Function UnloadLibrary( _
  239.                 ByRef path As String) As Boolean
  240.                
  241.     Dim hLib    As Long
  242.     Dim lpAddr  As Long
  243.     Dim ret     As Long
  244.    
  245.     If Not isInit Then Exit Function
  246.    
  247.     hLib = GetModuleHandle(StrPtr(path))
  248.     If hLib = 0 Then Exit Function
  249.    
  250.     lpAddr = GetProcAddress(hLib, "DllCanUnloadNow")
  251.     If lpAddr = 0 Then Exit Function
  252.    
  253.     ret = DllCanUnloadNow(lpAddr)
  254.    
  255.     If ret = 0 Then
  256.         FreeLibrary hLib
  257.         UnloadLibrary = True
  258.     End If
  259.    
  260. End Function
  261.  
  262. ' // Call "DllGetClassObject" function using a pointer.
  263. Private Function DllGetClassObject( _
  264.                  ByVal funcAddr As Long, _
  265.                  ByRef clsid As GUID, _
  266.                  ByRef iid As GUID, _
  267.                  ByRef out As IUnknown) As Long
  268.                  
  269.     Dim params(2)   As Variant
  270.     Dim types(2)    As Integer
  271.     Dim list(2)     As Long
  272.     Dim resultCall  As Long
  273.     Dim pIndex      As Long
  274.     Dim pReturn     As Variant
  275.    
  276.     params(0) = VarPtr(clsid)
  277.     params(1) = VarPtr(iid)
  278.     params(2) = VarPtr(out)
  279.    
  280.     For pIndex = 0 To UBound(params)
  281.         list(pIndex) = VarPtr(params(pIndex)):   types(pIndex) = VarType(params(pIndex))
  282.     Next
  283.    
  284.     resultCall = DispCallFunc(0&, funcAddr, CC_STDCALL, vbLong, 3, types(0), list(0), pReturn)
  285.              
  286.     If resultCall Then Err.Raise 5: Exit Function
  287.    
  288.     DllGetClassObject = pReturn
  289.    
  290. End Function
  291.  
  292. ' // Call "DllCanUnloadNow" function using a pointer.
  293. Private Function DllCanUnloadNow( _
  294.                  ByVal funcAddr As Long) As Long
  295.                  
  296.     Dim resultCall  As Long
  297.     Dim pReturn     As Variant
  298.    
  299.     resultCall = DispCallFunc(0&, funcAddr, CC_STDCALL, vbLong, 0, ByVal 0&, ByVal 0&, pReturn)
  300.              
  301.     If resultCall Then Err.Raise 5: Exit Function
  302.    
  303.     DllCanUnloadNow = pReturn
  304.    
  305. End Function
  306.  
  307. ' // Call "IClassFactory:CreateInstance" method.
  308. Private Function IClassFactory_CreateInstance( _
  309.                  ByVal obj As IUnknown, _
  310.                  ByVal punkOuter As Long, _
  311.                  ByRef riid As GUID, _
  312.                  ByRef out As IUnknown) As Long
  313.    
  314.     Dim params(2)   As Variant
  315.     Dim types(2)    As Integer
  316.     Dim list(2)     As Long
  317.     Dim resultCall  As Long
  318.     Dim pIndex      As Long
  319.     Dim pReturn     As Variant
  320.    
  321.     params(0) = punkOuter
  322.     params(1) = VarPtr(riid)
  323.     params(2) = VarPtr(out)
  324.    
  325.     For pIndex = 0 To UBound(params)
  326.         list(pIndex) = VarPtr(params(pIndex)):   types(pIndex) = VarType(params(pIndex))
  327.     Next
  328.    
  329.     resultCall = DispCallFunc(obj, &HC, CC_STDCALL, vbLong, 3, types(0), list(0), pReturn)
  330.          
  331.     If resultCall Then Err.Raise resultCall: Exit Function
  332.      
  333.     IClassFactory_CreateInstance = pReturn
  334.    
  335. End Function
  336.  
  337. ' // Call "ITypeLib:GetTypeInfoCount" method.
  338. Private Function ITypeLib_GetTypeInfoCount( _
  339.                  ByVal obj As IUnknown) As Long
  340.    
  341.     Dim resultCall  As Long
  342.     Dim pReturn     As Variant
  343.  
  344.     resultCall = DispCallFunc(obj, &HC, CC_STDCALL, vbLong, 0, ByVal 0&, ByVal 0&, pReturn)
  345.          
  346.     If resultCall Then Err.Raise resultCall: Exit Function
  347.      
  348.     ITypeLib_GetTypeInfoCount = pReturn
  349.    
  350. End Function
  351.  
  352. ' // Call "ITypeLib:GetTypeInfo" method.
  353. Private Function ITypeLib_GetTypeInfo( _
  354.                  ByVal obj As IUnknown, _
  355.                  ByVal index As Long, _
  356.                  ByRef ppTInfo As IUnknown) As Long
  357.    
  358.     Dim params(1)   As Variant
  359.     Dim types(1)    As Integer
  360.     Dim list(1)     As Long
  361.     Dim resultCall  As Long
  362.     Dim pIndex      As Long
  363.     Dim pReturn     As Variant
  364.    
  365.     params(0) = index
  366.     params(1) = VarPtr(ppTInfo)
  367.    
  368.     For pIndex = 0 To UBound(params)
  369.         list(pIndex) = VarPtr(params(pIndex)):   types(pIndex) = VarType(params(pIndex))
  370.     Next
  371.    
  372.     resultCall = DispCallFunc(obj, &H10, CC_STDCALL, vbLong, 2, types(0), list(0), pReturn)
  373.          
  374.     If resultCall Then Err.Raise resultCall: Exit Function
  375.      
  376.     ITypeLib_GetTypeInfo = pReturn
  377.    
  378. End Function
  379.  
  380. ' // Call "ITypeLib:FindName" method.
  381. Private Function ITypeLib_FindName( _
  382.                  ByVal obj As IUnknown, _
  383.                  ByRef szNameBuf As String, _
  384.                  ByVal lHashVal As Long, _
  385.                  ByRef ppTInfo As IUnknown, _
  386.                  ByRef rgMemId As Long, _
  387.                  ByRef pcFound As Integer) As Long
  388.    
  389.     Dim params(4)   As Variant
  390.     Dim types(4)    As Integer
  391.     Dim list(4)     As Long
  392.     Dim resultCall  As Long
  393.     Dim pIndex      As Long
  394.     Dim pReturn     As Variant
  395.    
  396.     params(0) = StrPtr(szNameBuf)
  397.     params(1) = lHashVal
  398.     params(2) = VarPtr(ppTInfo)
  399.     params(3) = VarPtr(rgMemId)
  400.     params(4) = VarPtr(pcFound)
  401.    
  402.     For pIndex = 0 To UBound(params)
  403.         list(pIndex) = VarPtr(params(pIndex)):   types(pIndex) = VarType(params(pIndex))
  404.     Next
  405.    
  406.     resultCall = DispCallFunc(obj, &H2C, CC_STDCALL, vbLong, 5, types(0), list(0), pReturn)
  407.          
  408.     If resultCall Then Err.Raise resultCall: Exit Function
  409.      
  410.     ITypeLib_FindName = pReturn
  411.    
  412. End Function
  413.  
  414. ' // Call "ITypeInfo:GetTypeAttr" method.
  415. Private Sub ITypeInfo_GetTypeAttr( _
  416.             ByVal obj As IUnknown, _
  417.             ByRef ppTypeAttr As Long)
  418.    
  419.     Dim resultCall  As Long
  420.     Dim pReturn     As Variant
  421.    
  422.     pReturn = VarPtr(ppTypeAttr)
  423.    
  424.     resultCall = DispCallFunc(obj, &HC, CC_STDCALL, vbEmpty, 1, vbLong, VarPtr(pReturn), 0)
  425.          
  426.     If resultCall Then Err.Raise resultCall: Exit Sub
  427.  
  428. End Sub
  429.  
  430. ' // Call "ITypeInfo:GetDocumentation" method.
  431. Private Function ITypeInfo_GetDocumentation( _
  432.                  ByVal obj As IUnknown, _
  433.                  ByVal memid As Long, _
  434.                  ByRef pBstrName As String, _
  435.                  ByRef pBstrDocString As String, _
  436.                  ByRef pdwHelpContext As Long, _
  437.                  ByRef pBstrHelpFile As String) As Long
  438.    
  439.     Dim params(4)   As Variant
  440.     Dim types(4)    As Integer
  441.     Dim list(4)     As Long
  442.     Dim resultCall  As Long
  443.     Dim pIndex      As Long
  444.     Dim pReturn     As Variant
  445.    
  446.     params(0) = memid
  447.     params(1) = VarPtr(pBstrName)
  448.     params(2) = VarPtr(pBstrDocString)
  449.     params(3) = VarPtr(pdwHelpContext)
  450.     params(4) = VarPtr(pBstrHelpFile)
  451.    
  452.     For pIndex = 0 To UBound(params)
  453.         list(pIndex) = VarPtr(params(pIndex)):   types(pIndex) = VarType(params(pIndex))
  454.     Next
  455.    
  456.     resultCall = DispCallFunc(obj, &H30, CC_STDCALL, vbLong, 5, types(0), list(0), pReturn)
  457.          
  458.     If resultCall Then Err.Raise resultCall: Exit Function
  459.      
  460.     ITypeInfo_GetDocumentation = pReturn
  461.    
  462. End Function
  463.  
  464. ' // Call "ITypeInfo:ReleaseTypeAttr" method.
  465. Private Sub ITypeInfo_ReleaseTypeAttr( _
  466.             ByVal obj As IUnknown, _
  467.             ByVal ppTypeAttr As Long)
  468.    
  469.     Dim resultCall  As Long
  470.    
  471.     resultCall = DispCallFunc(obj, &H4C, CC_STDCALL, vbEmpty, 1, vbLong, VarPtr(CVar(ppTypeAttr)), 0)
  472.          
  473.     If resultCall Then Err.Raise resultCall: Exit Sub
  474.  
  475. End Sub

Download.

Vb6 - cng test

$
0
0
Attached is a test program for various CNG (Cryptography Next Generation) functions.
1. Create Key Pair
2. Sign Data
3. Verify Signature
4. Test Hashes (AES-GMAC not functional yet)
5. Generate Random
6. Enumerate Algorithms
7. Test Encryption
8. Test Forward Secret (Eliptical DH keys not functional yet)
9. Create TLS 1.0 Master Keys

Tested on Windows Vista and Windows 8.1.

J.A. Coutts
Attached Images
 
Attached Files

Hook system wide with DLL in C++

$
0
0
Hello,

Even we are in 2015 and vb6 is old, it’s still great. As I had been in difficult to find a simple and efficient method to do hooking system wide, so I share my source code, here in zip attachment.

This project allow you to do global hook, system wide in Windows. The principle is to put the hook with a DLL, then get the message by subclassing our program. This hook system wide work only with 32 bits applications.

The DLL in attachment was compiled in C++. Which allow you to put hook system wide in Windows, then send to our program, with SendMessage, the message WM_USER and the hook code (nCode). With subclassing of our program, we can get the hook code by subtract WM_USER.

The hook provided from the DLL is not specific to our program but global in all Windows (system wide).

The DLL support these hooks types :
' WH_CALLWNDPROC = CallWndProc;
' WH_CALLWNDPROCRET = CallWndRetProc;
' WH_CBT = CBTProc;
' WH_DEBUG = DebugProc;
' WH_FOREGROUNDIDLE = ForegroundIdleProc;
' WH_GETMESSAGE = GetMsgProc;
' WH_JOURNALPLAYBACK = JournalPlaybackProc;
' WH_JOURNALRECORD = JournalRecordProc;
' WH_KEYBOARD = KeyboardProc;
' WH_KEYBOARD_LL = LowLevelKeyboardProc;
' WH_MSGFILTER = MessageProc;
' WH_MOUSE = MouseProc;
' WH_MOUSE_LL = LowLevelMouseProc;
' WH_SHELL = ShellProc;
' WH_SYSMSGFILTER = SysMsgProc;

This project provide a demo of these hooks system wide :
CBT / CreateWnd : get the name of the handle parent of the window to be created.
Keyboard = get the code of the keystroke.
Mouse = get the name of the handle pointed by the left click.

I’m not the author of the DLL, neither hooking and subclassing methods.
I took these three elements and make a simple project.
The DLL was coded in C++ by Renfield – 2007
Source code of subclassing by Renfield – 2010
Hooking routines by vbAccelerator – 2003

Have fun ;-)

-ZIP Removed By Moderator-

[VB6] Color Management - Different Approach

$
0
0
The class included in the attached zip file is intended for those that want to add some color management to their VB projects with minimal effort. The color management class (cICMLite) uses GDI higher level color management built-in functions and returns the image as a stdPicture object suitable to assigning to picture box, image control, etc, or selecting the picture handle into a DC for BitBlt and other rendering functions.

Pros:
1. Easy to use. Call the cICMLite.LoadPIctureICM function to return the image as a stdPicture
2. Unicode supported. Can optionally use the class as a unicode-friendly version of VB's LoadPicture
3. Can load PNG and TIFF files that GDI+ can read/process
4. CMYK jpgs handled without any additional requirements when run on Win7 or better
5. Can load alpha bitmaps, both premultiplied and not
6. Can load bitmaps using versions 4 & 5 of the BitmapInfoHeader format

Cons:
1. CMYK jpgs are not supported on XP but requires GDI+ v1.1 manifest when run on Vista
2. Transparency in PNG, TIFF, & bitmap images is filled with a backcolor your provide to cICMLite. This is because VB stdPictures do not support transparency except for icons & gifs.
3. Minor limitation. Cannot use the class for soft proofing printer ICM profiles.
4. Since icons don't support ICM, they are not specifically handled and passed to VB's LoadPicture. We all know that VB is quite limited with support for modern icons. However, you do not have to use the class to load any image files. You could also add your own custom handling routine to the class to handle modern icons.
5. When running on Vista or XP, GDI+ versions have some bugs that can prevent color managment profiles from being read

Some notes
1. In the class, you may find the pvValidateAlphaChannel logic useful for other graphic routines
2. GIFs, containing ICM profiles, are processed based on theory. I have not found any in the wild. The logic is unique
3. BMPs, containing ICM profiles, are processed based on theory. I've found only one in the wild & it was a test image
Since GDI+ does not honor alpha channels in bitmaps, and VB cannot load versions 4/5 of the BitmapInfoHeader, all bitmaps are processed manually. When possible, passed off to VB. The logic in the handling routines perform minimal sanity checks. Feel free to beef it up if desired.
4. GDI+ is used to extract ICM profiles from JPG, PNG, TIFF. Not guaranteed to find these if they exist in meta data tags vs. known ICM tags.

Since forum rules limit amount of stuff we attach, I'll include a link to my hotmail's one-drive where you can download additional images to play with. Googling for ICM Profiles can also yield more images to play with.
Attached Files
Viewing all 1324 articles
Browse latest View live




Latest Images