unique_ptr | Unique for autoclose handle
Ali Çehreli
acehreli at yahoo.com
Wed Dec 14 17:41:07 UTC 2022
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
More information about the Digitalmars-d-learn
mailing list