private static int MarshalPdbReader(IDebugUpdateInMemoryPE2 updater, out IntPtr pdbReaderPointer) { // ISymUnmanagedReader can only be accessed from an MTA thread, however, we need // fetch the IUnknown instance (call IENCSymbolReaderProvider.GetSymbolReader) here // in the STA. To further complicate things, we need to return synchronously from // this method. Waiting for the MTA thread to complete so we can return synchronously // blocks the STA thread, so we need to make sure the CLR doesn't try to marshal // ISymUnmanagedReader calls made in an MTA back to the STA for execution (if this // happens we'll be deadlocked). We'll use CoMarshalInterThreadInterfaceInStream to // achieve this. First, we'll marshal the object in a Stream and pass a Stream pointer // over to the MTA. In the MTA, we'll get the Stream from the pointer and unmarshal // the object. The reader object was originally created on an MTA thread, and the // instance we retrieved in the STA was a proxy. When we unmarshal the Stream in the // MTA, it "unwraps" the proxy, allowing us to directly call the implementation. // Another way to achieve this would be for the symbol reader to implement IAgileObject, // but the symbol reader we use today does not. If that changes, we should consider // removing this marshal/unmarshal code. IENCDebugInfo debugInfo; updater.GetENCDebugInfo(out debugInfo); var symbolReaderProvider = (IENCSymbolReaderProvider)debugInfo; object pdbReaderObjSta; symbolReaderProvider.GetSymbolReader(out pdbReaderObjSta); int hr = NativeMethods.GetStreamForObject(pdbReaderObjSta, out pdbReaderPointer); Marshal.ReleaseComObject(pdbReaderObjSta); return hr; }
private unsafe void SetFileUpdates( IDebugUpdateInMemoryPE2 updater, List<KeyValuePair<DocumentId, ImmutableArray<LineChange>>> edits) { int totalEditCount = edits.Sum(e => e.Value.Length); if (totalEditCount == 0) { return; } var lineUpdates = new LINEUPDATE[totalEditCount]; fixed (LINEUPDATE* lineUpdatesPtr = lineUpdates) { int index = 0; var fileUpdates = new FILEUPDATE[edits.Count]; for (int f = 0; f < fileUpdates.Length; f++) { var documentId = edits[f].Key; var deltas = edits[f].Value; fileUpdates[f].FileName = _vsProject.GetDocumentOrAdditionalDocument(documentId).FilePath; fileUpdates[f].LineUpdateCount = (uint)deltas.Length; fileUpdates[f].LineUpdates = (IntPtr)(lineUpdatesPtr + index); for (int l = 0; l < deltas.Length; l++) { lineUpdates[index + l].Line = (uint)deltas[l].OldLine; lineUpdates[index + l].UpdatedLine = (uint)deltas[l].NewLine; } index += deltas.Length; } // The updater makes a copy of all data, we can release the buffer after the call. updater.SetFileUpdates(fileUpdates, (uint)fileUpdates.Length); } }