Skip to content

Commit dcd0117

Browse files
committed
*backup
1 parent 27459ff commit dcd0117

File tree

11 files changed

+442
-126
lines changed

11 files changed

+442
-126
lines changed

ContextMenu.Avalonia/ViewModels/MainWindowViewModel.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public partial class MainWindowViewModel : ViewModelBase
2020
private const string SettingsFileName = "ContextMenuSettings.json";
2121
private const string ConfigFileName = "KitopiaContextMenu.json";
2222

23-
[ObservableProperty] private string _statusMessage = "Initializing...";
23+
[ObservableProperty] private string _statusMessage = "初始化中...";
2424
[ObservableProperty] private string _kitopiaPath = string.Empty;
2525

2626
public ObservableCollection<ContextMenuItemViewModel> Items { get; } = new();
@@ -65,7 +65,7 @@ private async Task LoadDataAsync()
6565

6666
if (string.IsNullOrEmpty(installPath))
6767
{
68-
StatusMessage = "Kitopia installation not found. Please set manually.";
68+
StatusMessage = "未找到 Kitopia 安装位置,请手动设置。";
6969
return;
7070
}
7171
KitopiaPath = installPath;
@@ -74,7 +74,7 @@ private async Task LoadDataAsync()
7474
var configPath = Path.Combine(installPath, "configs", ConfigFileName);
7575
if (!File.Exists(configPath))
7676
{
77-
StatusMessage = $"Config not found at: {configPath}";
77+
StatusMessage = $"未找到配置文件: {configPath}";
7878
return;
7979
}
8080

@@ -84,7 +84,7 @@ private async Task LoadDataAsync()
8484

8585
if (config?.Items == null)
8686
{
87-
StatusMessage = "Failed to parse config.";
87+
StatusMessage = "解析配置文件失败。";
8888
return;
8989
}
9090

@@ -115,11 +115,11 @@ private async Task LoadDataAsync()
115115
SaveSettings(settings);
116116
}
117117

118-
StatusMessage = "Loaded successfully.";
118+
StatusMessage = "加载成功。";
119119
}
120120
catch (Exception ex)
121121
{
122-
StatusMessage = $"Error: {ex.Message}";
122+
StatusMessage = $"错误: {ex.Message}";
123123
}
124124
}
125125

@@ -130,7 +130,7 @@ private async Task BrowsePath()
130130
{
131131
var folders = await desktop.MainWindow.StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
132132
{
133-
Title = "Select Kitopia Installation Folder",
133+
Title = "选择 Kitopia 安装文件夹",
134134
AllowMultiple = false
135135
});
136136

@@ -155,7 +155,7 @@ private async Task BrowsePath()
155155
}
156156
else
157157
{
158-
StatusMessage = "Selected folder does not appear to be a valid Kitopia installation.";
158+
StatusMessage = "选择的文件夹似乎不是有效的 Kitopia 安装目录。";
159159
}
160160
}
161161
}
@@ -260,7 +260,7 @@ private void SaveSettings(ContextMenuSettings? settings = null)
260260
}
261261
catch (Exception ex)
262262
{
263-
StatusMessage = $"Failed to save settings: {ex.Message}";
263+
StatusMessage = $"保存设置失败: {ex.Message}";
264264
}
265265
}
266266

ContextMenu.Avalonia/Views/MainWindow.axaml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,20 @@
99
Width="600" Height="400"
1010
WindowStartupLocation="CenterScreen"
1111
Icon="/Assets/icon.ico"
12-
Title="Kitopia Context Menu Manager">
12+
Title="Kitopia 右键菜单管理器">
1313

1414
<Design.DataContext>
1515
<vm:MainWindowViewModel/>
1616
</Design.DataContext>
1717

1818
<Grid RowDefinitions="Auto, *, Auto" Margin="20">
1919
<StackPanel Grid.Row="0" Spacing="10">
20-
<TextBlock Text="Kitopia Context Menu Manager" FontSize="20" FontWeight="Bold"/>
20+
<TextBlock Text="Kitopia 右键菜单管理器" FontSize="20" FontWeight="Bold"/>
2121
<TextBlock Text="{Binding StatusMessage}" Foreground="Gray" TextWrapping="Wrap"/>
2222

