3

I am trying to move winamps main window, with this code:

[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);
}

This code snippet works with all processes that I tested, except Winamp. When I use the mainWindowHandle of the process it moves another window. Anyone an idea how to get it working with Winamp?

Daniel Kurz
  • 816
  • 7
  • 21
  • 2
    You'll want to do a GetWindowLong no the hWnd to check that the window is actually resizable. Winamp being skinnable I suspect isn't technically resizable (as such) since it handles everything itself. – PhonicUK Oct 31 '12 at 12:03
  • I got a handle but the size is always the same even when I change the size. The window doesn't move or resize (this code doesn't resize the window, but I also tried it out) – Daniel Kurz Oct 31 '12 at 12:04
  • Does GetWindowRect return the correct displayed size? Maybe the MainWindowHandle is not the correct handle. – Benjamin Oct 31 '12 at 13:21
  • NO the GetWindowRect return a wrong size, I also think that there is something wrong with the handle – Daniel Kurz Oct 31 '12 at 13:31
  • @PhonicUK you mean I should GetWindowLong to find out the style? If as you said it is technically impossible to resize it, I have do it every time by hand... – Daniel Kurz Oct 31 '12 at 14:11
  • You might in that case have to move the window, and use `SendWindowMesssage` to send mouse-drag events to do the resize. – PhonicUK Oct 31 '12 at 14:15
  • You are calling GetForegroundWindow(). What makes you assume that this is Winamp's main window? If you want to operate on a specific window you will need to make sure you actually have the right window handle. [FindWindow](http://msdn.microsoft.com/en-us/library/ms633499.aspx) is probably more appropriate. (You can use Spy++ to retrieve the window class.) Also, any operation on a window should **always** be done from the thread owning the window. – IInspectable Dec 25 '12 at 23:05
  • With FindWindow and SendMessage I'm able to close the winamp window, is there a way to move the window around? – Daniel Kurz Dec 26 '12 at 18:35

4 Answers4

1

I have tried your code, it is not working always, and it is not re-sizing windows, it was moving it only, Actually I found a problem in the 2000 ms sleep, which you can change to a while loop checking if the handle is zero then proceed with the code,

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

this may help if the winamp takes too much time to build its own window

Abdallah Nasir
  • 607
  • 6
  • 33
  • you tried it with Winamp? because in my case it sort of moves something else when I insert your code it moves an older window to the position 0 0 which disappears when I klick on it – Daniel Kurz Nov 14 '12 at 14:51
  • I have tried your code with other applications, may be the main module of the winamp is not what we see !! I am not sure of that, but to determine where is the error, you may start another application other than winamp, or make an application prints the foreground handle using a timer so it can run in the background and compare it with the main handle of the winamp process – Abdallah Nasir Nov 18 '12 at 06:16
  • sorry for the long delay, I tried it with the foreground handle and they are different – Daniel Kurz Dec 16 '12 at 14:30
  • But still, when I use the new foreground handle winamp doesn't move, so I think it is not possible to move winamp like this – Daniel Kurz Dec 16 '12 at 14:37
  • @DanielKurz Why don't you try to move the window of winamp using the handle you get by the foreground? – Abdallah Nasir Dec 16 '12 at 14:40
1

With the following code I can confirm changing WinAmp's main window size does not work via the Win32 API's.

Changing other winamp window sizes via the Win32 API's did work, but is not a solution:

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);

}
}

Cause

Because WinAmp is skinnable it supports resizing via config files (not via external apps using win32 API's).

Solution

Open the file C:\Users[username]\AppData\Roaming\Winamp\studio.xnf and edit the following values:

  <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" />

I am using the Bento Skin. If you open the WinAmp.ini file you can detect the skin being used:

skin=Bento

The solution to set the initial size for WinAmp's main window is to edit the config file before shelling WinAmp with Process.Start.

Jeremy Thompson
  • 61,933
  • 36
  • 195
  • 321
1

This worked for me using the latest version, please give it a try:

    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();
    }
Żubrówka
  • 730
  • 1
  • 10
  • 24
0

Absolute nightmare! However, right clicking in the "song window" DID open up the docking menu - I think the undock-(something) worked. One of these options allowed me to move the god-damned thing. It was a fluke, but something opened up there that worked.