On Friday, 13 August 2021 at 03:05:22 UTC, Mike Parker wrote:
> On Friday, 13 August 2021 at 00:30:59 UTC, Ruby The Roobster wrote:
> When I run the program and close the window, the program still runs in background mode. I don't know why this happens nor how to fix it. Does anybody know what's going on?
frame beat me to it, but it may well be that you're getting -1. The documentation says that a window that has already been destroyed will result in the hWnd
parameter being invalid, which will cause the function to return -1.
After rewriting the program, I figured out that the bug was still there. Here is the function that causes it:
public class Entity {
package:
ulong id;
wchar[] name;
static ulong nextid;
Point centre;
Skeleton skeleton;
public:
this(ulong id, inout(wchar)[] name,Point centre, Skeleton skeleton) {
assert(init == true, "Error: dutils.entity has not been initialized yet. Call dutils.entity.initialize() to initialize the library.");
this.id = id;
this.name.length = name.length;
for(uint i = 0; i < name.length; i++) {
this.name[i] = name[i];
}
this.nextid = this.id + 1;
this.centre = centre;
if(!skeleton.init) {
this.skeleton = skeleton;
}
entitytable.length +=1;
entitytable[cast(uint)id] = this;
}
~this() {
entitytable.length -= 1;
this.nextid -=1;
did(cast(uint)this.id);
}
debug immutable(char)[] f() @property {
import std.format : format;
return format("ID: %s, Name: %s, NextID: %s, Centre: %s, Skeleton: %s", this.id, this.name, this.nextid, this.centre, this.skeleton);
}
ulong Id() @property {
return id;
}
}
Context for this: I am creating a module of my own, and this is a class contained in the module. You will notice that after calling this class' constructor anywhere in a Win32 API program, that the program doesn't close after the window is closed.
Here are the files:
entity.d:
module dutils.entity;
debug { package import core.sys.windows.winuser; } //For MessageBoxA in debug messages...
public struct Skeleton {
public Face[] faces;
package bool init = false;
public this(Face[] faces) {
this.faces.length = faces.length;
for(uint i = 0; i < faces.length; i++) {
this.faces[i] = faces[i];
}
}
package this(bool init) {
this.init = init;
}
public void opAssign(Skeleton rhs) {
this.faces.length = rhs.faces.length;
for(uint i; i < rhs.faces.length; i++) {
this.faces[i] = rhs.faces[i];
}
this.init = rhs.init;
}
}
public struct Face {
Point[] points;
Point centre;
void opAssign(Face rhs) {
this.points.length = rhs.points.length;
for(uint i = 0; i < rhs.points.length; i++) {
this.points[i] = rhs.points[i];
}
this.centre = rhs.centre;
}
}
public struct Point {
real x;
real y;
real z;
void opAssign(Point rhs) {
this.x = rhs.x;
this.y = rhs.y;
this.z = rhs.z;
}
}
public class Entity {
package:
ulong id;
wchar[] name;
static ulong nextid;
Point centre;
Skeleton skeleton;
public:
this(ulong id, inout(wchar)[] name,Point centre, Skeleton skeleton) {
assert(init == true, "Error: dutils.entity has not been initialized yet. Call dutils.entity.initialize() to initialize the library.");
this.id = id;
this.name.length = name.length;
for(uint i = 0; i < name.length; i++) {
this.name[i] = name[i];
}
this.nextid = this.id + 1;
this.centre = centre;
if(!skeleton.init) {
this.skeleton = skeleton;
}
entitytable.length +=1;
entitytable[cast(uint)id] = this;
}
~this() {
entitytable.length -= 1;
this.nextid -=1;
did(cast(uint)this.id);
}
debug immutable(char)[] f() @property {
import std.format : format;
return format("ID: %s, Name: %s, NextID: %s, Centre: %s, Skeleton: %s", this.id, this.name, this.nextid, this.centre, this.skeleton);
}
ulong Id() @property {
return id;
}
}
public class ImmobileEntity : Entity { //Same as Entity, but with a different constructor...
public:
this(inout(wchar)[] name, Point centre, Skeleton skeleton)
in {
assert(skeleton.init == false, "Error: Member Skeleton.init must always be set to false.");
}
do {
super(this.nextid, name, centre, skeleton);
}
}
public class MobileEntity : Entity { //Same as entity, but has a move feature(and a speed in miliseconds per whole number moved)...
package:
uint speed;
public:
this(inout(wchar)[] name, Point centre, Skeleton skeleton, uint speed)
in {
assert(skeleton.init == false, "Error: Member Skeleton.init must always be set to false.");
}
do {
super(this.nextid, name, centre, skeleton);
this.speed = speed;
}
void move(Point newpos) { //Distance between one point and another
import core.thread;
import core.math : sqrt;
real temp = sqrt(((newpos.x - this.centre.x)^^2) + ((newpos.y - this.centre.y)^^2) + ((newpos.z - this.centre.z)^^2));
temp *= speed;
uint time = cast(uint) temp;
Thread.sleep(dur!("msecs")(time));
this.centre = newpos;
}
}
package bool init;
package Entity entity;
public Entity[] entitytable;
public void initialize() {
entitytable.length = 0;
init = true;
entity = new Entity(0, "BaseEntityInitialized@id0"w, Point(0,0,0), Skeleton(true));
}
public void terminate() {
for(uint i = 0; i < entitytable.length; i++) {
destroy(entitytable[i]);
}
entitytable.length = 0;
}
package void did(uint currid) {
for(uint i = currid; i < entitytable.length; i++) {
entitytable[i].id -=1;
}
}
debug {
public void DebugInfo() { //Debug messages...
for(uint i = 0; i < entitytable.length; i++) {
MessageBoxA(null,cast(const(char)*)entitytable[i].f,"Test", MB_ICONINFORMATION | MB_OK);
}
}
}
test.d
import core.sys.windows.windef;
import core.runtime;
import core.sys.windows.wingdi;
import core.sys.windows.winuser;
import entity;
bool exit = false;
extern(Windows)
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
int ret;
try {
Runtime.initialize();
ret = prog(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
Runtime.terminate();
}
catch(Throwable o) {
MessageBoxA(null, "Error","Error", MB_OK | MB_ICONERROR);
}
debug MessageBoxA(null, "HERE!", "HERE!", MB_OK);
return ret;
}
int prog(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int CmdShow) {
WNDCLASSW wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = &WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = cast(HBRUSH)GetStockObject(GRAY_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = cast(const(wchar)*)"Test"w;
if(!RegisterClassW(&wndclass)) {
throw new Exception("F");
}
HWND hwnd = CreateWindowW(cast(const(wchar)*)"Test"w, cast(const(wchar)*)"Test Program"w, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 900, 900, NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, CmdShow);
UpdateWindow(hwnd);
MSG msg;
while((GetMessage(&msg,NULL,0,0))) {
if(exit) {
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
debug MessageBoxA(null, "HERE!", "HERE!", MB_OK);
}
return msg.wParam;
}
extern(Windows)
LRESULT WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) nothrow {
switch(msg) {
case WM_CREATE:
try {
entity.initialize();
Skeleton pyrskel;
Face[4] pyrfaces;
Point[3][2] pyrpoints;
pyrpoints[0][0] = Point(0, 0, 1);
pyrpoints[0][1] = Point(-1, 0, -1);
pyrpoints[0][2] = Point(1, 0, -1);
pyrpoints[1][0] = Point(0, 0.75, -0.5);
pyrpoints[1][1] = Point(-1, 0, 0.5);
pyrpoints[1][2] = Point(1, 0, -0.5);
for(uint i = 0;i < 3;i++) {
pyrfaces[i].points.length = 3;
for(uint j = 0;j < 3;j++) {
pyrfaces[i].points[j] = pyrpoints[1][j];
}
}
for(uint i = 0;i < 3;i++) {
pyrfaces[3].points.length = 3;
pyrfaces[3].points[i] = pyrpoints[0][i];
}
pyrskel = Skeleton(pyrfaces);
auto Pyramid = new Entity(entitytable[0].Id+1,"Pyramid"w, Point(0,0,0), pyrskel);
}
catch(Throwable e) {
MessageBoxA(hwnd,"ERROR", "ERROR", MB_OK | MB_ICONERROR);
PostQuitMessage(1);
}
return 0;
break;
case WM_CLOSE:
try {
entity.terminate();
DestroyWindow(hwnd);
}
catch(Throwable e) {
MessageBoxA(hwnd, "ERROR", "ERROR", MB_OK | MB_ICONERROR);
}
DestroyWindow(hwnd);
exit = true;
break;
case WM_DESTROY:
exit = true;
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd,msg,wparam,lparam);
}
return 0;
}
Sorry for the inconvenience and longness of this post.
P.S: The issue isn't GetMessage(), I can confirm that.