C#移动Winamp主窗口

3

我正在尝试使用以下代码移动Winamp的主窗口:

[DllImport("user32.dll")]
    static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
[DllImport("user32.dll")]
    static extern bool GetWindowRect(IntPtr hWnd, out RECT rect);
[DllImport("user32.dll")]
    static extern IntPtr GetForegroundWindow();

static void resize()
{
   Process w = new Process();
   w.StartInfo = new ProcessStartInfo("winamp.exe");
   w.Start();
   Thread.Sleep(5000);
   IntPtr hWnd = GetForegroundWindow();
   RECT rect;
   GetWindowRect(hWnd, out rect);
   int width = rect.right - rect.left;
   int height = rect.bottom - rect.top;
   MoveWindow(hWnd, 0, 0, width, height, true);
}

这段代码可以在我测试的所有进程中使用,除了Winamp。当我使用进程的mainWindowHandle时,它会移动另一个窗口。 有没有人有办法让它在Winamp上工作?


2
你需要对hWnd执行GetWindowLong来检查窗口是否实际上是可调整大小的。我猜Winamp作为可皮肤化的应用程序,从技术上讲并不是可调整大小的(因为它自己处理一切)。 - PhonicUK
我得到了一个句柄,但大小始终相同,即使我改变大小。窗口不会移动或调整大小(此代码不会调整窗口大小,但我也尝试过)。 - Daniel Kurz
GetWindowRect方法是否返回正确的显示尺寸?也许MainWindowHandle不是正确的句柄。 - Benjamin
@PhonicUK 你的意思是我应该使用 GetWindowLong 来查找样式吗?如果像你说的那样在技术上不可能调整大小,那么我每次都必须手动完成它... - Daniel Kurz
在这种情况下,您可能需要移动窗口,并使用 SendWindowMesssage 发送鼠标拖动事件来进行调整大小。 - PhonicUK
显示剩余3条评论
4个回答

1

我已经尝试了您的代码,但它并不总是有效,并且它不能重新调整窗口大小,只能移动它, 实际上,我发现在2000毫秒的休眠中存在问题,您可以将其更改为while循环,检查句柄是否为零,然后继续执行代码。

while (p.MainWindowHandle == 0)
{
}
IntPtr hWnd = p.MainWindowHandle;

如果Winamp花费太长时间来构建自己的窗口,这可能会有所帮助。


你试过在Winamp上运行吗?因为在我的情况下,当我插入你的代码时,它会将另一个旧窗口移动到0 0位置,但当我点击它时,它就消失了。 - Daniel Kurz
我已经尝试了您的代码与其他应用程序,也许winamp的主模块不是我们所看到的!我不确定这一点,但为了确定错误的位置,您可以启动另一个应用程序而不是winamp,或者使用定时器打印前台句柄的应用程序,以便它可以在后台运行并将其与winamp进程的主句柄进行比较。 - Abdallah Nasir
抱歉拖延了这么长时间,我尝试使用前台句柄,但它们是不同的。 - Daniel Kurz
但是,当我使用新的前景句柄 winamp 时,它并不会移动,所以我认为不能像这样移动 winamp。 - Daniel Kurz
@DanielKurz 为什么不尝试使用前景获取的句柄移动Winamp窗口? - Abdallah Nasir

1

通过以下代码,我可以确认通过Win32 API更改WinAmp的主窗口大小是不起作用的。

通过Win32 API更改其他Winamp窗口大小确实有效,但这不是一个解决方案:

public partial class Form1 : Form
{    
[DllImport("user32")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumChildWindows(IntPtr window, EnumWindowProc callback, IntPtr i);
[DllImport("user32.dll")]
static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
[DllImport("user32.dll")]
static extern bool GetWindowRect(IntPtr hWnd, out RECT rect);    
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
    public int Left;        // x position of upper-left corner
    public int Top;         // y position of upper-left corner
    public int Right;       // x position of lower-right corner
    public int Bottom;      // y position of lower-right corner
}    

private System.IntPtr hWnd;
private void button1_Click(object sender, EventArgs e)
{
    Process p = Process.Start(@"C:\Program Files\Winamp\winamp.exe");       
    try
    {
        do
        {
            p.Refresh();
        }
        while (p.MainWindowHandle.ToInt32() == 0);

        hWnd = new IntPtr(p.MainWindowHandle.ToInt32());
    }
    catch (Exception ex)
    {
        //Do some stuff...
        throw;
    }
}

private void button2_Click(object sender, EventArgs e)
{
    //Make sure we have a handle to the shelled exe
    if (hWnd == new IntPtr(0)) return;
    ResizeExternalExeChildWindows(hWnd);
}

private void ResizeExternalExeChildWindows(IntPtr parent)
{
    List<IntPtr> childWindows = GetChildWindows(hWnd);
    foreach (IntPtr childWindow in childWindows)
    {
        RECT rect;
        GetWindowRect(childWindow, out rect);
        int width = rect.Right - rect.Left;
        int height = rect.Bottom - rect.Top;
        MoveWindow(hWnd, 0, 0, width, height, true);
    }
}

// <summary>
/// Returns a list of child windows
/// </summary>
/// <param name="parent">Parent of the windows to return</param>
/// <returns>List of child windows</returns>
public static List<IntPtr> GetChildWindows(IntPtr parent)
{
    List<IntPtr> result = new List<IntPtr>();
    GCHandle listHandle = GCHandle.Alloc(result);
    try
    {
        EnumWindowProc childProc = new EnumWindowProc(EnumWindow);
        EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle));
    }
    finally
    {
        if (listHandle.IsAllocated)
            listHandle.Free();
    }
    return result;
}

/// <summary>
/// Callback method to be used when enumerating windows.
/// </summary>
/// <param name="handle">Handle of the next window</param>
/// <param name="pointer">Pointer to a GCHandle that holds a reference to the list to fill</param>
/// <returns>True to continue the enumeration, false to bail</returns>
private static bool EnumWindow(IntPtr handle, IntPtr pointer)
{
    GCHandle gch = GCHandle.FromIntPtr(pointer);
    List<IntPtr> list = gch.Target as List<IntPtr>;
if (list == null)
{
    throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>");
}
list.Add(handle);
//  You can modify this to check to see if you want to cancel the operation, then return a null here
return true;

}

/// <summary>
/// Delegate for the EnumChildWindows method
/// </summary>
/// <param name="hWnd">Window handle</param>
/// <param name="parameter">Caller-defined variable; we use it for a pointer to our list</param>
/// <returns>True to continue enumerating, false to bail.</returns>
public delegate bool EnumWindowProc(IntPtr hWnd, IntPtr parameter);

}
}
原因

由于WinAmp支持换肤,因此它通过配置文件(而不是使用win32 API的外部应用程序)支持调整大小。

解决方案

打开文件C:\ Users [用户名] \ AppData \ Roaming \ Winamp \ studio.xnf并编辑以下值:

  <entry name="Bento_nomax_h" value="492" />
  <entry name="Bento_nomax_w" value="633" />
  <entry name="Bento_nomax_x" value="27" />
  <entry name="Bento_nomax_y" value="16" />

我正在使用Bento皮肤。如果您打开WinAmp.ini文件,您可以检测到正在使用的皮肤:

skin=Bento

设置WinAmp主窗口的初始大小的解决方案是在使用Process.Start启动WinAmp之前编辑配置文件。


1

这对我有用,使用最新版本,请尝试一下:

    internal struct RECT
    {
        public int left;
        public int top;
        public int right;
        public int bottom;
    }

    [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, ExactSpelling = true, SetLastError = true)]
    internal static extern bool GetWindowRect(IntPtr hWnd, ref RECT rect);

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, SetWindowPosFlags uFlags);

    public static class HWND
    {
        public static IntPtr
        NoTopMost = new IntPtr(-2),
        TopMost = new IntPtr(-1),
        Top = new IntPtr(0),
        Bottom = new IntPtr(1);
    }

    [Flags]
    public enum SetWindowPosFlags : uint
    {
        SWP_ASYNCWINDOWPOS = 0x4000,
        SWP_DEFERERASE = 0x2000,
        SWP_DRAWFRAME = 0x0020,
        SWP_FRAMECHANGED = 0x0020,
        SWP_HIDEWINDOW = 0x0080,
        SWP_NOACTIVATE = 0x0010,
        SWP_NOCOPYBITS = 0x0100,
        SWP_NOMOVE = 0x0002,
        SWP_NOOWNERZORDER = 0x0200,
        SWP_NOREDRAW = 0x0008,
        SWP_NOREPOSITION = 0x0200,
        SWP_NOSENDCHANGING = 0x0400,
        SWP_NOSIZE = 0x0001,
        SWP_NOZORDER = 0x0004,
        SWP_SHOWWINDOW = 0x0040,
    }

    [DllImport("user32.dll", SetLastError = true)]
    private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

    static void Resize()
    {
        IntPtr winampMainWindow = IntPtr.Zero;

        while (true)
        {
            winampMainWindow = FindWindow("BaseWindow_RootWnd", "Main Window");
            if (winampMainWindow != IntPtr.Zero)
            {
                RECT rect = new RECT();
                GetWindowRect(winampMainWindow, ref rect);
                int width = rect.right - rect.left;
                int height = rect.bottom - rect.top;
                SetWindowPos(winampMainWindow,
                    HWND.Top,
                    0,
                    0,
                    width,
                    height,
                    SetWindowPosFlags.SWP_SHOWWINDOW | SetWindowPosFlags.SWP_NOZORDER | SetWindowPosFlags.SWP_NOSIZE | SetWindowPosFlags.SWP_NOSENDCHANGING | SetWindowPosFlags.SWP_NOOWNERZORDER | SetWindowPosFlags.SWP_NOCOPYBITS);
                break;
            }
            Thread.Sleep(1000);
        }
    }

    [STAThread]
    static void Main()
    {
        Process.Start("winamp.exe");
        Resize();
    }

我使用了版本5.63和不同的皮肤,但遗憾的是什么都没有发生。 - Daniel Kurz
由于您已将问题标记为已回答,我不会再提供进一步的答案。 - Żubrówka
@Żubrówka - 分享你的研究有助于每个人。当有人标记答案时,他们以后可以改变主意,我已经做过几次了。 - Jeremy Thompson

0

真是个噩梦! 不过,在“歌曲窗口”中右键单击确实打开了停靠菜单 - 我想是取消停靠(某些)起作用了。其中一个选项允许我移动这该死的东西。这是个意外,但在那里打开了一些有效的东西。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接