如何通过代码设置另存为对话框的目录?

如何解决如何通过代码设置另存为对话框的目录?

基本上我已经编写了一些代码来监听“另存为”对话框在应用程序中弹出,当它弹出时,它按下“保存”,所有这些都是通过代码完成的。这很好用,但是我需要能够在保存之前将文件路径设置为我想要的。

这是我目前的代码

False

我一直在使用 findwindowex 和 SendMessage 来控制窗口句柄。这对于 Save 按钮非常有效,但现在我正在尝试访问窗口的工具栏部分并将其文本设置为所需的目录。我什至不确定这种方法是否有效,但它似乎是最简单的。我附上了一个截图以供参考(红色圈出的区域是我在“按”保存之前尝试访问并更改为给定文件路径的句柄)

Image

如照片所示,我一直在使用 Spy++ 来获取有关 Window 及其句柄的信息。例如,如果我尝试这样做以获取指向该句柄的指针:

using System;
using System.Diagnostics;
using System.ComponentModel;
using System.Collections.Generic;



using System.Runtime.InteropServices;
using HWND = system.intPtr;
using System.Text;

/// <summary>Contains functionality to get all the open windows.</summary>
public static class OpenWindowGetter
{
    private const int BN_CLICKED = 245;
    /// <summary>Returns a dictionary that contains the handle and title of all the open windows.</summary>
    /// <returns>A dictionary that contains the handle and title of all the open windows.</returns>
    public static IDictionary<HWND,string> GetopenWindows()
    {

        HWND shellWindow = GetShellWindow();
        Dictionary<HWND,string> windows = new Dictionary<HWND,string>();

        EnumWindows(delegate (HWND hWnd,int lParam)
        {

            if (hWnd == shellWindow) return true;
            if (!IsWindowVisible(hWnd)) return true;

            int length = GetwindowTextLength(hWnd);
            if (length == 0) return true;

            StringBuilder builder = new StringBuilder(length);
            GetwindowText(hWnd,builder,length + 1);


            if (builder.ToString() == "Export Selection") //Check for the export selection window
            {
                //Press the "save" button through code here
                IntPtr hwndChild = findwindowex((IntPtr)hWnd,IntPtr.Zero,"Button","&Save");
                SendMessage((HWND)(int)hwndChild,BN_CLICKED,(HWND)0,IntPtr.Zero);
            }


            windows[hWnd] = builder.ToString();
            return true;

        },0);

        return windows;
    }

    private delegate bool EnumWindowsProc(HWND hWnd,int lParam);


    [DllImport("USER32.DLL")]
    private static extern int SetwindowText(HWND hWnd,String lpString);

    [DllImport("USER32.DLL")]
    private static extern bool EnumWindows(EnumWindowsProc enumFunc,int lParam);

    [DllImport("USER32.DLL")]
    private static extern int GetwindowText(HWND hWnd,StringBuilder lpString,int nMaxCount);

    [DllImport("USER32.DLL")]
    private static extern int GetwindowTextLength(HWND hWnd);

    [DllImport("USER32.DLL")]
    private static extern bool IsWindowVisible(HWND hWnd);

    [DllImport("USER32.DLL")]
    private static extern IntPtr GetShellWindow();

    [DllImport("user32.dll",SetLastError = true,CharSet = CharSet.Auto)]
    public static extern IntPtr findwindowex(IntPtr parentHandle,IntPtr childAfter,string lclassName,string windowTitle);

    [DllImport("User32.dll")]
    public static extern Int32 SendMessage(IntPtr hWnd,uint Msg,IntPtr wParam,IntPtr lParam);
}



namespace ConsoleApp1
{
    class Program
    {
       
        static void Main(string[] args)
        {
            while (true)
            {


                foreach (keyvaluePair<IntPtr,string> window in OpenWindowGetter.GetopenWindows())
                {
                    IntPtr handle = window.Key;
                    string title = window.Value;

                    //Console.WriteLine("{0}: {1}",handle,title);
                }

            }
        }
    }
}


它不起作用。在 Spy++ 应用程序中看到的“Caption”值更改为当前目录名称的任何内容,因此尝试访问它似乎没有意义。

下一行代码确实给了我一个返回指针,但它不是正确的地址。值得注意的是,此窗口上有多个句柄属于 ToolbarWindow32 类:

IntPtr hwndChildToolbar= findwindowex((IntPtr)hWnd,"ToolbarWindow32","Address: "+"C:\\Windows\\System32");

如果我能找到获得正确句柄的方法,那么从这里开始,如果可能的话,我只想使用 SetwindowText 并将其值设置为我想要的文件路径的字符串。

总而言之,我需要某种方式来轻松设置目录,我不确定这种方式是否可行。我的 C# 知识有限,所以任何事情都有帮助!

解决方法

这是一个示例 .NET Framework 控制台应用程序,它使用 UI 自动化、打开记事本、键入内容并将其保存为临时文件夹中的文件,使用通用对话框顶部的地址栏。

有关 UI 自动化的介绍和参考,请参阅此处 .NET UI Automation Overview 或此处 Native UI Automation。使用 UI 自动化通常比破解 Windows 句柄更好。如果您不能使用 UI 自动化来做到这一点,那么您可能无论如何也无法使用句柄来做到这一点。要发现您可以使用和编码的元素,您可以使用 Inspect tool from the Windows SDK

请注意,我在这里使用了本机 UI 自动化的 interop version,因为 Windows 提供的 .NET 原始包装器由于某种原因多年来没有由 Microsoft 更新。

// this code needs the "Interop.UIAutomationClient" Nuget package and "using Interop.UIAutomationClient"
class Program
{
    private static readonly CUIAutomation8 _automation = new CUIAutomation8();

    static void Main()
    {
        // track window open event
        var processId = 0;
        _automation.AddAutomationEventHandler(UIA_EventIds.UIA_Window_WindowOpenedEventId,_automation.GetRootElement(),TreeScope.TreeScope_Subtree,null,new AutomationEventHandler((window,id) =>
        {
            // check the process id we opened
            if (window.CurrentProcessId != processId)
                return;

            // get editor control
            var editor = window.FindFirst(TreeScope.TreeScope_Children,_automation.CreatePropertyCondition(UIA_PropertyIds.UIA_ControlTypePropertyId,UIA_ControlTypeIds.UIA_EditControlTypeId));
            if (editor == null) // not the window we're looking for
                return;

            // get editor's value pattern & set some text value
            var value = (IUIAutomationValuePattern)editor.GetCurrentPattern(UIA_PatternIds.UIA_ValuePatternId);
            value.SetValue("hello world");

            // get menu bar
            var menuBar = window.FindFirst(TreeScope.TreeScope_Children,UIA_ControlTypeIds.UIA_MenuBarControlTypeId));
            if (menuBar == null)
            {
                Console.WriteLine("Can't find menu bar.");
                return;
            }

            // get "File" menu item (beware of localization) & invoke (open)
            var file = menuBar.FindFirst(TreeScope.TreeScope_Children,_automation.CreatePropertyCondition(UIA_PropertyIds.UIA_NamePropertyId,"File"));
            if (file == null)
            {
                Console.WriteLine("Can't find 'File' menu item.");
                return;
            }

            // expand "File" menu
            var expand = (IUIAutomationExpandCollapsePattern)file.GetCurrentPattern(UIA_PatternIds.UIA_ExpandCollapsePatternId);
            expand.Expand();

            do
            {
                // get the "Save" item by name from the window subtree (as the menu that opens is a child of the window)
                // do some retry to handle menu opening time
                var save = window.FindFirst(TreeScope.TreeScope_Subtree,_automation.CreatePropertyConditionEx(UIA_PropertyIds.UIA_NamePropertyId,"Save",PropertyConditionFlags.PropertyConditionFlags_MatchSubstring));
                if (save != null)
                {
                    ((IUIAutomationInvokePattern)save.GetCurrentPattern(UIA_PatternIds.UIA_InvokePatternId)).Invoke();
                    break;
                }

            }
            while (true);

            // get the "Save As" dialog
            // do some retry to handle dialog opening time
            IUIAutomationElement dialog;
            do
            {
                dialog = window.FindFirst(TreeScope.TreeScope_Subtree,_automation.CreatePropertyCondition(UIA_PropertyIds.UIA_LocalizedControlTypePropertyId,"dialog"));
                if (dialog != null)
                    break;
            }
            while (true);

            // get the "Previous locations" to enable the Address edit box
            var previous = dialog.FindFirst(TreeScope.TreeScope_Subtree,_automation.CreateAndCondition(
                _automation.CreatePropertyCondition(UIA_PropertyIds.UIA_ControlTypePropertyId,UIA_ControlTypeIds.UIA_ButtonControlTypeId),"Previous Locations")));
            if (previous == null)
            {
                Console.WriteLine("Can't find 'Previous Locations' button.");
                return;
            }

            // push "Previous Locations" button
            var previousButton = (IUIAutomationInvokePattern)previous.GetCurrentPattern(UIA_PatternIds.UIA_InvokePatternId);
            previousButton.Invoke();

            // enter the directory path
            var address = dialog.FindFirst(TreeScope.TreeScope_Subtree,UIA_ControlTypeIds.UIA_EditControlTypeId),"Address")));
            if (address == null)
            {
                Console.WriteLine("Can't find 'Address' edit.");
                return;
            }

            // sets the directory (here we use the temp directory)
            var edit = (IUIAutomationValuePattern)address.GetCurrentPattern(UIA_PatternIds.UIA_ValuePatternId);
            edit.SetValue(System.IO.Path.GetTempPath());

            // push "Previous Locations" button again to "commit"
            previousButton.Invoke();

            // get the "File name:" edit
            // do some retry to handle folder refresh
            do
            {
                var fileName = dialog.FindFirst(TreeScope.TreeScope_Subtree,_automation.CreateAndCondition(
                    _automation.CreatePropertyCondition(UIA_PropertyIds.UIA_ControlTypePropertyId,"File name",PropertyConditionFlags.PropertyConditionFlags_MatchSubstring)));
                if (fileName != null)
                {
                    // sets the file name (some "random" name)
                    ((IUIAutomationValuePattern)fileName.GetCurrentPattern(UIA_PatternIds.UIA_ValuePatternId)).SetValue(@"hello" + Environment.TickCount + ".txt");
                    break;
                }
            }
            while (true);

            // get the "Save" button
            var dialogSave = dialog.FindFirst(TreeScope.TreeScope_Subtree,"Save")));
            if (dialogSave == null)
            {
                Console.WriteLine("Can't find 'Save' button.");
                return;
            }

            // press the 'Save' button
            ((IUIAutomationInvokePattern)dialogSave.GetCurrentPattern(UIA_PatternIds.UIA_InvokePatternId)).Invoke();
        }));

        // start notepad
        var process = Process.Start("notepad");
        processId = process.Id;

        Console.WriteLine("Press any key to quit...");
        Console.ReadKey(false);
        try
        {
            process.CloseMainWindow();
        }
        catch
        {
            // maybe closed by something else,do nothing
        }
    }

    // helper class
    class AutomationEventHandler : IUIAutomationEventHandler
    {
        public AutomationEventHandler(Action<IUIAutomationElement,int> action)
        {
            if (action == null)
                throw new ArgumentNullException(nameof(action));

            Action = action;
        }

        public Action<IUIAutomationElement,int> Action { get; }
        public void HandleAutomationEvent(IUIAutomationElement sender,int eventId) => Action(sender,eventId);
    }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?