Fixed SharedControl class, Control.invoke method and Control.delayInvoke method

This commit is contained in:
haru-s 2024-08-27 00:03:06 +09:00
parent bdd8449947
commit bf168783ef
3 changed files with 228 additions and 166 deletions

View file

@ -1866,20 +1866,18 @@ extern(Windows) LRESULT dflWndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lp
{
switch(wparam)
{
case WPARAM_DFL_INVOKE:
case WPARAM_DFL_INVOKE_PARAMS:
{
InvokeData* pinv;
pinv = cast(InvokeData*)lparam;
DflInvokeParam* p = cast(DflInvokeParam*)lparam;
try
{
pinv.result = pinv.dg(pinv.args);
p.fp(Application.lookupHwnd(hwnd), p.params.ptr[0 .. p.nparams]);
}
catch(DThrowable e)
{
//Application.onThreadException(e);
try
{
pinv.exception = e;
p.exception = e;
}
catch(DThrowable e2)
{
@ -1889,20 +1887,18 @@ extern(Windows) LRESULT dflWndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lp
}
return LRESULT_DFL_INVOKE;
case WPARAM_DFL_INVOKE_SIMPLE:
case WPARAM_DFL_INVOKE_NOPARAMS:
{
InvokeSimpleData* pinv;
pinv = cast(InvokeSimpleData*)lparam;
DflInvokeParam* p = cast(DflInvokeParam*)lparam;
try
{
pinv.dg();
p.fp(Application.lookupHwnd(hwnd), p.params);
}
catch(DThrowable e)
{
//Application.onThreadException(e);
try
{
pinv.exception = e;
p.exception = e;
}
catch(DThrowable e2)
{
@ -1912,21 +1908,24 @@ extern(Windows) LRESULT dflWndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lp
}
return LRESULT_DFL_INVOKE;
case WPARAM_DFL_DELAY_INVOKE:
try
case WPARAM_DFL_DELAY_INVOKE_NOPARAMS:
{
(cast(void function())lparam)();
}
catch(DThrowable e)
{
Application.onThreadException(e);
DflInvokeParam* p = cast(DflInvokeParam*)lparam;
try
{
p.fp(Application.lookupHwnd(hwnd), p.params);
}
catch(DThrowable e)
{
Application.onThreadException(e);
}
dfl.internal.clib.free(p);
}
break;
case WPARAM_DFL_DELAY_INVOKE_PARAMS:
{
DflInvokeParam* p;
p = cast(DflInvokeParam*)lparam;
DflInvokeParam* p = cast(DflInvokeParam*)lparam;
try
{
p.fp(Application.lookupHwnd(hwnd), p.params.ptr[0 .. p.nparams]);
@ -2044,36 +2043,20 @@ else
enum LRESULT LRESULT_DFL_INVOKE = 0x95FADF; // Magic number.
struct InvokeData
{
Object delegate(Object[]) dg;
Object[] args;
Object result;
DThrowable exception = null;
}
struct InvokeSimpleData
{
void delegate() dg;
DThrowable exception = null;
}
UINT wmDfl;
enum: WPARAM
{
WPARAM_DFL_INVOKE = 78,
WPARAM_DFL_DELAY_INVOKE = 79,
WPARAM_DFL_INVOKE_PARAMS = 78,
WPARAM_DFL_DELAY_INVOKE_NOPARAMS = 79,
WPARAM_DFL_DELAY_INVOKE_PARAMS = 80,
WPARAM_DFL_INVOKE_SIMPLE = 81,
WPARAM_DFL_INVOKE_NOPARAMS = 81,
}
struct DflInvokeParam
{
void function(Control, size_t[]) fp;
DThrowable exception;
size_t nparams;
size_t[1] params;
}

View file

@ -3614,16 +3614,37 @@ class Control: DObject, IWindow // docmain
if(!hwnd)
badInvokeHandle();
InvokeData inv;
inv.dg = dg;
inv.args = args;
static assert((DflInvokeParam*).sizeof <= LPARAM.sizeof);
if(LRESULT_DFL_INVOKE != SendMessageA(hwnd, wmDfl, WPARAM_DFL_INVOKE, cast(LRESULT)&inv))
static struct DelegateInvokeParam
{
Object delegate(Object[]) dg;
Object result;
Object[] args;
}
static void funcEntry(Control c, size_t[] p)
{
auto dip = cast(DelegateInvokeParam*)p[0];
dip.result = dip.dg(dip.args);
}
DelegateInvokeParam dip;
dip.dg = dg;
dip.args = args;
DflInvokeParam dflInvokeParam;
dflInvokeParam.fp = &funcEntry;
dflInvokeParam.exception = null;
dflInvokeParam.nparams = args.length;
dflInvokeParam.params[0] = cast(size_t)&dip;
if(LRESULT_DFL_INVOKE != SendMessageA(hwnd, wmDfl, WPARAM_DFL_INVOKE_PARAMS, cast(LPARAM)&dflInvokeParam))
throw new DflException("Invoke failure");
if(inv.exception)
throw inv.exception;
if(dflInvokeParam.exception)
throw dflInvokeParam.exception;
return inv.result;
return dip.result;
}
/// ditto
@ -3632,13 +3653,32 @@ class Control: DObject, IWindow // docmain
if(!hwnd)
badInvokeHandle();
InvokeSimpleData inv;
inv.dg = dg;
static assert((DflInvokeParam*).sizeof <= LPARAM.sizeof);
static struct DelegateInvokeParam
{
void delegate() dg;
}
static void funcEntry(Control c, size_t[] p)
{
auto dip = cast(DelegateInvokeParam*)p[0];
dip.dg();
}
DelegateInvokeParam dip;
dip.dg = dg;
DflInvokeParam dflInvokeParam;
dflInvokeParam.fp = &funcEntry;
dflInvokeParam.exception = null;
dflInvokeParam.nparams = 0;
dflInvokeParam.params[0] = cast(size_t)&dip;
if(LRESULT_DFL_INVOKE != SendMessageA(hwnd, wmDfl, WPARAM_DFL_INVOKE_SIMPLE, cast(LRESULT)&inv))
if(LRESULT_DFL_INVOKE != SendMessageA(hwnd, wmDfl, WPARAM_DFL_INVOKE_NOPARAMS, cast(LPARAM)&dflInvokeParam))
throw new DflException("Invoke failure");
if(inv.exception)
throw inv.exception;
if(dflInvokeParam.exception)
throw dflInvokeParam.exception;
}
@ -3654,10 +3694,24 @@ class Control: DObject, IWindow // docmain
if(!hwnd)
badInvokeHandle();
assert(!invokeRequired);
static assert(fn.sizeof <= LPARAM.sizeof);
PostMessageA(hwnd, wmDfl, WPARAM_DFL_DELAY_INVOKE, cast(LPARAM)fn);
static assert((DflInvokeParam*).sizeof <= LPARAM.sizeof);
static void funcEntry(Control c, size_t[] p)
{
auto func = cast(void function())p[0];
func();
}
DflInvokeParam* dflInvokeParam = cast(DflInvokeParam*)malloc(DflInvokeParam.sizeof);
if(!dflInvokeParam)
throw new OomException();
dflInvokeParam.fp = &funcEntry;
dflInvokeParam.exception = null;
dflInvokeParam.nparams = 0;
dflInvokeParam.params[0] = cast(size_t)fn;
PostMessageA(hwnd, wmDfl, WPARAM_DFL_DELAY_INVOKE_NOPARAMS, cast(LPARAM)dflInvokeParam);
}
/// ditto
@ -3671,22 +3725,19 @@ class Control: DObject, IWindow // docmain
if(!hwnd)
badInvokeHandle();
assert(!invokeRequired);
static assert((DflInvokeParam*).sizeof <= LPARAM.sizeof);
DflInvokeParam* p;
p = cast(DflInvokeParam*)dfl.internal.clib.malloc(
(DflInvokeParam.sizeof - size_t.sizeof)
+ params.length * size_t.sizeof);
if(!p)
DflInvokeParam* dflInvokeParams = cast(DflInvokeParam*)malloc(
DflInvokeParam.sizeof - size_t.sizeof + params.length * size_t.sizeof);
if(!dflInvokeParams)
throw new OomException();
p.fp = fn;
p.nparams = params.length;
p.params.ptr[0 .. params.length] = params[];
dflInvokeParams.fp = fn;
dflInvokeParams.exception = null;
dflInvokeParams.nparams = params.length;
dflInvokeParams.params.ptr[0 .. params.length] = params[];
PostMessageA(hwnd, wmDfl, WPARAM_DFL_DELAY_INVOKE_PARAMS, cast(LPARAM)p);
PostMessageA(hwnd, wmDfl, WPARAM_DFL_DELAY_INVOKE_PARAMS, cast(LPARAM)dflInvokeParams);
}
deprecated alias beginInvoke = delayInvoke;
@ -8323,15 +8374,3 @@ class ContainerControl: ScrollableControl, IContainerControl // docmain
return false;
}
}
private template hasLocalAliasing(T...)
{
import std.traits, std.typecons;
static if( !T.length )
enum hasLocalAliasing = false;
else
enum hasLocalAliasing = std.traits.hasLocalAliasing!(T[0]) ||
dfl.control.hasLocalAliasing!(T[1 .. $]);
}

View file

@ -5,12 +5,13 @@
///
module dfl.sharedcontrol;
private import dfl.base;
private import dfl.control;
private import dfl.application;
private import dfl.internal.winapi;
private import dfl.internal.dlib;
private import dfl.internal.clib;
private import dfl.internal.clib : malloc, free;
///
shared class SharedControl
@ -18,72 +19,49 @@ shared class SharedControl
private:
Control _ctrl;
LPARAM makeParam(ARGS...)(void function(Control, ARGS) fn, Tuple!(ARGS)* args)
void makeParam(ARGS...)(void function(Control, ARGS) func, ARGS args, DflInvokeParam* dflInvokeParam)
if (ARGS.length)
{
static assert((DflInvokeParam*).sizeof <= LPARAM.sizeof);
static struct InvokeParam
static struct FunctionInvokeParam
{
void function(Control, ARGS) fn;
void function(Control, ARGS) func;
ARGS args;
}
alias malloc = dfl.internal.clib.malloc;
alias free = dfl.internal.clib.free;
auto param = cast(InvokeParam*)malloc(InvokeParam.sizeof);
param.fn = fn;
param.args = args.field;
if (!param)
auto invokeParam = cast(FunctionInvokeParam*)malloc(FunctionInvokeParam.sizeof);
if (!invokeParam)
throw new OomException();
invokeParam.func = func;
invokeParam.args = args;
auto p = cast(DflInvokeParam*)malloc(DflInvokeParam.sizeof);
if (!p)
throw new OomException();
static void fnentry(Control c, size_t[] p)
static void funcEntry(Control c, size_t[] p)
{
auto param = cast(InvokeParam*)p[0];
param.fn(c, param.args);
auto param = cast(FunctionInvokeParam*)p[0];
param.func(c, param.args);
free(param);
}
p.fp = &fnentry;
p.nparams = 1;
p.params[0] = cast(size_t)param;
return cast(LPARAM)p;
dflInvokeParam.fp = &funcEntry;
dflInvokeParam.exception = null;
dflInvokeParam.nparams = 1;
dflInvokeParam.params[0] = cast(size_t)invokeParam;
}
LPARAM makeParamNoneArgs(void function(Control) fn)
void makeParamNoneArgs(void function(Control) func, DflInvokeParam* dflInvokeParam)
{
static assert((DflInvokeParam*).sizeof <= LPARAM.sizeof);
alias malloc = dfl.internal.clib.malloc;
alias free = dfl.internal.clib.free;
auto p = cast(DflInvokeParam*)malloc(DflInvokeParam.sizeof);
if (!p)
throw new OomException();
static void fnentry(Control c, size_t[] p)
static void funcEntry(Control c, size_t[] p)
{
auto fn = cast(void function(Control))p[0];
fn(c);
auto func = cast(void function(Control))p[0];
func(c);
}
p.fp = &fnentry;
p.nparams = 1;
p.params[0] = cast(size_t)fn;
return cast(LPARAM)p;
dflInvokeParam.fp = &funcEntry;
dflInvokeParam.exception = null;
dflInvokeParam.nparams = 0;
dflInvokeParam.params[0] = cast(size_t)func;
}
public:
///
this(Control ctrl)
@ -91,62 +69,124 @@ public:
assert(ctrl);
_ctrl = cast(shared)ctrl;
}
///
void invoke(ARGS...)(void function(Control, ARGS) fn, ARGS args)
void invoke(ARGS...)(void function(Control, ARGS) func, ARGS args)
if (ARGS.length && !hasLocalAliasing!(ARGS))
{
auto ctrl = cast(Control)_ctrl;
auto hwnd = ctrl.handle;
if(!hwnd)
Control.badInvokeHandle();
auto t = tuple(args);
auto p = makeParam(fn, &t);
SendMessageA(hwnd, wmDfl, WPARAM_DFL_DELAY_INVOKE_PARAMS, p);
synchronized
{
auto ctrl = cast(Control)_ctrl;
auto hwnd = ctrl.handle;
if(!hwnd)
throw new DflException("Must invoke with created handle"); // Control.badInvokeHandle();
static assert((DflInvokeParam*).sizeof <= LPARAM.sizeof);
auto dflInvokeParam = cast(DflInvokeParam*)malloc(DflInvokeParam.sizeof);
if (!dflInvokeParam)
throw new OomException();
makeParam(func, args, dflInvokeParam);
scope(exit)
{
free(dflInvokeParam);
}
if (LRESULT_DFL_INVOKE != SendMessageA(hwnd, wmDfl, WPARAM_DFL_INVOKE_PARAMS, cast(LPARAM)dflInvokeParam))
throw new DflException("Invoke failure");
if (dflInvokeParam.exception)
throw dflInvokeParam.exception;
}
}
///
void invoke(ARGS...)(void function(Control, ARGS) fn, ARGS args)
void invoke(ARGS...)(void function(Control, ARGS) func, ARGS args)
if (!ARGS.length)
{
auto ctrl = cast(Control)_ctrl;
auto hwnd = ctrl.handle;
if(!hwnd)
Control.badInvokeHandle();
auto p = makeParamNoneArgs(fn);
SendMessageA(hwnd, wmDfl, WPARAM_DFL_DELAY_INVOKE_PARAMS, p);
synchronized
{
auto ctrl = cast(Control)_ctrl;
auto hwnd = ctrl.handle;
if(!hwnd)
throw new DflException("Must invoke with created handle"); // Control.badInvokeHandle();
static assert((DflInvokeParam*).sizeof <= LPARAM.sizeof);
auto dflInvokeParam = cast(DflInvokeParam*)malloc(DflInvokeParam.sizeof);
if (!dflInvokeParam)
throw new OomException();
makeParamNoneArgs(func, dflInvokeParam);
scope(exit)
{
free(dflInvokeParam);
}
if (LRESULT_DFL_INVOKE != SendMessageA(hwnd, wmDfl, WPARAM_DFL_INVOKE_NOPARAMS, cast(LPARAM)dflInvokeParam))
throw new DflException("Invoke failure");
if (dflInvokeParam.exception)
throw dflInvokeParam.exception;
}
}
///
void delayInvoke(ARGS...)(void function(Control, ARGS) fn, ARGS args)
void delayInvoke(ARGS...)(void function(Control, ARGS) func, ARGS args)
if (ARGS.length && !hasLocalAliasing!(ARGS))
{
auto ctrl = cast(Control)_ctrl;
auto hwnd = ctrl.handle;
if(!hwnd)
Control.badInvokeHandle();
auto t = tuple(args);
auto p = makeParam(fn, &t);
PostMessageA(hwnd, wmDfl, WPARAM_DFL_DELAY_INVOKE_PARAMS, p);
synchronized
{
auto ctrl = cast(Control)_ctrl;
auto hwnd = ctrl.handle;
if(!hwnd)
throw new DflException("Must invoke with created handle"); // Control.badInvokeHandle();
static assert((DflInvokeParam*).sizeof <= LPARAM.sizeof);
auto dflInvokeParam = cast(DflInvokeParam*)malloc(DflInvokeParam.sizeof); // NOTE: You must free memory in window procedure.
if (!dflInvokeParam)
throw new OomException();
makeParam(func, args, dflInvokeParam);
PostMessageA(hwnd, wmDfl, WPARAM_DFL_DELAY_INVOKE_PARAMS, cast(LPARAM)dflInvokeParam);
}
}
///
void delayInvoke(ARGS...)(void function(Control, ARGS) fn, ARGS args)
void delayInvoke(ARGS...)(void function(Control, ARGS) func, ARGS args)
if (!ARGS.length)
{
auto ctrl = cast(Control)_ctrl;
auto hwnd = ctrl.handle;
if(!hwnd)
Control.badInvokeHandle();
auto p = makeParamNoneArgs(fn);
PostMessageA(hwnd, wmDfl, WPARAM_DFL_DELAY_INVOKE_PARAMS, p);
synchronized
{
auto ctrl = cast(Control)_ctrl;
auto hwnd = ctrl.handle;
if(!hwnd)
throw new DflException("Must invoke with created handle"); // Control.badInvokeHandle();
static assert((DflInvokeParam*).sizeof <= LPARAM.sizeof);
auto dflInvokeParam = cast(DflInvokeParam*)malloc(DflInvokeParam.sizeof); // NOTE: You must free memory in window procedure.
if (!dflInvokeParam)
throw new OomException();
makeParamNoneArgs(func, dflInvokeParam);
PostMessageA(hwnd, wmDfl, WPARAM_DFL_DELAY_INVOKE_NOPARAMS, cast(LPARAM)dflInvokeParam);
}
}
}
private template hasLocalAliasing(T...)
{
import std.traits : hasUnsharedAliasing;
static if (!T.length)
enum hasLocalAliasing = false;
else
enum hasLocalAliasing = std.traits.hasUnsharedAliasing!(T[0]) || dfl.sharedcontrol.hasLocalAliasing!(T[1 .. $]);
}