how to use the eventual lauching console in a winmain application? - user-interface

I have a small winmain application.
It is a winmain because I don't want it to flash a console at startup.
But if it is launched from a console, I would like to print in this console.
Is this possible ?

As noted by eryksun in the comments, AttachConsole is not perfect because cmd.exe only waits for console applications.
A sneaky workaround is to have a little console helper .exe that you rename to .com. It sits between you and the parent console application. You still need to use AttachConsole or DuplicateHandle to get access to the console handles in the GUI application...

here is the solution I've retained:
if ( AttachConsole(ATTACH_PARENT_PROCESS) )
{
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
int fd = _open_osfhandle((intptr_t)hStdOut, _O_TEXT);
if (fd > 0) *stdout = *_fdopen(fd, "w");
}

Related

Is there an API call to prompt user for UAC elevation?

My app needs to write to a file in \ProgramData that could be protected. This only happens once after installation.
Is there an API function that would take ACL info and prompt the user to authorize the app to access the file? In other words the app would ask Windows to prompt the user for confirmation and authorization. This should happen interactively, and allow the app to resume execution after access to the file has been authorized. The app runs as Standard User, does not require Admin privilege.
The file gets opened with CreateFile().
Edit: There is a subtle difference between my query and the others said to be duplicates. I am asking for permission to access one specific object, a file. The others are asking to elevate the privileges of the whole process. Anyway, I am grateful for all responses which include a solution.
If you don't want to elevate your entire app, you have a few options:
spawn a separate elevated process just to access the file. Use ShellExecute/Ex() with the runas verb, or CreateProcessElevated(), to run a second copy of your app, or another helper app, with command-line parameters to tell it what to do. The main process can wait for the second process to exit, if needed.
create a COM object to access the file, and then use the COM Elevation Moniker to run the COM object in an elevated state.
prompt the user for credentials using CredUIPromptForCredentials() or CredUIPromptForWindowsCredentials() (see Asking the User for Credentials for more details), then logon to the specified account using LogonUser() to get a token, impersonate that token using ImpersonateLoggedOnUser(), access the file as needed, and then stop impersonating using RevertToSelf() and close the token with CloseHandle().
Thanks to #Remy for the ShellExecuteEx suggestion, here are the sordid details. Note the use of 'cmd' and the double-command, so the user only has to reply once. Also, [1] must wait for process completion otherwise you could find yourself creating the file before it was deleted, and [2] don't wait for the process if it failed.
// delete file with Admin privilege
// 'file_name' is path of file to be deleted
SHELLEXECUTEINFO shex;
char param[512];
char *cmd = "/C \"attrib -H \"%s\" && del /F /Q \"%s\"\""; // double command
_snprintf(param, sizeof(param), cmd, file_name, file_name);
ZeroMemory(&shex, sizeof(shex));
shex.cbSize = sizeof(shex);
shex.lpVerb = "runas"; // runas, open
shex.lpFile = "cmd"; // not 'del'
shex.lpParameters = param;
shex.nShow = SW_HIDE;
shex.fMask = SEE_MASK_NOCLOSEPROCESS;
BOOL retshx = ShellExecuteEx(&shex);
// wait otherwise could return before completed
if(retshx)
{ time_t st = clock();
DWORD exitCode;
do
{ if(!GetExitCodeProcess(shex.hProcess, &exitCode))
break;
if(clock() - st > CLOCKS_PER_SEC * 5) // max 5 seconds
break;
} while(exitCode != STATUS_WAIT_0); // STILL_ACTIVE
CloseHandle(shex.hProcess);
}
Processes can only be launched with an elevated token, they can't gain it after the fact. So you can either re-launch your app elevated with a command line argument telling it what to do (simple solution), or implement an out-of-proc COM server that you can create elevated and pass instructions to it (harder).
A third solution is to leverage the built-in UAC support of the IFileOperation interface, but this doesn't let you read/write, only copy. So you could make a copy of the file you need to modify, modify the copy and then use IFileOperation to copy the temporary over the original.

Running EXE application in GINA beofe login screen (Command line)

I have created a Credential Launcher for Windows 7 and was able to run Windows application after the Tile button click event, it was very easy.
I added a few registry settings and *pbAutoLogon = FALSE;.
However now i am now trying to do the same for Windows XP.
Which function I should target or how to achieve the same results ?
I see you tagged your question with "Gina", so I guess you know that Credential Providers do not exist on XP.
Your answer depends on when exactly you want to run that program, especially with regards to the secure attention sequence (SAS, or when a user press CTRL-ALT-Delete)
Before the SAS, use WlxDisplaySASNotice
After the SAS, use WlxLoggedOutSAS
Since you don't want to write a whole GINA yourself, you could use a custom Gina that wraps msgina.dll. Here is one I wrote, you can find the original I started from in the Platform SDK.
Using that approch, you get a chance to execute code just before or just after certain events, like running your program after a successful logon, something like :
int WINAPI WlxLoggedOutSAS(PVOID pWlxContext, DWORD dwSasType, PLUID pAuthenticationId, PSID pLogonSid, PDWORD pdwOptions, PHANDLE phToken, PWLX_MPR_NOTIFY_INFO pMprNotifyInfo, PVOID * pProfile)
{
int result;
result = pfWlxLoggedOutSAS(pWlxContext, dwSasType, pAuthenticationId, pLogonSid, pdwOptions, phToken, pMprNotifyInfo, pProfile);
if (result == WLX_SAS_ACTION_LOGON)
{
//We have a successful logon, let's run our code
run_my_custom_code();
}
return result;
}
There are some caveats, though :
The code cannot block. Winlogon will wait, but your users might not. Spanw a process and let it run.
Your program will be running with SYSTEM privileges, which is a security risk. Sandboxing your process could be hard. If you can't break out of it, don't assume nobody can...

CreateDesktop and DDE

I am setting up a scratch desktop to run another application in a "silent mode" - the other app is noisy and throws all sorts of windows around while it processes.
I have used the info here: CreateDesktop() with vista and UAC on (C, windows)
and CreateDesktop works - I can create the other desktop, I can launch the application into the other desktop (I see it launching in task manager) - but when I try to interact with the app via DDE, the DdeConnect call hangs until it times out.
And here's how I'm calling CreateDesktop:
LPSTR desktopName = "MYDESKTOPNAME";
HDESK hDesk = CreateDesktop(desktopName , NULL, NULL, 0, DESKTOP_SWITCHDESKTOP|
DESKTOP_WRITEOBJECTS|
DESKTOP_READOBJECTS|
DESKTOP_ENUMERATE|
DESKTOP_CREATEWINDOW|
DESKTOP_CREATEMENU, NULL);
Here is CreateProcess to actually launch the app into the new desktop:
STARTUPINFO startupInfo;
GetStartupInfo(&startupInfo);
startupInfo.lpDesktop = desktopName;
PROCESS_INFORMATION procInfo;
memset(&procInfo, 0, sizeof(procInfo));
if (CreateProcess(NULL, exePath, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &startupInfo, &procInfo)){
WaitForInputIdle(procInfo.hProcess, INFINITE);
CloseHandle(procInfo.hProcess);
CloseHandle(procInfo.hThread);
}
If it matters, the call to DdeInitialize:
DWORD afCmd = APPCLASS_STANDARD | APPCMD_CLIENTONLY | CBF_SKIP_ALLNOTIFICATIONS;
UINT rslt = ::DdeInitialize(&ddeInst, NULL, afCmd, 0);
Here is the DdeConnect call (the hsz* parameters, etc... are all fine - if I launch the app into the regular desktop, the calls all work perfectly).
hConv = ::DdeConnect(ddeInst,
hszService,
hszTopic,
NULL);
This call just hangs for ~60 seconds.
Is this a security issue of some sort? i.e. the windows messages aren't passing between desktops? Or does anyone have any suggestion on how to troubleshoot this further?
The documentation for CreateDesktop contains a cross-reference to the Desktops topic, which says
Window messages can be sent only between processes that are on the same desktop.
The overview topics are important. They provide background information to help you understand the feature.
Raymond explains why the messages don't get through. In order to solve the problem, assuming you continue with the separate desktop, you will simply need to run the process that performs the DDE in the same desktop as the target app. If you need to communicate between your process on the main desktop and the target process then you will need to use some other form of IPC.

