Silent error when using hashmap
Mike Parker via Digitalmars-d
digitalmars-d at puremagic.com
Thu Jul 27 07:09:37 PDT 2017
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
More information about the Digitalmars-d
mailing list