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

VB6 - Elliptical Curve Diffie Hellman (ECDH) Demo

$
0
0
The heart of this demo is the "GetECCKey" function. It is a dual purpose function, requiring 4 supplied variables (pAlg, KeyLen, bPublicECCKey, & bPrivateECCKey). "pAlg" is a pointer to the wide string descriptor of the algorithm used ("SHA256"). "KeyLen" is self explanatary (256), and "bPublicECCKey" & "bPrivateECCKey" are the Public\Private key pair. If the key fields are empty, the function generates and returns a new key pair. If the Private key, and the Public key from the other end are supplied, then the function returns the Agreed Secret.

So how do we know if it is returning the correct information? For this, we look to RFC 5903. It supplies 2 key pairs and the Agreed Secret they should return.
--------------------------------------------------------------------------
We suppose that the initiator's Diffie-Hellman private key is:
i: C88F01F5 10D9AC3F 70A292DA A2316DE5 44E9AAB8 AFE84049 C62A9C57 862D1433
Then the public key is given by g^i=(gix,giy) where:
gix: DAD0B653 94221CF9 B051E1FE CA5787D0 98DFE637 FC90B9EF 945D0C37 72581180
giy: 5271A046 1CDB8252 D61F1C45 6FA3E59A B1F45B33 ACCF5F58 389E0577 B8990BB3
The KEi payload is as follows.
00000048 00130000 DAD0B653 94221CF9 B051E1FE CA5787D0 98DFE637 FC90B9EF
945D0C37 72581180 5271A046 1CDB8252 D61F1C45 6FA3E59A B1F45B33 ACCF5F58
389E0577 B8990BB3
--------------------------------------------------------------------------
But that doesn't exactly describe how Microsoft wants the information. CNG requires the Private key to include the Public key, and the "Magic" description in the first 8 bytes is different.
Code:

Public Key A
45 43 4B 31 20 00 00 00 (ECK1 )
DA D0 B6 53 94 22 1C F9 B0 51 E1 FE CA 57 87 D0
98 DF E6 37 FC 90 B9 EF 94 5D 0C 37 72 58 11 80
52 71 A0 46 1C DB 82 52 D6 1F 1C 45 6F A3 E5 9A
B1 F4 5B 33 AC CF 5F 58 38 9E 05 77 B8 99 0B B3
Private Key A
45 43 4B 32 20 00 00 00 (ECK2 )
DA D0 B6 53 94 22 1C F9 B0 51 E1 FE CA 57 87 D0
98 DF E6 37 FC 90 B9 EF 94 5D 0C 37 72 58 11 80
52 71 A0 46 1C DB 82 52 D6 1F 1C 45 6F A3 E5 9A
B1 F4 5B 33 AC CF 5F 58 38 9E 05 77 B8 99 0B B3
C8 8F 01 F5 10 D9 AC 3F 70 A2 92 DA A2 31 6D E5
44 E9 AA B8 AF E8 40 49 C6 2A 9C 57 86 2D 14 33

--------------------------------------------------------------------------
We suppose that the response Diffie-Hellman private key is:
r: C6EF9C5D 78AE012A 011164AC B397CE20 88685D8F 06BF9BE0 B283AB46 476BEE53
Then the public key is given by g^r=(grx,gry) where:
grx: D12DFB52 89C8D4F8 1208B702 70398C34 2296970A 0BCCB74C 736FC755 4494BF63
gry: 56FBF3CA 366CC23E 8157854C 13C58D6A AC23F046 ADA30F83 53E74F33 039872AB
The KEr payload is as follows.
00000048 00130000 D12DFB52 89C8D4F8 1208B702 70398C34 2296970A 0BCCB74C
736FC755 4494BF63 56FBF3CA 366CC23E 8157854C 13C58D6A AC23F046 ADA30F83
53E74F33 039872AB
The Diffie-Hellman common value (girx,giry) is:
girx: D6840F6B 42F6EDAF D13116E0 E1256520 2FEF8E9E CE7DCE03 812464D0 4B9442DE
giry: 522BDE0A F0D8585B 8DEF9C18 3B5AE38F 50235206 A8674ECB 5D98EDB2 0EB153A2
The Diffie-Hellman shared secret value is girx.
--------------------------------------------------------------------------
Code:

Public Key B
45 43 4B 31 20 00 00 00 (ECK1 )
D1 2D FB 52 89 C8 D4 F8 12 08 B7 02 70 39 8C 34
22 96 97 0A 0B CC B7 4C 73 6F C7 55 44 94 BF 63
56 FB F3 CA 36 6C C2 3E 81 57 85 4C 13 C5 8D 6A
AC 23 F0 46 AD A3 0F 83 53 E7 4F 33 03 98 72 AB
Private Key B
45 43 4B 32 20 00 00 00 (ECK2 )
D1 2D FB 52 89 C8 D4 F8 12 08 B7 02 70 39 8C 34
22 96 97 0A 0B CC B7 4C 73 6F C7 55 44 94 BF 63
56 FB F3 CA 36 6C C2 3E 81 57 85 4C 13 C5 8D 6A
AC 23 F0 46 AD A3 0F 83 53 E7 4F 33 03 98 72 AB
C6 EF 9C 5D 78 AE 01 2A 01 11 64 AC B3 97 CE 20
88 68 5D 8F 06 BF 9B E0 B2 83 AB 46 47 6B EE 53

When Private Key A and Public Key B are supplied to "GetECCKey", it returns:
Code:

D6 84 0F 6B 42 F6 ED AF D1 31 16 E0 E1 25 65 20
2F EF 8E 9E CE 7D CE 03 81 24 64 D0 4B 94 42 DE

And when Private Key B and Public Key A are supplied to "GetECCKey", it also returns:
Code:

D6 84 0F 6B 42 F6 ED AF D1 31 16 E0 E1 25 65 20
2F EF 8E 9E CE 7D CE 03 81 24 64 D0 4B 94 42 DE

But the program returns a different key:
Key
Code:

05 19 DC 09 B3 6E FA D1 D0 0A EF 1D 5B 53 B1 00
20 2E B9 10 B5 DE 0D ED E7 5F 19 0A 35 7A 36 7D

Therein lies one of the major problems with CNG. The only way to recover the Agreed Secret is as a hashed value, and Microsoft does not supply a NULL hash. If we click the Hash button, it uses an SHA256 hash on the value supplied by RFC 5903.
Hashed Secret
Code:

05 19 DC 09 B3 6E FA D1 D0 0A EF 1D 5B 53 B1 00
20 2E B9 10 B5 DE 0D ED E7 5F 19 0A 35 7A 36 7D

J.A. Coutts
Attached Images
 
Attached Files

Remember Form's Position for Next Execution, Multi-Monitor

$
0
0
Here's something I just cobbled together for a project I'm working on, and this occasionally comes up in these forums.

It's a couple of procedures (with support procedures) for saving the last position of a form, and putting it back there the next time it's shown. Now, this is easy so long as we only have one monitor. However, things get a bit tricky when we're on a multi-monitor system, and especially if that system may often have different monitor configurations (such as my laptop I haul around with me all over the place).

These procedures should be robust to changes in configurations. Furthermore, they make sure the form will always be fully shown on some monitor the next time it's shown.

The registry is used to store last position, so it'll be machine/user specific.

It's very easy to use. Here's an example in a form:

Code:


Option Explicit

Private Sub Form_Load()
    FetchAndSetFormPos Me
End Sub

Private Sub Form_Unload(Cancel As Integer)
    SaveFormPos Me
End Sub


And here's code for it that you can throw into a BAS module:

Code:


Option Explicit
'
Private Type POINTAPI
    X As Long
    Y As Long
End Type
Private Type RECT
    Left  As Long
    Top  As Long
    Right As Long ' This is +1 (right - left = width)
    Bottom As Long ' This is +1 (bottom - top = height)
End Type
Private Type MONITORINFO
    cbSize As Long
    rcMonitor As RECT
    rcWork As RECT
    dwFlags As Long
End Type
'
Private Declare Function EnumDisplayMonitors Lib "user32" (ByVal hdc As Long, lprcClip As Any, ByVal lpfnEnum As Long, dwData As Long) As Long
Private Declare Function MonitorFromWindow Lib "user32.dll" (ByVal hWnd As Long, ByVal dwFlags As Long) As Long
Private Declare Function MoveWindow Lib "user32" (ByVal hWnd As Long, ByVal X As Long, ByVal Y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal bRepaint As Long) As Long
Private Declare Function GetWindowRect Lib "user32" (ByVal hWnd As Long, lpRect As RECT) As Long
Private Declare Function GetMonitorInfo Lib "user32.dll" Alias "GetMonitorInfoA" (ByVal hMonitor As Long, ByRef lpmi As MONITORINFO) As Long
'

Public Sub FetchAndSetFormPos(frm As Form, Optional TopPixelsAdd As Long, Optional LeftPixelsAdd As Long)
    ' Initial (default) position is in center, biased toward top.
    ' The TopPixelsAdd and LeftPixelsAdd can be used to move from the center (top biased) default position.  They can be negative.
    '
    Dim iMon As Long
    Dim iTop As Long
    Dim iLeft As Long
    Dim hMonitor As Long
    Dim iFrmHeight As Long
    Dim iFrmWidth As Long
    Dim iMonHeight As Long
    Dim iMonWidth As Long
    '
    iFrmHeight = WindowHeightPx(frm.hWnd)
    iFrmWidth = WindowWidthPx(frm.hWnd)
    '
    iMon = GetSetting(App.Title, "Settings", frm.Name & "Mon", 1&)
    If iMon < 1& Then iMon = 1&
    If iMon > MonitorCount Then iMon = 1&
    hMonitor = MonitorHandle(iMon)
    iMonHeight = MonitorHeightPx(hMonitor)
    iMonWidth = MonitorWidthPx(hMonitor)
    '
    iTop = GetSetting(App.Title, "Settings", frm.Name & "Top", (iMonHeight - iFrmHeight) \ 3 + TopPixelsAdd)
    iLeft = GetSetting(App.Title, "Settings", frm.Name & "Left", (iMonWidth - iFrmWidth) \ 2 + LeftPixelsAdd)
    If iTop + iFrmHeight > iMonHeight Then iTop = iMonHeight - iFrmHeight
    If iLeft + iFrmWidth > iMonWidth Then iLeft = iMonWidth - iFrmWidth
    If iTop < 0 Then iTop = 0
    If iLeft < 0 Then iLeft = 0
    '
    PositionWindowOnMonitor frm.hWnd, hMonitor, iLeft, iTop
