May 04, 2012
Hmm... how exactly do you use RTInfo? (Is it usable yet? All I see is a void* and a dummy template.)
May 04, 2012
On 5/3/2012 1:32 PM, Simon wrote:
> On 03/05/2012 18:21, Mehrdad wrote:
>> In Windows, you need to register a "window class" before you can
>> actually create an instance of it.
>
> If you are mucking about on 'doze you might find my dubious port of the
> ATL window classes relevant:
>
> http://www.sstk.co.uk/atlWinD.php
>
> That does all that tedious registering of windows classes etc.
> I used a static class member IIRC.
>
> I've ripped this off of MS so use at your own risk. ;)
>

Heh, I've got a miniature (probably 20-30% complete) version of the WTL ported to D here, but without any ATL aside from the parts of CWindow.

The WTL uses the curiously recurring template design which also works in D, so a window class is something like this in D:


class GameWindow : CWindowUserBase!(CWindow, GameWindow)
{
    bool isFullscreen;
    bool isResizing;
    bool suppressRendering;
    bool allowCapture;
    wGameMessageLoop messageLoop;
    GameScene gameScene;
    RenderDevice renderDevice;
    DeviceContext immediateContext;
    SwapChain swapChain;
    Tid renderingThread;

    mixin DECLARE_WND_CLASS!("wWindowClass", CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS, COLOR_WINDOWFRAME);

    static DWORD GetWndStyle(DWORD InStyle)
    {
        return InStyle | WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
    }
    static DWORD GetWndExStyle(DWORD InStyleEx)
    {
        return InStyleEx | WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
    }
    static string GetWndCaption()
    {
        return "";
    }

/// lots of code deleted

    mixin(HOOK_MSG_WM_DESTROY!(OnDestroy));
    mixin(HOOK_MSG_WM_MOVE!(OnMove));
    mixin(HOOK_MSG_WM_SIZE!(OnSize));


    mixin REGISTER_MESSAGE_MAP!(
        BIND_MSG_WM_DESTROY!(OnDestroy),
        BIND_MSG_WM_MOVE!(OnMove),
        BIND_MSG_WM_SIZE!(OnSize));

    mixin MESSAGE_HANDLER!();
}




So the answer to the OP's question is, make the class stuff static and use mixins for the functions so the scope works out.
May 04, 2012
On 5/3/2012 1:41 PM, Mehrdad wrote:
> On Thursday, 3 May 2012 at 18:32:18 UTC, Simon wrote:
>> On 03/05/2012 18:21, Mehrdad wrote:
>>> In Windows, you need to register a "window class" before you can
>>> actually create an instance of it.
>>
>> If you are mucking about on 'doze you might find my dubious port of
>> the ATL window classes relevant:
>>
>> http://www.sstk.co.uk/atlWinD.php
>>
>> That does all that tedious registering of windows classes etc.
>> I used a static class member IIRC.
>>
>> I've ripped this off of MS so use at your own risk. ;)
>
> lol. thanks.
>


I could at give out the incomplete WTL port to D I had been working on off and on over the last year, as it has an open license to start with (but as WTL includes ATL some parts have to be built from scratch like CWindow which is a PITA).   Even without all the rest of the library the message crack module is very useful on Win32 systems.

May 04, 2012
On 2012-05-03 19:21, Mehrdad wrote:
> In Windows, you need to register a "window class" before you can
> actually create an instance of it.
>
> Mapping this idea to D (and most other languages, I admit) is hard.
> Microsoft's solution in C# is pretty ugly.

BTW, what's wrong with using some existing GUI library that handles all this, like DWT:

http://www.dsource.org/projects/dwt

-- 
/Jacob Carlborg
May 04, 2012
On Fri, 04 May 2012 01:13:07 -0400, Mehrdad <wfunction@hotmail.com> wrote:

> Hmm... how exactly do you use RTInfo? (Is it usable yet? All I see is a void* and a dummy template.)

You have to fill in object.di's RTInfo(T) to be whatever you want.  As I said, it's very beta, intended as a hook to use for more precise garbage collection, or any other runtime info goodies you want to put in there.  See my example for a hint.

