Automation and Spooler

  • Thread starter Thread starter Chris Miller
  • Start date Start date
C

Chris Miller

Hi Folks,

I have developed a port monitor with WebDAV behavior. One feature available
during port configuration is a "Test" button which automates IE and shows
the user a page from the webserver. That works. If I invoke the same code
from EndDocPort I get no failures from COM (ActiveX?) but the call to set
the instance visible has no effect -- I get no error and I also get no
visibility. I am able to fire up MessageBox displays.

My COM code is almost trivial -- 5 steps: Initialize COM, Create an
Instance, Allocate a BSTR, Call the Navigate Method of the instance, Set the
instance Visible.

Is there some subtlety about the spooler EndDocPort routine that I don't
understand? Can anybody see anything wrong in my code?



void Test(tstring *url)
{
HRESULT hr;
IWebBrowserApp* ie = NULL;
BSTR u;
VARIANT flags = {0};
VARIANT frame = {0};
VARIANT post = {0};
VARIANT hdr = {0};

if (FAILED(hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)))
{
SetLastError(hr);
Notify(_T("Test URL"), __LINE__);
}

if (FAILED(hr = CoCreateInstance(CLSID_InternetExplorer,
NULL,
CLSCTX_SERVER,
IID_IWebBrowserApp,
(LPVOID*)&ie)))
{
SetLastError(hr);
Notify(_T("Test URL"), __LINE__);
}

if ((u = SysAllocString(url->c_str())) == NULL){Notify(_T("Test URL"),
__LINE__);}

if (FAILED(hr = ie->Navigate(u, &flags, &frame, &post, &hdr)))
{
SetLastError(hr);
Notify(_T("Test URL"), __LINE__);
}

if (FAILED(hr = ie->put_Visible(VARIANT_TRUE)))
{
SetLastError(hr);
Notify(_T("Test URL"), __LINE__);
}
 
Hi Chris,
port monitors run in the spooler process with system account, which has
no Current User in the registry. Perhaps IE needs some information from
that place. You can try to copy some entries to HKEY_USERS\.Default
entry. Regmon can help you to identify needed entries.

Dieter
 
Hi Dieter,

Thanks for the response. I knew I was running is a system process, but I
wasn't sure why that should preclude IE from becoming visible but not
preclude MessageBoxes from appearing. I'm reluctant to try to trick Windows
into doing something that is apparently not a natural act and I am more
interested in understanding why windows thinks this is something that
shouldn't be done. You suggest a good experiment, but I can't help
believing that if it were that simple, IE would complain and I would have a
status code indicating the problem.

More and more I am considering that I probably really want to create a new
process for the user and fire up IE there. Can anybody advise me or provide
any examples?

Chris.
 
Hi Dieter,

Thanks so much. My research on RunAsEx is that it is not a WIN32 API -- at
least I didn't find it. The article seemed to describing a clever utility
that the author wrote. In my case, I need to step lightly on the user's
machine -- no registry hacks...

This is a new area for me. I can learn the identify of the printing user
from the JOB_INFO_* structure and with that I can get an SID from
LookupAccountName(). However, in order to CreateProcessAsUser(), I need a
token and it is not clear to me how to get one from the SID or even if I
need to start from the SID.

But I think I have a more fundamental question. Do I want to create a
process or should I create a thread? My expectations is that automating IE
will create a thread to run in any already existing IE process or create an
iexplorer.exe process if necessary. But I don't know this to be true -- I'm
guessing since I only ever see one iexplorer.exe process regardless of the
number of pages I am currently displaying. I still have the same user
identify/security groking issues...

Chris.
 
Hi Chris,
you can create a new thread and change the thread user with the
functions 'LogonUser' and 'ImpersonateLoggedOnUser'.
Or you use CreateProcessAsUser with the token from LogonUser.
"Redmon" is an example of a port monitor which uses
"OpenThreadToken" to get the token of the printer user.

You can experiment with redmon. It is possible to start a new
process, in your case "iexplore.exe <webpage>" with and without user
credentials.

Dieter
 
Hi Dieter,

I'm making some assumptions that may prove to be incorrect. For example.
I'm assuming that my current thread is not already impersonating the print
user. I may be wrong about that. How do I investigate the characteristics
of the thread?

If I *am* right than neither OpenThreadToken nor OpenProcessToken will get
me the token of the print user because they are both operating in the
context of the print spooler -- the print spooler token is probably all I
can get.

LogonUser seems to require that I know the user's password or I can get it.
I don't know it and I don't know where to get it, but I assume there must be
a way -- servers start sub-processes in the context of their users -- I just
don't know how to do it. Any advice?

CreateThread DOES have a way for me to specify an SID, but it is not clear
to me that this SID will be the execution context of the thread (hence the
first paragraph question about how to investigate the characteristics of the
thread) because I think I read that this SID restricts what the HANDLE
holder can do with the thread, not what the thread can do on the system. I
may be wrong about that also.

So, I need to learn how to investigate the current thread and how to get a
handle for the token for the user. I am beginning to suspect that I cannot
associate a thread with a user and I can only use the much more heavy handed
technique of creating a process. If I can use a thread, it is my
preference.

You've been very patient and I appreciate your help.

Chris.
 
Hi Chris,
you should really investigate time into examing "redmon".
You can easy find it with google.
In redmon.c there are functions GetSid, query_session_id,
RunProcessAsUser,...
You can decide to start a new process with system or printer
user account and see how this is done.
I think port monitors run with system account, whereas print processors
run with user account. In print processors you can simple change to
system account with 'RevertToPrinterSelf()' and back with
'ImpersonatePrinterClient()'. Perhaps this is possible with port
monitors, too.
Just create a new file and look at the owner of the new file to
determine the active sid.

Dieter
 
Hi Dieter,

I found redmon. I downloaded it and expanded the zip. I hacked the
makefile. I figured out how to build with a command line make. I built
ctags. I looked around.

I may have additional questions, but it looks to me like redmon will have an
example for everything I am trying to do.

Your advice to study this example is the best advice I have gotten from
anybody during this project. Thanks very much.

It is unusual, in my experience, that help comes from the newsgroups.
Generally there is a superficial response from someone who didn't read what
I wrote well enough to understand the question and that seems to stop others
from joining the thread. Engaging in a thoughtful discussion with someone
who seemed to understand the specifics of the problem was a welcome
counterexample.

Thanks for your help.

Chris.
 
Back
Top