I am trying to make an "overlay" application if you want to call it that. So you can see everything on the very top layer (above all applications) but you cannot interact with any of it so the mouse clicks are behind this window. I have managed to do it with the main Form with a TransparencyKey for the background color (white). But adding a PictureBox, the things that are not white on it are not transparent.
I found a solution in C# but not sure how to "translate" it or apply it to VB.net. Click through transparency for Visual C# Window Forms?
Things I have done and tried:
Create a Graphic of the image instead but I was not successful. As so:
Dim imageFile As Image = Image.FromFile("MyImage.jpg")
' Create graphics object for alteration.
Dim newGraphics As Graphics = Graphics.FromImage(imageFile)
' Alter image.
newGraphics.FillRectangle(New SolidBrush(Color.Black), _
100, 50, 100, 100)
' Draw image to screen.
newGraphics.Graphics.DrawImage(imageFile, New PointF(0.0F, 0.0F))
Found this on MSDN and tried to use it and various other examples I found on the internet but no luck.
So overall: Is there any way to make a whole application "transparent" to mouse clicks. What is a method of making each object (such as PictureBoxes) transparent to mouse clicks. - Thanks
Imports System.Runtime.InteropServices
Class Form1
Private InitialStyle As Integer
Dim PercentVisible As Decimal
Private Sub Form1_Load(sender As Object, e As RoutedEventArgs) Handles Form1.Load
InitialStyle = GetWindowLong(Me.Handle, -20)
PercentVisible = 0.8
SetWindowLong(Me.Handle, -20, InitialStyle Or &H80000 Or &H20)
SetLayeredWindowAttributes(Me.Handle, 0, 255 * PercentVisible, &H2)
Me.Topmost = True
End Sub
<DllImport("user32.dll", EntryPoint:="GetWindowLong")> Public Shared Function GetWindowLong(ByVal hWnd As IntPtr, ByVal nIndex As Integer) As Integer
End Function
<DllImport("user32.dll", EntryPoint:="SetWindowLong")> Public Shared Function SetWindowLong(ByVal hWnd As IntPtr, ByVal nIndex As Integer, ByVal dwNewLong As Integer) As Integer
End Function
<DllImport("user32.dll", EntryPoint:="SetLayeredWindowAttributes")> Public Shared Function SetLayeredWindowAttributes(ByVal hWnd As IntPtr, ByVal crKey As Integer, ByVal alpha As Byte, ByVal dwFlags As Integer) As Boolean
End Function
End Class
Related
As described here I managed to have a Windows-Form one can click through.
My (in my opinion for this question most) relevant code parts read as follows:
First imports:
...
Imports System.Runtime.InteropServices
...
then definition and import of DLLs
...
Private InitialStyle As Integer
Dim PercentVisible As Decimal
...
<DllImport("user32.dll", EntryPoint:="GetWindowLong")> Public Shared Function GetWindowLong(ByVal hWnd As IntPtr, ByVal nIndex As Integer) As Integer
End Function
<DllImport("user32.dll", EntryPoint:="SetWindowLong")> Public Shared Function SetWindowLong(ByVal hWnd As IntPtr, ByVal nIndex As Integer, ByVal dwNewLong As Integer) As Integer
End Function
<DllImport("user32.dll", EntryPoint:="SetLayeredWindowAttributes")> Public Shared Function SetLayeredWindowAttributes(ByVal hWnd As IntPtr, ByVal crKey As Integer, ByVal alpha As Byte, ByVal dwFlags As Integer) As Boolean
End Function
...
and finally using it
...
InitialStyle = GetWindowLong(Me.Handle, -20)
PercentVisible = 0.8
SetWindowLong(Me.Handle, -20, InitialStyle Or &H80000 Or &H20)
SetLayeredWindowAttributes(Me.Handle, 0, 255 * PercentVisible, &H2)
...
As mentioned, this code makes it possible to click throug a windows form, so the clicks reach the programm placed behind the windows form. In my opinion the feature is best described as color filter for parts of or the whole monitor.
Is there a possibility to modify the code in such a way, that only left clicks are transferred through the form? Right mouse clicks are needed to open a contextmenu or the like...
If you want to recieve mouse events, you'll have to remove &H20 from your window style like this
SetWindowLong(Me.Handle, -20, InitialStyle Or &H80000)
but this prevents all mouse event propagating throught your form. Now you can handle the event as you need. And you have to propagate the left mouse click related events all by yourself to other applications.
I have made a custom task pane using a user control.
Every time I resize it I raise a method called SuspendDrawing the reason I do this is because the buttons on my custom task pane flicker when I resize it therefore I need to suspend it. I add these buttons using the designer
This works like a treat but then I need to call a method called ResumeDrawing when the user stops resizing however I don't know what event I should use to call the ResumeDrawing method as there is no ResizeEnd event for a user control.
Any suggestions would be appreciated as I'm out of ideas.
My code is as follows
Public Property Resizing As Boolean
<DllImport("user32.dll", EntryPoint:="SendMessageA", ExactSpelling:=True, CharSet:=CharSet.Ansi, SetLastError:=True)>
Private Shared Function SendMessage(ByVal hwnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
End Function
Public Shared Sub SuspendDrawing(ByVal target As Control)
SendMessage(target.Handle, WM_SETREDRAW, 0, 0)
End Sub
Public Shared Sub ResumeDrawing(ByVal target As Control)
ResumeDrawing(target, True)
End Sub
Public Shared Sub ResumeDrawing(ByVal target As Control, ByVal redraw As Boolean)
SendMessage(target.Handle, WM_SETREDRAW, 1, 0)
If redraw Then
target.Refresh()
End If
End Sub
Private Sub SideBarPowerPoint_Resize(sender As Object, e As EventArgs) Handles MyBase.Resize
SuspendDrawing(Me)
End Sub
My Custom Task Pane
Dim taskPaneView = New PowerPointCommon.SideBarPowerPoint
sideBarTaskPane = Globals.ThisAddIn.CustomTaskPanes.Add(taskPaneView, " ")
If sideBarTaskPane.Visible = True Then
sideBarTaskPane.Visible = False
End If
sideBarTaskPane.Visible = True
sideBarTaskPane.DockPosition = Microsoft.Office.Core.MsoCTPDockPosition.msoCTPDockPositionRight
sideBarTaskPane.Width = 100
I have an application written in VB.net running on Windows 7 that opens a word document and inserts some values into it. This works fine, but on my client's machines(development works fine) Word is opening up behind my application. I've tried maximizing the document in code, but it's still opening behind my application on the client machines. Does anyone have any idea how I can fix this?
Things I've already tried:
maximizing word in my application
giving focus to word in my application
I've made sure the patches are up to date.
I've performed a repair on Office
Have you tried minimizing the application, as opposed to maximizing the document?
Me.WindowState = FormWindowState.Minimized will minimize the form that calls it (this is assuming that you are using a forms application).
You might need to bring Word to the forefront. This is a bit different from bringing a form in your app to the top.
You'll need to have a reference to two APIs, FindWindow and SetWindowPos - the first one can find the windows handle for another application that is running, and the second sends a message to the operating system to give an application focus (it uses the windows handle from FindWindow)
Here's some sample code.
Public Class Form1
<Runtime.InteropServices.DllImport("user32.dll", SetLastError:=True, CharSet:=Runtime.InteropServices.CharSet.Auto)> _
Private Shared Function FindWindow(ByVal lpClassName As String, _
ByVal lpWindowName As String) As IntPtr
End Function
<Runtime.InteropServices.DllImport("user32.dll", SetLastError:=True)> _
Private Shared Function SetWindowPos(ByVal hWnd As IntPtr, ByVal hWndInsertAfter As IntPtr, ByVal X As Integer, ByVal Y As Integer, ByVal cx As Integer, ByVal cy As Integer, ByVal uFlags As Integer) As Boolean
End Function
Private Shared ReadOnly HWND_TOPMOST As New IntPtr(-1)
Private Shared ReadOnly HWND_NOTOPMOST As New IntPtr(-2)
Private Const SWP_NOSIZE As Integer = &H1
Private Const SWP_NOMOVE As Integer = &H2
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Shell("calc.exe")
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim myHandle As IntPtr = FindWindow(Nothing, "Calculator")
SetWindowPos(myHandle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE)
SetWindowPos(myHandle, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE)
End Sub
End Class
Clicking the first button will instantiate a copy of Calculator, the second button will make it topmost, then set it back to normal... so it will still be the top form, but the user can activate other windows as well.
How can I get the color of a pixel at the location of the cursor? I know how to get the mouses position using MousePosition but I can not figure out how to get the pixel color at that location.
A C# version: How do I get the colour of a pixel at X,Y using c# ?
Should be easy to rewrite in VB.NET.
Quick simple very slow but it works.
The idea is to copy the screen to a bitmap which can be done using the GDI+ build into the drawing.graphics object. Then simply read the bitmap that it generates. Get pixel is very slow. The best way it to read the image byte array directly.
Function MakeScreenShot() As Drawing.Bitmap
Dim out As Drawing.Bitmap
'Get the screen Size
Dim bounds As Rectangle = Screen.GetBounds(Point.Empty)
'create the bitmap
out = New Drawing.Bitmap(bounds.Width, bounds.Height)
'create a graphic object to recive the pic
Using gr As Drawing.Graphics = Graphics.FromImage(out)
'Copy the screen using built in API
gr.CopyFromScreen(Point.Empty, Point.Empty, bounds.Size)
End Using
Return out
End Function
Private Sub Button5_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button5.Click
Dim BM As Drawing.Bitmap = MakeScreenShot()
Dim mouseloc As Point = Cursor.Position
Dim c As Color = BM.GetPixel(mouseloc.X, mouseloc.Y) ' The Slowest way possable to read a color
Debug.Print(c.R & "," & c.G & "," & c.B)
End Sub
Enjoy.
Try this code:
#Region "#include"
Imports System
Imports System.Drawing
Imports System.Runtime.InteropServices
#End Region
Public Class Test
#Region "From Windows API"
<DllImport("user32.dll", SetLastError:=True)> _
Public Shared Function GetWindowDC(ByVal hwnd As IntPtr) As IntPtr
'Do not try to name this method "GetDC" it will say that user32 doesnt have GetDC !!!
End Function
<DllImport("user32.dll", SetLastError:=True)> _
Public Shared Function ReleaseDC(ByVal hwnd As IntPtr, ByVal hdc As IntPtr) As Int32
End Function
<DllImport("gdi32.dll", SetLastError:=True)> _
Public Shared Function GetPixel(ByVal hdc As IntPtr, ByVal nXPos As Integer, ByVal nYPos As Integer) As UInteger
End Function
#End Region
REM --Test--
#Region "Some Functions"
Public Function GetPixelColor(ByVal x As Integer, ByVal y As Integer) As Color
Dim hdc As IntPtr = GetWindowDC(IntPtr.Zero)
Dim pixel As UInteger = GetPixel(hdc, x, y)
Dim color As Color
ReleaseDC(IntPtr.Zero, hdc)
MsgBox(pixel)
color = color.FromArgb(Int(pixel And &HFF), _
Int(pixel And &HFF00) >> 8, _
Int(pixel And &HFF0000) >> 16)
Return color
End Function
#End Region
REM --Test--
#Region "OnClick"
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim mouseloc As Point = Cursor.Position
Me.Label1.BackColor = GetPixelColor(mouseloc.X, mouseloc.Y)
Me.Refresh()
End Sub
#End Region
End Class
You need button (name==Button1) and label (name==Label1). To get color from screen you will need to use Timer.
If you need to rewrite code from C# to VB.NET use this link: http://www.harding.edu/fmccown/vbnet_csharp_comparison.html
Keep it simple, not very optimized but do the job:
Public Class Form1
Declare Auto Function FindWindow Lib "user32" (ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr
Declare Function GetDC Lib "user32" (ByVal hWnd As IntPtr) As IntPtr
Declare Function ReleaseDC Lib "user32" (ByVal hwnd As IntPtr, ByVal hdc As IntPtr) As IntPtr
Private Declare Function GetPixel Lib "gdi32" (ByVal hdc As IntPtr, ByVal X As Int32, ByVal Y As Int32) As Int32
Private Function CheckScreen()
Dim CursorLoc As Point = Cursor.Position
Dim hDC As IntPtr = GetDC(0) '0 = Get the color to any window on screen, not only your app
Try
Dim CursorColor As Integer = GetPixel(hDC, CursorLoc.X, CursorLoc.Y)
Me.Panel1.BackColor = ColorTranslator.FromWin32(CursorColor) 'a simple panel to show the color
Me.Refresh()
Return True
Catch ex As Exception
Return False
Finally
ReleaseDC(0, hDC)
End Try
End Function
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Me.Timer1.Start() 'Timer with a short delay
End Sub
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
CheckScreen()
End Sub
End Class
This is actually harder than you would guess. I would look for some example code that already does it, and copy their technique.
In the end, the algorithm is going to have to perform these operations:
Get a bitmap of the desktop/window close to the cursor position
Index into that bitmap with the cursor position and extract the pixel color
It sounds simple, but is not easy.
Does anyone know how to change the kerning (space between characters) in vb.net? For example, i would like to change "STRING" to "S T R I N G". If possible i would like to be able to create my own font where i can specify the kerning as i wish! Thanks in advance!
The only way I found is to P/Invoke. Assumming a generic form with a generic button this code will work.
Imports System.Runtime.InteropServices
Public Class Form1
Declare Function SetTextCharacterExtra Lib "gdi32" Alias "SetTextCharacterExtra" (ByVal hDC As Integer, ByVal nCharExtra As Integer) As Integer
<DllImport("gdi32")> _
Private Shared Function TextOut(ByVal hdc As IntPtr, ByVal x As Integer, ByVal y As Integer, ByVal textstring As String, ByVal charCount As Integer) As Boolean
End Function
<DllImport("gdi32")> _
Private Shared Function SelectObject(ByVal hdc As IntPtr, ByVal hgdiobj As IntPtr) As IntPtr
End Function
<DllImport("gdi32")> _
Private Shared Function DeleteObject(ByVal objectHandle As IntPtr) As Boolean
End Function
<DllImport("gdi32")> _
Private Shared Function SetBkColor(ByVal hdc As IntPtr, ByVal crColor As Integer) As UInt32
End Function
<DllImport("gdi32")> _
Private Shared Function SetTextColor(ByVal hdc As IntPtr, ByVal crColor As Integer) As UInt32
End Function
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Using G = Graphics.FromHwnd(Me.Handle)
Using myFont As New System.Drawing.Font("Arial", 20, FontStyle.Regular, GraphicsUnit.Pixel)
'Regular Way
Dim LeftEdge = 20
G.DrawString("Hello", myFont, Brushes.Red, LeftEdge, 40)
'If you want kerning
Dim Kerning As Integer = 6 'I think this is twips
Dim Hdc As IntPtr
Dim FontPtr As IntPtr
Try
'Grab the Graphic object's handle
Hdc = G.GetHdc()
'Set the current GDI font
FontPtr = SelectObject(Hdc, myFont.ToHfont())
'Set the drawing surface background color
SetBkColor(Hdc, ColorTranslator.ToWin32(Me.BackColor))
'Set the text color
SetTextColor(Hdc, ColorTranslator.ToWin32(Color.Red))
'Set the kerning
SetTextCharacterExtra(Hdc, Kerning)
Dim Text = "Hello"
'Draw the text at (20,60), Kerning will be applied so reset the left edge to half of kerning
TextOut(Hdc, LeftEdge + (Kerning \ 2), 60, Text, Text.Length)
Catch ex As Exception
Finally
'Release the font
DeleteObject(FontPtr)
'Release the handle on the graphics object
G.ReleaseHdc()
End Try
End Using
End Using
End Sub
End Class
You can use CSS.
I usually set the letter-spacing style attribute in my aspx page.