2 // Copyright (c) Microsoft. All rights reserved.
3 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
5 //*****************************************************************************
10 //*****************************************************************************
14 #ifdef FEATURE_DBG_PUBLISH
21 #ifndef SM_REMOTESESSION
22 #define SM_REMOTESESSION 0x1000
26 #include "../../dlls/mscorrc/resource.h"
29 // Publish shares header files with the rest of ICorDebug.
30 // ICorDebug should not call ReadProcessMemory & other APIs directly, it should instead go through
31 // the Data-target. ICD headers #define these APIs to help enforce this.
32 // Since Publish is separate and doesn't use data-targets, it can access the APIs directly.
33 // see code:RSDebuggingInfo#UseDataTarget
34 #undef ReadProcessMemory
36 //****************************************************************************
37 //************ App Domain Publishing Service API Implementation **************
38 //****************************************************************************
40 // This function enumerates all the process in the system and returns
42 BOOL GetAllProcessesInSystem(DWORD *ProcessId,
46 HandleHolder hSnapshotHolder;
48 #if !defined(FEATURE_CORESYSTEM)
49 // Load the dll "kernel32.dll".
50 HModuleHolder hDll = WszLoadLibrary(W("kernel32"));
51 _ASSERTE(hDll != NULL);
55 LOG((LF_CORDB, LL_INFO1000,
56 "Unable to load the dll for enumerating processes. "
57 "LoadLibrary (kernel32.dll) failed.\n"));
61 // Load the dll "api-ms-win-obsolete-kernel32-l1-1-0.dll".
62 HModuleHolder hDll = WszLoadLibrary(W("api-ms-win-obsolete-kernel32-l1-1-0.dll"));
63 _ASSERTE(hDll != NULL);
67 LOG((LF_CORDB, LL_INFO1000,
68 "Unable to load the dll for enumerating processes. "
69 "LoadLibrary (api-ms-win-obsolete-kernel32-l1-1-0.dll) failed.\n"));
75 // Create the Process' Snapshot
76 // Get the pointer to the requested function
77 FARPROC pProcAddr = GetProcAddress(hDll, "CreateToolhelp32Snapshot");
79 // If the proc address was not found, return error
80 if (pProcAddr == NULL)
82 LOG((LF_CORDB, LL_INFO1000,
83 "Unable to enumerate processes in the system. "
84 "GetProcAddr (CreateToolhelp32Snapshot) failed.\n"));
90 // Handle from CreateToolHelp32Snapshot must be freed via CloseHandle().
91 typedef HANDLE CREATETOOLHELP32SNAPSHOT(DWORD, DWORD);
94 ((CREATETOOLHELP32SNAPSHOT *)pProcAddr)(TH32CS_SNAPPROCESS, NULL);
96 if (hSnapshot == INVALID_HANDLE_VALUE)
98 LOG((LF_CORDB, LL_INFO1000,
99 "Unable to create snapshot of processes in the system. "
100 "CreateToolhelp32Snapshot() failed.\n"));
103 // HandleHolder doesn't deal with INVALID_HANDLE_VALUE, so we only assign if we have a legal value.
104 hSnapshotHolder.Assign(hSnapshot);
106 // Get the first process in the process list
107 // Get the pointer to the requested function
108 pProcAddr = GetProcAddress(hDll, "Process32First");
110 // If the proc address was not found, return error
111 if (pProcAddr == NULL)
113 LOG((LF_CORDB, LL_INFO1000,
114 "Unable to enumerate processes in the system. "
115 "GetProcAddr (Process32First) failed.\n"));
121 // need to initialize the dwSize field before calling Process32First
122 PE32.dwSize = sizeof (PROCESSENTRY32);
124 typedef BOOL PROCESS32FIRST(HANDLE, LPPROCESSENTRY32);
127 ((PROCESS32FIRST *)pProcAddr)(hSnapshot, &PE32);
131 LOG((LF_CORDB, LL_INFO1000,
132 "Unable to create snapshot of processes in the system. "
133 "Process32First() returned FALSE.\n"));
138 // Loop over and get all the remaining processes
139 // Get the pointer to the requested function
140 pProcAddr = GetProcAddress(hDll, "Process32Next");
142 // If the proc address was not found, return error
143 if (pProcAddr == NULL)
145 LOG((LF_CORDB, LL_INFO1000,
146 "Unable to enumerate processes in the system. "
147 "GetProcAddr (Process32Next) failed.\n"));
151 typedef BOOL PROCESS32NEXT(HANDLE, LPPROCESSENTRY32);
157 ProcessId [iIndex++] = PE32.th32ProcessID;
159 succ = ((PROCESS32NEXT *)pProcAddr)(hSnapshot, &PE32);
161 } while ((succ == TRUE) && (iIndex < (int)dwArraySize));
163 // I would like to know if we're running more than 512 processes on Win95!!
164 _ASSERTE (iIndex < (int)dwArraySize);
166 *pdwNumEntries = iIndex;
168 // If we made it this far, we succeeded
173 // We never want to wait infinite on an object that we can't verify.
174 // Wait with a timeout.
175 const DWORD SAFETY_TIMEOUT = 2000;
177 // ******************************************
179 // ******************************************
181 CorpubPublish::CorpubPublish()
182 : CordbCommonBase(0),
183 m_fpGetModuleFileNameEx(NULL)
185 // Try to get psapi!GetModuleFileNameExW once, and then every process object can use it.
186 // If we can't get it, then we'll fallback to getting information from the IPC block.
187 #if !defined(FEATURE_CORESYSTEM)
188 m_hPSAPIdll = WszLoadLibrary(W("psapi.dll"));
190 m_hPSAPIdll = WszLoadLibrary(W("api-ms-win-obsolete-psapi-l1-1-0.dll"));
193 if (m_hPSAPIdll != NULL)
195 m_fpGetModuleFileNameEx = (FPGetModuleFileNameEx*) GetProcAddress(m_hPSAPIdll, "GetModuleFileNameExW");
198 CordbCommonBase::InitializeCommon();
201 CorpubPublish::~CorpubPublish()
203 // m_hPSAPIdll is a module holder, so the dtor will free it automatically for us.
207 COM_METHOD CorpubPublish::QueryInterface(REFIID id, void **ppInterface)
209 if (id == IID_ICorPublish)
210 *ppInterface = (ICorPublish*)this;
211 else if (id == IID_IUnknown)
212 *ppInterface = (IUnknown*)(ICorPublish*)this;
216 return E_NOINTERFACE;
224 COM_METHOD CorpubPublish::EnumProcesses(COR_PUB_ENUMPROCESS Type,
225 ICorPublishProcessEnum **ppIEnum)
228 CorpubProcess* pProcessList = NULL ;
229 CorpubProcessEnum* pProcEnum = NULL;
232 if( Type != COR_PUB_MANAGEDONLY )
238 // call function to get PIDs for all processes in the system
239 #define MAX_PROCESSES 512
241 DWORD ProcessId[MAX_PROCESSES];
242 DWORD dwNumProcesses = 0;
243 if( !GetAllProcessesInSystem(ProcessId, MAX_PROCESSES, &dwNumProcesses) )
249 // iterate over all the processes to fetch all the managed processes
250 for (int i = 0; i < (int)dwNumProcesses; i++)
252 CorpubProcess *pProcess = NULL;
253 hr = GetProcessInternal( ProcessId[i], &pProcess );
256 _ASSERTE( pProcess == NULL );
257 goto exit; // a serious error has occurred, abort
262 // Success, Add the process to the list.
263 _ASSERTE( pProcess != NULL );
264 pProcess->SetNext( pProcessList );
265 pProcessList = pProcess;
269 // Ignore this process (isn't managed, or shut down, etc.)
270 _ASSERTE( pProcess == NULL );
274 // create and return the ICorPublishProcessEnum
275 pProcEnum = new (nothrow) CorpubProcessEnum(pProcessList);
276 if (pProcEnum == NULL)
283 hr = pProcEnum->QueryInterface(IID_ICorPublishProcessEnum, (void**)ppIEnum);
292 // release our handle on the process objects
293 while (pProcessList != NULL)
295 CorpubProcess *pTmp = pProcessList;
296 pProcessList = pProcessList->GetNextProcess();
299 if( pProcEnum != NULL )
301 pProcEnum->Release();
309 HRESULT CorpubPublish::GetProcess(unsigned pid,
310 ICorPublishProcess **ppProcess)
314 // Query for this specific process (even if we've already handed out a
315 // now-stale process object for this pid)
316 CorpubProcess * pProcess = NULL;
317 HRESULT hr = GetProcessInternal( pid, &pProcess );
320 // Couldn't get this process (doesn't exist, or isn't managed)
321 _ASSERTE( pProcess == NULL );
324 return hr; // there was a serious error trying to get this process info
326 return E_INVALIDARG; // this process doesn't exist, isn't managed or is shutting down
329 // QI to ICorPublishProcess and return it
330 _ASSERTE( pProcess != NULL );
331 hr = pProcess->QueryInterface(IID_ICorPublishProcess, (void**)ppProcess);
337 // Attempts to create a CorpubProcess object for a specific managed process
338 // On success returns S_OK and sets ppProcess to a new AddRef'd CorpubProcess
339 // object. Otherwise, returns S_FALSE if the process isn't managed or if it has
340 // terminated (i.e. it should be ignored), or and error code on a serious failure.
341 HRESULT CorpubPublish::GetProcessInternal(
343 CorpubProcess **ppProcess )
345 #if defined(FEATURE_DBGIPC_TRANSPORT_DI)
348 #else // !FEATURE_DBGIPC_TRANSPORT_DI
352 NewHolder<IPCReaderInterface> pIPCReader( new (nothrow) IPCReaderInterface() );
353 if (pIPCReader == NULL)
355 LOG((LF_CORDB, LL_INFO100, "CP::EP: Failed to allocate memory for IPCReaderInterface.\n"));
356 return E_OUTOFMEMORY;
359 // See if it is a managed process by trying to open the shared
361 hr = pIPCReader->OpenLegacyPrivateBlockTempV4OnPid(pid);
364 return S_FALSE; // Not a managed process
367 // Get the AppDomainIPCBlock
368 AppDomainEnumerationIPCBlock *pAppDomainCB = pIPCReader->GetAppDomainBlock();
369 if (pAppDomainCB == NULL)
371 LOG((LF_CORDB, LL_INFO1000, "CP::EP: Failed to obtain AppDomainIPCBlock.\n"));
375 // Get the process handle.
376 HANDLE hProcess = OpenProcess((PROCESS_VM_READ |
377 PROCESS_QUERY_INFORMATION |
381 if (hProcess == NULL)
383 LOG((LF_CORDB, LL_INFO1000, "CP::EP: OpenProcess() returned NULL handle.\n"));
387 // If the mutex isn't filled in, the CLR is either starting up or shutting down
388 if (pAppDomainCB->m_hMutex == NULL)
390 LOG((LF_CORDB, LL_INFO1000, "CP::EP: IPC block isn't properly filled in.\n"));
394 // Dup the valid mutex handle into this process.
396 if( !pAppDomainCB->m_hMutex.DuplicateToLocalProcess(hProcess, &hMutex) )
401 // Acquire the mutex, only waiting two seconds.
402 // We can't actually gaurantee that the target put a mutex object in here.
403 DWORD dwRetVal = WaitForSingleObject(hMutex, SAFETY_TIMEOUT);
405 if (dwRetVal == WAIT_OBJECT_0)
407 // Make sure the mutex handle is still valid. If
408 // its not, then we lost a shutdown race.
409 if (pAppDomainCB->m_hMutex == NULL)
411 LOG((LF_CORDB, LL_INFO1000, "CP::EP: lost shutdown race, skipping...\n"));
413 ReleaseMutex(hMutex);
420 // Again, landing here is most probably a shutdown race. Its okay, though...
421 LOG((LF_CORDB, LL_INFO1000, "CP::EP: failed to get IPC mutex.\n"));
423 if (dwRetVal == WAIT_ABANDONED)
425 ReleaseMutex(hMutex);
430 // Beware: if the target pid is not properly honoring the mutex, the data in the
431 // IPC block may still shift underneath us.
433 // If we get here, then hMutex is held by this process.
435 // Now create the CorpubProcess object for the ProcessID
436 CorpubProcess *pProc = new (nothrow) CorpubProcess(pid,
442 m_fpGetModuleFileNameEx);
444 // Release our lock on the IPC block.
445 ReleaseMutex(hMutex);
449 return E_OUTOFMEMORY;
451 pIPCReader.SuppressRelease();
453 // Success, return the Process object
458 #endif // FEATURE_DBGIPC_TRANSPORT_DI
463 // ******************************************
465 // ******************************************
468 CorpubProcess::CorpubProcess(DWORD dwProcessId,
472 AppDomainEnumerationIPCBlock *pAD,
473 #if !defined(FEATURE_DBGIPC_TRANSPORT_DI)
474 IPCReaderInterface *pIPCReader,
475 #endif // !FEATURE_DBGIPC_TRANSPORT_DI
476 FPGetModuleFileNameEx * fpGetModuleFileNameEx)
477 : CordbCommonBase(0, enumCorpubProcess),
478 m_dwProcessId(dwProcessId),
479 m_fIsManaged(fManaged),
480 m_hProcess(hProcess),
483 #if !defined(FEATURE_DBGIPC_TRANSPORT_DI)
484 m_pIPCReader(pIPCReader),
485 #endif // !FEATURE_DBGIPC_TRANSPORT_DI
489 // First try to get the process name from the OS. That can't be spoofed by badly formed IPC block.
490 // psapi!GetModuleFileNameExW can get that, but it's not available on all platforms so we
491 // need to load it dynamically.
492 if (fpGetModuleFileNameEx != NULL)
494 // MSDN is very confused about whether the lenght is in bytes (MSDN 2002) or chars (MSDN 2004).
495 // We err on the safe side by having buffer that's twice as large, and ignoring
496 // the units on the return value.
497 WCHAR szName[MAX_PATH * sizeof(WCHAR)];
499 DWORD lenInCharsOrBytes = MAX_PATH*sizeof(WCHAR);
501 // Pass NULL module handle to get "Main Module", which will give us the process name.
502 DWORD ret = (*fpGetModuleFileNameEx) (hProcess, NULL, szName, lenInCharsOrBytes);
505 // Recompute string length because we don't know if 'ret' is in bytes or char.
506 SIZE_T len = wcslen(szName) + 1;
507 m_szProcessName = new (nothrow) WCHAR[len];
508 if (m_szProcessName != NULL)
510 wcscpy_s(m_szProcessName, len, szName);
516 // This is a security feature on WinXp + above, so make sure it worked there.
517 CONSISTENCY_CHECK_MSGF(FALSE, ("On XP/2k03 OSes + above, we should have been able to get\n"
518 "the module name from psapi!GetModuleFileNameEx. fp=0x%p\n.", fpGetModuleFileNameEx));
520 // We couldn't get it from the OS, so fallthrough to getting it from the IPC block.
522 // Fetch the process name from the AppDomainIPCBlock
523 _ASSERTE (pAD->m_szProcessName != NULL);
525 if (pAD->m_szProcessName == NULL)
526 m_szProcessName = NULL;
531 _ASSERTE(pAD->m_iProcessNameLengthInBytes > 0);
533 // Note: this assumes we're reading the null terminator from
535 m_szProcessName = (WCHAR*) new (nothrow) char[pAD->m_iProcessNameLengthInBytes];
537 if (m_szProcessName == NULL)
539 LOG((LF_CORDB, LL_INFO1000,
540 "CP::CP: Failed to allocate memory for ProcessName.\n"));
545 BOOL bSucc = ReadProcessMemory(hProcess,
546 pAD->m_szProcessName,
548 pAD->m_iProcessNameLengthInBytes,
552 (nBytesRead != (SIZE_T)pAD->m_iProcessNameLengthInBytes))
554 // The EE may have done a rude exit
555 LOG((LF_CORDB, LL_INFO1000,
556 "CP::EAD: ReadProcessMemory (ProcessName) failed.\n"));
564 CorpubProcess::~CorpubProcess()
566 delete [] m_szProcessName;
567 #if !defined(FEATURE_DBGIPC_TRANSPORT_DI)
569 #endif // !FEATURE_DBGIPC_TRANSPORT_DI
570 CloseHandle(m_hProcess);
571 CloseHandle(m_hMutex);
575 HRESULT CorpubProcess::QueryInterface(REFIID id, void **ppInterface)
577 if (id == IID_ICorPublishProcess)
578 *ppInterface = (ICorPublishProcess*)this;
579 else if (id == IID_IUnknown)
580 *ppInterface = (IUnknown*)(ICorPublishProcess*)this;
584 return E_NOINTERFACE;
592 // Helper to tell if this process has exited.
593 bool CorpubProcess::IsExited()
595 DWORD res = WaitForSingleObject(this->m_hProcess, 0);
596 return (res == WAIT_OBJECT_0);
600 HRESULT CorpubProcess::IsManaged(BOOL *pbManaged)
602 *pbManaged = (m_fIsManaged == true) ? TRUE : FALSE;
608 // Allocates a local buffer (using 'new') and fills it by copying it from remote memory.
610 // - on success, S_OK, *ppNewLocalBuffer points to a newly allocated buffer containing
611 // the full copy from remote memoy. Caller must use 'delete []' to free this.
612 // - on failure, a failing HR. No memory is allocated.
613 HRESULT AllocateAndReadRemoteBuffer(
616 SIZE_T cbSize, // size of buffer to allocate + copy.
617 BYTE * * ppNewLocalBuffer
620 _ASSERTE(ppNewLocalBuffer != NULL);
621 *ppNewLocalBuffer = NULL;
624 if (pRemotePtr == NULL)
629 BYTE *pLocalBuffer = new (nothrow) BYTE[cbSize];
631 if (pLocalBuffer == NULL)
633 _ASSERTE(!"Failed to alloc memory. Likely size is bogusly large, perhaps from an attacker.");
634 return E_OUTOFMEMORY;
639 // Need to read in the remote process' memory
640 BOOL bSucc = ReadProcessMemory(hProcess,
642 pLocalBuffer, cbSize,
645 if ((bSucc == 0) || (nBytesRead != cbSize))
647 // The EE may have done a rude exit
648 delete [] pLocalBuffer;
652 *ppNewLocalBuffer = pLocalBuffer;
656 // Wrapper around AllocateAndReadRemoteBuffer,
657 // to ensure that we're reading an remote-null terminated string.
658 // Ensures that string is null-terminated.
659 HRESULT AllocateAndReadRemoteString(
662 SIZE_T cbSize, // size of buffer to allocate + copy.
663 __deref_out_bcount(cbSize) WCHAR * * ppNewLocalBuffer
666 // Make sure buffer has right geometry.
672 // If it's not on a WCHAR boundary, then we may have a 1-byte buffer-overflow.
673 SIZE_T ceSize = cbSize / sizeof(WCHAR);
674 if ((ceSize * sizeof(WCHAR)) != cbSize)
679 // It should at least have 1 char for the null terminator.
686 HRESULT hr = AllocateAndReadRemoteBuffer(hProcess, pRemotePtr, cbSize, (BYTE**) ppNewLocalBuffer);
689 // Ensure that the string we just read is actually null terminated.
690 // We can't call wcslen() on it yet, since that may AV on a non-null terminated string.
691 WCHAR * pString = *ppNewLocalBuffer;
693 if (pString[ceSize - 1] == W('\0'))
695 // String is null terminated.
698 pString[ceSize - 1] = W('\0');
700 SIZE_T ceTestLen = wcslen(pString);
701 if (ceTestLen == ceSize - 1)
703 // String was not previously null-terminated.
704 delete [] ppNewLocalBuffer;
712 // Enumerate the list of known application domains in the target process.
714 HRESULT CorpubProcess::EnumAppDomains(ICorPublishAppDomainEnum **ppIEnum)
716 VALIDATE_POINTER_TO_OBJECT(ppIEnum, ICorPublishAppDomainEnum **);
722 WCHAR *pAppDomainName = NULL;
723 CorpubAppDomain *pAppDomainHead = NULL;
725 // Lock the IPC block:
726 // We can't trust any of the data in the IPC block (including our own mutex handle),
727 // because we don't want bugs in the debuggee escalating into bugs in the debugger.
728 DWORD res = WaitForSingleObject(m_hMutex, SAFETY_TIMEOUT);
730 if (res == WAIT_TIMEOUT)
732 // This should only happen if the target process is illbehaved.
733 return CORDBG_E_TIMEOUT;
736 // If the process has gone away, or if it has cleared out its control block, then
737 // we've lost the race to access this process before it is terminated.
738 // Note that if the EE does a rude process exit, it won't have cleared the control block so there
739 // will be a small race window.
740 if (this->IsExited() || this->m_AppDomainCB->m_hMutex == NULL )
742 // This is the common case. A process holding the mutex shouldn't normally exit,
743 // but once it releases the mutex, it may exit asynchronously.
744 return CORDBG_E_PROCESS_TERMINATED;
747 if (res == WAIT_FAILED)
749 // This should be the next most common failure case
750 return HRESULT_FROM_GetLastError();
753 if (res != WAIT_OBJECT_0)
755 // Catch all other possible failures
759 int iAppDomainCount = 0;
760 AppDomainInfo *pADI = NULL;
762 // Make a copy of the IPC block so that we can gaurantee that it's not changing on us.
763 AppDomainEnumerationIPCBlock tempBlock;
764 memcpy(&tempBlock, m_AppDomainCB, sizeof(tempBlock));
766 // Allocate memory to read the remote process' memory into
767 const SIZE_T cbADI = tempBlock.m_iSizeInBytes;
769 // It's possible the process will not have any appdomains.
770 if ((tempBlock.m_rgListOfAppDomains == NULL) != (tempBlock.m_iSizeInBytes == 0))
772 _ASSERTE(!"Inconsistent IPC block in publish.");
777 // All the data in the IPC block is signed integers. They should never be negative,
778 // so check that now.
779 if ((tempBlock.m_iTotalSlots < 0) ||
780 (tempBlock.m_iNumOfUsedSlots < 0) ||
781 (tempBlock.m_iLastFreedSlot < 0) ||
782 (tempBlock.m_iSizeInBytes < 0) ||
783 (tempBlock.m_iProcessNameLengthInBytes < 0))
789 // Check other invariants.
790 if (cbADI != tempBlock.m_iTotalSlots * sizeof(AppDomainInfo))
792 _ASSERTE(!"Size mismatch");
797 hr = AllocateAndReadRemoteBuffer(m_hProcess, tempBlock.m_rgListOfAppDomains, cbADI, (BYTE**) &pADI);
802 _ASSERTE(pADI != NULL);
804 // Collect all the AppDomain info info a list of CorpubAppDomains
805 for (i = 0; i < tempBlock.m_iTotalSlots; i++)
807 if (!pADI[i].IsEmpty())
809 // Should be positive, and at least have a null-terminator character.
810 if (pADI[i].m_iNameLengthInBytes <= 1)
815 hr = AllocateAndReadRemoteString(m_hProcess,
816 (void*) pADI[i].m_szAppDomainName, pADI[i].m_iNameLengthInBytes, // remote string + size in bytes
823 // create a new AppDomainObject. This will take ownership of pAppDomainName.
824 // We know the string is a well-formed null-terminated string,
825 // but beyond that, we can't verify that the data is actually truthful.
826 CorpubAppDomain *pCurrentAppDomain = new (nothrow) CorpubAppDomain(pAppDomainName,
829 if (pCurrentAppDomain == NULL)
831 LOG((LF_CORDB, LL_INFO1000,
832 "CP::EAD: Failed to allocate memory for CorpubAppDomain.\n"));
838 // Since CorpubAppDomain now owns pAppDomain's memory, we don't worry about freeing it.
839 pAppDomainName = NULL;
841 // Add the appdomain to the list.
842 pCurrentAppDomain->SetNext(pAppDomainHead);
843 pAppDomainHead = pCurrentAppDomain;
845 // Shortcut to opt out of reading the rest of the array if it's empty.
846 if (++iAppDomainCount >= tempBlock.m_iNumOfUsedSlots)
852 _ASSERTE ((iAppDomainCount >= tempBlock.m_iNumOfUsedSlots)
853 && (i <= tempBlock.m_iTotalSlots));
855 // create and return the ICorPublishAppDomainEnum object, handing off the AppDomain list to it
856 CorpubAppDomainEnum *pTemp = new (nothrow) CorpubAppDomainEnum(pAppDomainHead);
864 pAppDomainHead = NULL; // handed off AppDomain list to enum, don't delete below
866 hr = pTemp->QueryInterface(IID_ICorPublishAppDomainEnum,
871 ReleaseMutex(m_hMutex);
873 // If we didn't hand off the AppDomain objects, delete them
874 while( pAppDomainHead != NULL )
876 CorpubAppDomain *pTemp = pAppDomainHead;
877 pAppDomainHead = pAppDomainHead->GetNextAppDomain();
884 if (pAppDomainName != NULL)
885 delete [] pAppDomainName;
887 // Either we succeeded && provided an enumerator; or we failed and didn't provide an enum.
888 _ASSERTE(SUCCEEDED(hr) == (*ppIEnum != NULL));
893 * Returns the OS ID for the process in question.
895 HRESULT CorpubProcess::GetProcessID(unsigned *pid)
897 *pid = m_dwProcessId;
903 * Get the display name for a process.
905 HRESULT CorpubProcess::GetDisplayName(ULONG32 cchName,
907 __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[])
909 VALIDATE_POINTER_TO_OBJECT_ARRAY_OR_NULL(szName, WCHAR, cchName, true, true);
910 VALIDATE_POINTER_TO_OBJECT_OR_NULL(pcchName, ULONG32 *);
912 // Reasonable defaults
919 const WCHAR *szTempName = m_szProcessName;
921 // In case we didn't get the name (most likely out of memory on ctor).
923 szTempName = W("<unknown>");
925 return CopyOutString(szTempName, cchName, pcchName, szName);
929 // ******************************************
931 // ******************************************
933 CorpubAppDomain::CorpubAppDomain (__in LPWSTR szAppDomainName, ULONG Id)
934 : CordbCommonBase (0, enumCorpubAppDomain),
936 m_szAppDomainName (szAppDomainName),
939 _ASSERTE(m_szAppDomainName != NULL);
942 CorpubAppDomain::~CorpubAppDomain()
944 delete [] m_szAppDomainName;
947 HRESULT CorpubAppDomain::QueryInterface (REFIID id, void **ppInterface)
949 if (id == IID_ICorPublishAppDomain)
950 *ppInterface = (ICorPublishAppDomain*)this;
951 else if (id == IID_IUnknown)
952 *ppInterface = (IUnknown*)(ICorPublishAppDomain*)this;
956 return E_NOINTERFACE;
965 * Get the name and ID for an application domain.
967 HRESULT CorpubAppDomain::GetID (ULONG32 *pId)
969 VALIDATE_POINTER_TO_OBJECT(pId, ULONG32 *);
977 * Get the name for an application domain.
979 HRESULT CorpubAppDomain::GetName(ULONG32 cchName,
981 __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[])
983 VALIDATE_POINTER_TO_OBJECT_ARRAY_OR_NULL(szName, WCHAR, cchName, true, true);
984 VALIDATE_POINTER_TO_OBJECT_OR_NULL(pcchName, ULONG32 *);
986 const WCHAR *szTempName = m_szAppDomainName;
988 // In case we didn't get the name (most likely out of memory on ctor).
990 szTempName = W("<unknown>");
992 return CopyOutString(szTempName, cchName, pcchName, szName);
997 // ******************************************
999 // ******************************************
1001 CorpubProcessEnum::CorpubProcessEnum (CorpubProcess *pFirst)
1002 : CordbCommonBase (0, enumCorpubProcessEnum),
1006 // Increment the ref count on each process, we own the list
1007 CorpubProcess * cur = pFirst;
1008 while( cur != NULL )
1011 cur = cur->GetNextProcess();
1015 CorpubProcessEnum::~CorpubProcessEnum()
1017 // Release each process in the list (our client may still have a reference
1019 while (m_pFirst != NULL)
1021 CorpubProcess *pTmp = m_pFirst;
1022 m_pFirst = m_pFirst->GetNextProcess();
1027 HRESULT CorpubProcessEnum::QueryInterface (REFIID id, void **ppInterface)
1029 if (id == IID_ICorPublishProcessEnum)
1030 *ppInterface = (ICorPublishProcessEnum*)this;
1031 else if (id == IID_IUnknown)
1032 *ppInterface = (IUnknown*)(ICorPublishProcessEnum*)this;
1035 *ppInterface = NULL;
1036 return E_NOINTERFACE;
1044 HRESULT CorpubProcessEnum::Skip(ULONG celt)
1046 while ((m_pCurrent != NULL) && (celt-- > 0))
1048 m_pCurrent = m_pCurrent->GetNextProcess();
1054 HRESULT CorpubProcessEnum::Reset()
1056 m_pCurrent = m_pFirst;
1061 HRESULT CorpubProcessEnum::Clone(ICorPublishEnum **ppEnum)
1063 VALIDATE_POINTER_TO_OBJECT(ppEnum, ICorPublishEnum **);
1067 HRESULT CorpubProcessEnum::GetCount(ULONG *pcelt)
1069 VALIDATE_POINTER_TO_OBJECT(pcelt, ULONG *);
1071 CorpubProcess *pTemp = m_pFirst;
1075 while (pTemp != NULL)
1078 pTemp = pTemp->GetNextProcess();
1084 HRESULT CorpubProcessEnum::Next(ULONG celt,
1085 ICorPublishProcess *objects[],
1086 ULONG *pceltFetched)
1088 VALIDATE_POINTER_TO_OBJECT_ARRAY(objects, ICorPublishProcess *,
1090 VALIDATE_POINTER_TO_OBJECT_OR_NULL(pceltFetched, ULONG *);
1092 if ((pceltFetched == NULL) && (celt != 1))
1094 return E_INVALIDARG;
1099 if (pceltFetched != NULL)
1110 while ((m_pCurrent != NULL) && (count < celt))
1112 hr = m_pCurrent->QueryInterface (IID_ICorPublishProcess,
1113 (void**)&objects[count]);
1121 m_pCurrent = m_pCurrent->GetNextProcess();
1124 if (pceltFetched != NULL)
1126 *pceltFetched = count;
1130 // If we reached the end of the enumeration, but not the end
1131 // of the number of requested items, we return S_FALSE.
1141 // ******************************************
1142 // CorpubAppDomainEnum
1143 // ******************************************
1144 CorpubAppDomainEnum::CorpubAppDomainEnum (CorpubAppDomain *pFirst)
1145 : CordbCommonBase (0, enumCorpubAppDomainEnum),
1149 CorpubAppDomain *pCur = pFirst;
1150 while( pCur != NULL )
1153 pCur = pCur->GetNextAppDomain();
1157 CorpubAppDomainEnum::~CorpubAppDomainEnum()
1159 // Delete all the app domains
1160 while (m_pFirst != NULL )
1162 CorpubAppDomain *pTemp = m_pFirst;
1163 m_pFirst = m_pFirst->GetNextAppDomain();
1168 HRESULT CorpubAppDomainEnum::QueryInterface (REFIID id, void **ppInterface)
1170 if (id == IID_ICorPublishAppDomainEnum)
1171 *ppInterface = (ICorPublishAppDomainEnum*)this;
1172 else if (id == IID_IUnknown)
1173 *ppInterface = (IUnknown*)(ICorPublishAppDomainEnum*)this;
1176 *ppInterface = NULL;
1177 return E_NOINTERFACE;
1185 HRESULT CorpubAppDomainEnum::Skip(ULONG celt)
1187 while ((m_pCurrent != NULL) && (celt-- > 0))
1189 m_pCurrent = m_pCurrent->GetNextAppDomain();
1195 HRESULT CorpubAppDomainEnum::Reset()
1197 m_pCurrent = m_pFirst;
1202 HRESULT CorpubAppDomainEnum::Clone(ICorPublishEnum **ppEnum)
1204 VALIDATE_POINTER_TO_OBJECT(ppEnum, ICorPublishEnum **);
1208 HRESULT CorpubAppDomainEnum::GetCount(ULONG *pcelt)
1210 VALIDATE_POINTER_TO_OBJECT(pcelt, ULONG *);
1212 CorpubAppDomain *pTemp = m_pFirst;
1216 while (pTemp != NULL)
1219 pTemp = pTemp->GetNextAppDomain();
1225 HRESULT CorpubAppDomainEnum::Next(ULONG celt,
1226 ICorPublishAppDomain *objects[],
1227 ULONG *pceltFetched)
1229 VALIDATE_POINTER_TO_OBJECT_ARRAY(objects, ICorPublishProcess *,
1231 VALIDATE_POINTER_TO_OBJECT_OR_NULL(pceltFetched, ULONG *);
1233 if ((pceltFetched == NULL) && (celt != 1))
1235 return E_INVALIDARG;
1240 if (pceltFetched != NULL)
1251 while ((m_pCurrent != NULL) && (count < celt))
1253 hr = m_pCurrent->QueryInterface (IID_ICorPublishAppDomain,
1254 (void **)&objects[count]);
1262 m_pCurrent = m_pCurrent->GetNextAppDomain();
1266 if (pceltFetched != NULL)
1268 *pceltFetched = count;
1272 // If we reached the end of the enumeration, but not the end
1273 // of the number of requested items, we return S_FALSE.
1283 #endif // defined(FEATURE_DBG_PUBLISH)