www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Class methods in D?

reply "Mehrdad" <wfunction hotmail.com> writes:
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.

The problem is this:
You make a class like
class Window
{
    HWND handle;
    virtual  property string className()  // How the system identifies this 
subclass
    { /*some default code for lazily registering a class*/ }
    this() { this.handle = className(this.className, ...); }
}
which people are supposed to inherit from.

The trouble is that there is *no clean way* (that I can think of) to ensure 
this:
if (typeid(windowA) == typeid(windowB))
{ assert(windowA.className == windowB.className); }

This is necessary in order to make sure that the idea of a "class" in D is 
the same as the one that the system sees.

If className() was class method, this assumption would be trivial to ensure: 
subclasses could override it, and it would be the same for all instances of 
the class. It would map to OOP in D **VERY** cleanly.
Right now, though, it's a big pain to map this concept... and the lack of 
proper reflection isn't helping.
(Microsoft just decided to make it an instance property, but if you look at 
the code, you'll see it's infinitely ugly...)

Is there any chance that we can get (overridable) class methods in D?
If not, is there a good solution to this problem?
(At least, will it be possible to retrieve the static methods of a class 
with reflection?) 
May 03 2012
next sibling parent "Mehrdad" <wfunction hotmail.com> writes:
    this() { this.handle = className(this.className, ...); }

whoops, typo. That line should say: this() { this.handle = CreateWindow(this.className, ...); }
May 03 2012
prev sibling next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 03 May 2012 13:21:55 -0400, Mehrdad <wfunction hotmail.com> 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.

 The problem is this:
 You make a class like
 class Window
 {
     HWND handle;
     virtual  property string className()  // How the system identifies  
 this subclass
     { /*some default code for lazily registering a class*/ }
     this() { this.handle = className(this.className, ...); }
 }
 which people are supposed to inherit from.

 The trouble is that there is *no clean way* (that I can think of) to  
 ensure this:
 if (typeid(windowA) == typeid(windowB))
 { assert(windowA.className == windowB.className); }

 This is necessary in order to make sure that the idea of a "class" in D  
 is the same as the one that the system sees.

 If className() was class method, this assumption would be trivial to  
 ensure: subclasses could override it, and it would be the same for all  
 instances of the class. It would map to OOP in D **VERY** cleanly.
 Right now, though, it's a big pain to map this concept... and the lack  
 of proper reflection isn't helping.
 (Microsoft just decided to make it an instance property, but if you look  
 at the code, you'll see it's infinitely ugly...)

 Is there any chance that we can get (overridable) class methods in D?
 If not, is there a good solution to this problem?
 (At least, will it be possible to retrieve the static methods of a class  
 with reflection?)

