Download - VSL Deep Dive
1
VSL Deep Dive
Josh Heitzman - Senior Software Design Engineer
2
VSL is…
•Acronym for “Visual Studio Library”•Modern C++ library targeting the Visual Studio Platform.•Styled after ATL and WTL.•Comprised only of header files. No binaries.•Extensible and customizable (macros can be overriden to change core behavior).•Not a framework like MFC, MPF, .Net Framework, etc..•Not a complete offering for the entire VS Platform
3
VSL Effect
Code Lines
Comment Lines Characters
Semi-colons Functions
Feature equivalent
C++ Tool Window 828 508 53,858 228 34
C# Tool Window 844 724 63,686 433 49
C++ Menus & Commands 178 222 18,996 38 11
C# Menus & Commands 227 201 20,498 90 10
C++ Services 315 320 28,230 78 15
C# Services 270 289 26,773 101 13
C++ Single View Editor 2,653 1,203 130,689 879 142
C# Single View Editor 3,253 1,620 251,990 1,147 276
Not feature equivalent
C++ Package 81 201 13,648 7 3
C# Package 204 261 22,284 72 17
4
Resources
<SDK Root>\VisualStudioIntegration\Common\Source\CPP\VSL•VSLArchitecture.htm – class diagrams•Include – VSL header files•MockInterfaces – Windows and Visual Studio Platform Interface mocks•UnitTest\VSLUnitTest.sln – solution with all of the VSL unit tests.
Questions/Issues:http://forums.microsoft.com/msdn/showforum.aspx?forumid=57&siteid=1•Prefix post title with “VSL”
Feedback/Suggestions:http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=123359&SiteID=1
Blog:http://blogs.msdn.com/josh_heitzman/
5
VSL Design Principles
•Minimize coupling•Avoid feature creep•Exploit the C++ language and the Microsoft Visual C++ compiler•Facilitate unit testing•Re-use without obstruction•Responsive to requests
6
Minimize coupling
Narrowly scoping the functionality of classes:•Implement one interface•Wrap one VS Service•Wrap one related set of Win32 APIs
Use of C++ templates to reduce hard dependencies between classes.
template<
class Derived_T,
class VsSiteCache_T = VsSiteCacheLocal>
class IVsWindowPaneImpl :
public IVsWindowPane
template <class Derived_T>
class IExtensibleObjectImpl :
public IExtensibleObject
7
Avoid feature creep
Only the functionality required for the task at hand is implemented.
Avoid investing resources in features that may not be needed.
class VsOutputWindowUtilities
{
void
OutputMessage(
const wchar_t* const szMessage);
void
OutputMessageWithPreAndPostBarsOfEquals(
const wchar_t* const szMessage);
};
8
Exploit the C++ language and the Visual C++ compiler
•When possible, fail at compile time rather then runtime•Make use of C++ exceptions•Use C++ templates and when necessary C pre-processor macros to minimize code redundancy and maximize reuse•Use of an extended version of the Resource Allocation Is Initialization paradigm
template <class Type_T, size_t NumberOfElements_T>class StaticArray{ C_ASSERT( NumberOfElements_T > 0);…__if_exists(Derived_T::GetViewObject){__if_exists(Derived_T:: GetLocalRegistryCLSIDViewObject) { // Can't speceify both an object and // a clsid C_ASSERT(0); } pViewObject = rDerived.GetViewObject();}…
9
Resource Allocation Is Initialization (RAII)
RAII is used with all resources to ensure their lifetime is properly managed in the face of exceptions.
template <...>class Resource{ ResourceType m_Resource; Resource(): m_Resource(Values::GetNullValue()) {} Resource(ResourceType resource): m_Resource(resource) {} ~Resource() { Free(); } void Free(); ResourceType Detach(); operator CastType() const;};
10
eXtendened Resource Allocation Is Initialization (XRAII)
RAII is extended to any set of calls that need balancing.
class Suspend{ Suspend(This& rThis): m_rThis(rThis) { m_rThis.SendMessage(WM_SETREDRAW, FALSE, 0); m_dwMaskToRestore = static_cast<DWORD>(m_rThis.SendMessage( EM_SETEVENTMASK, 0, ENM_NONE)); } ~SuspendDrawAndNotifications() { m_rThis.SendMessage( EM_SETEVENTMASK, 0, m_dwMaskToRestore); m_rThis.SendMessage(WM_SETREDRAW, TRUE, 0); } This& m_rThis; DWORD m_dwMaskToRestore;};
11
Facilitate unit testing
•Mocks for nearly all VS Platform interfaces•Mocks for many Windows Platform interfaces•Wrapper classes around some sets of Win32 APIs•Mocks for those classes
CursorCursorMockFileFileMockKeyboardKeyboardMockWindowWindowMock
12
Re-use without obstruction
Many classes take template parameters•Allows you to provide your own custom implementation for a dependency•Some template defaults will be correct for 99% of cases
A couple of classes using policy based design•a smart pointer and a smart resource
Optional statically bound call backs into a derived class•This is accomplished via __if_exists and __if_notexists
Numerous macros that can be overridden
13
Responsive to requests
VS SDK release cycle is short•CTP monthly•RTW every 4 months
Designs are never perfect the first time•Even more so when on short cycle
Breaking changes will be made as the demand arises•Short cycle means there won’t be a lot of BCs with any given release
14
VSL provides help with…
•Error and exception handling•Unit testing•Functors and delegates•Comparing various things•Managing resources•The basics necessary to create a VS Package•Command handling•VS Service consumption•Creating a VS Window that hosts a dialog or Win32 control•Creating a VS Document / VS Editor•Automation and VS Macro recording•VS Hierarchies
15
Error and exception handling
Error handling macros that convert errors to exceptions
Exception handling macros that catch and convert exceptions to HRESULTs
VSL_BEGIN_MSG_MAP – message map that catches exceptions
Header files:•VSLErrorHandlers.h•VSLExceptionHandlers.h
VSL_STDMETHODTRY{
VSL_CHECKHANDLE_GLE(::GetDC(hWnd));
}VSL_STDMETHODCATCH()
return VSL_GET_STDMETHOD_HRESULT();
16
Unit testing
•Unit testing framework•Mocks for nearly all VS Platform interfaces•Mocks for many Windows Platform interfaces•Mocks for wrapper classes around some sets of Win32 APIs•Including some of ATL::CWindow
Header files:•VSLUnitTest.h
class UnitTest :
public UnitTestBase
{
UnitTest(
const char* const szTestName):
UnitTestBase(szTestName)
{
UTCHK(false);
}
};
int _cdecl _tmain(int, _TCHAR*)
{
UTRUN(UnitTest);
return VSL::FailureCounter::Get();
}
17
Functors and delegates
Classes:•Functor•FunctionPointerFunctor•MemberFunctionPointerFunctor•Delegate
Header Files:•VSLCommon.h
FunctionPointerFunctor<void ()>
functor(&OnEvent1);
Delegate<void ()> event1;
event1 += functor;
event1();
event1 -= functor();
18
Comparing various things
•Implemented primarily for the interface mocks•IsStringLessThen can be used with STL algorithms
•Header files:•VSLComparison.h
19
Managing resources
Policy based resource managers:•Pointer•Resource
Header files:•VSLCommon.h•VSLFont.h
typedef Pointer<CoTaskMemPointerTraits> CoTaskMemPointer;
CoTaskMemPointer pBuffer = ::CoTaskMemAlloc(iBufferByteSize);
CHKPTR(static_cast<LPVOID>(pBuffer), E_OUTOFMEMORY);
CHK(0 == ::memcpy_s(pBuffer, iBufferByteSize, GetFileName(), iBufferByteSize), E_FAIL);
*ppszFilename = static_cast<LPOLESTR>(pBuffer.Detach());
20
The basics necessary to create a VS Package
Classes:•IVsPackageImpl•IVsInstalledProductImpl
Registry map macros
Header files:•VSLPackage.h
class Package :
public IVsPackageImpl<
Package,
&CLSID_Package>,
public IVsInstalledProductImpl<
IDS_PRODUCT_NAME,
IDS_PRODUCT_IDENTIFIER,
IDS_PRODUCT_DETAILS,
IDI_ LOGO>
{
VSL_BEGIN_REGISTRY_MAP(IDR_PACKAGE_RGS)
...
VSL_END_REGISTRY_MAP()
21
VsSiteCache
Can be local or global
IVsPackageImpl uses the global VsSiteCache by default•Once a package is sited anything can then use the global cache by creating an instance of VsSiteCacheGlobal or utilizing the static methods of VsIServiceProviderUtilities directly or via the macros:•VSQS - VsIServiceProviderUtilities<>::QueryService•VSQCS - VsIServiceProviderUtilities<>::QueryCachedService
IVsPaneWindow uses the local VsSiteCache by default•Once window is sited can correctly get context sensitive services like SID_STrackSelection and SID_SVsWindowFrame
22
Command handling
Classes:•IOleCommandTargetImpl•Command map macros•VsFontCommandHandling
Header files:•VSLCommandTarget.h
Samples:•Menus and Commands•Services•Tool Window•Single View Editor
class MenuAndCommandsPackage : ... public IOleCommandTargetImpl< MenuAndCommandsPackage>,...VSL_BEGIN_COMMAND_MAP() VSL_COMMAND_MAP_ENTRY( GUID_MenuAndCommandsCmdSet, cmdidMyCommand, NULL, &MenuCommandCallback) VSL_COMMAND_MAP_ENTRY_WITH_FLAGS( GUID_MenuAndCommandsCmdSet, cmdidDynVisibility2, NULL, &MenuVisibilityCallback, OLECMDF_SUPPORTED | OLECMDF_ENABLED | OLECMDF_INVISIBLE)VSL_END_VSCOMMAND_MAP()...
23
VS Service consumption
Wrapped VS Services:•VsOutputWindowUtilities•ProfferServiceUtilities•OleComponentUIManagerUtilities
Can use global or local VsSiteCache.
OleComponentUIManagerUtilities<>::ShowMessage(
L"Title",
L"Message");
Header files:•VSLPackage.h
Samples:•Menus and Command•Services•Tool Window•Single View Editor
24
Creating a VS Window that hosts a dialog
Classes:•IVsWindowPaneImpl•Window•VsWindowPaneFromResource
Header files:•VSLWindows.h
class Form :
public VsWindowPaneFromResource<
Form,
MAKEINTRESOURCE(IDD_DLG)>
25
Creating a VS Window that hosts a Win32 control
Classes:•IVsWindowPaneImpl•Window•ListViewWin32Control•RichEditWin32Control•Win32ControlContainer
Header files:•VSLControls.h•VSLWindows.h
class Document :
public Win32ControlContainer<
RichEditWin32Control<> >
class Report :
public Win32ControlContainer<
ListViewWin32Control<
ReportViewTraits<
false,
false> > >
26
Fully integrating a VS Window
Classes•VsWindowFrameEventSink•ISelectionContainerImpl•ISelectionContainerSingleItemImpl
Header files•VSLWindows.h
class WindowPane :
public IVsWindowPaneImpl<WindowPane>,
public VsWindowFrameEventSink<WindowPane>,
public ISomeInterface,
public ISelectionContainerSingleItemImpl<
WindowPane,
ISomeInterface>
27
Creating a VS Document / VS Editor
Classes:•IVsEditorFactoryImpl•IVsFindTargetImpl•SingleViewFindInFilesOutputWindowIntegrationImpl•File•DocumentPersistanceBase
Header Files:•VSLFile.h•VSLFindAndReplace.h•VSLWindow.h
Samples:•Single View Editor
28
Automation and VS Macro recording
Classes:•IExtensibleObjectImpl•VsMacroRecorder
Header Files:•VSLAutomation.h
Samples:•Single View Editor
void RecordCommand(
wchar_t* szCommand)
{
if(m_Recorder.IsRecording(
GetVsSiteCache()))
{
CStringW strLine =
L"ActiveDocument.Object.";
strLine += szCommand;
m_Recorder.RecordLine(
strLine);
}
}
29
Classes:•IVsHierarchyImpl•IVsUIHierarchyImpl•IVsHierarchyEventsDelegate•VsHierarchyRootItemBase•VsHierarchyItemBase•VsUIHierarchyItemBase•VsHierarchyRootItemBase•HierarchyNode
C++ Interfaces:•IVsHierarchyItem•IVsUIHierarchyItem•IVsHierarchyRootItem•IVsUIHierarchyRootItem
Header Files:•VSLHierarchy.h•VSLHierarchyNode.h
Samples:•Extensiblity Explorer
30
Miscellaneous Win32 Resource Managers/Wrappers
Classes:•Library – HMODULE’s from ::LoadLibrary•DeviceContext – HDC’s from ::GetDC•Cursor – HCURSOR from ::LoadCursor•Keyboard
These classes only provide what was necessary for the reference samples, but can be easily expanded as needed. For example:•Library has no methods (just constructor/destructor)•DeviceContext only has EnumFontFamiliesExW•Cursor only has Activate•Keyboard only has IsKeyDown
31
Data Collection
Do you:•Have existing packages written in C++?•Use VSL in C++ packages?•Plan to use VSL in C++ packages in the future?•Unit test existing C++ packages?•Use VSL for unit testing C++ packages?•Plan to use VSL for unit testing C++ packages in the future?•Plan to write new packages in C++ in the future?•What kind of package (project system, editor, designer, etc.)?
•Plan to expand add additional features in C++?•What type of features?
•Want better tools for creating scenario tests?•Want sample scenario tests?
32
Data Collection continued
•Plan to migrate existing C++ package to managed?•C++/CLI?•C#?•Other?•Over what time frame?