0

I currently have an IntPtr of a window handle, and I tried getting its Window using HwndSource.FromHwnd but it returns null. If the Window element was retrieved, it would have been possible to set its MaxWidth attribute.

Are there other ways to set the maximum width just from having a window handle of an external application?

EDIT: Trying to see if RbMm's approach works. The question's tagged C# but this could be worth a shot using a C++ custom DLL:

bool InitializeMaxWidthHook(int threadID, HWND destination)
{
    if (g_appInstance == NULL)
    {
        return false;
    }

    SetProp(GetDesktopWindow(), "WILSON_HOOK_HCBT_MINMAX", destination);

    hookMaxWidth = SetWindowsHookEx(WH_CBT, (HOOKPROC)MinMaxHookCallback, g_appInstance, threadID);
    return hookMaxWidth != NULL;
}

void UninitializeMaxWidthHook()
{
    if (hookMaxWidth != NULL)
        UnhookWindowsHookEx(hookMaxWidth);
    hookMaxWidth = NULL;
}

static LRESULT CALLBACK MinMaxHookCallback(int code, WPARAM wparam, LPARAM lparam)
{
    if (code >= 0)
    {
        UINT msg = 0;

        if (code == HCBT_MINMAX)
            msg = RegisterWindowMessage("WILSON_HOOK_HCBT_MINMAX");

        HWND dstWnd = (HWND)GetProp(GetDesktopWindow(), "WILSON_HOOK_HCBT_MINMAX");

        if (msg != 0)
            SendNotifyMessage(dstWnd, msg, wparam, lparam);
    }

    return CallNextHookEx(hookMaxWidth, code, wparam, lparam);
}

I'll update the question again after tinkering with this.

Community
  • 1
  • 1
Garmanarnar
  • 105
  • 8
  • 1
    window not have any `MaxWidth` attributes. window procedure handle [`WM_GETMINMAXINFO`](https://msdn.microsoft.com/en-us/library/windows/desktop/ms632626(v=vs.85).aspx) message and return `ptMaxSize` in [`MINMAXINFO`](https://msdn.microsoft.com/en-us/library/windows/desktop/ms632605(v=vs.85).aspx) - so only way control window procedure – RbMm Mar 16 '17 at 08:56
  • possible way do this - set [`WH_CALLWNDPROCRET`](https://msdn.microsoft.com/en-us/library/windows/desktop/ms644976(v=vs.85).aspx) - implement CallWndRetProc callback function and change `MINMAXINFO` structure – RbMm Mar 16 '17 at 09:03
  • Another approach would be to monitor (poll) window size and [resize it](http://stackoverflow.com/q/8443502/1997232) when it's too big. – Sinatr Mar 16 '17 at 09:25
  • RbMm's solutions cannot work, it requires injecting code into the process that owns the window and that can't be C# code. Using the System.Windows.Automation namespace or SetWinEventHook() to monitor for size changes is about as practical as it gets. – Hans Passant Mar 16 '17 at 11:08
  • @Hans Yeah, the tag's actually for C#. I'll definitely try your approach after checking the custom DLL one. – Garmanarnar Mar 17 '17 at 03:49
  • but `HCBT_MINMAX` is related to [`CBTProc`](https://msdn.microsoft.com/en-us/library/windows/desktop/ms644977(v=vs.85).aspx) callback - change `WH_CALLWNDPROCRET` to `WH_CBT`. also may be you need handle `HCBT_MOVESIZE` - `lParam Specifies a long pointer to a RECT structure containing the coordinates of the window. By changing the values in the structure, a CBTProc hook procedure can set the final coordinates of the window` – RbMm Mar 17 '17 at 04:35
  • @RbMm Haha I should have checked this thread an hour ago. I just found out about ```WH_CBT``` from the [documentation](https://msdn.microsoft.com/ja-jp/library/windows/desktop/ms644959(v=vs.85).aspx#wh_cbthook). I'll check out ```HCBT_MOVESIZE``` after this. It's really hard having to work on WPF without any prior knowledge. I just came from Android development and had to be assigned ASAP to a Windows project. Ahh the highs and lows of software development. – Garmanarnar Mar 17 '17 at 05:46

1 Answers1

0

The solution I came up with isn't purely C#, so this doesn't perfectly fit the question tags, but I'll post it anyway.

I created a third-party DLL with initialization functions for WndProc hook to listen to GETMINMAXINFO (I removed some parts of the code for privacy, but this is the one for GETMINMAXINFO:

#include "stdafx.h"
#include <windows.h>

HINSTANCE g_appInstance = NULL;
typedef void (CALLBACK *HookProc)(int code, WPARAM w, LPARAM l);

HHOOK hookWndProc = NULL;
static LRESULT CALLBACK WndProcHookCallback(int code, WPARAM wparam, LPARAM lparam);

bool InitializeWndProcHook(int threadID, HWND destination)
{
    if (g_appInstance == NULL)
    {
        return false;
    }

    SetProp(GetDesktopWindow(), "WILSON_HOOK_HWND_WND_PROC", destination);

    hookWndProc = SetWindowsHookEx(WH_CALLWNDPROC, (HOOKPROC)WndProcHookCallback, g_appInstance, threadID);
    return hookWndProc != NULL;
}

void UninitializeWndProcHook()
{
    if (hookWndProc != NULL)
        UnhookWindowsHookEx(hookWndProc);
    hookWndProc = NULL;
}

static LRESULT CALLBACK WndProcHookCallback(int code, WPARAM wparam, LPARAM lparam)
{
    if (code >= 0)
    {
        UINT msg = 0;

        WPARAM newWPARAM;
        LPARAM newLPARAM;
        if (code == HC_ACTION)
        {
            CWPSTRUCT *wndProc = (CWPSTRUCT *)lparam;           
            if (shouldSendMessageOnWindow(wndProc->hwnd))
            {
                // if the message is from other process, the value of wparam is null
                UINT wndProcMessage = wndProc->message;
                if (wndProcMessage == WM_GETMINMAXINFO)
                {
                    newWPARAM = (WPARAM)wndProc->hwnd;
                    newLPARAM = (LPARAM)wndProc->lParam;
                    msg = RegisterWindowMessage("WILSON_HOOK_HC_ACTION_WND_PROC_WM_GETMINMAXINFO");
                }
            }
        }

        if (msg != 0)
        {
            HWND dstWnd = (HWND)GetProp(GetDesktopWindow(), "WILSON_HOOK_HWND_WND_PROC");
            SendNotifyMessage(dstWnd, msg, newWPARAM, newLPARAM);
        }
    }

    return CallNextHookEx(hookWndProc, code, wparam, lparam);
}

I then initialized this hook in my C# code and waited for the MINMAX message then set the info to the size I wanted.

private struct POINT
{
    public int x;
    public int y;
}

private struct MINMAXINFO
{
    public POINT ptReserved;
    public POINT ptMaxSize;
    public POINT ptMaxPosition;
    public POINT ptMinTrackSize;
    public POINT ptMaxTrackSize;
}

/**Other Code**/

MINMAXINFO* minMaxInfo = (MINMAXINFO*) lParam;

int currentMaxSize = minMaxInfo->ptMaxSize.x;
Debug.WriteLine("Updated max" + currentMaxSize);

minMaxInfo->ptMaxSize.x = screenWidth; 
minMaxInfo->ptMaxSize.y = screenHeight;

User32.SetWindowPos(wParam, User32.SpecialWindowHandles.HWND_TOP, 0, 0, screenWidth, screenHeight, User32.SetWindowPosFlags.SWP_DRAWFRAME | User32.SetWindowPosFlags.SWP_ASYNCWINDOWPOS);

/**Other Code**/

This worked for some applications (I think for Win32 apps only). Some applications such as Metro Apps and possibly Java applets can't be accessed.

But for now, this is probably good for starters.

Thanks to Hans Passant and RbMm for guiding me to this answer.

Community
  • 1
  • 1
Garmanarnar
  • 105
  • 8