Archicad C++ API
About Archicad add-on development using the C++ API.
SOLVED!

Use Browser Control in modal window

Martin Walter
Enthusiast
Hi,

I'd like to use the DG::Browser embedded in a modal window created by the Windows API. I use the DG::Browser::SetUpForNativeWindow and the DG::Browser::LoadURL methods. But the browser does not show up in the window. And calling <delete browser> at the end crashes.
Many Thanks!

#include "APICommon.h"
#include "ResourceIDs.hpp"
#include "DG.h"
#include <windows.h>

// Window callback procedure
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg)
	{
	case WM_DESTROY: PostQuitMessage(0); break;
	default: return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
	}
	return 0;
}

// creating a window with the Windows API
HWND CreateWindow(WNDCLASS wc, HWND hwndMainWindow)
{
	// Create the window.
	HWND hwnd = ::CreateWindowEx(0, wc.lpszClassName, L"", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hwndMainWindow, NULL, wc.hInstance, NULL);
	if (hwnd == NULL)
	{
		return 0;
	}
	::ShowWindow(hwnd, SW_MAXIMIZE);
	return hwnd;
}

bool OpenBrowser()
{
	HWND hwndMainWindow = ACAPI_GetMainWindow();

	// disable the main window of Archicad
	::EnableWindow(hwndMainWindow, FALSE);

	// get instance of application
	HINSTANCE hInstance = ACAPI_GetExtensionInstance();

	// create window class
	WNDCLASS wc = { };
	wc.lpfnWndProc = WindowProc;
	wc.hInstance = hInstance;
	wc.lpszClassName = L"Browser Window Class";
	
	// register window class
	if (!::RegisterClass(&wc))
	{
		return false;
	}

	bool bResult = false;
	DG::Browser* browser = nullptr;

	// create a modal window
	HWND hWndBrowser = CreateWindow(wc, hwndMainWindow);
	if (hWndBrowser != nullptr)
	{
		RECT rect;
		const BOOL bRect = GetWindowRect(hWndBrowser, &rect);
		if (bRect)
		{
			const DG::Rect dgRect((short)rect.left, (short)rect.top, (short)rect.right, (short)rect.bottom);

			// create browser in modal window
			browser = new DG::Browser(dgRect);
			browser->SetUpForNativeWindow(hWndBrowser, dgRect);
			browser->LoadURL("https://google.com/");

			// Main message loop:
			MSG msg;
			while (::GetMessage(&msg, NULL, 0, 0))
			{
				::TranslateMessage(&msg);
				::DispatchMessage(&msg);
			}
			bResult = true;
		}
	}

	// unregister window class, freeing the memory
	::UnregisterClass(wc.lpszClassName, hInstance);

	// enable the main window of Archicad
	::EnableWindow(hwndMainWindow, TRUE);

	// TODO: crashes if deleted
	//delete browser;

	return bResult;
}
AC22-27, Windows 11, i7-1355U, 32GB RAM, 2TB SSD
1 ACCEPTED SOLUTION

Accepted Solutions
Solution
Ralph Wessel
Mentor
Are you constructing an instance of DG::ModalDialog? This is the panel owning the browser item. The index of the browser item is '1' according to the GRC file you showed earlier (because it is the first in the list).
Ralph Wessel BArch
Software Engineer Speckle Systems

View solution in original post

7 REPLIES 7
Ralph Wessel
Mentor
Martin wrote:
I'd like to use the DG::Browser embedded in a modal window created by the Windows API.
Would there be a problem creating the window using the ARCHICAD API rather than the Windows API? I believe your efforts are much more likely to be successful if you use one API for your UI workflow.
Ralph Wessel BArch
Software Engineer Speckle Systems
Martin Walter
Enthusiast
Well I need a modal window with a browser embedded but without any buttons like ok or cancel. The only button should be the closing cross on the top right side of the window. I believe that`s not possible with the ARCHICAD API isn`t it?
AC22-27, Windows 11, i7-1355U, 32GB RAM, 2TB SSD
Ralph Wessel
Mentor
Yes, it should be possible to do that. Have you already tried and hit an obstacle? If so, what was the problem?
Ralph Wessel BArch
Software Engineer Speckle Systems
Martin Walter
Enthusiast
I have two problems:
1. If there is no button in the dialog the message DG_MSG_CLICK is not propagated if the close box in the caption is clicked. Thus the dialog can not be closed.
2. I do not know how to connect an instance of DG::Browser to the dialog properly in order to show up the browser in dialog.

My code actually is this:

#include "DialogBrowser.h"
#include "APICommon.h"
#include "ResourceIDs.hpp"
#include "DG.h"
#include "DGModule.hpp"

DG::Browser* browser;

// -----------------------------------------------------------------------------
// browser dialog handler (callback)
// -----------------------------------------------------------------------------
static short DGCALLBACK DialogBrowserHandler(
	short				message,
	short				dialogID,
	short				item,
	DGUserData			/*userData*/,
	DGMessageData		/*msgData*/)
{
	short result = 0;
	switch (message)
	{
	case DG_MSG_INIT:
	{
		HWND hWndMain = ACAPI_GetMainWindow();
		if (hWndMain)
		{
			HWND hWndDialog = GetWindow(hWndMain, GW_HWNDPREV);
			if (hWndDialog)
			{
				RECT rect;
				if (GetWindowRect(hWndDialog, &rect))
				{
					// create browser in modal window
					const DG::Rect dgRect((short)rect.left, (short)rect.top, (short)rect.right, (short)rect.bottom);
					browser = new DG::Browser(dgRect);
					browser->LoadURL("https://google.com/");
				}
			}
		}
	}
	break;

	case DG_MSG_CLICK:
	{
		switch (item)
		{
		case DG_OK:
		case DG_CANCEL:
			result = item;
			break;
		}
	}
	break;

	case DG_MSG_CLOSE:
	{
		result = item;
	}
	break;
	}
	return result;
}

bool OpenBrowser()
{
	// Get the browser dialog from our resource file
	const short result = DGModalDialog(ACAPI_GetOwnResModule(), ID_DIALOG_BROWSER, ACAPI_GetOwnResModule(), DialogBrowserHandler, 0);
	return result;
}
And the .grc:

'GDLG' 32700 Modal 0 0 450 500 "" {
/* [ 1] */ Browser 0 0 450 450
}

'DLGH' 32700 DLG_32700_Browser {
1 "Browser Control" Browser_0
}
AC22-27, Windows 11, i7-1355U, 32GB RAM, 2TB SSD
Ralph Wessel
Mentor
For a start, I think you want to use the DG:Browser constructor that identifies the parent panel and the index of the relevant control, i.e.
	Browser	(const Panel& panel, short item);
Ralph Wessel BArch
Software Engineer Speckle Systems
Martin Walter
Enthusiast
But I call DGModalDialog(..) with no item in it.
Where can I get a panel from?
AC22-27, Windows 11, i7-1355U, 32GB RAM, 2TB SSD
Solution
Ralph Wessel
Mentor
Are you constructing an instance of DG::ModalDialog? This is the panel owning the browser item. The index of the browser item is '1' according to the GRC file you showed earlier (because it is the first in the list).
Ralph Wessel BArch
Software Engineer Speckle Systems