End Sub

Public Sub SaveFormPos(frm As Form)
    SaveSetting App.Title, "Settings", frm.Name & "Top", WindowTopPx(frm.hWnd)
    SaveSetting App.Title, "Settings", frm.Name & "Left", WindowLeftPx(frm.hWnd)
    SaveSetting App.Title, "Settings", frm.Name & "Mon", MonitorNumForHwnd(frm.hWnd)
End Sub

Public Function MonitorCount() As Long
    EnumDisplayMonitors 0&, ByVal 0&, AddressOf MonitorCountEnum, MonitorCount
End Function

Private Function MonitorCountEnum(ByVal hMonitor As Long, ByVal hdcMonitor As Long, uRect As RECT, dwData As Long) As Long
    dwData = dwData + 1
    MonitorCountEnum = 1 ' Count them all.
End Function

Public Function MonitorNumForHwnd(hWnd As Long) As Long
    MonitorNumForHwnd = MonitorNum(MonitorHandleForHwnd(hWnd))
End Function

Public Function MonitorHandleForHwnd(hWnd As Long) As Long
    Const MONITOR_DEFAULTTONULL = &H0
    MonitorHandleForHwnd = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONULL)
End Function

Public Function MonitorNum(hMonitor As Long) As Long
    ' This one returns the monitor number from the monitor's handle.
    ' ZERO is returned if not found.
    ' Monitors are ONE based when counted, no holes.
    ' These numbers do NOT necessarily match numbers in control panel.
    Dim dwData As Long
    dwData = -hMonitor  ' Send it in negative to indicate first iteration.
    EnumDisplayMonitors 0&, ByVal 0&, AddressOf MonitorNumEnum, dwData
    If Abs(dwData) <> hMonitor Then MonitorNum = dwData                          ' The number is returned in dwData if found.
End Function

Private Function MonitorNumEnum(ByVal hMonitor As Long, ByVal hdcMonitor As Long, uRect As RECT, dwData As Long) As Long
    Static iCount As Long
    If dwData < 0 Then
        iCount = 1
        dwData = -dwData
    Else
        iCount = iCount + 1
    End If
    If dwData = hMonitor Then
        dwData = iCount
        MonitorNumEnum = 0 ' Found it.
    Else
        MonitorNumEnum = 1 ' Keep looking.
    End If
End Function

Public Sub PositionWindowOnMonitor(hWnd As Long, hMonitor As Long, ByVal lLeftPixel As Long, ByVal lTopPixel As Long)
    ' This can be used to position windows on other programs so long as you have the hWnd.
    Dim lHeight As Long
    Dim lWidth As Long
    '
    lHeight = WindowHeightPx(hWnd)
    lWidth = WindowWidthPx(hWnd)
    '
    lLeftPixel = lLeftPixel + MonitorLeftPx(hMonitor)
    lTopPixel = lTopPixel + MonitorTopPx(hMonitor)
    '
    MoveWindow hWnd, lLeftPixel, lTopPixel, lWidth, lHeight, 1&
End Sub

Public Function WindowHeightPx(hWnd As Long) As Long
    Dim r As RECT
    GetWindowRect hWnd, r
    WindowHeightPx = r.Bottom - r.Top
End Function

Public Function WindowWidthPx(hWnd As Long) As Long
    Dim r As RECT
    GetWindowRect hWnd, r
    WindowWidthPx = r.Right - r.Left
End Function

Public Function WindowTopPx(hWnd As Long) As Long
    ' This adjusts for the monitor the window is on.
    Dim r As RECT
    GetWindowRect hWnd, r
    WindowTopPx = r.Top - MonitorTopPx(MonitorHandleForHwnd(hWnd))
End Function

Public Function WindowLeftPx(hWnd As Long) As Long
    ' This adjusts for the monitor the window is on.
    Dim r As RECT
    GetWindowRect hWnd, r
    WindowLeftPx = r.Left - MonitorLeftPx(MonitorHandleForHwnd(hWnd))
End Function

Public Function MonitorLeftPx(hMonitor As Long) As Long
    ' If you just have the number, do: MonitorLeftPx(MonitorHandle(MonitorNum))
    Dim uMonInfo As MONITORINFO
    uMonInfo.cbSize = LenB(uMonInfo)
    If GetMonitorInfo(hMonitor, uMonInfo) = 0 Then Exit Function
    MonitorLeftPx = uMonInfo.rcMonitor.Left
End Function

Public Function MonitorTopPx(hMonitor As Long) As Long
    ' If you just have the number, do: MonitorTopPx(MonitorHandle(MonitorNum))
    Dim uMonInfo As MONITORINFO
    uMonInfo.cbSize = LenB(uMonInfo)
    If GetMonitorInfo(hMonitor, uMonInfo) = 0 Then Exit Function
    MonitorTopPx = uMonInfo.rcMonitor.Top
End Function

Public Function MonitorHandle(ByVal MonitorNum As Long) As Long
    ' Monitors are ONE based when counted, no holes.
    ' These numbers do NOT necessarily match numbers in control panel.
    Dim dwData As Long
    dwData = -MonitorNum  ' Send it in negative.
    EnumDisplayMonitors 0&, ByVal 0&, AddressOf MonitorHandleEnum, dwData
    If dwData > 0 Then MonitorHandle = dwData                          ' The handle is returned in dwData if found.
End Function

Private Function MonitorHandleEnum(ByVal hMonitor As Long, ByVal hdcMonitor As Long, uRect As RECT, dwData As Long) As Long
    dwData = dwData + 1 ' They come in negative to stay out of the way of handles.
    If dwData = 0 Then ' We're at the one we want.
        dwData = hMonitor
        MonitorHandleEnum = 0
    Else
        MonitorHandleEnum = 1
    End If
End Function

Public Function MonitorWidthPx(hMonitor As Long) As Long
    ' If you just have the number, do: MonitorWidthPx(MonitorWidthPx(MonitorNum))
    Dim uMonInfo As MONITORINFO
    uMonInfo.cbSize = LenB(uMonInfo)
    If GetMonitorInfo(hMonitor, uMonInfo) = 0 Then Exit Function
    MonitorWidthPx = uMonInfo.rcMonitor.Right - uMonInfo.rcMonitor.Left
End Function

Public Function MonitorHeightPx(hMonitor As Long) As Long
    ' If you just have the number, do: MonitorHeightPx(MonitorWidthPx(MonitorNum))
    Dim uMonInfo As MONITORINFO
    uMonInfo.cbSize = LenB(uMonInfo)
    If GetMonitorInfo(hMonitor, uMonInfo) = 0 Then Exit Function
    MonitorHeightPx = uMonInfo.rcMonitor.Bottom - uMonInfo.rcMonitor.Top
End Function


All will work fine in the IDE. However, the last form position won't be saved if you use the IDE's stop button. I didn't want to use sub-classing, so I don't have any way to track form movement, other than querying it when the form closes.

Enjoy,
Elroy

EDIT1: Also, it should work just fine for as many forms as you'd like to use it for in a project.

VB6 - Remember App window Position and Size

$
0
0
Attached is a demo of saving and restoring an application position and size. Rather than hijacking Elroy's thread, I decided to create a new one. This code is further simplified from the code that I supplied there, in that it eliminates the need for the SysInfo control and doesn't account for the Taskbar. It also demonstrates how the onboard controls are adjusted when the form size is adjusted. This is a fairly simple demonstration, and more complex forms will take quite a bit more work. The "EXIT" button is there simply to allow the form to be unloaded when the right side is off the screen. The "InitFlg" in the "Resize" event simply prevents the controls from being adjusted on the intial activation.

The InkEdit control used as "Text1" should allow for the use of Unicode characters.

J.A. Coutts
Attached Images
 
Attached Files

[VB6] Neural Network

$
0
0
Since a neural network is missing in the codebank
here is my version:

It's very simple.

It initializes with "CREATE"
Code:

  NN.CREATE Array (2, 2, 1), 0.25, 4
-Where Array indicates the NN topology
Array (N of Inputs, Hidden layer neurons, ..., Hidden layer neurons, N of outputs)
-The second term is the Learning Rate.
-The third is the initial range of connections. (this value, together with the Learning Rate is very important and can drastically change the learning outcomes)

To get the output just call RUN with an array of inputs as arguments,
Return the Outputs Array

For learning (which is supervided) just call TRAIN.
The arguments are an array of Inputs and an array of expected Outputs
The learning process is done by backpropagation, the code is taken (and modified) by an article by Paras Chopra.

Neurons Index "Zero" [0] of each Layer is used for Bias. It is always 1 (The Biases are the weights of connections from 0-indexs neurons to next layer neurons) [Still not sure this way is correct tough]

Inputs and outputs range is from -1 to 1
the Activation function used is TANH.

Probably I'll put it on Github.

Enjoy

And, as always, anyone has ideas to improve it, is welcome
Attached Files

PNG (specifically 32-bit RGBA type PNG) Editing Tool

$
0
0
Hi All,

This was a request and I thought it would be fun. It turned out to be quite the learning experience.

Basically, I've developed a tool for editing the Gamma, Brightness, or Contrast of a 32-bit RGBA type PNG image. Sorry, but it's specifically limited to that type of an image file.

Here's a screen-shot of the main form:
Name:  PngMain.jpg
Views: 19
Size:  22.5 KB

Basically, when you open a PNG file, it loads it (via GDI+), displays it on a form, splits it into four channels (Red, Green, Blue, & Alpha), displays each of these on separate forms, and then displays one last form that shows modifications to the image. Here's a reduced screen-shot of how it looks:

