定位Windows系统日期时间窗口

时间:2017-12-15 16:21:04

标签: c# winforms

下面的事件方法会显示Windows系统日期时间窗口。我的标签位于表单的右下方,系统日期时间窗口出现在表单的左上方。当点击此事件处理程序时,有没有办法将此日期时间窗口定位在表单的右下方?

    private void LabelDateTime_Click(object sender, System.EventArgs e)
    {
        // bring up the date & time dialog
        System.Diagnostics.Process.Start("timedate.cpl");
    }

1 个答案:

答案 0 :(得分:0)

以这种方式使用System.Diagnostics.Process.Start()启动进程无效,因为生成的进程将在创建窗口后立即退出。 .cpl applet不是标准的可执行文件,需要操作系统shell和启动器才能启动。

但是,可以使用Rundll32.exe创建一个稳定的进程,这将生成一些线程来托管applet控件和GDI +支持。
但是,到达小程序窗口需要一些P / Invoke(ing),因为rundll是无窗口的,并且它没有引用它帮助创建的那个,所以Process.MainWindowHandle = 0

Doc Ref。 MSDN EnumThreadWndProc() CallbackEnumThreadWindows()GetWindowRect()GetWindowText()SetWindowPos()

using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;

ProcessStartInfo psInfo = new ProcessStartInfo() {
    UseShellExecute = true,
    FileName = "rundll32.exe",
    Arguments = "shell32.dll, Control_RunDLL timedate.cpl,,0", //<- 0 = First Tab
    WindowStyle = ProcessWindowStyle.Normal
};

Process sysClockProcess = new Process() {
    SynchronizingObject = this,
    EnableRaisingEvents = true,
    StartInfo = psInfo
};

sysClockProcess.Start();
sysClockProcess.WaitForInputIdle();

//Insert the Window title. It's case SENSITIVE
//Window Title in HKEY_CURRENT_USER\Software\Classes\Local Settings\MuiCache\[COD]\[LANG]\
string windowTitle = "Date and Time";
int maxLenght = 256;
SetWindowPosFlags flags = SetWindowPosFlags.NoSize |
                          SetWindowPosFlags.AsyncWindowPos |
                          SetWindowPosFlags.ShowWindow;

//The first thread is the Main thread. All Dialog windows' handles are attached here.
//The second thread is for GDI+ Hook Window. Ignore it.
EnumThreadWindows((uint)sysClockProcess.Threads[0].Id, (hWnd, lParam) =>
{
    StringBuilder lpString = new StringBuilder(maxLenght);
    if (GetWindowText(hWnd, lpString, maxLenght) > 0)
        if (lpString.ToString() == windowTitle)
        {
            GetWindowRect(hWnd, out RECT lpRect);
            Size size = new Size(lpRect.Right - lpRect.Left, lpRect.Bottom - lpRect.Top);
            //Caculate the position of the Clock Windows relative to the ref. Form Size
            SetWindowPos(hWnd, (IntPtr)0, ((this.Width + this.Left) - size.Width),
                                          ((this.Height + this.Top) - size.Height), 0, 0, flags);
            return false;
        }
    //Window not found: return true to continue the enumeration
    return true;
}, ref windowTitle);

sysClockProcess.Exited += (s, ev) => {
    Console.WriteLine($"The process has exited. Code: " +
        $"{sysClockProcess.ExitCode} Time: {sysClockProcess.ExitTime}");
    sysClockProcess.Dispose();
};

Win32声明:

// SetWindowPos() flags
[Flags]
public enum SetWindowPosFlags : uint
{
   NoSize =         0x0001,
   NoActivate =     0x0010,
   ShowWindow =     0x0040,
   DeferErase =     0x2000,
   AsyncWindowPos = 0x4000
}

[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
   public int Left;
   public int Top;
   public int Right;
   public int Bottom;
}

//Callback for `EnumThreadWindows()`.
public delegate bool EnumThreadWndProc([In] IntPtr hWnd, [In] IntPtr lParam);

[DllImport("user32.dll")]
static extern bool EnumThreadWindows([In] uint dwThreadId, [In] EnumThreadWndProc lpfn, [In] ref string lParam);

[DllImport("user32.dll")]
static extern int GetWindowText(IntPtr hWnd, [Out] StringBuilder lpString, [In] int nMaxCount);

[DllImport("user32.dll", SetLastError = true)]
static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect);

[DllImport("user32.dll", SetLastError=true)]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, SetWindowPosFlags uFlags);