www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Template: get function name

reply novice3 <sorryno em.ail> writes:
Hello.
I have wrapping Windows API functions, wich return 0 on success 
and erroro code on failure.

I copy wenforce template as:
```
private T denforce(T, S)(T value, lazy S msg = null, string file 
= __FILE__, size_t line = __LINE__)
{
   import core.sys.windows.winerror: NO_ERROR;
   import std.conv: to;
   if (value != NO_ERROR)
     throw new WindowsException(value, to!string(msg), file, line);
   return value;
}
```

and use it:
```
DhcpEnumServers(0, null, servers, null, 
null).denforce("DhcpEnumServers");
````

Then windows api - extern (Windows)DhcpEnumServers - return 
error, then Windows exception throwed with name of failed api 
"DhcpEnumServers".

Can we change template to avoid api name dublicate?
Can denforce template obtain "DhcpEnumServers" function name to 
format message "DhcpEnumServers api failed"?

Thanks.
Aug 17 2020
parent reply Simen =?UTF-8?B?S2rDpnLDpXM=?= <simen.kjaras gmail.com> writes:
On Monday, 17 August 2020 at 08:07:32 UTC, novice3 wrote:
 Hello.
 I have wrapping Windows API functions, wich return 0 on success 
 and erroro code on failure.

 I copy wenforce template as:
 ```
 private T denforce(T, S)(T value, lazy S msg = null, string 
 file = __FILE__, size_t line = __LINE__)
 {
   import core.sys.windows.winerror: NO_ERROR;
   import std.conv: to;
   if (value != NO_ERROR)
     throw new WindowsException(value, to!string(msg), file, 
 line);
   return value;
 }
 ```

 and use it:
 ```
 DhcpEnumServers(0, null, servers, null, 
 null).denforce("DhcpEnumServers");
 ````

 Then windows api - extern (Windows)DhcpEnumServers - return 
 error, then Windows exception throwed with name of failed api 
 "DhcpEnumServers".

 Can we change template to avoid api name dublicate?
 Can denforce template obtain "DhcpEnumServers" function name to 
 format message "DhcpEnumServers api failed"?

 Thanks.
Take the function as an alias parameter and wrap the entire call: auto denforce(alias fn, string file = __FILE__, size_t line = __LINE__, Args...)(Args args) { import core.sys.windows.winerror: NO_ERROR; auto value = fn(args); if (value != NO_ERROR) { throw new WindowsException(value, __traits(identifier, fn)~" api call failed.", file, line); } return value; } unittest { denforce!DhcpEnumServers(0, null, servers, null, null); } For bonus points, you could also get the error message for the returned error code: string convertErrorCode(uint code) { import core.sys.windows.winbase : FormatMessage, LoadLibrary, FORMAT_MESSAGE_FROM_SYSTEM, FORMAT_MESSAGE_IGNORE_INSERTS, FORMAT_MESSAGE_FROM_HMODULE; wchar[512] buf; auto written = FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, null, code, 0, buf.ptr, buf.length, null); if (!written) { auto inst = LoadLibrary("Ntdsbmsg.dll"); if (inst) { written = FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, inst, code, 0, buf.ptr, buf.length, null); } } if (written) { import std.conv : to; return buf.ptr.to!string; } else { import std.format : format; return format("An unknown error occured: %x", code); } } unittest { import core.sys.windows.winerror : ERROR_INVALID_FUNCTION; import std.stdio; writeln(convertErrorCode(ERROR_INVALID_FUNCTION)); writeln(convertErrorCode(1234567891)); } -- Simen
Aug 17 2020
parent reply novice3 <sorryno em.ail> writes:
On Monday, 17 August 2020 at 08:55:49 UTC, Simen Kjærås wrote:
 Take the function as an alias parameter and wrap the entire 
 call:

 auto denforce(alias fn, string file = __FILE__, size_t line = 
 __LINE__, Args...)(Args args)
Thank you, Simen!
Aug 17 2020
parent reply novice3 <sorryno em.ail> writes:
 On Monday, 17 August 2020 at 08:55:49 UTC, Simen Kjærås wrote:
 Take the function as an alias parameter and wrap the entire 
 call:
Simen, for some reasons, your code dont respect api arg with "out" attribute. For example, i have ``` extern (Windows) DhcpEnumServers( in DWORD Flags, // must be zero in LPVOID IdInfo, // must be NULL out LPDHCP_SERVER_INFO_ARRAY Servers, // output servers list in LPVOID CallbackFn, // must be NULL in LPVOID CallbackData // must be NULL ); ``` and then i use it: ``` LPDHCP_SERVER_INFO_ARRAY servers; denforce!DhcpEnumServers(0, null, servers, null, null); ``` access violation occur. In disassembler we can see that servers parameter passed by value (initial 0 instead of address). In my earler code it wass passed properly, by ref. May be this not matter of your code, and i can bypass it by change extern declaration to LPDHCP_SERVER_INFO_ARRAY *Servers, but it will be interest to know the reasons... Any way, tnaks you for your code, i will use it.
Aug 17 2020
parent reply novice3 <sorryno em.ail> writes:
On Monday, 17 August 2020 at 09:45:55 UTC, novice3 wrote:
 access violation occur.
reduced code https://run.dlang.io/is/U58t9R void test(out int x) { x = 42; } void call (alias fn, Args ...)(Args args) { fn(args); } void main(){ int a; a = 111; test(a); assert(a == 42); // OK a = 222; call!test(a); assert(a == 42); // FAIL }
Aug 17 2020
parent reply MoonlightSentinel <moonlightsentinel disroot.org> writes:
On Monday, 17 August 2020 at 09:59:21 UTC, novice3 wrote:
 On Monday, 17 August 2020 at 09:45:55 UTC, novice3 wrote:
 access violation occur.
reduced code https://run.dlang.io/is/U58t9R
The wrapper parameters don't inherit the storage classes from the wrapped function. Try using std.traits.Parameters instead: https://run.dlang.io/is/wTyJWD. ``` import std.traits : Parameters; void test(out int x) { x = 42; } void call (alias fn)(Parameters!fn args) { fn(args); } void main() { int a; a = 111; test(a); assert(a == 42); a = 222; call!test(a); assert(a == 42); } ```
Aug 17 2020
parent novice3 <sorryno em.ail> writes:
On Monday, 17 August 2020 at 10:11:29 UTC, MoonlightSentinel 
wrote:
 On Monday, 17 August 2020 at 09:59:21 UTC, novice3 wrote:
 On Monday, 17 August 2020 at 09:45:55 UTC, novice3 wrote:
 access violation occur.
reduced code https://run.dlang.io/is/U58t9R
The wrapper parameters don't inherit the storage classes from the wrapped function. Try using std.traits.Parameters instead: https://run.dlang.io/is/wTyJWD.
Nice, it works!
Aug 17 2020