首页 > 解决方案 > 如何在 C# Windows 服务应用程序中使用 Win32Api

问题描述

我正在 Visual Studio 中创建一个 Windows 服务应用程序,我想获取当前活动的窗口标题。下面是我尝试过的代码,但函数 GetForegroundWindow() 每次都返回 0。windows服务中使用win32api可以吗?

public partial class My_Service: ServiceBase
{
    Timer timer = new Timer();
    [DllImport("User32.dll")]
    static extern IntPtr GetForegroundWindow();

    [DllImport("User32.dll")]
    static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);

    public My_Service()
    {
        InitializeComponent();
    }

    protected override void OnStart(string[] args)
    {
        WriteToFile("Service is started at " + DateTime.Now);
        timer.Elapsed += new ElapsedEventHandler(OnElapsedTime);
        timer.Interval = 10000; //number in milisecinds  
        timer.Enabled = true;
    }

    protected override void OnStop()
    {
        WriteToFile("Service is stopped at " + DateTime.Now);
    }

    private void OnElapsedTime(object source, ElapsedEventArgs e)
    {
        string title = GetActivewindow();
        WriteToFile("Service is recall at " + title + DateTime.Now);

    }

    public void WriteToFile(string Message)
    {
       ....
    }

    public string GetActivewindow()
    {
        const int nChars = 256;
        StringBuilder buff = new StringBuilder(nChars);
        string title = "- ";
        IntPtr handle; 
        handle = GetForegroundWindow();
        if( GetWindowText(handle,buff,nChars) > 0)
        {
            title = buff.ToString();
        }
        return title;
    }
}

标签: c#winapiwindows-services

解决方案


作为评论,也根据文档:关于 Window Stations and Desktops - Window Station and Desktop Creation

您的服务可能正在运行Service-0x0-3e7$\default,但您要检索的前台窗口位于交互式窗口站 ( Winsta0\default)的默认桌面中

交互式窗口站是唯一可以显示用户界面或接收用户输入的窗口站。它分配给交互式用户的登录会话,并包含键盘、鼠标和显示设备。它始终命名为“WinSta0”。所有其他窗口站都是非交互式的,这意味着它们不能显示用户界面或接收用户输入。

这意味着您不能GetForegroundWindow直接从服务中使用。您可以在其中创建一个子进程Winsta0\default并重定向其输出。然后调用GetForegroundWindow子进程并输出。

示例(删除错误检查):

孩子:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.IO;
using System.Threading;
namespace ConsoleApp1
{
    class Program
    {
        [DllImport("User32.dll")]
        static extern IntPtr GetForegroundWindow();

        [DllImport("User32.dll")]
        static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
        static void Main(string[] args)
        {
            const int nChars = 256;
            StringBuilder buff = new StringBuilder(nChars);
            string title = "- ";
            IntPtr handle;
            handle = GetForegroundWindow();
            if (GetWindowText(handle, buff, nChars) > 0)
            {
                title = buff.ToString();
            }
            Console.WriteLine(title);
            return;
        }
    }
}

服务:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.IO;
using System.Diagnostics.Tracing;

