asCScriptObject::asCScriptObject(asCObjectType *ot) { refCount.set(1); objType = ot; objType->AddRef(); isDestructCalled = false; // Notify the garbage collector of this object if( objType->flags & asOBJ_GC ) objType->engine->gc.AddScriptObjectToGC(this, objType); // Construct all properties asCScriptEngine *engine = objType->engine; for( asUINT n = 0; n < objType->properties.GetLength(); n++ ) { asCObjectProperty *prop = objType->properties[n]; if( prop->type.IsObject() ) { size_t *ptr = (size_t*)(((char*)this) + prop->byteOffset); if( prop->type.IsObjectHandle() ) *ptr = 0; else { // Allocate the object and call it's constructor *ptr = (size_t)AllocateObject(prop->type.GetObjectType(), engine); } } } }
Bool LoadObject(int object_id,char *class_name) { class_node *c; c = GetClassByName(class_name); if (c == NULL) { eprintf("LoadObject can't find class name %s\n",class_name); return False; } if (AllocateObject(c->class_id) != object_id) { eprintf("LoadObject didn't make object id %i\n",object_id); return False; } /* set self = prop 0 */ objects[object_id].p[0].id = 0; objects[object_id].p[0].val.v.tag = TAG_OBJECT; objects[object_id].p[0].val.v.data = object_id; /* if no kod changed, then setting the properties shouldn't be * necessary. however, who knows. */ SetObjectProperties(object_id,c); return True; }
FCIMPL1(Object*, AssemblyNameNative::GetFileInformation, StringObject* filenameUNSAFE) { FCALL_CONTRACT; struct _gc { ASSEMBLYNAMEREF result; STRINGREF filename; } gc; gc.result = NULL; gc.filename = (STRINGREF) filenameUNSAFE; HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc); if (gc.filename == NULL) COMPlusThrow(kArgumentNullException, W("ArgumentNull_FileName")); if (gc.filename->GetStringLength() == 0) COMPlusThrow(kArgumentException, W("Argument_EmptyFileName")); gc.result = (ASSEMBLYNAMEREF) AllocateObject(MscorlibBinder::GetClass(CLASS__ASSEMBLY_NAME)); /////////////////////////////////////////////// SString sFileName(gc.filename->GetBuffer()); PEImageHolder pImage = PEImage::OpenImage(sFileName, MDInternalImport_NoCache); EX_TRY { #ifdef FEATURE_CORECLR // Allow AssemblyLoadContext.GetAssemblyName for native images on CoreCLR if (pImage->HasNTHeaders() && pImage->HasCorHeader() && pImage->HasNativeHeader()) pImage->VerifyIsNIAssembly(); else pImage->VerifyIsAssembly(); #else pImage->VerifyIsAssembly(); #endif } EX_CATCH { Exception *ex = GET_EXCEPTION(); EEFileLoadException::Throw(sFileName,ex->GetHR(),ex); } EX_END_CATCH_UNREACHABLE; SString sUrl = sFileName; PEAssembly::PathToUrl(sUrl); AssemblySpec spec; spec.InitializeSpec(TokenFromRid(mdtAssembly,1),pImage->GetMDImport(),NULL,TRUE); spec.SetCodeBase(sUrl); spec.AssemblyNameInit(&gc.result, pImage); HELPER_METHOD_FRAME_END(); return OBJECTREFToObject(gc.result); }
LPDRIVE_INFO CreateDriveInfoStructure( void ) /*++ Routine Description: Create a DRIVE_INFO object for the supplied drive. Arguments: None Return Value: LPDRIVE_INFO - Allocates and returns a pointer to a DRIVE_INFO object --*/ { LPDRIVE_INFO DriveInfo; // // Allocate a DRIVE_INFO object. // DriveInfo = AllocateObject( DRIVE_INFO, 1 ); DbgPointerAssert( DriveInfo ); if( DriveInfo == NULL ) { return NULL; } // // Initialize buffers with empty strings. // ZeroMemory( DriveInfo, sizeof(DRIVE_INFO) ); // // Set the signature // SetSignature( DriveInfo ); // // Mark Structure as invalid since it is not filled out yet. // DriveInfo->ValidDetails = FALSE; return DriveInfo; }
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; }
int CreateObject(int class_id,int num_parms,parm_node parms[]) { int new_object_id; class_node *c; new_object_id = AllocateObject(class_id); if (new_object_id == INVALID_OBJECT) return INVALID_OBJECT; /* set self = prop 0 */ objects[new_object_id].p[0].id = 0; objects[new_object_id].p[0].val.v.tag = TAG_OBJECT; objects[new_object_id].p[0].val.v.data = new_object_id; c = GetClassByID(class_id); if (c == NULL) /* can't ever be, because AllocateObject checks */ { eprintf("CreateObject can't find class id %i\n",class_id); return INVALID_OBJECT; } SetObjectProperties(new_object_id,c); /* might not be top level message, since can be called from blakod. If it really IS a top level message, then it better not post anything, since post messages won't be handled */ if (IsInterpreting()) SendBlakodMessage(new_object_id,CONSTRUCTOR_MSG,num_parms,parms); else SendTopLevelBlakodMessage(new_object_id,CONSTRUCTOR_MSG,num_parms,parms); if (ConfigBool(DEBUG_UNINITIALIZED)) { int i; for (i = 0; i < (1+c->num_properties); i++) if (objects[new_object_id].p[i].val.v.tag == TAG_INVALID) eprintf("Uninitialized properties after constructor, class %s\n", c->class_name); } return new_object_id; }
HRESULT CorHost::CreateEvidence(IUnknown **pEvidence) { HRESULT hr = S_OK; if (!pEvidence) return E_POINTER; BEGINCANNOTTHROWCOMPLUSEXCEPTION(); // Create the domain. Thread* pThread = GetThread(); if (!pThread) IfFailGo(E_UNEXPECTED); IfFailGo(QuickCOMStartup()); BOOL fWasGCEnabled; fWasGCEnabled = !pThread->PreemptiveGCDisabled(); if (fWasGCEnabled) pThread->DisablePreemptiveGC(); COMPLUS_TRY { struct _gc { OBJECTREF pEvidence; } gc; ZeroMemory(&gc, sizeof(gc)); MethodTable* pMT = g_Mscorlib.GetClass(CLASS__EVIDENCE); GCPROTECT_BEGIN(gc); gc.pEvidence = AllocateObject(pMT); IfFailThrow(QuickCOMStartup()); *pEvidence = GetComIPFromObjectRef((OBJECTREF*) &gc.pEvidence); GCPROTECT_END(); } COMPLUS_CATCH { hr = SecurityHelper::MapToHR(GETTHROWABLE()); } COMPLUS_END_CATCH if (fWasGCEnabled) pThread->EnablePreemptiveGC(); ErrExit: ENDCANNOTTHROWCOMPLUSEXCEPTION(); return hr; }
HRESULT CorHost::CreateDomainSetup(IUnknown **pAppDomainSetup) { HRESULT hr = S_OK; if (!pAppDomainSetup) return E_POINTER; BEGINCANNOTTHROWCOMPLUSEXCEPTION(); // Create the domain. Thread* pThread = GetThread(); if (!pThread) IfFailGo(E_UNEXPECTED); IfFailGo(QuickCOMStartup()); BEGIN_ENSURE_COOPERATIVE_GC(); COMPLUS_TRY { struct _gc { OBJECTREF pSetup; } gc; ZeroMemory(&gc, sizeof(gc)); MethodTable* pMT = g_Mscorlib.GetClass(CLASS__APPDOMAIN_SETUP); GCPROTECT_BEGIN(gc); gc.pSetup = AllocateObject(pMT); IfFailThrow(QuickCOMStartup()); *pAppDomainSetup = GetComIPFromObjectRef((OBJECTREF*) &gc.pSetup); GCPROTECT_END(); } COMPLUS_CATCH { hr = SecurityHelper::MapToHR(GETTHROWABLE()); } COMPLUS_END_CATCH END_ENSURE_COOPERATIVE_GC(); ErrExit: ENDCANNOTTHROWCOMPLUSEXCEPTION(); return hr; }
asCScriptStruct::asCScriptStruct(asCObjectType *ot) { gc.Init(ot); // Construct all properties asCScriptEngine *engine = gc.objType->engine; for( asUINT n = 0; n < gc.objType->properties.GetLength(); n++ ) { asCProperty *prop = gc.objType->properties[n]; if( prop->type.IsObject() ) { size_t *ptr = (size_t*)(((char*)this) + prop->byteOffset); if( prop->type.IsObjectHandle() ) *ptr = 0; else { // Allocate the object and call it's constructor *ptr = (size_t)AllocateObject(prop->type.GetObjectType(), engine); } } } }
int __cdecl main(int argc, char* argv[]) { // // Initialize system info // if (!GCToOSInterface::Initialize()) { return -1; } // // 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 GC heap // GcDacVars dacVars; IGCHeap *pGCHeap; IGCHandleManager *pGCHandleManager; if (!InitializeGarbageCollector(nullptr, &pGCHeap, &pGCHandleManager, &dacVars)) { return -1; } if (FAILED(pGCHeap->Initialize())) return -1; // // Initialize handle manager // if (!pGCHandleManager->Initialize()) return -1; // // Initialize current thread // ThreadStore::AttachCurrentThread(); // // 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* uint32_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 = HndCreateHandle(g_HandleTableMap.pBuckets[0]->pTable[GetCurrentThreadHomeHeapNumber()], HNDTYPE_DEFAULT, pObj); if (oh == NULL) return -1; for (int i = 0; i < 1000000; i++) { Object * pBefore = ((My *)HndFetchHandle(oh))->m_pOther1; // Allocate more instances of the same object Object * p = AllocateObject(pMyMethodTable); if (p == NULL) return -1; Object * pAfter = ((My *)HndFetchHandle(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 *)HndFetchHandle(oh))->m_pOther1), p); } // Create weak handle that points to our object OBJECTHANDLE ohWeak = HndCreateHandle(g_HandleTableMap.pBuckets[0]->pTable[GetCurrentThreadHomeHeapNumber()], HNDTYPE_WEAK_DEFAULT, HndFetchHandle(oh)); if (ohWeak == NULL) return -1; // Destroy the strong handle so that nothing will be keeping out object alive HndDestroyHandle(HndGetHandleTable(oh), HNDTYPE_DEFAULT, oh); // Explicitly trigger full GC pGCHeap->GarbageCollect(); // Verify that the weak handle got cleared by the GC assert(HndFetchHandle(ohWeak) == NULL); printf("Done\n"); return 0; }
BOOL InitializeSystemResourceLists( IN HREGKEY hRegKey ) /*++ Routine Description: InitializeSystemResourceLists recursively walks the resource map in the registry and builds the SYSTEM_RESOURCE lists. This is a data structure that links all resources of the same type together, as well as linking all resources belonging to a specific device/driver together. Lastly each resource is independently linked to the device/driver that owns it. This leds to a 'mesh' of linked lists with back pointers to the owning device/driver object. Arguments: hRegKey - Supplies a handle to a REGKEY object where the search is to continue. Return Value: BOOL - returns TRUE if the resource lists are succesfully built. --*/ { BOOL Success; HREGKEY hRegSubkey; DbgHandleAssert( hRegKey ); // // While there are still more device/driver resource descriptors... // while( QueryNextValue( hRegKey )) { PCM_FULL_RESOURCE_DESCRIPTOR FullResource; LPSYSTEM_RESOURCES SystemResource; LPDEVICE Device; LPTSTR Extension; DWORD Count; DWORD i; DWORD j; // // Based on the type of key, prepare to walk the list of // RESOURCE_DESCRIPTORS (the list may be one in length). // if( hRegKey->Type == REG_FULL_RESOURCE_DESCRIPTOR ) { Count = 1; FullResource = ( PCM_FULL_RESOURCE_DESCRIPTOR ) hRegKey->Data; } else if( hRegKey->Type == REG_RESOURCE_LIST ) { Count = (( PCM_RESOURCE_LIST ) hRegKey->Data )->Count; FullResource = (( PCM_RESOURCE_LIST ) hRegKey->Data )->List; } else { DbgAssert( FALSE ); continue; } // // Allocate a DEVICE object. // Device = AllocateObject( DEVICE, 1 ); DbgPointerAssert( Device ); if( Device == NULL ) { Success = DestroySystemResourceLists( _SystemResourceLists ); DbgAssert( Success ); return FALSE; } // // Allocate a buffer for the device/driver name. The maximum size of // the name will be the number of characters in both the key and // value name. // Device->Name = AllocateObject( TCHAR, _tcslen( hRegKey->Name ) + _tcslen( hRegKey->ValueName ) + sizeof( TCHAR ) ); DbgPointerAssert( Device->Name ); if( Device->Name == NULL ) { Success = DestroySystemResourceLists( _SystemResourceLists ); DbgAssert( Success ); return FALSE; } // // Rationalize the device name such that it is of the form Device.Raw // or Device.Translated. // Device->Name[ 0 ] = TEXT( '\0' ); if( ( _tcsnicmp( hRegKey->ValueName, TEXT( ".Raw" ), 4 ) == 0 ) || ( _tcsnicmp( hRegKey->ValueName, TEXT( ".Translated" ), 11 ) == 0 )) { _tcscpy( Device->Name, hRegKey->Name ); } _tcscat( Device->Name, hRegKey->ValueName ); // // Based on the device name, determine if the resource descriptors // should be added to the RAW or TRANSLATED lists. // if( Extension = _tcsstr( Device->Name, TEXT( ".Raw" ))) { SystemResource = &_SystemResourceLists[ RAW ]; } else if( Extension = _tcsstr( Device->Name, TEXT( ".Translated" ))) { SystemResource = &_SystemResourceLists[ TRANSLATED ]; } else { DbgAssert( FALSE ); Success = DestroySystemResourceLists( _SystemResourceLists ); DbgAssert( Success ); return FALSE; } // // Strip off the extension (.Raw or .Translated) from the device name. // Device->Name[ Extension - Device->Name ] = TEXT( '\0' ); // // Set the signature in the DEVICE object. // SetSignature( Device ); // // If the DEVICE object list is empty, add the device to the beginning // of the list else add it to the end of the list. // if( SystemResource->DeviceHead == NULL ) { SystemResource->DeviceHead = Device; SystemResource->DeviceTail = Device; } else { LPDEVICE ExistingDevice; // // See if the DEVICE object is already in the list. // ExistingDevice = SystemResource->DeviceHead; while( ExistingDevice ) { if( _tcsicmp( ExistingDevice->Name, Device->Name ) == 0 ) { break; } ExistingDevice = ExistingDevice->Next; } // // If the DEVICE object is not already in the list, add it else // free the DEICE object. // if( ExistingDevice == NULL ) { SystemResource->DeviceTail->Next = Device; SystemResource->DeviceTail = Device; } else { Success = FreeObject( Device ); DbgAssert( Success ); } } // // NULL terminate the DEVICE object list. // SystemResource->DeviceTail->Next = NULL; // // For each CM_FULL_RESOURCE DESCRIPTOR in the current value... // for( i = 0; i < Count; i++ ) { PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialResourceDescriptor; // // For each CM_PARTIAL_RESOURCE_DESCRIPTOR in the list... // for( j = 0; j < FullResource->PartialResourceList.Count; j++ ) { LPRESOURCE_DESCRIPTOR ResourceDescriptor; LPRESOURCE_DESCRIPTOR* Head; LPRESOURCE_DESCRIPTOR* Tail; // // Allocate a RESOURCE_DESCRIPTOR object. // ResourceDescriptor = AllocateObject( RESOURCE_DESCRIPTOR, 1 ); DbgPointerAssert( ResourceDescriptor ); if( ResourceDescriptor == NULL ) { Success = DestroySystemResourceLists( _SystemResourceLists ); DbgAssert( Success ); return FALSE; } // // Get a pointer to the current CM_PARTIAL_RESOURCE_DESCRIPTOR // in the current CM_FULLRESOURCE_DESCRIPTOR in the list. // PartialResourceDescriptor = &( FullResource[ i ].PartialResourceList.PartialDescriptors[ j ]); // // Based on the resource type grab the pointers to the head and // tail of the appropriate list. // switch( PartialResourceDescriptor->Type ) { case CmResourceTypePort: Head = &SystemResource->PortHead; Tail = &SystemResource->PortTail; break; case CmResourceTypeInterrupt: Head = &SystemResource->InterruptHead; Tail = &SystemResource->InterruptTail; break; case CmResourceTypeMemory: Head = &SystemResource->MemoryHead; Tail = &SystemResource->MemoryTail; break; case CmResourceTypeDma: Head = &SystemResource->DmaHead; Tail = &SystemResource->DmaTail; break; case CmResourceTypeDeviceSpecific: // // Since device specific data is not be collected, free the // associated RESOURCCE_DESCRIPTOR object. // Success = FreeObject( ResourceDescriptor ); DbgAssert( Success ); break; default: DbgPrintf(( L"Winmsd : Unknown PartialResourceDescriptor->Type == %1!d!\n", PartialResourceDescriptor->Type )); continue; } // // If the list is empty add the RESOURCE_DESCRIPTOR object to // the beginning of the list, else add it to the end. // if( *Head == NULL ) { *Head = ResourceDescriptor; *Tail = ResourceDescriptor; } else { ( *Tail )->NextSame = ResourceDescriptor; *Tail = ResourceDescriptor; } // // NULL terminate the list. // ( *Tail )->NextSame = NULL; // // Make a copy of the actual resource descriptor data. // CopyMemory( &ResourceDescriptor->CmResourceDescriptor, PartialResourceDescriptor, sizeof( CM_PARTIAL_RESOURCE_DESCRIPTOR ) ); // // Note the owner (device/driver) of this resource descriptor. // ResourceDescriptor->Owner = SystemResource->DeviceTail; // // The RESOURCE_DESCRIPTOR is complete so set its signature. // SetSignature( ResourceDescriptor ); // // Add the RESOURCE_DESCRIPTOR to the list of resources owned // by the current DEVICE. // if( SystemResource->DeviceTail->ResourceDescriptorHead == NULL ) { SystemResource->DeviceTail->ResourceDescriptorHead = ResourceDescriptor; SystemResource->DeviceTail->ResourceDescriptorTail = ResourceDescriptor; } else { SystemResource->DeviceTail->ResourceDescriptorTail->NextDiff = ResourceDescriptor; SystemResource->DeviceTail->ResourceDescriptorTail = ResourceDescriptor; } // // NULL terminate the list. // SystemResource->DeviceTail->ResourceDescriptorTail->NextDiff = NULL; } // // Get the next CM_FULL_RESOURCE_DESCRIPTOR from the list. // FullResource = ( PCM_FULL_RESOURCE_DESCRIPTOR )( PartialResourceDescriptor + 1 ); } } // // Traverse the list of keys in the resource descriptor portion of the // registry and continue building the lists. // while(( hRegSubkey = QueryNextSubkey( hRegKey )) != NULL ) { Success = InitializeSystemResourceLists( hRegSubkey ); DbgAssert( Success ); if( Success == FALSE ) { Success = DestroySystemResourceLists( _SystemResourceLists ); DbgAssert( Success ); return FALSE; } Success = CloseRegistryKey( hRegSubkey ); DbgAssert( Success ); if( Success == FALSE ) { Success = DestroySystemResourceLists( _SystemResourceLists ); DbgAssert( Success ); return FALSE; } } // // Set the signatures in both of the fully initialized lists. // SetSignature( &_SystemResourceLists[ RAW ]); SetSignature( &_SystemResourceLists[ TRANSLATED ]); return TRUE; }
//+---------------------------------------------------------------------------- // // Function: CallDescrWithObjectArray, private // // Synopsis: Builds the stack from a object array and call the object // // Note this function triggers GC and assumes that pServer, pArguments, pVarRet, and ppVarOutParams are // all already protected!! //+---------------------------------------------------------------------------- void CallDescrWithObjectArray(OBJECTREF& pServer, ReflectMethod *pRM, const BYTE *pTarget, MetaSig* sig, VASigCookie *pCookie, BOOL fIsStatic, PTRARRAYREF& pArgArray, OBJECTREF *pVarRet, PTRARRAYREF *ppVarOutParams) { THROWSCOMPLUSEXCEPTION(); TRIGGERSGC(); // the debugger, profiler code triggers a GC LOG((LF_REMOTING, LL_INFO10, "CallDescrWithObjectArray IN\n")); ByRefInfo *pByRefs = NULL; INT64 retval = 0; UINT nActualStackBytes = 0; LPBYTE pAlloc = 0; LPBYTE pFrameBase = 0; UINT32 numByRef = 0; DWORD attr = pRM->dwFlags; #ifdef _DEBUG MethodDesc *pMD = pRM->pMethod; #endif // check the calling convention BYTE callingconvention = sig->GetCallingConvention(); if (!isCallConv(callingconvention, IMAGE_CEE_CS_CALLCONV_DEFAULT)) { _ASSERTE(!"This calling convention is not supported."); COMPlusThrow(kInvalidProgramException); } #ifdef DEBUGGING_SUPPORTED // debugger goo What does this do? can someone put a comment here? if (CORDebuggerTraceCall()) g_pDebugInterface->TraceCall(pTarget); #endif // DEBUGGING_SUPPORTED #ifdef PROFILING_SUPPORTED // If we're profiling, notify the profiler that we're about to invoke the remoting target if (CORProfilerTrackRemoting()) g_profControlBlock.pProfInterface->RemotingServerInvocationStarted( reinterpret_cast<ThreadID>(GetThread())); #endif // PROFILING_SUPPORTED // Create a fake FramedMethodFrame on the stack. nActualStackBytes = sig->SizeOfActualFixedArgStack(fIsStatic); pAlloc = (LPBYTE)_alloca(FramedMethodFrame::GetNegSpaceSize() + sizeof(FramedMethodFrame) + nActualStackBytes); pFrameBase = pAlloc + FramedMethodFrame::GetNegSpaceSize(); // cycle through the parameters and see if there are byrefs BYTE typ = 0; BOOL fHasByRefs = FALSE; if (attr & RM_ATTR_BYREF_FLAG_SET) fHasByRefs = attr & RM_ATTR_HAS_BYREF_ARG; else { sig->Reset(); while ((typ = sig->NextArg()) != ELEMENT_TYPE_END) { if (typ == ELEMENT_TYPE_BYREF) { fHasByRefs = TRUE; attr |= RM_ATTR_HAS_BYREF_ARG; break; } } attr |= RM_ATTR_BYREF_FLAG_SET; pRM->dwFlags = attr; sig->Reset(); } int nFixedArgs = sig->NumFixedArgs(); // if there are byrefs allocate and array for the out parameters if (fHasByRefs) { *ppVarOutParams = PTRARRAYREF(AllocateObjectArray(sig->NumFixedArgs(), g_pObjectClass)); // Null out the array memset(&(*ppVarOutParams)->m_Array, 0, sizeof(OBJECTREF) * sig->NumFixedArgs()); } ArgIterator argit(pFrameBase, sig, fIsStatic); // set the this pointer OBJECTREF *ppThis = (OBJECTREF*)argit.GetThisAddr(); *ppThis = NULL; // if there is a return buffer, allocate it if (sig->HasRetBuffArg()) { EEClass *pEECValue = sig->GetRetEEClass(); _ASSERTE(pEECValue->IsValueClass()); MethodTable * mt = pEECValue->GetMethodTable(); *pVarRet = AllocateObject(mt); *(argit.GetRetBuffArgAddr()) = (*pVarRet)->UnBox(); #if defined(_PPC_) || defined(_SPARC_) // retbuf // the CallDescrWorker callsite for methods with return buffer is // different for RISC CPUs - we pass this information along by setting // the lowest bit in pTarget pTarget = (const BYTE *)((UINT_PTR)pTarget | 0x1); #endif } // gather data about the parameters by iterating over the sig: UINT32 arg = 0; UINT32 structSize = 0; int ofs = 0; // REVIEW: need to use actual arg count if VarArgs are supported ArgInfo* pArgInfo = (ArgInfo*) _alloca(nFixedArgs*sizeof(ArgInfo)); #ifdef _DEBUG // We expect to write useful data over every part of this so need // not do this in retail! memset((void *)pArgInfo, 0, sizeof(ArgInfo)*nFixedArgs); #endif for( ; 0 != (ofs = argit.GetNextOffset(&typ, &structSize)); arg++, pArgInfo++ ) { if (typ == ELEMENT_TYPE_BYREF) { EEClass *pClass = NULL; CorElementType brType = sig->GetByRefType(&pClass); if (CorIsPrimitiveType(brType)) { pArgInfo->dataSize = gElementTypeInfo[brType].m_cbSize; } else if (pClass->IsValueClass()) { pArgInfo->dataSize = pClass->GetAlignedNumInstanceFieldBytes(); numByRef ++; } else { pArgInfo->dataSize = sizeof(Object *); numByRef ++; } ByRefInfo *brInfo = (ByRefInfo *) _alloca(offsetof(ByRefInfo,data) + pArgInfo->dataSize); brInfo->argIndex = arg; brInfo->typ = brType; brInfo->pClass = pClass; brInfo->pNext = pByRefs; pByRefs = brInfo; pArgInfo->dataLocation = (BYTE*)brInfo->data; *((void**)(pFrameBase + ofs)) = (void*)pArgInfo->dataLocation; pArgInfo->dataClass = pClass; pArgInfo->dataType = brType; pArgInfo->byref = TRUE; } else { pArgInfo->dataLocation = pFrameBase + ofs; pArgInfo->dataSize = StackElemSize(structSize); pArgInfo->dataClass = sig->GetTypeHandle().GetClass(); // this may cause GC! pArgInfo->dataType = typ; pArgInfo->byref = FALSE; } } if (!fIsStatic) { // If this isn't a value class, verify the objectref #ifdef _DEBUG if (pMD->GetClass()->IsValueClass() == FALSE) { VALIDATEOBJECTREF(pServer); } #endif //_DEBUG *ppThis = pServer; } // There should be no GC when we fill up the stack with parameters, as we don't protect them // Assignment of "*ppThis" above triggers the point where we become unprotected. BEGINFORBIDGC(); // reset pArgInfo to point to the start of the block we _alloca-ed pArgInfo = pArgInfo-nFixedArgs; PBYTE dataLocation; INT32 dataSize; EEClass *dataClass; BYTE dataType; OBJECTREF* pArguments = pArgArray->m_Array; UINT32 i, j = arg; for (i=0; i<j; i++) { dataSize = pArgInfo->dataSize; dataLocation = pArgInfo->dataLocation; dataClass = pArgInfo->dataClass; dataType = pArgInfo->dataType; switch (dataSize) { case 1: // This "if" statement is necessary to make the assignement big-endian aware if (pArgInfo->byref) *((INT8*)dataLocation) = *((INT8*)pArguments[i]->GetData()); else *(StackElemType*)dataLocation = (StackElemType)*((INT8*)pArguments[i]->GetData()); break; case 2: // This "if" statement is necessary to make the assignement big-endian aware if (pArgInfo->byref) *((INT16*)dataLocation) = *((INT16*)pArguments[i]->GetData()); else *(StackElemType*)dataLocation = (StackElemType)*((INT16*)pArguments[i]->GetData()); break; case 4: if ((dataType == ELEMENT_TYPE_STRING) || (dataType == ELEMENT_TYPE_OBJECT) || (dataType == ELEMENT_TYPE_CLASS) || (dataType == ELEMENT_TYPE_SZARRAY) || (dataType == ELEMENT_TYPE_ARRAY)) { *(OBJECTREF *)dataLocation = pArguments[i]; } else { *(StackElemType*)dataLocation = (StackElemType)*((INT32*)pArguments[i]->GetData()); } break; case 8: *((INT64*)dataLocation) = *((INT64*)pArguments[i]->GetData()); break; default: { memcpy(dataLocation, pArguments[i]->UnBox(), dataSize); } } pArgInfo++; } #ifdef _DEBUG // Should not be using this any more pArgInfo = pArgInfo - nFixedArgs; memset((void *)pArgInfo, 0, sizeof(ArgInfo)*nFixedArgs); #endif // if there were byrefs, push a protection frame ProtectByRefsFrame *pProtectionFrame = NULL; if (pByRefs && numByRef > 0) { char *pBuffer = (char*)_alloca (sizeof (ProtectByRefsFrame)); pProtectionFrame = new (pBuffer) ProtectByRefsFrame(GetThread(), pByRefs); } // call the correct worker function depending of if the method // is varargs or not ENDFORBIDGC(); #ifdef _PPC_ FramedMethodFrame::Enregister(pFrameBase, sig, fIsStatic, nActualStackBytes); #endif INSTALL_COMPLUS_EXCEPTION_HANDLER(); retval = CallDescrWorker( pFrameBase + sizeof(FramedMethodFrame) + nActualStackBytes, nActualStackBytes / STACK_ELEM_SIZE, #if defined(_X86_) || defined(_PPC_) // argregs (ArgumentRegisters*)(pFrameBase + FramedMethodFrame::GetOffsetOfArgumentRegisters()), #endif (LPVOID)pTarget); UNINSTALL_COMPLUS_EXCEPTION_HANDLER(); // set floating point return values getFPReturn(sig->GetFPReturnSize(), &retval); // need to build a object based on the return type. if (!sig->HasRetBuffArg()) { BYTE *pRetVal = (BYTE*)&retval; #ifdef BIGENDIAN switch (sig->GetReturnTypeSize()) { case 1: pRetVal += sizeof(void*)-1; break; case 2: pRetVal += sizeof(void*)-2; break; default: // nothing to do break; } #endif GetObjectFromStack(pVarRet, pRetVal, sig->GetReturnType(), sig->GetRetEEClass()); } // extract the out args from the byrefs if (pByRefs) { do { // Always extract the data ptr every time we enter this loop because // calls to GetObjectFromStack below can cause a GC. // Even this is not enough, because that we are passing a pointer to GC heap // to GetObjectFromStack . If GC happens, nobody is protecting the passed in pointer. OBJECTREF pTmp = NULL; GetObjectFromStack(&pTmp, pByRefs->data, pByRefs->typ, pByRefs->pClass); (*ppVarOutParams)->SetAt(pByRefs->argIndex, pTmp); pByRefs = pByRefs->pNext; } while (pByRefs); if (pProtectionFrame) pProtectionFrame->Pop(); } #ifdef PROFILING_SUPPORTED // If we're profiling, notify the profiler that we're about to invoke the remoting target if (CORProfilerTrackRemoting()) g_profControlBlock.pProfInterface->RemotingServerInvocationReturned( reinterpret_cast<ThreadID>(GetThread())); #endif // PROFILING_SUPPORTED LOG((LF_REMOTING, LL_INFO10, "CallDescrWithObjectArray OUT\n")); }
BOOL ClbSetColumnWidths( IN HWND hWnd, IN int ControlId, IN LPDWORD Widths ) /*++ Routine Description: ClbSetColumnWidths sets the width of each column based on the supplied widths in characters. Note that the column on the far right extends to the edge of the Clb. Arguments: hWnd - Supplies the window handle for the parent window. ControlId - Supplies the control id for this Clb for the supplied hWnd. Widths - Supplies an array of widths, one less then the number of columns, in characters. Return Value: BOOL - Returns TRUE if the widths were successfully adjusted. --*/ { BOOL Success; DWORD Columns; LPCLB_INFO ClbInfo; HWND hWndClb; LONG CharWidth; LONG CharHeight; DWORD i; LPLONG WidthsInPixels; LONG TotalPixels; HDC hDCClientHeader; HD_ITEM hdi; UINT iRight; // // Validate arguments. // DbgHandleAssert( hWnd ); DbgPointerAssert( Widths ); // // Retrieve information for this ColumnListBox. // hWndClb = GetDlgItem( hWnd, ControlId ); DbgHandleAssert( hWndClb ); ClbInfo = RestoreClbInfo( hWndClb ); DbgPointerAssert( ClbInfo ); DbgAssert( CheckSignature( ClbInfo )); // // Get thd HDC for the header. // hDCClientHeader = GetDC( ClbInfo->hWndHeader ); DbgHandleAssert( hDCClientHeader ); // // Get the width of a character. // Success = GetCharMetrics( hDCClientHeader, &CharWidth, &CharHeight ); DbgAssert( Success ); // // Release the DC for the header. // Success = ReleaseDC( ClbInfo->hWndHeader, hDCClientHeader ); DbgAssert( Success ); // // Allocate an array of pixel widths, one for each column. // WidthsInPixels = AllocateObject( LONG, ClbInfo->Columns ); DbgPointerAssert( WidthsInPixels ); // // Compute the width of each column (not including the rightmost) in pixels, // and the total number of pixels used by these columns. // TotalPixels = 0; for( i = 0; i < ClbInfo->Columns - 1; i++ ) { WidthsInPixels[ i ] = Widths[ i ] * CharWidth; TotalPixels += WidthsInPixels[ i ]; } // // The caller did not specify the width of the rightmost column. // if( Widths[ i ] == -1 ) { RECT Rect; // // Set the width of the rightmost column to the remainder of the width // of the header window. // Success = GetClientRect( ClbInfo->hWndHeader, &Rect ); DbgAssert( Success ); WidthsInPixels[ i ] = ( Rect.right - Rect.left ) - TotalPixels; } else { // // Set the width of the rightmost column to the value supplied // by the caller. // WidthsInPixels[ i ] = Widths[ i ] * CharWidth; } // // Tell the header window the width of each column. // hdi.mask = HDI_WIDTH; for( i = 0; i < ClbInfo->Columns - 1; i++ ) { hdi.cxy = WidthsInPixels[i]; Success = Header_SetItem(ClbInfo->hWndHeader, i, &hdi); DbgAssert( Success ); } // // Calc the array of right edges. // iRight = 0; for( i = 0; i < ClbInfo->Columns - 1; i++ ) { iRight += WidthsInPixels[i]; ClbInfo->Right[i] = iRight; } // // Free the array of pixel widths. // Success = FreeObject( WidthsInPixels ); DbgAssert( Success ); return TRUE; }
BOOL AdjustClbHeadings( IN HWND hWnd, IN LPCLB_INFO ClbInfo, IN LPCWSTR Headings OPTIONAL ) /*++ Routine Description: AdjustClbHeadings adjust the number of columns, the widths an header text bbased on the optional Headings parameter. If Headings is NULL then the column widths are adjusted based on the old headings and the current size of the Clb. If Headings are supplied then they consist of ';' separated strings, each of which is a column heading. The number of columns and their widths is then computed based on these new headings. Arguments: hWnd - Supplies a window handle for this Clb. ClbInfo - Supplies a pointer the CLB_INFO structure for this Clb. Headings - Supplies an optional pointer to a ';' separated series of column header strings. Return Value: BOOL - Returns TRUE if the adjustment was succesfully made. --*/ { BOOL Success; DWORD Columns; DWORD ColumnWidth; DWORD i; TCHAR Buffer[ MAX_PATH ]; LPCWSTR Heading; RECT ClientRectHeader; HD_ITEM hdi; UINT iCount, j, iRight; DbgPointerAssert( ClbInfo ); DbgAssert( ! (( ClbInfo->Columns == 0 ) && ( Headings == NULL ))); // // If the user supplied headings, compute the new number of columns. // if( ARGUMENT_PRESENT( Headings )) { // // Initialize the column counter. // Columns = 0; // // Make a copy of the new headings in the Clb object. // lstrcpy( ClbInfo->Headings, Headings ); // // Make a copy of the heading string so that it can be tokenized. // i.e. wcstok destroys the string. // lstrcpy( Buffer, Headings ); // // Grab the first token (heading). // Heading = _tcstok( Buffer, HEADING_SEPARATOR ); // // For each heading... // while( Heading != NULL ) { // // Increment the number of columns. // Columns++; // // Get the next heading. // Heading = _tcstok( NULL, HEADING_SEPARATOR ); } } else { // // Same number of Columns as before. // Columns = ClbInfo->Columns; } // // If the number of columns in the Clb is zero (i.e. this is the first // time it is being initialized) allocate the right edge array. Otherwise // reallocate the existing array if the number of columns has changed. // if( ClbInfo->Columns == 0 ) { ClbInfo->Right = AllocateObject( LONG, Columns ); DbgPointerAssert( ClbInfo->Right ); } else if( Columns != ClbInfo->Columns ) { ClbInfo->Right = ReallocateObject( LONG, ClbInfo->Right, Columns ); DbgPointerAssert( ClbInfo->Right ); } // // Update the number of columns in the Clb (note this may be the same // number as before). // ClbInfo->Columns = Columns; // // Compute the default column width by dividing the available space by the // number of columns. // Success = GetClientRect( ClbInfo->hWndHeader, &ClientRectHeader ); DbgAssert( Success ); ColumnWidth = ( ClientRectHeader.right - ClientRectHeader.left ) / ClbInfo->Columns; // // Initialize the array of right edges to the width of each column. // for( i = 0; i < ClbInfo->Columns; i++ ) { ClbInfo->Right[ i ] = ColumnWidth; } // // Update the existing header items // iCount = Header_GetItemCount(ClbInfo->hWndHeader); j = 0; hdi.mask = HDI_WIDTH; while ((j < iCount) && (j < Columns)) { hdi.cxy = ClbInfo->Right[j]; Header_SetItem (ClbInfo->hWndHeader, j, &hdi); j++; } // // Add new header items if necessary. // hdi.mask = HDI_WIDTH; for (; j < Columns; j++) { hdi.cxy = ClbInfo->Right[j]; Header_InsertItem (ClbInfo->hWndHeader, j, &hdi); } // // Query the header for the array of right edges. // iRight = 0; for( i = 0; i < ClbInfo->Columns - 1; i++ ) { iRight += ClbInfo->Right[i]; ClbInfo->Right[i] = iRight; } ClbInfo->Right[i] = ClientRectHeader.right; // // Copy and parse the headings so that each column's heading // can be set. These can be new or old headings. // lstrcpy( Buffer, ClbInfo->Headings ); Heading = _tcstok( Buffer, HEADING_SEPARATOR ); hdi.mask = HDI_TEXT | HDI_FORMAT; hdi.fmt = HDF_STRING; for( i = 0; i < ClbInfo->Columns; i++ ) { hdi.pszText = (LPTSTR)Heading; Header_SetItem (ClbInfo->hWndHeader, i, &hdi); Heading = _tcstok( NULL, HEADING_SEPARATOR ); } return TRUE; }
BOOL ClbAddData( IN HWND hWnd, IN int ControlId, IN LPCLB_ROW ClbRow ) /*++ Routine Description: ClbAddData adds a new row of data to the Clb control's List Box. Arguments: hWnd - Supplies the window handle for the parent window. ControlId - Supplies the control id for this Clb for the supplied hWnd. ClbRow - Supplies a pointer to a CLB_ROW object which contains user define per row data along with an array of CLB_STRINGs. Return Value: BOOL - Returns TRUE if the data was successfully added. --*/ { LPCLB_INFO ClbInfo; LRESULT LbErr; DWORD i; HWND hWndClb; LPCLB_ROW TempRow; // // Validate arguments. // DbgHandleAssert( hWnd ); DbgPointerAssert( ClbRow ); // // Retrieve information for this ColumnListBox. // hWndClb = GetDlgItem( hWnd, ControlId ); DbgHandleAssert( hWndClb ); ClbInfo = RestoreClbInfo( hWndClb ); DbgPointerAssert( ClbInfo ); DbgAssert( CheckSignature( ClbInfo )); // // Validate the count of strings. // DbgAssert( ClbRow->Count == ClbInfo->Columns ); // // Capture the CLB_ROW object. // TempRow = AllocateObject( CLB_ROW, 1 ); DbgPointerAssert( TempRow ); CopyMemory( TempRow, ClbRow, sizeof( CLB_ROW) ); // // Capture the strings. // TempRow->Strings = AllocateObject( CLB_STRING, ClbInfo->Columns ); DbgPointerAssert( TempRow->Strings ); for( i = 0; i < ClbInfo->Columns; i++ ) { // // Copy the header. // CopyMemory( &TempRow->Strings[ i ], &ClbRow->Strings[ i ], sizeof( CLB_STRING ) ); // // Copy the string. // TempRow->Strings[ i ].String = _wcsdup( ClbRow->Strings[ i ].String ); } // // Store the CLB_ROW object in the listbox. // LbErr = SendMessage( ClbInfo->hWndListBox, LB_ADDSTRING, 0, ( LPARAM ) TempRow ); DbgAssert(( LbErr != LB_ERR ) && ( LbErr != LB_ERRSPACE )); return TRUE; }
LRESULT ClbWndProc( IN HWND hWnd, IN UINT message, IN WPARAM wParam, IN LPARAM lParam ) /*++ Routine Description: This function is the window procedure for the Clb custom control. Arguments: Standard window procedure parameters. Return Value: LRESULT - dependent on the supplied message. --*/ { BOOL Success; LPCLB_INFO ClbInfo; if( message == WM_NCCREATE ) { LONG Long; // // Save the original styles. // Long = SetWindowLong( hWnd, GWL_USERDATA, (( LPCREATESTRUCT ) lParam )->style ); DbgAssert( Long == 0 ); // // Get rid of any styles that are uninteresting to the Clb. // SetWindowLong( hWnd, GWL_STYLE, (( LPCREATESTRUCT ) lParam )->style & CLBS_CLB ); return TRUE; } if( message == WM_CREATE ) { // // Assert that there is no prior per window information associated // with this Clb. // DbgAssert( RestoreClbInfo( hWnd ) == NULL ); // // Restore the original styles. // (( LPCREATESTRUCT ) lParam )->style = GetWindowLong( hWnd, GWL_USERDATA ); // // Allocate a CLB_INFO object for this Clb and initialize the Clb // relevant fields. // ClbInfo = AllocateObject( CLB_INFO, 1 ); DbgPointerAssert( ClbInfo ); // // Set the number of columns to zero so that remainder of creation // understands the state of the Clb. // ClbInfo->Columns = 0; // // Create the header portion of the Clb. // Success = CreateHeader( hWnd, ClbInfo, ( LPCREATESTRUCT ) lParam ); DbgAssert( Success ); // // Create the list box portion of the Clb. // Success = CreateListBox( hWnd, ClbInfo, ( LPCREATESTRUCT ) lParam ); DbgAssert( Success ); // // Adjust the column number, widths based on the heading text. // Success = AdjustClbHeadings( hWnd, ClbInfo, (( LPCREATESTRUCT ) lParam )->lpszName ); DbgAssert( Success ); // // Everything was succesfully created so set the Clb's signature // and save it away as part of the per window data. // SetSignature( ClbInfo ); SaveClbInfo( ClbInfo ); return 0; } // // Get the ClbInfo object for this Clb and make sure that its already // been created i.e. WM_CREATE was already executed and thereby initialized // and saved a ClbInfo object. // ClbInfo = RestoreClbInfo( hWnd ); if( ClbInfo != NULL ) { // // Validate that this really is a ClbInfo object. // DbgAssert( CheckSignature( ClbInfo )); switch( message ) { case WM_DESTROY: { // // Delete the font used in the list box. // Success = DeleteObject( ClbInfo->hFontListBox ); DbgAssert( Success ); // // Delete the array of right habd edges. // Success = FreeObject( ClbInfo->Right ); DbgAssert( Success ); // // Delete the CLB_INFO object for this window. // Success = FreeObject( ClbInfo ); DbgAssert( Success ); SaveClbInfo ( ClbInfo ); return 0; } case WM_PAINT: { PAINTSTRUCT ps; RECT Rect; POINT Points[ 2 ]; HDC hDC; HPEN hPen; hDC = BeginPaint( hWnd, &ps ); DbgAssert( hDC == ps.hdc ); Success = GetClientRect( hWnd, &Rect ); DbgAssert( Success ); Points[ 0 ].x = 0; Points[ 0 ].y = ClbInfo->HeaderHeight + 1; Points[ 1 ].x = Rect.right - Rect.left; Points[ 1 ].y = ClbInfo->HeaderHeight + 1; hPen = GetStockObject( BLACK_PEN ); DbgHandleAssert( hPen ); hPen = SelectObject( hDC, hPen ); Success = Polyline( hDC, Points, NumberOfEntries( Points )); DbgAssert( Success ); hPen = SelectObject( hDC, hPen ); Success = DeleteObject( hPen ); DbgAssert( Success ); Success = EndPaint( hWnd, &ps ); DbgAssert( Success ); return 0; } case WM_COMMAND: switch( LOWORD( wParam )) { case ID_LISTBOX: switch( HIWORD( wParam )) { case LBN_DBLCLK: case LBN_KILLFOCUS: case LBN_SELCHANGE: { // // These messages come to ClbWndProc because it is the parent // of the list box, but they are really intended for the parent // of the Clb. // HWND hWndParent; // // Forward the message to the Clb's parent if it has a parent. // hWndParent = GetParent( hWnd ); DbgHandleAssert( hWndParent ); if( hWndParent != NULL ) { // // Replace the control id and handle with the Clb's. // LOWORD( wParam ) = GetDlgCtrlID( hWnd ); DbgAssert( LOWORD( wParam ) != 0 ); lParam = ( LPARAM ) hWnd; // // Forward the message... // return SendMessage( hWndParent, message, wParam, lParam ); } } } break; } break; // // Forward to listbox. // case LB_GETCURSEL: case LB_SETCURSEL: case LB_FINDSTRING: case LB_GETITEMDATA: case LB_RESETCONTENT: case WM_CHAR: case WM_GETDLGCODE: case WM_KILLFOCUS: return SendMessage( ClbInfo->hWndListBox, message, wParam, lParam ); case WM_SETFOCUS: { SetFocus( ClbInfo->hWndListBox ); return 0; } case WM_COMPAREITEM: { // // This message comes to ClbWndProc because it is the parent // of the list box, but is really intended for the parent // of the Clb. // HWND hWndParent; // // Forward the message to the Clb's parent if it has a parent. // hWndParent = GetParent( hWnd ); DbgHandleAssert( hWndParent ); if( hWndParent != NULL ) { int ControlId; LPCOMPAREITEMSTRUCT lpcis; lpcis = ( LPCOMPAREITEMSTRUCT ) lParam; ControlId = GetDlgCtrlID( hWnd ); DbgAssert( ControlId != 0 ); // // Modify the COMPAREITEMSTRUCT so that it refers to the Clb. // lpcis->CtlID = ControlId; lpcis->hwndItem = hWnd; // // Forward the message... // return SendMessage( hWndParent, message, ( WPARAM ) ControlId, lParam ); } break; } case WM_DELETEITEM: { LPDELETEITEMSTRUCT lpditms; LPCLB_ROW ClbRow; DWORD i; DbgAssert( wParam == ID_LISTBOX ); // // Retrieve the pointer to the DELETEITEMSTRUCT. // lpditms = ( LPDELETEITEMSTRUCT ) lParam; DbgAssert(( lpditms->CtlType == ODT_LISTBOX ) &&( lpditms->CtlID == ID_LISTBOX )); // // If there is no data, just return. // if( lpditms->itemData == 0 ) { return TRUE; } // // Retrieve the CLB_ROW object for this row. // ClbRow = ( LPCLB_ROW ) lpditms->itemData; // // For each column delete the string. // for( i = 0; i < ClbInfo->Columns; i++ ) { // // Strings were copied with _tcsdup so they must be // freed with free( ). // free( ClbRow->Strings[ i ].String ); } // // Free the CLB_STRING object. // Success = FreeObject( ClbRow->Strings ); DbgAssert( Success ); // // Free the CLB_ROW object. // Success = FreeObject( ClbRow ); DbgAssert( Success ); return TRUE; } case WM_DRAWITEM: { LPDRAWITEMSTRUCT lpdis; BOOL DrawFocus; DbgAssert( wParam == ID_LISTBOX ); // // Retrieve the pointer to the DRAWITEMSTRUCT. // lpdis = ( LPDRAWITEMSTRUCT ) lParam; DbgAssert(( lpdis->CtlType == ODT_LISTBOX ) &&( lpdis->CtlID == ID_LISTBOX )); // // If there is no data, just return. // if( lpdis->itemData == 0 ) { return TRUE; } if( lpdis->itemAction & ( ODA_DRAWENTIRE | ODA_SELECT )) { DWORD i; LPCLB_ROW ClbRow; COLORREF TextColor; COLORREF BkColor; // // Retrieve the CLB_ROW object for this row. // ClbRow = ( LPCLB_ROW ) lpdis->itemData; // // If the item is selected, set the selection colors. // if( lpdis->itemState & ODS_SELECTED ) { BkColor = COLOR_HIGHLIGHT; TextColor = COLOR_HIGHLIGHTTEXT; } else { BkColor = COLOR_WINDOW; TextColor = COLOR_WINDOWTEXT; } BkColor = GetSysColor( BkColor ); TextColor = GetSysColor( TextColor ); BkColor = SetBkColor( lpdis->hDC, BkColor ); DbgAssert( BkColor != CLR_INVALID ); TextColor = SetTextColor( lpdis->hDC, TextColor ); DbgAssert( TextColor != CLR_INVALID ); // // For each column display the text. // for( i = 0; i < ClbInfo->Columns; i++ ) { RECT ClipOpaqueRect; int x; int Left; UINT GdiErr; // // Depending on the format, adjust the alignment reference // point (x) and the clipping rectangles left edge so that // there are five pixels between each column. // switch( ClbRow->Strings[ i ].Format ) { case CLB_LEFT: if( i == 0 ) { x = 2; } else { x = ClbInfo->Right[ i - 1 ] + 2; } Left = x - 2; break; case CLB_RIGHT: if( i == 0 ) { Left = 0; } else { Left = ClbInfo->Right[ i - 1 ]; } x = ClbInfo->Right[ i ] - 3; break; default: DbgAssert( FALSE ); } // // Set the format for this column. // GdiErr = SetTextAlign( lpdis->hDC, ClbRow->Strings[ i ].Format | TA_TOP ); DbgAssert( GdiErr != GDI_ERROR ); // // Clip each string to its column width less two pixels // (for asthetics). // Success = SetRect( &ClipOpaqueRect, Left, lpdis->rcItem.top, ClbInfo->Right[ i ], lpdis->rcItem.bottom ); DbgAssert( Success ); Success = ExtTextOut( lpdis->hDC, x, lpdis->rcItem.top, ETO_CLIPPED | ETO_OPAQUE, &ClipOpaqueRect, ClbRow->Strings[ i ].String, ClbRow->Strings[ i ].Length, NULL ); DbgAssert( Success ); // // If the item has the focus, draw the focus rectangle. // DrawFocus = lpdis->itemState & ODS_FOCUS; } } else { // // If the Clb has the focus, display a focus rectangle // around the selected item. // DrawFocus = lpdis->itemAction & ODA_FOCUS; } // // If needed, toggle the focus rectangle. // if( DrawFocus ) { Success = DrawFocusRect( lpdis->hDC, &lpdis->rcItem ); DbgAssert( Success ); } return TRUE; } case WM_NOTIFY: { HD_NOTIFY * lpNot; HD_ITEM *pHDI; lpNot = (HD_NOTIFY *)lParam; pHDI = lpNot->pitem; switch( lpNot->hdr.code) { static DRAW_ERASE_LINE DrawEraseLine; static HPEN hPen; static HDC hDCClientListBox; HD_ITEM hdi; UINT iRight; UINT i; RECT ClientRectHeader; case HDN_BEGINTRACK: { RECT ClientRectListBox; // // Get thd HDC for the list box. // hDCClientListBox = GetDC( ClbInfo->hWndListBox ); DbgHandleAssert( hDCClientListBox ); // // Create the pen used to display the drag position and // select it into the in list box client area DC. Also set // the ROP2 code so that drawing with the pen twice in the // same place will erase it. This is what allows the // line to drag. // hPen = CreatePen( PS_DOT, 1, RGB( 255, 255, 255 )); DbgHandleAssert( hPen ); hPen = SelectObject( hDCClientListBox, hPen ); SetROP2( hDCClientListBox, R2_XORPEN ); // // Set up the DRAW_ERASE_LINE structure so that the drag line is // drawn from the top to the bottom of the list box at the // current drag position. // Success = GetClientRect( ClbInfo->hWndListBox, &ClientRectListBox ); DbgAssert( Success ); // // Draw the initial drag line from the top to the bottom // of the list box equivalent with the header edge grabbed // by the user. // DrawEraseLine.Draw.Src.x = ClbInfo->Right[ pHDI->cxy ]; DrawEraseLine.Draw.Src.y = 0; DrawEraseLine.Draw.Dst.x = ClbInfo->Right[ pHDI->cxy ]; DrawEraseLine.Draw.Dst.y = ClientRectListBox.bottom - ClientRectListBox.top; Success = DrawLine( hDCClientListBox, &DrawEraseLine ); DbgAssert( Success ); return 0; } case HDN_TRACK: { //DWORD Columns; // // Get new drag position. // iRight = 0; hdi.mask = HDI_WIDTH; for( i = 0; i < ClbInfo->Columns - 1; i++ ) { if (i != (UINT)lpNot->iItem) { Header_GetItem(ClbInfo->hWndHeader, i, &hdi); } else { hdi.cxy = pHDI->cxy; } iRight += hdi.cxy; ClbInfo->Right[i] = iRight; } GetClientRect( ClbInfo->hWndHeader, &ClientRectHeader ); ClbInfo->Right[i] = ClientRectHeader.right; // // Erase the old line and draw the new one at the new // drag position. // Success = RedrawVerticalLine( hDCClientListBox, ClbInfo->Right[lpNot->iItem], &DrawEraseLine ); DbgAssert( Success ); return 0; } case HDN_ENDTRACK: // // Replace the old pen and delete the one created // during HBN_BEGINDRAG. // hPen = SelectObject( hDCClientListBox, hPen ); Success = DeleteObject( hPen ); DbgAssert( Success ); // // Release the DC for the list box. // Success = ReleaseDC( ClbInfo->hWndListBox, hDCClientListBox ); DbgAssert( Success ); Success = RedrawWindow( hWnd, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN ); DbgAssert( Success ); return 0; } break; } case WM_SETTEXT: // // Adjust the column number and widths based on the heading text. // Success = AdjustClbHeadings( hWnd, ClbInfo, ( LPCWSTR ) lParam ); DbgAssert( Success ); return Success; case WM_SIZE: { HDWP hDWP; LONG Width; LONG Height; LONG Style; LONG VScrollWidth; Width = LOWORD( lParam ); Height = HIWORD( lParam ); hDWP = BeginDeferWindowPos( 2 ); DbgHandleAssert( hDWP ); // // Retrieve the list box's styles. // Style = GetWindowLong( ClbInfo->hWndListBox, GWL_STYLE ); // // If the list box has a vertical scroll bar compute its // width so that the header window's width can be adjusted // appropriately. // VScrollWidth = ( Style & WS_VSCROLL ) ? GetSystemMetrics( SM_CXVSCROLL ) + ( GetSystemMetrics( SM_CXBORDER ) * 2 ) : 0; // // Size the header window to the width of the Clb and its // default / original height. // hDWP = DeferWindowPos( hDWP, ClbInfo->hWndHeader, NULL, 0, 0, Width - VScrollWidth, ClbInfo->HeaderHeight, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER ); DbgHandleAssert( hDWP ); // // If the list box has a vertical scroll bar, bump the width // and height by two so that its border overwrites the Clb // border. This eliminates a double border (and a gap) between // the right and bottom edges of the scroll bar and the Clb. // if( Style & WS_VSCROLL ) { Height += 2; Width += 2; } // // Size the list box so that it is the size of the Clb less // the height of the header window less the height of the // border. // hDWP = DeferWindowPos( hDWP, ClbInfo->hWndListBox, NULL, 0, 0, Width, Height - ClbInfo->HeaderHeight - 3, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER ); DbgHandleAssert( hDWP ); Success = EndDeferWindowPos( hDWP ); DbgAssert( Success ); break; } } } return DefWindowProc( hWnd, message, wParam, lParam ); }
HRESULT STDMETHODCALLTYPE ICorDBPrivHelperImpl::CreateManagedObject( /*in*/ WCHAR *wszAssemblyName, /*in*/ WCHAR *wszModuleName, /*in*/ mdTypeDef classToken, /*in*/ void *rawData, /*out*/ IUnknown **ppUnk) { _ASSERTE(TypeFromToken((mdTypeDef)classToken) == mdtTypeDef); _ASSERTE(wszAssemblyName && wszModuleName && ppUnk); if (!wszAssemblyName || !wszModuleName || classToken == mdTokenNil) return E_INVALIDARG; if (!ppUnk) return E_POINTER; HRESULT hr = S_OK; BEGINCANNOTTHROWCOMPLUSEXCEPTION(); // This will set up a managed thread object if one does not already exist // for this particular thread. Thread* pThread = SetupThread(); if (pThread == NULL) { hr = E_OUTOFMEMORY; goto Exit; } // Start up COM Interop if (FAILED(hr = QuickCOMStartup())) goto Exit; { // Don't want to be interrupted... BOOL fWasGCEnabled = !pThread->PreemptiveGCDisabled(); if (fWasGCEnabled) pThread->DisablePreemptiveGC(); Assembly *pAssembly; Module *pModule; if (GetAppDomain() == NULL) hr = E_INVALIDARG; else { // Try and load the assembly, given the name provided. OBJECTREF pThrowable = NULL; GCPROTECT_BEGIN(pThrowable); hr = AssemblySpec::LoadAssembly(wszAssemblyName, &pAssembly, &pThrowable); GCPROTECT_END(); if (SUCCEEDED(hr)) { _ASSERTE(pAssembly); // Try and load the module, given the name provided. hr = pAssembly->GetModuleFromFilename(wszModuleName, &pModule); if (SUCCEEDED(hr)) { _ASSERTE(pModule); // If the class isn't known,then don't try and create it. if (!pModule->GetMDImport()->IsValidToken(classToken)) hr = E_INVALIDARG; else { COMPLUS_TRY { OBJECTREF obj = NULL; GCPROTECT_BEGIN(obj); // Now try and get the TypeHandle for the given token NameHandle nameHandle(pModule, classToken); TypeHandle typeHandle = pAssembly->LoadTypeHandle(&nameHandle, &obj); // If an exception was thrown at some point, convert // it to an HRESULT if (obj != NULL) hr = SecurityHelper::MapToHR(obj); // No longer need the object, can be GC'd if desired obj = NULL; if (SUCCEEDED(hr)) { _ASSERTE(typeHandle.AsMethodTable()); MethodTable *pMT = typeHandle.AsMethodTable(); if (!pMT->GetClass()->IsValueClass() || pMT->ContainsPointers()) hr = CORDBG_E_OBJECT_IS_NOT_COPYABLE_VALUE_CLASS; if (SUCCEEDED(hr)) { // Now run the class initialiser if (!pMT->CheckRunClassInit(&obj)) hr = SecurityHelper::MapToHR(obj); // No longer need the object, can be GC'd if // desired obj = NULL; if (SUCCEEDED(hr)) { // If successful, allocate an instance of // the class // This may throw an // OutOfMemoryException, but the below // COMPLUS_CATCH should handle it. If // the class is a ValueClass, the // created object will be a boxed // ValueClass. obj = AllocateObject(pMT); // Now create a COM wrapper around // this object. Note that this can // also throw. *ppUnk = GetComIPFromObjectRef(&obj); _ASSERTE(ppUnk); // This is the nasty part. We're gonna // copy the raw data we're given over // the new instance of the value // class... CopyValueClass(obj->UnBox(), rawData, pMT, obj->GetAppDomain()); // No longer need the object, can be GC'd // if desired obj = NULL; } } } GCPROTECT_END(); // obj } COMPLUS_CATCH { // If there's an exception, convert it to an HR hr = SecurityHelper::MapToHR(GETTHROWABLE()); } COMPLUS_END_CATCH } } } } if (fWasGCEnabled) pThread->EnablePreemptiveGC(); } Exit: ENDCANNOTTHROWCOMPLUSEXCEPTION(); return (hr); }
static Object* InitializeAppDomain() { Object* appDomain = AllocateObject(&System_AppDomain_rtti); return appDomain; }
int __cdecl main(int argc, char* argv[]) { // // Initialize system info // if (!GCToOSInterface::Initialize()) { return -1; } // // 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(); // // 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* uint32_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); if (pBefore != pAfter) { printf("%8i) pBefore = 0x%08x, pAfter = 0x%08x, diff = 0x%08x (%i)\n", i, pBefore, pAfter, pBefore - pAfter, pBefore - pAfter); PrintGCStats(pGCHeap); } // 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); // Verify that the weak handle has not yet been cleared (i.e. before the GC has run) assert(ObjectFromHandle(ohWeak) != NULL); printf("\nBEFORE Final Call to pGCHeap->GarbageCollect()"); PrintGCStats(pGCHeap); // Explicitly trigger full GC pGCHeap->GarbageCollect(); printf("\nAFTER Final Call to pGCHeap->GarbageCollect()"); PrintGCStats(pGCHeap); // Verify that the weak handle got cleared by the GC assert(ObjectFromHandle(ohWeak) == NULL); printf("Done\n"); return 0; }