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

[VB6] - Custom rendering window.

$
0
0

In Windows 7, there was a remarkable thing - indication of progress on the taskbar button. To use this feature on VB6 (and any other language) you need to create an object TaskBarList, get ITaskBarList3 interface and use its methods - SetProgressState and SetProgressValue. In my module, I added the ability to set the state of the progress bar on the taskbar, and duplicated this indicator on the form itself + added ability to use animated icons in the form header (also supported by the usual icons). From this example, you can learn how to draw the non-client area of the window, make buttons that are highlighted when hovering. The example uses double buffering, so everything works smoothly and without flicker. This module can be connected to any project with any forms.
Functions:
SetNCSkin - set new style window;
RemoveNCSkin - remove style from window;
SetIcon - set animated (or simple) icon to window;
PlayAnimation - enable playing icon animation;
StopAnimation - stop animation playing;
SetProgressState - set state of taskbar button;
GetProgressState - get state of taskbar button;
SetProgressValue - set value of progressbar in the taskbar button (0..1);
GetProgressValue - same, only get a value.

Example use:
Code:

Option Explicit
 
' Тестовая форма модуля пользовательской отрисовки окна
' © Кривоус Анатолий Анатольевич (The trick), 2014
 
Dim Value As Single
 
Private Sub cboIcon_Click()
    Select Case cboIcon.ListIndex
    Case 0: SetIcon Me, LoadResPicture("TRICKICON", vbResBitmap), 21
    Case 1: SetIcon Me, LoadResPicture("WAITICON", vbResBitmap), 20
    End Select
End Sub
 
Private Sub cmdDuplicate_Click()
    Dim frm As frmTest
    Set frm = New frmTest
    frm.Show
End Sub
 
Private Sub cmdHideProgress_Click()
    SetProgressState Me, TBPF_NOPROGRESS
End Sub
 
Private Sub cmdIcon_Click()
    PlayAnimation Me, 32, False
End Sub
Private Sub cmdIconLoop_Click()
    PlayAnimation Me, 32, True
End Sub
Private Sub cmdProgress_Click()
    tmrTimer.Enabled = True
    Value = 0
End Sub
Private Sub cmdShowProgress_Click()
    If optState(0).Value Then SetProgressState Me, TBPF_NORMAL
    If optState(1).Value Then SetProgressState Me, TBPF_PAUSED
    If optState(2).Value Then SetProgressState Me, TBPF_ERROR
End Sub
Private Sub cmdStopAnimation_Click()
    StopAnimation Me
End Sub
Private Sub cmdStopProgress_Click()
    tmrTimer.Enabled = False
End Sub
Private Sub Form_Load()
    SetNCSkin Me
    cboIcon.ListIndex = 0
End Sub
Private Sub Form_Unload(Cancel As Integer)
    RemoveNCSkin Me
End Sub
Private Sub optState_Click(Index As Integer)
    Call cmdShowProgress_Click
End Sub
 
Private Sub tmrTimer_Timer()
    Value = Value + 0.01
    SetProgressValue Me, Value
End Sub

Attached Files

[VB6] Bytarr - String-style operations by wrapping a Byte array

$
0
0
People seem to get tangled up in their underwear a lot trying to fiddle with binary data in String variables. Often they run into nightmares where they convert Unicode "to Unicode" and then back later, in the vain hope of avoiding data corruption. And then some locale boundary gets crossed and it all falls down. Hard.

From what I've seen the bulk of this comes from the desire to use String operations on binary data. But most of these are fairly trivial to synthesize, especially with the help of CopyMemory.


The Bytarr Class wraps a dynamic Byte array along with several properties and methods to make this easier.

You can use the Class for lots of applications, or when you only need one or two operations it can server as a template for inline code when you don't want the Class.


Bytarr (biter?) is bundled with a test program in the attachment. This also includes my Dump Class, which I find handy for debugging and testing.

Name:  sshot.png
Views: 77
Size:  8.0 KB


There may be lingering bugs, but these should be easily found and fixed as required. You could also add more operations or convert the Class into a binary stringbuilder for better performance when you need to accumulate a lot of chunks into one array.
Attached Images
 
Attached Files

Login and registry system for application

$
0
0
Hi all

As part of my Computing coursework I need to create an application as per a scenario. The full thing is explained in the pdf below:
Training Log.pdf

Due to my work being deleted, I was forced to start again a few weeks back. I decided to approach the scenario a different way. As opposed to creating a database I would use file storage to create and edit the records. My idea has been to create the records using the ''register'' form, but the problem has been that during the debugging phase, instead of creating new records each time it replaces the file each time. E.g, the file in question is called ''runner1'' and when I run the app, I input details and click ''send to file''. If I then open the file under Visual Basic 2008 > Debug > bin > runner1, it opens up a notepad document with the information I entered. However, if I were to debug again, then if I were to enter completely different data, it would not create a new file. Rather, ''runner1'' would simply have the previous information replaced with the new load. I also need to make it so my login system can use the ''ID'' and ''password'' stored in the files can be used for my login screen.

Here are two screenshots of the code I used to create this form of my application:
Name:  structure.PNG
Views: 15
Size:  12.0 KB
Name:  Proceed code.jpg
Views: 10
Size:  21.5 KB

Officially the complete coursework needs to be in by May 15th but my teachers wish to collect it all in by Easter, so I'm really under pressure to get this complete!

Can someone please tell me what I'm doing wrong? I'd really appreciate it, and I'm sorry if this turns out to be trivially easy. I'm a noob and an idiot but I suppose everyone was a beginner once.
Attached Images
  
Attached Images

[VB6] - Injection to another process.

$
0
0

Everyone knows the utility SPYXX. With it you can do a lot of interesting things. Among its features - View messages sent by the window, and the results of their treatment. I decided to do something like that just to VB6 (not as the creation of programs such as SPYXX, as well as a demonstration of the possibility of an injection of code from VB6, so that the functionality of a program is very small). As you know SPYXX does this by using a global hook, but I was interested in the idea of injection without DLL (DLL can be much easier to do, Richter describes how to inject several functions in a foreign process using DLL, and I put an example) and I decided to do a little differently. In my example code along with the window procedure directly copied into the address space of the desired process and it starts (only works with 32-bit applications). There I place the code that establishes a new procedure for processing messages for the window and sleeping thread. In the new procedure, I just superfluous to pass a parameter that someone else got the window, my window (frmSpy), hereinafter called the original window procedure. I have to say - the transfer is not the most efficient way, it was possible to make a much more effective working directly with "FileMapping", or asynchronously transmit 2 posts in a row. But I did not complicate the code over, because my ultimate goal is not effective. Cancel injection is performed awakening threads and completion of its natural way, then from its program I release resources. Work I checked in the debugger everything works as intended.
When running in another process, the runtime is not used, although it is possible to download and use (about context initialization thread separately) its functions, arrays, strings, etc. Also, there is a problem working with variables, as global variables "does not exist", and, accordingly, any reference to such variables could be fatal to the whole process. To call the API I'm using splicing "pseudofunctions API", replace the call to an unconditional jump to the desired function. Working with variables is carried out in a dedicated area for this. To keep it, I use "SetProp", because from "WindowProc" I can identify something only through "hWnd". If you need to add any global variables, it is possible in this field to allocate space for the string, etc. (for example to call "LoadLibrary" with the required parameter). If in VB was to work directly with pointers (without VarPtr, GetMem functions, etc.), it was much easier. You can do once the assembly adapter and it is possible to learn the values of variables passed to the stream without "SetProp" and "CopyMemory", but it's the details, who wants to - he did.
Everything works only in a compiled (native) form.

[VB6] Scroller - DataRepeater alternative

$
0
0
If the stock DataRepeater control works well for you that's just great. But sometimes it can be awkward to work with because of its use of data binding and the need for a separate OCX containing the "scrolled" control.

Refresher:

Quote:

The DataRepeater control functions as a scrollable container of data-bound user controls. Each control appears in its own row as a "repeated" control, allowing the user to view several data-bound user controls at once.

Scroller

Scroller, as presented here, is not a finished drop-in component but a technique that can be used as an alternative to the MSDatRep.ocx plus one or more additional custom "scrolled control" OCXs. Unlike the DataRepeater control, the Scroller technique shown here even allows scrolled items to vary in height.

Note that this demo only explores a repeated control that presents static information, i.e. it has no data entry controls. This simplifies the demo though you could certainly extend the concept to do so.

Instead of normal data binding, Scroller was built using a "virtual view" approach. As the user scrolls the Scroller control a callback event is raised to fetch data to be "painted" into the scrolled view. So you will still need access to the entire set of data, though it could be held in a database, a Recordset, or Collections and arrays as done in the demo.

If you added data entry/edit controls to your scrolled control you might want to add a second callback to feed changes back to the parent Form for storage.


Scroller Demo

The demo uses a set of Twitter™-like messages based on quotes and images from the movie Office Space, just to make it a little more entertaining.


Name:  sshot1.png
Views: 80
Size:  15.0 KB


While this demo doesn't do data entry, it does accept mouse clicks. A click on an item brings up a secondary window with more detail than may have fit in the scrollable view, e.g.:


Name:  sshot2.png
Views: 50
Size:  19.0 KB


This is obviously a stripped down bare example, but I hope you find uses for it. I'm not sure most programmers are even aware of the DataRepeater, and fewer still have bothered dealing with its quirks. Maybe this simplified approach will offer inspiration.

The trickiest part of this demo is the dynamic vertical sizing that tracks autosize Label controls. If you stripped that out there isn't a whole lot here.

The data and images are included. The data is in a delimited text format next to the JPEG images used here.
Attached Images
  
Attached Files

Enumerate Schannel Cipher Suites

$
0
0
Learning from our experience with BCryptEnumAlgorithms, we can enumerate the Cipher Suites supported by Schannel our system (43 on my system).

J.A. Coutts

Code:

Option Explicit
'================================
'EVENTS
'================================
Public Event Error(ByVal Number As Long, Description As String, ByVal Source As String)

Private Const MS_SCHANNEL_PROVIDER As String = "Microsoft SSL Protocol Provider"

Private Const NCRYPT_SSL_MAX_NAME_SIZE As Long = 64
Private Type NCRYPT_SSL_CIPHER_SUITE
    dwProtocol As Long
    dwCipherSuite As Long
    dwBaseCipherSuite As Long
    szCipherSuite(NCRYPT_SSL_MAX_NAME_SIZE) As Byte
    szCipher(NCRYPT_SSL_MAX_NAME_SIZE) As Byte
    dwCipherLen As Long
    dwCipherBlockLen As Long  'in bytes
    szHash(NCRYPT_SSL_MAX_NAME_SIZE) As Byte
    dwHashLen As Long
    szExchange(NCRYPT_SSL_MAX_NAME_SIZE) As Byte
    dwMinExchangeLen As Long
    dwMaxExchangeLen As Long
    szCertificate(NCRYPT_SSL_MAX_NAME_SIZE) As Byte
    dwKeyType As Long
End Type

'CNG API Declares
Private Declare Function SslOpenProvider Lib "ncrypt.dll" (ByRef hSslProvider As Long, ByVal pszProviderName As Long, ByVal dwFlags As Long) As Long
Private Declare Function SslFreeObject Lib "ncrypt.dll" (ByVal hObject As Long, ByVal dwFlags As Long) As Long
Private Declare Function SslEnumCipherSuites Lib "ncrypt.dll" (ByVal hSslProvider As Long, ByVal hPrivateKey As Long, ByRef ppCipherSuite As Long, ByRef ppEnumState As Long, ByVal dwFlags As Long) As Long
Private Declare Function SslFreeBuffer Lib "ncrypt.dll" (ByVal pvBuffer As Long) As Long

'API memory functions
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private Declare Function lstrlen Lib "kernel32" Alias "lstrlenW" (ByVal lpString As Long) As Long
Private Declare Function lstrcpyn Lib "kernel32" Alias "lstrcpynW" (ByVal lpStringDest As Long, ByVal lpStringSource As Long, ByVal iMaxLength As Long) As Long

'Constants for Cryptography API error messages
Private Const SOP As String = "SslOpenProvider"
Private Const SECS As String = "SslEnumCipherSuites"

Public Function Test1() As Boolean
    Const Routine As String = "clsSSL.Test1"
    Dim hSslProvider As Long
    Dim ppCipherSuite As Long 'NCRYPT_SSL_CIPHER_SUITE
    Dim ppEnumState As Long
    Dim lRet As Long
    Dim NameLen As Long
    Dim CipherName As String
    Dim N%
    lRet = SslOpenProvider(hSslProvider, StrPtr(MS_SCHANNEL_PROVIDER), 0)
    If lRet <> 0 Then
        RaiseEvent Error(lRet, SOP, Routine)
        GoTo ReleaseHandles
    End If
    While SslEnumCipherSuites(hSslProvider, 0&, ppCipherSuite, ppEnumState, 0) = 0
        NameLen = lstrlen(ppCipherSuite + 12)
        CipherName = Space$(NameLen)
        lstrcpyn StrPtr(CipherName), ppCipherSuite + 12, NameLen + 1
        Debug.Print CipherName
    Wend
ReleaseHandles:
    SslFreeBuffer ppCipherSuite
    SslFreeObject hSslProvider, 0
End Function

VB6 Handling of PNG-Sprites in a Game-like Scenario

$
0
0
Well, this small Demo shows, how to properly handle a Sprite-based "Game-Scenario"
(using a 64x64 tiled Map of "plain-Grass") - as well as a few other "static Sprites"
(as unmoving Trees, and two unmoving, but animated "Coins") - as well as four moving
(and animated) "Person-Sprites".

There's no vbRichClient5-Reference needed for this Demo - instead the transparent
(Alpha)Sprite-Rendering is ensured with a small Helper-Class cPngCacheGDIP,
which supports Alpha-Pngs, but also all kind of other Image-Resources.
I'd say, it's quite easy to either make or find nice PNG-Images for your Sprites...,
and thus good old "masked Bitmap-Handling" is "banned for good" here. ;)

The Demo handles the Sprites in 2 small and simple Classes (no Picture- or Image-Controls are needed)
and shows, how to use a normal VB-PictureBox as the Game-Canvas in Double-Buffered-Mode properly.
So there's no flickering, since any Sprites are rendered onto the (AutoRedraw-)BackBuffer,
before the Buffer is flipped back onto the Screen per PicCanvas.Refresh.

