I am investigating developing a new project system for a language not currently supported by Visual Studio.
There already exists a third party Debugger Adapter Protocol server for this language, however as it doesn't seem to work properly with the native DAP client used in Visual Studio I'd like to write my own AD7Engine and simply defer all the calls I don't need to modify back to the original implementation in Microsoft.VisualStudio.Debugger.VSCodeDebuggerHost.dll
In theory I feel this should be relatively simple; given the target COM object
namespace Microsoft.VisualStudio.Debugger.VSCodeDebuggerHost.AD7.Implementation
{
[ComVisible(true)]
[Guid("8355452D-6D2F-41b0-89B8-BB2AA2529E94")]
internal class AD7Engine
I think I should be able to do something like
var type = Type.GetTypeFromCLSID(new Guid("8355452D-6D2F-41b0-89B8-BB2AA2529E94"));
var instance = Activator.CreateInstance(type);
However this fails, saying the class is not registered. Even if I try and create an instance of my own AD7Engine
using this technique it says class not registered. The crux of this issue, I feel, is that the COM object is defined in the registry under HKCU\Software\Microsoft\VisualStudio\<version>\CLSID
(or maybe under Visual Studio's private registry hive in newer versions), however I strongly suspect Activator.CreateInstance
does not know about that location so can't see how to create it.
I've been pulling apart vsdebug.dll
in IDA to see where the engine creation details come from; ultimately, it uses a very similar technique to this, this and this
v8 = GetLoader(a1, &rclsid);
if (v8 < 0)
goto LABEL_26;
v8 = GetModulePath(a1, &bstrString);
if (v8 < 0)
{
v4 = bstrString;
goto LABEL_26;
}
v9 = CoCreateInstance(&rclsid, 0, dwClsContext, &_GUID_10e4254c_6d73_4c38_b011_e0049b2e0a0f, &ppv);
v4 = bstrString;
if (v9 < 0)
{
v8 = -2147155456;
goto LABEL_26;
}
v8 = (*(int(__stdcall * *)(LPVOID, BSTR, IID *, LPUNKNOWN, DWORD, LPVOID *))(*(_DWORD*)ppv + 28))(
ppv,
bstrString,
a1,
pUnkOuter,
dwClsContext,
v17);
if (v8 < 0)
{
LABEL_26:
v11 = CoCreateInstance(a1, pUnkOuter, dwClsContext, &IID_IUnknown, v17);
if (v11 >= 0 || v8 != -2147155456)
however ultimately I feel I shouldn't have to resort to trying to calculate the VS CLSID registry path (which vsdebug.dll gets from somewhere unknown and everyone else just calculates or hardcodes); I feel there should be some high level way of creating arbitrary COM objects in the Visual Studio context, similar to when you use ServiceProvider.GetService()
.
For my purposes, this whole thing is a fun learning exercise, so whether this is a good idea or not is irrelevant to me; I'm committed to finding the answer at this stage; I just have to know what APIs exist for either
- achieving this outright with a simple API like GetService
- creating new instances of objects defined under the current Visual Studio version's CLSID registry key, or
- accessing keys under privateregistry.bin within a running extension
Any assistance would be greatly appreciated