Exposing Project Objects
Visual Studio provides a dynamic environment where VSPackages can be extended to seamlessly contribute to the Visual Studio automation model. These new objects extend the automation model's DTE object.
The DTE object is the main object in the Visual Studio automation model. It sits atop the Visual Studio automation object hierarchy.
The names of the VSPackage-specific objects are stored in the registry, and the code that creates and returns the object is part-- of your VSPackage implementation. The following steps describe the process for finding VSPackage-specific objects.
The environment starts.
It reads from the registry all value names under the Automation, AutomationEvents and AutomationProperties keys of all VSPackages and stores these names in a table.
An automation consumer calls the GetObject method or IDispatch::GetIDsOfNames, passing the name of an object, as shown below:
DTE.GetObject("VCProjects")
The Visual Studio environment finds the string parameter in the table and loads the corresponding VSPackage.
The environment calls the GetAutomationObject method with the name such as "VCProjects" passed in the call.
The VSPackage creates and returns the IDispatch pointer of the object. If the object already exists, its reference count is incremented. In this example, the caller is passed back a pointer to a standard Projects collection object, the one implemented by Visual C++.
The object that is returned is the entry point for looking at the rest of a project's automation objects.
After obtaining a particular Projects object, use the Item method to obtain a Project object corresponding to a Visual C++ project. Once you obtain a standard Project object, call the Object object to get to a project-specific object. The Object object is the place where you return an object that extends the Project object with your unique methods and properties. You can even create and return other objects.
The names of the automation objects you want to expose are stored as names of string values under the following key:
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\8.0\Packages\ <PkgGUID>\Automation]
Note
The text <PkgGUID> represents the actual GUID of your VSPackage.
The following code example and table contain typical registry entries.
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\8.0\Packages\<PkgGUID>\Automation]
@=""
"FigProjects"="Figures project automation object"
Name |
Type |
Range |
Description |
---|---|---|---|
Default (@) |
REG_SZ |
null |
Unused. You can use this for documentation. |
FigProjects |
REG_SZ |
Name of your unique Projects collection object. |
Only the key name is relevant. You can use the data field for documentation. |
All VSPackages that provide new project types should provide automation objects. For example, Visual C++ creates VSPackage-specific objects that add-ins can then call through DTE.VCProjects or DTE.GetObject("VCProjects") to get the project objects of Visual C++ through the Projects collection. The Projects and its contained Project items are the Visual C++ implementation but follow the standard pattern. However, the consumer can get to Project.Object, which is unique for the project type, and can provide its own unique objects as well. A projects automation model can also have Project.CodeModel, which can be queried for a most-derived object (VCCodeModel).
The same goes for ProjectItem, which also surfaces ProjectItem.Object, and a FileCodeModel.
The Visual C++ VSPackage then creates the objects to pass back to the automation consumer.
To contribute a VSPackage-specific object for a project
Add the appropriate keys to the registry settings of your VSPackage.
Implement the code in the GetAutomationObject of the IVsPackage interface that returns an IDispatch object.
The following code example shows an implementation of the GetAutomationObject method.
STDMETHODIMP CVsPackage::GetAutomationObject(
/* [in] */ LPCOLESTR pszPropName,
/* [out] */ IDispatch ** ppIDispatch)
{
ExpectedPtrRet(ppIDispatch);
*ppIDispatch = NULL;
if (_wcsicmp(pszPropName, g_wszAutomationProjects) == 0)
//Is the requested name our Projects object?
{
return GetAutomationProjects(ppIDispatch);
// Gets our Projects object
}
else if (_wcsicmp(pszPropName, g_wszAutomationProjectsEvents) == 0)
//Is the requested name our ProjectsEvents object?
{
return CAutomationEvents::GetAutomationEvents(ppIDispatch);
// Gets our ProjectEvents object
}
else if (_wcsicmp(pszPropName, g_wszAutomationProjectItemsEvents) == 0) //Is the requested name our ProjectsItemsEvents object?
{
return CAutomationEvents::GetAutomationEvents(ppIDispatch);
// Gets our ProjectItemsEvents object
}
return E_INVALIDARG;
}
In the code above, g_wszAutomationProjects is the name of your project collection. In this example, this is "FigProjects," the string registered under <PkgGUID>\Automation key as shown in the registry entries. The GetAutomationProjects method creates an object that implements the Projects interface and returns an IDispatch pointer to the calling object as shown in this code example.
HRESULT CVsPackage::GetAutomationProjects(/* [out] */ IDispatch ** ppIDispatch)
{
ExpectedPtrRet(ppIDispatch);
*ppIDispatch = NULL;
if (!m_srpAutomationProjects)
{
HRESULT hr = CACProjects::CreateInstance(&m_srpAutomationProjects);
IfFailRet(hr);
ExpectedExprRet(m_srpAutomationProjects != NULL);
}
return m_srpAutomationProjects.CopyTo(ppIDispatch);
}
You should choose a unique name for your automation object. Name conflicts are unpredictable, and collisions cause a conflicting object name to be arbitrarily thrown out if multiple VSPackages use the same name. To avoid such collisions, it is advisable to include your corporate name or some unique aspect of its product name in the name of the automation object.
The Projects collection object is the entry point for the remaining part of your project automation model. Once you have created the appropriate code and registry entries that provide consumers with Projects collection objects, your implementation must provide remaining standard objects for the project model. For more information, see Project Modeling.