Creating a child Process C# win32 API - c#

I am using the CreateProcess MSDN call() to manually launch an application and here's my code
void LaunchProg()
{
STARTUPINFO si = new STARTUPINFO();
si.cb = Marshal.SizeOf(si);
si.lpDesktop = "testProg";
PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
var lpCurrentDirectory = Path.GetDirectoryName(executablePath);
CreateProcess("c:\Windows\System32\notepad.exe", null,
IntPtr.Zero, IntPtr.Zero, true,
NORMAL_PRIORITY_CLASS, IntPtr.Zero, lpCurrentDirectory, ref si, ref pi);
}
This code works perfectly fine and launches the program in the specified desktop "testProg" but the issue is that when notepad.exe creates a child process which has a new window. This window is displayed in the Default desktop and not within the "testprog" desktop view (Active desktop view)
Not sure as to which parameter is not set correctly for all the child windows to be spawned within the same active desktop. I looked at the documentation and it is not clearer to me.
Update on an observation: The child process is not inherited from the application launched but its a child process of a system process running in the default desktop.
Any pointers? Thanks in advance!

From the MSDN documentation about threads and desktops, if a desktop is specified in the STARTUPINFO, that is used, otherwise the default desktop for the windows station to which the process is connected will be used. In your case, it seems likely that notepad is not marking the handle to the desktop inheritable, or it is doing a CreateProcess that doesn't inherit handles. Maybe you could attach a debugger and see what parameters the CreateProcess is being called with?

Related

Set position and size of a ClickOnce application

I would like to know if there is any way to set a position and a size of a ClickOnce deployed application, started via Process.Start. With normal (.exe) applications there is no problem, I can do something like that:
var externalAppProcess = Process.Start("calc");
var externalAppPtr = externalAppProcess.MainWindowHandle;
and then use invoked MoveWindow to set stuff like position, size etc. However, when I'm starting an appref-ms file, it runs without any issues, but I can't access its MainWindowHandle, it says that "Process has exited, so the requested information is not available". Any ideas?
When you launch *.appref-ms, rundll32 or dfshim process will run. It does ClickOnce checking and eventually starts executable of ClickOnce deployed application.
So you may try finding main window handle like this:
var processes = Process.GetProcessesByName("ClickOnceDeployedApp");
foreach (Process p in processes)
{
IntPtr windowHandle = p.MainWindowHandle;
// do something
}

create interactive elevated process from windows service and show to logged-on user

I have a service that spawns a WPF application process when a user logs on.
But for some reason the WPF application gets killed about 10 minutes after it has been created? The termination is immediate with no traces found in the Event Log nor are any normal close/exit events called in the WPF application.
In fact, when the termination occurs, Windows 7 seems to hang for a second, the mouse becoming unresponsive and then acting out the mouse gestures after a short delay (when it normalizes, but now lacking the created process).
The When
public partial class Service1 : ServiceBase
{
public Service1()
{
InitializeComponent();
CanHandleSessionChangeEvent = true;
}
protected override void OnSessionChange(SessionChangeDescription changeDescription)
{
if (changeDescription.Reason == SessionChangeReason.SessionLogon
&& changeDescription.SessionId > 0)
{
ApplicationLoader.PROCESS_INFORMATION procInfo;
ApplicationLoader.StartProcessAndBypassUAC(#"myapp.exe", out procInfo);
}
base.OnSessionChange(changeDescription);
}
}
Process Creation As Per Pero Matic Code
// ...
bool result = CreateProcessAsUser(hUserTokenDup, // client's access token
null, // file to execute
applicationName, // command line
ref sa, // pointer to process SECURITY_ATTRIBUTES
ref sa, // pointer to thread SECURITY_ATTRIBUTES
false, // handles are not inheritable
dwCreationFlags, // creation flags
IntPtr.Zero, // pointer to new environment block
null, // name of current directory
ref si, // pointer to STARTUPINFO structure
out procInfo // receives information about new process
);
the termination does not seem to happen if i target notepad.exe, however?
tested it with a vanilla\empty WPF application (.NET 4), and that crashed as well
Process Creation with Administrative Privileges and No Prompt
It seems that the issue is trying to duplicate the administrative SYSTEM token from winlogon.exe (but which is running in session 1+), because if you duplicate the specific user token instead (e.g. from explorer.exe) then the crashes are no more!
this is confirmed with the same vanilla/empty WPF application, and with running Marcel Roma code here - note that he uses explorer.exe instead of winlogon.exe
although using explorer.exe gets rid of the termination I lose the administrative privileges with that, which does not work for me
any ideas how to get it to work with the winlogon process token?
or is it possible to adjust the exlorer.exe token to make the duplicate elevated? im guessing somehow using TokenElevation and SetTokenInformation or AdjustTokenPrivileges
or could it be that Windows 7 has been patched to disallow such process impersonation?
alternatively, is there any way to get the specific user token with administrative privileges (rather than the owner being SYSTEM), but again, without password knowledge/prompts (excluding CreateProcessWithLogonW)
is this maybe to do with garbage collection somehow?
Well I'm just suggesting you a work around:
Why you don't put your core functionalities in a windows service, and then use the wpf app as a frontend ? So that if the user kill it, it doesn't stop the service. Then the service can regularly check that the wpf front end is started, and if needed restart it.
I think it'll be a more "trusted" design that the one you're trying to do, which could let the antivirus think you're a bad software and block you.
And to protect the windows service there is another question here: Protecting a Windows Service from untrusted users
I don't think you can (and definitly should not be able) to do this. Your best bet is to create an application that doesn't need elevated privileges and then use IPC to talk back to your service which then performs administrative tasks on the users behalf.

Black backgrounds on interactive windows launched from a service

I am implementing a Windows service in C#. This service calls a separate application that launches interactive windows. I have been able to work through the problems imposed by Session 0 Isolation by using the following series of steps:
LogonUser() to get a logon token for the user who will execute the separate application
SetTokenInformation() to transfer the user's logon token into session 1
CreateProcessAsUser() to launch the application in the user's session.
This works; When the service launches the application, I see the application's windows appear in my console session. However, the application's windows have black backgrounds and all of the controls are invisible. If I click in an area where I know there is a button, the window responds, so it is clearly able to receive user input.
Here is (a simplified and stripped down version of) the code I'm using:
IntPtr logonToken;
LogonUser(username, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, out logonToken);
SetTokenInformation(logonToken, TOKEN_INFORMATION_CLASS.TokenSessionId, sessionIdValuePtr, sessionIdSize);
STARTUPINFO startupinfo = new STARTUPINFO();
startupinfo.cb = Marshal.SizeOf(startupinfo);
startupinfo.lpDesktop = #"winsta0\default";
PROCESS_INFORMATION processinfo;
SECURITY_ATTRIBUTES processAttributes = new SECURITY_ATTRIBUTES();
SECURITY_ATTRIBUTES threadAttributes = new SECURITY_ATTRIBUTES();
ImpersonateLoggedOnUser(logonToken);
CreateProcessAsUser(
logonToken,
null,
cmdLine,
ref processAttributes,
ref threadAttributes,
false,
0,
IntPtr.Zero,
workingDirectory,
ref startupinfo,
out processinfo)
RevertToSelf();
I have tried adding code to load the user's profile before calling CreateProcessAsUser, but this did not help.
What could be causing the black backgrounds on my windows, and how should I go about fixing this problem? Any help would be most appreciated.
UPDATE: This appears to be very similar to the problem in this question: CreateProcessAsUser doesn't draw the GUI. He is using XP SP3, and I am having this problem in Windows 7 and Server 2008, meaning that I have the additional problem of dealing with Session 0 Isolation, but the symptoms in the two cases seem similar.

Finding the Child Window inside a Microsoft RemoteApp Programmatically

Background
I'm using SendKeys() to send keyboard commands to the active window, but I'm not having any luck finding the child window when the application is running through RemoteApp. It all works as expected when I run the application locally.
Microsoft RemoteApp allows users to connect to applications through the RDP protocol, but instead of showing the entire remote Virtual machine, it just shows the application window. To the end user, there is no difference between an application running under RemoteApp and it running on their desktop.
I've been using ManagedSpy to determine the class name of the .NET application window so that I can use the Win32 API function FindWindowEx to make one of the child windows active, and it works well. However, I'm having a problem when the application is running over RemoteApp.
I can still use the .NET Process.GetProcessesByName() to find the application, I just have to have it invoke mstsc.exe:
IntPtr hwndChild = IntPtr.Zero;
Process[] processess = Process.GetProcessesByName("mstsc");
IntPtr appHandle = IntPtr.Zero;
foreach (Process p in processess)
{
if ((p.MainWindowHandle != IntPtr.Zero))
{
appHandle = p.MainWindowHandle;
}
}
if (appHandle == IntPtr.Zero)
{
MessageBox.Show("Application is not Running.");
return;
}
However, I can't use FindWindowEx in the same way. This question revolves around that.
For the unmanaged code to tell me what windows mstsc.exe has active, I used Spy++, but for mstsc.exe it comes back with a different class name, called RAIL_WINDOW:
Here is the code I'm using to find the Child Window:
[DllImport("USER32.DLL")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);
hwndChild = FindWindowEx(appHandle, IntPtr.Zero, "RAIL_WINDOW", "MyApplication (Remote)");
SetForegroundWindow(hwndChild);
Questions
I can use Spy++ to highlight the active child window in the RemoteApp version of the application, and I get RAIL_WINDOW, but I cannot seem to access this window programmatically. Given the code above, what am I missing to be able to do so?
Are there other ways of sending keyboard strokes to an application running over Remote App?
Knowing how Microsoft does things, I'll bet the "rail window" is nothing more than a dumb, local proxy that doesn't bother responding to what SendKeys is sending. I haven't looked, but I'll bet that ends up sending WM_CHAR messages, to which a dumb proxy probably wouldn't bother responding. Instead, try sending it WM_KEYUP and WM_KEYDOWN messages manually and see if that works, given that I expect it would transmit those and mouse clicks (and what not) rather than the translated versions.
What commands are you sending using SendKeys()?
It may be better to look for an alternative solution instead of using `SendKeys()'.
And you can probably take advantage of handling IMsTscAxEvents::OnRemoteWindowDisplayed event that gives you the proper window handle at the right time without calling FindWindowEx, etc.

CreateProcessAsUser doesn't draw the GUI

I have a windows service running under "SYSTEM" account that checks if a specific application is running for each logged in user. If the application is not running, the service starts it (under corresponding user name).
I'm trying to accomplish my goal using CreateProcessAsUser(). The service does start the application under corresponding user name, but the GUI is not drawn. (Yes, I'm making sure that "Allow service to interact with desktop" check box is enabled).
System: XP SP3, language: C#
Here is some code that might be of interest:
PROCESS_INFORMATION processInfo = new PROCESS_INFORMATION();
startInfo.cb = Marshal.SizeOf(startInfo);
startInfo.lpDesktop = "winsta0\\default";
bResult = Win32.CreateProcessAsUser(hToken, null, strCommand, IntPtr.Zero, IntPtr.Zero, false, 0, IntPtr.Zero, null, ref startInfo, out processInfo);
As far as I understand, setting startInfo.lpDesktop = "winsta0\default"; should have used the desktop of corresponding user.
Even contrary to what is stated here: http://support.microsoft.com/kb/165194, I tried setting lpDesktop to null, or not setting it at all, both giving the same result: process was started in the name of expected user and I could see a part of window's title bar. The "invisible" window intercepts mouse click events, handles them as expected. It just doesn't draw itself.
Is anyone familiar with such a problem and knows what am I doing wrong?
MSDN has a sample of how to create a process as another user setting explicit permissions on the window station and desktop objects:
CreateProcessAsUser() windowstations and desktops
You can port the code to C# using P/Invoke or you could use a C++/CLI assembly.
However, be aware that your scenario is not supported and likely to break with Vista's (and Windows 7's) Session-0 isolation (download the whitepaper on the right).

Categories

Resources