My project consists of 2 programs and a dll called VDesk. One program runs all the time and references the dll, and tells the dll to switch the desktop on a hotkey. I will not show any of that code, because all it does it tell the desktops to switch, and i am having no problem with it. In the dll: i have 4 objects: A structure called Window that represents an open window on a desktop. A class called Methods, all that holds is declares on windows dll's, and it is used by all of the rest of my code. A class called Desktop. Basically all that holds is a Collection(Of Window) and a property called name, which is the string name to represent the desktop. Lastly, and most importantly, i have a class called VirtualDesktopManager. It holds a Collection(Of Desktop) and several overloads of a method called SwitchDesktop, which switches between desktops. In the other program: it is called DeskSwitch.exe. I has one form called Switcher. I will explain more about that later on.
Now for my code. Here is the code for the Methods class, which i believe is the easiest to figure out:
Imports System.Runtime.InteropServices
Public Class Methods
''' <summary>
''' Determines weather or not a handle is a window
''' </summary>
''' <param name="hWnd">The hande to the process</param>
''' <returns></returns>
''' <remarks></remarks>
Public Declare Function IsWindow Lib "user32.dll" (ByVal hWnd As IntPtr) As Boolean
Public Delegate Function CallBack(ByVal hwnd As IntPtr, ByVal lParam As Integer) As Boolean
''' <summary>
''' Enumarates through all the open windows
''' </summary>
''' <param name="Adress">A method</param>
''' <param name="y">Must be zero</param>
''' <returns></returns>
''' <remarks></remarks>
Public Declare Function EnumWindows Lib "user32" (ByVal Adress As CallBack, ByVal y As Integer) As Integer
''' <summary>
''' Determines if a window is shown in the taksbar
''' </summary>
''' <param name="hwnd">The handle to the window</param>
''' <returns></returns>
''' <remarks></remarks>
Public Declare Function IsWindowVisible Lib "user32.dll" (ByVal hwnd As IntPtr) As Boolean
''' <summary>
''' Returns the handle to the foreground window
''' </summary>
''' <returns></returns>
''' <remarks></remarks>
Public Declare Function GetForegroundWindow Lib "user32.dll" () As IntPtr
''' <summary>
''' Ends a process
''' </summary>
''' <param name="hWnd">The handle to the window to kill</param>
''' <returns></returns>
''' <remarks></remarks>
Public Declare Function EndTask Lib "user32.dll" (ByVal hWnd As IntPtr) As Integer
''' <summary>
''' Shows or hides a window
''' </summary>
''' <param name="hwnd">The handle to the window</param>
''' <param name="nCmdShow"></param>
''' <returns></returns>
''' <remarks></remarks>
Public Declare Function ShowWindow Lib "user32.dll" (ByVal hwnd As IntPtr, ByVal nCmdShow As WindowShowStyle) As Boolean
Public Enum WindowShowStyle As UInteger
''' <summary>Hides the window and activates another window.</summary>
''' <remarks>See SW_HIDE</remarks>
Hide = 0
'''<summary>Activates and displays a window. If the window is minimized
''' or maximized, the system restores it to its original size and
''' position. An application should specify this flag when displaying
''' the window for the first time.</summary>
''' <remarks>See SW_SHOWNORMAL</remarks>
ShowNormal = 1
''' <summary>Activates the window and displays it as a minimized window.</summary>
''' <remarks>See SW_SHOWMINIMIZED</remarks>
ShowMinimized = 2
''' <summary>Activates the window and displays it as a maximized window.</summary>
''' <remarks>See SW_SHOWMAXIMIZED</remarks>
ShowMaximized = 3
''' <summary>Maximizes the specified window.</summary>
''' <remarks>See SW_MAXIMIZE</remarks>
Maximize = 3
''' <summary>Displays a window in its most recent size and position.
''' This value is similar to "ShowNormal", except the window is not
''' actived.</summary>
''' <remarks>See SW_SHOWNOACTIVATE</remarks>
ShowNormalNoActivate = 4
''' <summary>Activates the window and displays it in its current size
''' and position.</summary>
''' <remarks>See SW_SHOW</remarks>
Show = 5
''' <summary>Minimizes the specified window and activates the next
''' top-level window in the Z order.</summary>
''' <remarks>See SW_MINIMIZE</remarks>
Minimize = 6
''' <summary>Displays the window as a minimized window. This value is
''' similar to "ShowMinimized", except the window is not activated.</summary>
''' <remarks>See SW_SHOWMINNOACTIVE</remarks>
ShowMinNoActivate = 7
''' <summary>Displays the window in its current size and position. This
''' value is similar to "Show", except the window is not activated.</summary>
''' <remarks>See SW_SHOWNA</remarks>
ShowNoActivate = 8
''' <summary>Activates and displays the window. If the window is
''' minimized or maximized, the system restores it to its original size
''' and position. An application should specify this flag when restoring
''' a minimized window.</summary>
''' <remarks>See SW_RESTORE</remarks>
Restore = 9
''' <summary>Sets the show state based on the SW_ value specified in the
''' STARTUPINFO structure passed to the CreateProcess function by the
''' program that started the application.</summary>
''' <remarks>See SW_SHOWDEFAULT</remarks>
ShowDefault = 10
''' <summary>Windows 2000/XP: Minimizes a window, even if the thread
''' that owns the window is hung. This flag should only be used when
''' minimizing windows from a different thread.</summary>
''' <remarks>See SW_FORCEMINIMIZE</remarks>
ForceMinimized = 11
End Enum
<Runtime.InteropServices.DllImport("user32.dll")> _
Shared Function GetWindowText(ByVal hWnd As IntPtr, ByVal lpWindowText As System.Text.StringBuilder, _
ByVal nMaxCount As Integer) As Integer
End Function
''' <summary>
''' Get's the handle and text of the foreground window
''' </summary>
Public Shared Function GetWindowText(ByVal hwnd As IntPtr) As String
Dim title As New System.Text.StringBuilder(255)
Dim titleLength As Integer = GetWindowText(hwnd, title, title.Capacity + 1)
title.Length = titleLength
Return title.ToString()
End Function
''' <summary>
''' Sets the text of a window
''' </summary>
''' <param name="hWnd">The handle to the window</param>
''' <param name="lpstring">The text to set</param>
''' <returns></returns>
''' <remarks></remarks>
Public Declare Auto Function SetWindowText Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal lpstring As String) As Boolean
End Class
As you can see, all that holds is methods that are inside windows dll's that my project needs to function.
Here, i have the code for the Window structure:
Imports VDesk.Methods
''' <summary>
''' Represents an open, visible window
''' </summary>
Public Structure Window
''' <summary>
''' Creates a new window based on the specified handle
''' </summary>
''' <param name="hwnd">The handle to the window</param>
Sub New(ByVal hwnd As IntPtr)
Me.hwnd = hwnd
Me.mainwintext = GetWindowText(Handle)
End Sub
''' <summary>
''' Gets the handle of the window
''' </summary>
Public ReadOnly Property Handle() As IntPtr
Get
Return hwnd
End Get
End Property
''' <summary>
''' Gets or sets the text of the window
''' </summary>
Public Property Text() As String
Get
Return mainwintext
End Get
Set(ByVal value As String)
SetWindowText(hwnd, value)
mainwintext = value
End Set
End Property
Private hwnd As IntPtr
Private mainwintext As String
''' <summary>
''' Shows the window in it's last size and position after being hidden
''' </summary>
Public Sub Show()
ShowWindow(Handle, WindowShowStyle.Show)
End Sub
''' <summary>
''' Maximizes the window
''' </summary>
Public Sub Maximize()
ShowWindow(Handle, WindowShowStyle.Maximize)
End Sub
''' <summary>
''' Minimizes the window
''' </summary>
Public Sub Minimize()
ShowWindow(Handle, WindowShowStyle.ShowMinimized)
End Sub
''' <summary>
''' Shows the window maximized after being hidden
''' </summary>
Public Sub ShowMaximized()
ShowWindow(Handle, WindowShowStyle.ShowMaximized)
End Sub
''' <summary>
''' Shows the window in it's default startup size after being hidden
''' </summary>
Public Sub ShowDefault()
ShowWindow(Handle, WindowShowStyle.ShowDefault)
End Sub
''' <summary>
''' Shows the window in it's after being hidden.
''' </summary>
Public Sub ShowNormal()
ShowWindow(Handle, WindowShowStyle.ShowNormal)
End Sub
Public Sub Kill()
EndTask(Handle)
End Sub
Public Sub Hide()
ShowWindow(Handle, WindowShowStyle.Hide)
End Sub
Public Sub Restore()
ShowWindow(Handle, WindowShowStyle.Restore)
End Sub
Public Function HasExited() As Boolean
Return Not IsWindow(Handle)
End Function
End Structure
That basically holds the handle and several methods that can be applied to an open window.
Here is the Desktop class:
''' <summary>
''' Represents a desktop that controls a set of windows
''' </summary>
Public Class Desktop
''' <summary>
''' Creates a new desktop object
''' </summary>
''' <param name="Name">The name of the desktop</param>
Public Sub New(ByVal Name As String)
DesktopName = Name
End Sub
''' <summary>
''' Represents the windows displayed on the desktop
''' </summary>
Public Windows As New System.Collections.ObjectModel.Collection(Of Window)
''' <summary>
''' Represents the name of the desktop
''' </summary>
Public DesktopName As String
End Class
Not much there. All that does is hold a collection of windows and a name property.
Here is the code i am having trouble with
Ok, i had to show you that code so you wouldn't be lost when i showed you this. First, i am going to show you two classes. One is called VirtualDesktopManager. It basically holds a collection of desktops, properties that will return the current desktop, and methods to switch them. Next, i have a separate program called DeskSwitch.exe with a form called Switcher. It is what actually switches the desktop. Here's how they work together: The VirtualDesktopManager class, when called to switch between desktops, will create a file called Desktop.dat, in which it will write the handles and text of the windows that need to be shown on the new desktop. It then shells a program called DeskSwitcher.exe, and passes it the path to the dat file. When the DeskSwitch.exe runs, it will show it's form maximized, and fade the screen black via a timer (just to make it look better). After that is done, it will hide all the open windows, and open the dat file and show all the windows specified in that file. It will then fade transparent again via another timer, delete the dat file, and close. I know my problem is in one of these classes, i just have no idea which one.
First, here is the code for the VirtualDesktopManager class:
Imports VDesk.Methods
Public Class VirtualDesktopManager
Public Sub New()
curdeskind = 0
UpdateActiveWindowList()
End Sub
Public Sub New(ByVal Desks As Collections.ObjectModel.Collection(Of Desktop))
Desktops = Desks
curdeskind = 0
UpdateActiveWindowList()
End Sub
Private ActiveWindows As New System.Collections.ObjectModel.Collection(Of Window)
''' <summary>
''' Represents the collection of dekstops handled by this manager
''' </summary>
''' <remarks></remarks>
Public Desktops As New System.Collections.ObjectModel.Collection(Of Desktop)
'This is the current desktop name
Public ReadOnly Property CurrentDesktopName() As String
Get
Return curdesk.DesktopName
End Get
End Property
' This is the current desktop index
Public ReadOnly Property CurrentDesktopIndex() As Integer
Get
Return curdeskind
End Get
End Property
' This is the current desktop
Public ReadOnly Property CurrentDesktop() As Desktop
Get
Return curdesk
End Get
End Property
Private curdesk As Desktop
Private curdeskind As Integer
Private Sub UpdateActiveWindowList()
ActiveWindows.Clear()
EnumWindows(AddressOf Enumer, 0)
End Sub
Private Function Enumer(ByVal hwnd As IntPtr, ByVal lParam As Integer) As Boolean
If IsWindowVisible(hwnd) And Not GetWindowText(hwnd) = "" And Not GetWindowText(hwnd) = "Program Manager" Then
ActiveWindows.Add(New Window(hwnd))
End If
Return True
End Function
Public tdir As String 'Represents the current directory
Public Sub SwitchDesk(ByVal Index As Integer)
If Desktops.Count - 1 > Index Then Throw New ArgumentOutOfRangeException( _
"Index was out of the bounds of the Desktops collection")
SaveCurrentDesktopLayout()
FileOpen(1, tdir & "\Desktop.dat", OpenMode.Output)
For Each win As Window In Desktops(Index).Windows
WriteLine(1, win.Handle.ToInt32)
WriteLine(1, win.Text.ToCharArray())
Next
FileClose(1)
curdeskind = Index
curdesk = Desktops(Index)
Shell(Chr(34) & tdir & "\DeskSwitch.exe" & Chr(34) & " " & Chr(34) & tdir & "\Desktop.dat" & Chr(34))
End Sub
''' <summary>
''' Saves the current layout of the desktop to the active desktop object. This method is called
''' automatically every time the SwitchDesk() method is called.
''' </summary>
''' <remarks></remarks>
Public Sub SaveCurrentDesktopLayout()
UpdateActiveWindowList()
Desktops(curdeskind).Windows = ActiveWindows
End Sub
Public Sub SwitchDesk(ByVal Destination As Desktop)
If Not Desktops.Contains(Destination) Then Throw New ArgumentException( _
"The requested desktop is not contained in the Desktops collection")
SaveCurrentDesktopLayout()
FileOpen(1, tdir & "\Desktop.dat", OpenMode.Output)
For Each win As Window In Destination.Windows
WriteLine(1, win.Handle)
WriteLine(1, win.Text.ToCharArray())
Next
FileClose(1)
curdeskind = Desktops.IndexOf(Destination)
curdesk = Destination
Shell(Chr(34) & tdir & "\DeskSwitch.exe" & Chr(34) & " " & Chr(34) & tdir & "\Desktop.dat" & Chr(34))
End Sub
Public Sub SwitchDesk(ByVal DestinationName As String)
Dim ind As Integer
For Each d As Desktop In Desktops
If d.DesktopName = DestinationName Then
ind = Desktops.IndexOf(d)
GoTo switch
End If
Next
Throw New ArgumentException( _
"No desktop in the desktop collection has a name with the one you specified")
switch:
SaveCurrentDesktopLayout()
FileOpen(1, tdir & "\Desktop.dat", OpenMode.Output)
For Each win As Window In Desktops(ind).Windows
WriteLine(1, win.Handle.ToInt32)
WriteLine(1, win.Text.ToCharArray())
Next
FileClose(1)
curdeskind = ind
curdesk = Desktops(ind)
Shell(Chr(34) & tdir & "\DeskSwitch.exe" & Chr(34) & " " & Chr(34) & tdir & "\Desktop.dat" & Chr(34))
End Sub
End Class
And here is the code for the Switcher form:
Imports VDesk
Imports VDesk.Methods
Public Class Switcher
Private ActiveWindows As New System.Collections.ObjectModel.Collection(Of Window)
Private Sub HideScreen_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles HideScreen.Tick
Me.Opacity += 0.1
If Me.Opacity = 1 Then
HideScreen.Enabled = False
switch()
End If
End Sub
Private Sub ShowScreen_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ShowScreen.Tick
Me.Opacity -= 0.1
If Me.Opacity = 0 Then
ShowScreen.Enabled = False
Application.Exit()
End If
End Sub
Public Sub UpdateActiveWindowList()
ActiveWindows.Clear()
EnumWindows(AddressOf Enumer, 0)
End Sub
Function Enumer(ByVal hwnd As IntPtr, ByVal lParam As Integer) As Boolean
If IsWindowVisible(hwnd) And Not GetWindowText(hwnd) = "" And Not GetWindowText(hwnd) = "Program Manager" Then
ActiveWindows.Add(New Window(hwnd))
End If
Return True
End Function
<Runtime.InteropServices.DllImport("user32.dll")> _
Shared Function SetForegroundWindow(ByVal hwnd As IntPtr) As Long
End Function
Dim desk As Integer = 1
Private Sub switch()
UpdateActiveWindowList()
SetForegroundWindow(Process.GetProcessesByName("explorer")(0).MainWindowHandle)
For Each win As Window In ActiveWindows
My.Computer.Audio.Play(My.Computer.FileSystem.CurrentDirectory & "\Sounds\Notify.wav", AudioPlayMode.WaitToComplete)
win.Hide()
Next
Dim wins As New Collections.ObjectModel.Collection(Of InactiveWindow)
FileOpen(1, Args.arg, OpenMode.Input)
Do Until EOF(1)
Dim h As IntPtr = LineInput(1)
Dim t As String = LineInput(1)
Dim w As New InactiveWindow(h, t)
w.Handle = h
w.Text = t
wins.Add(w)
My.Computer.Audio.Play(My.Computer.FileSystem.CurrentDirectory & "\Sounds\Notify.wav", AudioPlayMode.WaitToComplete)
Loop
For Each win As InactiveWindow In wins
win.Show()
My.Computer.Audio.Play(My.Computer.FileSystem.CurrentDirectory & "\Sounds\Notify.wav", AudioPlayMode.WaitToComplete)
Next
FileClose(1)
IO.File.Delete(Args.arg)
ShowScreen.Enabled = True
End Sub
Private Sub VirtualDesktopManager_Shown(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Shown
HideScreen.Enabled = True
End Sub
End Class
If you have even read this far, i give you high marks for even taking the time to do that. If you have done something like this before, i would love to know how you did it, or any suggestions you have for me. Also note there may of been some unused code in my project. I have changed it up so many times it may have gotten a bit unorganized.
The problem is: like i said, i am testing this with 2 desktops. When the program starts, it saves the layout of the screen into the first desktop. When i tell it to switch to the second, it does that fine. The desktop is blank, like it should be because i havn't opened any windows on it. But, when i switch back to the first, none of the windows i had open there are visible either! After that, it screws up in so many ways i can't even keep track of them.
This post has been edited by jacobjordan: 10 July 2008 - 12:29 PM

New Topic/Question
Reply




MultiQuote





|