|
|
楼主 |
发表于 2026-11-5 21:36:37
|
显示全部楼层
让CodeBuddy按ahk的方式简化一下脚本
它自己测试了好几分钟,发现"Shell.Application".Windows不含桌面
我把AutoHotkey和脚本发给它测试成功,它自己去AutoHotkey社区找答案
发现AutoHotkey在"Shell.Application".Windows找不到桌面后会自己FindWindowSW找桌面
然后它生成了新的c#
用win10自带的csc.exe编译成exe文件,速度也是极快
适用于极度不想用第三方软件的人
用以下代码编译- $cs="D:\1\SetIconMedium.cs";
- $csc="C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe";
- & $csc /nologo /target:winexe /platform:anycpu /optimize+ /out:"D:\1\SetIconMedium.exe" $cs;
复制代码
c#源码- // =====================================================================
- // SetIconMedium.cs v6 —— 将桌面图标统一设为中等图标 (48px)
- //
- // 编译为 /target:winexe 时运行无任何窗口(适合开机/登录静默部署),
- // 编译为 /target:exe 时(SetIconMedium_console.exe)带控制台输出供排查。
- //
- // 路径A(首选,文档化 COM API,与验证过的 AHK 脚本同链路):
- // IShellWindows::FindWindowSW(SWC_DESKTOP) 定位桌面浏览器
- // (该 API 对 SWC_DESKTOP 走特殊分支,桌面无需出现在可枚举集合中,
- // 与 AHK 的 Item(VT_I4 SWC_DESKTOP) 等效)
- // -> QueryService(SID_STopLevelBrowser) -> IShellBrowser
- // -> QueryActiveShellView(虚表偏移 15)
- // -> IFolderView2::SetViewModeAndIconSize(FVM_ICON=1, size)(偏移 35)
- // -> GetViewModeAndIconSize(偏移 36)读回确认
- //
- // 路径B(补位):当 FindWindowSW 也找不到桌面浏览器时(极少数壳环境),
- // 向可见 SHELLDLL_DefView 发送视图命令:
- // 0x704E(FVM_MEDIUMICON)=中48px / 0x7050(FVM_SMALL)=小32px
- // (Win7 可能吞掉第一次消息,自动重发,最多 3 次)
- //
- // 校验:读回像素值 + LVM_GETITEMSPACING 实际图标间距变化
- // 用法:SetIconMedium.exe [size] (缺省 48;32=小图标,其他值走 48)
- // 返回码:0 成功,1 失败
- // =====================================================================
- using System;
- using System.Collections.Generic;
- using System.Reflection;
- using System.Runtime.InteropServices;
- using System.Text;
- class Program
- {
- const int SWC_DESKTOP = 8;
- const int FVM_ICON = 1;
- const int WM_COMMAND = 0x0111;
- const int CMD_MEDIUM = 0x704E; // FVM_MEDIUMICON -> 48px
- const int CMD_SMALL = 0x7050; // FVM_SMALL -> 32px
- static readonly Guid SID_STopLevelBrowser = new Guid("4C96BE40-915C-11CF-99D3-00AA004AE837");
- static readonly Guid IID_IShellBrowser = new Guid("000214E2-0000-0000-C000-000000000046");
- static readonly Guid IID_IFolderView2 = new Guid("1AF3A467-214F-4298-908E-06B03E0B39F9");
- static readonly Guid CLSID_ShellWindows = new Guid("9BA05972-F6A8-11CF-A442-00A0C90A8F39");
- static void Log(string s) {
- try { Console.WriteLine(s); } catch {}
- }
- [ComImport, Guid("6D5140C1-7436-11CE-8034-00AA006009FA"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
- interface IServiceProvider
- {
- [PreserveSig] int QueryService(ref Guid guidService, ref Guid riid, out IntPtr ppvObject);
- }
- [UnmanagedFunctionPointer(CallingConvention.StdCall)]
- delegate int QueryActiveShellView_t(IntPtr self, out IntPtr ppshv);
- [UnmanagedFunctionPointer(CallingConvention.StdCall)]
- delegate int GetViewModeAndIconSize_t(IntPtr self, out int viewMode, out int iconSize);
- [UnmanagedFunctionPointer(CallingConvention.StdCall)]
- delegate int SetViewModeAndIconSize_t(IntPtr self, int viewMode, int iconSize);
- [UnmanagedFunctionPointer(CallingConvention.StdCall)]
- delegate int GetWindow_t(IntPtr self, out IntPtr hwnd); // IOleWindow::GetWindow(偏移3)
- // ---------- Win32 窗口枚举 ----------
- delegate bool EnumProc(IntPtr hWnd, IntPtr lParam);
- [DllImport("user32.dll")] static extern bool EnumWindows(EnumProc cb, IntPtr lParam);
- [DllImport("user32.dll")] static extern bool EnumChildWindows(IntPtr parent, EnumProc cb, IntPtr lParam);
- [DllImport("user32.dll", CharSet = CharSet.Unicode)] static extern int GetClassName(IntPtr h, StringBuilder sb, int max);
- [DllImport("user32.dll")] static extern IntPtr GetAncestor(IntPtr hwnd, uint flags);
- [DllImport("user32.dll")] static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
- static IntPtr defView = IntPtr.Zero;
- static IntPtr listView = IntPtr.Zero;
- static List<IntPtr> allDefViews = new List<IntPtr>();
- static bool ChildCb(IntPtr h, IntPtr l) {
- StringBuilder sb = new StringBuilder(256);
- GetClassName(h, sb, 256);
- string cls = sb.ToString();
- if (cls == "SHELLDLL_DefView") { defView = h; allDefViews.Add(h); }
- if (cls == "SysListView32" && listView == IntPtr.Zero) { listView = h; }
- return true;
- }
- static bool TopCb(IntPtr h, IntPtr l) {
- StringBuilder sb = new StringBuilder(256);
- GetClassName(h, sb, 256);
- string cls = sb.ToString();
- if (cls == "Progman" || cls == "WorkerW") {
- EnumChildWindows(h, ChildCb, IntPtr.Zero);
- }
- return true;
- }
- static void FindDesktop() {
- defView = IntPtr.Zero; listView = IntPtr.Zero;
- allDefViews.Clear();
- EnumWindows(TopCb, IntPtr.Zero);
- }
- static bool IsDesktopView(IntPtr hwnd) {
- foreach (IntPtr v in allDefViews) { if (v == hwnd) { return true; } }
- return false;
- }
- // LVM_GETITEMSPACING:实际图标间距(布局变化的直接证据)
- static string GetSpacing() {
- if (listView == IntPtr.Zero) { return "n/a"; }
- long r = SendMessage(listView, 0x1033, IntPtr.Zero, IntPtr.Zero).ToInt64() & 0xFFFFFFFF;
- return (r & 0xFFFF) + "x" + ((r >> 16) & 0xFFFF);
- }
- static object GetProp(object obj, string name) {
- try { return obj.GetType().InvokeMember(name, BindingFlags.GetProperty, null, obj, null); }
- catch { return null; }
- }
- // 对 ShellWindows 项取其视图窗口句柄:QueryService -> QueryActiveShellView -> GetWindow
- static IntPtr GetCandidateViewHwnd(object candidate) {
- IntPtr pUnk = Marshal.GetIUnknownForObject(candidate);
- try {
- IServiceProvider sp = (IServiceProvider)Marshal.GetObjectForIUnknown(pUnk);
- Guid sid = SID_STopLevelBrowser;
- Guid iidB = IID_IShellBrowser;
- IntPtr pBrowser;
- int hr = sp.QueryService(ref sid, ref iidB, out pBrowser);
- if (hr != 0) { return IntPtr.Zero; }
- try {
- IntPtr vtbl = Marshal.ReadIntPtr(pBrowser);
- QueryActiveShellView_t qasv = (QueryActiveShellView_t)Marshal.GetDelegateForFunctionPointer(
- Marshal.ReadIntPtr(vtbl, 15 * IntPtr.Size), typeof(QueryActiveShellView_t));
- IntPtr pView;
- hr = qasv(pBrowser, out pView);
- if (hr != 0 || pView == IntPtr.Zero) { return IntPtr.Zero; }
- try {
- IntPtr vtblV = Marshal.ReadIntPtr(pView);
- GetWindow_t gw = (GetWindow_t)Marshal.GetDelegateForFunctionPointer(
- Marshal.ReadIntPtr(vtblV, 3 * IntPtr.Size), typeof(GetWindow_t));
- IntPtr hwnd;
- hr = gw(pView, out hwnd);
- return (hr == 0) ? hwnd : IntPtr.Zero;
- } finally { Marshal.Release(pView); }
- } finally { Marshal.Release(pBrowser); }
- } catch { return IntPtr.Zero; }
- finally { Marshal.Release(pUnk); }
- }
- // 文档化 API:IShellWindows::FindWindowSW(SWC_DESKTOP)(经 IDispatch 后期绑定,安全)
- static object FindDesktopByFindWindowSW(object shellWindows) {
- Type t = shellWindows.GetType();
- object[] locCandidates = new object[] { 0, Type.Missing }; // 0=CSIDL_DESKTOP 或 VT_EMPTY
- foreach (object loc in locCandidates) {
- try {
- object[] args = new object[] { loc, Type.Missing, SWC_DESKTOP, 0, 1 /*SWFO_NEEDDISPATCH*/ };
- ParameterModifier mod = new ParameterModifier(5);
- mod[3] = true; // pHWND 为出参
- ParameterModifier[] mods = new ParameterModifier[] { mod };
- object ret = t.InvokeMember("FindWindowSW", BindingFlags.InvokeMethod, null,
- shellWindows, args, mods, null, null);
- if (ret != null) {
- Log("[INFO] FindWindowSW ok, browser hwnd=" + args[3]);
- return ret;
- }
- Log("[INFO] FindWindowSW returned null (loc=" + (loc is int ? "0" : "empty") + ")");
- } catch (Exception ex) {
- Log("[INFO] FindWindowSW failed: " + ex.Message);
- }
- }
- return null;
- }
- static int Main(string[] args)
- {
- int size = 48;
- if (args.Length > 0) {
- int v;
- if (int.TryParse(args[0], out v) && v >= 16 && v <= 256) { size = v; }
- }
- try { return Run(size); }
- catch (Exception ex) {
- Log("[FAIL] " + ex.Message);
- return 1;
- }
- }
- static int Run(int size)
- {
- // 1. 定位可见桌面视图
- FindDesktop();
- if (defView == IntPtr.Zero) {
- Log("[FAIL] SHELLDLL_DefView not found");
- return 1;
- }
- IntPtr root = GetAncestor(defView, 2);
- string spacingBefore = GetSpacing();
- Log("[INFO] DefView=0x" + defView.ToInt64().ToString("X") +
- " Root=0x" + root.ToInt64().ToString("X") + " spacing=" + spacingBefore);
- // 2. 路径A:COM 定位桌面项。FindWindowSW(SWC_DESKTOP) 是文档化的桌面查找 API,
- // 其返回的浏览器句柄即桌面根窗口,可直接信任,无需再做视图匹配
- object desktop = null;
- Type t = Type.GetTypeFromCLSID(CLSID_ShellWindows);
- object shellWindows = Activator.CreateInstance(t);
- object viaSW = FindDesktopByFindWindowSW(shellWindows);
- if (viaSW != null) { desktop = viaSW; }
- if (desktop == null) {
- // 兜底定位:集合枚举 + 视图窗口句柄匹配
- List<object> candidates = new List<object>();
- try {
- object cand = t.InvokeMember("Item", BindingFlags.InvokeMethod, null, shellWindows,
- new object[] { SWC_DESKTOP });
- if (cand != null) { candidates.Add(cand); }
- } catch {}
- int count = 0;
- object c1 = GetProp(shellWindows, "Count");
- if (c1 is int) { count = (int)c1; }
- for (int i = 0; i < count; i++) {
- object item = null;
- try {
- item = t.InvokeMember("Item", BindingFlags.InvokeMethod, null, shellWindows,
- new object[] { i });
- } catch {}
- if (item != null) { candidates.Add(item); }
- }
- Log("[INFO] ShellWindows candidates: " + candidates.Count);
- foreach (object cand in candidates) {
- IntPtr viewHwnd = GetCandidateViewHwnd(cand);
- if (viewHwnd != IntPtr.Zero && IsDesktopView(viewHwnd)) { desktop = cand; break; }
- }
- }
- // 3. 路径A执行:IFolderView2::SetViewModeAndIconSize
- if (desktop != null) {
- Log("[INFO] desktop item located, applying via IFolderView2...");
- int mode, isz;
- int hr = ApplyByCom(desktop, size, out mode, out isz);
- if (hr == 0) {
- System.Threading.Thread.Sleep(300);
- string spacingAfter = GetSpacing();
- Log("[INFO] after: spacing=" + spacingAfter + " (was " + spacingBefore + ")");
- if (spacingAfter != spacingBefore) {
- Log("[OK] desktop icons set to " + size + "px via COM, layout changed");
- return 0;
- }
- if (isz == size) {
- Log("[OK] view reports " + isz + "px, already at target (no layout change needed)");
- return 0;
- }
- Log("[INFO] COM applied but unverified, trying message path...");
- } else {
- Log("[INFO] COM path failed (hr=0x" + hr.ToString("X") + "), trying message path...");
- }
- } else {
- Log("[INFO] desktop item not found via COM, using message path...");
- }
- // 4. 路径B:消息方式(Win7 可能吞掉第一次消息,自动重发)
- return ApplyByMessage(size, spacingBefore);
- }
- static int ApplyByCom(object desktop, int size, out int mode, out int isz) {
- mode = -1; isz = -1;
- IntPtr pUnk = Marshal.GetIUnknownForObject(desktop);
- try {
- IServiceProvider sp = (IServiceProvider)Marshal.GetObjectForIUnknown(pUnk);
- Guid sid = SID_STopLevelBrowser;
- Guid iidB = IID_IShellBrowser;
- IntPtr pBrowser;
- int hr = sp.QueryService(ref sid, ref iidB, out pBrowser);
- if (hr != 0) { return hr; }
- try {
- IntPtr vtbl = Marshal.ReadIntPtr(pBrowser);
- QueryActiveShellView_t qasv = (QueryActiveShellView_t)Marshal.GetDelegateForFunctionPointer(
- Marshal.ReadIntPtr(vtbl, 15 * IntPtr.Size), typeof(QueryActiveShellView_t));
- IntPtr pView;
- hr = qasv(pBrowser, out pView);
- if (hr != 0 || pView == IntPtr.Zero) { return (hr == 0) ? -1 : hr; }
- try {
- Guid iidFV2 = IID_IFolderView2;
- IntPtr pFV2;
- hr = Marshal.QueryInterface(pView, ref iidFV2, out pFV2);
- if (hr != 0) { return hr; }
- try {
- IntPtr vtbl2 = Marshal.ReadIntPtr(pFV2);
- SetViewModeAndIconSize_t setFn = (SetViewModeAndIconSize_t)Marshal.GetDelegateForFunctionPointer(
- Marshal.ReadIntPtr(vtbl2, 35 * IntPtr.Size), typeof(SetViewModeAndIconSize_t));
- GetViewModeAndIconSize_t getFn = (GetViewModeAndIconSize_t)Marshal.GetDelegateForFunctionPointer(
- Marshal.ReadIntPtr(vtbl2, 36 * IntPtr.Size), typeof(GetViewModeAndIconSize_t));
- hr = setFn(pFV2, FVM_ICON, size);
- if (hr != 0) { return hr; }
- hr = getFn(pFV2, out mode, out isz);
- if (hr == 0 && isz > 0) {
- Log("[INFO] read-back: mode=" + mode + " size=" + isz + "px");
- }
- return 0;
- } finally { Marshal.Release(pFV2); }
- } finally { Marshal.Release(pView); }
- } finally { Marshal.Release(pBrowser); }
- } finally { Marshal.Release(pUnk); }
- }
- static int ApplyByMessage(int size, string spacingBefore) {
- int cmd = (size <= 32) ? CMD_SMALL : CMD_MEDIUM;
- if (defView == IntPtr.Zero) {
- Log("[FAIL] no DefView for message path");
- return 1;
- }
- for (int attempt = 1; attempt <= 3; attempt++) {
- SendMessage(defView, WM_COMMAND, (IntPtr)cmd, IntPtr.Zero);
- for (int i = 0; i < 4; i++) {
- System.Threading.Thread.Sleep(250);
- if (GetSpacing() != spacingBefore) {
- Log("[OK] desktop icons set to " + ((size <= 32) ? 32 : 48) +
- "px via message 0x" + cmd.ToString("X") + " (attempt " + attempt + "), layout changed");
- return 0;
- }
- }
- if (attempt < 3) {
- Log("[INFO] message attempt " + attempt + " no effect, resending...");
- System.Threading.Thread.Sleep(1000);
- }
- }
- Log("[FAIL] no layout change after message path");
- return 1;
- }
- }
复制代码 |
|