Re: Silent error when using hashmap
On Thursday, 27 July 2017 at 14:09:37 UTC, Mike Parker wrote: 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). Figures that the different calling conventions inside the depths of windows wouldn't be unwound properly. I'll just make sure to do blanket try catches for all throwables in each of these extern windows functions so that the buffer flushes for debug output and then explicitly exit the program. 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; ``` Knew about this but didn't think you could do this in one line. This is fantastic. 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. 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*)). 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. So in the language, references to class objects are treated the same syntactically as pointers? So if we were in C++, me declaraing a WinThing** (reference to a reference to an object) is the same as WinThing* in D? Tried out your changes, that definately cleaned up the mess. Why can I not also do the same with the create struct like: CREATESTRUCT createStruct = cast(CREATESTRUCT) lparam; I take it this is because CREATESTRUCT is not a D class, but a struct somewhere? Note that you don't have to dereference the createStruct pointer to access its fields. Nice tip, didn't realize D implicitly dereferenced pointers when you apply the dot operator. Very nice. 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; Is the only difference between this and private static immutable values that the enum could not be an lvalue and has no reference at runtime?
Re: Silent error when using hashmap
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*)). 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
Re: Silent error when using hashmap
On 7/26/17 10:30 PM, FatalCatharsis wrote: On Thursday, 27 July 2017 at 01:21:40 UTC, Steven Schveighoffer wrote: the writeln("start"); and writeln("end"); in main. This is what I meant by printing. These do not appear in the output. The programs starts and immediately ends without printing "start" and "end". try flushing the output. In some cases the output streams do not flush on newlines. I did not put an output in the exception handler of the WndProc because writeln can throw and the function is marked nothrow. All I as trying to do there was get it to recover. Just surround writeln with try/catch(Exception), should work. You could also just use good old printf. This appears to be it. When an error is thrown, stdout does not flush. When I put stdout.flush() immediately after the writeln("start") at the beginning it is printed correctly. However, when I try to catch the error and then do stdout.flush() in main, it does not print. Do you know of a way to make D always flush the output buffer when an error is thrown? Are you sure the error is being caught? I thought the event loop was run in a separate thread. Not sure, because I don't do windows development. Try catching the error right in the event handler. -Steve
Re: Silent error when using hashmap
On Thursday, 27 July 2017 at 02:30:17 UTC, FatalCatharsis wrote: On Thursday, 27 July 2017 at 01:21:40 UTC, Steven Schveighoffer wrote: [...] This appears to be it. When an error is thrown, stdout does not flush. When I put stdout.flush() immediately after the writeln("start") at the beginning it is printed correctly. However, when I try to catch the error and then do stdout.flush() in main, it does not print. Do you know of a way to make D always flush the output buffer when an error is thrown? On Thursday, 27 July 2017 at 01:05:28 UTC, ketmar wrote: [...] Yes, I understand this. This is not my question. My question is why all previous output to the console does not occur before the error is thrown. As Steve said, this is because the output buffer is not flushed when an error occurs. I just noticed this without an exception. I changed my writeln's to write and printed a "\n" but it did not flush. Had to flush it manually. Not sure if that is by design or what.
Re: Silent error when using hashmap
On Thursday, 27 July 2017 at 01:21:40 UTC, Steven Schveighoffer wrote: the writeln("start"); and writeln("end"); in main. This is what I meant by printing. These do not appear in the output. The programs starts and immediately ends without printing "start" and "end". try flushing the output. In some cases the output streams do not flush on newlines. I did not put an output in the exception handler of the WndProc because writeln can throw and the function is marked nothrow. All I as trying to do there was get it to recover. Just surround writeln with try/catch(Exception), should work. You could also just use good old printf. -Steve This appears to be it. When an error is thrown, stdout does not flush. When I put stdout.flush() immediately after the writeln("start") at the beginning it is printed correctly. However, when I try to catch the error and then do stdout.flush() in main, it does not print. Do you know of a way to make D always flush the output buffer when an error is thrown? On Thursday, 27 July 2017 at 01:05:28 UTC, ketmar wrote: 'cause, as i said, RangeError is not an exception. i thought that you already know it, as this is "general", not "learning" NG. Yes, I understand this. This is not my question. My question is why all previous output to the console does not occur before the error is thrown. As Steve said, this is because the output buffer is not flushed when an error occurs.
Re: Silent error when using hashmap
On 7/26/17 8:51 PM, FatalCatharsis wrote: On Thursday, 27 July 2017 at 00:48:48 UTC, ketmar wrote: FatalCatharsis wrote: On Thursday, 27 July 2017 at 00:34:28 UTC, ketmar wrote: wrap the whole event handler function in `try/catch` block, and print it there. after all, this is what Dmain does, and so can you. having *full* stack trace has no sense there anyway, as you know for sure that event handler is called by windows, not by you (and usually from your event loop anyway, so detailed stack trace has little useful info). I tried that like so: https://gist.github.com/FatalCatharsis/39c5f35ae78ecd5399eebe0fb2491004 I put exception blocks both around main and around the invocation of the hash lookup and still get no printouts anywhere, including at the beginning and end of main. 'cause you never printed anything. the writeln("start"); and writeln("end"); in main. This is what I meant by printing. These do not appear in the output. The programs starts and immediately ends without printing "start" and "end". try flushing the output. In some cases the output streams do not flush on newlines. I did not put an output in the exception handler of the WndProc because writeln can throw and the function is marked nothrow. All I as trying to do there was get it to recover. Just surround writeln with try/catch(Exception), should work. You could also just use good old printf. -Steve
Re: Silent error when using hashmap
FatalCatharsis wrote: On Thursday, 27 July 2017 at 00:48:48 UTC, ketmar wrote: FatalCatharsis wrote: On Thursday, 27 July 2017 at 00:34:28 UTC, ketmar wrote: wrap the whole event handler function in `try/catch` block, and print it there. after all, this is what Dmain does, and so can you. having *full* stack trace has no sense there anyway, as you know for sure that event handler is called by windows, not by you (and usually from your event loop anyway, so detailed stack trace has little useful info). I tried that like so: https://gist.github.com/FatalCatharsis/39c5f35ae78ecd5399eebe0fb2491004 I put exception blocks both around main and around the invocation of the hash lookup and still get no printouts anywhere, including at the beginning and end of main. 'cause you never printed anything. the writeln("start"); and writeln("end"); in main. This is what I meant by printing. These do not appear in the output. The programs starts and immediately ends without printing "start" and "end". I did not put an output in the exception handler of the WndProc because writeln can throw and the function is marked nothrow. All I as trying to do there was get it to recover. 'cause, as i said, RangeError is not an exception. i thought that you already know it, as this is "general", not "learning" NG.
Re: Silent error when using hashmap
On Thursday, 27 July 2017 at 00:48:48 UTC, ketmar wrote: FatalCatharsis wrote: On Thursday, 27 July 2017 at 00:34:28 UTC, ketmar wrote: wrap the whole event handler function in `try/catch` block, and print it there. after all, this is what Dmain does, and so can you. having *full* stack trace has no sense there anyway, as you know for sure that event handler is called by windows, not by you (and usually from your event loop anyway, so detailed stack trace has little useful info). I tried that like so: https://gist.github.com/FatalCatharsis/39c5f35ae78ecd5399eebe0fb2491004 I put exception blocks both around main and around the invocation of the hash lookup and still get no printouts anywhere, including at the beginning and end of main. 'cause you never printed anything. the writeln("start"); and writeln("end"); in main. This is what I meant by printing. These do not appear in the output. The programs starts and immediately ends without printing "start" and "end". I did not put an output in the exception handler of the WndProc because writeln can throw and the function is marked nothrow. All I as trying to do there was get it to recover.
Re: Silent error when using hashmap
FatalCatharsis wrote: On Thursday, 27 July 2017 at 00:34:28 UTC, ketmar wrote: wrap the whole event handler function in `try/catch` block, and print it there. after all, this is what Dmain does, and so can you. having *full* stack trace has no sense there anyway, as you know for sure that event handler is called by windows, not by you (and usually from your event loop anyway, so detailed stack trace has little useful info). I tried that like so: https://gist.github.com/FatalCatharsis/39c5f35ae78ecd5399eebe0fb2491004 I put exception blocks both around main and around the invocation of the hash lookup and still get no printouts anywhere, including at the beginning and end of main. besides, RangeError is not Exception.
Re: Silent error when using hashmap
FatalCatharsis wrote: On Thursday, 27 July 2017 at 00:34:28 UTC, ketmar wrote: wrap the whole event handler function in `try/catch` block, and print it there. after all, this is what Dmain does, and so can you. having *full* stack trace has no sense there anyway, as you know for sure that event handler is called by windows, not by you (and usually from your event loop anyway, so detailed stack trace has little useful info). I tried that like so: https://gist.github.com/FatalCatharsis/39c5f35ae78ecd5399eebe0fb2491004 I put exception blocks both around main and around the invocation of the hash lookup and still get no printouts anywhere, including at the beginning and end of main. 'cause you never printed anything.
Re: Silent error when using hashmap
On Thursday, 27 July 2017 at 00:34:28 UTC, ketmar wrote: wrap the whole event handler function in `try/catch` block, and print it there. after all, this is what Dmain does, and so can you. having *full* stack trace has no sense there anyway, as you know for sure that event handler is called by windows, not by you (and usually from your event loop anyway, so detailed stack trace has little useful info). I tried that like so: https://gist.github.com/FatalCatharsis/39c5f35ae78ecd5399eebe0fb2491004 I put exception blocks both around main and around the invocation of the hash lookup and still get no printouts anywhere, including at the beginning and end of main.
Re: Silent error when using hashmap
FatalCatharsis wrote: On Thursday, 27 July 2017 at 00:12:20 UTC, ketmar wrote: 'cause windows' event handler called from darkes depths of windows code, and D just can't make sense of the stack to unwind it properly and to show you error message and stack trace. never ever rely on getting proper stack traces for exceptions thrown in windows callbacks: it *may* work sometimes, but it is not guaranteed. Is there a way to get it to not fail so hard so that prints that occur before and after the failure aren't lost? The "begin" and "end" in the main don't even get output when the failure happens. wrap the whole event handler function in `try/catch` block, and print it there. after all, this is what Dmain does, and so can you. having *full* stack trace has no sense there anyway, as you know for sure that event handler is called by windows, not by you (and usually from your event loop anyway, so detailed stack trace has little useful info).
Re: Silent error when using hashmap
On Thursday, 27 July 2017 at 00:12:20 UTC, ketmar wrote: 'cause windows' event handler called from darkes depths of windows code, and D just can't make sense of the stack to unwind it properly and to show you error message and stack trace. never ever rely on getting proper stack traces for exceptions thrown in windows callbacks: it *may* work sometimes, but it is not guaranteed. Is there a way to get it to not fail so hard so that prints that occur before and after the failure aren't lost? The "begin" and "end" in the main don't even get output when the failure happens.
Re: Silent error when using hashmap
FatalCatharsis wrote: On Wednesday, 26 July 2017 at 16:39:15 UTC, ketmar wrote:> 'cause `WM_CREATE` is not the first message window receiving. check if hwnd is in hash with `in` first. 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. 'cause windows' event handler called from darkes depths of windows code, and D just can't make sense of the stack to unwind it properly and to show you error message and stack trace. never ever rely on getting proper stack traces for exceptions thrown in windows callbacks: it *may* work sometimes, but it is not guaranteed.
Re: Silent error when using hashmap
On Wednesday, 26 July 2017 at 16:39:15 UTC, ketmar wrote:> 'cause `WM_CREATE` is not the first message window receiving. check if hwnd is in hash with `in` first. 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. On Wednesday, 26 July 2017 at 22:08:45 UTC, Steven Schveighoffer wrote: Note that in D when a thread crashes besides the main thread, you may not get a stack trace printout. You may get nothing. -Steve This example doesn't create any threads explicitly. Are there other threads that dlang generates? How do I obtain debug output and proper exception handling from these threads?
Re: Silent error when using hashmap
On 7/26/17 12:09 PM, FatalCatharsis wrote: I apologize, I'm not sure if this is expected behavior, a bug in the compiler, or a bug in the core windows libraries, so I'll post this here until pointed elsewhere. I've done this trick with win32 for awhile in other languages where I pass a reference to a specific class of my own that represents an instance of window to the CreateWindowEx function, and then use a static router function to send messages to the specific instance. I've made the most minimal example I can in this gist. https://gist.github.com/FatalCatharsis/d3cc6ec621f0600975806fe23610ae32 When I compile this and run this, nothing is printed and no window is created. I've tried putting try catches around everything (including the inside of the static constructor), but nothing is caught. Note that in D when a thread crashes besides the main thread, you may not get a stack trace printout. You may get nothing. -Steve
Re: Silent error when using hashmap
On Wednesday, 26 July 2017 at 16:09:30 UTC, FatalCatharsis wrote: When I compile this and run this, nothing is printed and no window is created. I've tried putting try catches around everything (including the inside of the static constructor), but nothing is caught. You're casting this to void*, which is correct, but then when you fetch it back you're casting to a WinThing*, which is not correct. this is a reference, not a pointer. Cast to WinThing instead of WinThing*.
Re: Silent error when using hashmap
FatalCatharsis wrote: I apologize, I'm not sure if this is expected behavior, a bug in the compiler, or a bug in the core windows libraries, so I'll post this here until pointed elsewhere. I've done this trick with win32 for awhile in other languages where I pass a reference to a specific class of my own that represents an instance of window to the CreateWindowEx function, and then use a static router function to send messages to the specific instance. I've made the most minimal example I can in this gist. https://gist.github.com/FatalCatharsis/d3cc6ec621f0600975806fe23610ae32 When I compile this and run this, nothing is printed and no window is created. I've tried putting try catches around everything (including the inside of the static constructor), but nothing is caught. However, when I comment out the hash lookup on line 54, the compiled program runs fine and creates a window, (but only for a moment since there is not a message handling loop). The expected printout of "start" and "end" occurs just fine. What is happening here that causes the program not execute at all, with no output and no exceptions? Is this a bug with my code, a bug with the core.sys.windows.windows library, or a bug with the compiler? Any info about how to debug this further is greatly appreciated. 'cause `WM_CREATE` is not the first message window receiving. check if hwnd is in hash with `in` first.
Silent error when using hashmap
I apologize, I'm not sure if this is expected behavior, a bug in the compiler, or a bug in the core windows libraries, so I'll post this here until pointed elsewhere. I've done this trick with win32 for awhile in other languages where I pass a reference to a specific class of my own that represents an instance of window to the CreateWindowEx function, and then use a static router function to send messages to the specific instance. I've made the most minimal example I can in this gist. https://gist.github.com/FatalCatharsis/d3cc6ec621f0600975806fe23610ae32 When I compile this and run this, nothing is printed and no window is created. I've tried putting try catches around everything (including the inside of the static constructor), but nothing is caught. However, when I comment out the hash lookup on line 54, the compiled program runs fine and creates a window, (but only for a moment since there is not a message handling loop). The expected printout of "start" and "end" occurs just fine. What is happening here that causes the program not execute at all, with no output and no exceptions? Is this a bug with my code, a bug with the core.sys.windows.windows library, or a bug with the compiler? Any info about how to debug this further is greatly appreciated.