cad.net 实现不重复打开文件夹
原因
实现不重复地打开dwg文件的所在目录的资源管理器,也就是打开文件夹,并设置焦点.
c++
看这里: https://www.cnblogs.com/shankun/p/4088860.html
c#
这里地址的方法也是可用的,但是net3.5不能使用
方法有两个,两者有点差别,可以配合用.
例子一:
枚举桌面资源管理器,关闭相同的.var wins = new ShellWindows();
然后用Process.Start 开启并设置焦点.
例子二:
用 Shell32.ShowFileInExplorer(filename3);
它可以直接设置一个文件夹和焦点,
如果是我自己开的同路径文件夹,它的表现是自己开一个新的.
但是我用它开的,然后换了焦点,它则不开新的,而是重设焦点了.
就好像有个缓存,它不是在全屏幕检索的,是在它第一次开了的文件夹上面检索的.
命令
#if !HC2020
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.DatabaseServices;
using Acap = Autodesk.AutoCAD.ApplicationServices.Application;
#else
using GrxCAD.DatabaseServices;
using GrxCAD.EditorInput;
using GrxCAD.ApplicationServices;
using GrxCAD.Runtime;
using Acap = GrxCAD.ApplicationServices.Application;
#endif
using System.Diagnostics;
using System.Runtime.InteropServices;
using System;
using System.IO;
using Win32API;
namespace JoinBox
{
public static class Command_jjOpenFilePath
{
/// <summary>
/// 不重复打开dwg路径的资源管理器
/// </summary>
[CommandMethod("JJ_OpenDwgFilePath")]
public static void JJ_OpenDwgFilePath()
{
Database db = HostApplicationServices.WorkingDatabase;//当前的数据库
Editor ed = Acap.DocumentManager.MdiActiveDocument.Editor;
ed.WriteMessage(Environment.NewLine + "****惊惊连盒-打开当前Dwg的目录");
try
{
var filename3 = db.GetDwgFullPath();
if (filename3 == null)
{
return;
}
if (filename3 == "")
{
ed.WriteMessage(Environment.NewLine + "你没有保存文件!\n");
return;
}
#if true
//例子一:
//关闭已经打开的同路径文件夹们
var wins = new ShellWindows();//这个名字是为了兼容高版本(没想到吧
if (wins.Enumerator.Count > 0)
{
string dwgname = CadSystem.Getvar("dwgname");
foreach (var item in wins.Enumerator)
{
if (!string.IsNullOrEmpty(item.LocationURL) &&
item.LocationURL + "\\" + dwgname == filename3)
{
item.Quit();//关闭
}
}
}
//重开一个,防止选择状态被改变,
Process.Start("explorer", "/select,\"" + filename3 + "\"");//加引号防止空格中断
#else
//例子二
JoinBoxCurrency.Shell32.ShowFileInExplorer(filename3);
#endif
}
catch (System.Exception e)
{
ed.WriteMessage(Environment.NewLine + e.Message);
}
}
}
}
遍历桌面资源管理器
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using static Win32API.WinApi;
namespace Win32API
{
public class InternetExplorer
{
/// <summary>
/// 句柄
/// </summary>
public IntPtr HWND { get; set; }
/// <summary>
/// 文件夹路径
/// </summary>
public string LocationURL { get; set; }
/// <summary>
/// 关闭窗口,关闭文件夹
/// </summary>
public void Quit()
{
SendMessage(HWND, (int)WM.WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
}
}
/// <summary>
/// 遍历桌面资源管理器
/// </summary>
public class ShellWindows
{
public List<InternetExplorer> Enumerator = new List<InternetExplorer>();
/// <summary>
/// 获取桌面所有文件夹的路径
/// </summary>
/// <returns></returns>
public ShellWindows()
{
var wndList = new List<WindowInfo>();
GetAllDesktopWindows(wndList);
var classArrar = new string[] {
"WorkerW",
"ReBarWindow32",
"Address Band Root",
"msctls_progress32",
"Breadcrumb Parent",
"ToolbarWindow32"
};
var displays = new Shell32.GetDisplays();
foreach (var item in wndList)
{
if (item.ClassName != "CabinetWClass")//资源管理器
{
continue;
}
var fi = Finds(item.Hwnd, classArrar);
if (fi == IntPtr.Zero)
{
continue;
}
//知识:toolbar上的按钮没有handler,要用发送通知信息
var sb = new StringBuilder(256);
//获取窗口名称-路径地址
GetWindowText(fi, sb, sb.Capacity);
string path = sb.ToString();
path = path.Substring(4, path.Length - 4);//4表示"地址: "长度...怎么对应每个语言呢?
//窗口名称如果是特殊文件夹则不是路径,如"桌面"/"文档"/"音乐"
if (string.IsNullOrEmpty(Path.GetDirectoryName(path)))
{
path = displays.GetPath(path);
}
Enumerator.Add(new InternetExplorer
{
HWND = item.Hwnd,
LocationURL = path
});
Enumerator.Add(ie);
}
}
/// <summary>
/// 递归查找子窗体句柄
/// </summary>
IntPtr Finds(IntPtr hwnd, string[] classArrar, int arrNum = 0)
{
IntPtr fi = IntPtr.Zero;
if (classArrar.Length > arrNum)
{
fi = FindWindowEx(hwnd, 0, classArrar[arrNum], null);
if (fi != IntPtr.Zero && classArrar.Length > arrNum + 1)//最后一个就不找了
{
fi = Finds(fi, classArrar, ++arrNum);
}
}
return fi;
}
}
}
Win32API使用
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Text;
namespace Win32API
{
public class WinApi
{
public delegate bool WNDENUMPROC(IntPtr hwnd, int lParam);
/// <summary>
/// 置前窗口
/// </summary>
/// <param name="hwnd"></param>
/// <returns></returns>
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern bool SetForegroundWindow(IntPtr hwnd);
/// <summary>
/// 枚举窗口
/// </summary>
/// <param name="lpEnumFunc"></param>
/// <param name="lParam"></param>
/// <returns></returns>
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern bool EnumWindows(WNDENUMPROC lpEnumFunc, int lParam);
/// <summary>
/// 获取窗口Text
/// </summary>
/// <param name="hwnd"></param>
/// <param name="lpString"></param>
/// <param name="nMaxCount"></param>
/// <returns></returns>
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int GetWindowText(IntPtr hwnd, [MarshalAs(UnmanagedType.LPWStr)]StringBuilder lpString, int nMaxCount);
/// <summary>
/// 获取窗口类名
/// </summary>
/// <param name="hwnd"></param>
/// <param name="lpString"></param>
/// <param name="nMaxCount"></param>
/// <returns></returns>
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int GetClassName(IntPtr hwnd, [MarshalAs(UnmanagedType.LPWStr)]StringBuilder lpString, int nMaxCount);
/// <summary>
/// 窗口隐藏
/// </summary>
/// <param name="hwnd">窗口句柄</param>
/// <returns></returns>
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern bool IsWindowVisible(IntPtr hwnd);
/// <summary>
/// 查找子窗口
/// </summary>
/// <param name="hwnd"></param>
/// <param name="hwndChildAfter"></param>
/// <param name="lpszClass"></param>
/// <param name="lpszWindow"></param>
/// <returns></returns>
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern IntPtr FindWindowEx(IntPtr hwnd, uint hwndChildAfter, string lpszClass, string lpszWindow);
///https://jingyan.baidu.com/article/c45ad29cd5fb58051653e278.html
/// <summary>
/// 发送消息
/// </summary>
/// <returns></returns>
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);
/// <summary>
/// 发送消息
/// </summary>
/// <returns></returns>
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, ref Rectangle lParam);
/// <summary>
/// 关闭文件夹
/// </summary>
/// <param name="hwnd"></param>
public static void QuitToolbar(IntPtr hwnd)
{
// https://docs.microsoft.com/zh-cn/windows/desktop/winmsg/wm-close
const int WM_CLOSE = 0x0010;
SendMessage(hwnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
}
//窗口样式
public struct WindowInfo
{
public IntPtr hwnd;
public string windowName;
public string className;
}
/// <summary>
/// 枚举所有桌面窗口
/// </summary>
/// <returns></returns>
public static WindowInfo[] GetAllDesktopWindows()
{
//用来保存窗口对象 列表
var wndList = new List<WindowInfo>();
//枚举所有桌面窗口
EnumWindows(delegate (IntPtr hWnd, int lParam)
{
WindowInfo wnd = new WindowInfo();
StringBuilder sb = new StringBuilder(256);
//获得HWND
wnd.hwnd = hWnd;
//获取窗口名称
GetWindowText(hWnd, sb, sb.Capacity);
wnd.windowName = sb.ToString();
//获取窗口类
GetClassName(hWnd, sb, sb.Capacity);
wnd.className = sb.ToString();
//添加到列表中
wndList.Add(wnd);
return true;
}, 0);
return wndList.ToArray();
}
}
}
Sell32API使用
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
namespace JoinBoxCurrency
{
public partial class Shell32
{
/// <summary>
/// 打开文件夹并选择项目
/// </summary>
[DllImport("shell32.dll", CharSet = CharSet.Auto)]
public static extern int SHOpenFolderAndSelectItems(IntPtr pidlFolder, uint cidl, [MarshalAs(UnmanagedType.LPArray)] IntPtr[] apidl, uint dwFlags);
/// <summary>
/// 解析显示名称
/// </summary>
[DllImport("shell32.dll", CharSet = CharSet.Auto)]
public static extern void SHParseDisplayName([MarshalAs(UnmanagedType.LPWStr)] string name, IntPtr bindingContext, out IntPtr pidl, uint sfgaoIn, out uint psfgaoOut);
// https://stackoverflow.com/questions/8182494/how-can-i-set-an-existing-explorer-exe-instance-to-select-a-file
/// <summary>
/// 置前文件夹并设置文件焦点
/// </summary>
/// <param name="file">文件路径</param>
public static void ShowFileInExplorer(string file)
{
// 如果是我自己开的同路径文件夹,它的表现是自己开一个新的.
// 但是我用它开的,然后换了焦点,它则不开新的,而是重设焦点了.
// 就好像有个缓存,它不是在全屏幕检索的,是在它第一次开了的文件夹上面检索的.
// 获取当前打开的文件夹(资源管理器)指针
var directory = Path.GetDirectoryName(file);
SHParseDisplayName(directory, IntPtr.Zero, out IntPtr folderPtr, 0, out _);
if (folderPtr == IntPtr.Zero)
{
return;
}
if (File.Exists(file))
{
file = Path.GetFileName(file);
SHParseDisplayName(file, IntPtr.Zero, out IntPtr filePtr, 0, out _);
if (filePtr != IntPtr.Zero)
{
IntPtr[] files = { filePtr };
SHOpenFolderAndSelectItems(folderPtr, (uint)files.Length, files, 0);
Marshal.FreeCoTaskMem(filePtr);
}
}
Marshal.FreeCoTaskMem(folderPtr);
}
}
public partial class Shell32
{
/// <summary>
/// 获取文件信息
/// </summary>
[DllImport("shell32.dll")]
public static extern int SHGetFileInfoW(IntPtr pidl, uint dwFileAttributes, out SHFILEINFO psfi, uint cbFileInfo, uint flags);
/// <summary>
/// 获取文件夹路径
/// </summary>
[DllImport("shell32.dll")]
public static extern HResult SHGetFolderLocation(IntPtr hwnd, int nFolder, IntPtr token, int dwReserved, out IntPtr pidl);
/// <summary>
/// 释放指针
/// </summary>
/// <param name="pidl"></param>
[DllImport("shell32.dll")]
public static extern void ILFree(IntPtr pidl);
/// <summary>
/// 获取特殊文件夹枚举值(如"桌面","文档")的中文名称
/// </summary>
public static string GetDisplayInvoke(Environment.SpecialFolder specialFolder)
{
IntPtr pidl = IntPtr.Zero;
try
{
HResult hr = SHGetFolderLocation(IntPtr.Zero, (int)specialFolder, IntPtr.Zero, 0, out pidl);
if (hr.IsFailure)
return null;
SHFILEINFO shfi;
if (0 != SHGetFileInfoW(pidl,
FILE_ATTRIBUTE_NORMAL,
out shfi,
(uint)Marshal.SizeOf(typeof(SHFILEINFO)),
SHGFI_PIDL | SHGFI_DISPLAYNAME))
{
return shfi.szDisplayName;
}
return null;
}
finally
{
if (pidl != IntPtr.Zero)
ILFree(pidl);
}
}
/// <summary>
/// 获取所有的特殊文件夹
/// </summary>
/// <returns></returns>
public static Dictionary<Environment.SpecialFolder, string> GetDisplayDictionary()
{
var dic = new Dictionary<Environment.SpecialFolder, string>();
foreach (var value in Enum.GetValues(typeof(Environment.SpecialFolder)))
{
var spe = (Environment.SpecialFolder)value; //然后强转成枚举类型,可作为输出
var name = GetDisplayInvoke(spe);
if (!dic.ContainsKey(spe))
{
dic.Add(spe, name);
}
}
return dic;
}
/// <summary>
/// 通过特殊文件夹的名称获取对应的枚举
/// </summary>
/// <returns></returns>
public static Environment.SpecialFolder? GetDisplayInvoke(string specialFolder)
{
var dic = GetDisplayDictionary();
foreach (var pa in dic)
{
if (pa.Value == specialFolder)
{
return pa.Key;
}
}
return null;
}
public class GetDisplays
{
Dictionary<Environment.SpecialFolder, string> dic;
public GetDisplays()
{
dic = GetDisplayDictionary();
}
//返回名称
public string GetName(Environment.SpecialFolder specialFolder)
{
// 透过缓存速度更快
return dic[specialFolder];
}
//返回枚举
public Environment.SpecialFolder? GetName(string specialFolder)
{
foreach (var pa in dic)
{
if (pa.Value == specialFolder)
return pa.Key;
}
return null;
}
//窗口名称如果是特殊文件夹则不是路径,如"桌面"/"文档"/"音乐"
//返回路径
public string GetPath(string specialFolder)
{
string path = null;
var sf = GetName(specialFolder);
if (sf != null)
{
path = Environment.GetFolderPath(sf.Value);
}
return path;
}
}
private const uint FILE_ATTRIBUTE_NORMAL = 0x00000080;
private const uint SHGFI_DISPLAYNAME = 0x000000200; // get display name
private const uint SHGFI_PIDL = 0x000000008; // pszPath is a pidl
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct SHFILEINFO
{
public IntPtr hIcon;
public int iIcon;
public uint dwAttributes;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szDisplayName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
public string szTypeName;
}
[StructLayout(LayoutKind.Sequential)]
public struct HResult
{
private int _value;
public int Value
{
get { return _value; }
}
public Exception Exception
{
get { return Marshal.GetExceptionForHR(_value); }
}
public bool IsSuccess
{
get { return _value >= 0; }
}
public bool IsFailure
{
get { return _value < 0; }
}
}
}
}
(完)