查看: 38|回覆: 0

C# 调用 Win10/11 文件关联对话框

[複製鏈接]

4

主題

0

回帖

0

積分

热心网友

金币
0
閲讀權限
220
精華
0
威望
0
贡献
0
在線時間
0 小時
註冊時間
2012-3-26
發表於 2025-4-2 15:32:00 | 顯示全部樓層 |閲讀模式

方法一:调用未公开接口 IOpenWithLauncher

Adobe Acrobat 应该是调用的未公开接口方法
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("6A283FE2-ECFA-4599-91C4-E80957137B26")]
interface IOpenWithLauncher
{
    [PreserveSig]
    int Launch(IntPtr hWndParent,
         [MarshalAs(UnmanagedType.LPWStr)] string lpszPath,
         IMMERSIVE_OPENWITH flags);
}

[Flags]
enum IMMERSIVE_OPENWITH
{
    NONE = 0,
    OVERRIDE = 0x1,
    DONOT_EXEC = 0x4,
    PROTOCOL = 0x8,
    URL = 0x10,
    USEPOSITION = 0x20,
    DONOT_SETDEFAULT = 0x40,
    ACTION = 0x80,
    ALLOW_EXECDEFAULT = 0x100,
    NONEDP_TO_EDP = 0x200,
    EDP_TO_NONEDP = 0x400,
    CALLING_IN_APP = 0x800,
};

public static void ShowSetAssocDialog(string extension)
{
    var CLSID_ExecuteUnknown = new Guid("{E44E9428-BDBC-4987-A099-40DC8FD255E7}");
    var obj = Activator.CreateInstance(Type.GetTypeFromCLSID(CLSID_ExecuteUnknown));
    if (obj is IOpenWithLauncher launcher)
    {
        launcher.Launch(IntPtr.Zero, extension, IMMERSIVE_OPENWITH.DONOT_EXEC);
        Marshal.ReleaseComObject(launcher);
    }
}

方法二:通过模拟点击属性对话框“更改”打开方式

此方法来自两年前我的自问自答,代码引用了 《C# 窗口过程消息处理 WndProc》 中的附加到其他窗口辅助类

Bandizip 使用的这种方法
[DllImport("shell32.dll", CharSet = CharSet.Auto)]
static extern bool SHObjectProperties(IntPtr hWnd, SHOP shopObjectType, string pszObjectName, string pszPropertyPage);

enum SHOP
{
    PRINTERNAME = 1,
    FILEPATH = 2,
    VOLUMEGUID = 4
}

[DllImport("kernel32.dll")]
static extern int GetCurrentProcessId();

[DllImport("user32.dll")]
static extern int GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);

[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);

[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);

[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);

[DllImport("user32.dll")]
static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);

delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);

public static void ShowSetAssocDialog(string extension)
{
    string fileName = Path.ChangeExtension(Path.GetRandomFileName(), extension);
    string filePath = Path.Combine(Path.GetTempPath(), fileName);
    fileName = Path.GetFileNameWithoutExtension(fileName);
    File.WriteAllText(filePath, string.Empty); // 创建临时文件
    var frame = new DispatcherFrame();
    int pid = GetCurrentProcessId();
    SHObjectProperties(IntPtr.Zero, SHOP.FILEPATH, filePath, null); // 显示属性对话框
    while (true)
    {
        bool found = !EnumWindows((hWnd, lParam) => // 枚举窗口
        {
            GetWindowThreadProcessId(hWnd, out int id);
            if (id == pid) // 比较进程 id
            {
                const int MAX_PATH = 260;
                var sb = new StringBuilder(MAX_PATH);
                GetClassName(hWnd, sb, sb.Capacity);
                if (sb.ToString() == "#32770") // 对话框类名
                {
                    GetWindowText(hWnd, sb, sb.Capacity);
                    if (sb.ToString().Contains(fileName)) // 对话框标题是否包含文件名
                    {
                        SetWindowPos(hWnd, IntPtr.Zero, 0, 0, 0, 0, SWP.HIDEWINDOW); // 隐藏属性对话框
                        MessageHooker.AddHook(hWnd, (ref Message m) =>
                        {
                            const int PSM_CHANGED = 0x400 + 104;
                            if (m.Msg == PSM_CHANGED) // 监测属性表页更改
                            {
                                frame.Continue = false;
                                PostMessage(hWnd, WM.CLOSE, 0, 0); // 等效 EndDialog(hWnd, 0)
                            }
                            return false;
                        });
                        SetForegroundWindow(hWnd);
                        SendKeys.SendWait("%C"); // ALT + C 快捷键
                        return false;
                    }
                }
            }
            return true;
        }, IntPtr.Zero);
        if (found) break;
    }
    File.Delete(filePath); // 删除临时文件
    Dispatcher.PushFrame(frame);
}

相关资料

Redirecting Open With in Properties Dialog in Windows 10

How to call the "Open With" dialog used to associate file formats in Windows 10 or 11?



来源:https://www.cnblogs.com/BluePointLilac/p/18806046
回覆

使用道具 舉報

您需要登錄後才可以回帖 登錄 | 立即注册

本版積分規則

相关侵权、举报、投诉及建议等,请发 E-mail:qiongdian@foxmail.com

Powered by Discuz! X5.0 © 2001-2026 Discuz! Team.

在本版发帖返回顶部