Template: get function name

Simen Kjærås simen.kjaras at gmail.com
Mon Aug 17 08:55:49 UTC 2020


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


More information about the Digitalmars-d-learn mailing list