From: Bee on
On Jan 9, 7:45 pm, Just_a_...(a)home.net wrote:
> I have a little clock with a color-key type of invisibility.  
>
> In Windows XP, it works just fine.  In Vista, I can move the form by
> clicking and dragging in the invisible area.  It is invisible but still
> "there" to Vista.
>
> Here's the code I have used for years to prepare the form:
>
>   Public Const InvisibleColor = 16744705
>
>  'Prepare for Invisibility
>   Ret = GetWindowLong(Me.hwnd, GWL_EXSTYLE)
>   Ret = Ret Or WS_EX_LAYERED
>   SetWindowLong Me.hwnd, GWL_EXSTYLE, Ret
>  'Set the opacity of the layered window to 128
>   SetLayeredWindowAttributes Me.hwnd, InvisibleColor, 0, LWA_COLORKEY
>
> Then the usual to invoke it:
>
>   gbInvisible = GetSetting(App.EXEName, "Options", "Invisible", False)
>   If gbInvisible Then Me.BackColor = InvisibleColor
>
> Is there an update to make it work properly on Vista?
>
> Mike

What happens when you turn off Aero?
From: Oxana on
...Same problem.

After switching to Aero Theme from any other my LayeredWindow
becomes invisible.. but still exists for Vista.
UpdateLayeredWindow function doesn't return any mistakes.
Window is invisible even if i use ULW_OPAQUE..

Playing with BLENDFUNCTION structure doesnt give any result too.

Need help!


"Bee" wrote:

> On Jan 9, 7:45 pm, Just_a_...(a)home.net wrote:
> > I have a little clock with a color-key type of invisibility.
> >
> > In Windows XP, it works just fine. In Vista, I can move the form by
> > clicking and dragging in the invisible area. It is invisible but still
> > "there" to Vista.
> >
> > Here's the code I have used for years to prepare the form:
> >
> > Public Const InvisibleColor = 16744705
> >
> > 'Prepare for Invisibility
> > Ret = GetWindowLong(Me.hwnd, GWL_EXSTYLE)
> > Ret = Ret Or WS_EX_LAYERED
> > SetWindowLong Me.hwnd, GWL_EXSTYLE, Ret
> > 'Set the opacity of the layered window to 128
> > SetLayeredWindowAttributes Me.hwnd, InvisibleColor, 0, LWA_COLORKEY
> >
> > Then the usual to invoke it:
> >
> > gbInvisible = GetSetting(App.EXEName, "Options", "Invisible", False)
> > If gbInvisible Then Me.BackColor = InvisibleColor
> >
> > Is there an update to make it work properly on Vista?
> >
> > Mike
>
> What happens when you turn off Aero?
> .
>
From: Mike Williams on
<Just_a_fan(a)home.net> wrote in message
news:g1jik5hrpetmp6ra24pevtijn0koin6na1(a)4ax.com...

> I have a little clock with a color-key type of invisibility.
> In Windows XP, it works just fine. In Vista, I can move the
> form by clicking and dragging in the invisible area. It is invisible
> but still "there" to Vista.

I know this solves only part of the problem but on the presumption that you
are allowing the user to drag the Form by releasing capture and sending a
button down message then why don't you do that only if the user clicks a
part of the Form that is not set to the transparent colour, something like:

Private Sub Form_MouseDown(Button As Integer, Shift As Integer, _
X As Single, Y As Single)
If Button = vbLeftButton And Point(X, Y) <> InvisibleColor Then
ReleaseCapture
SendMessageLong Me.hWnd, WM_NCLBUTTONDOWN, HTCAPTION, 0&
End If
End Sub

You'll still need to look for a means of preventing the Form from picking up
the focus when the user clicks a transparent area of it, but at least it
will prevent the Form from moving under such conditions and it might be
sufficient to get you by until you find a better solution.

Mike



From: Mike Williams on
<Just_a_fan(a)home.net> wrote in message
news:g1jik5hrpetmp6ra24pevtijn0koin6na1(a)4ax.com...

> In Windows XP, it works just fine . . . but In Vista
> [whilst running Aero] I can move the form by clicking
> and dragging in the invisible area. It is invisible but still
> "there" to Vista.