Essentially, the compiler's going to do this:

class C {...}

// compiler: hmmm... have to generate TypeInfo_Class for C.  Let me set up all the normal hooks

TypeInfo_Class CTypeInfo;
CTypeInfo.name = "C";
...

// compiler: ok, now let me generate the RTInfo part
CTypeInfo.m_rtInfo = RTInfo!C;

Now, you can call typeid(instanceOfC).rtInfo and it will give you the data that comes from RTInfo!C.  And you don't have to know the type of instanceOfC, it could be Object.  It's essentially a way to convert compile-time data into runtime data.

-Steve
May 04, 2012
Oooooh okay, I see. Let me try it. :)

@Everyone: Haha thanks for pointing me to the existing libraries. :) I'm doing this more for learning than anything else, so I'm trying to solve these problems myself instead of just using another library.

And it seems to be going well:

class Window
{
	private static shared tstring classNames[TypeInfo];

	shared static this() { EnableVisualStyles(); RegisterClass(typeid(typeof(this))); }

	public static Window fromHandle(HWND hWnd) { assert(0, "fromHandle() not implemented"); }

	private static extern(Windows) LRESULT StaticWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
	{
		enum tstring WINDOW_INSTANCE_PROP = "WINDOW_INSTANCE";
		if (uMsg == WM_NCCREATE || uMsg == WM_CREATE)
		{
			auto this_ = cast(typeof(this))(cast(LPCREATESTRUCT)lParam).lpCreateParams;
			this_._hWnd = hWnd;
			BOOL success = SetProp(hWnd, WINDOW_INSTANCE_PROP, cast(void*)this_);
			assert(success, "Could not set window instance information.");
		}
		return (cast(typeof(this))cast(void*)GetProp(hWnd, WINDOW_INSTANCE_PROP)).WndProc(uMsg, wParam, lParam);
	}

	protected static void RegisterClass(
		TypeInfo_Class type, tstring className = null, bool existingWin32Class = false, UINT style = 0, HICON hIcon = null,
		HCURSOR hCursor = LoadCursor(null, IDC_ARROW), HBRUSH hBrBackground = GetSysColorBrush(COLOR_3DFACE),
		HICON hIconSm = null, tstring menuName = null, int cbClsExtra = 0, int cbWndExtra = 0, HINSTANCE hInstance = null)
	in { assert(type !in classNames); }
	body
	{
		if (className == null) { className = "WINDOW_CLASS_" ~ to!tstring(type.name); }
		if (!existingWin32Class)
		{
			WNDCLASSEX wndClassEx;
			wndClassEx = typeof(wndClassEx)(wndClassEx.sizeof, style, &StaticWndProc, cbClsExtra, cbWndExtra, hInstance, hIcon, hCursor, hBrBackground, menuName.toSZ(), className.toSZ(), hIconSm);
			ATOM atom = RegisterClassEx(&wndClassEx);
			assert(atom != 0, "Unable to RegisterClass window class.");
		}
		synchronized(typeid(typeof(this))) { classNames[type] = className.idup; }
	}

	public static void EnableVisualStyles()
	{
		tchar[MAX_PATH] dir;
		dir[GetSystemDirectory(dir.ptr, dir.length)] = '\0';
		enum ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID = 0x00000004, ACTCTX_FLAG_RESOURCE_NAME_VALID = 0x00000008, ACTCTX_FLAG_SET_PROCESS_DEFAULT = 0x00000010;
		auto actCtx = ACTCTX(
			ACTCTX.sizeof, ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_SET_PROCESS_DEFAULT | ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID,
			"shell32.dll", PROCESSOR_ARCHITECTURE_INTEL, 0, dir.ptr, MAKEINTRESOURCE(124), null, null);
		auto hActCtx = CreateActCtx(actCtx);
		assert(hActCtx != INVALID_HANDLE_VALUE);
		ULONG_PTR ulpActivationCookie;
		BOOL success = ActivateActCtx(hActCtx, ulpActivationCookie);
		assert(success);
	}

	private HWND _hWnd;
	public @property auto hWnd() const { assert(this.isWindow, "Invalid window handle."); return cast(HWND)this._hWnd; }
	public @property auto hWnd(typeof(this._hWnd) value) { assert(this._hWnd == null, "Cannot overwrite valid window handle."); this._hWnd = value; }
	public @property auto isWindow() const { return .IsWindow(cast(HWND)this._hWnd); }

	public this() { }

	public void CreateWindow(scope tstring windowName = null, Window parent = null, DWORD style = WS_OVERLAPPEDWINDOW,
		DWORD exStyle = 0, int x = CW_USEDEFAULT, int y = CW_USEDEFAULT, int width = CW_USEDEFAULT,
		int height = CW_USEDEFAULT, HMENU hMenu = null, HINSTANCE hInstance = null)
	{
		this.hWnd = .CreateWindowEx(exStyle, this.className.toSZ(), windowName.toSZ(), style, x, y, width, height, parent is null ? null : parent.hWnd, hMenu, hInstance, cast(void*)this);
		assert(this.hWnd != null);
	}

	private final @property tstring className() { synchronized(typeid(typeof(this))) { return classNames[typeid(this)]; } }

	protected LRESULT WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
	{
		return .DefWindowProc(this.hWnd, uMsg, wParam, lParam);
	}

	public ~this() { }
	public auto GetFont(HFONT hFont)
	{ return this.SendMessage(WM_GETFONT); }
	public auto SetFont(HFONT hFont, bool redraw = true)
	{ return this.SendMessage(WM_SETFONT, cast(WPARAM)hFont, redraw ? 1 : 0); }
	template opDispatch(string name)
	{
		public auto opDispatch(T...)(scope T args)
		{ return mixin(q{.} ~ name ~ q{(this.hWnd, args)}); }
	}
}

mixin template Win32WindowT(string wrapperClassName, string win32ClassName)
{
	mixin(Format!(
	q{
		class %s : Window
		{
			shared static this() { RegisterClass(typeid(typeof(this)), "%s", true); }
		}
	}, wrapperClassName, win32ClassName));
}

mixin Win32WindowT!(q{Button}, "Button");



On Friday, 4 May 2012 at 12:27:41 UTC, Steven Schveighoffer wrote:
> On Fri, 04 May 2012 01:13:07 -0400, Mehrdad <wfunction@hotmail.com> wrote:
>
>> Hmm... how exactly do you use RTInfo? (Is it usable yet? All I see is a void* and a dummy template.)
>
> You have to fill in object.di's RTInfo(T) to be whatever you want.  As I said, it's very beta, intended as a hook to use for more precise garbage collection, or any other runtime info goodies you want to put in there.  See my example for a hint.
>
> Essentially, the compiler's going to do this:
>
> class C {...}
>
> // compiler: hmmm... have to generate TypeInfo_Class for C.  Let me set up all the normal hooks
>
> TypeInfo_Class CTypeInfo;
> CTypeInfo.name = "C";
> ...
>
> // compiler: ok, now let me generate the RTInfo part
> CTypeInfo.m_rtInfo = RTInfo!C;
>
> Now, you can call typeid(instanceOfC).rtInfo and it will give you the data that comes from RTInfo!C.  And you don't have to know the type of instanceOfC, it could be Object.  It's essentially a way to convert compile-time data into runtime data.
>
> -Steve

May 04, 2012
On 04/05/2012 13:27, Steven Schveighoffer wrote:
> On Fri, 04 May 2012 01:13:07 -0400, Mehrdad <wfunction@hotmail.com> wrote:
>
>> Hmm... how exactly do you use RTInfo? (Is it usable yet? All I see is
>> a void* and a dummy template.)
>
> You have to fill in object.di's RTInfo(T) to be whatever you want. As I
> said, it's very beta, intended as a hook to use for more precise garbage
> collection, or any other runtime info goodies you want to put in there.
> See my example for a hint.
>
> Essentially, the compiler's going to do this:
>
> class C {...}
>
> // compiler: hmmm... have to generate TypeInfo_Class for C. Let me set
> up all the normal hooks
>
> TypeInfo_Class CTypeInfo;
> CTypeInfo.name = "C";
> ...
>
> // compiler: ok, now let me generate the RTInfo part
> CTypeInfo.m_rtInfo = RTInfo!C;
>
> Now, you can call typeid(instanceOfC).rtInfo and it will give you the
> data that comes from RTInfo!C. And you don't have to know the type of
> instanceOfC, it could be Object. It's essentially a way to convert
> compile-time data into runtime data.
>
> -Steve

If you do that, won't anybody who wants to use the code have to have the same hacks to object di?

If so that's not going to be give anything that's either portable or reusable.

-- 
My enormous talent is exceeded only by my outrageous laziness.
http://www.ssTk.co.uk
May 04, 2012
On Fri, 04 May 2012 13:08:44 -0400, Simon <s.d.hammett@gmail.com> wrote:

> On 04/05/2012 13:27, Steven Schveighoffer wrote:
>> On Fri, 04 May 2012 01:13:07 -0400, Mehrdad <wfunction@hotmail.com> wrote:
>>
>>> Hmm... how exactly do you use RTInfo? (Is it usable yet? All I see is
>>> a void* and a dummy template.)
>>
>> You have to fill in object.di's RTInfo(T) to be whatever you want. As I
>> said, it's very beta, intended as a hook to use for more precise garbage
>> collection, or any other runtime info goodies you want to put in there.
>> See my example for a hint.
>>
>> Essentially, the compiler's going to do this:
>>
>> class C {...}
>>
>> // compiler: hmmm... have to generate TypeInfo_Class for C. Let me set
>> up all the normal hooks
>>
>> TypeInfo_Class CTypeInfo;
>> CTypeInfo.name = "C";
>> ...
>>
>> // compiler: ok, now let me generate the RTInfo part
>> CTypeInfo.m_rtInfo = RTInfo!C;
>>
>> Now, you can call typeid(instanceOfC).rtInfo and it will give you the
>> data that comes from RTInfo!C. And you don't have to know the type of
>> instanceOfC, it could be Object. It's essentially a way to convert
>> compile-time data into runtime data.
>>
>> -Steve
>
> If you do that, won't anybody who wants to use the code have to have the same hacks to object di?
>
> If so that's not going to be give anything that's either portable or reusable.

I think we can construct a way to have the type generate part of the data without having to alter object.di's template.

See my previous example for a possible way to do this.

-Steve
May 04, 2012
On 2012-05-04 16:31, Mehrdad wrote:
> Oooooh okay, I see. Let me try it. :)
>
> @Everyone: Haha thanks for pointing me to the existing libraries. :) I'm
> doing this more for learning than anything else, so I'm trying to solve
> these problems myself instead of just using another library.
>
> And it seems to be going well:
>
> class Window
> {
> private static shared tstring classNames[TypeInfo];
>
> shared static this() { EnableVisualStyles();
> RegisterClass(typeid(typeof(this))); }

For classes there's a shourtcut:

this.classinfo;

-- 
/Jacob Carlborg
May 04, 2012
On Fri, 04 May 2012 15:53:36 -0400, Jacob Carlborg <doob@me.com> wrote:

> On 2012-05-04 16:31, Mehrdad wrote:
>> Oooooh okay, I see. Let me try it. :)
>>
>> @Everyone: Haha thanks for pointing me to the existing libraries. :) I'm
>> doing this more for learning than anything else, so I'm trying to solve
>> these problems myself instead of just using another library.
>>
>> And it seems to be going well:
>>
>> class Window
>> {
>> private static shared tstring classNames[TypeInfo];
>>
>> shared static this() { EnableVisualStyles();
>> RegisterClass(typeid(typeof(this))); }
>
> For classes there's a shourtcut:
>
> this.classinfo;

Not really.  this gets the TypeInfo of the *runtime* type (and BTW, classinfo is deprecated IIRC, use typeid(this) instead).  The code Mehrdad wrote above gets the TypeInfo of the *static* type.  Not to mention, there's no 'this' in a static constructor.

-Steve