Enough of ObOpenObjectByName to handle basic usage + asserts for others.
Fixes #143.
This commit is contained in:
parent
2c49eec79f
commit
90e489527a
|
@ -151,7 +151,8 @@ X_STATUS ObjectTable::RemoveHandle(X_HANDLE handle) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
X_STATUS ObjectTable::GetObject(X_HANDLE handle, XObject** out_object) {
|
X_STATUS ObjectTable::GetObject(X_HANDLE handle, XObject** out_object,
|
||||||
|
bool already_locked) {
|
||||||
assert_not_null(out_object);
|
assert_not_null(out_object);
|
||||||
|
|
||||||
X_STATUS result = X_STATUS_SUCCESS;
|
X_STATUS result = X_STATUS_SUCCESS;
|
||||||
|
@ -162,28 +163,32 @@ X_STATUS ObjectTable::GetObject(X_HANDLE handle, XObject** out_object) {
|
||||||
}
|
}
|
||||||
|
|
||||||
XObject* object = NULL;
|
XObject* object = NULL;
|
||||||
{
|
if (!already_locked) {
|
||||||
std::lock_guard<std::mutex> lock(table_mutex_);
|
table_mutex_.lock();
|
||||||
|
}
|
||||||
|
|
||||||
// Lower 2 bits are ignored.
|
// Lower 2 bits are ignored.
|
||||||
uint32_t slot = handle >> 2;
|
uint32_t slot = handle >> 2;
|
||||||
|
|
||||||
// Verify slot.
|
// Verify slot.
|
||||||
if (slot > table_capacity_) {
|
if (slot > table_capacity_) {
|
||||||
result = X_STATUS_INVALID_HANDLE;
|
result = X_STATUS_INVALID_HANDLE;
|
||||||
|
} else {
|
||||||
|
ObjectTableEntry& entry = table_[slot];
|
||||||
|
if (entry.object) {
|
||||||
|
object = entry.object;
|
||||||
} else {
|
} else {
|
||||||
ObjectTableEntry& entry = table_[slot];
|
result = X_STATUS_INVALID_HANDLE;
|
||||||
if (entry.object) {
|
|
||||||
object = entry.object;
|
|
||||||
} else {
|
|
||||||
result = X_STATUS_INVALID_HANDLE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Retain the object pointer.
|
// Retain the object pointer.
|
||||||
if (object) {
|
if (object) {
|
||||||
object->Retain();
|
object->Retain();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!already_locked) {
|
||||||
|
table_mutex_.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
*out_object = object;
|
*out_object = object;
|
||||||
|
@ -203,5 +208,42 @@ X_HANDLE ObjectTable::TranslateHandle(X_HANDLE handle) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
X_STATUS ObjectTable::AddNameMapping(const std::string& name, X_HANDLE handle) {
|
||||||
|
std::lock_guard<std::mutex> lock(table_mutex_);
|
||||||
|
if (name_table_.count(name)) {
|
||||||
|
return X_STATUS_OBJECT_NAME_COLLISION;
|
||||||
|
}
|
||||||
|
name_table_.insert({ name, handle });
|
||||||
|
return X_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObjectTable::RemoveNameMapping(const std::string& name) {
|
||||||
|
std::lock_guard<std::mutex> lock(table_mutex_);
|
||||||
|
auto it = name_table_.find(name);
|
||||||
|
if (it != name_table_.end()) {
|
||||||
|
name_table_.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
X_STATUS ObjectTable::GetObjectByName(const std::string& name,
|
||||||
|
X_HANDLE* out_handle) {
|
||||||
|
std::lock_guard<std::mutex> lock(table_mutex_);
|
||||||
|
auto it = name_table_.find(name);
|
||||||
|
if (it == name_table_.end()) {
|
||||||
|
*out_handle = X_INVALID_HANDLE_VALUE;
|
||||||
|
return X_STATUS_OBJECT_NAME_NOT_FOUND;
|
||||||
|
}
|
||||||
|
*out_handle = it->second;
|
||||||
|
|
||||||
|
// We need to ref the handle. I think.
|
||||||
|
XObject* obj = nullptr;
|
||||||
|
if (XSUCCEEDED(GetObject(it->second, &obj, true))) {
|
||||||
|
obj->RetainHandle();
|
||||||
|
obj->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
return X_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace kernel
|
} // namespace kernel
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
#define XENIA_KERNEL_XBOXKRNL_OBJECT_TABLE_H_
|
#define XENIA_KERNEL_XBOXKRNL_OBJECT_TABLE_H_
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "xenia/common.h"
|
#include "xenia/common.h"
|
||||||
#include "xenia/xbox.h"
|
#include "xenia/xbox.h"
|
||||||
|
@ -27,7 +29,12 @@ class ObjectTable {
|
||||||
|
|
||||||
X_STATUS AddHandle(XObject* object, X_HANDLE* out_handle);
|
X_STATUS AddHandle(XObject* object, X_HANDLE* out_handle);
|
||||||
X_STATUS RemoveHandle(X_HANDLE handle);
|
X_STATUS RemoveHandle(X_HANDLE handle);
|
||||||
X_STATUS GetObject(X_HANDLE handle, XObject** out_object);
|
X_STATUS GetObject(X_HANDLE handle, XObject** out_object,
|
||||||
|
bool already_locked = false);
|
||||||
|
|
||||||
|
X_STATUS AddNameMapping(const std::string& name, X_HANDLE handle);
|
||||||
|
void RemoveNameMapping(const std::string& name);
|
||||||
|
X_STATUS GetObjectByName(const std::string& name, X_HANDLE* out_handle);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
X_HANDLE TranslateHandle(X_HANDLE handle);
|
X_HANDLE TranslateHandle(X_HANDLE handle);
|
||||||
|
@ -39,6 +46,7 @@ class ObjectTable {
|
||||||
uint32_t table_capacity_;
|
uint32_t table_capacity_;
|
||||||
ObjectTableEntry* table_;
|
ObjectTableEntry* table_;
|
||||||
uint32_t last_free_entry_;
|
uint32_t last_free_entry_;
|
||||||
|
std::unordered_map<std::string, X_HANDLE> name_table_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace kernel
|
} // namespace kernel
|
||||||
|
|
|
@ -18,6 +18,35 @@
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace kernel {
|
namespace kernel {
|
||||||
|
|
||||||
|
SHIM_CALL ObOpenObjectByName_shim(PPCContext* ppc_state, KernelState* state) {
|
||||||
|
// r3 = ptr to info?
|
||||||
|
// +0 = -4
|
||||||
|
// +4 = name ptr
|
||||||
|
// +8 = 0
|
||||||
|
// r4 = ExEventObjectType | ExSemaphoreObjectType | ExTimerObjectType
|
||||||
|
// r5 = 0
|
||||||
|
// r6 = out_ptr (handle?)
|
||||||
|
uint32_t obj_attributes_ptr = SHIM_GET_ARG_32(0);
|
||||||
|
uint32_t object_type_ptr = SHIM_GET_ARG_32(1);
|
||||||
|
uint32_t unk = SHIM_GET_ARG_32(2);
|
||||||
|
uint32_t handle_ptr = SHIM_GET_ARG_32(3);
|
||||||
|
|
||||||
|
uint32_t name_str_ptr = SHIM_MEM_32(obj_attributes_ptr + 4);
|
||||||
|
X_ANSI_STRING name_str(SHIM_MEM_BASE, name_str_ptr);
|
||||||
|
auto name = name_str.to_string();
|
||||||
|
|
||||||
|
XELOGD("ObOpenObjectByName(%.8X(name=%s), %.8X, %.8X, %.8X)",
|
||||||
|
obj_attributes_ptr, name.c_str(), object_type_ptr, unk, handle_ptr);
|
||||||
|
|
||||||
|
X_HANDLE handle = X_INVALID_HANDLE_VALUE;
|
||||||
|
X_STATUS result = state->object_table()->GetObjectByName(name, &handle);
|
||||||
|
if (XSUCCEEDED(result)) {
|
||||||
|
SHIM_SET_MEM_32(handle_ptr, handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
SHIM_SET_RETURN_32(result);
|
||||||
|
}
|
||||||
|
|
||||||
SHIM_CALL ObReferenceObjectByHandle_shim(PPCContext* ppc_state,
|
SHIM_CALL ObReferenceObjectByHandle_shim(PPCContext* ppc_state,
|
||||||
KernelState* state) {
|
KernelState* state) {
|
||||||
uint32_t handle = SHIM_GET_ARG_32(0);
|
uint32_t handle = SHIM_GET_ARG_32(0);
|
||||||
|
@ -130,6 +159,7 @@ SHIM_CALL NtClose_shim(PPCContext* ppc_state, KernelState* state) {
|
||||||
|
|
||||||
void xe::kernel::xboxkrnl::RegisterObExports(ExportResolver* export_resolver,
|
void xe::kernel::xboxkrnl::RegisterObExports(ExportResolver* export_resolver,
|
||||||
KernelState* state) {
|
KernelState* state) {
|
||||||
|
SHIM_SET_MAPPING("xboxkrnl.exe", ObOpenObjectByName, state);
|
||||||
SHIM_SET_MAPPING("xboxkrnl.exe", ObReferenceObjectByHandle, state);
|
SHIM_SET_MAPPING("xboxkrnl.exe", ObReferenceObjectByHandle, state);
|
||||||
SHIM_SET_MAPPING("xboxkrnl.exe", ObDereferenceObject, state);
|
SHIM_SET_MAPPING("xboxkrnl.exe", ObDereferenceObject, state);
|
||||||
SHIM_SET_MAPPING("xboxkrnl.exe", NtDuplicateObject, state);
|
SHIM_SET_MAPPING("xboxkrnl.exe", NtDuplicateObject, state);
|
||||||
|
|
|
@ -57,6 +57,26 @@ namespace kernel {
|
||||||
// stw r3, 0x160(r11)
|
// stw r3, 0x160(r11)
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
void AssertNoNameCollision(KernelState* state, uint32_t obj_attributes_ptr) {
|
||||||
|
// If the name exists and its type matches, we can return that (ref+1)
|
||||||
|
// with a success of NAME_EXISTS.
|
||||||
|
// If the name exists and its type doesn't match, we do NAME_COLLISION.
|
||||||
|
// Otherwise, we add like normal.
|
||||||
|
auto membase = state->memory()->membase();
|
||||||
|
uint32_t name_str_ptr =
|
||||||
|
poly::load_and_swap<uint32_t>(membase + obj_attributes_ptr + 4);
|
||||||
|
if (name_str_ptr) {
|
||||||
|
X_ANSI_STRING name_str(membase, name_str_ptr);
|
||||||
|
auto name = name_str.to_string();
|
||||||
|
X_HANDLE handle = X_INVALID_HANDLE_VALUE;
|
||||||
|
X_RESULT result = state->object_table()->GetObjectByName(name, &handle);
|
||||||
|
if (XSUCCEEDED(result)) {
|
||||||
|
// Found something!
|
||||||
|
assert_always("Existing names not implemented");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SHIM_CALL ExCreateThread_shim(PPCContext* ppc_state, KernelState* state) {
|
SHIM_CALL ExCreateThread_shim(PPCContext* ppc_state, KernelState* state) {
|
||||||
uint32_t handle_ptr = SHIM_GET_ARG_32(0);
|
uint32_t handle_ptr = SHIM_GET_ARG_32(0);
|
||||||
uint32_t stack_size = SHIM_GET_ARG_32(1);
|
uint32_t stack_size = SHIM_GET_ARG_32(1);
|
||||||
|
@ -425,13 +445,16 @@ SHIM_CALL NtCreateEvent_shim(PPCContext* ppc_state, KernelState* state) {
|
||||||
XELOGD("NtCreateEvent(%.8X, %.8X, %d, %d)", handle_ptr, obj_attributes_ptr,
|
XELOGD("NtCreateEvent(%.8X, %.8X, %d, %d)", handle_ptr, obj_attributes_ptr,
|
||||||
event_type, initial_state);
|
event_type, initial_state);
|
||||||
|
|
||||||
|
// TODO(benvanik): check for name collision. May return existing object if
|
||||||
|
// type matches.
|
||||||
|
AssertNoNameCollision(state, obj_attributes_ptr);
|
||||||
|
|
||||||
XEvent* ev = new XEvent(state);
|
XEvent* ev = new XEvent(state);
|
||||||
ev->Initialize(!event_type, !!initial_state);
|
ev->Initialize(!event_type, !!initial_state);
|
||||||
|
|
||||||
// obj_attributes may have a name inside of it, if != NULL.
|
// obj_attributes may have a name inside of it, if != NULL.
|
||||||
auto obj_attributes = SHIM_MEM_ADDR(obj_attributes_ptr);
|
if (obj_attributes_ptr) {
|
||||||
if (obj_attributes) {
|
ev->SetAttributes(SHIM_MEM_ADDR(obj_attributes_ptr));
|
||||||
// ev->SetName(...);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handle_ptr) {
|
if (handle_ptr) {
|
||||||
|
@ -566,12 +589,16 @@ SHIM_CALL NtCreateSemaphore_shim(PPCContext* ppc_state, KernelState* state) {
|
||||||
XELOGD("NtCreateSemaphore(%.8X, %.8X, %d, %d)", handle_ptr,
|
XELOGD("NtCreateSemaphore(%.8X, %.8X, %d, %d)", handle_ptr,
|
||||||
obj_attributes_ptr, count, limit);
|
obj_attributes_ptr, count, limit);
|
||||||
|
|
||||||
|
// TODO(benvanik): check for name collision. May return existing object if
|
||||||
|
// type matches.
|
||||||
|
AssertNoNameCollision(state, obj_attributes_ptr);
|
||||||
|
|
||||||
XSemaphore* sem = new XSemaphore(state);
|
XSemaphore* sem = new XSemaphore(state);
|
||||||
sem->Initialize(count, limit);
|
sem->Initialize(count, limit);
|
||||||
|
|
||||||
// obj_attributes may have a name inside of it, if != NULL.
|
// obj_attributes may have a name inside of it, if != NULL.
|
||||||
if (obj_attributes_ptr) {
|
if (obj_attributes_ptr) {
|
||||||
// sem->SetName(...);
|
sem->SetAttributes(SHIM_MEM_ADDR(obj_attributes_ptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handle_ptr) {
|
if (handle_ptr) {
|
||||||
|
@ -656,12 +683,16 @@ SHIM_CALL NtCreateMutant_shim(PPCContext* ppc_state, KernelState* state) {
|
||||||
XELOGD("NtCreateMutant(%.8X, %.8X, %.1X)", handle_ptr, obj_attributes_ptr,
|
XELOGD("NtCreateMutant(%.8X, %.8X, %.1X)", handle_ptr, obj_attributes_ptr,
|
||||||
initial_owner);
|
initial_owner);
|
||||||
|
|
||||||
|
// TODO(benvanik): check for name collision. May return existing object if
|
||||||
|
// type matches.
|
||||||
|
AssertNoNameCollision(state, obj_attributes_ptr);
|
||||||
|
|
||||||
XMutant* mutant = new XMutant(state);
|
XMutant* mutant = new XMutant(state);
|
||||||
mutant->Initialize(initial_owner ? true : false);
|
mutant->Initialize(initial_owner ? true : false);
|
||||||
|
|
||||||
// obj_attributes may have a name inside of it, if != NULL.
|
// obj_attributes may have a name inside of it, if != NULL.
|
||||||
if (obj_attributes_ptr) {
|
if (obj_attributes_ptr) {
|
||||||
// mutant->SetName(...);
|
mutant->SetAttributes(SHIM_MEM_ADDR(obj_attributes_ptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handle_ptr) {
|
if (handle_ptr) {
|
||||||
|
@ -709,12 +740,16 @@ SHIM_CALL NtCreateTimer_shim(PPCContext* ppc_state, KernelState* state) {
|
||||||
XELOGD("NtCreateTimer(%.8X, %.8X, %.1X)", handle_ptr, obj_attributes_ptr,
|
XELOGD("NtCreateTimer(%.8X, %.8X, %.1X)", handle_ptr, obj_attributes_ptr,
|
||||||
timer_type);
|
timer_type);
|
||||||
|
|
||||||
|
// TODO(benvanik): check for name collision. May return existing object if
|
||||||
|
// type matches.
|
||||||
|
AssertNoNameCollision(state, obj_attributes_ptr);
|
||||||
|
|
||||||
XTimer* timer = new XTimer(state);
|
XTimer* timer = new XTimer(state);
|
||||||
timer->Initialize(timer_type);
|
timer->Initialize(timer_type);
|
||||||
|
|
||||||
// obj_attributes may have a name inside of it, if != NULL.
|
// obj_attributes may have a name inside of it, if != NULL.
|
||||||
if (obj_attributes_ptr) {
|
if (obj_attributes_ptr) {
|
||||||
// timer->SetName(...);
|
timer->SetAttributes(SHIM_MEM_ADDR(obj_attributes_ptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handle_ptr) {
|
if (handle_ptr) {
|
||||||
|
|
|
@ -56,9 +56,25 @@ void XObject::Release() {
|
||||||
}
|
}
|
||||||
|
|
||||||
X_STATUS XObject::Delete() {
|
X_STATUS XObject::Delete() {
|
||||||
|
if (!name_.empty()) {
|
||||||
|
kernel_state_->object_table()->RemoveNameMapping(name_);
|
||||||
|
}
|
||||||
return kernel_state_->object_table()->RemoveHandle(handle_);
|
return kernel_state_->object_table()->RemoveHandle(handle_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void XObject::SetAttributes(const uint8_t* obj_attrs_ptr) {
|
||||||
|
if (!obj_attrs_ptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t name_str_ptr = poly::load_and_swap<uint32_t>(obj_attrs_ptr + 4);
|
||||||
|
if (name_str_ptr) {
|
||||||
|
X_ANSI_STRING name_str(membase(), name_str_ptr);
|
||||||
|
name_ = name_str.to_string();
|
||||||
|
kernel_state_->object_table()->AddNameMapping(name_, handle_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t XObject::TimeoutTicksToMs(int64_t timeout_ticks) {
|
uint32_t XObject::TimeoutTicksToMs(int64_t timeout_ticks) {
|
||||||
if (timeout_ticks > 0) {
|
if (timeout_ticks > 0) {
|
||||||
// Absolute time, based on January 1, 1601.
|
// Absolute time, based on January 1, 1601.
|
||||||
|
|
|
@ -46,9 +46,11 @@ class XObject {
|
||||||
|
|
||||||
Emulator* emulator() const { return kernel_state_->emulator_; }
|
Emulator* emulator() const { return kernel_state_->emulator_; }
|
||||||
KernelState* kernel_state() const { return kernel_state_; }
|
KernelState* kernel_state() const { return kernel_state_; }
|
||||||
|
uint8_t* membase() const { return kernel_state_->memory()->membase(); }
|
||||||
|
|
||||||
Type type();
|
Type type();
|
||||||
X_HANDLE handle() const;
|
X_HANDLE handle() const;
|
||||||
|
const std::string& name() const { return name_; }
|
||||||
|
|
||||||
void RetainHandle();
|
void RetainHandle();
|
||||||
bool ReleaseHandle();
|
bool ReleaseHandle();
|
||||||
|
@ -59,6 +61,8 @@ class XObject {
|
||||||
// Reference()
|
// Reference()
|
||||||
// Dereference()
|
// Dereference()
|
||||||
|
|
||||||
|
void SetAttributes(const uint8_t* obj_attrs_ptr);
|
||||||
|
|
||||||
X_STATUS Wait(uint32_t wait_reason, uint32_t processor_mode,
|
X_STATUS Wait(uint32_t wait_reason, uint32_t processor_mode,
|
||||||
uint32_t alertable, uint64_t* opt_timeout);
|
uint32_t alertable, uint64_t* opt_timeout);
|
||||||
static X_STATUS SignalAndWait(XObject* signal_object, XObject* wait_object,
|
static X_STATUS SignalAndWait(XObject* signal_object, XObject* wait_object,
|
||||||
|
@ -88,6 +92,7 @@ class XObject {
|
||||||
|
|
||||||
Type type_;
|
Type type_;
|
||||||
X_HANDLE handle_;
|
X_HANDLE handle_;
|
||||||
|
std::string name_; // May be zero length.
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace kernel
|
} // namespace kernel
|
||||||
|
|
|
@ -10,10 +10,11 @@
|
||||||
#ifndef XENIA_XBOX_H_
|
#ifndef XENIA_XBOX_H_
|
||||||
#define XENIA_XBOX_H_
|
#define XENIA_XBOX_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "poly/memory.h"
|
#include "poly/memory.h"
|
||||||
#include "xenia/common.h"
|
#include "xenia/common.h"
|
||||||
|
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -41,6 +42,7 @@ typedef uint32_t X_STATUS;
|
||||||
#define X_STATUS_ALERTED ((X_STATUS)0x00000101L)
|
#define X_STATUS_ALERTED ((X_STATUS)0x00000101L)
|
||||||
#define X_STATUS_TIMEOUT ((X_STATUS)0x00000102L)
|
#define X_STATUS_TIMEOUT ((X_STATUS)0x00000102L)
|
||||||
#define X_STATUS_PENDING ((X_STATUS)0x00000103L)
|
#define X_STATUS_PENDING ((X_STATUS)0x00000103L)
|
||||||
|
#define X_STATUS_OBJECT_NAME_EXISTS ((X_STATUS)0x40000000L)
|
||||||
#define X_STATUS_TIMER_RESUME_IGNORED ((X_STATUS)0x40000025L)
|
#define X_STATUS_TIMER_RESUME_IGNORED ((X_STATUS)0x40000025L)
|
||||||
#define X_STATUS_BUFFER_OVERFLOW ((X_STATUS)0x80000005L)
|
#define X_STATUS_BUFFER_OVERFLOW ((X_STATUS)0x80000005L)
|
||||||
#define X_STATUS_NO_MORE_FILES ((X_STATUS)0x80000006L)
|
#define X_STATUS_NO_MORE_FILES ((X_STATUS)0x80000006L)
|
||||||
|
@ -57,6 +59,8 @@ typedef uint32_t X_STATUS;
|
||||||
#define X_STATUS_ACCESS_DENIED ((X_STATUS)0xC0000022L)
|
#define X_STATUS_ACCESS_DENIED ((X_STATUS)0xC0000022L)
|
||||||
#define X_STATUS_BUFFER_TOO_SMALL ((X_STATUS)0xC0000023L)
|
#define X_STATUS_BUFFER_TOO_SMALL ((X_STATUS)0xC0000023L)
|
||||||
#define X_STATUS_OBJECT_TYPE_MISMATCH ((X_STATUS)0xC0000024L)
|
#define X_STATUS_OBJECT_TYPE_MISMATCH ((X_STATUS)0xC0000024L)
|
||||||
|
#define X_STATUS_OBJECT_NAME_NOT_FOUND ((X_STATUS)0xC0000034L)
|
||||||
|
#define X_STATUS_OBJECT_NAME_COLLISION ((X_STATUS)0xC0000035L)
|
||||||
#define X_STATUS_INVALID_PAGE_PROTECTION ((X_STATUS)0xC0000045L)
|
#define X_STATUS_INVALID_PAGE_PROTECTION ((X_STATUS)0xC0000045L)
|
||||||
#define X_STATUS_MUTANT_NOT_OWNED ((X_STATUS)0xC0000046L)
|
#define X_STATUS_MUTANT_NOT_OWNED ((X_STATUS)0xC0000046L)
|
||||||
#define X_STATUS_MEMORY_NOT_ALLOCATED ((X_STATUS)0xC00000A0L)
|
#define X_STATUS_MEMORY_NOT_ALLOCATED ((X_STATUS)0xC00000A0L)
|
||||||
|
@ -268,13 +272,20 @@ public:
|
||||||
buffer = 0;
|
buffer = 0;
|
||||||
}
|
}
|
||||||
char* Duplicate() {
|
char* Duplicate() {
|
||||||
if (buffer == NULL || length == 0) {
|
if (!buffer || !length) {
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
auto copy = (char*)calloc(length + 1, sizeof(char));
|
auto copy = (char*)calloc(length + 1, sizeof(char));
|
||||||
std::strncpy(copy, buffer, length);
|
std::strncpy(copy, buffer, length);
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
std::string to_string() {
|
||||||
|
if (!buffer || !length) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
std::string result(buffer, length);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
//static_assert_size(X_ANSI_STRING, 8);
|
//static_assert_size(X_ANSI_STRING, 8);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue