如何从 Visual Studio 应用打开文件资源管理器 window 并设置位置和大小?
How can I open a File Explorer window from a Visual Studio app and set the position and size?
我有一个 VB.net 应用程序可以压缩 JPG 文件、重命名它们并将它们从一个位置复制到另一个位置。当最终用户使用该程序时,他们将打开两个文件资源管理器 windows 以获取源位置和目标位置并将它们拖到文本框中。
我添加了打开两个文件资源管理器以设置位置的代码,但我希望一个 windows 位于屏幕的左下方,另一个位于屏幕的右下方。每个尺寸都将占据屏幕的 1/4。
我发现的大部分内容都非常古老。我发现有人说这是不可能的,还有一些人提供了非常旧的代码,这些代码似乎不太适合 Visual Studio 2019。
Private Sub btnOpenExplorer_Click(sender As Object, e As EventArgs) Handles btnOpenExplorer.Click
Process.Start("explorer.exe", String.Format("/n, /e, {0}", "C:\Users\" & Environment.UserName & "\Box\Site Visit Photos"))
Process.Start("explorer.exe", String.Format("/n, /e, {0}", "P:\"))
End Sub
以上代码运行良好。我只需要添加大小和定位。
您可以在 user32.dll
中使用 MoveWindow()
。
window句柄可以通过proc.MainWindowHandle
得到,其中proc
是Process.Start()
返回的进程。
此外,这对我来说效果很好:
https://www.codeproject.com/Tips/1057230/Windows-Resize-and-Move
解决方案 1
问题
我认为很难在调用例程中执行此操作 btnOpenExplorer_Click
,因为获取已分配所有属性的进程对象还为时过早。大多数情况下,ProcessMainWindowTitle and the Process.MainWindowHandle properties which are needed to solve this problem. A workaround to do this is to make the caller starts the processes and a Timer to do the positioning and resizing by the SetWindowPos 函数。
这是我的做法:
API 函数
<DllImport("user32.dll", EntryPoint:="SetWindowPos")>
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 UInteger) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
<DllImport("user32.dll")>
Private Shared Function IsIconic(hWnd As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
<DllImport("user32.dll")>
Public Shared Function ShowWindow(hWnd As IntPtr, <MarshalAs(UnmanagedType.I4)> nCmdShow As Integer) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
Class 水平常量和变量
Private Const HWND_TOP As Integer = &H0
Private Const SW_SHOWNORMAL As Integer = &H1
Private dir1, dir2 As String
Private WithEvents Timer1 As New Timer With {.Interval = 250}
进程查找器
Private Function GetExplorerProcess(title As String) As Process
Dim dirName As String = If(IO.Directory.Exists(title), New IO.DirectoryInfo(title).Name, title).ToLower
Return Process.GetProcesses.Where(
Function(a) a.ProcessName.ToLower.Equals("explorer") AndAlso
a.MainWindowTitle.ToLower.Equals(dirName)
).FirstOrDefault
End Function
来电者
Private Sub btnOpenExplorer_Click(sender As Object, e As EventArgs) Handles btnOpenExplorer.Click
Dim proc1 As Process = GetExplorerProcess(dir1)
If proc1 Is Nothing Then
Dim procInfo1 As New ProcessStartInfo With {
.FileName = "explorer.exe",
.Arguments = dir1,
.WindowStyle = ProcessWindowStyle.Normal
}
Process.Start(procInfo1)
End If
Dim proc2 As Process = GetExplorerProcess(dir2)
If proc2 Is Nothing Then
Dim procInfo2 As New ProcessStartInfo With {
.FileName = "explorer.exe",
.Arguments = dir2,
.WindowStyle = ProcessWindowStyle.Normal
}
Process.Start(procInfo2)
End If
Timer1.Start()
End Sub
计时器 - 激活 Windows,设置大小和位置
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
Dim proc1 As Process = GetExplorerProcess(dir1)
Dim proc2 As Process = GetExplorerProcess(dir2)
If proc1 IsNot Nothing AndAlso proc2 IsNot Nothing Then
Timer1.Stop()
Dim R As Rectangle = Screen.PrimaryScreen.WorkingArea
Dim R1 As New Rectangle(R.X, R.Height - (R.Height / 3), R.Width / 2, R.Height / 4)
Dim R2 As New Rectangle(R1.Right, R1.Y, R1.Width, R1.Height)
Dim hWnd1 As IntPtr = proc1.MainWindowHandle
Dim hWnd2 As IntPtr = proc2.MainWindowHandle
'Restore the first window if its minimized.
If IsIconic(hWnd1) Then
ShowWindow(hWnd1, SW_SHOWNORMAL)
End If
'Set the size and location of the first window.
SetWindowPos(hWnd1, IntPtr.op_Explicit(HWND_TOP), R1.X, R1.Y, R1.Width, R1.Height, 0)
'Restore the second window if its minimized.
If IsIconic(hWnd2) Then
ShowWindow(hWnd2, SW_SHOWNORMAL)
End If
'Set the size and location of the second window.
SetWindowPos(hWnd2, IntPtr.op_Explicit(HWND_TOP), R2.X, R2.Y, R2.Width, R2.Height, 0)
End If
End Sub
解决方案 2
到处谷歌搜索后,我想出了一个更好的方法(我认为)通过使用 Microsoft Internet Controls - SHDocVw 组件。
首先,我们需要添加对该 COM 组件的引用:
- 在您的项目浏览器中,右键单击
References
节点和 select Add Reference
。
- 在参考管理器 Select 中的
COM
选项卡。
- 找到并检查
Microsoft Internet Controls
并点击确定。
我们只需要 solution1 APIs 和常量,以及一个获取 IE 的新函数 window:
Private Function GetIE(dir As String) As SHDocVw.InternetExplorer
Return (From ie In New SHDocVw.ShellWindows
Where New Uri(DirectCast(ie, SHDocVw.InternetExplorer).LocationURL).LocalPath.Equals(dir, StringComparison.OrdinalIgnoreCase)
Select DirectCast(ie, SHDocVw.InternetExplorer)).FirstOrDefault
End Function
最后,来电者:
Private Sub btnOpenExplorer_Click(sender As Object, e As EventArgs) Handles btnOpenExplorer.Click
Dim dir1 As String = "FirstPath"
Dim dir2 As String = "SecondPath"
Dim ie1, ie2 As SHDocVw.InternetExplorer
If Not IO.Path.GetPathRoot(dir1).Equals(dir1, StringComparison.OrdinalIgnoreCase) Then
dir1 = dir1.TrimEnd(IO.Path.DirectorySeparatorChar)
End If
If Not IO.Path.GetPathRoot(dir2).Equals(dir2, StringComparison.OrdinalIgnoreCase) Then
dir2 = dir2.TrimEnd(IO.Path.DirectorySeparatorChar)
End If
ie1 = GetIE(dir1)
ie2 = GetIE(dir2)
If ie1 Is Nothing OrElse ie2 Is Nothing Then
Process.Start(dir1)
Process.Start(dir2)
Threading.Thread.Sleep(1000)
End If
If ie1 Is Nothing Then ie1 = GetIE(dir1)
If ie2 Is Nothing Then ie2 = GetIE(dir2)
If ie1 IsNot Nothing AndAlso ie2 IsNot Nothing Then
Dim hWnd1 = IntPtr.op_Explicit(ie1.HWND)
Dim hWnd2 = IntPtr.op_Explicit(ie2.HWND)
Dim R As Rectangle = Screen.PrimaryScreen.WorkingArea
Dim R1 As New Rectangle(R.X, R.Height - (R.Height \ 3), R.Width \ 2, R.Height \ 4)
Dim R2 As New Rectangle(R1.Right, R1.Y, R1.Width, R1.Height)
SetWindowPos(hWnd1, IntPtr.op_Explicit(HWND_TOP), R2.X, R2.Y, R2.Width, R2.Height, 0)
SetWindowPos(hWnd2, IntPtr.op_Explicit(HWND_TOP), R1.X, R1.Y, R1.Width, R1.Height, 0)
If IsIconic(hWnd1) Then
ShowWindow(hWnd1, SW_SHOWNORMAL)
End If
If IsIconic(hWnd2) Then
ShowWindow(hWnd2, SW_SHOWNORMAL)
End If
End If
End Sub
请注意,此解决方案也适用于驱动器(即:c:\
、d:\
..等),而第一个则不行。
这是一个演示:
我有一个 VB.net 应用程序可以压缩 JPG 文件、重命名它们并将它们从一个位置复制到另一个位置。当最终用户使用该程序时,他们将打开两个文件资源管理器 windows 以获取源位置和目标位置并将它们拖到文本框中。
我添加了打开两个文件资源管理器以设置位置的代码,但我希望一个 windows 位于屏幕的左下方,另一个位于屏幕的右下方。每个尺寸都将占据屏幕的 1/4。
我发现的大部分内容都非常古老。我发现有人说这是不可能的,还有一些人提供了非常旧的代码,这些代码似乎不太适合 Visual Studio 2019。
Private Sub btnOpenExplorer_Click(sender As Object, e As EventArgs) Handles btnOpenExplorer.Click
Process.Start("explorer.exe", String.Format("/n, /e, {0}", "C:\Users\" & Environment.UserName & "\Box\Site Visit Photos"))
Process.Start("explorer.exe", String.Format("/n, /e, {0}", "P:\"))
End Sub
以上代码运行良好。我只需要添加大小和定位。
您可以在 user32.dll
中使用 MoveWindow()
。
window句柄可以通过proc.MainWindowHandle
得到,其中proc
是Process.Start()
返回的进程。
此外,这对我来说效果很好: https://www.codeproject.com/Tips/1057230/Windows-Resize-and-Move
解决方案 1
问题
我认为很难在调用例程中执行此操作 btnOpenExplorer_Click
,因为获取已分配所有属性的进程对象还为时过早。大多数情况下,ProcessMainWindowTitle and the Process.MainWindowHandle properties which are needed to solve this problem. A workaround to do this is to make the caller starts the processes and a Timer to do the positioning and resizing by the SetWindowPos 函数。
这是我的做法:
API 函数
<DllImport("user32.dll", EntryPoint:="SetWindowPos")>
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 UInteger) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
<DllImport("user32.dll")>
Private Shared Function IsIconic(hWnd As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
<DllImport("user32.dll")>
Public Shared Function ShowWindow(hWnd As IntPtr, <MarshalAs(UnmanagedType.I4)> nCmdShow As Integer) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
Class 水平常量和变量
Private Const HWND_TOP As Integer = &H0
Private Const SW_SHOWNORMAL As Integer = &H1
Private dir1, dir2 As String
Private WithEvents Timer1 As New Timer With {.Interval = 250}
进程查找器
Private Function GetExplorerProcess(title As String) As Process
Dim dirName As String = If(IO.Directory.Exists(title), New IO.DirectoryInfo(title).Name, title).ToLower
Return Process.GetProcesses.Where(
Function(a) a.ProcessName.ToLower.Equals("explorer") AndAlso
a.MainWindowTitle.ToLower.Equals(dirName)
).FirstOrDefault
End Function
来电者
Private Sub btnOpenExplorer_Click(sender As Object, e As EventArgs) Handles btnOpenExplorer.Click
Dim proc1 As Process = GetExplorerProcess(dir1)
If proc1 Is Nothing Then
Dim procInfo1 As New ProcessStartInfo With {
.FileName = "explorer.exe",
.Arguments = dir1,
.WindowStyle = ProcessWindowStyle.Normal
}
Process.Start(procInfo1)
End If
Dim proc2 As Process = GetExplorerProcess(dir2)
If proc2 Is Nothing Then
Dim procInfo2 As New ProcessStartInfo With {
.FileName = "explorer.exe",
.Arguments = dir2,
.WindowStyle = ProcessWindowStyle.Normal
}
Process.Start(procInfo2)
End If
Timer1.Start()
End Sub
计时器 - 激活 Windows,设置大小和位置
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
Dim proc1 As Process = GetExplorerProcess(dir1)
Dim proc2 As Process = GetExplorerProcess(dir2)
If proc1 IsNot Nothing AndAlso proc2 IsNot Nothing Then
Timer1.Stop()
Dim R As Rectangle = Screen.PrimaryScreen.WorkingArea
Dim R1 As New Rectangle(R.X, R.Height - (R.Height / 3), R.Width / 2, R.Height / 4)
Dim R2 As New Rectangle(R1.Right, R1.Y, R1.Width, R1.Height)
Dim hWnd1 As IntPtr = proc1.MainWindowHandle
Dim hWnd2 As IntPtr = proc2.MainWindowHandle
'Restore the first window if its minimized.
If IsIconic(hWnd1) Then
ShowWindow(hWnd1, SW_SHOWNORMAL)
End If
'Set the size and location of the first window.
SetWindowPos(hWnd1, IntPtr.op_Explicit(HWND_TOP), R1.X, R1.Y, R1.Width, R1.Height, 0)
'Restore the second window if its minimized.
If IsIconic(hWnd2) Then
ShowWindow(hWnd2, SW_SHOWNORMAL)
End If
'Set the size and location of the second window.
SetWindowPos(hWnd2, IntPtr.op_Explicit(HWND_TOP), R2.X, R2.Y, R2.Width, R2.Height, 0)
End If
End Sub
解决方案 2
到处谷歌搜索后,我想出了一个更好的方法(我认为)通过使用 Microsoft Internet Controls - SHDocVw 组件。
首先,我们需要添加对该 COM 组件的引用:
- 在您的项目浏览器中,右键单击
References
节点和 selectAdd Reference
。 - 在参考管理器 Select 中的
COM
选项卡。 - 找到并检查
Microsoft Internet Controls
并点击确定。
我们只需要 solution1 APIs 和常量,以及一个获取 IE 的新函数 window:
Private Function GetIE(dir As String) As SHDocVw.InternetExplorer
Return (From ie In New SHDocVw.ShellWindows
Where New Uri(DirectCast(ie, SHDocVw.InternetExplorer).LocationURL).LocalPath.Equals(dir, StringComparison.OrdinalIgnoreCase)
Select DirectCast(ie, SHDocVw.InternetExplorer)).FirstOrDefault
End Function
最后,来电者:
Private Sub btnOpenExplorer_Click(sender As Object, e As EventArgs) Handles btnOpenExplorer.Click
Dim dir1 As String = "FirstPath"
Dim dir2 As String = "SecondPath"
Dim ie1, ie2 As SHDocVw.InternetExplorer
If Not IO.Path.GetPathRoot(dir1).Equals(dir1, StringComparison.OrdinalIgnoreCase) Then
dir1 = dir1.TrimEnd(IO.Path.DirectorySeparatorChar)
End If
If Not IO.Path.GetPathRoot(dir2).Equals(dir2, StringComparison.OrdinalIgnoreCase) Then
dir2 = dir2.TrimEnd(IO.Path.DirectorySeparatorChar)
End If
ie1 = GetIE(dir1)
ie2 = GetIE(dir2)
If ie1 Is Nothing OrElse ie2 Is Nothing Then
Process.Start(dir1)
Process.Start(dir2)
Threading.Thread.Sleep(1000)
End If
If ie1 Is Nothing Then ie1 = GetIE(dir1)
If ie2 Is Nothing Then ie2 = GetIE(dir2)
If ie1 IsNot Nothing AndAlso ie2 IsNot Nothing Then
Dim hWnd1 = IntPtr.op_Explicit(ie1.HWND)
Dim hWnd2 = IntPtr.op_Explicit(ie2.HWND)
Dim R As Rectangle = Screen.PrimaryScreen.WorkingArea
Dim R1 As New Rectangle(R.X, R.Height - (R.Height \ 3), R.Width \ 2, R.Height \ 4)
Dim R2 As New Rectangle(R1.Right, R1.Y, R1.Width, R1.Height)
SetWindowPos(hWnd1, IntPtr.op_Explicit(HWND_TOP), R2.X, R2.Y, R2.Width, R2.Height, 0)
SetWindowPos(hWnd2, IntPtr.op_Explicit(HWND_TOP), R1.X, R1.Y, R1.Width, R1.Height, 0)
If IsIconic(hWnd1) Then
ShowWindow(hWnd1, SW_SHOWNORMAL)
End If
If IsIconic(hWnd2) Then
ShowWindow(hWnd2, SW_SHOWNORMAL)
End If
End If
End Sub
请注意,此解决方案也适用于驱动器(即:c:\
、d:\
..等),而第一个则不行。
这是一个演示: