CreateProcessWithLogonW

A

amdrit

Hello Everyone,

I have a C# component that is referenced by a VB6 standard executable. The
C# component has a method LaunchProcess that subsequently makes an API call
to CreateProcessWithLogonW in the advapi32 library. This is used to shell
open an external application such as Excel or Word with alternate
credentials than the logged in user.

I am encountering an issue where Excel and Word are initialized and show up
as processes for the impersonated user, but I am unable to interact with the
document. This only occurs in my target application, my stripped down test
application behaves as expected.

I am hoping someone has an idea of where to look. The calls are identical,
and only the target application has more bells and whistles on it.

I apologize if this post is rather large; I just wanted you all to have as
much information you needed. Again, this logic all works from a simple VB6
application (Form1, Button1_Click) and is giving me fits in the main
application. The main application has timers and back end processing going
at the same time. I figured having the document opened asynchronously would
be my redemption.

The functionality is new to the old VB6 application and new features are
implemented in .Net until everything is in .Net. I am fairly confident that
..Net is not my issue here. But who knows after spending three days solid on
this, I am not sure that I even have the correct API signature anymore.

In the VB6 code I have

[Reference to C# TLB]

Const DocumentName as string = \\uncpath\document.doc
Dim Executable as string * 255
Dim CleanExecutable as string
Dim i as Long
Dim objLauncher As DonNetCOM.Launcher
Set objLauncher = new DonNetCOM.Launcher

i = FindExecutable(DocumentName, "", Executable)

'Assuming FindExecutable always worked
CleanExecutable = TrimNulls(Executable)

Call objLauncher. CreateProcess("mydomain", "myusername", "mypassword",
CleanExecutable, DocumentName)

In C# code I have

[DllImport("advapi32.dll", SetLastError = true, CharSet =
CharSet.Unicode)]
private static extern bool CreateProcessWithLogonW(
String userName,
String domain,
String password,
UInt32 logonFlags,
String applicationName,
String commandLine,
UInt32 creationFlags,
UInt32 environment,
String currentDirectory,
ref StartupInfo startupInfo,
out ProcessInformation processInformation);

private class ProcessHelper
{
private string _domain; string _username; string _password; string _command;
string _commandLine; string _workDirectory;

public ProcessHelper(string domain; string username; string password; string
command; string commandLine;)
{
_username = username;
_password = password;
_domain = domain;
_command = command;
_commandLine = commandLine;
_workingDirectory = String.Empty;
}

Public void Launch()
{
StartupInfo startupInfo = new StartupInfo();
startupInfo.reserved = null;
startupInfo.flags &= Startf_UseStdHandles;
startupInfo.stdOutput = (IntPtr)StdOutputHandle;
startupInfo.stdError = (IntPtr)StdErrorHandle;

UInt32 exitCode = -1;
ProcessInformation processInfo = new ProcessInformation();
String paramaters = string.Format(" {0}", _commandLine);
String currentDirectory = this._workingDirectory;

bool epicFailure = false;

try
{
CreateProcessWithLogonW(
_username, _domain, _password, (UInt32)1,
_command, paramaters, (UInt32)0, (UInt32)0,
currentDirectory, ref startupInfo, out processInfo);
}
catch (Exception ex)
{
epicFailure = true;
throw ex;
}

Debug.WriteLine("Running ...");
WaitForSingleObject(processInfo.process, Infinite);
GetExitCodeProcess(processInfo.process, ref exitCode);
Debug.WriteLine("exitCode: " + exitCode.ToString());

CloseHandle(processInfo.process);
CloseHandle(processInfo.thread);

if (epicFailure == true)
{
throw new ApplicationException("Unable to create a new process.");
}

if (exitCode == -1)
{
throw new ApplicationException("Warehouse process didn't fire.
unknown error.");
}

//return true;
}
}

public void CreateProcess(string domain, string username, string password,
string command, string commandLine)
{

ProcessHelper lp = new ProcessHelper
(username,password,domain,command,commandLine);

Threading.ThreadStart ts = new Threading.ThreadStart(lp.Launch);
Threading.Thread t = new Threading.Thread(ts);
t.Start();
}


Thank you in advance
 
F

Family Tree Mike

amdrit said:
Hello Everyone,

I have a C# component that is referenced by a VB6 standard executable. The
C# component has a method LaunchProcess that subsequently makes an API call
to CreateProcessWithLogonW in the advapi32 library. This is used to shell
open an external application such as Excel or Word with alternate
credentials than the logged in user.

I am encountering an issue where Excel and Word are initialized and show up
as processes for the impersonated user, but I am unable to interact with the
document. This only occurs in my target application, my stripped down test
application behaves as expected.

In what way are you trying to interact with the document, through the user,
or through your vb6 app, or through the .net C# dll? Why do you need to
impersonate a different user to do this? Couldn't you just run the VB 6 app
as that user?
 
A

amdrit

First the goal is to replace the ShellExecute api. What we normally do is
shell out Word or Excel or Notepad with a target document for the user. The
reason I need impersonation is for the user to access restricted file shares
on the network. While I may have my own issues with the methodology, it was
one that was handed down to me. The user must be able to interact with the
shelled application.

I hope that enlightens you a little better.


Some things that I have noticed with the primary application are that it
makes use of subclassing and I wonder if that is what is causing my issues.
My issue with accepting that logic is that ShellExecute worked just fine
with that in place. Perhaps though when I call CreateProcessWithLogonW, it
is using the windows handle of the application launching it, and I should
figure out a way to assign a new context? I do not need this application to
wait for the shelled process to complete is that is of any help.

I have looked for other creation/desktop flags to use, none seem to be
relevant.

I am lost on ideas, anyone?
 
A

amdrit

shameless bump

I really appreciate any insight on this matter.


amdrit said:
Hello Everyone,

I have a C# component that is referenced by a VB6 standard executable.
The C# component has a method LaunchProcess that subsequently makes an API
call to CreateProcessWithLogonW in the advapi32 library. This is used to
shell open an external application such as Excel or Word with alternate
credentials than the logged in user.

I am encountering an issue where Excel and Word are initialized and show
up as processes for the impersonated user, but I am unable to interact
with the document. This only occurs in my target application, my stripped
down test application behaves as expected.

I am hoping someone has an idea of where to look. The calls are
identical, and only the target application has more bells and whistles on
it.

I apologize if this post is rather large; I just wanted you all to have as
much information you needed. Again, this logic all works from a simple
VB6 application (Form1, Button1_Click) and is giving me fits in the main
application. The main application has timers and back end processing
going at the same time. I figured having the document opened
asynchronously would be my redemption.

The functionality is new to the old VB6 application and new features are
implemented in .Net until everything is in .Net. I am fairly confident
that .Net is not my issue here. But who knows after spending three days
solid on this, I am not sure that I even have the correct API signature
anymore.

In the VB6 code I have

[Reference to C# TLB]

Const DocumentName as string = \\uncpath\document.doc
Dim Executable as string * 255
Dim CleanExecutable as string
Dim i as Long
Dim objLauncher As DonNetCOM.Launcher
Set objLauncher = new DonNetCOM.Launcher

i = FindExecutable(DocumentName, "", Executable)

'Assuming FindExecutable always worked
CleanExecutable = TrimNulls(Executable)

Call objLauncher. CreateProcess("mydomain", "myusername", "mypassword",
CleanExecutable, DocumentName)

In C# code I have

[DllImport("advapi32.dll", SetLastError = true, CharSet =
CharSet.Unicode)]
private static extern bool CreateProcessWithLogonW(
String userName,
String domain,
String password,
UInt32 logonFlags,
String applicationName,
String commandLine,
UInt32 creationFlags,
UInt32 environment,
String currentDirectory,
ref StartupInfo startupInfo,
out ProcessInformation processInformation);

private class ProcessHelper
{
private string _domain; string _username; string _password; string
_command; string _commandLine; string _workDirectory;

public ProcessHelper(string domain; string username; string password;
string command; string commandLine;)
{
_username = username;
_password = password;
_domain = domain;
_command = command;
_commandLine = commandLine;
_workingDirectory = String.Empty;
}

Public void Launch()
{
StartupInfo startupInfo = new StartupInfo();
startupInfo.reserved = null;
startupInfo.flags &= Startf_UseStdHandles;
startupInfo.stdOutput = (IntPtr)StdOutputHandle;
startupInfo.stdError = (IntPtr)StdErrorHandle;

UInt32 exitCode = -1;
ProcessInformation processInfo = new ProcessInformation();
String paramaters = string.Format(" {0}", _commandLine);
String currentDirectory = this._workingDirectory;

bool epicFailure = false;

try
{
CreateProcessWithLogonW(
_username, _domain, _password, (UInt32)1,
_command, paramaters, (UInt32)0, (UInt32)0,
currentDirectory, ref startupInfo, out processInfo);
}
catch (Exception ex)
{
epicFailure = true;
throw ex;
}

Debug.WriteLine("Running ...");
WaitForSingleObject(processInfo.process, Infinite);
GetExitCodeProcess(processInfo.process, ref exitCode);
Debug.WriteLine("exitCode: " + exitCode.ToString());

CloseHandle(processInfo.process);
CloseHandle(processInfo.thread);

if (epicFailure == true)
{
throw new ApplicationException("Unable to create a new
process.");
}

if (exitCode == -1)
{
throw new ApplicationException("Warehouse process didn't fire.
unknown error.");
}

//return true;
}
}

public void CreateProcess(string domain, string username, string password,
string command, string commandLine)
{

ProcessHelper lp = new ProcessHelper
(username,password,domain,command,commandLine);

Threading.ThreadStart ts = new Threading.ThreadStart(lp.Launch);
Threading.Thread t = new Threading.Thread(ts);
t.Start();
}


Thank you in advance
 
W

Willy Denoyette [MVP]

amdrit said:
shameless bump

I really appreciate any insight on this matter.

You will have to tell us exactly what you mean with "I am unable to interact
with the document. "


Willy.
 
P

Phil Wilson

Some of this behavior is by design, but unfortunately I don't know the exact
details. My initial reaction was that this should never work - the
interactive user owns the desktop, and an app running with another account
cannot interact with the desktop. Example: If you use Accessories-System
Tools-Scheduled Tasks to run Notepad with another account you will not see
notepad's UI when it runs, just the process in Task Manager running with the
other account.
So I don't know why your stripped down test app works, unless the account
you're using to fire off the app is actually your account and not another
one. Have you actually looked in Task Manager and seen that your test app
has really really fired off that other process with a different account and
you can interact with it from the desktop?
--
Phil Wilson
[MVP Windows Installer]

amdrit said:
Hello Everyone,

I have a C# component that is referenced by a VB6 standard executable.
The C# component has a method LaunchProcess that subsequently makes an API
call to CreateProcessWithLogonW in the advapi32 library. This is used to
shell open an external application such as Excel or Word with alternate
credentials than the logged in user.

I am encountering an issue where Excel and Word are initialized and show
up as processes for the impersonated user, but I am unable to interact
with the document. This only occurs in my target application, my stripped
down test application behaves as expected.

I am hoping someone has an idea of where to look. The calls are
identical, and only the target application has more bells and whistles on
it.

I apologize if this post is rather large; I just wanted you all to have as
much information you needed. Again, this logic all works from a simple
VB6 application (Form1, Button1_Click) and is giving me fits in the main
application. The main application has timers and back end processing
going at the same time. I figured having the document opened
asynchronously would be my redemption.

The functionality is new to the old VB6 application and new features are
implemented in .Net until everything is in .Net. I am fairly confident
that .Net is not my issue here. But who knows after spending three days
solid on this, I am not sure that I even have the correct API signature
anymore.

In the VB6 code I have

[Reference to C# TLB]

Const DocumentName as string = \\uncpath\document.doc
Dim Executable as string * 255
Dim CleanExecutable as string
Dim i as Long
Dim objLauncher As DonNetCOM.Launcher
Set objLauncher = new DonNetCOM.Launcher

i = FindExecutable(DocumentName, "", Executable)

'Assuming FindExecutable always worked
CleanExecutable = TrimNulls(Executable)

Call objLauncher. CreateProcess("mydomain", "myusername", "mypassword",
CleanExecutable, DocumentName)

In C# code I have

[DllImport("advapi32.dll", SetLastError = true, CharSet =
CharSet.Unicode)]
private static extern bool CreateProcessWithLogonW(
String userName,
String domain,
String password,
UInt32 logonFlags,
String applicationName,
String commandLine,
UInt32 creationFlags,
UInt32 environment,
String currentDirectory,
ref StartupInfo startupInfo,
out ProcessInformation processInformation);

private class ProcessHelper
{
private string _domain; string _username; string _password; string
_command; string _commandLine; string _workDirectory;

public ProcessHelper(string domain; string username; string password;
string command; string commandLine;)
{
_username = username;
_password = password;
_domain = domain;
_command = command;
_commandLine = commandLine;
_workingDirectory = String.Empty;
}

Public void Launch()
{
StartupInfo startupInfo = new StartupInfo();
startupInfo.reserved = null;
startupInfo.flags &= Startf_UseStdHandles;
startupInfo.stdOutput = (IntPtr)StdOutputHandle;
startupInfo.stdError = (IntPtr)StdErrorHandle;

UInt32 exitCode = -1;
ProcessInformation processInfo = new ProcessInformation();
String paramaters = string.Format(" {0}", _commandLine);
String currentDirectory = this._workingDirectory;

bool epicFailure = false;

try
{
CreateProcessWithLogonW(
_username, _domain, _password, (UInt32)1,
_command, paramaters, (UInt32)0, (UInt32)0,
currentDirectory, ref startupInfo, out processInfo);
}
catch (Exception ex)
{
epicFailure = true;
throw ex;
}

Debug.WriteLine("Running ...");
WaitForSingleObject(processInfo.process, Infinite);
GetExitCodeProcess(processInfo.process, ref exitCode);
Debug.WriteLine("exitCode: " + exitCode.ToString());

CloseHandle(processInfo.process);
CloseHandle(processInfo.thread);

if (epicFailure == true)
{
throw new ApplicationException("Unable to create a new
process.");
}

if (exitCode == -1)
{
throw new ApplicationException("Warehouse process didn't fire.
unknown error.");
}

//return true;
}
}

public void CreateProcess(string domain, string username, string password,
string command, string commandLine)
{

ProcessHelper lp = new ProcessHelper
(username,password,domain,command,commandLine);

Threading.ThreadStart ts = new Threading.ThreadStart(lp.Launch);
Threading.Thread t = new Threading.Thread(ts);
t.Start();
}


Thank you in advance
 
W

Willy Denoyette [MVP]

Phil Wilson said:
Some of this behavior is by design, but unfortunately I don't know the
exact details. My initial reaction was that this should never work - the
interactive user owns the desktop, and an app running with another
account cannot interact with the desktop. Example: If you use
Accessories-System Tools-Scheduled Tasks to run Notepad with another
account you will not see notepad's UI when it runs, just the process in
Task Manager running with the other account.

TaskMan runs in a "Service" account (or the System account, depending on the
OS version) attached to a non interactive desktop, processes launched by
Taskman share this non-interactive desktop.
Processes started with CreateProcessWithLogonW run in the winstation\desktop
of the parent process, if this one happens to be the winsta0\default (the
interactive) desktop, then the child process will run in the interactive
desktop too. No one stops you from having different accounts running in the
default desktop.
Note that it's not necessary to PInvoke "CreateProcessWithLogonW" on V2 of
the framework, this API is now wrapped by the Process an ProcessStartInfo
classes in System.Diagnostics.


Willy.
 
A

amdrit

Oh good, reaction. I love it.

Ok to answer you Phil, yes I have looked in task manager and seen my process
running under another account. I can provide a screen capture to demontrate
it you'd like. What's more, if you right click on any EXE your context menu
gives you the option to Run As (another user account, usually so you can
elevate yourself in the permissions list). What I am attempting here is no
different.

What I mean by "I cannot interact with the launched application" is that I
see the splash screen and some kind of border where the application is
resting on my screen. Pressing ALT+F4 closes the application, but I can not
see it (kinda like a repaint hasn't been fired yet.) I think this is
because my shelled application is tied to my host application's device
context, which is capturing windows messages and handeling certain ones
itself. Looking into the way I call ShellExecute I see that I create a new
device handle before calling shell. So I am certian that my problem exists
in this neiborhood.

Looking at CreateProcessAsUser API, I see the Security_Attributes structure
and it allows for a handle. However, it seems to me that
CreateProcessAsUser requires the impernation account to act as part of the
operating system, which I think is too great a permission for this user.

It seems that CreateProcessWithLogonW is the way to go, I can be swayed for
a working solution, I just need to figure out how to change it's device
context. Since CreateProcessWithLogonW is not included in my API viewer,
and documentation isn't all that clear, I don't really know where to start.
I have seen some honorable mentions to Karl Petersen and Randy Birch on the
subject, but nothing really stood out as a fix for me. As far as
CreateProcessWithLogonW, I have two structures STARTUPINFO and
PROCESSINFORMATION and I also have dwCreationFlags.

With dwCreationFlags, I can set Create_New_Console (&H10) were I am
currently using &H0.
With StartUpInformation, I can specify handle pointers, but I don't know to
what other than the constants.

So, I am off to try setting the creationflags, while I wait for more input
from you guys.


Phil Wilson said:
Some of this behavior is by design, but unfortunately I don't know the
exact details. My initial reaction was that this should never work - the
interactive user owns the desktop, and an app running with another
account cannot interact with the desktop. Example: If you use
Accessories-System Tools-Scheduled Tasks to run Notepad with another
account you will not see notepad's UI when it runs, just the process in
Task Manager running with the other account.
So I don't know why your stripped down test app works, unless the account
you're using to fire off the app is actually your account and not another
one. Have you actually looked in Task Manager and seen that your test app
has really really fired off that other process with a different account
and you can interact with it from the desktop?
--
Phil Wilson
[MVP Windows Installer]

amdrit said:
Hello Everyone,

I have a C# component that is referenced by a VB6 standard executable.
The C# component has a method LaunchProcess that subsequently makes an
API call to CreateProcessWithLogonW in the advapi32 library. This is
used to shell open an external application such as Excel or Word with
alternate credentials than the logged in user.

I am encountering an issue where Excel and Word are initialized and show
up as processes for the impersonated user, but I am unable to interact
with the document. This only occurs in my target application, my
stripped down test application behaves as expected.

I am hoping someone has an idea of where to look. The calls are
identical, and only the target application has more bells and whistles on
it.

I apologize if this post is rather large; I just wanted you all to have
as much information you needed. Again, this logic all works from a
simple VB6 application (Form1, Button1_Click) and is giving me fits in
the main application. The main application has timers and back end
processing going at the same time. I figured having the document opened
asynchronously would be my redemption.

The functionality is new to the old VB6 application and new features are
implemented in .Net until everything is in .Net. I am fairly confident
that .Net is not my issue here. But who knows after spending three days
solid on this, I am not sure that I even have the correct API signature
anymore.

In the VB6 code I have

[Reference to C# TLB]

Const DocumentName as string = \\uncpath\document.doc
Dim Executable as string * 255
Dim CleanExecutable as string
Dim i as Long
Dim objLauncher As DonNetCOM.Launcher
Set objLauncher = new DonNetCOM.Launcher

i = FindExecutable(DocumentName, "", Executable)

'Assuming FindExecutable always worked
CleanExecutable = TrimNulls(Executable)

Call objLauncher. CreateProcess("mydomain", "myusername", "mypassword",
CleanExecutable, DocumentName)

In C# code I have

[DllImport("advapi32.dll", SetLastError = true, CharSet =
CharSet.Unicode)]
private static extern bool CreateProcessWithLogonW(
String userName,
String domain,
String password,
UInt32 logonFlags,
String applicationName,
String commandLine,
UInt32 creationFlags,
UInt32 environment,
String currentDirectory,
ref StartupInfo startupInfo,
out ProcessInformation processInformation);

private class ProcessHelper
{
private string _domain; string _username; string _password; string
_command; string _commandLine; string _workDirectory;

public ProcessHelper(string domain; string username; string password;
string command; string commandLine;)
{
_username = username;
_password = password;
_domain = domain;
_command = command;
_commandLine = commandLine;
_workingDirectory = String.Empty;
}

Public void Launch()
{
StartupInfo startupInfo = new StartupInfo();
startupInfo.reserved = null;
startupInfo.flags &= Startf_UseStdHandles;
startupInfo.stdOutput = (IntPtr)StdOutputHandle;
startupInfo.stdError = (IntPtr)StdErrorHandle;

UInt32 exitCode = -1;
ProcessInformation processInfo = new ProcessInformation();
String paramaters = string.Format(" {0}", _commandLine);
String currentDirectory = this._workingDirectory;

bool epicFailure = false;

try
{
CreateProcessWithLogonW(
_username, _domain, _password, (UInt32)1,
_command, paramaters, (UInt32)0, (UInt32)0,
currentDirectory, ref startupInfo, out processInfo);
}
catch (Exception ex)
{
epicFailure = true;
throw ex;
}

Debug.WriteLine("Running ...");
WaitForSingleObject(processInfo.process, Infinite);
GetExitCodeProcess(processInfo.process, ref exitCode);
Debug.WriteLine("exitCode: " + exitCode.ToString());

CloseHandle(processInfo.process);
CloseHandle(processInfo.thread);

if (epicFailure == true)
{
throw new ApplicationException("Unable to create a new
process.");
}

if (exitCode == -1)
{
throw new ApplicationException("Warehouse process didn't fire.
unknown error.");
}

//return true;
}
}

public void CreateProcess(string domain, string username, string
password, string command, string commandLine)
{

ProcessHelper lp = new ProcessHelper
(username,password,domain,command,commandLine);

Threading.ThreadStart ts = new Threading.ThreadStart(lp.Launch);
Threading.Thread t = new Threading.Thread(ts);
t.Start();
}


Thank you in advance
 
W

Willy Denoyette [MVP]

amdrit said:
Oh good, reaction. I love it.

Ok to answer you Phil, yes I have looked in task manager and seen my
process running under another account. I can provide a screen capture to
demontrate it you'd like. What's more, if you right click on any EXE your
context menu gives you the option to Run As (another user account, usually
so you can elevate yourself in the permissions list). What I am attempting
here is no different.

What I mean by "I cannot interact with the launched application" is that I
see the splash screen and some kind of border where the application is
resting on my screen. Pressing ALT+F4 closes the application, but I can
not see it (kinda like a repaint hasn't been fired yet.) I think this is
because my shelled application is tied to my host application's device
context, which is capturing windows messages and handeling certain ones
itself. Looking into the way I call ShellExecute I see that I create a
new device handle before calling shell. So I am certian that my problem
exists in this neiborhood.

This is different from what you said in your first post: "I am unable to
interact
with the document. " now you are saying "I cannot interact with the launched
application". Are you still talking about launching Word & Excel?
Another question is where "ShellExecute" comes into play, I thought you
were using CreateProcessWithLogonW to start another process running with
different credentials than the logged-on user.
And what account are you using to start Word/Excel, is this a local account
or a domain account?
So, from what I understand and what I suppose hereafter, is that your
(failing) scenario looks like this:
1. A VB6 application that calls into a .NET C# DLL using COM interop.
2. The COM exposed .NET DLL, calls CreateProcessWithLogonW to launch
another application (Word or Excel) to run as a different user.
3. Word or Excel comes up but fails to (completely) draw it's main form,
focus is set to the main form because it's possible to close the application
(ALT/F4).

In this scenario there is no sharing of "device contexts" as you may assume,
each process (VB6 and Word/Excel) run in a completely different context.
Also, you should not shell-out an Office like application using
CreateProcessWithLogonW, without loading the profile of the "other" user.
When calling "CreateProcessWithLogonW" to run an application under "another"
account without loading the profile, the application will get the "default"
profile and environment loaded in the process, this is NOT the
environment/profile of the "other" user. Office application may not run as
expected with this profile.
From your description it looks like the shelled application is not
completely initialized, but I can't imagine the reason without seeing your
"failing" code, or a more precise description of what you are doing in your
failing code.

Willy.
 
A

amdrit

Willy I appreciate your comments.

Below, I have attached my original Process.Start code for native .Net. This
is where I started from and immediately recieved the issue I am posting
about.

I may have mispoken about the description of the error, I should know better
having heard it a million times from users and the help desk. You are
correct, I can (if I focus real hard) interact with say the Excel menu bar
to close the application. The fact that the application never fully paints
makes me think that it hasn't fully initialized, but I shouldn't be able to
interact with it then.

Perhaps, I slipped in quietly that this new functionality is replacing the
ShellExecute API. It is doing that because the logged on user will not have
access to a network share and will need to provide them access via this new
logic. Let's forget about office for the moment, because the same thing
happens with Notepad. The point is, that when I call the code from a
vanilla VB6 application with nothing more than a button and a click event
handler, this works fine. This doesn't work from within my target
application, while ShellExecute does. While, I originally had LoadProfile
enabled in the .Net code, I opted not to mess with Profile API's when I went
to the CreateProcessWithLogon API since I can replicate my problem with
Notepad.

The thing that gets me the most about the .Net code is that I have it set to
maximize the shelled application and it clearly does not.

//Inside a try block

SecureString ss = new SecureString();
System.Diagnostics.Process p;

foreach (char c in _password.ToCharArray())
{
ss.AppendChar(c);
}

System.Diagnostics.ProcessStartInfo psi=new
ProcessStartInfo(_command,paramaters);
psi.UseShellExecute = false;
psi.UserName = _username;
psi.Password = ss;
psi.Domain = _domain;
psi.LoadUserProfile = true;
psi.WindowStyle = ProcessWindowStyle.Maximized;

p = System.Diagnostics.Process.Start(psi);
p.WaitForInputIdle();
p.WaitForExit();
 
W

Willy Denoyette [MVP]

amdrit said:
Willy I appreciate your comments.

Below, I have attached my original Process.Start code for native .Net.
This is where I started from and immediately recieved the issue I am
posting about.

I may have mispoken about the description of the error, I should know
better having heard it a million times from users and the help desk. You
are correct, I can (if I focus real hard) interact with say the Excel menu
bar to close the application. The fact that the application never fully
paints makes me think that it hasn't fully initialized, but I shouldn't be
able to interact with it then.

Perhaps, I slipped in quietly that this new functionality is replacing the
ShellExecute API. It is doing that because the logged on user will not
have access to a network share and will need to provide them access via
this new logic. Let's forget about office for the moment, because the
same thing happens with Notepad. The point is, that when I call the code
from a vanilla VB6 application with nothing more than a button and a click
event handler, this works fine. This doesn't work from within my target
application, while ShellExecute does. While, I originally had LoadProfile
enabled in the .Net code, I opted not to mess with Profile API's when I
went to the CreateProcessWithLogon API since I can replicate my problem
with Notepad.

The thing that gets me the most about the .Net code is that I have it set
to maximize the shelled application and it clearly does not.

//Inside a try block

SecureString ss = new SecureString();
System.Diagnostics.Process p;

foreach (char c in _password.ToCharArray())
{
ss.AppendChar(c);
}

System.Diagnostics.ProcessStartInfo psi=new
ProcessStartInfo(_command,paramaters);
psi.UseShellExecute = false;
psi.UserName = _username;
psi.Password = ss;
psi.Domain = _domain;
psi.LoadUserProfile = true;
psi.WindowStyle = ProcessWindowStyle.Maximized;

p = System.Diagnostics.Process.Start(psi);
p.WaitForInputIdle();
p.WaitForExit();


This works for me:

// startnotepad.cs
using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Collections;
using System.Diagnostics;
namespace Willys
{
class Program
{
static void Main()
{
string pwd = "SomeSecret";
ProcessStartInfo myProcess = new ProcessStartInfo();
myProcess.UserName = "someUser";
myProcess.Domain="somedomain";
myProcess.Password = new System.Security.SecureString();
foreach(char c in pwd)
myProcess.Password.AppendChar(c);
myProcess.FileName = "notepad.exe";
myProcess.Arguments = "startnotepad.cs"; // open this file
myProcess.UseShellExecute = false;
myProcess.LoadUserProfile = true;
Process p = Process.Start(myProcess);
Thread.Sleep(1000); // give the process some time to start it's
message loop, else the WaitForInputIdle will throw
p.WaitForInputIdle();
p.WaitForExit();
}
}
}


Setting the WindowsStyle when starting a new process makes little sense, in
general this is overruled by the process itself which initializes it's GUI
with values taken from the user's profile.

Willy.
 
A

amdrit

Willy having the thread sleep made no difference. This is akin to the
floating point issues people ask about all the time (why doesn't 2+2 =4,
where is 3.967845345 coming from), then everyone links an article on IEEE
floating precision and remind developers to use integers or decimals not to
use doubles. In a perfect world, both code snippets work fine. The problem
only occurs in my target application and I am hoping someone has a magic
article that says what I am doing wrong.

My target application has aged since '95 and has a lot of moving pieces,
custom components and the like. I am sure something was done at one time
that has led to this issue. What I am looking for are reasons why your code
doesn't behave as expected. If I were to get errors I can chase them down,
or at I can chase red herrings. As it is now, it isn't working and I have
nothing to chase.
 
W

Willy Denoyette [MVP]

See inline.

Willy.

amdrit said:
Willy having the thread sleep made no difference.

I did not say this was the solution for you problem, I only mean that you
should wait before calling WaitForInputIdle, until the other application
has finished to initialize and run it's message loop. Initializing includes
loading thye profile from the logon server (when dealing with a domain
user).

This is akin to the
floating point issues people ask about all the time (why doesn't 2+2 =4,
where is 3.967845345 coming from), then everyone links an article on IEEE
floating precision and remind developers to use integers or decimals not
to use doubles. In a perfect world, both code snippets work fine. The
problem only occurs in my target application and I am hoping someone has a
magic article that says what I am doing wrong.

My target application has aged since '95 and has a lot of moving pieces,
custom components and the like. I am sure something was done at one time
that has led to this issue. What I am looking for are reasons why your
code doesn't behave as expected.

Hm.... My code behaves as expected, it works, and that's what I'm
expecting.
..

If I were to get errors I can chase them down,
or at I can chase red herrings. As it is now, it isn't working and I have
nothing to chase.

I don't understand, really. In your pervious post you said "Below, I have
attached my original Process.Start code for native .Net.
This is where I started from and immediately recieved the issue I am
posting about."
From this quote I assumed that the code YOU posted would illustrate the
issue, no matter what program you were shelling-out, however, it doesn't
illustrate the issue, it works as I would have expected, as shown by the
(basically) same code I posted.
Anyway, I'm still not clear on what you meant with the message in your
original post "Can not interact with ...", so it's hard for me to give you a
clue, other than the profile/environment stuff.

Willy.
 
E

expvb

What you are experiencing is a security feature in Windows 2000+. If one
application uses SetWindowsHookEx() to hook another application run by a
different user, the hook fails, even if the target process is visible and on
the same desktop. I just tried this with Notepad, it works fine when I start
it as the same user, and doesn't work when I use Run As to start it as a
different user(tried Administrator and Power User). I am logged in using an
account that is a member of the Administrators group. SetWindowsHookEx()
returns 0 in these cases and GetLastError() returns 5, Access is denied,
ERROR_ACCESS_DENIED. The hook procedure is in a C++ DLL.

Also, in Vista and later, SendMessage can only send messages to processes
with the same privilege or lower, otherwise it fails with error access
denied. See here:

SendMessage Function
http://msdn2.microsoft.com/en-us/library/ms644950.aspx

Finally, while on the same subject GUI and security, staring with Vista;
services run in their own terminal services session for security reasons, so
services that create a hidden window to let other applications talk to it
using SendMessage(To configure the service, for example) will be blocked
from receiving such messages in Vista and after. You have to use another
method like named pipes. See here:

AC: Session 0 Isolation
http://msdn2.microsoft.com/en-us/library/bb756986.aspx
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top