Name:  PngFull.png
Views: 12
Size:  118.9 KB

A couple of caveats: I do use SaveSettings to save a few things to the registry. I know that some people are concerned about this. Therefore, if you're running in the IDE, upon normal exit, I ask if you'd like to delete all of these settings.

Also, to try and keep things speedy, I startup the GDI+ upon opening the app, and don't shut it down until you're exiting. I didn't have any problems with the IDE stop button, but I'm not totally clear on whether or not an IDE stop is totally safe here. I'm hoping that the worst case is a memory leak (that's cleared up when you exit the IDE).

The entire project is in the attachment to this post. A PNG file has also been supplied for you to play with (same one shown).

Now, I'd also like to take this opportunity to outline how I did things. Basically (because I want to handle PNG files with an active Alpha channel), I used the GDI+ to load the image. And then I immediately use the GDI+ to show this original image. Next, I get the image's RgbQuad() data, and then split that into its separate channels, creating separate arrays for Red, Green, Blue, & Alpha. And then I use the regular GDI32's SetDIBits to show these channels on the separate forms. And then, I take the four RgbQuad() channel arrays, re-combine them, and then show them on a Modifications form (using GDI+ and the still open hBitmap to do this).

Just as an FYI, the individual RgbQuad() channel arrays have no Alpha in them (it's always zero). The original image's Alpha channel is copied into the Red, Green, & Blue channels of the Alpha's RgbQuad() array, effectively creating a gray-scale image to show the Alpha channel.

I also "save in memory" all kinds of information (thinking that this would keep things speedy). Therefore, this thing is not memory efficient. Here's a list of what I maintain in memory:

  1. I keep the original file open (hBitmat) with the GDI+.
  2. I keep the original RgbQuad().
  3. I keep each channel's original RgbQuad() (four of them).
  4. I keep each channel's modified RgbQuad() (four of them).
  5. I keep a modified RgbQuad() of the full modified image.


Some of the things I learned during all of this:

  • When leaving a PNG file open (active hBitmap) with GDI+, somehow, GDI+ keeps its hooks into that file until you execute a GdipDisposeImage (or something similar).

  • These PNG files can have a DPI scaling factor embedded in them that makes using GdipDrawImage a bit dubious. If you want to "think" in pixels, this will get fouled up. To "think" in pixels, you must use GdipDrawImageRectI.

  • The GDI+ seems to prefer scanning images from top-down, whereas the GDI32 prefers seeing them as bottom-up. That just caused me to jump through a few hoops to tell the GDI+ that I want them bottom-up so that I'm not constantly flipping them.

  • As I got into it, it dawned on me that the order in which Gamma, Brightness, & Contrast are applied might matter. The approach I took was to always go back to the original image when making changes (and hence saving all those RgbQuad() arrays). Always going back to the original allows me to return to that original while editing, if I so desire. Rather than get overly complicated, I just decided on a Gamma(first), Brightness(second), & Contrast(last) approach to applying things.

  • I also learned that Contrast can be complicated. There are several theories/ideas on how this should be done. I'm not entirely happy with my approach, but it works. I save the mean value (as a Single) of each of the channels upon load. And then, pixels are either stretched away from (or pushed toward) this mean to achieve contrast changes. Other approaches would be to go toward or away from 128 (middle value). Yet another approach would be to calculate the mean each time (thereby accounting for brightness and gamma changes) but this could have speed consequences.

  • I also learned that, with larger images, my approach can bog down. At first, I was showing all changes "in real time" on each click of a control. However, it quickly became apparent that this wasn't going to work. Therefore, I implemented a timer that fires every 200ms. If a bIsModDirty flag is true and if the mouse button isn't down, it calculates and shows the changes. This allows the interface to work much more smoothly, although you don't see changes until you release the mouse button.


And, here's a list of things I may want to consider for the future:

  • Possibly exploring (learning more about) how to use the GDI+ to do my Gamma, Brightness, Contrast changes. I feel certain it's capable of this, and it may make the entire project more memory efficient, and possibly more speedy as well.

  • Possibly learn how to read a TGA (Targa) file as well. This was actually part of the original request, but I had to start somewhere. If I do this, I'd probably want my SaveAs... to be able to convert between the two.

  • Think more about the order in which the effects are applied (especially since I'm always going back to the original). I might let that be user-specified, just to see what difference it makes.

  • Possibly consider additional effects (soften, sharpen, etc.).


I've done my level-headed best to keep this code as organized as possible. However, I do use somewhat deeply nested UDTs to keep track of everything. However, for a somewhat seasoned VB6 programmer, that shouldn't be a huge deal.

If you're interested in studying this code for purposes of how to manipulate images, the place to start is the code in frmMain. And then, you'll want to get into the modPng code, and then the modGdip code. I've tried to make the modGdip code as generic as possible (i.e., not really tied to the specifics of this project). The code in modPng is rather specific to this project. You'll see all the stuff that's maintained in memory in the ThePng UDT variable that's in the modPng file. There's also a touch of GDI32 stuff in the modPng file.

Version 1.03 (original release)

Enjoy,
Elroy

p.s. Please stay focused and please don't be upset if I don't respond to all of these, but critiques and suggestions for improvement are welcomed and encouraged.
Attached Images
  
Attached Files

[vb6] GDI+ Image Attributes Intro & Usage

$
0
0
Thought it would be worthwhile sharing some information regarding GDI+ and its Image Attributes object. Specifically, we are going to discuss the color matrix. This is a 5x5 matrix/grid, variable type: Single.

GDI+ uses this matrix to change image color values, on-the-fly. This prevents you from having to manipulate and change individual color values by hand. Since the matrix is basically a batch, of sorts, of formulas applied to each pixel value, there is little that cannot be done and limited only by imagination or creativity.

The project included below is provided to get your feet wet. There exists on many sites sample matrices you can use to achieve many different color transformations. Wouldn't be a bad idea to start collecting these and storing away for future use. This project, though truly a demo, offers a method to save and load your personal collections of matrices (assuming they were saved while using the demo).

The project is also designed to punch in any matrix values you want and see the results with a click of a button. Like what you see after your changes? Save the matrix or copy the matrix to the clipboard and paste into your project.

I've included a sample PNG in the file, but the project allows you to select images from your computer. I'm sure some of you will ask questions, but let's not discuss modifying the demo project... let's talk about GDI+ image attributes.

This is a good link to read a bit more about GDI+ color matrices. The link starts at page 7 at that site, be sure to browse some of the other pages too.

Here is another site that has sample matrices while also discussing the color matrix. You'll also see where I got the sepia matrix from, hint hint. In the demo project below, I am also defining brightness differently than most. But that shouldn't matter. Use whatever matrix you wish for your particular needs.

Screenshot below is a more complex matrix. Most matrices are just 3-5 non-zero entries.

Name:  Untitled.png
Views: 90
Size:  49.7 KB

Note for non-US locales, use US decimals. The project expects that format in the textboxes.

Until I fix this and repost, in Form_Unload, move the line "GdiplusShutdown m_Token" to just before the "End If" line. Can't shut down GDI+ then attempt to dispose of a GDI+ object, now can we?
Attached Images
 
Attached Files

VB6 - Sort Routine

$
0
0
Shown here is a sort routine that utilizes the built in Command Line sort function. Outside of this routine, a file is loaded into a Textbox and the file name is saved in "m_Filename". The user is first asked where in each line the sort is to start. I use this routine to sort log files, which often begin with a time stamp. The file is appended chronologically, so it is already sorted by time. For example:

00:03:14 Request from 74.125.80.70 for TXT-record for _adsp._domainkey.yellowhead.com.
00:03:15 Sending reply to 74.125.80.70 about TXT-record for _adsp._domainkey.yellowhead.com.:
00:03:16 -> Header: Name does not exist!

I am only interested in the "Request" part of it, so I would start at position 25. I can then easily delete the unwanted portions.

The sorted file is temporarily stored in the users "Temp" directory. You will probably find lots of junk in that directory, as many programs are not very good at cleaning up after themselves. We will attempt not to be one of those, and "Kill" off the file after we are done with it.

The heart of the routine is the "Shell" function. In that I use the seldom used "Environ" function to recover the "COMSPEC" string from the Environment. Environment variables will vary with the individual computer, and can be viewed from the Command Prompt with the "Set" command. To this I add "/c" to concatenate, the "type" command, the file name to sort, the pipe option (|), the "sort" command, and the name of the file to direct the output to. I also add a "vbHide" option, since we are not interested in displaying the results in a Command Prompt window.

We then enter a loop waiting for the directory to be updated. To prevent getting stuck in an endless loop, a counter is implemented. Since file I/O is a buffered operation, an additional 100 ms delay is added to allow for the write operation to complete. The "Loadfile" routine loads the newly sorted file back into the Textbox. We use another 100 ms delay to allow that operation to complete before we delete the temporary file. We then restore the App.Path and the original file name.
Code:

Private Sub mnuSort_Click()
    Dim sTmp As String
    Dim lCntr As Long
    Dim SortStart As Long
    Dim SortCmd As String
    If Len(m_Filename) = 0 Then
        MsgBox "Text must be saved as a file before it can be sorted!", vbExclamation
        Exit Sub
    End If
    SortStart = InputBox("Enter character count to start at - ", "Start", 0)
    If SortStart = 0 Then
        SortCmd = "|sort>tmpsort.txt" 'Default starts at beginning of line
    Else
        SortCmd = "|sort /+" & CStr(SortStart) & ">tmpsort.txt"
    End If
    ChDir TmpPath 'Sorted file is output to temp path
    sTmp = m_Filename 'Save current file location
    Debug.Print Timer
    Call Shell(Environ("COMSPEC") & " /c type " & m_Filename & SortCmd, vbHide)
    m_Filename = "tmpsort.txt" 'Change filename to sorted file
    Do Until Dir(m_Filename) = m_Filename 'Wait for directory to be updated
        DoEvents
        Sleep 10
        lCntr = lCntr + 1
        If lCntr > 100 Then GoTo SortErr
    Loop
    Debug.Print lCntr
    Sleep 100 'Wait an additional 100 ms for file write to complete
    Debug.Print Timer
    LoadFile 'Load sorted file to Textbox
    Sleep 100 'Wait an additional 100 ms for sorted file to load
    Kill m_Filename
    Debug.Print Timer
    m_Filename = sTmp 'Restore original filename
    ChDir App.Path 'Restore Application path
    m_Flg1 = True 'Set change flag
    Exit Sub
SortErr:
    MsgBox "Sort Timed out!"
End Sub

Private Const MAX_PATH = 260
Private Declare Function GetTempPath Lib "kernel32" Alias "GetTempPathA" (ByVal nBufferLength As Long, ByVal lpBuffer As String) As Long
Public Function GetTmpPath() As String
    Dim sFolder As String ' Name of the folder
    Dim lRet As Long ' Return Value
    sFolder = String(MAX_PATH, 0)
    lRet = GetTempPath(MAX_PATH, sFolder)
    If lRet <> 0 Then
        GetTmpPath = Left(sFolder, InStr(sFolder, Chr(0)) - 1)
    Else
        GetTmpPath = vbNullString
    End If
End Function

I have found this routine to be a lot faster than any algorithm I could put together in VB6, especially for large text files. For the most part it is an in-memory sort, but for very large files it will temporarily store the first run to the disk before attempting the second run. An example of how to use this routine will be forthcoming in the near future.

J.A. Coutts

PNG/TGA (specifically 32-bpp type files) Editing Tool

$
0
0
Note, this project uses mscomctl.ocx version 2.2. If you have an older version, the project may not load correctly for you. To fix this problem, you will need to update your mscomctl.ocx. Here's a link to a post by LaVolpe that explains the issue more fully, and provides links for the updates. Also, mscomct2.ocx version 2.0 is used for the status bar. If you have an older version of that, you may need to update it as well (or remove the status bar, which wouldn't be difficult).

Version 1.03 (original release, attached to this OP)
Version 1.04 released in post #16
Version 1.05 released in post #17
Version 1.06 released in post #18

Hi All,

This was a request and I thought it would be fun. It turned out to be quite the learning experience.

Basically, I've developed a tool for editing the Gamma, Brightness, or Contrast of a 32-bit RGBA type PNG or TGA image. Sorry, but it's specifically limited to that type of an image file.

Here's a screen-shot of the main form:
Name:  PngMain.jpg
Views: 223
Size:  22.5 KB

Basically, when you open a PNG file, it loads it (via GDI+), displays it on a form, splits it into four channels (Red, Green, Blue, & Alpha), displays each of these on separate forms, and then displays one last form that shows modifications to the image. Here's a reduced screen-shot of how it looks:

Name:  PngTga.png
Views: 27
Size:  116.2 KB

A couple of caveats: I do use SaveSettings to save a few things to the registry. I know that some people are concerned about this. Therefore, if you're running in the IDE, upon normal exit, I ask if you'd like to delete all of these settings.

Also, to try and keep things speedy, I startup the GDI+ upon opening the app, and don't shut it down until you're exiting. I didn't have any problems with the IDE stop button, but I'm not totally clear on whether or not an IDE stop is totally safe here. I'm hoping that the worst case is a memory leak (that's cleared up when you exit the IDE).