Further to my previous response, you can solve the problem in a better way
(solving both parts of the problem) by setting the translucency and the
transparent colour exactly as you are doing now, presumably something like:

SetLayeredWindowAttributes Me.hwnd, transColor, 128, _
LWA_COLORKEY Or LWA_ALPHA

.. . . and then following that line with a line with another line to set the
window region, such as:

SetWindowRgn Me.hwnd, Rgn1, True

.. . . where Rgn1 is a region created using one of the regular shaped region
function (CreateEllipticRgn for example if your clock is a nice round shape)
or alternatively a region created in code from a bitmap (either drawn or
loaded) by combining smaller rectangular regions into one whole if your
clock (or whatever) is irregularly shaped.

I've just tried that now on both regular and irregularly shaped images and
the translucency and the region transparency work fine together (although
the LWA_COLORKEY flag in the call to SetLayeredWindowAttributes is of course
no longer actually required when using a region to set the shape). It works
fine both in XP and in Vista, regardless of whether Vista is running Aero or
not.

Mike


From: Mike Williams on
<Just_a_fan(a)home.net> wrote in message
news:bf9ql5p168nkt791dcli7ajj33tmvfa8sr(a)4ax.com...

> Again a miss but thanks for answering.

I think you're dismissing my suggestion without even giving it a try.
Personally I reckon it will work fine and will solve your problem. It is at
the very least worth giving it a try.

> This is a VERY irregular form and the parts which are visible
> and invisible change every second. It is an odd clock. Go to
> Planet-Source-Code, search for Mike Morrow and get the
> Triangular Clock under that name. Compile it, take it to Vista
> and you should see what I mean. Dots go on and off every
> second & minute and become either Red/Green or invisible.
> Yes, much of the form stays invisible all of the time but this,
> too, is very irregular, being the area outside the dots.

I've just downloaded and ran your code and I can see that your triangular
clock, although quite small, has a fairly complex shape, with all those
little separate circles and pieces of text and other stuff, at least as far
as creating a region "on the fly" is concerned, but I still think it is very
"doable" using the suggestion I made in my previous response. I know that it
would be necessary to examine the image pixel by pixel in order to create
such a complex shaped region, but examining pixels is very quick if you use
code to load the pixel data into a VB array so as to get rid of the need to
repeatedly call GetPixel. Using that code to examine the image data and
determine all the required little rectangular regions and then combining all
those subregions into one main region is obviously going to take much more
time than simply examining the pixel data would take of course, but it is
nevertheless still reasonably quick if you do it correctly

> Dots go on and off every second & minute
> and become either Red/Green or invisible.

Yes, I can see that you are using Shape Controls for those things and are
effectively using them to create a slightly different composite "image"
which changes in certain parts every second. That part of your code could
easily be replaced by some simple drawing instructions though. Even using
the native VB Circle method you should be able to draw all of those 25
little filled (or unfilled) circles and print the small amount of text which
displays the time all in a very short space of time, probably something less
than half a millisecond for the full drawing even on fairly modest machines.
That then leaves just the region to create from the complex finished
drawing, so that you can set the region in order to overcome your current
display problems on Vista when running Aero. Admittedly analyzing the
drawing and creating and setting the complex region is going to be by far
the most time consuming part of the job, taking much longer than the half
millisecond needed to create the drawing in the first place, but you should
nevertheless be able to do it in the time available.

In fact since first responding to your earlier messages in this thread I
cobbled together some test code to show you how to create a small reasonably
complex shaped drawing and get it into a region. At the time I was mainly
concerned in providing you with something which actually works and which
overcomes your Vista Aero problem, rather than worrying about the speed
issue or about writing neat code, so it is a bit of a jumble at the moment,
but it seems okay. I've just added some timer code to it in response to this
latest post of yours and I think it will do the job for you. Using my own
test image, which is created in the Form load event just for testing
purposes and which consists of 5 fairly large coloured filled circles and a
large point size piece of text, I have timed how long it takes the code to
create and set the region and the translucency etc from that image. Code of
such nature (which consists in a large part of examining data in a VB array)
runs faster as a compiled exe than it does in the IDE of course, although of
course the creation and cobbling together of the individual little regions
into one composite region does slow it down a lot whether compiled or not,
but I think it will be fast enough for you. In this test the main part of
the drawing (the five relatively large coloured filled circles) and the
"outline" part of what is effectively some "outline text with a transparent
fill" are all treated as being part of the region and therefore semi
translucent, and any point that is not within the irregular shaped drawing
or is within the transparent fill of the outline text is treated as not
being part of the region and therefore being totally transparent. If the
mouse is anywhere on any of these transparent areas then you can "clcik
through" onto the desktop (or whatever), and it works just as well in Vista
when running Aero (because of the region) as it does otherwise.

