On 12/14/22 05:58, Vitaliy Fadeev wrote:
> On Wednesday, 14 December 2022 at 11:30:07 UTC, Vitaliy Fadeev wrote:
>> How to define HANDLE var ?  What to return from procedure? How to call
>> CloseHandle( h ) when variable destroyed?

An obvious way is an RAII type where the destructor calls CloseHandle.

> struct SafeHandle
> {
>      Unique!void _safe;

So you made Unique a member of SafeHandle. I've never used Unique but I think it has a bug (or a design issue?): Its destructor is the following:

    ~this()
    {
        if (_p !is null)
        {
            destroy(_p);
            _p = null;
        }
    }

Because _p is a pointer, destroy(_p) will not dereference and destroy what it points to. I think this is a bug with Unique. I think it should do

  destroy(*_p);

In any case, I would use a Handle RAII type that calls CloseHandle in its destructor. Here is the code that made sense to me:

import std;

// Some values and types to make the code compile:
alias HANDLE = void*;
alias LPCWSTR = string;
enum INVALID_HANDLE_VALUE = null;
enum FILE_SHARE_READ = 1;
enum FILE_SHARE_WRITE = 2;
enum NULL = null;
enum OPEN_EXISTING = 1000;

// Some mocks of system functions
HANDLE CreateFileW(LPCWSTR path, int, int, void*, int, int, void*) {
    auto handle = cast(HANDLE)(new int(42));
    writeln("Created ", handle);
    return handle;
}

int CloseHandle(HANDLE handle) {
    writeln("Closing ", handle);
    return 0;
}

// This is the RAII type for closing system handles
struct Handle {
    HANDLE value;

    // Disabling copying and assignment
    @disable this(this);
    @disable typeof(this) opAssign(const(typeof(this)));

    this(HANDLE value) {
        this.value = value;
        writeln("Constructed Handle with ", value);
    }

    ~this() {
        const ret = CloseHandle(value);
        if (ret) {
            stderr.writefln!"Failed to close handle %s"(value);
        }
    }
}

Handle open_keyboard_device2( LPCWSTR path, int* error_number )
{
   // ...
   HANDLE dev_handle =
        CreateFileW(
            path,
            0,
            FILE_SHARE_READ | FILE_SHARE_WRITE,
            NULL,
            OPEN_EXISTING,
            0,
            NULL
        );

   // According to documentation, the handler must be created dynamically:
   // We make a unique owner for it:
   auto result = Handle(dev_handle);
   writeln("Exiting open_keyboard_device2");
   return result;

    // if ( dev_handle.get() != INVALID_HANDLE_VALUE ) {
    //     // ...
    // }
   // ...
}

void processDevice( ... )
{
    int err;
    auto dev_handle = open_keyboard_device2("foo", &err );
    // set_keyboard_indicator2( dev_handle, KEYBOARD_CAPS_LOCK_ON );
    // ...
    writeln("Exiting processDevice");
}

void main() {
    processDevice();
    writeln("Exiting main");
}

The output of the program looks acceptable to me:

Created 7F1BD5A7D000
Constructed Handle with 7F1BD5A7D000
Exiting open_keyboard_device2
Exiting processDevice
Closing 7F1BD5A7D000
Exiting main

Ali

Reply via email to