The entire project is in the attachment to this post. A PNG file has also been supplied for you to play with (same one shown).

Now, I'd also like to take this opportunity to outline how I did things. Basically (because I want to handle PNG files with an active Alpha channel), I used the GDI+ to load the image. And then I immediately use the GDI+ to show this original image. Next, I get the image's RgbQuad() data, and then split that into its separate channels, creating separate arrays for Red, Green, Blue, & Alpha. And then I use the regular GDI32's SetDIBits to show these channels on the separate forms. And then, I take the four RgbQuad() channel arrays, re-combine them, and then show them on a Modifications form (using GDI+ and the still open hBitmap to do this).

Just as an FYI, the individual RgbQuad() channel arrays have no Alpha in them (it's always zero). The original image's Alpha channel is copied into the Red, Green, & Blue channels of the Alpha's RgbQuad() array, effectively creating a gray-scale image to show the Alpha channel.

I also "save in memory" all kinds of information (thinking that this would keep things speedy). Therefore, this thing is not memory efficient. Here's a list of what I maintain in memory:

  1. I keep the original file open (hBitmat) with the GDI+.
  2. I keep the original RgbQuad().
  3. I keep each channel's original RgbQuad() (four of them).
  4. I keep each channel's modified RgbQuad() (four of them).
  5. I keep a modified RgbQuad() of the full modified image.


Some of the things I learned during all of this:

  • When leaving a PNG file open (active hBitmap) with GDI+, somehow, GDI+ keeps its hooks into that file until you execute a GdipDisposeImage (or something similar).

  • These PNG files can have a DPI scaling factor embedded in them that makes using GdipDrawImage a bit dubious. If you want to "think" in pixels, this will get fouled up. To "think" in pixels, you must use GdipDrawImageRectI.

  • The GDI+ seems to prefer scanning images from top-down, whereas the GDI32 prefers seeing them as bottom-up. That just caused me to jump through a few hoops to tell the GDI+ that I want them bottom-up so that I'm not constantly flipping them.

  • As I got into it, it dawned on me that the order in which Gamma, Brightness, & Contrast are applied might matter. The approach I took was to always go back to the original image when making changes (and hence saving all those RgbQuad() arrays). Always going back to the original allows me to return to that original while editing, if I so desire. Rather than get overly complicated, I just decided on a Gamma(first), Brightness(second), & Contrast(last) approach to applying things.

  • I also learned that Contrast can be complicated. There are several theories/ideas on how this should be done. I'm not entirely happy with my approach, but it works. I save the mean value (as a Single) of each of the channels upon load. And then, pixels are either stretched away from (or pushed toward) this mean to achieve contrast changes. Other approaches would be to go toward or away from 128 (middle value). Yet another approach would be to calculate the mean each time (thereby accounting for brightness and gamma changes) but this could have speed consequences.

  • I also learned that, with larger images, my approach can bog down. At first, I was showing all changes "in real time" on each click of a control. However, it quickly became apparent that this wasn't going to work. Therefore, I implemented a timer that fires every 200ms. If a bIsModDirty flag is true and if the mouse button isn't down, it calculates and shows the changes. This allows the interface to work much more smoothly, although you don't see changes until you release the mouse button.


And, here's a list of things I may want to consider for the future:

  • Possibly exploring (learning more about) how to use the GDI+ to do my Gamma, Brightness, Contrast changes. I feel certain it's capable of this, and it may make the entire project more memory efficient, and possibly more speedy as well.

  • Possibly learn how to read a TGA (Targa) file as well. This was actually part of the original request, but I had to start somewhere. If I do this, I'd probably want my SaveAs... to be able to convert between the two.

  • Think more about the order in which the effects are applied (especially since I'm always going back to the original). I might let that be user-specified, just to see what difference it makes.

  • Possibly consider additional effects (soften, sharpen, etc.).


I've done my level-headed best to keep this code as organized as possible. However, I do use somewhat deeply nested UDTs to keep track of everything. However, for a somewhat seasoned VB6 programmer, that shouldn't be a huge deal.

If you're interested in studying this code for purposes of how to manipulate images, the place to start is the code in frmMain. And then, you'll want to get into the modPng code, and then the modGdip code. I've tried to make the modGdip code as generic as possible (i.e., not really tied to the specifics of this project). The code in modPng is rather specific to this project. You'll see all the stuff that's maintained in memory in the ThePng UDT variable that's in the modPng file. There's also a touch of GDI32 stuff in the modPng file.

Enjoy,
Elroy

p.s. Please stay focused and please don't be upset if I don't respond to all of these, but critiques and suggestions for improvement are welcomed and encouraged.
Attached Images
  
Attached Files

Standard API Color Picker

$
0
0
It's strange that this doesn't have more of a presence on these forums than it does, but hey ho.

Attached is the my ChooseColorAPI wrapper that I've just polished up. Here are its features:
  • It just always opens allowing you to select custom colors.
  • You can save the user-specified custom colors if you so choose (your application specific).
  • It has the ability of allowing you to specify your own dialog title.
  • You can double-click on the colors and they will auto-select and be returned to you.

Beyond that, it's pretty much the standard ChooseColorAPI function.

More could be done with this thing, but this is precisely what I needed, and I thought I'd share.

Here's code for a standard BAS module (everything needed, just focus on the ShowColorDialog procedure):

Code:


Option Explicit
'
' These are used to get information about how the dialog went.
Public ColorDialogSuccessful As Boolean
Public ColorDialogColor As Long
'
Private Type ChooseColorType
    lStructSize        As Long
    hWndOwner          As Long
    hInstance          As Long
    rgbResult          As Long
    lpCustColors      As Long
    flags              As Long
    lCustData          As Long
    lpfnHook          As Long
    lpTemplateName    As String
End Type
Private Enum ChooseColorFlagsEnum
    CC_RGBINIT = &H1                  ' Make the color specified by rgbResult be the initially selected color.
    CC_FULLOPEN = &H2                ' Automatically display the Define Custom Colors half of the dialog box.
    CC_PREVENTFULLOPEN = &H4          ' Disable the button that displays the Define Custom Colors half of the dialog box.
    CC_SHOWHELP = &H8                ' Display the Help button.
    CC_ENABLEHOOK = &H10              ' Use the hook function specified by lpfnHook to process the Choose Color box's messages.
    CC_ENABLETEMPLATE = &H20          ' Use the dialog box template identified by hInstance and lpTemplateName.
    CC_ENABLETEMPLATEHANDLE = &H40    ' Use the preloaded dialog box template identified by hInstance, ignoring lpTemplateName.
    CC_SOLIDCOLOR = &H80              ' Only allow the user to select solid colors. If the user attempts to select a non-solid color, convert it to the closest solid color.
    CC_ANYCOLOR = &H100              ' Allow the user to select any color.
End Enum
#If False Then ' Intellisense fix.
    Public CC_RGBINIT, CC_FULLOPEN, CC_PREVENTFULLOPEN, CC_SHOWHELP, CC_ENABLEHOOK, CC_ENABLETEMPLATE, CC_ENABLETEMPLATEHANDLE, CC_SOLIDCOLOR, CC_ANYCOLOR
#End If
Private Type KeyboardInput        '
    dwType As Long                ' Set to INPUT_KEYBOARD.
    wVK As Integer                ' shift, ctrl, menukey, or the key itself.
    wScan As Integer              ' Not being used.
    dwFlags As Long              '            HARDWAREINPUT hi;
    dwTime As Long                ' Not being used.
    dwExtraInfo As Long          ' Not being used.
    dwPadding As Currency        ' Not being used.
End Type
Private Type POINTAPI
    X As Long
    Y As Long
End Type
Private Const WM_LBUTTONDBLCLK As Long = 515&
Private Const WM_SHOWWINDOW    As Long = 24&
Private Const WM_SETTEXT      As Long = &HC&
Private Const INPUT_KEYBOARD  As Long = 1&
Private Const KEYEVENTF_KEYUP  As Long = 2&
Private Const KEYEVENTF_KEYDOWN As Long = 0&
'
Private muEvents(1) As KeyboardInput    ' Just used to emulate "Enter" key.
Private pt32 As POINTAPI
Private msColorTitle As String
'
Private Declare Function ChooseColorAPI Lib "comdlg32" Alias "ChooseColorA" (pChoosecolor As ChooseColorType) As Long
Private Declare Function SendInput Lib "user32" (ByVal nInputs As Long, pInputs As Any, ByVal cbSize As Long) As Long
Private Declare Function SetFocusTo Lib "user32" Alias "SetFocus" (Optional ByVal hWnd As Long) As Long
Private Declare Function GetWindowTextLength Lib "user32" Alias "GetWindowTextLengthA" (ByVal hWnd As Long) As Long
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hWnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
Private Declare Function ScreenToClient Lib "user32" (ByVal hWnd As Long, lpPoint As POINTAPI) As Long
Private Declare Function ChildWindowFromPointEx Lib "user32" (ByVal hWnd As Long, ByVal xPoint As Long, ByVal yPoint As Long, ByVal uFlags As Long) As Long
Private Declare Function SendMessageWLong Lib "user32" Alias "SendMessageW" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
'

Public Function ShowColorDialog(hWndOwner As Long, Optional NewColor As Long, Optional Title As String = "Select Color", Optional CustomColorsHex As String) As Boolean
    ' You can optionally use ColorDialogSuccessful & ColorDialogColor or the return of ShowColorDialog and NewColor.  They will be the same.
    '
    ' CustomColorHex is a comma separated hex string of 16 custom colors.  It's best to just let the user specify these, starting out with all black.
    ' If this CustomColorHex string doesn't separate into precisely 16 values, it's ignored, resulting with all black custom colors.
    ' The string is returned, and it's up to you to save it if you wish to save your user-specified custom colors.
    ' These will be specific to this program, because this is your CustomColorsHex string.
    '
    Dim uChooseColor As ChooseColorType
    Dim CustomColors(15) As Long
    Dim sArray() As String
    Dim i As Long
    '
    msColorTitle = Title
    '
    ' Setup custom colors.
    sArray = Split(CustomColorsHex, ",")
    If UBound(sArray) = 15 Then
        For i = 0 To 15
            CustomColors(i) = Val("&h" & sArray(i))
        Next i
    End If
    '
    uChooseColor.hWndOwner = hWndOwner
    uChooseColor.lpCustColors = VarPtr(CustomColors(0))
    uChooseColor.flags = CC_ENABLEHOOK Or CC_FULLOPEN
    uChooseColor.hInstance = App.hInstance
    uChooseColor.lStructSize = LenB(uChooseColor)
    uChooseColor.lpfnHook = ProcedureAddress(AddressOf ColorHookProc)
    '
    ColorDialogSuccessful = False
    If ChooseColorAPI(uChooseColor) = 0 Then
        Exit Function
    End If
    If uChooseColor.rgbResult > &HFFFFFF Then Exit Function
    '
    ColorDialogColor = uChooseColor.rgbResult
    NewColor = uChooseColor.rgbResult
    ColorDialogSuccessful = True
    ShowColorDialog = True
    '
    ' Return custom colors.
    ReDim sArray(15)
    For i = 0 To 15
        sArray(i) = Hex$(CustomColors(i))
    Next i
    CustomColorsHex = Join(sArray, ",")
End Function

Private Function ColorHookProc(ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    If uMsg = WM_SHOWWINDOW Then
        SetWindowText hWnd, msColorTitle
        ColorHookProc = 1&
    End If
    '
    If uMsg = WM_LBUTTONDBLCLK Then
        '
        ' If we're on a hWnd with text, we probably should ignore the double-click.
        GetCursorPos pt32
        ScreenToClient hWnd, pt32
        '
        If WindowText(ChildWindowFromPointEx(hWnd, pt32.X, pt32.Y, 0&)) = vbNullString Then
            ' For some reason, this SetFocus is necessary for the dialog to receive keyboard input under certain circumstances.
            SetFocusTo hWnd
            ' Build EnterKeyDown & EnterKeyDown events.
            muEvents(0).wVK = vbKeyReturn: muEvents(0).dwFlags = KEYEVENTF_KEYDOWN: muEvents(0).dwType = INPUT_KEYBOARD
            muEvents(1).wVK = vbKeyReturn: muEvents(1).dwFlags = KEYEVENTF_KEYUP:  muEvents(1).dwType = INPUT_KEYBOARD
            ' Put it on buffer.
            SendInput 2&, muEvents(0), Len(muEvents(0))
            ColorHookProc = 1&
        End If
    End If
End Function

Private Function ProcedureAddress(AddressOf_TheProc As Long)
    ProcedureAddress = AddressOf_TheProc
End Function

Private Function WindowText(hWnd As Long) As String
    WindowText = Space$(GetWindowTextLength(hWnd) + 1)
    WindowText = Left$(WindowText, GetWindowText(hWnd, WindowText, Len(WindowText)))
End Function

Public Sub SetWindowText(hWnd As Long, sText As String)
    SendMessageWLong hWnd, WM_SETTEXT, 0&, StrPtr(sText)
End Sub


And, if you wish to just test/play, here's a bit of code for a Form1:

Code:


Option Explicit
'
Dim msOurCustomColors As String
'

Private Sub Form_Click()
    ShowColorDialog Me.hWnd, , "Pick a color for background", msOurCustomColors
    If ColorDialogSuccessful Then Me.BackColor = ColorDialogColor
End Sub

Enjoy,
Elroy

[VB6] BatchRtb 2

$
0
0
Since I am almost 100% retired now and doing a lot less VB6 programming I have been looking for things in my toolkit that might be worth sharing with the remaining VB6 community.

I have done a big rewrite of my BatchRtb Class. Here is the main ReadMe:

Code:

========
BatchRtb Version 2.0
========

BatchRtb is a VB6 class for working with RTF data in batch programs.

Instead of a RichTextBox control it creates an invisible RichEdit
control and exposes its Text Object Model (TOM) ITextDocument
interface.  A few additional methods and properties are provided for
opening, saving, and clearing RTF data.

Open and save operations accept:

    o A file name.
    o A Byte array.
    o An IStream object.
    o A ShStream object (another provided class also used internally).
    o An ADODB.Stream object.

These should all contain raw RTF data.


Notes:

    Edanmo's olelib.tlb is required for compiling, but is of course
    not needed at run time and does not need to be deployed.  A recent
    copy has been included.

    If necessary you could even create and compile an ActiveX DLL
    Project exposing the BatchRtb class and perhaps the ShStream class.
    Then this can be used from VBScript in WSH scripts, IIS ASP
    scripts, etc. (anywhere a 32-bit ActiveX DLL can be used).

    Several demo/test Projects using BatchRtb are included.


Some uses:

    o Command line programs.  Local, via PsExec.exe, etc.
    o Batch unattended scheduled tasks.
    o Services.
    o Or anywhere that you don't have a Form or UserControl you can
      site a RichTextBox or InkEdit control on.

This isn't for everyone. Few people are doing Service development, ASP scripting, etc. Most don't even have a clue how to use a CLI (cmd.exe) window, let alone schedule a non-interactive batch task using Task Scheduler any more.

But this code may contain techniques you could employ in your own programs.


BatchRtb 2.0 has been tested on Windows 10 Fall Creator's Update but not on anything else yet. It should work on anything from Windows Vista on up. I'm not sure it could be made to work on Win9x but I think it could be reworked to run on NT 4.0 on up by rewriting the ShStream class - as long as a recent version of ADO (2.5 or later) is installed. The ADO requirement could also be stripped out if necessary.

I haven't done exhaustive testing so bugs may remain in this release. But the attachment contains a number of test case Projects that exercise most of its operations.
Attached Files

VB6 - Multiline Textbox Printer

$
0
0
I had previously used a RichTextBox and the SelPrint routine, but I discovered that routine would not work with an InkEdit Control. With the help of jpbro, we put together a routine for the InkEdit Control (located in the parent forum). But that routine does not work with a Textbox, and I could not find anything online to fit the bill. So I came up with the routine attached.

This routine has experienced very little testing because my development computer does not currently have access to an actual printer. Bug reports would be appreciated.

J.A. Coutts
Attached Files

VB6 - Text Editor

$
0
0
I found a need for addtional functions that NotePad did not provide, so I came up with my own Text Editor. It has most of the functions of NotePad with a couple of extra ones.
Code:

File                Edit                Format                Search
-New                -Undo                -Word Wrap        -Find
-Open                -Cut                -Sort                -Find Next
-Save                -Copy                -Font
-Save as        -Paste
-Print                -Delete
-Exit                -Replace
                -Select All

The noticeable extra is the Sort function, which is covered in a previous post. The other extra is the ability to replace character ranges per line in addition to search and replace specific text. This is accomplished by replacing the double characters CrLf with a single character Cr, using a Split function to separate individual lines into a string array, looping through each line to replace the selected character range, and reassembling the complete string with the Join function. For large text files, search and Replace All by text will be slow, whereas Replace All by character count will be fast by comparison.

The print function has taken some time to put together, as printing from a Text Box is not straight forward, and it has experienced limited testing due to lack of an available printer. It also has been covered in a previous post.

The Line/Col function that comes with Text Editor is not considered an option, as in NotePad. Unlike NotePad, it is available in either Wrap or Unwrap modes, and is only activated by mouse click. If it is important to you, you are welcome to add activation by cursor keys.

Originally I used the API to perform the Edit functions since the VB functions were limited to 64K. But then I discovered that the keyboard functions are not limited to 64K, and perform most of those tasks quite well and with good speed. So it made a lot of sense to use the keyboard functions instead.

Like NotePad, Text Editor provides an adjustable window that remembers it's location and size.

The surprising part of this effort is that with the additional functionality provided, the executable is 1/3 the size of Notepad. I have added functions that meet my current needs, and other users may have specific functions that can be added to meet their needs.

J.A. Coutts
Attached Images
  
Attached Files

[VB6] QuadTree

$
0
0
Hi
this is a Class to implement (points) QuadTree for 2D collision detection.

Suggestions and improvements are welcome (especially regarding speed)


(Used to use it, this demo requires vbRichClient (for Draw). However, you can easily modify a few lines of code to do without it)

Inspired by:
Attached Files

AES Demo

$
0
0
Attached is a demo of AES encryption/decryption using CNG. The default uses a key size of 128, but there is provision for 192 and 256. The HMAC is SHA256, which is what is used in TLS 1.2.

The PreMaster Secret or Key Exchange in this case was randomly generated as were the Server and Client Randoms. The ones currently being used were taken from an actual session shown here:

http://www.yellowhead.com/TLS_Handshake5.htm

The above page shows a packet capture for a TLS session using the mandatory TLS 1.2 cipher suite (002F - TLS_RSA_WITH_AES_128_CBC_SHA). The Pre-Master Secret could also have been the Agreed Secret generated by a Diffie-Hellman Ephemeral process. The Master Keys are generated from all 3 values, and differ depending on whether it is for the Server or the Client. The default is the Client process and produces:
ReadKey:
63 4C 69 C0 A4 1E 24 40 11 F8 CA 37 21 47 9A 92
ReadMAC:
0A 8E 88 F1 1F 51 12 FA 80 05 9A 79 72 A1 32 18
46 7A D4 B5
ReadIV:
DF 9D E1 74 68 60 55 19 26 02 00 00 66 00 28 00
WriteKey:
03 2C 9E EA 56 F4 C9 6F AC 12 01 47 82 BB FE F8
WriteMAC:
63 62 57 B8 EE 53 F9 7F 37 4F 0A 24 B0 5E 86 04
A3 FB A8 FA
WriteIV:
06 68 62 BE 20 46 10 12 AE 3B 36 F7 12 47 DA FD

PRF1_2 is used to create the Master Secret from Pre-Master Secret, Client Random, & Server Random. The Client & Server Randoms are then switched, and PRF1_2 is again used to create the Master Hash from the Master Secret, Server Random, & Client Random. The various keys are then extracted from the Master Hash.

That's the hard part. The easy part is the actual encryption and decryption. If you are wondering what the IV variable is used for, it stands for Initialization Vector, and is necessary for any Block Algorithm. Block Algorithms use a repeating Xor (exclusive or) routine of the Block Length to create the encrypted value, and that repetition makes it vulnerable to being hacked when a known value is being encrypted. The Initialization Vector resolves that issue. As well, that repetition can make the encrypted value longer than the original value, necessitating Block Padding.

This demo uses the full Unicode characters, which for ASCII (English) doubles the length of the encrypted value. You can alternatively use every second byte, or the UTF8 value. The difficulty with UTF8 is that there is no enforced standard for detecting it in an encrypted value.

J.A. Coutts
Attached Images
 
Attached Files

VB6 MultiProcessing (StdExe-IPC via SharedMemory)

$
0
0
This demonstrates, how one can implement robust, asynchronous Workers in VB6 -
by using a (cross-process) SharedMemory-approach (which is one of the common IPC-mechanisms).

For convenient usage, the more complex stuff (the MemoryMapping- as well as the CreateProcess-APIs),
are encapsulated in two generic "Drop-In"-Classes (cIPCMaster and cIPCWorker).

Those Classes can be used either "split-up" (in separate VB6-Projects for Master and Worker) -
but also "all-in-one" (when the same Project - or Process - is used to act as Master and Worker both).

The latter case (using an "all-in-one"-Project), is the most convenient for developing/testing.
Here the Worker-Process is "shelled" against the same ExeName as the Main- (or Master-) Project,
using a simple "forking" in Sub Main() ... (as shown below from the content of Demo1 modMain.bas):
Code:

Option Explicit

Sub Main() 'Process-Startup-Forking
  If Len(Trim$(Command$)) = 0 Then 'no Cmd-Arg was passed (it was started as the Master-Process)
    fMaster.Show '... so we simply startup the Main-Form
   
  Else 'it was started as a WorkerProcess (pass the CommandLine-Arg into the WorkerRoutine)
    EnterWorkerLoop New cIPCWorker, Trim$(Command$)
  End If
End Sub

Above, the blue-colored call represents the "master-fork-path" to your normal "GUI-Project-Code"
(entered when no Commandline-Param was passed to your Executable).

And as the magenta-colored routine-name (in the "worker-fork-path") suggests, the upstarting worker is not fired up
like in an old "classic WebServer-CGI-call" (where the Process exits, after only a single Job was performed).

Instead the current mechanism is implemented in a way, that the WorkerProcess is fired up once -
and then enters an "IDLE-loop" (waiting for Jobs, provided by the Master-Process later).
This way one of the disadvantages of MultiProcessing (the higher Startup-Costs, compared to MultiThreading) is avoided.

The advantages of doing MultiProcessing instead of threading are:
- no typelibs, no extra-Dlls are needed
- in the IDE (after compiling the same Project), the asynchronous workers will behave the same way as in the compiled binary
- a hard terminate of a worker is possible in a stable and "residue-free" manner (though graceful termination-support is of course built-in)
- the communication between Master and Worker(s) happens in an absolute "non-blocking" way

To explain the last point above a bit more... "non-blocking" means, that neither Post- or SendMessage-calls are involved
(as in VB6-OleBased-Communications between "threaded Apartments", where Events, raised from the Workers will block the Main-Thread) -
nor are there other mechanisms in play like Mutexes or CriticalSections, which are normally used in conjunction with shared memory...

Instead the Demo shows, how "state-machine-based" communication (using the shared mem-area) can be implemented.

The approach is extremely robust, completely IDE- and crash-safe, and "cleans up after itself" under any circumstances:
- upstarted Worker-Processes will automatically close, when the Master-Class goes out of scope
- you can even use the IDE-stop-button, whilst asynchronous workers are "deep within a Job" (worker-processes will autoclose nevertheless)

There is also not a single thing, which is "forbidden to use" in the workers (like in many of the threading-approaches for VB6)...

The Zip below comes with 3 Demo-Folders (a simple one to get up to speed - and two "medium-difficult" ones for MandelBrot-rendering).

Ok, here is, what the MandelBrot-Demos will produce (using two Workers, independent from the Main-App):


And here's the Demo-Zip: IPCSharedMem.zip

Have fun...

Olaf
Attached Files

Auto-Complete RichTextBox

$
0
0
Whipped this up this afternoon (bored!) so it may not be perfect. It was mentioned/requested here:

http://www.vbforums.com/showthread.p...the-first-word

It's a little different from the usual auto-complete textboxes in terms of how the user interacts with it and it's possible to auto-complete any part of a string, not just from the start.

It's basically just a small class that is initialised by setting a reference to a RichText Box and an ADO recordset.

Have a play and modify as you see fit. I have no desire to do any more with it as I don't use ADO...
Attached Images
 
Attached Files

[VB6] - Module for working with multithreading.

$
0
0
Hello everyone!

I present the module for working with multithreading in VB6 for Standard EXE projects. This module is based on this solution with some bugfixing and the new functionality is added. The module doesn't require any additional dependencies and type libraries, works as in the IDE (all the functions work in the main thread) as in the compiled form.


To start working with the module, you need to call the Initialize function, which initializes the necessary data (it initializes the critical sections for exclusive access to the heaps of marshalinig and threads, modifies VBHeader (here is description), allocates a TLS slot for passing the parameters to the thread).

The main function of thread creation is vbCreateThread, which is an analog of the CreateThread function.

Code:

' // Create a new thread
Public Function vbCreateThread(ByVal lpThreadAttributes As Long, _
                              ByVal dwStackSize As Long, _
                              ByVal lpStartAddress As Long, _
                              ByVal lpParameter As Long, _
                              ByVal dwCreationFlags As Long, _
                              ByRef lpThreadId As Long, _
                              Optional ByVal bIDEInSameThread As Boolean = True) As Long

The function creates a thread and calls the function passed in the lpStartAddress parameter with the lpParameter parameter.
In the IDE, the call is reduced to a simple call by the pointer implemented through DispCallFunc. In the compiled form, this function works differently. Because a thread requires initialization of project-specific data and initialization of the runtime, the parameters passed to lpStartAddress and lpParameter are temporarily stored into the heap by the PrepareData function, and the thread is created in the ThreadProc function, which immediately deals with the initialization and calling of the user-defined function with the user parameter. This function creates a copy of the VBHeader structure via CreateVBHeaderCopy and changes the public variable placement data in the VbPublicObjectDescriptor.lpPublicBytes, VbPublicObjectDescriptor.lpStaticBytes structures (BTW it wasn't implemented in the previous version) so that global variables are not affected during initialization. Further, VBDllGetClassObject calls the FakeMain function (whose address is written to the modified VBHeader structure). To transfer user parameters, it uses a TLS slot (since Main function doesn't accept parameters, details here). In FakeMain, parameters are directly extracted from TLS and a user procedure is called. The return value of the function is also passed back through TLS. There is one interesting point related to the copy of the header that wasn't included in the previous version. Because the runtime uses the header after the thread ends (with DLL_THREAD_DETACH), we can't release the header in the ThreadProc procedure, therefore there will be a memory leak. To prevent the memory leaks, the heap of fixed size is used, the headers aren't cleared until there is a free memory in this heap. As soon as the memory ends (and it's allocated in the CreateVBHeaderCopy function), resources are cleared. The first DWORD of header actually stores the ID of the thread which it was created in and the FreeUnusedHeaders function checks all the headers in the heap. If a thread is completed, the memory is freed (although the ID can be repeated, but this doesn't play a special role, since in any case there will be a free memory in the heap and if the header isn't freed in one case, it will be released later). Due to the fact that the cleanup process can be run immediately from several threads, access to the cleanup is shared by the critical section tLockHeap.tWinApiSection and if some thread is already cleaning up the memory the function will return True which means that the calling thread should little bit waits and the memory will be available.

The another feature of the module is the ability to initialize the runtime and the project and call the callback function. This can be useful for callback functions that can be called in the context of an arbitrary thread (for example, InternetStatusCallback). To do this, use the InitCurrentThreadAndCallFunction and InitCurrentThreadAndCallFunctionIDEProc functions. The first one is used in the compiled application and takes the address of the callback function that will be called after the runtime initialization, as well as the parameter to be passed to this function. The address of the first parameter is passed to the callback procedure to refer to it in the user procedure:

Code:

' // This function is used in compiled form
Public Function CallbackProc( _
                ByVal lThreadId As Long, _
                ByVal sKey As String, _
                ByVal fTimeFromLastTick As Single) As Long
    ' // Init runtime and call CallBackProc_user with VarPtr(lThreadId) parameter
    InitCurrentThreadAndCallFunction AddressOf CallBackProc_user, VarPtr(lThreadId), CallbackProc
End Function

' // Callback function is called by runtime/window proc (in IDE)
Public Function CallBackProc_user( _
                ByRef tParam As tCallbackParams) As Long

End Function

CallBackProc_user will be called with the initialized runtime.

This function doesn't work in the IDE because in the IDE everything works in the main thread. For debugging in the IDE the function InitCurrentThreadAndCallFunctionIDEProc is used which returns the address of the assembler thunk that translates the call to the main thread and calls the user function in the context of the main thread. This function takes the address of the user's callback function and the size of the parameters in bytes. It always passes the address of the first parameter as a parameter of a user-defined function. I'll tell you a little more about the work of this approach in the IDE. To translate a call from the calling thread to the main thread it uses a message-only window. This window is created by calling the InitializeMessageWindow function. The first call creates a WindowProc procedure with the following code:

Code:

    CMP DWORD [ESP+8], WM_ONCALLBACK
    JE SHORT L
    JMP DefWindowProcW
L:  PUSH DWORD PTR SS:[ESP+10]
    CALL DWORD PTR SS:[ESP+10]
    RETN 10

As you can see from the code, this procedure "listens" to the WM_ONCALLBACK message which contains the parameter wParam - the function address, and in the lParam parameters. Upon receiving this message it calls this procedure with this parameter, the remaining messages are ignored. This message is sent just by the assembler thunk from the caller thread. Futher, a window is created and the handle of this window and the code heap are stored into the data of the window class. This is used to avoid a memory leak in the IDE because if the window class is registered once, then these parameters can be obtained in any debugging session. The callback function is generated in InitCurrentThreadAndCallFunctionIDEProc, but first it's checked whether the same callback procedure has already been created (in order to don't create the same thunk). The thunk has the following code:

Code:

LEA EAX, [ESP+4]
PUSH EAX
PUSH pfnCallback
PUSH WM_ONCALLBACK
PUSH hMsgWindow
Call SendMessageW
RETN lParametersSize

As you can see from the code, during calling a callback function, the call is transmitted via SendMessage to the main thread. The lParametersSize parameter is used to correctly restore the stack.

The next feature of the module is the creation of objects in a separate thread, and you can create them as private objects (the method is based on the code of the NameBasedObjectFactory by firehacker module) as public ones. To create the project classes use the CreatePrivateObjectByNameInNewThread function and for ActiveX-public classes CreateActiveXObjectInNewThread and CreateActiveXObjectInNewThread2 ones. Before creating instances of the project classes you must first enable marshaling of these objects by calling the EnablePrivateMarshaling function. These functions accept the class identifier (ProgID / CLSID for ActiveX and the name for the project classes) and the interface identifier (IDispatch / Object is used by default). If the function is successfully called a marshaled object and an asynchronous call ID are returned. For the compiled version this is the ID of thread for IDE it's a pointer to the object. Objects are created and "live" in the ActiveXThreadProc function. The life of objects is controlled through the reference count (when it is equal to 1 it means only ActiveXThreadProc refers to the object and you can delete it and terminate the thread).
You can call the methods either synchronously - just call the method as usual or asynchronously - using the AsynchDispMethodCall procedure. This procedure takes an asynchronous call ID, a method name, a call type, an object that receives the call notification, a notification method name and the list of parameters. The procedure copies the parameters to the temporary memory, marshals the notification object, and sends the data to the object's thread via WM_ASYNCH_CALL. It should be noted that marshaling of parameters isn't supported right now therefore it's necessary to transfer links to objects with care. If you want to marshal an object reference you should use a synchronous method to marshal the objects and then call the asynchronous method. The procedure is returned immediately. In the ActiveXThreadProc thread the data is retrieved and a synchronous call is made via MakeAsynchCall. Everything is simple, CallByName is called for the thread object and CallByName for notification. The notification method has the following prototype:

Code:

Public Sub CallBack (ByVal vRet As Variant)
, where vRet accepts the return value of the method.

The following functions are intended for marshaling: Marshal, Marshal2, UnMarshal, FreeMarshalData. The first one creates information about the marshaling (Proxy) of the interface and puts it into the stream (IStream) that is returned. It accepts the interface identifier in the pInterface parameter (IDispatch / Object by default). The UnMarshal function, on the contrary, receives a stream and creates a Proxy object based on the information in the stream. Optionally, you can release the thread object. Marshal2 does the same thing as Marshal except that it allows you to create a Proxy object many times in different threads. FreeMarshalData releases the data and the stream accordingly.
If, for example, you want to transfer a reference to an object between two threads, it is enough to call the Marshal / UnMarshal pair in the thread which created the object and in the thread that receives the link respectively. In another case, if for example there is the one global object and you need to pass a reference to it to the multiple threads (for example, the logging object), then Marshal2 is called in the object thread, and UnMarshal with the bReleaseStream parameter is set to False is called in client threads. When the data is no longer needed, FreeMarshalData is called.

The WaitForObjectThreadCompletion function is designed to wait for the completion of the object thread and receives the ID of the asynchronous call. It is desirable to call this function always at the end of the main process because an object thread can somehow interact with the main thread and its objects (for example, if the object thread has a marshal link to the interface of the main thread).

The SuspendResume function is designed to suspend/resume the object's thread; bSuspend determines whether to sleep or resume the thread.

In addition, there are also several examples in the attacment of working with module:
  1. Callback - the project demonstrates the work with the callback-function periodically called in the different threads. Also, there is an additional project of native dll (on VB6) which calls the function periodically in the different threads;
  2. JuliaSet - the Julia fractal generation in the several threads (user-defined);
  3. CopyProgress - Copy the folder in a separate thread with the progress of the copy;
  4. PublicMarshaling - Creating public objects (Dictionary) in the different threads and calling their methods (synchronously / asynchronously);
  5. PrivateMarshaling - Creating private objects in different threads and calling their methods (synchronously / asynchronously);
  6. MarshalUserInterface - Creating private objects in different threads and calling their methods (synchronously / asynchronously) based on user interfaces (contains tlb and Reg-Free manifest).


The module is poorly tested so bugs are possible. I would be very glad to any bug-reports, wherever possible I will correct them.
Thank you all for attention!

Best Regards,
The trick.
Attached Files

Viewing Token Privileges

$
0
0
Privileges can be required to access system resources, and it can be a nuisance when an API call fails because a privilege is not available. This application displays the privileges available to the process token for the current logged on User.
If run as administrator, it will show the elevated privileges. In general, if a privilege is required for an API function, the application should be running with elevated credentials as a standard user has very few privileges. The application may also need to enable the privilege, before the API function is called.

For example there are a number of API functions to create a process, and only some of these require privileges:

  • CreateProcessWithTokenW
    must have the SE_IMPERSONATE_NAME privilege.
  • CreateProcessAsUser
    must have the SE_INCREASE_QUOTA_NAME privilege and may require the SE_ASSIGNPRIMARYTOKEN_NAME privilege if the token is not assignable
  • CreateProcessWithLogonW
    requires no special privileges as the new process runs in the security context of the Logon User
  • CreateProcess
    requires no special privileges as the new process runs in the security context of the calling process

The following screen image illustrates the privileges available for an elevated user.
Name:  Token Privileges.png
Views: 105
Size:  115.5 KB

From this example, the elevated user can call the CreateProcessWithTokenW, but before calling the CreateProcessAsUser, the application must first enable the SeIncreaseQuotaPrivilege. But this API would still return unsuccessful if the token is not assignable, because this elevated user does not have the SeAssignedPrimaryTokenPrivilege.

This application also has code to enable and disable a privilege.

The attached project also includes more detailed information on this application.
TokenPrivilege.zip
Attached Images
 
Attached Files

Encrypting passwords with CryptProtectMemory

$
0
0
Protecting passwords in memory
In this age of security awareness, it is important to protect any passwords or other sensitive data that may be used by applications and written to the computer memory. The protection is twofold, firstly by encrypting the sensitive data, and secondly by erasing any memory that might have contained unprotected sensitive data, before the variable goes out of scope.

The Windows API includes the CryptProtectMemory function to encrypt data in memory. For example, one might request user credentials using the API CredUIPromptForWindowsCredentials, and then use these credentials to launch an application using the API CreateProcessWithLogonW function. Between these two functions, the password would be held in a variable and hence the password is somewhere in the computer memory. The password should be protected by encrypting the password as soon as it is returned from the API, then erasing the variable that held the password before it goes out of scope. Just before the CreateProcessWithLogonW function is called the password can be decrypted into a variable, the variable passed to the api and then erase the memory used by this variable.

Sample Application
The attached application demonstrates the usage of the CryptProtectMemory function to encrypt and decrypt data. This application does not involve any passwords, but demonstrates the process of encrypting a text string, and decrypting the text, and a simple method to erase the memory used by a string variable. Erasing a string could be tricky as in VB normal string manipulation assigns a string to a new memory, leaving the original string as free memory. One simply solution to erase the actual data in memory is to use the mid$ statement:
Mid$(sData, 1, Len(sData)) = String$(Len(sData), vbNullChar)
This writes zeroes to the string without changing its location in memory.

The application consists of a form to enter the text, a button to encrypt the text and show the result as hex bytes, and then to decrypt the encrypted text to recover the original text.

Name:  CryptProtectMemory.png
Views: 82
Size:  9.4 KB
In this application the encrypted data is converted into a hex string, which makes it easy to inspect the result and compare the different encryptions. In normal usage the encrypted data should not be exposed in this way.

The CryptProtectMemory has three different flags for setting different types of encryption and this defines the scope for which the encrypted data can be shared.

Comparing the different encryption settings

The Windows API CryptProtectMemory has 3 flag settings for the type of encryption.
· CRYPTPROTECTMEMORY_SAME_PROCESS
· CRYPTPROTECTMEMORY_SAME_LOGON
· CRYPTPROTECTMEMORY_CROSS_PROCESS

This application provides radio buttons to select the type of encryption, and the text alongside the Decrypt button will show the scope of the selected option.

Explore the implications of these different settings by running multiple instances of this application. Use the run as administrator to create an instance with a different logon session.

Additional documentation is included in the attached project files
CryptProtectMemory.zip
Attached Images
 
Attached Files

Scintilla Source Code editor OCX for VB

$
0
0
I noticed the board didn't have much on the Scintilla source code editor so wanted to make sure a copy of this got saved.

Scintilla is a source code editor component that includes source code highlighting, code folding, line numbering, bookmarks, built in intellisense etc. It is a great control if you want to create a source code editor or debugger UI.

Name:  screenshot.jpg
Views: 137
Size:  14.5 KB

Its a free component written in C and builds as SciLexer.dll. You can download the source files here:

https://www.scintilla.org/

The source attached here, scivb2.ocx, is a vb6 control that makes using it quite easy. This is an update to Stewarts great scivb.ocx control that is part of his cEditXP souce code editor.

http://www.planet-source-code.com/vb...66207&lngWId=1

I spent some time inside of it and adapted it for what I needed so I could use it as a debugger UI You can see an example of it in action here:

https://www.youtube.com/watch?v=nSr1-OugQ1M

I have attached a copy of the ocx source. I have been using this for several years now and has proven stable. Any updates will be in the git repo below.

https://github.com/dzzie/scivb2

public methods:
Code:

'Events
Event NewLine()
Event MouseDwellEnd(lline As Long, Position As Long)
Event MouseDwellStart(lline As Long, Position As Long)
Event MarginClick(lline As Long, Position As Long, margin As Long, modifiers As Long)
Event AutoCSelection(Text As String)                        'Auto Completed selected
Event CallTipClick(Position As Long)                        'Clicked a calltip
Event UserListSelection(listType As Long, Text As String)  'Selected AutoComplete
Event LineChanged(Position As Long)
Event OnModified(Position As Long, modificationType As Long)
Event DoubleClick()
Event MouseUp(Button As Integer, Shift As Integer, x As Long, y As Long)
Event MouseDown(Button As Integer, Shift As Integer, x As Long, y As Long)
Event key(ch As Long, modifiers As Long)
Event KeyUp(KeyCode As Long, Shift As Long)
Event KeyDown(KeyCode As Long, Shift As Long)
Event DebugMsg(Msg As String)
Event KeyPress(Char As Long)
Event AutoCompleteEvent(className As String)

'Properties
Property FoldComment() As Boolean
Property FoldAtElse() As Boolean
Property FoldMarker() As FoldingStyle
Property Folding() As Boolean    'If true folding will be automatically handled.
Property DisplayCallTips() As Boolean  'If this is set to true then calltips will be displayed.  To use this you must also use <B>LoadAPIFile</b> to load an external API file which contains simple instructions to the editor on what calltips to display.
Property SelFore() As OLE_COLOR  'The allows you to control the fore color of the selected color.
Property SelBack() As OLE_COLOR  'This allow's you to set the backcolor for selected text.
Property WordWrap() As Boolean 'If set to true the document will wrap lines which are longer than itself.  If false then it will dsiplay normally.
Property ShowFlags() As Boolean  'If this is true the second gutter will be displayed and Flags/Bookmarks will be displayed.
Property isDirty() As Boolean  'This is a read only property.  It allows you to get the modified status of the Scintilla window.
Property ReadOnly() As Boolean  'This property allows you to set the readonly status of Scintilla.  When in readonly you can scroll the document, but no editing can be done.
Property LineNumbers() As Boolean    'If this is set to true then the first gutter will be visible and display line numbers.  If this is false then the first gutter will remain hidden.
Property ContextMenu() As Boolean    'If set to true then the default Scintilla context menu will be displayed when a user right clicks on the window.  If this is set to false then no context menu will be displayed.  If you are utilizing a customer context menu then this should be set to false.
Property AutoCompleteString() As String  'This store's the list which autocomplete will use.  Each word needs to be seperated by a space.
Property IndentWidth() As Long  'This controls the number of spaces Tab will indent.  IndentWidth only applies if <B>TabIndents</b> is set to false.
Property BackSpaceUnIndents() As Boolean 'If tabindents is set to false, and BackSpaceUnIndents is set to true then the backspaceunindents will remove the same number of spaces as tab inserts.  If it's set to false then it will work normally.
Property UseTabIndents() As Boolean 'If this is true tab inserts indent characters.  If it is set to false tab will insert spaces.
Property useTabs() As Boolean
Property ShowIndentationGuide() As Boolean  'If true indention guide's will be displayed.
Property MaintainIndentation() As Boolean 'If this is set to true the editor will automatically keep the previous line's indentation.
Property HighLightActiveLine() As Boolean    'When set to true the active line will be highlighted using the color selected from LineBackColor.
Property ActiveLineBackColor() As OLE_COLOR    'Allows you to control the backcolor of the active line.
Property SelText() As String 'Allows you to get and set the seltext of the scintilla window.
Property Text() As String    'Allows you to get and set the text of the scintilla window.
Property SelLength() As Long
Property SelEnd() As Long
Property SelStart() As Long
Property codePage() As SC_CODETYPE
Property TotalLines() As Long
Property VisibleLines() As Long
Property FirstVisibleLine() As Long
Property AutoCloseQuotes() As Boolean    'When set to true quotes will automatically be closed.
Property AutoCloseBraces() As Boolean    'When this is set to true braces <B>{, [, (</b> will be closed automatically.
Property Version() As String
Property currentHighlighter() As String
Property sciHWND() As Long
Friend Property Let ReplaceFormActive(x As Boolean)

'Methods
Function isMouseOverCallTip() As Boolean
Sub LockEditor(Optional locked As Boolean = True)
Function WordUnderMouse(pos As Long, Optional ignoreWhiteSpace As Boolean = False) As String
Sub ShowGoto()
Sub ShowAbout()
Function ShowFindReplace() As Object
Function FindNext(Optional wrap As Boolean = False) As Long
Function Find(sSearch As String, _
Function FindAll(sSearch As String, _
Function ReplaceAll(strSearchFor As String, _
Function ReplaceText(strSearchFor As String, _
Sub MarkAll(strFind As String)
Sub SetMarker(iLine As Long, Optional iMarkerNum As Long = 2)
Sub DeleteAllMarkers(Optional marknum As Long = 2)
Sub PrevMarker(lline As Long, Optional marknum As Long = 2)
Sub NextMarker(lline As Long, Optional marknum As Long = 2)
Sub DeleteMarker(iLine As Long, Optional marknum As Long = 2)
Sub ToggleMarker(Optional line As Long = -1)
Sub FoldAll()
Sub ShowCallTip(strVal As String)
Sub StopCallTip()
Function AddCallTip(functionPrototype As String)
Function LoadCallTips(strFile As String) As Long
Function LoadFile(strFile As String) As Boolean
Function SaveFile(strFile As String) As Boolean
Function PreviousWord() As String
Function CurrentWord() As String
Sub ShowAutoComplete(strVal As String)
Function GetCaretInLine() As Long
Function CurrentLine() As Long
Sub SetCurrentPosition(lval As Long)
Function PositionFromLine(lline As Long) As Long
Sub ClearUndoBuffer()
Function SelectLine() As Long
Function SelectAll() As Long
Function Paste() As Long
Function Copy() As Long
Function Cut() As Long
Function Undo() As Long
Function Redo() As Long
Function SetFocus() As Long
Function GotoCol(Column As Long) As Long
Sub GotoLineColumn(iLine As Long, iCol As Long)
Function GotoLine(line As Long) As Long
Function GetLineText(ByVal lline As Long) As String
Function FileExists(strFile As String) As Boolean
Function FolderExists(path) As Boolean
Sub GotoLineCentered(ByVal line As Long, Optional selected As Boolean = True)
Function hilightWord(sSearch As String, Optional color As Long = 0, Optional compare As VbCompareMethod = vbTextCompare) As Long
Sub hilightClear()
Sub UncommentBlock()
Sub CommentBlock()
Function ExportToHTML(filePath As String) As Boolean
Function LoadHighlightersDir(dirPath As String) As Long
Function HighlighterForExtension(fPath As String) As String
Function LoadHighlighter(filePath As String, Optional andSetActive As Boolean = True) As Boolean
Function SetHighlighter(langName As String) As Boolean

Attached Images
 
Attached Files
Viewing all 1476 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>