This works: import std.stdio; class A { string name; this() {this.name = typeid(this).name;} } class B : A {} void main() { A b = new B; A a = new A; writefln("A: %s, B: %s", a.name, b.name); } outputs: A: testclassname.A, B: testclassname.B Do what you want with that name, not sure if the window class can have dots in it... (I haven't done much low-level GUI work on windows). Why does this work? Because typeid(obj) gets the TypeInfo based on the object's *derived* type, not it's static type. Since the typeinfo is properly set before the ctor is called, this means you get the correct type. Also, note if there is anything you need via the TypeInfo, it's accessible. Given the recent additions to the compiler and the RTInfo template, you should be able to generate everything you need. -Steve
May 03 2012
next sibling parent reply "Mehrdad" <wfunction hotmail.com> writes:
On Thursday, 3 May 2012 at 17:45:20 UTC, Steven Schveighoffer 
wrote:
 This works:

 import std.stdio;

 class A
 {
   string name;
   this() {this.name = typeid(this).name;}
 }

 class B : A {}

 void main()
 {
    A b = new B;
    A a = new A;
    writefln("A: %s, B: %s", a.name, b.name);
 }

 outputs:

 A: testclassname.A, B: testclassname.B

 -Steve

Oh, but that's only the name! The trouble is that window classes have a lot of attributes -- styles, background brushes, etc. -- that are all shared across instances. There is currently no way (that I know of) to allow a subclass to define its own attributes, *without* also giving it a chance to define them per-instance instead of per-class.
May 03 2012
next sibling parent Simon <s.d.hammett gmail.com> writes:
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
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
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
parent reply Jacob Carlborg <doob me.com> writes:
On 2012-05-04 22:46, Steven Schveighoffer wrote:
 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

Ah, didn't think that far. BTW, why is .classinfo deprecated? -- /Jacob Carlborg
May 04 2012
parent Jacob Carlborg <doob me.com> writes:
On 2012-05-04 23:31, Steven Schveighoffer wrote:

 TBH, I'm not exactly sure that classinfo is officially deprecated, but I
 don't think it appears anywhere in the docs.

http://dlang.org/property.html#classinfo -- /Jacob Carlborg
May 04 2012
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 03 May 2012 13:48:24 -0400, Mehrdad <wfunction hotmail.com> wrote:

 On Thursday, 3 May 2012 at 17:45:20 UTC, Steven Schveighoffer wrote:
 This works:

 import std.stdio;

 class A
 {
   string name;
   this() {this.name = typeid(this).name;}
 }

 class B : A {}

 void main()
 {
    A b = new B;
    A a = new A;
    writefln("A: %s, B: %s", a.name, b.name);
 }

 outputs:

 A: testclassname.A, B: testclassname.B

 -Steve

Oh, but that's only the name! The trouble is that window classes have a lot of attributes -- styles, background brushes, etc. -- that are all shared across instances. There is currently no way (that I know of) to allow a subclass to define its own attributes, *without* also giving it a chance to define them per-instance instead of per-class.

There's the RTInfo method I told you about (recently added) if you want to stick the information directly into TypeInfo at compile time. There's also static ctors. Just add a hashtable based on the class name, and use typeid(this).name as the initial key. You have to handle all the inheritance of properties yourself, but that shouldn't be too difficult. -Steve
May 03 2012
prev sibling next sibling parent "Mehrdad" <wfunction hotmail.com> writes:
 There's the RTInfo method I told you about (recently added) if 
 you want to stick the information directly into TypeInfo at 
 compile time.

 There's also static ctors.  Just add a hashtable based on the 
 class name, and use typeid(this).name as the initial key.  You 
 have to handle all the inheritance of properties yourself, but 
 that shouldn't be too difficult.

 -Steve

Ooh... how do I get RTInfo? It's not in druntime/phobos....
May 03 2012
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 03 May 2012 14:05:26 -0400, Mehrdad <wfunction hotmail.com> wrote:

 There's the RTInfo method I told you about (recently added) if you want  
 to stick the information directly into TypeInfo at compile time.

 There's also static ctors.  Just add a hashtable based on the class  
 name, and use typeid(this).name as the initial key.  You have to handle  
 all the inheritance of properties yourself, but that shouldn't be too  
 difficult.

 -Steve

Ooh... how do I get RTInfo? It's not in druntime/phobos....

https://github.com/D-Programming-Language/druntime/blob/master/import/object.di#L622 Need the github versions of dmd/druntime/phobos. Basically how it works is the compiler evaluates RTInfo!T where T is the type for which TypeInfo is being generated, and places the result into a location that is returned by TypeInfo.rtInfo property. This all happens at compile-time, so it effectively gives you a hook to store runtime type information into the TypeInfo. As far as I know, there's not official documentation on it, it's a pretty beta feature. But I think it will open a door to actual runtime type information that we never had before. One limitation is, it has to be inside the runtime, and specifically in object.di. However, we may be able to effectively generate class/struct specific runtime type information. For example: struct RTTI { // druntime-specified properties ... // type-specific properties void *typeSpecificProperties; } template RTInfo_Instance(T) { static if(is(typeof({void *x = T.__rtInfo();})) immutable RTTI RTInfo_Instance = RTTI(..., T.__rtInfo()); else immutable RTTI RTInfo_Instance = RTTI(..., null); } template RTInfo(T) { immutable void * RTInfo = &RTInfo_Instance!T; } I have no idea if this works :) But I'm *positive* someone with better template skills than me can make something like this work. -Steve
May 03 2012
prev sibling next sibling parent "Mehrdad" <wfunction hotmail.com> writes:
Oo ok I'll take a look at it, thanks.
May 03 2012
prev sibling next sibling parent "Mehrdad" <wfunction hotmail.com> writes:
Hmm... how exactly do you use RTInfo? (Is it usable yet? All I 
see is a void* and a dummy template.)
May 03 2012
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
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
prev sibling next sibling parent "Mehrdad" <wfunction hotmail.com> writes:
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
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
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
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
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
May 04 2012
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 04 May 2012 17:21:57 -0400, Jacob Carlborg <doob me.com> wrote:

 On 2012-05-04 22:46, Steven Schveighoffer wrote:
 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

Ah, didn't think that far. BTW, why is .classinfo deprecated?

Because typeid(this) gives the same exact thing. A long time ago, there was a separate Classinfo type. But it has been merged into TypeInfo. It was determined also that the most useful thing to return from typeid was the runtime TypeInfo, since you could always get the static typeinfo by doing typeid(typeof(x)). TBH, I'm not exactly sure that classinfo is officially deprecated, but I don't think it appears anywhere in the docs. -Steve
May 04 2012
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 04 May 2012 18:05:39 -0400, Jacob Carlborg <doob me.com> wrote:

 On 2012-05-04 23:31, Steven Schveighoffer wrote:

 TBH, I'm not exactly sure that classinfo is officially deprecated, but I
 don't think it appears anywhere in the docs.

http://dlang.org/property.html#classinfo

http://d.puremagic.com/issues/show_bug.cgi?id=8059 :) I also found this statement from Walter while searching for pre-existing bugs: http://forum.dlang.org/post/hffssv$9ro$1 digitalmars.com -Steve
May 07 2012
prev sibling next sibling parent reply Simon <s.d.hammett gmail.com> writes:
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. ;) -- My enormous talent is exceeded only by my outrageous laziness. http://www.ssTk.co.uk
May 03 2012
next sibling parent reply "Mehrdad" <wfunction hotmail.com> writes:
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.
May 03 2012
parent Sean Cavanaugh <WorksOnMyMachine gmail.com> writes:
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 03 2012
prev sibling parent Sean Cavanaugh <WorksOnMyMachine gmail.com> writes:
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 03 2012
prev sibling parent Jacob Carlborg <doob me.com> writes:
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