Code

Extensions. Fix for bug #647744 ([inx] min/max float values ignored with locale using...
[inkscape.git] / src / winconsole.cpp
1 /** \file
2  * @brief Command-line wrapper for Windows.
3  *
4  * Windows has two types of executables: GUI and console.
5  * The GUI executables detach immediately when run from the command
6  * prompt (cmd.exe), and whatever you write to standard output
7  * disappears into a black hole. Console executables handle
8  * do display standard output and take standard input from the console,
9  * but when you run them from the GUI, an extra console window appears.
10  * It's possible to hide it, but it still flashes from a fraction
11  * of a second.
12  *
13  * To provide an Unix-like experienve, where the application will behave
14  * correctly in command line mode and at the same time won't create
15  * the ugly console window when run from the GUI, we have to have two
16  * executables. The first one, inkscape.exe, is the GUI application.
17  * Its entry points are in main.cpp and winmain.cpp. The second one,
18  * called inkscape.com, is a small helper application contained in
19  * this file. It spawns the GUI application and redirects its output
20  * to the console.
21  *
22  * Note that inkscape.com has nothing to do with "compact executables"
23  * from DOS. It's a normal PE executable renamed to .com. The trick
24  * is that cmd.exe picks .com over .exe when both are present in PATH,
25  * so when you type "inkscape" into the command prompt, inkscape.com
26  * gets run. The Windows program loader does not inspect the extension,
27  * just like an Unix program loader; it determines the binary format
28  * based on the contents of the file.
29  *
30  *//*
31  * Authors:
32  *   Jos Hirth <jh@kaioa.com>
33  *   Krzysztof KosiƱski <tweenk.pl@gmail.com>
34  *
35  * Copyright (C) 2008-2010 Authors
36  *
37  * Released under GNU GPL, read the file 'COPYING' for more information
38  */
40 #ifdef WIN32
41 #undef DATADIR
42 #include <windows.h>
44 struct echo_thread_info {
45     HANDLE echo_read;
46     HANDLE echo_write;
47     unsigned buffer_size;
48 };
50 // thread function for echoing from one file handle to another
51 DWORD WINAPI echo_thread(void *info_void)
52 {
53     echo_thread_info *info = static_cast<echo_thread_info*>(info_void);
54     char *buffer = reinterpret_cast<char *>(LocalAlloc(LMEM_FIXED, info->buffer_size));
55     DWORD bytes_read, bytes_written;
57     while(true){
58         if (!ReadFile(info->echo_read, buffer, info->buffer_size, &bytes_read, NULL) || bytes_read == 0)
59             if (GetLastError() == ERROR_BROKEN_PIPE)
60                 break;
62         if (!WriteFile(info->echo_write, buffer, bytes_read, &bytes_written, NULL)) {
63             if (GetLastError() == ERROR_NO_DATA)
64                 break;
65         }
66     }
68     LocalFree(reinterpret_cast<HLOCAL>(buffer));
69     CloseHandle(info->echo_read);
70     CloseHandle(info->echo_write);
72     return 1;
73 }
75 int main()
76 {
77     // structs that will store information for our I/O threads
78     echo_thread_info stdin = {NULL, NULL, 4096};
79     echo_thread_info stdout = {NULL, NULL, 4096};
80     echo_thread_info stderr = {NULL, NULL, 4096};
81     // handles we'll pass to inkscape.exe
82     HANDLE inkscape_stdin, inkscape_stdout, inkscape_stderr;
83     HANDLE stdin_thread, stdout_thread, stderr_thread;
85     SECURITY_ATTRIBUTES sa;
86     sa.nLength=sizeof(SECURITY_ATTRIBUTES);
87     sa.lpSecurityDescriptor=NULL;
88     sa.bInheritHandle=TRUE;
90     // Determine the path to the Inkscape executable.
91     // Do this by looking up the name of this one and redacting the extension to ".exe"
92     const int pathbuf = 2048;
93     WCHAR *inkscape = reinterpret_cast<WCHAR*>(LocalAlloc(LMEM_FIXED, pathbuf * sizeof(WCHAR)));
94     GetModuleFileNameW(NULL, inkscape, pathbuf);
95     WCHAR *dot_index = wcsrchr(inkscape, L'.');
96     wcsncpy(dot_index, L".exe", 4);
98     // we simply reuse our own command line for inkscape.exe
99     // it guarantees perfect behavior w.r.t. quoting
100     WCHAR *cmd = GetCommandLineW();
102     // set up the pipes and handles
103     stdin.echo_read = GetStdHandle(STD_INPUT_HANDLE);
104     stdout.echo_write = GetStdHandle(STD_OUTPUT_HANDLE);
105     stderr.echo_write = GetStdHandle(STD_ERROR_HANDLE);
106     CreatePipe(&inkscape_stdin, &stdin.echo_write, &sa, 0);
107     CreatePipe(&stdout.echo_read, &inkscape_stdout, &sa, 0);
108     CreatePipe(&stderr.echo_read, &inkscape_stderr, &sa, 0);
110     // fill in standard IO handles to be used by the process
111     PROCESS_INFORMATION pi;
112     STARTUPINFOW si;
114     ZeroMemory(&si,sizeof(STARTUPINFO));
115     si.cb = sizeof(STARTUPINFO);
116     si.dwFlags = STARTF_USESTDHANDLES;
117     si.hStdInput = inkscape_stdin;
118     si.hStdOutput = inkscape_stdout;
119     si.hStdError = inkscape_stderr;
121     // spawn inkscape.exe
122     CreateProcessW(inkscape, // path to inkscape.exe
123                    cmd, // command line as a single string
124                    NULL, // process security attributes - unused
125                    NULL, // thread security attributes - unused
126                    TRUE, // inherit handles
127                    0, // flags
128                    NULL, // environment - NULL = inherit from us
129                    NULL, // working directory - NULL = inherit ours
130                    &si, // startup info - see above
131                    &pi); // information about the created process - unused
133     // clean up a bit
134     LocalFree(reinterpret_cast<HLOCAL>(inkscape));
135     CloseHandle(pi.hThread);
136     CloseHandle(pi.hProcess);
137     CloseHandle(inkscape_stdin);
138     CloseHandle(inkscape_stdout);
139     CloseHandle(inkscape_stderr);
141     // create IO echo threads
142     DWORD unused;
143     stdin_thread = CreateThread(NULL, 0, echo_thread, (void*) &stdin, 0, &unused);
144     stdout_thread = CreateThread(NULL, 0, echo_thread, (void*) &stdout, 0, &unused);
145     stderr_thread = CreateThread(NULL, 0, echo_thread, (void*) &stderr, 0, &unused);
147     // wait until the standard output thread terminates
148     WaitForSingleObject(stdout_thread, INFINITE);
150     return 0;
153 #endif