DOCUMENT:Q247035 15-MAY-2002 [visualc] TITLE :HOWTO: Automate Visual C++ PRODUCT :Microsoft C Compiler PROD/VER::5.0,6.0 OPER/SYS: KEYWORDS:kbAutomation kbide kbVC500 kbVC600 kbVCObj kbDevStudio kbDSupport kbGrpDSTools ====================================================================== ------------------------------------------------------------------------------- The information in this article applies to: - Microsoft Visual C++, 32-bit Enterprise Edition, versions 5.0, 6.0 - Microsoft Visual C++, 32-bit Professional Edition, versions 5.0, 6.0 - Microsoft Visual C++, 32-bit Learning Edition, version 6.0 ------------------------------------------------------------------------------- SUMMARY ======= The Developer Studio object model introduced with Visual C++ 5.0 provides COM objects for automation. The objects are manipulated using methods, properties, and events associated with the objects. You can automate tasks in the Visual C++ environment using these objects. This article provides sample code that utilizes two different approaches to automating Visual C++. The first method uses #include to include Visual C++ automation header files and the second method uses #import to import Visual C++ type libraries. The sample code provided in the "More Information" section does the following: 1. Launches Visual C++. 2. Opens a workspace that you have specified on the command line. 3. Enumerates all the projects in the workspace and displays their names. 4. Enumerates all the configurations of individual projects in the workspace and displays their names. 5. Builds all the projects in all their configurations. 6. Displays the active project name. 7. Quits Visual C++. NOTE: The sample code provided in the following sections is not supported by Microsoft. MORE INFORMATION ================ Visual C++ Automation Using #include ------------------------------------ 1. Using the "Win32 Console Application" AppWizard, create a new "Hello World" project named "VCAutomationMethod1" (without the quotation marks). 2. Open the generated VCAutomationMethod1.cpp and add the following code after #include "stdafx.h" and before the main() function: #include //These are required for creating com components, CComPtr, CComBSTR, CComPtr //and CComQIPtr. #include extern CComModule _Module; #include #include #include /*The following header files are used for these objects: 1. Application 2. Document 3. Documents 4. Window 5. Windows */ #include #include #include /*The following header files are used for these objects: 1. BuildProject 2. Configuration 3. Configurations 4. Project 5. Projects */ #include #include #include /*The following header files are used for these objects: 1. TextDocument 2. TextEditor 3. TextSelection 4. TextWindow */ #include #include #include /*The following header files are used for these objects: 1. Breakpoint 2. Breakpoints 3. Debugger */ #include #include #include 3. Replace the entire main() function with the following code: IApplication *pApp; //Initialize COM and VC++ BOOL InitializeCOMandVC() { //Initialize COM libraries HRESULT hr = CoInitialize(NULL); if(FAILED(hr)) { printf("Failed to initialize the COM libraries\n"); return FALSE; } //Obtain the IApplication pointer hr = CoCreateInstance(CLSID_Application, NULL, CLSCTX_LOCAL_SERVER, IID_IApplication, (void**)&pApp); if(FAILED(hr)) { printf("Failed to create an instance of MSDEV\n"); CoUninitialize(); return FALSE; } return TRUE; } //Uninitialize COM and VC++ void UnInitializeCOMandVC() { //Quit from Visual C++ pApp->Quit(); pApp=NULL; //Uninitialize COM libraries CoUninitialize(); } BOOL PerformTask(char workspace_name[]) { HRESULT hr; //Set the visibility of MSDEV to TRUE VARIANT_BOOL visibility=VARIANT_TRUE; hr = pApp->put_Visible(visibility); if(FAILED(hr)) { printf("Failed to set visibility of MSDEV\n"); //Uninitialize COM libraries and quit from Visual C++ UnInitializeCOMandVC(); return FALSE; } CComPtr iDisp=NULL; //Obtain the IDocuments pointer using smart pointer classes pApp->get_Documents(&iDisp); CComQIPtr pDocs(iDisp); //Open the workspace passed as the command line argument CComBSTR fname(workspace_name); CComVariant type="Auto"; CComVariant read="False"; iDisp=NULL; hr = pDocs->Open(fname,type,read,&iDisp); if(FAILED(hr)) { printf("Failed to open the workspace: %s\n",workspace_name); //Uninitialize COM libraries and quit from Visual C++ UnInitializeCOMandVC(); return FALSE; } //Obtain the IProjects pointer using smart pointer classes iDisp=NULL; pApp->get_Projects(&iDisp); CComQIPtr pProjects(iDisp); //Obtain the number of projects in the workspace long count; pProjects->get_Count(&count); printf("Number of projects = %d\n",count); CComVariant index; //CComVariant conf CComPtr pProject; CComQIPtr pBldProject; CComPtr pConfigs; CComPtr pConfig; long numconfigs; CComBSTR projname; CComBSTR configname; CComBSTR projtype; _bstr_t temp; //The outer loop will enumerate projects for(int i=1; i <= count; i++) { index=i; //Obtain the IGenericProject pointer pProjects->Item(index, &pProject); //Obtain the IBuildProject pointer pBldProject=pProject; //Print the name of the project pProject->get_Name(&projname); temp=projname.m_str; printf("Project name %s\n",(char *) temp); //Obtain the IConfigurations pointer pBldProject->get_Configurations(&pConfigs); //Obtain the number of configurations for the project pConfigs->get_Count(&numconfigs); printf("Number of configurations = %d\n",numconfigs); //Obtain the project type pBldProject->get_Type(&projtype); //The inner loop will enumerate configurations of the individual projects for(int j=1; j <= numconfigs; j++) { index=j; //Obtain the IConfiguration pointer pConfigs->Item(index, &pConfig); //Print the name of the configuration pConfig->get_Name(&configname); temp=configname.m_str; printf("Configuration name %s\n",(char *) temp); //If the project is buildable then build it if(projtype == "Build") { printf("Building the project\n"); CComVariant VarDisp = pConfig; pApp->Build(VarDisp); } pConfig=NULL; } pConfigs=NULL; pProject=NULL; } //Obtain the active project and display the name iDisp=NULL; pApp->get_ActiveProject(&iDisp); CComQIPtr pActiveProj(iDisp); iDisp=NULL; pActiveProj->get_Name(&projname); temp=projname.m_str; printf("Active Project name %s\n",(char *) temp); return TRUE; } int main(int argc, char* argv[]) { if(argc != 2) { printf("USAGE: VCAutomationMethod1.exe \n"); return 0; } // does the workspace file exist ? if( -1 == GetFileAttributes((LPCTSTR)argv[1]) ) { LPVOID lpMsgBuf; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR) &lpMsgBuf, 0, NULL ); printf("%s:%s\n",argv[1],(LPCTSTR)lpMsgBuf); // Free the buffer. LocalFree( lpMsgBuf ); return 0; } //Initialize COM libraries and create an instance of IApplication if(InitializeCOMandVC() == FALSE) return 0; //Perform the designated task if(PerformTask(argv[1]) == FALSE) { printf("An error has occurred\n"); return 0; } else printf("The task completed successfully\n"); //Uninitialize COM libraries and quit from Visual C++ UnInitializeCOMandVC(); return 0; } 4. Select Build VCAutomationMethod1.exe from the Build menu to create the executable. Visual C++ Automation Using #import ----------------------------------- 1. Using the "Win32 Console Application" AppWizard, create a new "Hello World" project named "VCAutomationMethod2" (without the quotation marks). 2. Open the generated VCAutomationMethod2.cpp and add the following code after #include "stdafx.h" and before the main() function: #include //These are required for creating com components, CComPtr, CComBSTR, CComPtr //and CComQIPtr. #include extern CComModule _Module; #include #include #include #import using namespace DSSharedObjects; #import using namespace DSTextEditor; #import using namespace DSProjectSystem; #import using namespace DSDebugger; 3. Replace the entire main() function with the following code: DSSharedObjects::IApplicationPtr pApp; //Initialize COM and VC++ BOOL InitializeCOMandVC() { HRESULT hr = CoInitialize(NULL); if(FAILED(hr)) { printf("Failed to initialize the COM libraries\n"); return FALSE; } //Obtain the IApplication pointer hr=pApp.CreateInstance("MSDEV.Application"); if(FAILED(hr)) { printf("Failed to create an instance of MSDEV"); CoUninitialize(); return FALSE; } return TRUE; } //Uninitialize COM and VC++ void UnInitializeCOMandVC() { //Quit from MSDEV pApp->Quit(); pApp=NULL; //Uninitialize COM libraries CoUninitialize(); } BOOL PerformTask(char workspace_name[]) { DSSharedObjects::IProjectsPtr pProjects; DSSharedObjects::IGenericProjectPtr pProject; DSSharedObjects::IGenericProjectPtr pActiveProject; DSProjectSystem::IBuildProjectPtr pBldProject; DSProjectSystem::IConfigurationsPtr pConfigs; DSProjectSystem::IConfigurationPtr pConfig; DSSharedObjects::IDocumentsPtr pDocs; HRESULT hr; //Set the visibility of MSDEV to TRUE pApp->Visible=VARIANT_TRUE; //Open the workspace passed as the command line argument pDocs=pApp->Documents; _bstr_t fname(workspace_name); CComVariant type="Auto"; CComVariant read="False"; hr = pDocs->Open(fname,type,read); if(FAILED(hr)) { printf("Failed to open the workspace: %s\n",workspace_name); //Uninitialize COM libraries and quit from Visual C++ UnInitializeCOMandVC(); return FALSE; } //Obtain the IProjects pointer using smart pointers pProjects=pApp->Projects; //Obtain the number of projects in the workspace long count; count=pProjects->Count; printf("Number of projects = %d\n",count); CComVariant index; _bstr_t projtype; _bstr_t projname; _bstr_t configname; long numconfigs; //The outer loop will enumerate projects for(int i=1; i <= count; i++) { index=i; //Obtain the IGenericProject pointer pProject=pProjects->Item(index); //Obtain the IBuildProject pointer pBldProject=pProject; //Print the name of the project projname=pProject->Name; printf("Project name %s\n",(char *) projname); //Obtain the IConfigurations pointer pConfigs=pBldProject->Configurations; //Obtain the number of configurations for the project numconfigs=pConfigs->Count; printf("Number of configurations = %d\n",numconfigs); //Obtain the project type projtype=pProject->Type; //The inner loop will enumerate configurations of the individual projects for(int j=1; j <= numconfigs; j++) { index=j; //Obtain the IConfiguration pointer pConfig=pConfigs->Item(index); //Print the name of the configuration configname=pConfig->Name; printf("Configuration name %s\n",(char *) configname); //If the project is buildable then build it if(!strcmp((char *)projtype, "Build")) { printf("Building the project\n"); //Pass the IConfiguration pointer to Build pApp->Build(pConfig.GetInterfacePtr()); } } } //Obtain the active project and display the name pActiveProject=pApp->ActiveProject; projname=pActiveProject->Name; printf("Active Project name %s\n",(char *) projname); return TRUE; } int main(int argc, char* argv[]) { if(argc != 2) { printf("USAGE: VCAutomationMethod2.exe \n"); return 0; } // does the workspace file exist ? if( -1 == GetFileAttributes((LPCTSTR)argv[1]) ) { LPVOID lpMsgBuf; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR) &lpMsgBuf, 0, NULL ); printf("%s:%s\n",argv[1],(LPCTSTR)lpMsgBuf); // Free the buffer. LocalFree( lpMsgBuf ); return 0; } //Initialize COM libraries and create an instance of IApplication if(InitializeCOMandVC() == FALSE) return 0; //Perform the designated task if(PerformTask(argv[1]) == FALSE) { printf("An error has occurred\n"); return 0; } else printf("The task completed successfully\n"); //Uninitialize COM libraries and quit from Visual C++ UnInitializeCOMandVC(); return 0; } 4. Select Build VCAutomationMethod2.exe from the Build menu to create the executable. This automation code will execute to completion only if no message boxes are displayed by Visual C++. So, before you start using the executables, you may want to take the following precautions: - Disable "Tip of the Day": Select Tip of the Day from the Help menu, clear Show tips at startup, and click Close. - Open your workspace at least once to ensure that Visual C++ doesn't display message boxes. REFERENCES ========== MSDN Library: Visual Studio 6.0 Documentation; Visual C++ Documentation; Using Visual C++; Visual C++ User's Guide; Automating Tasks in Visual C++; Developer Studio Objects For additional information, click the article numbers below to view the articles in the Microsoft Knowledge Base: Q200074 BUG: Can't Get IBuildProject Interface From Developer Studio Q192912 PRB: MSDev Doesn't Close When COM Reference Count Is Zero Additional query words: ====================================================================== Keywords : kbAutomation kbide kbVC500 kbVC600 kbVCObj kbDevStudio kbDSupport kbGrpDSTools Technology : kbVCsearch kbAudDeveloper kbVC500 kbVC600 kbVC32bitSearch kbVC500Search Version : :5.0,6.0 Issue type : kbhowto ============================================================================= THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY. Copyright Microsoft Corporation 2002.