namespace WindowsService3
{
    public partial class MyNewService : ServiceBase
    {
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        internal struct STARTUPINFO
        {
            public Int32 cb;
            public string lpReserved;
            public string lpDesktop;
            public string lpTitle;
            public Int32 dwX;
            public Int32 dwY;
            public Int32 dwXSize;
            public Int32 dwYSize;
            public Int32 dwXCountChars;
            public Int32 dwYCountChars;
            public Int32 dwFillAttribute;
            public Int32 dwFlags;
            public Int16 wShowWindow;
            public Int16 cbReserved2;
            public IntPtr lpReserved2;
            public IntPtr hStdInput;
            public IntPtr hStdOutput;
            public IntPtr hStdError;
        }
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        internal struct PROCESS_INFORMATION
        {
            public IntPtr hProcess;
            public IntPtr hThread;
            public Int32 dwProcessId;
            public Int32 dwThreadId;
        }
        [StructLayout(LayoutKind.Sequential)]
        public struct SECURITY_ATTRIBUTES
        {
            public int nLength;
            public IntPtr lpSecurityDescriptor;
            public int bInheritHandle;
        }


        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern bool CreateProcessAsUser(
            IntPtr hToken,
            string lpApplicationName,
            string lpCommandLine,
            IntPtr lpProcessAttributes,
            IntPtr lpThreadAttributes,
            bool bInheritHandles,
            uint dwCreationFlags,
            IntPtr lpEnvironment,
            IntPtr lpCurrentDirectory,
            ref STARTUPINFO lpStartupInfo,
            out PROCESS_INFORMATION lpProcessInformation);
        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern bool CreatePipe(
            ref IntPtr hReadPipe,
            ref IntPtr hWritePipe,
            ref SECURITY_ATTRIBUTES lpPipeAttributes,
            uint nSize);
        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern bool ReadFile(
            IntPtr hFile,
            byte[] lpBuffer,
            uint nNumberOfBytesToRead,
            out uint lpNumberOfBytesRead,
            IntPtr lpOverlapped);
        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern bool CloseHandle(IntPtr hObject);
        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern uint WTSGetActiveConsoleSessionId();
        [DllImport("Wtsapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern bool WTSQueryUserToken(UInt32 SessionId, out IntPtr hToken);

        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern uint WaitForSingleObject(IntPtr hProcess, uint dwMilliseconds);
        public MyNewService()
        {
            InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
            System.Diagnostics.Debugger.Launch();
            using (StreamWriter sw = File.CreateText("Path\\Log.txt"))
            {
                IntPtr read = new IntPtr();
                IntPtr write = new IntPtr();
                IntPtr read2 = new IntPtr();
                IntPtr write2 = new IntPtr();
                SECURITY_ATTRIBUTES saAttr = new SECURITY_ATTRIBUTES();
                saAttr.nLength = Marshal.SizeOf(typeof(SECURITY_ATTRIBUTES));
                saAttr.bInheritHandle = 1;
                saAttr.lpSecurityDescriptor = IntPtr.Zero;

                CreatePipe(ref read, ref write, ref saAttr, 0);
                CreatePipe(ref read2, ref write2, ref saAttr, 0);

                uint CREATE_NO_WINDOW = 0x08000000;
                int STARTF_USESTDHANDLES = 0x00000100;
                STARTUPINFO si = new STARTUPINFO();
                si.cb = Marshal.SizeOf(typeof(STARTUPINFO));
                si.hStdOutput = write;
                si.hStdError = write;
                si.hStdInput = read2;
                si.lpDesktop = "Winsta0\\default";
                si.dwFlags = STARTF_USESTDHANDLES;
                PROCESS_INFORMATION pi;

                IntPtr hToken;
                bool err = WTSQueryUserToken(WTSGetActiveConsoleSessionId(), out hToken);
                string path = "Path\\ConsoleApp1.exe";
                if (CreateProcessAsUser(hToken, path, null, IntPtr.Zero, IntPtr.Zero, true, CREATE_NO_WINDOW, IntPtr.Zero, IntPtr.Zero, ref si, out pi))
                {
                    uint ret = WaitForSingleObject(pi.hProcess, 2000); //wait for the child process exit.
                    if (ret == 0)
                    {
                        byte[] title = new byte[200];
                        uint reads = 0;
                        CloseHandle(write);
                        err = ReadFile(read, title, 200, out reads, IntPtr.Zero);
                        string result = System.Text.Encoding.UTF8.GetString(title).Replace("\0","").Replace("\r", "").Replace("\n", "");

                        sw.WriteLine(result);

                    }
                }
                CloseHandle(read2);
                CloseHandle(write2);
                CloseHandle(read);
            }

        }

        protected override void OnStop()
        {

        }
    }
}

推荐阅读