コード例 #1
0
ファイル: token.cpp プロジェクト: bragin/ring3k
NTSTATUS NTAPI NtOpenProcessToken(
	HANDLE Process,
	ACCESS_MASK DesiredAccess,
	PHANDLE Token )
{
	NTSTATUS r;

	TRACE("%p %08lx %p\n", Process, DesiredAccess, Token);

	r = VerifyForWrite( Token, sizeof *Token );
	if (r < STATUS_SUCCESS)
		return r;

	PROCESS *p = 0;
	r = ObjectFromHandle( p, Process, 0 );
	if (r < STATUS_SUCCESS)
		return r;

	TOKEN *token = new TOKEN_IMPL;
	if (!token)
		return STATUS_NO_MEMORY;

	r = AllocUserHandle( token, DesiredAccess, Token );
	Release( token );

	return r;
}
コード例 #2
0
ファイル: timer.cpp プロジェクト: bragin/ring3k
NTSTATUS NtCancelTimer(
	HANDLE TimerHandle,
	PBOOLEAN PreviousState)
{
	NTSTATUS r;

	NTTIMER* timer = 0;
	r = ObjectFromHandle( timer, TimerHandle, TIMER_MODIFY_STATE );
	if (r < STATUS_SUCCESS)
		return r;

	if (PreviousState)
	{
		r = VerifyForWrite( PreviousState, sizeof *PreviousState );
		if (r < STATUS_SUCCESS)
			return r;
	}

	BOOLEAN prev = 0;
	timer->Cancel(prev);

	if (PreviousState)
		CopyToUser( PreviousState, &prev, sizeof prev );

	return STATUS_SUCCESS;
}
コード例 #3
0
ファイル: token.cpp プロジェクト: bragin/ring3k
NTSTATUS NTAPI NtOpenThreadToken(
	HANDLE Thread,
	ACCESS_MASK DesiredAccess,
	BOOLEAN OpenAsSelf,
	PHANDLE TokenHandle )
{
	NTSTATUS r;

	TRACE("%p %08lx %u %p\n", Thread, DesiredAccess, OpenAsSelf, TokenHandle);

	r = VerifyForWrite( TokenHandle, sizeof *TokenHandle );
	if (r < STATUS_SUCCESS)
		return r;

	THREAD *t = 0;
	r = ObjectFromHandle( t, Thread, DesiredAccess );
	if (r < STATUS_SUCCESS)
		return r;

	TOKEN *tok = t->GetToken();
	if (tok == 0)
		return STATUS_NO_TOKEN;

	r = AllocUserHandle( tok, DesiredAccess, TokenHandle );

	return r;
}
コード例 #4
0
ファイル: timer.cpp プロジェクト: bragin/ring3k
NTSTATUS NTAPI NtQueryTimer(
	HANDLE TimerHandle,
	TIMER_INFORMATION_CLASS TimerInformationClass,
	PVOID TimerInformation,
	ULONG TimerInformationLength,
	PULONG ResultLength)
{
	NTSTATUS r;

	NTTIMER* timer = 0;
	r = ObjectFromHandle( timer, TimerHandle, TIMER_MODIFY_STATE );
	if (r < STATUS_SUCCESS)
		return r;

	union
	{
		TIMER_BASIC_INFORMATION basic;
	} info;
	ULONG sz = 0;

	switch (TimerInformationClass)
	{
	case TimerBasicInformation:
		sz = sizeof info.basic;
		break;
	default:
		return STATUS_INVALID_INFO_CLASS;
	}

	// this seems like the wrong order, but agrees with what tests show
	r = VerifyForWrite( TimerInformation, sz );
	if (r < STATUS_SUCCESS)
		return r;

	if (sz != TimerInformationLength)
		return STATUS_INFO_LENGTH_MISMATCH;

	switch (TimerInformationClass)
	{
	case TimerBasicInformation:
		info.basic.SignalState = timer->IsSignalled();
		timer->TimeRemaining( info.basic.TimeRemaining );
		break;
	default:
		assert(0);
	}

	r = CopyToUser( TimerInformation, &info, sz );
	if (r < STATUS_SUCCESS)
		return r;

	if (ResultLength)
		CopyToUser( ResultLength, &sz, sizeof sz );

	return r;
}
コード例 #5
0
ファイル: comcallwrapper.cpp プロジェクト: ArildF/masters
OBJECTREF ComCallWrapper::GetObjectRefFromComIP(IUnknown* pUnk)
{
    ComCallWrapper *pWrapper;

    THROWSCOMPLUSEXCEPTION();
    _ASSERTE(pUnk != NULL);
    
    // check whether the IUnknown* is comming from our wrapper
    if (*(PVOID*)pUnk != GetComCallWrapperVPtr())
        COMPlusThrow(kInvalidCastException);

    pWrapper = GetWrapperFromIP(pUnk);      
    return ObjectFromHandle(pWrapper->m_hThis);
}
コード例 #6
0
ファイル: comcallwrapper.cpp プロジェクト: ArildF/masters
static OBJECTREF GetOleAutBinder()
{
    THROWSCOMPLUSEXCEPTION();

    // If we have already create the instance of the OleAutBinder then simply return it.
    if (s_hndOleAutBinder)
        return ObjectFromHandle(s_hndOleAutBinder);

    MethodTable *pOleAutBinderClass = g_Mscorlib.GetClass(CLASS__OLE_AUT_BINDER);

    // Allocate an instance of the OleAutBinder class.
    OBJECTREF OleAutBinder = AllocateObject(pOleAutBinderClass);

    // Keep a handle to the OleAutBinder instance.
    s_hndOleAutBinder = CreateGlobalHandle(OleAutBinder);

    return OleAutBinder;
}
コード例 #7
0
ファイル: token.cpp プロジェクト: bragin/ring3k
NTSTATUS NTAPI
NtSetInformationToken(
	IN HANDLE TokenHandle,
	IN TOKEN_INFORMATION_CLASS TokenInformationClass,
	IN PVOID TokenInformation,
	IN ULONG TokenInformationLength)
{
	TOKEN *Token;
	//ULONG Len;
	NTSTATUS Status;

	FIXME("UNIMPLEMENTED: %08lx %08lx\n", TokenHandle, TokenInformationClass);

	Status = ObjectFromHandle(Token, TokenHandle, TOKEN_QUERY);
	if (Status < STATUS_SUCCESS)
		return Status;

	return STATUS_SUCCESS;
}
コード例 #8
0
ファイル: completion.cpp プロジェクト: bragin/ring3k
// nonblocking
NTSTATUS NTAPI NtSetIoCompletion(
	HANDLE IoCompletionHandle,
	ULONG IoCompletionKey,
	ULONG IoCompletionValue,
	NTSTATUS Status,
	ULONG Information)
{
	NTSTATUS r;

	TRACE("%p %08lx %08lx %08lx %08lx\n", IoCompletionHandle, IoCompletionKey,
		  IoCompletionValue, Status, Information);

	COMPLETION_PORT_IMPL *port = 0;
	r = ObjectFromHandle( port, IoCompletionHandle, IO_COMPLETION_MODIFY_STATE );
	if (r < STATUS_SUCCESS)
		return r;

	port->Set( IoCompletionKey, IoCompletionValue, Status, Information );

	return STATUS_SUCCESS;
}
コード例 #9
0
ファイル: token.cpp プロジェクト: bragin/ring3k
//NtPrivilegeCheck(00000154,0006fdc0,0006fe34) ret=77fa7082
NTSTATUS NtPrivilegeCheck(
	HANDLE TokenHandle,
	PPRIVILEGE_SET RequiredPrivileges,
	PBOOLEAN Result)
{
	TOKEN *token = 0;

	NTSTATUS r = ObjectFromHandle( token, TokenHandle, TOKEN_QUERY );
	if (r < STATUS_SUCCESS)
		return r;

	PRIVILEGES_SET ps;
	r = ps.CopyFromUser( RequiredPrivileges );
	if (r < STATUS_SUCCESS)
		return r;

	BOOLEAN ok = TRUE;
	r = CopyToUser( Result, &ok, sizeof ok );

	FIXME("\n");

	return r;
}
コード例 #10
0
ファイル: token.cpp プロジェクト: bragin/ring3k
NTSTATUS NTAPI NtDuplicateToken(
	HANDLE ExistingToken,
	ACCESS_MASK DesiredAccess,
	POBJECT_ATTRIBUTES ObjectAttributes,
	BOOLEAN EffectiveOnly,
	TOKEN_TYPE TokenType,
	PHANDLE TokenHandle)
{
	TOKEN *existing = 0;

	NTSTATUS r = ObjectFromHandle( existing, ExistingToken, TOKEN_QUERY );
	if (r < STATUS_SUCCESS)
		return r;

	TOKEN *token = new TOKEN_IMPL;
	if (!token)
		return STATUS_NO_MEMORY;

	r = AllocUserHandle( token, DesiredAccess, TokenHandle );
	Release( token );

	return r;
}
コード例 #11
0
ファイル: assemblyspec.cpp プロジェクト: ArildF/masters
HRESULT AssemblySpecBindingCache::Lookup(AssemblySpec *pSpec, 
                                         PEFile **ppFile,
                                         IAssembly** ppIAssembly,
                                         OBJECTREF *pThrowable)
{
    DWORD key = pSpec->Hash();

    AssemblyBinding *entry = (AssemblyBinding *) m_map.LookupValue(key, pSpec);

    if (entry == (AssemblyBinding *) INVALIDENTRY)
        return S_FALSE;
    else
    {
        if (ppFile) 
        {
            if (entry->file == NULL)
                *ppFile = NULL;
            else
                PEFile::Clone(entry->file, ppFile);
        }
        if (ppIAssembly) 
        {
            *ppIAssembly = entry->pIAssembly;
            if (*ppIAssembly != NULL)
                (*ppIAssembly)->AddRef();
        }
        if (pThrowable) 
        {
            if (entry->hThrowable == NULL)
                *pThrowable = NULL;
            else
                *pThrowable = ObjectFromHandle(entry->hThrowable);
        }

        return entry->hr;
    }
}
コード例 #12
0
ファイル: timer.cpp プロジェクト: bragin/ring3k
NTSTATUS NtSetTimer(
	HANDLE TimerHandle,
	PLARGE_INTEGER DueTime,
	PTIMER_APC_ROUTINE TimerApcRoutine,
	PVOID TimerContext,
	BOOLEAN Resume,
	LONG Period,
	PBOOLEAN PreviousState)
{
	LARGE_INTEGER due;

	NTSTATUS r = CopyFromUser( &due, DueTime, sizeof due );
	if (r < STATUS_SUCCESS)
		return r;

	TRACE("due = %llx\n", due.QuadPart);

	NTTIMER* timer = 0;
	r = ObjectFromHandle( timer, TimerHandle, TIMER_MODIFY_STATE );
	if (r < STATUS_SUCCESS)
		return r;

	if (PreviousState)
	{
		r = VerifyForWrite( PreviousState, sizeof *PreviousState );
		if (r < STATUS_SUCCESS)
			return r;
	}

	BOOLEAN prev = FALSE;
	r = timer->Set( due, (PKNORMAL_ROUTINE)TimerApcRoutine, TimerContext, Resume, Period, prev );
	if (r == STATUS_SUCCESS && PreviousState )
		CopyToUser( PreviousState, &prev, sizeof prev );

	return r;
}
コード例 #13
0
ファイル: token.cpp プロジェクト: bragin/ring3k
NTSTATUS NTAPI NtQueryInformationToken(
	HANDLE TokenHandle,
	TOKEN_INFORMATION_CLASS TokenInformationClass,
	PVOID TokenInformation,
	ULONG TokenInformationLength,
	PULONG ReturnLength )
{
	TOKEN *token;
	ULONG len;
	NTSTATUS r;
	TOKEN_STATISTICS stats;

	TRACE("%p %u %p %lu %p\n", TokenHandle, TokenInformationClass,
		  TokenInformation, TokenInformationLength, ReturnLength );

	r = ObjectFromHandle( token, TokenHandle, TOKEN_QUERY );
	if (r < STATUS_SUCCESS)
		return r;

	switch( TokenInformationClass )
	{
	case TokenOwner:
		TRACE("TokenOwner\n");
		r = CopyPtrToUser( token->GetOwner(), TokenInformation, TokenInformationLength, len );
		break;

	case TokenPrimaryGroup:
		TRACE("TokenPrimaryGroup\n");
		r = CopyPtrToUser( token->GetPrimaryGroup(), TokenInformation, TokenInformationLength, len );
		break;

	case TokenDefaultDacl:
		TRACE("TokenDefaultDacl\n");
		r = CopyPtrToUser( token->GetDefaultDacl(), TokenInformation, TokenInformationLength, len );
		break;

	case TokenUser:
		TRACE("TokenUser\n");
		len = token->GetUser().GetLength();
		if (len > TokenInformationLength)
		{
			r = STATUS_BUFFER_TOO_SMALL;
			break;
		}

		r = token->GetUser().CopyToUser( (SID_AND_ATTRIBUTES*) TokenInformation );
		break;

	case TokenImpersonationLevel:
		FIXME("UNIMPLEMENTED: TokenImpersonationLevel\n");
		return STATUS_INVALID_INFO_CLASS;

	case TokenStatistics:
		TRACE("TokenStatistics\n");
		len = sizeof stats;
		if (len != TokenInformationLength)
			return STATUS_INFO_LENGTH_MISMATCH;

		memset( &stats, 0, sizeof stats );
		r = CopyToUser( TokenInformation, &stats, sizeof stats );
		if (r < STATUS_SUCCESS)
			return r;

		break;

	case TokenGroups:
		TRACE("TokenGroups\n");
		len = token->GetGroups().GetLength();
		if (len > TokenInformationLength)
		{
			r = STATUS_BUFFER_TOO_SMALL;
			break;
		}

		r = token->GetGroups().CopyToUser( (TOKEN_GROUPS*) TokenInformation );
		break;

	case TokenRestrictedSids:
		TRACE("TokenRestrictedSids\n");
		len = token->GetRestrictedSids().GetLength();
		if (len > TokenInformationLength)
		{
			r = STATUS_BUFFER_TOO_SMALL;
			break;
		}

		r = token->GetGroups().CopyToUser((TOKEN_GROUPS*)TokenInformation);
		break;

	default:
		FIXME("UNIMPLEMENTED: info class %d\n", TokenInformationClass);
		return STATUS_INVALID_INFO_CLASS;
	}

	if (ReturnLength)
		CopyToUser( ReturnLength, &len, sizeof len );

	return r;
}
コード例 #14
0
ファイル: token.cpp プロジェクト: bragin/ring3k
NTSTATUS NTAPI NtAdjustPrivilegesToken(
	HANDLE TokenHandle,
	BOOLEAN DisableAllPrivileges,
	PTOKEN_PRIVILEGES NewState,
	ULONG BufferLength,
	PTOKEN_PRIVILEGES PreviousState,
	PULONG ReturnLength )
{
	NTSTATUS r;

	TRACE("%p %u %p %lu %p %p\n", TokenHandle, DisableAllPrivileges,
		  NewState, BufferLength, PreviousState, ReturnLength );

	if (ReturnLength)
	{
		r = VerifyForWrite( ReturnLength, sizeof *ReturnLength );
		if (r < STATUS_SUCCESS)
			return r;
	}

	if (!NewState)
		return STATUS_INVALID_PARAMETER;

	// getting the old state requires query rights
	ACCESS_MASK mask = TOKEN_ADJUST_PRIVILEGES;
	if (PreviousState)
		mask |= TOKEN_QUERY;

	TOKEN *token = 0;
	r = ObjectFromHandle( token, TokenHandle, mask );
	if (r < STATUS_SUCCESS)
		return r;

	CTOKEN_PRIVILEGES privs;
	r = privs.CopyFromUser( NewState );
	if (r < STATUS_SUCCESS)
		return r;

	// return previous state information if required
	if (PreviousState)
	{
		CTOKEN_PRIVILEGES& prev_state = token->GetPrivs();

		ULONG len = prev_state.GetLength();
		TRACE("old privs %ld bytes\n", len);
		prev_state.Dump();
		if (len > BufferLength)
			return STATUS_BUFFER_TOO_SMALL;

		r = prev_state.CopyToUser( PreviousState );
		if (r < STATUS_SUCCESS)
			return r;

		r = CopyToUser( ReturnLength, &len, sizeof len );
		assert( r == STATUS_SUCCESS );
	}

	r = token->Adjust( privs );

	TRACE("new privs\n");
	privs.Dump();

	return r;
}
コード例 #15
0
ファイル: corgc-gc.cpp プロジェクト: Spo1ler/mono
MonoObject*
mono_gc_weak_link_get (void **link_addr)
{
  return ObjectFromHandle((OBJECTHANDLE)*link_addr);
}
コード例 #16
0
ファイル: comcallwrapper.cpp プロジェクト: ArildF/masters
VOID ComCallWrapper::InvokeByNameCallback(LPVOID ptr)
{
    InvokeByNameArgs* args = (InvokeByNameArgs*)ptr;
    INT32 NumByrefArgs = 0;
    INT32 *aByrefArgMngVariantIndex = NULL;
    INT32 iArg;
    struct __gc {
        OBJECTREF Target;
        STRINGREF MemberName;
        PTRARRAYREF ParamArray;
        OBJECTREF TmpObj;
        OBJECTREF RetVal;
    } gc;
    ZeroMemory(&gc, sizeof(gc));

    GCPROTECT_BEGIN(gc);

    gc.MemberName = COMString::NewString(args->MemberName);

    gc.ParamArray = (PTRARRAYREF)AllocateObjectArray(args->ArgCount, g_pObjectClass);

    //
    // Fill in the arguments.
    //

    for (iArg = 0; iArg < args->ArgCount; iArg++)
    {
        // Convert the variant.
        VARIANT *pSrcOleVariant = &args->ArgList[iArg];
        OleVariant::MarshalObjectForOleVariant(pSrcOleVariant, &gc.TmpObj);
        gc.ParamArray->SetAt(iArg, gc.TmpObj);

        // If the argument is byref then add it to the array of byref arguments.
        if (V_VT(pSrcOleVariant) & VT_BYREF)
        {
            if (aByrefArgMngVariantIndex == NULL) {
                aByrefArgMngVariantIndex = (INT32 *)_alloca(sizeof(INT32) * args->ArgCount);
            }

            aByrefArgMngVariantIndex[NumByrefArgs] = iArg;
            NumByrefArgs++;
        }
    }

    gc.Target = ObjectFromHandle(args->pThis->m_hThis);

    //
    // Invoke using IReflect::InvokeMember
    //

    EEClass *pClass = gc.Target->GetClass();

    // Retrieve the method descriptor that will be called on.
    MethodDesc *pMD = GetInvokeMemberMD();

    // Prepare the arguments that will be passed to Invoke.
    ARG_SLOT Args[] = {
            ObjToArgSlot(GetReflectionObject(pClass)), // IReflect
            ObjToArgSlot(gc.MemberName),    // name
            (ARG_SLOT) args->BindingFlags,  // invokeAttr
            ObjToArgSlot(GetOleAutBinder()),// binder
            ObjToArgSlot(gc.Target),        // target
            ObjToArgSlot(gc.ParamArray),    // args
            ObjToArgSlot(NULL),             // modifiers
            ObjToArgSlot(NULL),             // culture
            ObjToArgSlot(NULL)              // namedParameters
    };

    // Do the actual method invocation.
    MetaSig metaSig(pMD->GetSig(),pMD->GetModule());
    gc.RetVal = ArgSlotToObj(pMD->Call(Args, &metaSig));

    //
    // Convert the return value and the byref arguments.
    //

    // Convert all the ByRef arguments back.
    for (iArg = 0; iArg < NumByrefArgs; iArg++)
    {
        INT32 i = aByrefArgMngVariantIndex[iArg];
        gc.TmpObj = gc.ParamArray->GetAt(i);
        OleVariant::MarshalOleRefVariantForObject(&gc.TmpObj, &args->ArgList[i]);
    }

    // Convert the return COM+ object to an OLE variant.
    if (args->pRetVal)
        OleVariant::MarshalOleVariantForObject(&gc.RetVal, args->pRetVal);

    GCPROTECT_END();
}
コード例 #17
0
ファイル: GCSample.cpp プロジェクト: ravindrapro/coreclr
int main(int argc, char* argv[])
{
    //
    // Initialize system info
    //
    InitializeSystemInfo();

    //
    // Initialize free object methodtable. The GC uses a special array-like methodtable as placeholder
    // for collected free space.
    //
    static MethodTable freeObjectMT;
    freeObjectMT.InitializeFreeObject();
    g_pFreeObjectMethodTable = &freeObjectMT;

    //
    // Initialize handle table
    //
    if (!Ref_Initialize())
        return -1;

    //
    // Initialize GC heap
    //
    GCHeap *pGCHeap = GCHeap::CreateGCHeap();
    if (!pGCHeap)
        return -1;

    if (FAILED(pGCHeap->Initialize()))
        return -1;

    //
    // Initialize current thread
    //
    ThreadStore::AttachCurrentThread(false);

    //
    // Create a Methodtable with GCDesc
    //

    class My : Object {
    public:
        Object * m_pOther1;
        int dummy_inbetween;
        Object * m_pOther2;
    };

    static struct My_MethodTable
    {
        // GCDesc
        CGCDescSeries m_series[2];
        size_t m_numSeries;

        // The actual methodtable
        MethodTable m_MT;
    }
    My_MethodTable;

    // 'My' contains the MethodTable*
    size_t baseSize = sizeof(My);
    // GC expects the size of ObjHeader (extra void*) to be included in the size.
    baseSize = baseSize + sizeof(ObjHeader);
    // Add padding as necessary. GC requires the object size to be at least MIN_OBJECT_SIZE.
    My_MethodTable.m_MT.m_baseSize = max(baseSize, MIN_OBJECT_SIZE);

    My_MethodTable.m_MT.m_componentSize = 0;    // Array component size
    My_MethodTable.m_MT.m_flags = MTFlag_ContainsPointers;

    My_MethodTable.m_numSeries = 2;

    // The GC walks the series backwards. It expects the offsets to be sorted in descending order.
    My_MethodTable.m_series[0].SetSeriesOffset(offsetof(My, m_pOther2));
    My_MethodTable.m_series[0].SetSeriesCount(1);
    My_MethodTable.m_series[0].seriessize -= My_MethodTable.m_MT.m_baseSize;

    My_MethodTable.m_series[1].SetSeriesOffset(offsetof(My, m_pOther1));
    My_MethodTable.m_series[1].SetSeriesCount(1);
    My_MethodTable.m_series[1].seriessize -= My_MethodTable.m_MT.m_baseSize;

    MethodTable * pMyMethodTable = &My_MethodTable.m_MT;

    // Allocate instance of MyObject
    Object * pObj = AllocateObject(pMyMethodTable);
    if (pObj == NULL)
        return -1;

    // Create strong handle and store the object into it
    OBJECTHANDLE oh = CreateGlobalHandle(pObj);
    if (oh == NULL)
        return -1;

    for (int i = 0; i < 1000000; i++)
    {
        Object * pBefore = ((My *)ObjectFromHandle(oh))->m_pOther1;

        // Allocate more instances of the same object
        Object * p = AllocateObject(pMyMethodTable);
        if (p == NULL)
            return -1;

        Object * pAfter = ((My *)ObjectFromHandle(oh))->m_pOther1;

        // Uncomment this assert to see how GC triggered inside AllocateObject moved objects around
        // assert(pBefore == pAfter);

        // Store the newly allocated object into a field using WriteBarrier
        WriteBarrier(&(((My *)ObjectFromHandle(oh))->m_pOther1), p);
    }

    // Create weak handle that points to our object
    OBJECTHANDLE ohWeak = CreateGlobalWeakHandle(ObjectFromHandle(oh));
    if (ohWeak == NULL)
        return -1;

    // Destroy the strong handle so that nothing will be keeping out object alive
    DestroyGlobalHandle(oh);

    // Explicitly trigger full GC
    pGCHeap->GarbageCollect();

    // Verify that the weak handle got cleared by the GC
    assert(ObjectFromHandle(ohWeak) == NULL);

    printf("Done\n");

    return 0;
}
コード例 #18
0
ファイル: completion.cpp プロジェクト: bragin/ring3k
// blocking
NTSTATUS NTAPI NtRemoveIoCompletion(
	HANDLE IoCompletionHandle,
	PULONG IoCompletionKey,
	PULONG IoCompletionValue,
	PIO_STATUS_BLOCK IoStatusBlock,
	PLARGE_INTEGER TimeOut)
{
	NTSTATUS r;

	TRACE("%p %p %p %p %p\n", IoCompletionHandle, IoCompletionKey,
		  IoCompletionValue, IoStatusBlock, TimeOut);

	COMPLETION_PORT_IMPL *port = 0;
	r = ObjectFromHandle( port, IoCompletionHandle, IO_COMPLETION_MODIFY_STATE );
	if (r < STATUS_SUCCESS)
		return r;

	if (IoCompletionKey)
	{
		r = VerifyForWrite( IoCompletionKey, sizeof *IoCompletionKey );
		if (r < STATUS_SUCCESS)
			return r;
	}

	if (IoCompletionValue)
	{
		r = VerifyForWrite( IoCompletionValue, sizeof *IoCompletionValue );
		if (r < STATUS_SUCCESS)
			return r;
	}

	if (IoStatusBlock)
	{
		r = VerifyForWrite( IoStatusBlock, sizeof *IoStatusBlock );
		if (r < STATUS_SUCCESS)
			return r;
	}

	LARGE_INTEGER t;
	t.QuadPart = 0LL;
	if (TimeOut)
	{
		r = CopyFromUser( &t, TimeOut, sizeof t );
		if (r < STATUS_SUCCESS)
			return r;
		TimeOut = &t;
	}

	ULONG key = 0, val = 0;
	IO_STATUS_BLOCK iosb;
	iosb.Status = 0;
	iosb.Information = 0;
	port->Remove( key, val, iosb.Status, iosb.Information, TimeOut );

	if (IoCompletionKey)
		CopyToUser( IoCompletionKey, &key, sizeof key );

	if (IoCompletionValue)
		CopyToUser( IoCompletionValue, &val, sizeof val );

	if (IoStatusBlock)
		CopyToUser( IoStatusBlock, &iosb, sizeof iosb );

	return r;
}