Skip to content

Commit eefefe1

Browse files
authored
Adds Support for Command-Line on Windows (flameshot-org#3699)
* + cli support on windows - removes the preprocessor macro that prevented arg parsing on Windows - adds windows-cli.cpp as src for a wrapper exe - adds flameshot-cli target into cmake when building on Windows - updates README * updates PR + support for unicode characters in cli args + additional clarification in README re: flameshot-cli + new workaround for spaces in _popen path; works with relative output paths * fix EOL * updated flameshot.exe path construction avoids using the hard-coded length of flameshot-cli.exe * fix whitespace (clang)
1 parent 134238b commit eefefe1

File tree

4 files changed

+88
-2
lines changed

4 files changed

+88
-2
lines changed

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,14 @@ A systray icon will be in your system's panel while Flameshot is running.
153153
Do a right click on the tray icon and you'll see some menu items to open the configuration window and the information window.
154154
Check out the About window to see all available shortcuts in the graphical capture mode.
155155

156+
### Usage on Windows
157+
158+
On Windows, `flameshot.exe` will behave as expected for all supported command-line arguments,
159+
but it will not output any text to the console. This is problematic if, for example, you are
160+
running `flameshot.exe -h`.
161+
162+
If you require console output, run `flameshot-cli.exe` instead. `flameshot-cli.exe` is a minimal wrapper around `flameshot.exe` that ensures all stdout is captured and output to the console.
163+
156164
### CLI configuration
157165

158166
You can use the graphical menu to configure Flameshot, but alternatively you can use your terminal or scripts to do so.

src/CMakeLists.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,13 @@ if(FLAMESHOT_ICON)
7373
endif()
7474

7575
if (WIN32)
76+
add_executable(flameshot-cli)
77+
target_sources(
78+
flameshot-cli
79+
PRIVATE
80+
windows-cli.cpp)
81+
set_target_properties(flameshot-cli PROPERTIES OUTPUT_NAME "flameshot-cli")
82+
target_link_options(flameshot-cli PRIVATE /SUBSYSTEM:CONSOLE)
7683
set_property(TARGET flameshot PROPERTY WIN32_EXECUTABLE true)
7784
if (MSVC)
7885
target_compile_options(flameshot PRIVATE /source-charset:utf-8)
@@ -322,6 +329,10 @@ install(TARGETS flameshot
322329
EXPORT flameshot-targets
323330
BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR}
324331
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
332+
if (WIN32)
333+
install(TARGETS flameshot-cli
334+
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
335+
endif ()
325336

326337
if (UNIX)
327338
# Install desktop files, completion and dbus files

src/main.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,6 @@ int main(int argc, char* argv[])
184184
return qApp->exec();
185185
}
186186

187-
#if !defined(Q_OS_WIN)
188187
/*--------------|
189188
* CLI parsing |
190189
* ------------*/
@@ -609,6 +608,5 @@ int main(int argc, char* argv[])
609608
}
610609
finish:
611610

612-
#endif
613611
return 0;
614612
}

src/windows-cli.cpp

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#include <iostream>
2+
#include <windows.h>
3+
4+
std::wstring joinArgs(int argc, wchar_t* argv[])
5+
{
6+
std::wstring result;
7+
for (int i = 1; i < argc; ++i) {
8+
if (i > 1) {
9+
result += L" ";
10+
}
11+
result += argv[i];
12+
}
13+
return result;
14+
}
15+
16+
void CallFlameshot(const std::wstring args, bool wait)
17+
{
18+
// generate full path for flameshot executable
19+
wchar_t path[MAX_PATH];
20+
int pathLength = GetModuleFileNameW(NULL, path, MAX_PATH);
21+
std::wstring pathstring(path);
22+
23+
// Find the last backslash to isolate the filename
24+
size_t lastBackslash = pathstring.find_last_of(L'\\');
25+
std::wstring directory = (lastBackslash != std::wstring::npos)
26+
? pathstring.substr(0, lastBackslash + 1)
27+
: L"";
28+
29+
// generate command string
30+
// note: binary path placed within quotes in case of spaces in path
31+
int cmdSize = 32 + sizeof(directory) + sizeof(args);
32+
wchar_t* cmd = (wchar_t*)malloc(sizeof(wchar_t) * cmdSize);
33+
swprintf(cmd,
34+
cmdSize,
35+
L"\"%s\\flameshot.exe\" %s",
36+
directory.c_str(),
37+
args.c_str());
38+
// call subprocess
39+
FILE* stream = _wpopen(cmd, L"r");
40+
free(cmd);
41+
if (wait) {
42+
if (stream) {
43+
const int MAX_BUFFER = 2048;
44+
char buffer[MAX_BUFFER];
45+
while (!feof(stream)) {
46+
if (fgets(buffer, MAX_BUFFER, stream) != NULL) {
47+
std::cout << buffer;
48+
}
49+
}
50+
}
51+
_pclose(stream);
52+
}
53+
return;
54+
}
55+
56+
// Console 'wrapper' for flameshot on windows
57+
int wmain(int argc, wchar_t* argv[])
58+
{
59+
// if no args, do not wait for stdout
60+
if (argc == 1) {
61+
std::cout << "Starting flameshot in daemon mode" << std::endl;
62+
CallFlameshot(L"", false);
63+
} else {
64+
std::wstring argString = joinArgs(argc, argv);
65+
CallFlameshot(argString, true);
66+
}
67+
std::cout.flush();
68+
return 0;
69+
}

0 commit comments

Comments
 (0)