From b8420c60391dfa7b7e1d7c45d3b03cec42041f58 Mon Sep 17 00:00:00 2001 From: Dennis Korpel Date: Tue, 18 Jun 2024 13:45:01 +0200 Subject: [PATCH 1/2] com.d: Add named argument support --- com.d | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/com.d b/com.d index 4066a9a..309d444 100644 --- a/com.d +++ b/com.d @@ -271,10 +271,12 @@ struct ComResult { struct ComProperty { IDispatch innerComObject_; DISPID dispid; + string name; this(IDispatch a, DISPID c, string name) { this.innerComObject_ = a; this.dispid = c; + this.name = name; } T getD(T)() { @@ -393,9 +395,22 @@ struct ComProperty { } ComResult opCall(Args...)(Args args) { + return callNamedArgs!([])(args); + } + + /// Call with named arguments + /// + /// Note that all positional arguments are always followed by all named arguments. + /// + /// So to call: `Com.f(10, 20, A: 30, B: 40)`, invoke this function as follows: + /// --- + /// Com.f().callNamedArgs!(["A", "B"])(10, 20, 30, 40); + /// --- + /// Argument names are case-insensitive + ComResult callNamedArgs(string[] argNames, Args...)(Args args) { DISPPARAMS disp_params; - static if(args.length) { + static if (args.length) { VARIANT[args.length] vargs; foreach(idx, arg; args) { // lol it is put in backwards way to explain MSFT @@ -404,6 +419,27 @@ struct ComProperty { disp_params.rgvarg = vargs.ptr; disp_params.cArgs = cast(int) args.length; + + static if (argNames.length > 0) { + wchar*[argNames.length + 1] namesW; + // GetIDsOfNames wants Method name at index 0 followed by parameter names. + // Order of passing named args is up to us, but it's standard to also put them backwards, + // and we've already done so with values in `vargs`, so we continue this trend + // with dispatch IDs of names + import std.conv: to; + namesW[0] = (to!wstring(this.name) ~ "\0"w).dup.ptr; + foreach (i; 0 .. argNames.length) { + namesW[i + 1] = (to!wstring(argNames[$ - 1 - i]) ~ "\0"w).dup.ptr; + } + DISPID[argNames.length + 1] dispIds; + innerComObject_.GetIDsOfNames( + &GUID_NULL, namesW.ptr, namesW.length, LOCALE_SYSTEM_DEFAULT, dispIds.ptr + ).ComCheck("Unknown parameter name"); + + // Strip Member name at index 0 + disp_params.cNamedArgs = dispIds.length - 1; + disp_params.rgdispidNamedArgs = &dispIds[1]; + } } VARIANT result; From 27aafc79b4314031724f3b5564a9c31eba2e2a79 Mon Sep 17 00:00:00 2001 From: Dennis Korpel Date: Wed, 19 Jun 2024 16:48:37 +0200 Subject: [PATCH 2/2] Make named arguments runtime --- com.d | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/com.d b/com.d index 309d444..1b3d05b 100644 --- a/com.d +++ b/com.d @@ -395,7 +395,7 @@ struct ComProperty { } ComResult opCall(Args...)(Args args) { - return callNamedArgs!([])(args); + return callWithNamedArgs!Args(null, args); } /// Call with named arguments @@ -404,10 +404,10 @@ struct ComProperty { /// /// So to call: `Com.f(10, 20, A: 30, B: 40)`, invoke this function as follows: /// --- - /// Com.f().callNamedArgs!(["A", "B"])(10, 20, 30, 40); + /// Com.f().callWithNamedArgs!(["A", "B"])(10, 20, 30, 40); /// --- /// Argument names are case-insensitive - ComResult callNamedArgs(string[] argNames, Args...)(Args args) { + ComResult callWithNamedArgs(Args...)(string[] argNames, Args args) { DISPPARAMS disp_params; static if (args.length) { @@ -420,8 +420,8 @@ struct ComProperty { disp_params.rgvarg = vargs.ptr; disp_params.cArgs = cast(int) args.length; - static if (argNames.length > 0) { - wchar*[argNames.length + 1] namesW; + if (argNames.length > 0) { + wchar*[Args.length + 1] namesW; // GetIDsOfNames wants Method name at index 0 followed by parameter names. // Order of passing named args is up to us, but it's standard to also put them backwards, // and we've already done so with values in `vargs`, so we continue this trend @@ -431,7 +431,7 @@ struct ComProperty { foreach (i; 0 .. argNames.length) { namesW[i + 1] = (to!wstring(argNames[$ - 1 - i]) ~ "\0"w).dup.ptr; } - DISPID[argNames.length + 1] dispIds; + DISPID[Args.length + 1] dispIds; innerComObject_.GetIDsOfNames( &GUID_NULL, namesW.ptr, namesW.length, LOCALE_SYSTEM_DEFAULT, dispIds.ptr ).ComCheck("Unknown parameter name");