2323
<Grid ColumnDefinitions="*, Auto" RowDefinitions="Auto">
24-
<TextBlock Grid.Column="0" Text="{Binding KitopiaPath, StringFormat='Installation: {0}'}" FontSize="12" Foreground="Gray" TextWrapping="Wrap" VerticalAlignment="Center"/>
25-
<Button Grid.Column="1" Content="Browse..." Command="{Binding BrowsePathCommand}" Margin="10,0,0,0"/>
24+
<TextBlock Grid.Column="0" Text="{Binding KitopiaPath, StringFormat='安装位置: {0}'}" FontSize="12" Foreground="Gray" TextWrapping="Wrap" VerticalAlignment="Center"/>
25+
<Button Grid.Column="1" Content="浏览..." Command="{Binding BrowsePathCommand}" Margin="10,0,0,0"/>
2626
</Grid>
2727
</StackPanel>
2828

@@ -34,7 +34,7 @@
3434
</ListBox.ItemTemplate>
3535
</ListBox>
3636

37-
<TextBlock Grid.Row="2" Text="Changes are saved automatically." HorizontalAlignment="Center" Foreground="Gray"/>
37+
<TextBlock Grid.Row="2" Text="更改会自动保存。" HorizontalAlignment="Center" Foreground="Gray"/>
3838
</Grid>
3939

4040
</Window>

ContextMenuDll/Assets/icon.png

164 KB
Loading

ContextMenuDll/CommandHelper.cs

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Diagnostics;
4+
using System.IO;
5+
using System.Text;
6+
7+
namespace ContextMenuDll;
8+
9+
public static class CommandHelper
10+
{
11+
public static string ResolvePath(string path, string? kitopiaPath)
12+
{
13+
if (string.IsNullOrEmpty(path)) return path;
14+
15+
// If absolute, return as is
16+
if (Path.IsPathRooted(path)) return path;
17+
18+
// If we have kitopia path, combine
19+
if (!string.IsNullOrEmpty(kitopiaPath))
20+
{
21+
return Path.Combine(kitopiaPath, path);
22+
}
23+
24+
return path;
25+
}
26+
27+
public static void ExecuteCommand(ContextMenuItem item, List<string> paths, string? kitopiaPath, Action<string> logAction)
28+
{
29+
if (string.IsNullOrEmpty(item.Command)) return;
30+
31+
try
32+
{
33+
if (paths.Count > 0)
34+
{
35+
// Simple replacement logic
36+
string args = item.Arguments ?? string.Empty;
37+
string command = ResolvePath(item.Command, kitopiaPath);
38+
39+
// Case 1: Multi-file placeholder {all} or %*
40+
if (args.Contains("{all}") || args.Contains("%*"))
41+
{
42+
var sb = new StringBuilder();
43+
foreach (var p in paths) sb.Append($"\"{p}\" ");
44+
string allPaths = sb.ToString().Trim();
45+
46+
string finalArgs = args
47+
.Replace("\"{all}\"", "{all}") // Remove existing quotes around placeholder
48+
.Replace("\"%*\"", "%*") // Remove existing quotes around placeholder
49+
.Replace("{all}", allPaths)
50+
.Replace("%*", allPaths);
51+
52+
logAction($"Executing (Case 1): {command} Args: {finalArgs}");
53+
54+
Process.Start(new ProcessStartInfo
55+
{
56+
FileName = command,
57+
Arguments = finalArgs,
58+
UseShellExecute = true
59+
});
60+
}
61+
// Case 2: Per-file placeholder {0} or %1
62+
else if (args.Contains("{0}") || args.Contains("%1"))
63+
{
64+
foreach(var path in paths)
65+
{
66+
string quotedPath = $"\"{path}\"";
67+
string fileArgs = args
68+
.Replace("\"{0}\"", "{0}") // Remove existing quotes around placeholder
69+
.Replace("\"%1\"", "%1") // Remove existing quotes around placeholder
70+
.Replace("{0}", quotedPath)
71+
.Replace("%1", quotedPath);
72+
73+
logAction($"Executing (Case 2): {command} Args: {fileArgs}");
74+
Process.Start(new ProcessStartInfo
75+
{
76+
FileName = command,
77+
Arguments = fileArgs,
78+
UseShellExecute = true
79+
});
80+
}
81+
}
82+
// Case 3: No placeholder - Append all paths (Run once)
83+
else
84+
{
85+
var sb = new StringBuilder();
86+
if (!string.IsNullOrEmpty(args)) sb.Append(args + " ");
87+
foreach (var p in paths) sb.Append($"\"{p}\" ");
88+
89+
var finalArgs = sb.ToString().Trim();
90+
logAction($"Executing (Case 3): {command} Args: {finalArgs}");
91+
92+
Process.Start(new ProcessStartInfo
93+
{
94+
FileName = command,
95+
Arguments = finalArgs,
96+
UseShellExecute = true
97+
});
98+
}
99+
}
100+
else
101+
{
102+
// No files selected (background click?), just run command
103+
string command = ResolvePath(item.Command, kitopiaPath);
104+
logAction($"Executing (No files): {command} Args: {item.Arguments}");
105+
106+
Process.Start(new ProcessStartInfo
107+
{
108+
FileName = command,
109+
Arguments = item.Arguments,
110+
UseShellExecute = true
111+
});
112+
}
113+
}
114+
catch (Exception ex)
115+
{
116+
logAction($"Error invoking command: {ex.Message}");
117+
Debug.WriteLine($"Error invoking command: {ex.Message}");
118+
}
119+
}
120+
}

