使用SetWindowPos移动窗口

时间:2015-10-02 01:11:55

标签: c# interop handle intptr

我正在尝试移动我正在建立的程序窗口。我通过处理Process.GetProcesses()中的所有进程来获取它的句柄。然后,我正在调用SetWindowPos,但没有任何反应。这是我的代码。

<?php
require("/Users/jargon/Desktop/workbench/net/dell/PHPMailer/PHPMailerAutoload.php");

$mail = new PHPMailer();  
$body = "this is the body";   
$mail->IsSMTP();  // telling the class to use SMTP 
$mail->Mailer = "smtp";

$mail->SMTPAuth = true; // turn on SMTP authentication
$mail->SMTPSecure = "tls";     
$mail->Host = "";
$mail->Port = 26;
$mail->Username = ""; // SMTP username
$mail->Password = ""; // SMTP password 

$mail->SetFrom     = "";  

$mail->Subject  = "Dell Powered";  
$mail->AltBody    = "To view the message, please use an HTML compatible email viewer!";
$mail->MsgHTML($body);

$address = "";
$mail->AddAddress($address, "");

if(!$mail->Send()) {
    echo "Mailer Error: " . $mail->ErrorInfo;
} else {
    echo "Message sent!";
}

?>

NewGUI.SetWarning只显示标签并正确显示。 _correctHandle是一个简单的bool,SetWindowPos是

internal static void CheckHandle()
{
    Process[] ps = Process.GetProcesses();
    foreach (Process p in ps)
    {
        try
        {
            if (string.Equals(p.ProcessName, "TestBuild0001"))
            {
                _correctHandle = true;
                _handle = p.Handle;
            }
        }
        catch
        {
            //no catch, simply exited process
        }
    }
}

internal static void SetPosition()
{
    if (!_correctHandle)
        CheckHandle();
    if (_correctHandle)
    {
        NewGUI.SetWarning("Window set!",5,50,900,300,50);
        SetWindowPos(_handle, 0, 0, 0, 0, 0, 0x0001);
    }
}

我已经尝试过很多东西让它发挥作用,但是我没有想法。试图让前景窗口带回一个完全不正确的句柄,名称的findwindow带回0,而其他一些东西似乎不起作用。任何人都知道我的错误是什么/

2 个答案:

答案 0 :(得分:2)

p.Handle是流程&#39;把手,而不是窗把手。你想要p.MainWindowHandle

您尝试附加的流程也可能只有一个隐藏的仅限消息的主窗口。为了解决这个问题,你需要使用像Spy ++这样的工具来查看窗口的结构。

如果所有其他方法都失败,Spy ++还会为您提供一个窗口类,您可以使用FindWindowEx来定位窗口。 (我在this answer

中使用Sticky Notes窗口执行相同的操作

答案 1 :(得分:0)

来自这个帖子的GetActiveWindow想法:Any way to bring Unity3d to the foreground?给了我正确的窗口ID,但更改分辨率仍然引起了我的问题,因为在调用我的SetWindowPos后,unity将窗口位置设置为两个监视器之间的中间位置。这是我为其他需要这样的人的解决方案。

void FixedUpdate()
{
    if (Handle == IntPtr.Zero)
    {
        Handle = GetActiveWindow();
        uint uP;
        GetWindowThreadProcessId(Handle, out uP);
        System.Diagnostics.Process p = System.Diagnostics.Process.GetProcessById((int)uP);
        if (string.Equals(p.ProcessName, "Unity"))
            AllowReset = false;
        else if (string.Equals(p.ProcessName, "TestBuild00001"))
            AllowReset = true;
        else
            Handle = IntPtr.Zero;
    }
}

void Update()
{
    if (ScreenSet && AllowReset && GuiValidReset)
    {
        GuiValidReset = false;
        ScreenSet = false;
        SetPosition();
    }
}

void OnGUI()
{
    if (ScreenSet && AllowReset && !GuiValidReset)
        GuiValidReset = true;
}

internal static void SetPosition()
{
        SetWindowPos(Handle, 0, 0, 0, 0, 0, 0x0001);
}

Dll导入

[DllImport("User32.dll")]
internal static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[DllImport("user32.dll")]
internal static extern IntPtr GetActiveWindow();
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetWindowPos(IntPtr hwnd, int hWndInsertAfter, int x, int Y, int cx, int cy, int wFlags);

更新和ongui检查以确保在定位窗口之前完全重绘统一,因为在调整分辨率的同时调用它会导致窗口重置为中间屏幕。设置分辨率后,ScreenSet立即设置为true。