The shape of the drawing in my example (as far as creating a region is
concerned) is reasonably complex, mainly because it includes some large
point size outline text with an effectively transparent fill, and when
testing as a standard native code compiled exe it does the entire job in an
average of about 9 milliseconds on my own machine. I've just tried it again,
this time using a copy of your own image of the triangular clock consisting
of the 25 little circles and the text showing the time. Your own drawing is
smaller, but is more complex because it contains 25 little circles and
because the text, although not transparently filled, contains more and
smaller characters. In fact it takes the same time on your drawing as it
does on my own, an average of about 9 milliseconds. Since it will take
certainly less than 1 millisecond to actually create a new drawing each
time, or to modify the existing one, then that is a total of less than 10
milliseconds (say 10 milliseconds on average) both to create the drawing and
to analyze it and create and set the complex region from it.

So, on my machine at least, your clock would be updating itself once every
second (once every 1000 milliseconds) and it will take just 10 milliseconds
to perform the entire "next second" modification and to create and assign
any new region that might be required. Your code will therefore be working
for a maximum of only 1 per cent of the available time, and it will be
spending the remaining 99 per cent of the time waiting for the next second
to arrive. Sounds okay to me.

Anyway, here's my example so you can try it out yourself on your own
machine. Start a new VB project and place one PictureBox, one Label Control
and two Command Buttons on the Form. Set the Form's BorderStyle property to
None in the IDE. Then paste in the following code. Run it as a native code
compiled exe. Clicking one button will cause the filled circles and the
outline of the text to become semi translucent, with the remainder of the
Form and the area within the outline of the characters becoming totally
transparent. Even when running Vista in Aero mode you should find that the
transparent areas (anywhere outside the filled circles and anywhere within
the "transparent fill" of the outline characters) is properly "click
through". The time taken to analyze the image and to create and assign the
complex region will be displayed in the Label (in milliseconds). Click the
other button to make the Form solid again. With Windoze being what it is you
should of course click the buttons to set and reset the transparency /
translucency a number of times and take the average of them.

This is just a sample to test the speed of operation of course, and you will
need to include the code to create your triangular clock image and to
repeatedly pefform the necessary stuff every second but, as I have already
mentioned, the drawing part of the code will take virtually no time at all
by comparison (certainly less than an additional one millisecond). Let me
know if it is any good for you. Anyway, here's the example code:

Mike

