简体   繁体   English

如何从 Visual Studio 应用程序打开文件资源管理器 window 并设置 position 和大小?

[英]How can I open a File Explorer window from a Visual Studio app and set the position and size?

I have a VB.net application that compacts JPG files, renames them, and copies them from one location to another.我有一个 VB.net 应用程序,它可以压缩 JPG 文件、重命名它们并将它们从一个位置复制到另一个位置。 When the end-user uses the program, they'll open two file explorer windows to get the source and destination locations and drag them onto the text boxes.当最终用户使用该程序时,他们将打开两个文件浏览器 windows 以获取源和目标位置并将它们拖到文本框上。

I have added code that opens two file explorers to set locations, but I would like one windows to be in the lower left size of the screen and the other to be in the lower right.我添加了打开两个文件资源管理器以设置位置的代码,但我希望一个 windows 位于屏幕的左下方,另一个位于屏幕的右下方。 Each would be sized to take up 1/4 of the screen.每个都将占据屏幕的 1/4。

Most of what I have found is very old.我发现的大部分东西都很古老。 I've found people who said it can't be done and others who provide very old code that doesn't seem to play nice with Visual Studio 2019.我发现有人说无法完成,其他人提供的代码非常陈旧,似乎无法与 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

The above code works well.上面的代码运行良好。 I just need to add sizing and positioning.我只需要添加尺寸和定位。

You can use MoveWindow() in user32.dll .您可以在user32.dll中使用MoveWindow() The window handle can be obtained by proc.MainWindowHandle where proc is the process returned by Process.Start() . window 句柄可以通过proc.MainWindowHandle获得,其中procProcess.Start()返回的进程。

Additionaly this works well for me: https://www.codeproject.com/Tips/1057230/Windows-Resize-and-Move另外这对我很有效: https://www.codeproject.com/Tips/1057230/Windows-Resize-and-Move

Solution 1解决方案 1

The Problem问题

I think it's difficult to do it in the caller routine btnOpenExplorer_Click since it will be too early to get a process object with all of its properties assigned.我认为在调用程序btnOpenExplorer_Click中很难做到这一点,因为现在获得一个分配了所有属性的进程 object 还为时过早。 Mostly, the ProcessMainWindowTitle and the Process.MainWindowHandle properties which are needed to solve this problem.大多数情况下,解决此问题所需的ProcessMainWindowTitleProcess.MainWindowHandle属性。 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 function.一个解决方法是让调用者启动进程和一个计时器来通过SetWindowPos function 进行定位和调整大小。

Here's how I'd do it:这是我的做法:

The API Functions 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 Level Constants & Variables 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}

Process Finder进程查找器

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

The Caller呼叫者,召集者

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

The Timer - Activate the Windows, Set Both Size & Location计时器 - 激活 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

Solution 2解决方案 2

After some googling here and there, I figured out a better approach (I think) through using the Microsoft Internet Controls - SHDocVw component.在到处搜索之后,我通过使用Microsoft Internet Controls - SHDocVw 组件找到了一种更好的方法(我认为)。

First, we need to add a reference to that COM component:首先,我们需要添加对 COM 组件的引用:

  • In your project browser, right-click on the References node and select Add Reference .在您的项目浏览器中,右键单击References节点和 select Add Reference
  • In the Reference Manager Select the COM tab.在参考管理器 Select 中的COM选项卡。
  • Find and check the Microsoft Internet Controls and hit OK.查找并检查Microsoft Internet Controls ,然后单击确定。

We need from solution1 the APIs and the constants only, and a new function to get the IE window:我们只需要解决方案1 中的 API 和常量,以及一个新的 function 来获取 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

And finally, the caller:最后,调用者:

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

Please note, this solution works also with drives (IE: c:\ , d:\ ..etc.) while the first one doesn't.请注意,此解决方案也适用于驱动器(即: c:\ , d:\ ..etc.),而第一个不适用。

Here's a demo:这是一个演示:

IEDemo

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何让 visual studio 记住 .net 控制台应用程序的 window position 和大小,每次调试或操作 session - how to get visual studio to remember .net console app's window position and size, each debug or operation session 如何在Visual Studio(2013)中打开.vb文件路径 - How do I open .vb file path in Visual Studio (2013) 如何将特定文件的资源管理器窗口设置为TopMost窗体的子窗口? - How to set the Explorer window of a specific file as a child window of TopMost form? 如何在文件资源管理器中使用 Open With function 在我的应用程序中打开文本文件? - How can I use the Open With function in File explorer to open a text file in my application? 如何在Visual Studio中将输出值设置为2个小数位? - How can I set an output value to 2 decimal places in Visual Studio? 如何打开 windows 资源管理器 window 并选择特定文件夹 - How do I open a windows explorer window with a specific folder selected 如何调试Visual Studio 2013中引用的DLL文件? - How can I debug a referenced DLL file from Visual Studio 2013? 如何在Compact Framework 3.5 / Visual Studio 2008中的属性窗口中隐藏属性? - How do I hide a property from the properties window in Compact Framework 3.5 / Visual Studio 2008? 如何从文件中的特定位置读取 - How can I read from a specific position in a file 如何在Visual Studio中为自定义控件设置要编辑的默认事件? - How can I set the default event to be edited for my custom control in Visual Studio?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM