Class methods in D?

Mehrdad wfunction at hotmail.com
Fri May 4 07:31:19 PDT 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 at 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



More information about the Digitalmars-d mailing list