This WORKS as expected on two Windows 10 systems (on a VM, the other a live PC). But on a third system (customer's, unfortunately) the form minimizes rather than being topmost.
SetwindowPos (TargetForm.hwnd, HWND_TOP,0,0,0,0, SWP_NOMOVE Or SWP_NOSIZE)
the Form (window) minimizes.
Any idea what would cause that?
This is a VB6 program (don't laugh!, I make a living on this program :)
UPDATE:
More details on code:
Set FormActive = frmToShow
frmToShow.Show
FormZorderSet frmToShow, Z_top
If Not frmPrevious Is Nothing Then
frmPrevious.Hide
End If
Public Function FormZorderSet(frmTarget As Form, Zorder As FormZorderType) As Long
FLAGS = SWP_NOMOVE Or SWP_NOSIZE
FormZorderSet = SetWindowPos(frmTarget.hwnd, Zorder, 0, 0, 0, 0, FLAGS)
Global declares
Public Declare Function SetWindowPos Lib "User32" (ByVal hwnd As Long, ByVal hWndInsertAfter As Long, ByVal X As Long, ByVal Y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
Const SWP_NOSIZE = &H1
Const SWP_NOMOVE = &H2
Const HWND_TOPMOST = -1
Const HWND_TOP = 0
Try using this ontop function
'moudle code
Option Explicit
Public Const SWP_NOMOVE = 2
Public Const SWP_NOSIZE = 1
Public Const FLAGS = SWP_NOMOVE Or SWP_NOSIZE
Public Const HWND_TOPMOST = -1
Public Const HWND_NOTOPMOST = -2
Declare Function SetWindowPos Lib "user32" _
(ByVal hwnd As Long, _
ByVal hWndInsertAfter As Long, _
ByVal x As Long, _
ByVal y As Long, _
ByVal cx As Long, _
ByVal cy As Long, _
ByVal wFlags As Long) As Long
Public Function SetTopMostWindow(hwnd As Long, Topmost As Boolean) _
As Long
If Topmost = True Then 'Make the window topmost
SetTopMostWindow = SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, _
0, FLAGS)
Else
SetTopMostWindow = SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, _
0, 0, FLAGS)
SetTopMostWindow = False
End If
End Function
Then for the use
'use
Dim lR As Long
Private Sub Form_Load()
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'set form to allways on top
lR = SetTopMostWindow(Me.hwnd, True)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
End Sub
This has worked for me in windows 10 without it minimizing my program.
Related
I want to remove and insert spaces after every byte in a hex string.
E.g.: if the hex string is
str = "0F0D3E"
then I want to insert spaces after every byte to obtain
str = "0F 0D 3E"
and also the reverse (remove spaces from the string so the string becomes "0F0D3E" again).
A quick and naïve approach would be:
Option Explicit
Private Sub Form_Load()
Dim sSrc As String
Dim sTgt As String
sSrc = "0F0D3E"
sTgt = SpaceIt(sSrc)
Debug.Print sTgt
sSrc = UnspaceIt(sTgt)
Debug.Print sSrc
End Sub
Private Function SpaceIt(sSrc As String) As String
Dim i As Long
Dim asSrc() As String
ReDim asSrc(0 To Len(sSrc) \ 2 - 1) As String
For i = 0 To Len(sSrc) - 1 Step 2
asSrc(i \ 2) = Mid$(sSrc, i + 1, 2)
Next i
SpaceIt = Join(asSrc, " ")
End Function
Private Function UnspaceIt(sSrc As String) As String
UnspaceIt = Replace(sSrc, " ", "")
End Function
You can harness the power of the Mid$ statement and the Mid$ function and a little arithmetic to write a function to do this pretty flexibly and efficiently:
Private Function Spacify( _
ByVal Text As String, _
ByVal StrideIn As Long, _
ByVal StrideOut As Long, _
Optional ByVal RTrim As Boolean) As String
Dim OutLen As Long
Dim CopyLen As Long
Dim OutPos As Long
Dim InPos As Long
If StrideIn <= StrideOut Then
OutLen = (Len(Text) \ StrideIn) * StrideOut
If RTrim Then OutLen = OutLen - (StrideOut - StrideIn)
CopyLen = StrideIn
Else
OutLen = ((Len(Text) + (StrideIn - StrideOut)) \ StrideIn) * StrideOut
CopyLen = StrideOut
End If
Spacify = Space$(OutLen)
OutPos = 1
For InPos = 1 To Len(Text) Step StrideIn
Mid$(Spacify, OutPos) = Mid$(Text, InPos, CopyLen)
OutPos = OutPos + StrideOut
Next
End Function
Example:
Private Sub Main()
Dim S As String
S = "0f030d"
Debug.Print """"; S; """"
S = Spacify(S, 2, 3)
Debug.Print """"; S; """"
S = Spacify(S, 3, 2)
Debug.Print """"; S; """"
S = Spacify(S, 2, 3, True)
Debug.Print """"; S; """"; " trimmed"
S = Spacify(S, 3, 2)
Debug.Print """"; S; """"
Debug.Print
S = "abc"
Debug.Print """"; S; """"
S = Spacify(S, 1, 2)
Debug.Print """"; S; """"
S = Spacify(S, 2, 1)
Debug.Print """"; S; """"
S = Spacify(S, 1, 2, True)
Debug.Print """"; S; """"; " trimmed"
S = Spacify(S, 2, 1)
Debug.Print """"; S; """"
Stop
End Sub
Result:
"0f030d"
"0f 03 0d "
"0f030d"
"0f 03 0d" trimmed
"0f030d"
"abc"
"a b c "
"abc"
"a b c" trimmed
"abc"
Try this:
Private Sub Form_Load()
Dim str As String
Dim newstr As String
str = "0F0D3E"
newstr = AddSpaces(str)
str = Replace(newstr, " ", "")
End Sub
Private Function AddSpaces(s As String) As String
Dim i As Integer
For i = 1 To Len(s) Step 2
AddSpaces = AddSpaces & Mid$(s, i, 2) & " "
Next
AddSpaces = Trim(AddSpaces)
End Function
Are there any ways so I can generate random numbers from 0 to &HFFFFFFFF in Visual Basic 6.0?
I am using the following function
Function RandomNumberLong(Lowerbound As Long, Upperbound As Long) As Long
RandomNumberLong = Clng((Upperbound - Lowerbound + 1) * Rnd + Lowerbound)
End Function
If I use
x = RandomNumberLong(0,&HFFFFFFFF)
It always returns 0
The problem here is the max value of long can hold is 7FFFFFFF or 2147483647 in decimal
So how I am supposed to fix this? Even if I use a single data type it always return negative without unsigned numbers.
According to MSDN Long type
Long (long integer) variables are stored as signed 32-bit (4-byte)
numbers ranging in value from -2,147,483,648 to 2,147,483,647.
Thetype-declaration character for Long is the ampersand (&).
But the value of FFFFFFFF is equal to -1 or 4294967294 which overflow.
I think I am confused on this.
Edited:
Since this seems to be a little bit complicated, i have coded a small Shell code to use the RDTSC instruction instead to generate a random long number including singed and unsigned.
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
(Destination As Any, Source As Any, ByVal Length As Long)
Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" _
(ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, _
ByVal wParam As Long, ByVal lParam As Long) As Long
Option Explicit
Private Sub Form_Load()
Dim x(1 To 10) As Byte, VAL As Long
CopyMemory x(1), &H60, 1 'PUSHAD
CopyMemory x(2), &H310F, 2 'RDTSC EAX holds a random value
CopyMemory x(4), &HA3, 1 'MOV EAX
CopyMemory x(5), VarPtr(VAL), 4 'Pointer of variable // MOV DWORD [VAL],EAX
CopyMemory x(9), &H61, 1 'POPAD
CopyMemory x(10), &HC3, 1 'RET
CallWindowProc VarPtr(x(1)), 0, 0, 0, 0 'Call the shellcode
MsgBox VAL
End Sub
&HFFFFFFFF - represents a 32-bit signed integer, and the value of &HFFFFFFFF overflows the integer and becomes -1
Hence, when you call RandomNumberLong function, you are passing 0 to Lowerbound and -1 to Upperbound
In order to fix this in Vb.NET, use &HFFFFFFFFL or &HFFFFFFFF& to indicate Long type literal. I am not sure how to fix this as quickly in VB6 as in VB.NET from the example above. I guess you will need to write your own function to convert large HEX numbers to double and pass the number instead of the HEX.
EDIT:
I don't think VB6 allows you to convert &HFFFFFFFF to anything but base 16, which overflows and results in -1:
EDIT 2:
You can convert some Hex numbers into other datatype by adding & to the end:
&HFFFF = -1
&HFFFF& = 65535
Still, there seems to be a limit to the Hex number in VB6 (base 16 only?) because:
VB.NET:
&HFFFFFFFF&=4294967295
VB6:
&HFFFFFFFF&=-1
MSDN: Type Characters (Visual Basic)
The compiler normally construes an integer literal to be in the decimal (base 10) number system. You can force an integer literal to be hexadecimal (base 16) with the &H prefix, and you can force it to be octal (base 8) with the &O prefix. The digits that follow the prefix must be appropriate for the number system.
Truth is that VB6 Long is 32-bit signed integer data type. As such it simply cannot store &HFFFFFFFF (MSDN). But (1) you seem to be OK with using Long anyway, and (2) you do not explain what is your use case, and if it is really that crucial to work in a positive range only.
One can use the following function to generate random Long values from the whole range of Long data type (i.e. from -&H80000000 to &H7FFFFFFF):
Function RandomNumberLong() As Long
RandomNumberLong = &H7FFFFFFF * Rnd() + (-1 - &H7FFFFFFF) * Rnd()
End Function
The problem is that VB6 converts any hex number which exits out of only "F" to -1
This will make your function to use -1 as its upperbound, and causes it to return 0
By separating the 8 digits into 2 variables with 4 digits, you still have the same problem as VB6 will still convert &HFFFF to -1 which will make your function to return 0 again.
A solution is to add &H10000 to the 4 digit variables before converting, and substracting Val("&H10000") after the conversion has been done.
After that you can use these 2 values to obtain 2 random numbers, and combine them into 1 random 8 digit hex number.
Below is a test project which shows what i mean:
'1 form with:
' 1 command button: name=Command1
Option Explicit
Private Sub Command1_Click()
Dim strX As String
Dim lngX As Long
strX = RndHex("FFFFFFFF")
lngX = Val("&H" & strX)
Caption = strX & " = " & CStr(Hex$(lngX)) & " = " & CStr(lngX)
End Sub
Function RndHex(strMax As String) As String
Dim strMax1 As String, strMax2 As String
Dim lngMax1 As Long, lngMax2 As Long
Dim lngVal1 As Long, lngVal2 As Long
Dim strVal1 As String, strVal2 As String
'make sure max is 8 digits
strMax1 = Right$("00000000" & strMax, 8)
'split max in 2 parts
strMax2 = Right$(strMax1, 4)
strMax1 = Left$(strMax1, 4)
'convert max values from string to values
lngMax1 = Val("&H1" & strMax1) - Val("&H10000")
lngMax2 = Val("&H1" & strMax2) - Val("&H10000")
'calculate separate random values
lngVal1 = CLng(lngMax1 + 1) * Rnd
lngVal2 = CLng(lngMax2 + 1) * Rnd
'convert values to 4 digit hex strings
strVal1 = Right$("0000" & Hex$(lngVal1), 4)
strVal2 = Right$("0000" & Hex$(lngVal2), 4)
'combine 2 random values and return the result as an 8 digit hex string
RndHex = strVal1 & strVal2
End Function
Private Sub Form_Load()
'seed random generator with system timer
Randomize
End Sub
Run the project above and click the command button and view the values in the caption of the form.
Rnd will only give you 24 bits of randomness since it returns a Single.
RandomNumberLong = Clng(&HFFFF * Rnd()) + (Clng(&HFFFF * Rnd()) * &H10000)
will construct a 32-bit value from two 16-bit random integers.
UPDATE - well, it won't, because as Hrqls points out, &HFFFF is -1 in VB. Instead:
RandomNumberLong = Clng(65535 * Rnd()) + (Clng(65535 * Rnd()) * 65536)
I have an application in which i'm drawing a line/square on a picturebox. I also need the user to click on a particular point on the picturebox(after drawing the square/line) so as to get the location of the second point. But the mouse down event does not work for the second click. My code is as shown:
Dim m_Drawing As Boolean
'm_Drawing = False
Dim m_Startx As Single
Dim m_Starty As Single
Dim m_endx As Single
Dim m_endy As Single
Dim square_click As Boolean
'square_click = False
Dim line_click As Boolean
'line_click = False
Dim bclick As Boolean
'blick = True
Dim startx As Single
Dim starty As Single
Dim endx As Single
Dim endy As Single
Dim laserx_mm As Single
Dim lasery_mm As Single
Dim rectx_mm As Single
Dim recty_mm As Single
Dim xpos As Single
Dim ypos As Single
Dim uxpos As Single
Dim uypos As Single
Dim dist As Single
Dim dist1 As Single
Private Sub Command1_Click()
square_click = True
End Sub
Private Sub Command2_Click()
line_click = True
End Sub
Private Sub Picture1_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
Dim diffx As Single
Dim diffy As Single
Picture1.Cls
If m_Startx = 0 And m_Starty = 0 Then
m_Startx = X
m_Starty = Y
'End If
startx = X
starty = Y
rectx_mm = X
recty_mm = Y
'move to start position
ElseIf m_Startx <> 0 And m_Starty <> 0 Then
laserx_mm = X
lasery_mm = Y
diffx = rectx_mm - laserx_mm
diffy = recty_mm - lasery_mm
dist = xpos + (diffx / 4.74 / 1000)
dist1 = ypos - (diffy / 4.68 / 1000)
End If
End Sub
Private Sub Picture1_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
endx = X
endy = Y
m_endx = X
m_endy = Y
If square_click = True Then
Picture1.Line (m_Startx, m_Starty)-(endx, endy), vbWhite, B
ElseIf line_click = True Then
Picture1.Line (m_Startx, m_Starty)-(endx, endy), vbWhite
End If
End Sub
The Code: ElseIf m_Startx <> 0 And m_Starty <> 0
does not get executed unless and until i put a breakpoint there. I'm not sure why this is happening. Please help me out! Hope i was clear enough! Thanks.
I threw a Debug.Print "Here I am" call inside your ElseIf m_Startx <> 0 And m_Starty <> 0...Works like a charm on the 2nd click. Perhaps you may want to go with a darker color or a thicker line? The white line is fairly hard to see.
Can anyone tell me if it's possible to fill a polygon with a gradient in VB6?
The code below will draw a gradient filled rectangle. I modified it slightly from this thread from vbcity.com.
Drop this into a Module:
Public Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private Declare Function CreateSolidBrush Lib "gdi32" (ByVal crColor As Long) As Long
Private Declare Function FillRect Lib "user32" (ByVal hdc As Long, lpRect As RECT, ByVal hBrush As Long) As Long
Public Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
Public Sub gdiDrawGradient( _
ByVal hdc As Long, _
ByRef rct As RECT, _
ByVal lEndColor As Long, _
ByVal lStartColor As Long, _
ByVal bVertical As Boolean)
Dim lStep As Long
Dim lPos As Long, lSize As Long
Dim bRGB(1 To 3) As Integer
Dim bRGBStart(1 To 3) As Integer
Dim dR(1 To 3) As Double
Dim dPos As Double, d As Double
Dim hBr As Long
Dim tR As RECT
LSet tR = rct
If bVertical Then
lSize = (tR.Bottom - tR.Top)
Else
lSize = (tR.Right - tR.Left)
End If
lStep = lSize \ 255
If (lStep < 3) Then
lStep = 3
End If
bRGB(1) = lStartColor And &HFF&
bRGB(2) = (lStartColor And &HFF00&) \ &H100&
bRGB(3) = (lStartColor And &HFF0000) \ &H10000
bRGBStart(1) = bRGB(1): bRGBStart(2) = bRGB(2): bRGBStart(3) = bRGB(3)
dR(1) = (lEndColor And &HFF&) - bRGB(1)
dR(2) = ((lEndColor And &HFF00&) \ &H100&) - bRGB(2)
dR(3) = ((lEndColor And &HFF0000) \ &H10000) - bRGB(3)
For lPos = lSize To 0 Step -lStep '
' Draw bar
If bVertical Then
tR.Top = tR.Bottom - lStep
Else
tR.Left = tR.Right - lStep
End If
If tR.Top < rct.Top Then
tR.Top = rct.Top
End If
If tR.Left < rct.Left Then
tR.Left = rct.Left
End If
hBr = CreateSolidBrush((bRGB(3) * &H10000 + bRGB(2) * &H100& + bRGB(1)))
FillRect hdc, tR, hBr
DeleteObject hBr
' Adjust colour '
dPos = ((lSize - lPos) / lSize)
If bVertical Then
tR.Bottom = tR.Top
bRGB(1) = bRGBStart(1) + dR(1) * dPos
bRGB(2) = bRGBStart(2) + dR(2) * dPos
bRGB(3) = bRGBStart(3) + dR(3) * dPos
Else
tR.Right = tR.Left
bRGB(1) = bRGBStart(1) + dR(1) * dPos
bRGB(2) = bRGBStart(2) + dR(2) * dPos
bRGB(3) = bRGBStart(3) + dR(3) * dPos
End If
Next lPos
End Sub
To test, add this code to a form:
Private Sub Command1_Click()
Dim r As RECT
r.Left = 10
r.Top = 10
r.Right = 100
r.Bottom = 150
Call gdiDrawGradient(Me.hdc, r, vbRed, vbBlue, True)
End Sub
Here's how to fill any polygon with a gradient, using Windows API calls from VB6.
Here's how to fill a PictureBox with a gradient, pure VB6 with no API calls.
VB6 doesn't appear to make it that easy to store +infinity, -infinity and NaN into double vars. It would help if it could so that I could do comparisons with those values in the context of complex numbers. How?
Actually, there is a MUCH simpler way to get Infinity, -Infinity and Not a Number:
public lfNaN as Double ' or As Single
public lfPosInf as Double
public lfNegInf as Double
on error resume next ' to ignore Run-time error '6': Overflow and '11': Division by zero
lfNaN = 0 / 0 ' -1.#IND
lfPosInf = 1 / 0 ' 1.#INF
lfNegInf = -1 / 0 ' -1.#INF
on error goto 0 ' optional to reset the error handler
A few different things. As you can see from Pax's example, you really just need to look up the IEEE 754 standard and then plug your bytes into the right places. The only caution I would give you is that MicroSoft has deprecated RtlMoveMemory due to it's potential for creating security issues of the overflow type. As an alternative you can accomplish this in "pure" VB with a little careful coercion using User Defined Types and LSet. (Also note that there are two types of NaN.)
Option Explicit
Public Enum abIEEE754SpecialValues
abInfinityPos
abInfinityNeg
abNaNQuiet
abNaNSignalling
abDoubleMax
abDoubleMin
End Enum
Private Type TypedDouble
value As Double
End Type
Private Type ByteDouble
value(7) As Byte
End Type
Public Sub Example()
MsgBox GetIEEE754SpecialValue(abDoubleMax)
End Sub
Public Function GetIEEE754SpecialValue(ByVal value As abIEEE754SpecialValues) As Double
Dim dblRtnVal As Double
Select Case value
Case abIEEE754SpecialValues.abInfinityPos
dblRtnVal = BuildDouble(byt6:=240, byt7:=127)
Case abIEEE754SpecialValues.abInfinityNeg
dblRtnVal = BuildDouble(byt6:=240, byt7:=255)
Case abIEEE754SpecialValues.abNaNQuiet
dblRtnVal = BuildDouble(byt6:=255, byt7:=255)
Case abIEEE754SpecialValues.abNaNSignalling
dblRtnVal = BuildDouble(byt6:=248, byt7:=255)
Case abIEEE754SpecialValues.abDoubleMax
dblRtnVal = BuildDouble(255, 255, 255, 255, 255, 255, 239, 127)
Case abIEEE754SpecialValues.abDoubleMin
dblRtnVal = BuildDouble(255, 255, 255, 255, 255, 255, 239, 255)
End Select
GetIEEE754SpecialValue = dblRtnVal
End Function
Public Function BuildDouble( _
Optional byt0 As Byte = 0, _
Optional byt1 As Byte = 0, _
Optional byt2 As Byte = 0, _
Optional byt3 As Byte = 0, _
Optional byt4 As Byte = 0, _
Optional byt5 As Byte = 0, _
Optional byt6 As Byte = 0, _
Optional byt7 As Byte = 0 _
) As Double
Dim bdTmp As ByteDouble, tdRtnVal As TypedDouble
bdTmp.value(0) = byt0
bdTmp.value(1) = byt1
bdTmp.value(2) = byt2
bdTmp.value(3) = byt3
bdTmp.value(4) = byt4
bdTmp.value(5) = byt5
bdTmp.value(6) = byt6
bdTmp.value(7) = byt7
LSet tdRtnVal = bdTmp
BuildDouble = tdRtnVal.value
End Function
One last side note, you can also get NaN this way:
Public Function GetNaN() As Double
On Error Resume Next
GetNaN = 0 / 0
End Function
This page shows a slightly torturous way to do it. I've trimmed it down to match what your question asked for but haven't tested thoroughly. Let me know if there's any problems. One thing I noticed on that site is that the code they had for a quiet NaN was wrong, it should start the mantissa with a 1-bit - they seemed to have got that confused with a signalling NaN.
Public NegInfinity As Double
Public PosInfinity As Double
Public QuietNAN As Double
Private Declare Sub CopyMemoryWrite Lib "kernel32" Alias "RtlMoveMemory" ( _
ByVal Destination As Long, source As Any, ByVal Length As Long)
' IEEE754 doubles: '
' seeeeeee eeeemmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm '
' s = sign '
' e = exponent '
' m = mantissa '
' Quiet NaN: s = x, e = all 1s, m = 1xxx... '
' +Inf : s = 0, e = all 1s, m = all 0s. '
' -Inf : s = 1, e = all 1s, m = all 0s. '
Public Sub Init()
Dim ptrToDouble As Long
Dim byteArray(7) As Byte
Dim i As Integer
byteArray(7) = &H7F
For i = 0 To 6
byteArray(i) = &HFF
Next
ptrToDouble = VarPtr(QuietNAN)
CopyMemoryWrite ptrToDouble, byteArray(0), 8
byteArray(7) = &H7F
byteArray(6) = &HF0
For i = 0 To 5
byteArray(i) = 0
Next
ptrToDouble = VarPtr(PosInfinity)
CopyMemoryWrite ptrToDouble, byteArray(0), 8
byteArray(7) = &HFF
byteArray(6) = &HF0
For i = 0 To 5
byteArray(i) = 0
Next
ptrToDouble = VarPtr(NegInfinity)
CopyMemoryWrite ptrToDouble, byteArray(0), 8
End Sub
It basically uses kernel-level memory copies to transfer the bit patterns from a byte array to the double.
You should keep in mind however that there are multiple bit-values that can represent QNaN, specifically the sign bit can be 0 or 1 and all bits of the mantissa other than the first can also be zero or 1. This may complicate your strategy for comparisons unless you can discover if VB6 only uses one of the bit patterns - it won't affect the initialization of those values however, assuming VB6 properly implements IEE754 doubles.