C#编写的服务程序,用来每分钟一次地检测个USB设备是否被拨下,如果被拨下,就调用一个窗体程序,显示警告信息,并使蜂鸣器发声。因为需要访问局域网内其它电脑的资源,所以用来启动服务的用户帐户不是System(默认的System是没有网络访问权限的),而是另建立了一个管理员帐户,专门用来启动并登录此服务。由此,那个“允许服务与桌面交互”的选项是灰的,不能选的。
----------------以上是前提介绍-------------------------------为了能在服务里启动并显示报警窗体,程序调用了如下代码。问题就是,这段代码在win2000环境下是很正常的,窗体能显示出来,但是在winXP下就不行了,界面看不到,但确实是运行了的,进程里面有,请问有什么办法解决?
[System.Runtime.InteropServices.StructLayout(LayoutKind.Sequential)]
public class SECURITY_ATTRIBUTES     
{
    public int nLength;
    public string lpSecurityDescriptor;
    public bool bInheritHandle;
}[StructLayout(LayoutKind.Sequential)]
public struct STARTUPINFO
{
    public int cb;
    public string lpReserved;
    public string lpDesktop;
    public int lpTitle;
    public int dwX;
    public int dwY;
    public int dwXSize;
    public int dwYSize;
    public int dwXCountChars;
    public int dwYCountChars;
    public int dwFillAttribute;
    public int dwFlags;
    public int wShowWindow;
    public int cbReserved2;
    public byte lpReserved2;
    public IntPtr hStdInput;
    public IntPtr hStdOutput;
    public IntPtr hStdError;
}[StructLayout(LayoutKind.Sequential)]
public struct PROCESS_INFORMATION
{
    public IntPtr hProcess;
    public IntPtr hThread;
    public int dwProcessId;
    public int dwThreadId;
}
[DllImport("Kernel32.dll", CharSet = CharSet.Ansi)]
public static extern bool CreateProcess(
    StringBuilder lpApplicationName, StringBuilder lpCommandLine,
    SECURITY_ATTRIBUTES lpProcessAttributes,
    SECURITY_ATTRIBUTES lpThreadAttributes,
    bool bInheritHandles,
    int dwCreationFlags,
    StringBuilder lpEnvironment,
    StringBuilder lpCurrentDirectory,
    ref STARTUPINFO lpStartupInfo,
    ref PROCESS_INFORMATION lpProcessInformation
    );[DllImport("Kernel32.dll")]
public static extern uint WaitForSingleObject(System.IntPtr hHandle, uint dwMilliseconds);[DllImport("Kernel32.dll")]
public static extern bool CloseHandle(System.IntPtr hObject);[DllImport("Kernel32.dll")]
static extern bool GetExitCodeProcess(System.IntPtr hProcess, ref uint lpExitCode);/////////////////////////////////////////////////////////////////////////////////////////////////string argm = "调用的exe程序路径";
STARTUPINFO sInfo = new STARTUPINFO();
sInfo.lpDesktop = "Winsta0\\Default";
 PROCESS_INFORMATION pInfo = new PROCESS_INFORMATION();
 if (!CreateProcess(null, new StringBuilder(argm), null, null, false, 0, null, null, ref sInfo, ref pInfo))
 {
              throw new Exception("调用失败");
 }
  uint i = 0;
  WaitForSingleObject(pInfo.hProcess, int.MaxValue);
  GetExitCodeProcess(pInfo.hProcess, ref i);
  CloseHandle(pInfo.hProcess);
  CloseHandle(pInfo.hThread);

解决方案 »

  1.   

    记得系统服务里有个叫MESSAGE信使服务,与通知有关,看看它是否有被打开了
      

  2.   

    与Message服务也有关?我试下先!
      

  3.   

    你的实现走弯路了。最简单的就是使用System.Diagnosis.Process;示例代码如下:
    Process p = new Process();
    ...
    p.Start();
    p.WaitForExit();如果是.net 1.1就没有p.WaitForExit,但可以使用其它的方法来等待线程运行结束。参考Process的用法。
    http://www.cnblogs.com/qkhh/archive/2009/03/18/1415390.html
      

  4.   

    唉,还是不行,应该根本不是Messager服务的事吧,系统里都说明了,这个服务只是用来收发net send消息的。
      

  5.   

    你修改一下做个例子,尝试启动一个其他的软件比如notepad.exe看是否可以,然后检查一下你的程序?
      

  6.   

    To pengshan: 你可能没做过服务程序吧?自己试试你的方法!
      

  7.   

    其实方法也很多:1、如果是无人值守的机器,本机显示不是好办法,可以选择服务发信息给控制中心。
    2、如果机器需要用户登录,把检测程序放到用户启动项里,而不是做成服务。
    3、如果服务偶尔要显示信息,用WTSSendString API,该对话框会自动超时退出,不会永远阻碍服务。
    4、如果一定要创建用户桌面进程,则可以从服务里偷一个用户Token,然后CreateProcessAsUser。
      

  8.   

    更正#12WTSSendMessage
      

  9.   

    感谢gomoku提供的思路。关于我这个系统为什么要如此使用就不多说了,必须得这样。问题很奇怪,在2000里很正常,但在xp里,那个窗体界面程序是已经运行了的,进程里面有,而且界面肯定也已经打开了的。因为这个被调用的窗体程序是窗口置顶的,这时,鼠标已经点不到桌面上其它的程序了(被这个程序窗体挡住了),所以可以肯定这个窗体的界面其实已经出现了,只是看不到,就像这个窗体是完全透明的一样(实际上不是透明的)。
      

  10.   

    我将被调用的程序改为notepad.exe也一样,程序已经在运行了,任务栏里也有显示,但就是看不到界面,真是晕啊!
      

  11.   


    任务栏?底部?你点击一下看能否打开。如果可以,你用api:SetForegroundWindow试试。
      

  12.   

    会不会有可能是这样:因为我用的是另一个管理员级用记启动服务的,但是在服务中调用的窗体程序是用CreateProcess启动的,这样一来,是不是启动的那个窗体显示到登录到系统的用户桌面上去了?
      

  13.   

    原因终于找到了:服务是以另一个管理员帐户运行的,而登录系统用的又是另一个用户名,所以在调用窗体程序时,运行的窗体画面是显示到登录服务的帐户桌面上,因此在系统登录用户是看不到的。就算将登录系统和启动服务都用同一个用户,窗体还是看不到。将启动服务改为LocalSystem,窗体就可以显示出来了。但是LocalSystem是没有网络访问权限的,我在服务程序里需要访问到共享网络,因此目前还是没办法解决啊。
      

  14.   

    马甲继续。将服务帐户改为LocalSystem,窗体可以正常显示,但是不能访问网络。就想到在程序里先LogouUser一个管理员用户Token,然后DuplicateTokenEx、CreateEnvironmentBlock建立用户环境,在这个环境里用WNetAddConnection2A来建立网络盘的映射,但还是失败,返回1314错误码,有没有高手指教啊?