1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4//*****************************************************************************
5// File: RsMda.cpp
6//
7
8// Manage Debug Assistant support in the Right-Side
9//
10//*****************************************************************************
11#include "stdafx.h"
12
13#include "winbase.h"
14#include "corpriv.h"
15
16//-----------------------------------------------------------------------------
17// Cordb MDA notification
18//-----------------------------------------------------------------------------
19CordbMDA::CordbMDA(CordbProcess * pProc, DebuggerMDANotification * pData)
20: CordbBase(pProc, 0, enumCordbMDA)
21{
22 _ASSERTE(pData != NULL);
23
24 // Owning Parent process should add us to process'es neuter list.
25
26 // Pick up ownership of strings
27 m_szName = pData->szName.TransferStringData();
28 m_szDescription = pData->szDescription.TransferStringData();
29 m_szXml = pData->szXml.TransferStringData();
30
31 m_dwOSTID = pData->dwOSThreadId;
32 m_flags = pData->flags;
33}
34
35//-----------------------------------------------------------------------------
36// Destructor for CordbMDA object. Not much to do here since neutering should
37// have taken care of it all.
38//-----------------------------------------------------------------------------
39CordbMDA::~CordbMDA()
40{
41 // Strings protected w/ holders that will automatically free them.
42 _ASSERTE(IsNeutered());
43}
44
45//-----------------------------------------------------------------------------
46// Neuter the CordbMDA object.
47//-----------------------------------------------------------------------------
48void CordbMDA::Neuter()
49{
50 // Release buffers. Once we're neutered, these can no longer be accessed anyways,
51 // so may as well free them now.
52 // This is being done under the process-lock, and our accessors are also done
53 // under that lock, so we don't have to worry about any races here. :)
54 m_szName.Clear();
55 m_szDescription.Clear();
56 m_szXml.Clear();
57
58 CordbBase::Neuter();
59};
60
61//-----------------------------------------------------------------------------
62// Implement IUnknown::QueryInterface.
63//-----------------------------------------------------------------------------
64HRESULT CordbMDA::QueryInterface(REFIID riid, void **ppInterface)
65{
66 if (riid == IID_ICorDebugMDA)
67 *ppInterface = static_cast<ICorDebugMDA*>(this);
68 else if (riid == IID_IUnknown)
69 *ppInterface = static_cast<IUnknown*>(static_cast<ICorDebugMDA*>(this));
70 else
71 {
72 *ppInterface = NULL;
73 return E_NOINTERFACE;
74 }
75
76 ExternalAddRef();
77 return S_OK;
78}
79
80//-----------------------------------------------------------------------------
81// Helper to marshal a string object out through the ICorDebug interfaces
82// *GetName() functions using the common triple design pattern.
83//
84// parameters:
85// pInputString - the string that we want to marshal out via the triple
86// cchName, pcchName, szName - triple used to marshal out a string.
87// Same usage as CordbModule::GetName and other string getters on the API.
88//
89// *pcchName is always set to the length of pInputString (including NULL). This lets
90// callers know the full size of buffer they'd need to allocate to get the full string.
91//
92// if (cchName == 0) then we're in "query" mode:
93// szName must be null. pcchName must be non-null and this function will just set
94// *pcchName to let the caller know how large of a buffer to allocate.
95
96// if (cchName != 0) then we copy as much as can fit into szName. We will always
97// null terminate szName.
98// pcchName can be null. If it's non-null, we set it.
99//
100//
101// Expected usage is that caller calls us twice, once in query mode to allocate
102// buffer, then a 2nd time to fill the buffer.
103//
104// Returns: S_OK on success.
105//-----------------------------------------------------------------------------
106HRESULT CopyOutString(LPCWSTR pInputString, ULONG32 cchName, ULONG32 * pcchName, __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[])
107{
108 _ASSERTE(pInputString != NULL);
109 ULONG32 len = (ULONG32) wcslen(pInputString) + 1;
110
111 if (cchName == 0)
112 {
113 // Query length
114 if ((szName != NULL) || (pcchName == NULL))
115 {
116 return E_INVALIDARG;
117 }
118 *pcchName = len;
119 return S_OK;
120 }
121 else
122 {
123 // Get data
124 if (szName == NULL)
125 {
126 return E_INVALIDARG;
127 }
128
129 // Just copy whatever we can fit into the buffer. If we truncate, that's ok.
130 // This will also guarantee that we null terminate.
131 wcsncpy_s(szName, cchName, pInputString, _TRUNCATE);
132
133 if (pcchName != 0)
134 {
135 *pcchName = len;
136 }
137
138 return S_OK;
139 }
140}
141
142//-----------------------------------------------------------------------------
143// Get the string for the type of the MDA. Never empty.
144// This is a convenient performant alternative to getting the XML stream and extracting
145// the type from that based off the schema.
146// See CopyOutString for parameter details.
147//-----------------------------------------------------------------------------
148HRESULT CordbMDA::GetName(ULONG32 cchName, ULONG32 * pcchName, __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[])
149{
150 HRESULT hr = S_OK;
151 PUBLIC_API_BEGIN(this)
152 {
153 hr = E_NOTIMPL;
154 }
155 PUBLIC_API_END(hr);
156 return hr;
157}
158
159//-----------------------------------------------------------------------------
160// Get a string description of the MDA. This may be empty (0-length).
161// See CopyOutString for parameter details.
162//-----------------------------------------------------------------------------
163HRESULT CordbMDA::GetDescription(ULONG32 cchName, ULONG32 * pcchName, __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[])
164{
165 HRESULT hr = S_OK;
166 PUBLIC_API_BEGIN(this)
167 {
168 hr = E_NOTIMPL;
169 }
170 PUBLIC_API_END(hr);
171 return hr;
172}
173
174//-----------------------------------------------------------------------------
175// Get the full associated XML for the MDA. This may be empty.
176// This could be a potentially expensive operation if the xml stream is large.
177// See the MDA documentation for the schema for this XML stream.
178// See CopyOutString for parameter details.
179//-----------------------------------------------------------------------------
180HRESULT CordbMDA::GetXML(ULONG32 cchName, ULONG32 * pcchName, __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[])
181{
182 HRESULT hr = S_OK;
183 PUBLIC_API_BEGIN(this)
184 {
185 hr = E_NOTIMPL;
186 }
187 PUBLIC_API_END(hr);
188 return hr;
189}
190
191//-----------------------------------------------------------------------------
192// Get flags for this MDA object.
193//-----------------------------------------------------------------------------
194HRESULT CordbMDA::GetFlags(CorDebugMDAFlags * pFlags)
195{
196 HRESULT hr = S_OK;
197 PUBLIC_API_BEGIN(this)
198 {
199 hr = E_NOTIMPL;
200 }
201 PUBLIC_API_END(hr);
202 return hr;
203}
204
205//-----------------------------------------------------------------------------
206// Thread that the MDA is fired on. We use the os tid instead of an ICDThread in case an MDA is fired on a
207// native thread (or a managed thread that hasn't yet entered managed code and so we don't have a ICDThread
208// object for it yet)
209//-----------------------------------------------------------------------------
210HRESULT CordbMDA::GetOSThreadId(DWORD * pOsTid)
211{
212 HRESULT hr = S_OK;
213 PUBLIC_API_BEGIN(this)
214 {
215 hr = E_NOTIMPL;
216 }
217 PUBLIC_API_END(hr);
218 return hr;
219}
220
221