Option Explicit
Private s1 As String, s2 As String
Private Declare Function CreateRectRgn Lib "gdi32" _
(ByVal x1 As Long, ByVal y1 As Long, ByVal X2 As Long, _
ByVal Y2 As Long) As Long
Private Declare Function CombineRgn Lib "gdi32" _
(ByVal hDestRgn As Long, ByVal hSrcRgn1 As Long, _
ByVal hSrcRgn2 As Long, ByVal nCombineMode As Long) As Long
Private Declare Function DeleteObject Lib "gdi32" _
(ByVal hObject As Long) As Long
Private Declare Function GetWindowRgn Lib "user32" _
(ByVal hWnd As Long, ByVal hRgn As Long) As Long
Private Declare Function SetWindowRgn Lib "user32" _
(ByVal hWnd As Long, ByVal hRgn As Long, _
ByVal bRedraw As Boolean) As Long
Private Declare Function GetWindowLong Lib "user32" _
Alias "GetWindowLongA" (ByVal hWnd As Long, _
ByVal nIndex As Long) As Long
Private Declare Function SetWindowLong Lib "user32" _
Alias "SetWindowLongA" (ByVal hWnd As Long, _
ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Private Declare Function SetLayeredWindowAttributes _
Lib "user32" (ByVal hWnd As Long, ByVal crKey As Long, _
ByVal bAlpha As Byte, ByVal dwFlags As Long) As Long
Private Declare Function SendMessageLong Lib "user32" _
Alias "SendMessageA" (ByVal hWnd As Long, _
ByVal wMsg As Long, ByVal wParam As Long, _
ByVal lParam As Long) As Long
Private Declare Function ReleaseCapture _
Lib "user32" () As Long
Private Declare Function GetDIBits Lib "gdi32" _
(ByVal hdc As Long, ByVal hBitmap As Long, _
ByVal nStartScan As Long, ByVal nNumScans As Long, _
lpBits As Any, lpBI As BITMAPINFO, _
ByVal wUsage As Long) As Long
Private Declare Function timeBeginPeriod Lib "winmm.dll" _
(ByVal uPeriod As Long) As Long
Private Declare Function timeEndPeriod Lib "winmm.dll" _
(ByVal uPeriod As Long) As Long
Private Declare Function timeGetTime _
Lib "winmm.dll" () As Long
Private Type BITMAPINFOHEADER
biSize As Long
biWidth As Long
biHeight As Long
biPlanes As Integer
biBitCount As Integer
biCompression As Long
biSizeImage As Long
biXPelsPerMeter As Long
biYPelsPerMeter As Long
biClrUsed As Long
biClrImportant As Long
End Type
Private Type BITMAPINFO
bmiHeader As BITMAPINFOHEADER
End Type
Private Const DIB_RGB_COLORS = 0
Private Const BI_RGB = 0
Private Const RGN_COPY = 5
Private Const RGN_OR = 2
Private Const WM_NCLBUTTONDOWN = &HA1
Private Const HTCAPTION = 2
Private Const GWL_EXSTYLE = (-20)
Private Const WS_EX_LAYERED = &H80000
Private Const LWA_COLORKEY = &H1
Private Const LWA_ALPHA = &H2
Private transColour As Long, Opacity As Long
Private oldRgn As Long, oldStyle As Long

Private Sub Command1_MouseDown(Button As Integer, _
Shift As Integer, X As Single, Y As Single)
Dim t1 As Long, t2 As Long
Dim lStyle As Long, rgn1 As Long
t1 = timeGetTime
lStyle = oldStyle Or WS_EX_LAYERED
SetWindowLong Me.hWnd, GWL_EXSTYLE, lStyle
SetLayeredWindowAttributes Me.hWnd, transColour, _
Opacity, LWA_COLORKEY Or LWA_ALPHA
rgn1 = RegionFromImage(Picture1, transColour)
SetWindowRgn Me.hWnd, rgn1, True
DeleteObject rgn1
t2 = timeGetTime
Label1.Caption = Format(t2 - t1) & " msecs"
End Sub

Private Sub Command2_MouseDown(Button As Integer, _
Shift As Integer, X As Single, Y As Single)
SetWindowLong Me.hWnd, GWL_EXSTYLE, oldStyle
SetWindowRgn Me.hWnd, oldRgn, True
Label1.Caption = ""
End Sub

Private Sub Form_Load()
Dim X As Long, Y As Long
timeBeginPeriod 1 ' set timing resolution
' (in the following line make sure you use a colour that
' is actually available as a solid colour in the typical
' "5-6-5 bit" RGB arrangement of a system that might be
' running its display at the old low 16 bit colour depth,
' or alternatively you can check the colour depth of the
' system in code and omit the region stuff altogether on
' 16 bit systems since they cannot be running Vista in
' Aero mode and the Aero problem will not therefore arise)
transColour = RGB(0, 0, 8) ' or any suitable unused colour
' set opacity (anything between 0 and 255)
Opacity = 150
Me.ScaleMode = vbPixels
Command1.Caption = "Make Translucent"
Command1.Move 75, 150, 100, 40
Command2.Caption = "Make Solid"
Command2.Move 10, 40
Label1.FontBold = True
Label1.Move 20, 14, 60, 20
Me.BackColor = transColour
' The following is just some temporary code to draw
' an irregularly shaped bitmp for test purposes
With Picture1
.Visible = False
.ScaleMode = vbPixels
.AutoRedraw = True
.BorderStyle = vbBSNone
.Move 0, 0, 250, 250 ' 250 x 250 pixels
.BackColor = transColour
.FillStyle = vbFSSolid
.FillColor = vbRed
Picture1.Circle (125, 125), 80, .FillColor
.FillColor = vbBlue
Picture1.Circle (200, 50), 49, .FillColor
.FillColor = vbGreen
Picture1.Circle (50, 50), 49, .FillColor
.FillColor = vbMagenta
Picture1.Circle (50, 200), 49, .FillColor
.FillColor = vbCyan
Picture1.Circle (200, 200), 49, .FillColor
Picture1.Font.Name = "Times New Roman"
Picture1.Font.Size = 38
Picture1.Font.Bold = True
Picture1.ForeColor = vbBlue
For Y = 89 To 91
For X = 59 To 61
Picture1.CurrentX = X
Picture1.CurrentY = Y
Picture1.Print "TEST";
Next X
Next Y
Picture1.ForeColor = transColour
Picture1.CurrentX = 60
Picture1.CurrentY = 90
Picture1.Print "TEST";
Me.Width = ScaleX(.Width, vbPixels, vbTwips)
Me.Height = ScaleY(.Height, vbPixels, vbTwips)
End With
Set Me.Picture = Picture1.Image
oldStyle = GetWindowLong(hWnd, GWL_EXSTYLE)
GetWindowRgn Me.hWnd, oldRgn
End Sub

Private Sub Form_Unload(Cancel As Integer)
timeEndPeriod 1 ' release timing resolution
End Sub

Private Sub Form_MouseDown(Button As Integer, Shift As Integer, _
X As Single, Y As Single)
If Button = vbLeftButton Then
' allow the user to move the Form ...
ReleaseCapture
SendMessageLong Me.hWnd, WM_NCLBUTTONDOWN, HTCAPTION, 0&
End If
End Sub

Private Sub Form_DblClick()
Unload Me
End Sub

Private Function RegionFromImage(p1 As PictureBox, _
transClr As Long) As Long
Dim FullRgn As Long, LineRgn As Long, TempRgn As Long
Dim X As Long, Y As Long, p1Pixel As Boolean
Dim xBegin As Long, xEnd As Long, PicOld As Boolean
Dim wide As Long, high As Long
Dim transColourBGR As Long
FullRgn = CreateRectRgn(0, 0, 0, 0)
' swap r and b of rgb to account for the fact that
' they are in that order in a DIBSection
transColourBGR = transClr And &HFF00FF00 _
Or (transClr And &HFF&) * &H10000 _
Or (transClr And &HFF0000) \ &H10000
wide = Picture1.ScaleWidth
high = Picture1.ScaleHeight
ReDim myArray(0 To wide - 1, 0 To high - 1) As Long
' Get Picture1 pixels into array 1
Dim bmapinfo As BITMAPINFO
With bmapinfo.bmiHeader
.biSize = 40
.biWidth = wide
' make the following negative to cause the GetDIBits
' to return the scanlines in "top down" order instead
' of its normal "bottom up" order
.biHeight = -high
.biPlanes = 1
.biBitCount = 32
.biCompression = BI_RGB
End With
GetDIBits p1.hdc, p1.Image, 0, high, _
myArray(0, 0), bmapinfo, DIB_RGB_COLORS
For Y = 0 To high - 1
For X = 0 To wide - 1
p1Pixel = (myArray(X, Y) <> transColourBGR)
If p1Pixel = True Then
If PicOld = False Then
xBegin = X
End If
PicOld = True
Else
If PicOld = True Then
xEnd = X
LineRgn = CreateRectRgn(xBegin, Y, xEnd, Y + 1)
CombineRgn FullRgn, FullRgn, LineRgn, RGN_OR
DeleteObject LineRgn
End If
PicOld = False
End If
Next X
If PicOld = True Then
xEnd = X
LineRgn = CreateRectRgn(xBegin, Y, xEnd, Y + 1)
CombineRgn FullRgn, FullRgn, LineRgn, RGN_OR
DeleteObject LineRgn
End If
PicOld = False
Next Y
RegionFromImage = FullRgn
End Function