How to prevent console from being displayed when using VLC's dummy interface

I'm trying to launch VLC in "dummy" mode from a Node.js server script, however using child_process.spawn('vlc',['-I dummy']) produces a new console window for VLC's output when using Windows. Is there a way to prevent this happening and force all stdout though the stdout ReadableStream so no "popup windows" occur?
EDIT: This problem had nothing to do with node.js, it was simply the way I was calling it and VLC's behaviour. The solution is below.
Thanks.
I found a solution for the specific problem:
VLC has a command line option to surpress this window --*-quiet where * is the interface.
e.g. For the dummy interface, use
child_process.spawn('vlc',['-I dummy','--dummy-quiet'])
For the rc interface, use
child_process.spawn('vlc',['-I rc','--rc-quiet'])
I would like to complement Adam M-W answer.
VLC has a command line option to suppress this window --*-quiet where * is the interface.
e.g. For the dummy interface, use
child_process.spawn('vlc',['-I dummy','--dummy-quiet']) For the rc
interface, use
child_process.spawn('vlc',['-I rc','--rc-quiet'])
answered Jun 13 '11 at 14:12
Adam M-W
at least on my system, VLC now sends its messages to stdError, so this is the channel which needs to be monitored.
My interface is with Qt , QtProcess and these are the options that worked for me.
Using MergedChannels and reading stdOut.
m_proc->setProcessChannelMode(QProcess::MergedChannels);
connect (m_proc,SIGNAL(readyReadStandardOutput()),
this, SLOT(readyRead()));
void ReDirVLC::readyRead(){
if (!m_proc) return;
qDebug()<<m_proc->readAllStandardOutput() << endl;
}
Using SeparateChannels and reading stdError
m_proc->setProcessChannelMode(QProcess::SeparateChannels);
connect (m_proc,SIGNAL(readyReadStandardError()),
this, SLOT(readyRead()));
void ReDirVLC::readyRead(){
if (!m_proc) return;
qDebug()<<m_proc->readAllStandardError() << endl;
}
Maybe you could run the process with child_process.spawn('start', ['/b', 'vlc', '-I dummy']) instead?

Terminal Services

HI,
Im using Delphi and I want to make an application that can do the following
When started from within Terminal services (remote desktop), if another user logs into another terminal services session they should be able to see the application running in the desktop tray. However if a user sitting at the server logs in then they shouldn't see the application running in the desktop tray. Its fine if everyone can see it running in the process list, just not the desktop tray.
How can I do this?
Make your application launch on startup on every user, then use this function to determine whether to quit or not:
#include <windows.h>
#include <winternl.h>
BOOL IsRunningOnTerminalServerClient( void )
{
PWINSTATIONQUERYINFORMATIONW WinStationQueryInformationW;
WINSTATIONINFORMATIONW wsInfo;
HINSTANCE hInstWinSta;
ULONG ReturnLen;
hInstWinSta = LoadLibraryA( "winsta.dll" );
if( hInstWinSta )
{
WinStationQueryInformationW = (PWINSTATIONQUERYINFORMATIONW)
GetProcAddress( hInstWinSta, "WinStationQueryInformationW" );
if( WinStationQueryInformationW &&
WinStationQueryInformationW( SERVERNAME_CURRENT,
LOGONID_CURRENT,
WinStationInformation,
&wsInfo,
sizeof(wsInfo),
&ReturnLen ) &&
( wsInfo.LogonId != 0 ) )
{
FreeLibrary( hInstWinSta );
return( TRUE );
}
FreeLibrary( hInstWinSta );
}
return FALSE;
}
Pulled from http://msdn.microsoft.com/en-us/library/aa383827(v=VS.85).aspx
Assumption: You are logging into a Windows Server - two people cannot RDP at the same time on the Desktop OSes. My experience with this is that you should not see applications running visually - ie on the desktop or on the taskbar or tray icon area.
If you go into the task manager and look at the processes running - you may see process running. Also, if you are Administrator, then you may "Kill" the process, else there is nothing you can do with it.
Does this help?
Please clarify what you are asking.

Resources