On Thursday, 27 July 2017 at 00:07:39 UTC, FatalCatharsis wrote:

I figured this was the case. WM_NCCREATE is probably sent first and the lookup fails. I'm more concerned with why there was no exceptions/debug output of any kind.

There are a few things going on with your code. I'll break it down one at a time.

1. You can't expect exceptions thrown in a callback called from C to be propagated through the C side back into the D side. That includes errors. It happens on some platforms, but not all. On Windows, it does not (at least, not with DMD -- I can't speak for LDC).

2. The error you're getting is because neither WM_CREATE nore WM_NCCREATE is the first message sent. You can see this by inserting the following into your WndProc:

```
static UINT first;
if(msg == WM_NCCREATE) {
    try {
        if(first == 0) writeln("NCCREATE is first");
        else writeln("First is ", first);
    }
    catch(Exception e){}
}
else {
    // window = winMap[hwnd];
    if(first == 0) first = msg;
}
```

This prints 36, which if you look it up (hexcode on MSDN, but I like the list at WineHQ [1]) will show you is WM_GETMINMAXINFO. That means that when you try to fetch the window instance from winMap, there's nothing there. When you try to access a non-extent element in an AA, you get a RangeError. Because of point 1 above, you're never seeing it and instead are getting a crash.

You could try to catch the error and stash it for later, but better to do change the way you access the map:

```
if(auto pwin = hwnd in winMap) window = *pwin;
```

The in operator returns a pointer, so it needs to be dereferenced.

3. As I mentioned in another post in this thread, you are doing the wrong thing with your window reference. In your call to CreateWindowEx, you are correctly casting the reference to void*. Everywhere else, you're treating it as a pointer. That's wrong! To prove it, you can to this. Declare an instance of WinThing at the top of the file.

```
WinThing testMe;
```

Then, add this in the class constructor *before* the call to CreateWindowEx.

```
testMe = this;
```

Finally, where you handle the WM_NCCREATE message, do this:

```
try writeln("window is testMe = ", *window is testMe);
catch(Exception e) {}
```

This will print false. Why? Because the window instance you created is a reference. In CreateWindowEx, you've treated it as such. But then when you fetch it out of lpCreateParams, you cast it to a WinThing*. For that to be correct, you would have to change CreateWindowEx to pass a pointer to the reference (i.e. cast(void*)&window). But actually, that's still not correct because you're taking the address of a local variable. So the correct thing to do is to leave CreateWindowEx as is, and change all every WinThing* to WinThing.

```
WinThing[HWND] winMap;

WinThing window;
window = cast(WinThing)createStruct.lpCreateParams;
```

Note that you don't have to dereference the createStruct pointer to access its fields.

Fix these these issues and it should compile. One other thing, in case you are unaware (not an error, just a matter of style).

```
private static string BASE_CLASS = "BaseClass";
```

There's no reason to make this static member or to call toUTFz when you use it. You can use a manifest constant with a wchar literal. Unlike char -> char*, whcar does not implicitly convert to wchar*, but you can use the .ptr property.

enum baseClass = "BaseClass"w;
wc.lpszClassName = baseClass.ptr;

[1] https://wiki.winehq.org/List_Of_Windows_Messages

Reply via email to