ContextMenuDll/ContextMenuDll.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,15 @@
4646
<Content Include="SparsePackage.appxmanifest">
4747
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
4848
</Content>
49-
<Content Include="configs\KitopiaContextMenu.json">
50-
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
51-
</Content>
5249
</ItemGroup>
5350

5451
<ItemGroup>
5552
<None Update="Assets\icon.ico">
5653
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
5754
</None>
55+
<None Update="configs\KitopiaContextMenu.json">
56+
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
57+
</None>
5858
</ItemGroup>
5959

6060
</Project>

ContextMenuDll/Interop/ComInterfaces.cs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,3 +126,67 @@ public partial interface IClassFactory
126126
void CreateInstance([MarshalAs(UnmanagedType.Interface)] object? pUnkOuter, ref Guid riid, out IntPtr ppvObject);
127127
void LockServer([MarshalAs(UnmanagedType.Bool)] bool fLock);
128128
}
129+
130+
#if DEBUG
131+
[ComImport]
132+
#else
133+
[GeneratedComInterface]
134+
#endif
135+
[Guid("000214e4-0000-0000-c000-000000000046")]
136+
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
137+
public partial interface IContextMenu
138+
{
139+
[PreserveSig]
140+
int QueryContextMenu(IntPtr hMenu, uint indexMenu, uint idCmdFirst, uint idCmdLast, uint uFlags);
141+
142+
[PreserveSig]
143+
int InvokeCommand(IntPtr pici);
144+
145+
[PreserveSig]
146+
int GetCommandString(nuint idCmd, uint uType, IntPtr pReserved, IntPtr pszName, uint cchMax);
147+
}
148+
149+
#if DEBUG
150+
[ComImport]
151+
#else
152+
[GeneratedComInterface]
153+
#endif
154+
[Guid("000214e8-0000-0000-c000-000000000046")]
155+
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
156+
public partial interface IShellExtInit
157+
{
158+
[PreserveSig]
159+
int Initialize(IntPtr pidlFolder, IntPtr pdtobj, IntPtr hKeyProgID);
160+
}
161+
162+
public enum CMF : uint
163+
{
164+
CMF_NORMAL = 0x00000000,
165+
CMF_DEFAULTONLY = 0x00000001,
166+
CMF_VERBSONLY = 0x00000002,
167+
CMF_EXPLORE = 0x00000004,
168+
CMF_NOVERBS = 0x00000008,
169+
CMF_CANRENAME = 0x00000010,
170+
CMF_NODEFAULT = 0x00000020,
171+
CMF_INCLUDESTATIC = 0x00000040,
172+
CMF_ITEMMENU = 0x00000080,
173+
CMF_EXTENDEDVERBS = 0x00000100,
174+
CMF_DISABLEDVERBS = 0x00000200,
175+
CMF_ASYNCVERBSTATE = 0x00000400,
176+
CMF_OPTIMIZEFORINVOKE = 0x00000800,
177+
CMF_SYNCCASCADEMENU = 0x00001000,
178+
CMF_DONOTPICKDEFAULT = 0x00002000,
179+
CMF_RESERVED = 0xffff0000
180+
}
181+
182+
public enum GCS : uint
183+
{
184+
GCS_VERBA = 0x00000000,
185+
GCS_HELPTEXTA = 0x00000001,
186+
GCS_VALIDATEA = 0x00000002,
187+
GCS_VERBW = 0x00000004,
188+
GCS_HELPTEXTW = 0x00000005,
189+
GCS_VALIDATEW = 0x00000006,
190+
GCS_VERBICONW = 0x00000014,
191+
GCS_UNICODE = 0x00000004
192+
}

0 commit comments

Comments
 (0)