is it possible to create a program that works as console application if started from the console and works as windows program (with GUI) when started otherwise?
If it is possible - how can I do that?
regards
Tobias
If you set the program up to build as a GUI program you can then attempt to attach to the console using AttachConsole(). You you attach OK then you were started from a console and you can proceed to redirect your standard handles to the newly attached console.
In this way you can start up and see if you are being started from a console that you can attach to and if so become a console program. If you cant attach you can show a GUI.
I've had some success with this, the main problem I have is redisplaying the command window's prompt when my program exits (which is how normal console programs operate), but I expect you could do something clever (read the console buffer on start up and find the prompt to redisplay when you exit?) if you really wanted to ...
If you need the program to act as a console application (e.g. print the usage information to the console) you must complile as a console application. A windows application will not have access to the console and cmd.exe will not wait for it to finish before printing the prompt and accepting the next command.
The best solution is to have two versions, one for command line and one for the GUI (which users usually run via a link on the desktop or start menu).
If you insist on using a single binary you will have to live with a console window appearing, at least for a short time. You can get rid of the console window using
FreeConsole();
You can tell that your application was run from GUI if it is the only process attached to the console. You can use GetConsoleProcessList to find the list of processes attached to the console.
This is the answer from Dan Tillett and it is remarkably effective. No flashes, no .com and .exe to trick cmd.exe. Seems to work flawlessly typing the command, in a .bat file, with focus, without focus and as double-click GUI app.
It's the bees knees!
Here is web page describing it, but I've posted it here because if that page goes 404 next month or 2 years from now, the excellent and "most complete" solution I've seen would be "off the grid".
http://www.tillett.info/2013/05/13/how-to-create-a-windows-program-that-works-as-both-as-a-gui-and-console-application/
#define WINVER 0x0501 // Allow use of features specific to Windows XP or later.
#define _WIN32_WINNT 0x0501
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <io.h>
#include <fcntl.h>
#include <stdio.h>
#pragma comment(lib, "User32.lib")
// Attach output of application to parent console
static BOOL attachOutputToConsole(void) {
HANDLE consoleHandleOut, consoleHandleError;
int fdOut, fdError;
FILE *fpOut, *fpError;
if (AttachConsole(ATTACH_PARENT_PROCESS)) {
//redirect unbuffered STDOUT to the console
consoleHandleOut = GetStdHandle(STD_OUTPUT_HANDLE);
fdOut = _open_osfhandle((intptr_t)consoleHandleOut, _O_TEXT);
fpOut = _fdopen(fdOut, "w" );
*stdout = *fpOut;
setvbuf(stdout, NULL, _IONBF, 0 );
//redirect unbuffered STDERR to the console
consoleHandleError = GetStdHandle(STD_ERROR_HANDLE);
fdError = _open_osfhandle((intptr_t)consoleHandleError, _O_TEXT);
fpError = _fdopen(fdError, "w" );
*stderr = *fpError;
setvbuf(stderr, NULL, _IONBF, 0 );
return TRUE;
}
//Not a console application
return FALSE;
}
//Send the "enter" to the console to release the command prompt on the parent console
static void sendEnterKey(void) {
INPUT ip;
// Set up a generic keyboard event.
ip.type = INPUT_KEYBOARD;
ip.ki.wScan = 0; // hardware scan code for key
ip.ki.time = 0;
ip.ki.dwExtraInfo = 0;
//Send the "Enter" key
ip.ki.wVk = 0x0D; // virtual-key code for the "Enter" key
ip.ki.dwFlags = 0; // 0 for key press
SendInput(1, &ip, sizeof(INPUT));
// Release the "Enter" key
ip.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release
SendInput(1, &ip, sizeof(INPUT));
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, INT nCmdShow) {
int argc = __argc;
char **argv = __argv;
UNREFERENCED_PARAMETER(hInstance);
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
UNREFERENCED_PARAMETER(nCmdShow);
BOOL console;
int i;
//Is the program running as console or GUI application
console = attachOutputToConsole();
if (console) {
//Print to stdout
printf("Program running as console application\n");
for (i = 0; i < argc; i++) {
printf("argv[%d] %s\n", i, argv[i]);
}
//Print to stderr
fprintf(stderr, "Output to stderr\n");
}
else {
MessageBox(NULL, "Program running as windows gui application",
"Windows GUI Application", MB_OK | MB_SETFOREGROUND);
}
//Send "enter" to release application from the console
//This is a hack, but if not used the console doesn't know the application has returned
//"enter" only sent if the console window is in focus
if (console && GetConsoleWindow() == GetForegroundWindow()){
sendEnterKey();
}
return 0;
}
The program itself will never know how it was started. Unless you are willing to pass an execution arguments to the program. For example: program.exe -GUI ... you can capture the passed parameters and decide how the program should run based on parameters passed.
your program whould be something like:
class MainClass
{
public static int Main(string[] args)
{
// Test if input arguments were supplied:
if(args[0]=="GUI")
new myGUI().show(); //runs an instance of your gui
else
//you know what should go here
}
}
You can sort of guess whether you are started from the console or not by doing this:
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
fConsole = csbi.dwCursorPosition.X | csbi.dwCursorPosition.Y;
It's a guess -- if your cursor position is not 0,0 than you are in a console and can work as a console app. Otherwise go and create your windows.
Another way to guess is to look at the process tree and see what process launched your app. If it is cmd.exe go in console mode, otherwise go into GUI mode.
Make it a console application and put this into the code:
void ConsoleWindowVisible(bool show)
{
DWORD dummy;
if
(
!show && // Trying to hide
GetConsoleProcessList(&dummy, 1) == 1 // Have our own console window
)
ShowWindow(GetConsoleWindow, SW_HIDE); // Hide the window
else // Trying to show or use parent console window
ShowWindow(GetConsoleWindow, SW_NORMAL); // Show the window
}
int main(int argc, char** argv)
{
ConsoleWindowVisible(false);
}
Cheers.
gor.f.gyolchanyan#gmail.com
Related
I wrote a test program for SDL2 text event handling, and the input method cannot be turned on when I'm focusing on the window created by SDL2.
I'm testing that on Linux with Xfce desktop and Fcitx input method engine.
The code is simple:
#include <SDL.h>
int main(int argc, char** argv)
{
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_EVENTS);
SDL_Window* window = SDL_CreateWindow("sdl text test", 50, 50, 400, 400, SDL_WINDOW_OPENGL);
SDL_StartTextInput();
while (1)
{
// process events
SDL_Event event{};
bool should_exit = false;
while (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_QUIT:
should_exit = true;
break;
case SDL_TEXTEDITING:
printf("text edit: %s %d %d\n", event.edit.text, event.edit.start, event.edit.length);
break;
case SDL_TEXTINPUT:
printf("text input: %s\n", event.text.text);
break;
}
}
if (should_exit) break;
SDL_Delay(20);
}
SDL_StopTextInput();
}
I have a brief look on SDL2's documents, but failed to find anything related with keyboard grabbing.
try delete
videodata->ime_uilesss = UILess_SetupSinks(videodata);
in function IME_Init of SDL_windowskeyboard.c.
It's ugly, but works.
If videodata->ime_uiless == SDL_False,
then windows will show input method,
else the sdl2 will render and show input method.
I'm using Windows 10 + SDL and was looking at SDL support for the IME under Windows, and have no idea how it could possibly work considering the IME_Render/IME_Present function are never called in SDL codebase.
Compiling SDL with #define SDL_DISABLE_WINDOWS_IME in SDL_windowskeyboard.c fixed it for me (xwang's suggestion will lead to a similar result).
I don't know why but it may do the trick: build SDL2 yourself.
I once use SDL2 comes with Ubuntu apt repo, libsdl2-dev/bionic-updates,now 2.0.8+dfsg1-1ubuntu1.18.04.1 amd64 . IME cannot be shown or switched.
After I replace with myself-built SDL2 lib(same version 2.0.8), IME works good.
I am experiencing odd behavior when using GetKeyState (or GetAsyncKeyState, for that matter) in a console app. One aspect of the app is to ask the user for a file to open using GetFileOpen. At the end of the program, GetKeyState monitors the state of the spacebar. The GetKeyState (or GetAsyncKeyState) function never sets the high order bit whenever the spacebar is pressed. If I do not call GetOpenFile and then monitor GetKeyState, all works as expected.
Here are the two basic scenarios.
Scenario 1:
#include <windows.h>
int main(int argc, char *argv[])
{
char filename[ 512 ] = {0};
OPENFILENAME ofn = {0};
int filenameSize = 512;
char title[1000] = {0};
strcpy(title, "Open File");
ZeroMemory(&ofn, sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = null;
ofn.lpstrFile = filename;
ofn.nMaxFile = filenameSize;
ofn.lpstrFilter = "All files (*.*)\0*.*\0\0";
ofn.nFilterIndex = 1;
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.lpfnHook = NULL;
ofn.lpstrTitle = title;
ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
GetOpenFileName(&ofn); // filename obtained
WaitForSpaceBar(); // return value's upper bit is never set for
// GetKeyState(VK_SPACE);
return 0;
}
Scenario 2:
int main(int argc, char *argv[])
{
WaitForSpaceBar(); // returns immediately after spacebar is pressed
return 0;
}
WaitForSpaceBar code
void WaitForSpaceBar()
{
#define KEY_PRESSED_FLAG 1
SHORT spacePressed = GetKeyState(VK_SPACE);
printf("\nPress spacebar to continue...\n");
while (!(spacePressed & KEY_PRESSED_FLAG))
{
Sleep(1);
spacePressed = GetKeyState(VK_SPACE);
// for debugging purposes only
printf("spacePressed = 0x%04x\n", spacePressed);
}
}
The first scenario outputs "spacePressed = 0x0000" indefinitely regardless of how many times I press the spacebar.
The second scenario outputs "spacePressed = 0x0000" until the spacebar is actually pressed. Once pressed, the output is "spacePressed = 0xffffff81", and the program terminates.
Any ideas as to what is happening?
The GetKeyState function is useless if your are not pumping message.
From the documentation:
Remarks
The key status returned from this function changes as a thread reads
key messages from its message queue. The status does not reflect the
interrupt-level state associated with the hardware. Use the
GetAsyncKeyState function to retrieve that information.
Use the following code for your WaitForSpaceBar function (note the new value for KEY_PRESSED_FLAG):
void WaitForSpaceBar()
{
SHORT spacePressed = GetAsyncKeyState(VK_SPACE);
#define KEY_PRESSED_FLAG 0x8000
printf("\nPress spacebar to continue...\n");
while (!(spacePressed & KEY_PRESSED_FLAG))
{
Sleep(1);
spacePressed = GetAsyncKeyState(VK_SPACE);
// for debugging purposes only
printf("spacePressed = 0x%04x\n", spacePressed);
}
}
From the MSDN documentation, it looks like GetKeyState is only meaningful when your thread is pumping messages and calling it in response to a keyboard message.
The key status returned from this function changes as a thread reads key messages from its message queue.
I suspect that GetOpenFile spins up its own thread and that thread somehow becomes the main UI thread for your process (because it's the only one doing GUI work).
If you're using Windows API calls, you may as well use something console-specific like ReadConsole.
Update: I pasted the question code into VS 2010, and cannot reproduce the problem. The GetKeyState function is working as expected regardless of whether GetOpenFileName was called.
I am writing a C++ (Windows) client console application which reads from an anonymous pipe on STDIN. I would like to be able to use my program as follows:
echo input text here | my_app.exe
and do something in the app with the text that is piped in
OR
my_app.exe
and then use some default text inside of the app instead of the input from the pipe.
I currently have code that successfully reads from the pipe on STDIN given the first situation:
#include <Windows.h>
#include <iostream>
#include <string>
#define BUFSIZE 4096
int main(int argc, const char *argv[]) {
char char_buffer[BUFSIZE];
DWORD bytes_read;
HANDLE stdin_handle;
BOOL continue_reading;
unsigned int required_size;
bool read_successful = true;
stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
if (stdin_handle == INVALID_HANDLE_VALUE) {
std::cout << "Error: invalid handle value!\n\n";
} else {
continue_reading = true;
while (continue_reading) {
continue_reading = ReadFile(stdin_handle, char_buffer, BUFSIZE,
&bytes_read, NULL);
if (continue_reading) {
if (bytes_read != 0) {
// Output what we have read so far
for (unsigned int i = 0; i < bytes_read; i++) {
std::cout << char_buffer[i];
}
} else {
continue_reading = false;
}
}
}
}
return 0;
}
I know that my only option with anonymous pipes is to do a blocking read with ReadFile. If I understand correctly, in regard to how I am invoking it, ReadFile will continue to read from the buffer on STDIN until it detects an end of write operation on the other end of the pipe (perhapse reads some sort of "end of write" token??). I would like to know if there is some sort of "beginning write" token that will be in the buffer if something is being piped in which I can check on STDIN BEFORE I call ReadFile. If this were the case I could just skip calling ReadFile and use some default text.
If there is not a way to do this, I can always pass in a command line argument that denotes that I should not check the pipe and just use the default text (or the other way around), but I would much prefer to do it the way that I specified.
Look at PeekNamedPipe(). Despite its name, it works for both named and anonymous pipes.
int main(int argc, const char *argv[])
{
char char_buffer[BUFSIZE];
DWORD bytes_read;
DWORD bytes_avail;
DWORD dw;
HANDLE stdin_handle;
bool is_pipe;
stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
is_pipe = !GetConsoleMode(stdin_handle, &dw);
if (stdin_handle == INVALID_HANDLE_VALUE) {
std::cout << "Error: invalid handle value!\n\n";
} else {
while (1) {
if (is_pipe) {
if (PeekNamedPipe(stdin_handle, NULL, 0, NULL, &bytes_avail, NULL)) {
if (bytes_avail == 0) {
Sleep(100);
continue;
}
}
}
if (!ReadFile(stdin_handle, char_buffer, min(bytes_avail, BUFSIZE), &bytes_read, NULL)) {
break;
}
if (bytes_read == 0) {
break;
}
// Output what we have read so far
for (unsigned int i = 0; i < bytes_read; i++) {
std::cout << char_buffer[i];
}
}
}
return 0;
}
It looks like what you're really trying to do here is to determine whether you've got console input (where you use default value) vs pipe input (where you use input from the pipe).
Suggest testing that directly instead of trying to check if there's input ready: the catch with trying to sniff whether there's data in the pipe is that if the source app is slow in generating output, your app might make an incorrect assumption just because there isn't input yet available. (It might also be possible that, due to typeahead, there's a user could have typed in characters that area ready to be read from console STDIN before your app gets around to checking if input is available.)
Also, keep in mind that it might be useful to allow your app to be used with file redirection, not just pipes - eg:
myapp.exe < some_input_file
The classic way to do this "interactive mode, vs used with redirected input" test on unix is using isatty(); and luckily there's an equivalent in the Windows CRT - see function _isatty(); or use GetFileType() checking for FILE_TYPE_CHAR on GetStdHandle(STD_INPUT_HANDLE) - or use say GetConsoleMode as Remy does, which will only succeed on a real console handle.
This also works without overlapped I/O while using a second thread, that does the synchronous ReadFile-call. Then the main thread waits an arbitrary amount of time and acts like above...
Hope this helps...
I have an application and wish to monitor MSWord keypressing (LOCAL HOOK), but I cant figure out how to find the pid to be used! The bellow CODE WORKS GOOD with global hook (pid = 0) and with (pid = GetCurrentThreadId). But doesn´t work with GetWindowThreadProcessId:
HWND hWindow = FindWindowEx(NULL,NULL,String("Notepad").w_str(),NULL);
if (!hWindow) {
ShowMessage("hWindow fail");
return;
}
unsigned long pid;
GetWindowThreadProcessId(hWindow ,&pid);
//pid = GetCurrentThreadId();
if (!hWindow) {
ShowMessage("pid fail");
return;
}
String s = "HookDLL.dll";
DllHandle=LoadLibrary(s.w_str());
HOOKFCT_2 InstHook=reinterpret_cast<HOOKFCT_2> (GetProcAddress(DllHandle,"InstallHook"));
if(!InstHook(pid, (void *)(callIt) ))
{
Label1->Caption="Unable to install mouse hook!";
}
else Label1->Caption="Mouse hook installed!";
I will be very, very gratefuLl for any light on the problem...
Notice:
I wish a hook to MSWord only.
The above code works, failling only when trying to hook on another application (i.e.: not using pid=0 or pid=GetCurrentThreadId), resulting in = "Unable to install mouse hook!".
I already try FindWindow, FindWindowEx, GetForegroundWindow, GetActiveWindow; since not of this works, I belive the problem is GetWindowThreadProcessId.
SetWindowsHookEx requires thread ID, not process ID. Pass thread ID instead:
DWORD threadID = GetWindowThreadProcessId(hWindow, 0);
if(!InstHook(threadID, (void *)(callIt) )) {...}
I have written a simple program which will report key press and release events for a particular window. In my case, it is mostly the terminal since I invoke the program from the terminal. I am able to get the key press and release events taking place in the terminal window (I have used XSelectInput() with KeyPressMask and KeyReleaseMask on the terminal) but the same is not working with ButtonPress and ButtonRelease. Not just these, but any events related to the mouse are not being reported. Any idea why this is happening?
#include
#include
#include
#include
#include
#include
int main() {
Display *display = XOpenDisplay(NULL);
KeySym k;
int revert_to;
Window window;
XEvent event;
XGetInputFocus(display, &window, &revert_to);
XSelectInput(display, window, KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask);
while(1)
{
XNextEvent(display,&event);
switch (event.type) {
case KeyPress : printf("Key Pressed\n"); break;
case KeyRelease : printf("Key Released\n"); break;
case ButtonPress : printf("Button Pressed\n"); break;
case ButtonRelease : printf("Button Released\n"); break;
case EnterNotify : printf("Enter\n"); break;
}
}
XCloseDisplay(display);
return 0;
}
The problem you encounter is that Xlib sends ButtonPress/Release events to only one client. I think that the window you're working with already has a client which is listening to its mouse events. Therefore your SelectInput call did not actually set ButtonPress/Release masks and generated an error which you didn't check for.