July 27, 2017
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.
July 27, 2017
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.
July 27, 2017
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.
July 26, 2017
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
July 27, 2017
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.

July 27, 2017
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.
July 27, 2017
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
July 27, 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

July 28, 2017
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*)&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.

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?


1 2
Next ›   Last »