The "Game-Loop" is ensured over a fast ticking Timer here (for simplicitys sake) - and
refreshes the Screen with a new Scene (constantly redrawing 95 Sprites) any 15msec or so
(that's roughly 60Hz) - and it causes only 0.3% CPU-Load whilst doing so, because the
Systems AlphaBlend-Call is done in Hardware on most Systems these days.

The CodeBase is really quite small ...
When we leave out the unchanging Helper-Class cPngCacheGDIP, we have only:

modMain.bas
Code:

Option Explicit

Public PngCache As New cPngCacheGDIP 'let's declare it here for global usage
 
Sub Main()
  'add true Alpha-Channel-Png-resources (once, at App-Startup)
  PngCache.AddImage "Grass", App.Path & "\Res\Grass.jpg"
  PngCache.AddImage "Tree", App.Path & "\Res\Tree.png"
  PngCache.AddImage "AnimCoin", App.Path & "\Res\AnimCoin.png"
  PngCache.AddImage "Person", App.Path & "\Res\Person.png"

  fTest.Show 'load and show the Main-Form
End Sub

cSprites.cls (which aggregates the Sprites in a Collection and offers an Add-method)
Code:

Option Explicit

Public Col As New Collection

Public Sub AddAndInit(Sprite As cSprite, Key, ImgKey, x, y, Optional aShiftX, Optional aShiftY)
  Sprite.Key = Key
  Sprite.ImgKey = ImgKey
  Sprite.dX = PngCache.Width(ImgKey)
  Sprite.dY = PngCache.Height(ImgKey)
  Sprite.x = x
  Sprite.y = y
  If Not IsMissing(aShiftX) Then Sprite.aShiftX = aShiftX
  If Not IsMissing(aShiftY) Then Sprite.aShiftY = aShiftY
 
  Col.Add Sprite, Key
End Sub

cSprite.cls (which offers StateProperties for a single Sprite-Instance and Draw- and Animate-Methods)
Code:

Option Explicit
 
Public Key, ImgKey, x, y, dX, dY 'standard Properties
Public aShiftX, aShiftY, aX, aY  'additional Props for (optional) animation
 
Public Sub Draw(ByVal hDC As Long)
  PngCache.AlphaRenderTo hDC, ImgKey, x, y, IIf(aShiftX, aShiftX, dX), IIf(aShiftY, aShiftY, dY), aX, aY
End Sub

Public Sub MoveRel(xRel, yRel)
  x = x + xRel
  y = y + yRel
End Sub

Public Sub Animate()
  aX = aX + aShiftX: If aX >= dX - 1 Then aX = 0
  aY = aY + aShiftY: If aY >= dY - 1 Then aY = 0
End Sub

And finally the Form-Code, which ensures the Loading and animated rendering of the Sprites:
Code:

Option Explicit 'shows, how to make use of the two small Classes: cSprites and cSprite

Private x, y, Statics As New cSprites, Movers As New cSprites, Sprite As cSprite

Private Sub Form_Load()
  'add a static BackGround-Image onto our Canvas
  Set picCanvas.Picture = LoadPicture(App.Path & "\Res\Checker.jpg")
 
  'add the "Map"-Content (grass only in this demo)
  For y = 0 To 480 Step 64: For x = 0 To 640 Step 64
    Statics.AddAndInit New cSprite, "Grass_" & x & "_" & y, "Grass", x, y
  Next x, y
  Statics.Col.Remove "Grass_0_0" 'just to show, that "removing by key" works of course
  Statics.Col.Remove "Grass_128_128" 'and another one (leaving the BackGround-Image shine through)
 
  'add a few more static Sprites into the same (static) Collection as the Map-Content above
  Statics.AddAndInit New cSprite, "Tree1", "Tree", 40, 40
  Statics.AddAndInit New cSprite, "Tree2", "Tree", 300, 200
  Statics.AddAndInit New cSprite, "Tree3", "Tree", 540, 320
  Statics.AddAndInit New cSprite, "AnimCoin1", "AnimCoin", 580, 80, 44
  Statics.AddAndInit New cSprite, "AnimCoin2", "AnimCoin", 60, 420, 44
 
  'now the "PlayerSprites" which are to be moved (we add them to the Movers-Collection)
  Movers.AddAndInit New cSprite, "Person1", "Person", 120, 120, 45
  Movers.AddAndInit New cSprite, "Person2", "Person", 500, 120, 45
  Movers.AddAndInit New cSprite, "Person3", "Person", 500, 320, 45
  Movers.AddAndInit New cSprite, "Person4", "Person", 120, 320, 45
 
  Caption = Statics.Col.Count + Movers.Col.Count & " Sprites handled in a 60Hz-Refresh-Loop"
End Sub
 
Private Sub Redraw() 'our central scene-drawing-routine
  picCanvas.Cls 'clear anything on the backbuffer (leaving only the background-picture)
    DrawAllSpritesIn Statics 'all statics first
    DrawAllSpritesIn Movers 'movers are drawn on top of statics
  picCanvas.Refresh 'flip the DoubleBuffer to the Screen
End Sub

Private Sub DrawAllSpritesIn(Sprites As cSprites)
  For Each Sprite In Sprites.Col
    Sprite.Draw picCanvas.hDC
  Next
End Sub
 
Private Sub tmrRefresh_Timer() 'we handle the Sprites-State in a timer
Static Cnt&: Cnt = (Cnt + 1) Mod 72
Static Fac&: If Cnt = 0 Then Fac = IIf(Fac, -Fac, 1)
 
  For Each Sprite In Statics.Col
    Select Case Sprite.Key
      Case "AnimCoin1", "AnimCoin2": If Cnt Mod 4 = 0 Then Sprite.Animate
    End Select
  Next
 
  For Each Sprite In Movers.Col
    Select Case Sprite.Key
      Case "Person1": Sprite.MoveRel 1 * Fac, 1 * Fac
      Case "Person2": Sprite.MoveRel -1 * Fac, 1 * Fac
      Case "Person3": Sprite.MoveRel -1 * Fac, -1 * Fac
      Case "Person4": Sprite.MoveRel 1 * Fac, -1 * Fac
    End Select
    If Cnt Mod 3 = 0 Then Sprite.Animate
  Next
 
  Redraw
End Sub

Here's a ScreenShot:




And here the Zip-Archive for the Project:
PngSprites.zip

Have fun,

Olaf
Attached Files

VB6 fast MJPG-Stream-Decoding from (http-streamed) WebCams - vbRichClient5

$
0
0
Ok, the title is mentioning it already - this Demo is related to the decoding
of "true WebCam-streams" (not to the Cams, which hang on your USB-port),
and those Internet-Cams are usually directly accessible per Browser over http -
and then (most) often pump their stream continously, using: mime=multipart/x-mixed-replace
on a (Keep-Alive) http-Connection.

The Demo shows, how to capture such streams in a decent performance
without using a Browser-Client ... as e.g. FireFox, which has no problem with
e.g. this URL here in Helsinki (Finland): http://77.72.56.163/mjpg/video.mjpg

Important in such a scenario is a fast (M)JPEG-Decoder - and vbRichClient5 contains
a quite speedy one (based on libJPGTurbo), which works about factor 2-3 faster than
what's available on Windows per default (e.g. when decoding per WIA or GDI+).

So, to avoid using a Browser-Client (and the default-JPG-Decoder which comes with
the Browser-API), we would also need our own socket-handling for the http-GET-
request, and in this case we use cTCPClient (also from RC5) for this part.

What's also shown is, how to configure a CommandString for the quite wellknown
VLC-MediaPlayer, which supports different Streaming-Modes - and to be compatible
with true WebCam-Streaming, we have to force VLC into "multipart/x-mixed-replace"-
mode as well.

This is done in the Demo-Code in Sub Main() - and I've split the different parts
of the VLC-CommandString into easier to understand snippets, as shown below:

complete content of modMain.bas (the important parts, which ensure WebCam-compatible http-streaming are in Magenta)
Code:

Option Explicit
 
Sub Main() 'just a short demonstration, how to build a proper VLC-http-MJPG-CommandString
  Dim FilePath$:  FilePath = "C:\Tests\Test.mp4"
  Dim VLCPath$:    VLCPath = "C:\Program Files (x86)\VideoLAN\VLC\vlc.exe"
  Dim transcode$:  transcode = "vcodec=MJPG,vb=5600,scale=Automatic,acodec=none"
  Dim http$:      http = "mime=multipart/x-mixed-replace;boundary=--7b3cc56e5f"
  Dim dst$:        dst = "127.0.0.1:8080/"
 
  If MsgBox("Shall I start a VLC-Instance for: " & FilePath & "?", vbYesNo) = vbYes Then
    Shell VLCPath & " " & FilePath & " " & BuildStreamSettingsVLC(transcode, http, dst)
  End If
 
  fWebCam.Show
End Sub

Public Function BuildStreamSettingsVLC(transcode As String, http As String, dst As String) As String
  Const VLCBaseSettings$ = ":sout=#transcode{@1}:standard{access=http{@2},mux=mpjpeg,dst=@3}"
  BuildStreamSettingsVLC = Replace(Replace(Replace(VLCBaseSettings, "@1", transcode), "@2", http), "@3", dst)
End Function

So, the above code asks any time the Demo is started, if you want to Shell an appropriate
Instance of the VLC-Player (in Stream-Mode) - in case you find that unnerving, just comment
out the appropriate Lines in Sub Main().

The achieved performance is quite good - also because the final (stretched) rendering happens
over a Cairo-DirectX-uploaded Surface (which performs the final stretch to the picVid-PictureBox
in Hardware)...

The CPU-Load is only around 1% whilst receiving+JPGDecoding+StretchedRendering takes place
with about 24-25FPS receiving streamed VideoFrames from a 1280x696 VLC-transcoded Video.
(the VLC-Player which has to perform a transcoding from MP4 to MJPG in this case, has a bit
more Stress - and thus needs about 4-5% of the CPU - but it runs in a different process and
doesn't affect the VB6-App whilst doing so...

Here's a ScreenShot, which shows the whole thing in action:


And here's the Download-Link for the Demo-Zip:
WebCamRC5.zip

Olaf
Attached Files

[VB6] Code Snippet: Converting an hIcon to an hBitmap

$
0
0
So this isn't a full on project (although it will be part of an upcoming one), just some code- doing this conversion in VB turned out to be very difficult for someone unfamiliar with graphics APIs. Found tons of other people having the same question with mostly incomplete answers, and I couldn't find anywhere showing it done in VB.. spent hours figuring it out from other codes, which turned the issue into something far more complicated than the ultimate solution I found turned out to be.

The use case this was developed as a response to was to be able to use take hIcon's extracted from files and be able to use them as a value for MENUITEMINFO.hbmpItem.
Code:


'Declares
Private Type BITMAPINFOHEADER
  biSize                  As Long
  biWidth                  As Long
  biHeight                As Long
  biPlanes                As Integer
  biBitCount              As Integer
  biCompression            As Long
  biSizeImage              As Long
  biXPelsPerMeter          As Long
  biYPelsPerMeter          As Long
  biClrUsed                As Long
  biClrImportant          As Long
End Type

Private Type BITMAPINFO
  bmiHeader                As BITMAPINFOHEADER
  bmiColors(3)            As Byte
End Type

Private Const DIB_RGB_COLORS = 0&
Private Const DI_NORMAL = 3&

Private Declare Function GetDC Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function DeleteDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function ReleaseDC Lib "user32" (ByVal hWnd As Long, ByVal hdc As Long) As Long
Private Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function SelectObject Lib "gdi32" (ByVal hdc As Long, ByVal hObject As Long) As Long
Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
Private Declare Function CreateDIBSection Lib "gdi32" (ByVal hdc As Long, pBitmapInfo As BITMAPINFO, ByVal un As Long, ByRef lplpVoid As Any, ByVal Handle As Long, ByVal dw As Long) As Long
Private Declare Function DrawIconEx Lib "user32" (ByVal hdc As Long, ByVal XLeft As Long, ByVal YTop As Long, ByVal hIcon As Long, ByVal CXWidth As Long, ByVal CYWidth As Long, ByVal istepIfAniCur As Long, ByVal hbrFlickerFreeDraw As Long, ByVal diFlags As Long) As Long

'Functions
Public Function HBitmapFromHIcon(hIcon As Long, cx As Long, cy As Long) As Long
        Dim hdc As Long
        Dim hBackDC As Long
        Dim hBitmap As Long
        Dim hBackSV As Long

        hdc = GetDC(0)
        hBackDC = CreateCompatibleDC(hdc)
        hBitmap = Create32BitHBITMAP(hBackDC, cx, cy)
       
        hBackSV = SelectObject(hBackDC, hBitmap)
        DrawIconEx hBackDC, 0, 0, hIcon, cx, cy, 0, 0, DI_NORMAL
       
        Call SelectObject(hBackDC, hBackSV)
        Call ReleaseDC(0, hdc)
        Call DeleteDC(hBackDC)
HBitmapFromHIcon = hBitmap
End Function
Public Function Create32BitHBITMAP(hdc As Long, cx As Long, cy As Long) As Long
Dim bmi As BITMAPINFO
Dim hdcUsed As Long
    bmi.bmiHeader.biSize = Len(bmi.bmiHeader)
    bmi.bmiHeader.biPlanes = 1
    bmi.bmiHeader.biCompression = 0

    bmi.bmiHeader.biWidth = cx
    bmi.bmiHeader.biHeight = cy
    bmi.bmiHeader.biBitCount = 32
    Create32BitHBITMAP = CreateDIBSection(hdc, bmi, DIB_RGB_COLORS, ByVal 0&, 0, 0)
   
End Function

The initial hIcon can be from any source that has that type returned; e.g. ExtractIcon[Ex], LoadImage, etc.

EDIT - KNOWN ISSUES
**The above code only works for 24-bit icons with an alpha channel.**
For 24-bit icons without an alpha channel, and icons with 256 or fewer colors:
Code:

Public Function HBitmapFromHIconNoAlpha(hIcon As Long) As Long
Dim himg As Long
Dim hb As Long
GdipCreateBitmapFromHICON hIcon, himg
GdipCreateHBITMAPFromBitmap himg, hb, &HFF000000
GdipDisposeImage himg
HBitmapFromHIconNoAlpha = hb
End Function

(note that this requires gdiplus to be initialized, so use the entire module below which includes it)

This of course requires knowing which one to use, I'm working on one without GDIPlus, in the mean time there's this one from Leandro Ascierto's clsMenuImage:
Code:

Option Explicit
'If you are using this don't just copy the main function, note the startup and shutdown of gdiplus
Public gInitToken As Long
Private Const PixelFormat32bppRGB  As Long = &H22009
Private Type GdiplusStartupInput
    GdiplusVersion          As Long
    DebugEventCallback      As Long
    SuppressBackgroundThread As Long
    SuppressExternalCodecs  As Long
End Type
Private Type RECT
    Left As Long
    Top As Long
    Right As Long
    Bottom As Long
End Type
Private Type ARGB
    Blue            As Byte
    Green          As Byte
    Red            As Byte
    Alpha          As Byte
End Type
Private Type BitmapData
    Width          As Long
    Height          As Long
    Stride          As Long
    PixelFormat    As Long
    Scan0          As Long
    Reserved        As Long
End Type
Private Enum ImageLockMode
    ImageLockModeRead = &H1
    ImageLockModeWrite = &H2
    ImageLockModeUserInputBuf = &H4
End Enum
Private Declare Function GdiplusStartup Lib "GdiPlus.dll" (Token As Long, gdipInput As GdiplusStartupInput, GdiplusStartupOutput As Long) As Long
Private Declare Sub GdiplusShutdown Lib "GdiPlus.dll" (ByVal Token As Long)
Private Declare Function GdipCreateBitmapFromHBITMAP Lib "GdiPlus.dll" (ByVal hBmp As Long, ByVal hPal As Long, GpBitmap As Long) As Long
Private Declare Function GdipGetImagePixelFormat Lib "GDIplus" (ByVal Image As Long, ByRef PixelFormat As Long) As Long
Private Declare Function GdipGetImageDimension Lib "GDIplus" (ByVal Image As Long, ByRef Width As Single, ByRef Height As Single) As Long
Private Declare Function GdipBitmapLockBits Lib "GDIplus" (ByVal BITMAP As Long, ByRef RECT As RECT, ByVal Flags As ImageLockMode, ByVal PixelFormat As Long, ByRef LockedBitmapData As BitmapData) As Long
Private Declare Function GdipBitmapUnlockBits Lib "GDIplus" (ByVal BITMAP As Long, ByRef LockedBitmapData As BitmapData) As Long
Private Declare Function GdipDisposeImage Lib "GdiPlus.dll" (ByVal Image As Long) As Long

Public Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long


Public Sub InitGDIP()
    Static Token    As Long
    If Token = 0 Then
        Dim gdipInit As GdiplusStartupInput
        gdipInit.GdiplusVersion = 1
        GdiplusStartup Token, gdipInit, ByVal 0&
        gInitToken = Token
    End If
End Sub

Public Function pvIsAlphaIcon(ByVal IconHandle As Long) As Boolean

    Dim tARGB() As ARGB
    Dim tRECT As RECT
    Dim tICONINFO As ICONINFO
    Dim tBitmapData As BitmapData
    Dim lPixelFormat As Long
    Dim lngX As Long
    Dim lngY As Long
    Dim sngWidth As Single
    Dim sngHeight As Single
    Dim lngArgbBmp As Long
    Dim lngColorBmp As Long
    Dim bolRet As Boolean
    Dim hr As Long
   
On Error GoTo e0
If gInitToken = 0 Then InitGDIP
hr = GetIconInfo(IconHandle, tICONINFO)
If hr <> 0 Then
    If tICONINFO.hBMColor <> 0 Then
        If GdipCreateBitmapFromHBITMAP(tICONINFO.hBMColor, 0&, lngColorBmp) = 0 Then
            If GdipGetImagePixelFormat(lngColorBmp, lPixelFormat) = 0 Then
                If lPixelFormat <> PixelFormat32bppRGB Then
                    bolRet = False
                Else
                    If GdipGetImageDimension(lngColorBmp, sngWidth, sngHeight) = 0 Then
                        With tRECT
                            .Right = CLng(sngWidth)
                            .Bottom = CLng(sngHeight)
                        End With
                        ReDim tARGB(tRECT.Right - 1&, tRECT.Bottom - 1&)
                        With tBitmapData
                            .Scan0 = VarPtr(tARGB(0&, 0&))
                            .Stride = 4& * tRECT.Right
                        End With
                        If GdipBitmapLockBits(lngColorBmp, tRECT, ImageLockModeRead Or ImageLockModeUserInputBuf, lPixelFormat, tBitmapData) = 0 Then
                            For lngY = 0 To tBitmapData.Height - 1
                                For lngX = 0 To tBitmapData.Width - 1
                                    If tARGB(lngX, lngY).Alpha > 0 Then
                                        If tARGB(lngX, lngY).Alpha < 255 Then
                                            bolRet = True
                                            Exit For
                                        End If
                                    End If
                                Next lngX
                                If bolRet Then Exit For
                            Next lngY
                            Call GdipDisposeImage(lngArgbBmp)
                            Call GdipBitmapUnlockBits(lngColorBmp, tBitmapData)
                        End If
                    End If
                End If
            End If
            Call GdipDisposeImage(lngColorBmp)
        End If
        Call DeleteObject(tICONINFO.hBMColor)
    End If
    Call DeleteObject(tICONINFO.hBMMask)
Else
    bolRet = False
End If
pvIsAlphaIcon = bolRet
ReleaseGDIP
On Error GoTo 0
Exit Function

e0:
Debug.Print "modGDIP.pvIsAlphaIcon.Error->" & Err.Description & " (" & Err.Number & ")"
   
End Function
Public Function HBitmapFromHIconNoAlpha(hIcon As Long) As Long
Dim himg As Long
Dim hb As Long
GdipCreateBitmapFromHICON hIcon, himg
GdipCreateHBITMAPFromBitmap himg, hb, &HFF000000
GdipDisposeImage himg
HBitmapFromHIconNoAlpha = hb
End Function
Public Sub ReleaseGDIP()
GdiplusShutdown gInitToken
End Sub

[VB6] List/Execute File Handlers: IAssocHandler and IAssocHandlerInvoker (Vista+)

$
0
0
Association Handlers Demo

IAssocHandler | IEnumAssocHandlers | IAssocHandlerInvoker

Windows Vista and above provider a shell interface to get a list of all handlers registered to open a particular file type that also returns where the icon is and what the friendly name is. Most importantly, it provider an interface to invoke that handler in a much better way than trying to make a command to launch it.

These things were just crying out to be made into an example of how to replicate the Open With menu in VB. There's even two groups: the recommended ones that show up on that menu in Explorer, or if so inclined you could list all the ones that appear on the actual Open With dialog.

Requirements
The project uses the newest version of oleexp.tlb, my Modern Interfaces Type Library project, which is a large expansion of the original olelib. The latest versions of both of those must be referenced, see the link for more details.

Ambition is also a bit of a requirement... using the invoker (which you don't have to) involves getting deep into IShellFolder and pidls, and there's a lot of supporting code.

Basic Outline

SHAssocEnumHandlers is called to get an object that can enumerate all the handlers for the extension passed- IEnumAssocHandlers.
That object lists IAssocHandler interfaces for each handler, and in the demo project we use the information provided by that to list them on a menu.
When one is chosen, the handlers are cycled through again to find the desired one to launch- it's here that we need some complex stuff like IShellFolder and IDataObject.


Main Code
Code:

Dim sFile As String
Dim sExt As String
Dim nIcoIdx As Long
Dim MII() As MENUITEMINFO
Dim miiZ As MENUITEMINFO

Dim uRec() As AssocInfo
Dim i As Long, j As Long, k As Long
Dim ieah As IEnumAssocHandlers
Dim iah As IAssocHandler
Dim hr As Long
Dim lPtr As Long
Dim sApp As String
Dim sIcon As String
Dim hIcon As Long
Dim hBmp As Long
Dim PT As POINTAPI
Dim idCmd As Long
Dim hMenu As Long

Const widBase As Long = 1000
Const sCP As String = "Choose program..."

j = -1
ReDim MII(0)
ReDim uRec(0)

sFile = Text1.Text
sExt = Right(sFile, Len(sFile) - InStrRev(sFile, ".") + 1)

'First, we use an API call to get the object that will list the handlers
'The other flag value will show all handlers- the recommended ones are the
'ones that show up in Explorer's right click open-with menu

hr = SHAssocEnumHandlers(StrPtr(sExt), ASSOC_FILTER_RECOMMENDED, ieah)
If hr <> S_OK Then Exit Sub

'now we're ready to start enumerating the handlers, in this project
'we're going to load them into a popup menu
hMenu = CreatePopupMenu()

'Most IEnum______ classes work exactly like this. .Next fills the IAssocHandler iface
Do While (ieah.Next(1, iah, 0) = 0)
    If (iah Is Nothing) = False Then
        j = j + 1
        ReDim Preserve MII(j)
        ReDim Preserve uRec(j) 'in case we need the info later
       
        Call iah.GetUIName(lPtr) 'can't receive a LPWSTR As String like sending it
        sApp = BStrFromLPWStr(lPtr)
        uRec(j).sUIName = sApp
        Call iah.GetName(lPtr)
        sApp = BStrFromLPWStr(lPtr)
        uRec(j).sPath = sApp
        Call iah.GetIconLocation(lPtr, i)
        sIcon = BStrFromLPWStr(lPtr)
        uRec(j).sIcon = sIcon
        uRec(j).nIcon = i
       
        'association interface includes icon info for our menu
        Call ExtractIconEx(sIcon, i, ByVal 0&, hIcon, 1)
        hBmp = HBitmapFromHIcon(hIcon, 16, 16) 'can't use hIcon directly
       
        With MII(j)
            .cbSize = Len(MII(j))
            .fMask = MIIM_ID Or MIIM_STRING Or MIIM_BITMAP
            .wID = widBase + j
            .cch = Len(uRec(j).sUIName)
            .dwTypeData = uRec(j).sUIName
            .hbmpItem = hBmp
           
            Call InsertMenuItem(hMenu, j, True, MII(j))
           
        Call DestroyIcon(hIcon)
        End With
             
    Else
        Debug.Print "iah=Nothing"
    End If
    Set iah = Nothing
Loop

'Add separator and open with other
miiZ.cbSize = Len(miiZ)
miiZ.fMask = MIIM_ID Or MIIM_TYPE
miiZ.fType = MFT_SEPARATOR
miiZ.wID = 9999
Call InsertMenuItem(hMenu, -1, False, miiZ)

miiZ.fMask = MIIM_ID Or MIIM_STRING
miiZ.wID = 3000
miiZ.cch = Len(sCP)
miiZ.dwTypeData = sCP
Call InsertMenuItem(hMenu, -1, False, miiZ)

Call GetCursorPos(PT)
PT.y = PT.y + 5

idCmd = TrackPopupMenu(hMenu, TPM_LEFTBUTTON Or TPM_RIGHTBUTTON Or TPM_LEFTALIGN Or TPM_TOPALIGN Or TPM_HORIZONTAL Or TPM_RETURNCMD, PT.x, PT.y, 0, Me.hWnd, 0)

Set ieah = Nothing

If idCmd Then
    If idCmd = 3000 Then
        OpenWith Text1.Text, OAIF_ALLOW_REGISTRATION Or OAIF_EXEC, Me.hWnd
    Else
       
        k = idCmd - widBase
    '    MsgBox "Handler selected: " & uRec(k).sUIName & vbCrLf & _
    '            uRec(k).sPath & vbCrLf & _
    '            "Icon=" & uRec(k).sIcon & "," & uRec(k).nIcon, _
    '            vbOKOnly, App.Title
    '
        'i know.. pidl and ishellfolder stuff is confusing, but there's no other way
        Dim isf As IShellFolder
        Dim pidl As Long, pidlFQ As Long
        Dim zc As Long
        pidlFQ = PathToPidl(sFile)
        pidl = GetPIDLParent(pidlFQ)
        Set isf = GetIShellFolder(isfDesktop, pidl)
        Dim pidlChild As Long
        pidlChild = GetItemID(pidlFQ, GIID_LAST)
       
        'Now that we have the pidl and shellfolder representing our file, we create
        'an IDataObject for it, then re-enumerate the handlers- we still have the
        'selected one stored in k. it may be possible to just have an array to avoid
        'the reenumeration
        Dim ido As olelib.IDataObject
        Call isf.GetUIObjectOf(0, 1, pidlChild, IID_IDataObject, 0, ido)
        Dim invk As IAssocHandlerInvoker
        hr = SHAssocEnumHandlers(StrPtr(sExt), ASSOC_FILTER_RECOMMENDED, ieah)
        Do While (ieah.Next(1, iah, 0) = 0)
            If (iah Is Nothing) = False Then
                If zc = k Then
                    'theoretically, we could take the path to the executable and
                    'run a launch command, but the actual invoke interfacer is a
                    'far better choice
                    Call iah.CreateInvoker(ido, invk)
                    invk.Invoke
                    Exit Do
                Else
                    zc = zc + 1
                End If
            End If
            Set iah = Nothing
        Loop
    End If
End If
 
If pidlFQ Then CoTaskMemFree pidlFQ
If pidl Then CoTaskMemFree pidl
If pidlChild Then CoTaskMemFree pidlChild

Set ido = Nothing
Set isf = Nothing
Set invk = Nothing
Set iah = Nothing
Set ieah = Nothing

End Sub


Included in ZIP
-All the core and supporting code required to generate a menu like that in the picture.
-The latest versions of oleexp.tlb and olelib.tlb (v1.5 and v1.91 respectively; this version or better is required). TLB files only, for full source visit the main oleexp project thread.

Future Goals
This is the very first release, and I do plan on trying to simplify things a bit as well as test out Unicode support. Please report any and all bugs so they can be fixed in the next version.
Attached Files

[VB6] GDI+ Matrix For Rendering and Hit Testing

$
0
0
GDI+ offers a matrix object that can be applied to various other GDI+ objects. One of those is the Graphics object (similar to GDI's hDC). With a matrix, we can simultaneously scale, rotate, shear & offset/translate a rendering in basically one call.

The attached offers such options in a simple sample project. The matrix is created and can be cached for all future rendering, unless of course something changes and the matrix should be recreated. What's kind of neat is that an inverted copy of the matrix can be used for hit testing on the rotated, scaled, sheared, translated rendering relative to the original object, un-rotated, un-scaled, un-sheared, un-translated.

Please read the comments included in the code, especially within the pvCreateDisplayMatrix routine, before asking questions about the code

Name:  Untitled.jpg
Views: 25
Size:  44.6 KB
Attached Images
 
Attached Files

FloodFill code using pure VB code (no API)

$
0
0
Note it runs slow, but I believe this has more to do with the fact that it uses PSet and Point (rather than getting an array of pixels using GetDibBits and then operating on the array) than it does with some inherant slowness of the algorithm. The algorithm uses a stack (albeit a simulated one with a Long array and a separate Long variable for the stack pointer, not the real stack and pointer that you can directly access if you know assembly language) to store points to check to see if they are clear (equal to RefCol, the reference color), and thus to be filled in with a fill color (FillCol) which is generated randomly at the start of the FloodFill operation (and is always guarantied to not be the same as RefCol, because of how it is picked).

Here is the code for Module1
Code:

Dim Stack(10000000 - 1) As Long
Public SP As Long

Public Sub Push(ByVal Value As Long)
SP = SP + 1
Stack(SP) = Value
End Sub

Public Sub Pop(ByRef Value As Long)
Value = Stack(SP)
SP = SP - 1
End Sub

And here is the code for Form1
Code:

Private Sub Form_Load()
Randomize
SP = -1
End Sub

Private Sub Form_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
If Button <> 1 Then Exit Sub
If Check1.Value Then FloodFill X, Y Else PSet (X, Y)
End Sub

Public Sub FloodFill(ByVal X0 As Long, ByVal Y0 As Long)
Dim X As Long
Dim Y As Long
Dim n As Long
Dim RefCol As Long
Dim FillCol As Long

RefCol = Me.Point(X0, Y0)
Do
    FillCol = RGB(Int(Rnd * 256), Int(Rnd * 256), Int(Rnd * 256))
Loop Until FillCol <> RefCol

Push Y0
Push X0


Do Until SP = -1
    Pop X
    Pop Y
    If Point(X, Y) = RefCol Then
        PSet (X, Y), FillCol
        n = n + 1
        If n Mod 10000 = 0 Then
            Refresh
            If n Mod 100000 = 0 Then DoEvents
        End If
        If Point(X, Y - 1) = RefCol Then
            Push Y - 1
            Push X
        End If
        If Point(X, Y + 1) = RefCol Then
            Push Y + 1
            Push X
        End If
        If Point(X - 1, Y) = RefCol Then
            Push Y
            Push X - 1
        End If
        If Point(X + 1, Y) = RefCol Then
            Push Y
            Push X + 1
        End If
    End If
Loop
Form1.Caption = n
End Sub

Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
If (Button = 1) And (Check1.Value = 0) Then Line -(X, Y)
End Sub

Private Sub Form_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
If (Button = 1) And (Check1.Value = 0) Then PSet (X, Y)
End Sub

The only things you need to do to Form1 to make this work are add a checkbox control, change the form's ScaleMode to Pixel, and change the form's AutoRedraw property to True.

Draw shapes with the checkbox unchecked, and then click inside the shapes you draw after making the checkbox checked, to fill the shapes you have drawn.

[VB6] API File Drag from multiple paths w/o native OLE or dragsource, SHDoDragDrop

$
0
0


It took many months of wasting hours, giving up, and revisiting to finally get a working solution, and the only previous VB solution was monstrously complex. I understand very few people will find this useful, but wanted to share anyway due to the lack of answers I found while trying to get it working and the simplicity over other solutions.

Background
DragDrop functionality is easy if you're using, say, VB's ListView, but what if you're using a ListView created via CreateWindowEx that has no OLEStartDrag/OLESetData with pre-provided DataObject, and want to start a drag operation that can be dragged around Windows Explorer (or any drop target accepting dropped files)? Previous solutions have used the DoDragDrop API and then had to implement their own IDataObject and IDropSource interfaces, and I had yet to see one that supported multiple paths. Turns out that unless you require other-than-default behavior, you accomplish a full drag-to-explorer operation in just a few lines of code. The SHDoDragDrop API provides both a default drag source and a default drag icon showing the number of files, just like Explorer. It also supports the action options menu if you drag with the right button. And no further action is required, the receiving program handles the operation.

The included sample project doesn't use any subclassed/CreateWindowEx ListViews, but does show how you can initiate the operation from any arbitary point in code given a list of files.

Requirements
This code does require a typelib with the IDataObject interface such as olelib (either the original or my expansion) or OLEGuids to be added as a reference. Works with XP and above.

For the purposes of the below code, we'll assume you have your own routine to enumerate the full paths of the files that are selected. This code will typically be for a Begin Drag notification, such as LVN_BEGINDRAG.

Code:

Public Sub InitDrag(sSelFullPath() As String)
Dim hr0 As Long
Dim iData As IDataObject
Dim apidl() As Long
Dim cpidl As Long
Dim rpidl As Long
Dim pidlDesk As Long
Dim lRetDD As Long
Dim i As Long
Dim AllowedEffects As DROPEFFECTS
Call SHGetSpecialFolderLocation(0, CSIDL_DESKTOP, pidlDesk) 'we support multiple paths by creating an IDataObject with the desktop as the root and then supplying fully qualified pidls rather than child pidls

'EnumSelectedFiles - Whatever routine you have to get your selected files list, a standard routine like
'  Do
'    i = ListView_GetNextItem(hLVS, i, LVNI_SELECTED)
'    If (i <> LVI_NOITEM) Then
ReDim apidl(UBound(sSelFullPath)) 'sSelFullPath would then contain the full path to the file, C:\folder\file.ext, //Computer/folder/file.ext
For i = 0 To UBound(apidl)
      apidl(i) = GetPIDLFromPathW(sSelFullPath(i)) 'support function to return fully qualified pidls for each file, see below
Next i
cpidl = UBound(apidl) + 1
Call SHCreateDataObject(pidlDesk, cpidl, VarPtr(apidl(0)), ByVal 0&, IID_IDataObject, iData) 'even though the desktop pidl is just the zero-terminator, don't confuse that with passing zero instead of this-- results in an invalid drag source that can't be dropped anywhere
If iData Is Nothing Then
    Debug.Print "Failed to created IDataObject"
    Exit Sub
End If
           
AllowedEffects = DROPEFFECT_COPY Or DROPEFFECT_MOVE Or DROPEFFECT_LINK

hr0 = SHDoDragDrop(0&, ObjPtr(iData), 0, AllowedEffects, lRetDD) 'theoretically you can supply your own IDropSource implementation, but I never got it working

Debug.Print "hr0=" & hr0 & ",lRet=" & lRetDD 'hr0 contains the HRESULT of the call, and lRetDD is the result of the operation, see the full DROPEFFECT description for all possible values
Call CoTaskMemFree(pidlDesk)
For i = 0 To UBound(apidl)
    Call CoTaskMemFree(apidl(i))
Next i
Set iData = Nothing

End Sub
'If instead this is in a WndProc, you'll probably want to cancel the notification by returning 1 and exiting before a DefWndProc call.

'Supporting declares and functions:
Public Declare Function SHGetSpecialFolderLocation Lib "shell32.dll" (ByVal hWndOwner As Long, ByVal nFolder As Long, pidl As Long) As Long
Public Const CSIDL_DESKTOP = &H0
Public Declare Sub CoTaskMemFree Lib "ole32.dll" (ByVal pv As Long) ' Frees memory allocated by the shell

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 SHDoDragDrop Lib "shell32" (ByVal hWnd As Long, ByVal pdtObj As Long, ByVal pdsrc As Long, ByVal dwEffect As Long, pdwEffect As Long) As Long
Public Declare Function ILCreateFromPathW Lib "shell32" (ByVal pwszPath As Long) As Long
Public Function GetPIDLFromPathW(sPath As String) As Long
  GetPIDLFromPathW = ILCreateFromPathW(StrPtr(sPath))
End Function
Public Function IID_IDataObject() As UUID
'0000010e-0000-0000-C000-000000000046
Static IID As UUID
 If (IID.Data1 = 0) Then Call DEFINE_UUID(IID, &H10E, CInt(&H0), CInt(&H0), &HC0, &H0, &H0, &H0, &H0, &H0, &H0, &H46)
  IID_IDataObject = 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

You can specify your own drag image with something like LVM_CREATEDRAGIMAGE, but when dragged into Explorer the standard one is overlayed on top of it, here's a simple technique that creates a drag image of the selected items icon:
Code:

'from http://www.mvps.org/emorcillo/en/code/vb6/listviewdragdropimage.shtml
Public Sub ListView_StartDrag( _
  ByVal hWndListView As Long, _
  Optional ByVal X As Long = 20, _
  Optional ByVal Y As Long = 20)
Dim tPoint As POINTAPI
Dim LITEM As Long

  ' Get the selected item
  LITEM = SendMessage(hWndListView, LVM_GETNEXTITEM, -1, ByVal LVNI_SELECTED)

  ' Get a ImageList with
  ' the drag image
  m_lIL = SendMessage(hWndListView, LVM_CREATEDRAGIMAGE, LITEM, tPoint)

  ' Start the image dragging
  ImageList_BeginDrag m_lIL, 0, X, Y
  ImageList_DragEnter 0, 0, 0

  ' Start the timer
  m_lTimer = SetTimer(0, 0, 1, AddressOf pvTimerDragMove)

End Sub
Public Sub DragComplete()
 
  ' Stop the timer
  KillTimer 0, m_lTimer

  ' End the image dragging
  ImageList_EndDrag
 
  ' Destroy the ImageList
  ImageList_Destroy m_lIL
 
End Sub
Private Sub pvTimerDragMove( _
  ByVal hWnd As Long, _
  ByVal uMsg As Long, _
  ByVal idEvent As Long, _
  ByVal dwTime As Long)
Dim tPoint As POINTAPI
 
  ' Get the cursor position
  GetCursorPos tPoint

  ' Move the image to the new cursor position
  ImageList_DragMove tPoint.X, tPoint.Y
 
End Sub

Attached Files

[VB6] GDI+ Matrix For Rotation/Scale/Shear and Hit Testing

$
0
0
GDI+ offers a matrix object that can be applied to various other GDI+ objects. One of those is the Graphics object (similar to GDI's hDC). With a matrix, we can simultaneously scale, rotate, shear & offset/translate a rendering in basically one call.

The attached offers such options in a simple sample project. The matrix is created and can be cached for all future rendering, unless of course something changes and the matrix should be recreated. What's kind of neat is that an inverted copy of the matrix can be used for hit testing on the rotated, scaled, sheared, translated rendering relative to the original object, un-rotated, un-scaled, un-sheared, un-translated.

Please read the comments included in the code, especially within the pvCreateDisplayMatrix routine, before asking questions about the code

Name:  Untitled.jpg
Views: 92
Size:  44.6 KB


Just some notes. When rotating and not choosing both horizontal & vertical center alignment, keep in mind that you are rotating around a specific point on the edge of the picturebox. The top/left pixel of the image is where rotation begins within the image, not the center of the image. Should anyone want to rotate this way, obviously, the edges of the viewing area would not be a good point to begin rotation from, therefore the pvCreateDisplayMatrix allows an optional point to be passed. But since the sample project uses the edges of the viewing area if not centering rotation, the following is provided:

- Alignment determines point of rotation
- Point of rotation is optional passed parameters to function or, if no parameters passed, relative to display area

Center/Center :: rotation is from center of image over the point of rotation
any other combination :: rotation is from top/left pixel of image around the the point of rotation

So, let's say you have horizontal alignment on right edge & vertical alignment on bottom edge, ok? Well, the picturebox is now only displaying the northwest quadrant of the 360 degree rotation area. The other 3 quadrants are off the picturebox. If you try to rotate image at 45 degrees around the bottom/right corner, the rendering would fall in the southeast quadrant and not viewable. Angles from 180 to 269 would be the northwest quadrant.
Attached Images
 
Attached Files

VB6 + vbRichClient5 (lightweight, fully Alpha-aware Windowless-Controls)

$
0
0
Just a short Demo, to show how to write Alpha-aware, Windowless-Controls,
using Cairo-Drawing against a (Control-covering) BackBuffer-Surface (avoiding
AutoRedraw on the Control itself).

Note, that this is not using the RC5-WidgetEngine (which allows windowless controls
as well, but implemented in normal VB6-Classes) - here a normal VB6 (Project-Private)
Usercontrol is sufficient (only making use of the Raw-Drawing-capabilities of Cairo internally).

Tried for a BareBones-approach to keep the example easy to understand
(the whole Demo is only about 80 lines of code total).

What's interesting maybe (aside from the Cairo-Drawing), is the usage of the
RC5-Properties Enumerator, which allows (in a generic way) to write and read the 3
Properties of the Control (Alpha, ImgKey and Moveable) to and from the PropertyBag.

ScreenShot:



And Download-Link:
WindowlessControlsCairo.zip

Have fun,

Olaf
Attached Files

VB6 fast EdgeDetection (direct Pixel-Manipulation on Cairo-Surfaces)

$
0
0
Whilst cairo is known as a VectorGraphics-Library - it supports fast Blending-Operators
on its Pixel-Surfaces (aka ImageSurfaces) - and most wrappers around this library will
offer (in addition to cairos blending-ops) a few additional Pixel-Massaging-Methods.

The vbRichClient has 6 of that category already implemented:
- cCairo.PreMultiplyAlpha
- cCairo.DeMultiplyAlpha
- cCairoSurface.FastBlur
- cCairoSurface.GaussianBlur
- cCairoSurface.Sharpen
- cCairoSurface.AdjustColors (Brightness, Contrast, Gamma - all in one routine)

Now, there's certainly much more pixel-algorithms out there in the wild -
but the above few are what I restricted myself to, since they are often needed.

To accomodate those who want to perform their own PixelOps on those Surfaces, I've choosen
to make pixel-access as easy as possible - and so there exist two Array-Binding-Methods:
- cCairoSurface.BindArray(ByteArray) ... and its companion .ReleaseArray ByteArray
- cCairoSurface.BindArrayLong(LongArray) ... and its companion .ReleaseArrayLong LongArray

This is done without copying any Data - I guess the underlying SafeArray-technique is quite
wellknown in the meantime - and the Arrays in question need to be dynamic and uninitialized ones.

Well, that said - let's look at what the Demo has to offer:
Edge-Detection is a wide field - and I decided not to implement "the whole bunch of algos for comparison",
instead I concentrated on a very simple one (the "Roberts-Cross") - with focus on performance.

Since the algorithm is so simple (only using a small 2x2 Kernel), it was quite easy to avoid an
"inner Kernel-Loop" - and since the Formulas were not all that complex in this case too, coming
up with some Lookup-Tables for them was also relative easy to accomplish.

I've tuned it a bit though:
Instead of a SquareRoot on the "squared differences", I found that a logarithmic scaling produced
somewhat nicer results - and since the kernel is so small (compared to Sobel, Prewitt & Co.), the
algo captures fine details quite well, but tends to be "noisy" - so, a slight (and fast) PreBlurring was
added into the processing-queue, to remedy that.

For comparison (direct links instead of the forums img-tag, to get "the real image" -
and to easier compare - after loading them all - by just clicking between Browser-Tabs):
https://softwarebydefault.files.word..._grayscale.jpg
https://softwarebydefault.files.word..._grayscale.jpg
http://vbRichClient.com/Downloads/Lo...ithPreBlur.png

The last link of the above three, was generated with the Demo.

Performancewise, the Algo (including the steps: PreBlur, GreyScaling, LogarithmicRoberts, GammaCorrection, Sharpen)
takes in Sum only about 20msec total when native compiled (performing all steps on a 800x600 TrueColor-Image).

The Demo includes a few Demo-Images - here some ScreenShots:

Monarch-Original-Image:


Monarch-EdgeDetected and in ColorMode (algo performed on each color-channel separately).
The GreyScale-Result-Link I've posted already further above...


And another Result of one of the Demo-Images in Color-Mode:


Here's the Source-Zip:
EdgeDetection.zip

Have fun,

Olaf
Attached Files

Exporting crystal report generated from vb6 straight to pdf without the viewing...

$
0
0
Private Sub cmdView_Click(Index As Integer)
Select Case Index
Case 0
If Me.optRR(0).Value = True Then irisreports (16)
If Me.optRR(1).Value = True Then irisreports (17)
If Me.optRR(2).Value = True Then irisreports (18)
If Me.optRR(3).Value = True Then irisreports (19)
If Me.optRR(4).Value = True Then irisreports (20)
If Me.optRR(5).Value = True Then irisreports (21)
If Me.optRR(6).Value = True Then irisreports (22)

If Me.optTransfer(0).Value = True Then irisreports (23)
If Me.optTransfer(1).Value = True Then irisreports (24)
If Me.optTransfer(2).Value = True Then irisreports (25)
If Me.optTransfer(3).Value = True Then irisreports (26)
If Me.optTransfer(4).Value = True Then irisreports (27)
If Me.optTransfer(5).Value = True Then irisreports (28)
If Me.optTransfer(6).Value = True Then irisreports (29)
Case 1
If Me.optEndingInv(0).Value = True Then irisreports (12)
If Me.optEndingInv(1).Value = True Then irisreports (13)
If Me.optEndingInv(2).Value = True Then irisreports (14)
If Me.optEndingInv(3).Value = True Then irisreports (15)
If Me.optEndingInv(4).Value = True Then irisreports (33)
Case 2
If Me.optCGS.Value = True Then
generateAverageCost
irisreports (30)
End If
If Me.optSalesSummary(0).Value = True Then irisreports (31)
If Me.optSalesSummary(1).Value = True Then irisreports (32)
'mat 08082006
If Me.optReportToGenerate(6).Value = True Then irisreports (46)

If Me.optReportToGenerate(0).Value = True Then irisreports (35) 'product breakdown
If Me.optReportToGenerate(1).Value = True Then irisreports (36) 'daily sales report net
If Me.optReportToGenerate(2).Value = True Then irisreports (40) 'daily sales report gross
If Me.optReportToGenerate(3).Value = True Then irisreports (37) 'tender department
If Me.optReportToGenerate(4).Value = True Then irisreports (38) 'sales register
If Me.optReportToGenerate(5).Value = True Then irisreports (39) 'gross profit

If Me.optSalesReceiptsWithTender.Value = True Then irisreports (60)
If Me.optSalesReceiptNumbers.Value = True Then irisreports (61)
If Me.optVATSales.Value = True Then irisreports (63)


Case 3
If Me.optJournal.Value = True Then irisreports (34)
Case 4
If Me.OptInventoryAdjustment.Value = True Then irisreports (62)


End Select

End Sub

How to track TextBox carot position, notify use if text1.SelStart = Len(text1.Text)

$
0
0
On the Form two ListBoxes are displayed side by side and a TextBox is on the right side.
ListBox 2 is displayed having several CheckBoxes. When the user clicks on a CheckBox,
from Private Sub List2_Click() I use selItem = List2.ListIndex to select an Article in a .txt file. Many times the length of the Article is too great to be assigned to text1.Text so I divide it into portions using .Text = Mid(Art, (thisPortion * ArtMaxSize ) + 1, ArtMaxSize), where thisPortion starts out as 0 and ArtMaxSize = the maximum length of text1.Text.
The TextBox is Locked (Read-Only).
I tried to track the TextBox carot position with a Do Loop before List2_Click() End Sub:
Do
Select Case text1.SelStart
Case 0 'at beginning of thisPortion
'InputBox(Read previous portion of Article Y/N)
Case Len(text1.Text)
' InputBox(Read next portion of Article Y/N)
'if yes then go to next portion, thisPortion=thisPortion +1
Case Else
'Let user move around in TextBox
End Select
Loop

The Do Loop causes the Form with the two ListBoxes and the TextBox not to be displayed. Do I need to Set the Focus on the TextBox before going into the Do Loop or is there a better way to track the TextBox carot position? I also tried using a Private Sub text1_KeyDown(KeyCode as Integer, Shift As Integer) to trap the navigation keys and setting the carot location for vbKeyLeft, VbKeyRight, etc. but this seemed more difficult to code.
Maybe someone knows of a Windows API for vb6 where I can track the TextBox carot position while moving around in the TextBox and notify the user when reaching the end of this portion, e.g. "Please Wait, Loading Portion 3 of 5."
Please help.
Thanks,
John

VB6 compact Charting-Class (using an InMemory-DB as the DataStorage for x,y-Plots)

$
0
0
This Demo is making use of the Cairo-Drawing-, as well as the InMemory-DB-features of vbRichClient5.

Background:
Although the contained cChart-Class is able to render any x,y-ValuePairs - often one has to
handle and store "timestamp-based Data", as e.g. from a "Stock-Exchange-Ticker" (when the
y-Values are Prices) - or from a "Data-Logger" of a measurement-device (where y-Data comes
in as more "physically related units"...

Though in both cases we have some kind of time-values in the x-Members of the x,y-Pairs -
and the amount of data can get quite large "over time".

So, a DB-based storage is not only useful to "archive and persist" such x,y-Pairs (on Disk) -
it is also useful, to make use of "time-range-queries".

These are usually queries which start from the most recent TimeStamp-Value in the DB-Table,
then covering a certain range "to the left of this RightMost-x,y-Pair".

E.g. "Show me a Chart for all the Values in the last hour" (or the last day, or the last week, etc.)

Now one might say: "Yeah - a DB and SQL-queries would be nicer to use - but for my small project
I don't want to introduce a DB-Engine, just for more comfortable Charting..."

Well, and this is the scenario where an InMemory-DB makes sense - offering all of the benefits
of a full DB-Engine, at basically no cost - later on (in case persisting of the Data on Disk becomes
a topic) - the App would be upgradable to a filebased-DB just by changing the DB-Creation-Line.

What's nice with DB-Engines in general, is that they offer a robust and convenient way, to
perform "grouping aggregations" - which is useful for Charting, in case one wants to visualize
trends, averages, Min- and Max-Values etc.

With SQL one can handle such tasks quite nicely and efficient in one single statement,
as e.g. this one here, which I used in the Demo, to do Grouping on the x.y-Pairs
with regards to Average, Min- and Max-Values - and the time-range (starting from
a MaxDate, then reaching parts - or multiples - of HoursBack into the DataStorage.

Code:

Private Function GetData(ByVal MaxDate#, Optional ByVal HoursBack# = 1, Optional ByVal GroupingSeconds& = 60) As cRecordset
  With New_c.StringBuilder
    .AppendNL "Select Avg(TS) AvgT, Avg(Price) AvgP, Min(Price) MinP, Max(Price) MaxP From Ch1"
    .AppendNL "Where TS Between " & Str(MaxDate - HoursBack / 24) & "+1e-6 And " & Str(MaxDate)
    .AppendNL "Group By CLng(0.500001 + TS*24*60/" & Str(GroupingSeconds / 60) & ") Order By TS"

    Set GetData = MemDB.GetRs(.ToString)
  End With
End Function

Important for InMemory-Usage of DB-Engines is, that they can be filled with Data fast (being
roughly at "Dictionary-Level") - and with SQLite that is a given, as the following ScreenShot
shows ... second-based values of two full days (2*86400) were transferred into the DB in
about 370msec, included in this case also the time, to create an index on the TimeStamp-column.



The above ScreenShot shows also, how the Min- Max- and Avg-Values are rendered finally -
due to the index we build at the time of data-import, we can then perform fast
querying and rendering in typically 10-30msec per complete Chart...

Below is another Picture, which shows the timing, needed for both (querying and rendering),
and at this occasion also how the same Data will be rendered with cChart, when certain
Options are changed (no BSpline, no Min-Values, no Max-Values - note the automatic
scaling of the Y-Axis, which now covers a different value-range):



Here's the Demo-Zip:
SimpleCharting.zip

So, yeah - and as is normal for RichClient-based code, the whole thing is quite compact -
cChart.cls, as well as the second Code-Module (fMain.frm) contain both less than 100 lines of code...
have fun adapting it to your needs.


Olaf
Attached Files

Well I did it. WMP Remoting in VB6, Change Vis, Control EQ Etc

$
0
0
Not sure where to put this, but I figured here would be as good a place
as any. Mods, do what you must if not lol :chuckle:

I sat down last week, 11 years after I actually needed it lol, and figured out how to remote Windows Media Player and control the visualizations, equalizer, and other things.

In case anyone finds it useful, I release it into the wild..

Here guys, feedback welcome.

Frodo



https://github.com/bagginsfrodo/VB6-...eMediaServices



Here is a copy of the readme, might explain a bit:

Code:

'Readme.txt
'©2015 Kevin Lincecum AKA FrodoBaggins  email: baggins DOT frodo AT_SYMBOL gmail DOT com
'License: Free usage as long as you send me an email and mention me somewhere in your readme, about, etc



Hi, I'm Kevin Lincecum, aka frodobaggins. A long time ago I developed a car pc application for
playing media and other things. "FrodoPlayer" if you want to search for it. Like a lot of beginning
programmers, I chose VB to do my programming in, mainly because of the rapid application development
aspect of it. I never really encountered any difficulties with the project, except when it came to
doing advanced stuff with windows media player. I used windows media player as the "engine" of my
media playing project, and for the most part, it was great. However, my users and I eventually wanted
to change the visualizations, and use the equalizer. Well Microsoft says you can't from VB..or
really from C++ either.

But it turns out you can, IF you use the remoting services to host the control in local mode, then
you can skin the player, and control the objects through the skin. BUT, Microsoft says you can't remote
the control in VB, only in C++. Well I didn't accept this then, or now. I searched off and on for a long
time trying to figure it out, even after I let that part of my life go, that application long behind me.
It still bothered me even years later, and after some more searching, it seems that no one else figured
it out, or did, but didn't share it ! Grrrr!

Recently, I was looking over some things where I had been playing with doing this in .NET. I had it working
pretty good there, and it got me interested in doing it in VB6. It turns out it's not that difficult to do
and most of the information on how to do it was in the documentation the whole time, I just wasn't looking
well enough.

Anyway, here's how it was done.

When I was looking before, an aquaintence I knew from the MP3Car forums, Chuck Holbrook, aka godofcpu, posted
in a microsoft mailing list some hints on how to control the visualization from C++ once the player was remoted.
It didn't seem to difficult to implement if I could get the player remoted, but getting the player remoted was
the real problem.

Microsoft says you can't remote the player in anything but C++. We all know that's bull, but figuring it out is
a bear. (Even though the information was actually in the docs![not for vb]) Well screwing around a few years ago
I wanted to do it in vb.net, so I began the search anew. I ran across Eric Gunnersons page which led me to a post
by Jonathan Dibble on how to remote the player in C#. It was pretty trivial to convert this code to VB.Net, and
soon I had a remoted player.

A short time after, I had complete control of the visualizations and EQ (thanks to the hints before from godofcpu)
in VB.NET. I was overjoyed, and used it a bit in some personal projects. I wondered then if I could back port it
to VB6, but never got very far because life got in the way. It happens!

Fast forward to a few days ago, and I decided, better late than never. I looked at the code again, and the docs
again. The lights went off in my head. The docs and code samples from .NET said I needed to implement
IWMPRemoteMediaServices, and IServiceProvider. To use IServiceProvider, I also needed to implement IOleClientSite.

So I first made a new type library with for VB with the IWMPRemoteMediaServices interface, then made a class
from the interface.

I started to make another TypLib for IOleClientSite, and IServiceProvider, but then remembered Eduardo A. Morcillo
aka Edanmo, had done some excellent work in the OLE area. Browsed google to find his website "Namespace Edanmo,"
and sure enough, he had two excellent ole type libraries with the definitions already there!

I implemented all the interfaces, tied it all together with ductape, spit, and bubblegum, and called SetClientSite on
the WMP Control... And BAM, I got a call to my IServiceProvider interface. I wired that up to my IWMPRemoteMediaServices
interface and that worked too. (Several crashes later).

Now I made a simple skin from my old VB.Net code I knew worked, and tried wmp.uimode = "custom"..
It didn't work.
For a long time.
And longer.
Then I realized my skin was *****.
So I fixed it, and HOLY MF CRAP IT WORKED. I EVEN PASSED IT A SCRIPTABLE OBJECT.
GOT INFO BACK FROM IT! WOOT!!

I celebrated.

Then I wrote the skin up properly to pass the visualization objects and eq back to my test code, and a few lines later,
that worked too!

I celebrated some more. I realize this is an OLD issue, but I was still excited.

Now a little while after that, I realized how stressed I had been back then that no one seemed to want to help with this
issue, and decided that it was time to show the world, just in case it was still usefull.


So, I have coded up a nice little test harness with I hope all the pieces to the puzzle for you to peruse and
use to your hearts content. All I ask for in return is if you actually use any of this, or find this helpful,
that you mention me somewhere in your about box, readme, etc. You probably want to mention some of the others too,
depending on what you do with it.


Better late than never,
Kevin Lincecum
AKA frodobaginns
baggins DOT frodo AT_SYMBOL gmail DOT com





P.S. This project is not meant to be a documentation of using wmp in a custom program, there are plenty of
examples on how best to do that.

Also, read the comments. It's real easy if you are not careful to cause an improper teardown (aka crash) of objects with this code.
I may in the future, or you may (I suggest) to wrap this up in a custom control or something to remove these obstacles from
your main app. Get it right, then just use it!

Viewing all 1325 articles
Browse latest View live




Latest Images