Example
test QueryObjectName {
if (builtin.os.tag != .windows)
return;
//any file will do; canonicalization works on NTFS junctions and symlinks, hardlinks remain separate paths.
var tmp = std.testing.tmpDir(.{});
defer tmp.cleanup();
const handle = tmp.dir.fd;
var out_buffer: [PATH_MAX_WIDE]u16 = undefined;
const result_path = try QueryObjectName(handle, &out_buffer);
const required_len_in_u16 = result_path.len + @divExact(@intFromPtr(result_path.ptr) - @intFromPtr(&out_buffer), 2) + 1;
//insufficient size
try std.testing.expectError(error.NameTooLong, QueryObjectName(handle, out_buffer[0 .. required_len_in_u16 - 1]));
//exactly-sufficient size
_ = try QueryObjectName(handle, out_buffer[0..required_len_in_u16]);
}
Source
pub fn QueryObjectName(handle: HANDLE, out_buffer: []u16) QueryObjectNameError![]u16 {
const out_buffer_aligned = mem.alignInSlice(out_buffer, @alignOf(OBJECT_NAME_INFORMATION)) orelse return error.NameTooLong;
const info = @as(*OBJECT_NAME_INFORMATION, @ptrCast(out_buffer_aligned));
// buffer size is specified in bytes
const out_buffer_len = std.math.cast(ULONG, out_buffer_aligned.len * 2) orelse std.math.maxInt(ULONG);
// last argument would return the length required for full_buffer, not exposed here
return switch (ntdll.NtQueryObject(handle, .ObjectNameInformation, info, out_buffer_len, null)) {
.SUCCESS => blk: {
// info.Name.Buffer from ObQueryNameString is documented to be null (and MaximumLength == 0)
// if the object was "unnamed", not sure if this can happen for file handles
if (info.Name.MaximumLength == 0) break :blk error.Unexpected;
// resulting string length is specified in bytes
const path_length_unterminated = @divExact(info.Name.Length, 2);
break :blk info.Name.Buffer.?[0..path_length_unterminated];
},
.ACCESS_DENIED => error.AccessDenied,
.INVALID_HANDLE => error.InvalidHandle,
// triggered when the buffer is too small for the OBJECT_NAME_INFORMATION object (.INFO_LENGTH_MISMATCH),
// or if the buffer is too small for the file path returned (.BUFFER_OVERFLOW, .BUFFER_TOO_SMALL)
.INFO_LENGTH_MISMATCH, .BUFFER_OVERFLOW, .BUFFER_TOO_SMALL => error.NameTooLong,
else => |e| unexpectedStatus(e),
};
}