Skip to content

Commit 3ab1fb1

Browse files
committed
Fix clipboard action under sta thread issue
1 parent 532b5dc commit 3ab1fb1

File tree

4 files changed

+170
-23
lines changed

4 files changed

+170
-23
lines changed

Flow.Launcher.Infrastructure/NativeMethods.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,7 @@ WM_KEYUP
1616
WM_SYSKEYDOWN
1717
WM_SYSKEYUP
1818

19-
EnumWindows
19+
EnumWindows
20+
21+
OleInitialize
22+
OleUninitialize

Flow.Launcher.Infrastructure/UserSettings/Settings.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ public SearchPrecisionScore QuerySearchPrecision
230230
[JsonIgnore]
231231
public ObservableCollection<BuiltinShortcutModel> BuiltinShortcuts { get; set; } = new()
232232
{
233-
new BuiltinShortcutModel("{clipboard}", "shortcut_clipboard_description", Clipboard.GetText),
233+
new BuiltinShortcutModel("{clipboard}", "shortcut_clipboard_description", () => Win32Helper.StartSTATaskAsync(Clipboard.GetText).Result),
234234
new BuiltinShortcutModel("{active_explorer_path}", "shortcut_active_explorer_path", FileExplorerHelper.GetActiveExplorerPath)
235235
};
236236

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
using System;
2+
using System.Threading;
3+
using System.Threading.Tasks;
4+
using Windows.Win32;
5+
6+
namespace Flow.Launcher.Infrastructure
7+
{
8+
/// <summary>
9+
/// Provides static helper for Win32.
10+
/// Codes are edited from: https://github.com/files-community/Files.
11+
/// </summary>
12+
public static class Win32Helper
13+
{
14+
public static Task StartSTATaskAsync(Action action)
15+
{
16+
var taskCompletionSource = new TaskCompletionSource();
17+
Thread thread = new(() =>
18+
{
19+
PInvoke.OleInitialize();
20+
21+
try
22+
{
23+
action();
24+
taskCompletionSource.SetResult();
25+
}
26+
catch (System.Exception)
27+
{
28+
taskCompletionSource.SetResult();
29+
}
30+
finally
31+
{
32+
PInvoke.OleUninitialize();
33+
}
34+
})
35+
{
36+
IsBackground = true,
37+
Priority = ThreadPriority.Normal
38+
};
39+
40+
thread.SetApartmentState(ApartmentState.STA);
41+
thread.Start();
42+
43+
return taskCompletionSource.Task;
44+
}
45+
46+
public static Task StartSTATaskAsync(Func<Task> func)
47+
{
48+
var taskCompletionSource = new TaskCompletionSource();
49+
Thread thread = new(async () =>
50+
{
51+
PInvoke.OleInitialize();
52+
53+
try
54+
{
55+
await func();
56+
taskCompletionSource.SetResult();
57+
}
58+
catch (System.Exception)
59+
{
60+
taskCompletionSource.SetResult();
61+
}
62+
finally
63+
{
64+
PInvoke.OleUninitialize();
65+
}
66+
})
67+
{
68+
IsBackground = true,
69+
Priority = ThreadPriority.Normal
70+
};
71+
72+
thread.SetApartmentState(ApartmentState.STA);
73+
thread.Start();
74+
75+
return taskCompletionSource.Task;
76+
}
77+
78+
public static Task<T?> StartSTATaskAsync<T>(Func<T> func)
79+
{
80+
var taskCompletionSource = new TaskCompletionSource<T?>();
81+
82+
Thread thread = new(() =>
83+
{
84+
PInvoke.OleInitialize();
85+
86+
try
87+
{
88+
taskCompletionSource.SetResult(func());
89+
}
90+
catch (System.Exception)
91+
{
92+
taskCompletionSource.SetResult(default);
93+
}
94+
finally
95+
{
96+
PInvoke.OleUninitialize();
97+
}
98+
})
99+
{
100+
IsBackground = true,
101+
Priority = ThreadPriority.Normal
102+
};
103+
104+
thread.SetApartmentState(ApartmentState.STA);
105+
thread.Start();
106+
107+
return taskCompletionSource.Task;
108+
}
109+
110+
public static Task<T?> StartSTATaskAsync<T>(Func<Task<T>> func)
111+
{
112+
var taskCompletionSource = new TaskCompletionSource<T?>();
113+
114+
Thread thread = new(async () =>
115+
{
116+
PInvoke.OleInitialize();
117+
try
118+
{
119+
taskCompletionSource.SetResult(await func());
120+
}
121+
catch (System.Exception)
122+
{
123+
taskCompletionSource.SetResult(default);
124+
}
125+
finally
126+
{
127+
PInvoke.OleUninitialize();
128+
}
129+
})
130+
{
131+
IsBackground = true,
132+
Priority = ThreadPriority.Normal
133+
};
134+
135+
thread.SetApartmentState(ApartmentState.STA);
136+
thread.Start();
137+
138+
return taskCompletionSource.Task;
139+
}
140+
}
141+
}

Flow.Launcher/PublicAPIInstance.cs

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using System.Collections.Generic;
33
using System.Linq;
44
using System.Net;
@@ -117,35 +117,38 @@ public void ShellRun(string cmd, string filename = "cmd.exe")
117117
ShellCommand.Execute(startInfo);
118118
}
119119

120-
public void CopyToClipboard(string stringToCopy, bool directCopy = false, bool showDefaultNotification = true)
120+
public async void CopyToClipboard(string stringToCopy, bool directCopy = false, bool showDefaultNotification = true)
121121
{
122122
if (string.IsNullOrEmpty(stringToCopy))
123123
return;
124124

125-
var isFile = File.Exists(stringToCopy);
126-
if (directCopy && (isFile || Directory.Exists(stringToCopy)))
125+
await Win32Helper.StartSTATaskAsync(() =>
127126
{
128-
var paths = new StringCollection
127+
var isFile = File.Exists(stringToCopy);
128+
if (directCopy && (isFile || Directory.Exists(stringToCopy)))
129129
{
130-
stringToCopy
131-
};
130+
var paths = new StringCollection
131+
{
132+
stringToCopy
133+
};
132134

133-
Clipboard.SetFileDropList(paths);
135+
Clipboard.SetFileDropList(paths);
134136

135-
if (showDefaultNotification)
136-
ShowMsg(
137-
$"{GetTranslation("copy")} {(isFile ? GetTranslation("fileTitle") : GetTranslation("folderTitle"))}",
138-
GetTranslation("completedSuccessfully"));
139-
}
140-
else
141-
{
142-
Clipboard.SetDataObject(stringToCopy);
137+
if (showDefaultNotification)
138+
ShowMsg(
139+
$"{GetTranslation("copy")} {(isFile ? GetTranslation("fileTitle") : GetTranslation("folderTitle"))}",
140+
GetTranslation("completedSuccessfully"));
141+
}
142+
else
143+
{
144+
Clipboard.SetDataObject(stringToCopy);
143145

144-
if (showDefaultNotification)
145-
ShowMsg(
146-
$"{GetTranslation("copy")} {GetTranslation("textTitle")}",
147-
GetTranslation("completedSuccessfully"));
148-
}
146+
if (showDefaultNotification)
147+
ShowMsg(
148+
$"{GetTranslation("copy")} {GetTranslation("textTitle")}",
149+
GetTranslation("completedSuccessfully"));
150+
}
151+
});
149152
}
150153

151154
public void StartLoadingBar() => _mainVM.ProgressBarVisibility = Visibility.Visible;

0 commit comments

Comments
 (0)