1 / 22

Programming ArcObjects with VC++

Programming ArcObjects with VC++. Lesson 2 overview. VC++ and ArcObjects/COM programming review How to import type libraries Smart pointers COM data types, HRESULTs , strings, and variants Microsoft Visual Studio Exercise 2: Simple console application.

johnsont
Download Presentation

Programming ArcObjects with VC++

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Programming ArcObjects with VC++

  2. Lesson 2 overview • VC++ and ArcObjects/COM programming review • How to import type libraries • Smart pointers • COM data types, HRESULTs, strings, and variants • Microsoft Visual Studio • Exercise 2: Simple console application

  3. How VC++ facilitates ArcObjects development • Client-side COM support • Native compiler support: Direct-To-COM (DTC) • #import directive to import type libraries • Support classes for standard OLE types (BSTRs, VARIANTs, …) • Server-side COM support • ATL (Active Template Library) • Templates and wizards for building COM objects and servers

  4. Importing the ArcObjects library • #importmodifiers are required • Specify esriCore.olb path: Tools > Options > Directories // stdafx.h #pragma warning(push) // Sets the current warning state #pragma warning(disable : 4146) // Ignore –2147483648 for uint #pragma warning(disable : 4192) // Exclude‘name’ while importing #import "c:\arcgis\arcexe81\bin\esriCore.olb" \ // Type lib to generate C++ mapping raw_interfaces_only, \ // Don’t add raw_ to method names raw_native_types, \ // Don’t map to DTC smart types no_namespace, \ // Don’t wrap with C++ name space named_guids, \ // Named guids and declspecs exclude("OLE_COLOR", "OLE_HANDLE") // Exclude conflicting types #pragma warning(pop) // Restores state of warnings – undo Instructor Demo

  5. ArcObjects wrapper classes • #import automatically generates type library wrappers • Creates typedefs, smart pointers, structures… // Created by Microsoft (R) C/C++ Compiler Version 12.00.8168.0 (d727fb44). // // c:\student\arcobjectscpp\exercises\(1) - cpp\aoconsoleapp_solution\debug\esriCore.tlh // // C++ source equivalent of Win32 type library esriCore.olb // compiler-generated file created 12/20/01 at 11:33:49 - DO NOT EDIT! … /* interface */IMap; struct __declspec(uuid("34b2ef81-f4ac-11d1-a245-080009b6f22b")) … extern "C" const GUID __declspec(selectany) CLSID_Map = {0xe6bdaa76,0x4d35,0x11d0,{0x98,0xbe,0x00,0x80,0x5f,0x7c,0xed,0x21}}; … _COM_SMARTPTR_TYPEDEF(IMap, __uuidof(IMap)); Typedef _com_ptr_t<_com_IIID<IMap, __uuidof(IMap)>> IMapPtr; … struct __declspec(uuid("e6bdaa75-4d35-11d0-98be-00805f7ced21")) IMap : IUnknown { // Raw methods provided by interface virtual HRESULT __stdcall get_Name ( BSTR * Name ) = 0; virtual HRESULT __stdcall put_Name ( BSTR Name ) = 0; …

  6. DTC smart types • VC++ classes that encapsulate data types • _com_ptr_t<> Encapsulates a COM interface pointer (smart pointer) • _bstr_t Encapsulates the BSTR data type • _variant_t Encapsulates variant type and automatically initializes • _com_error Represents a COM exception using IErrorInfo • Classes behave like raw types • Helpful constructors, functions, and operators • Maps all COM errors to C++ exceptions • Use to simplify ArcObjects code…

  7. Initializing the COM library • Necessary for stand-alone ArcObjects applications • Steps 1. ::CoInitialize() - Loads the COM libraries 2. Cocreate and use ArcObjects objects 3. ::CoUninitialize() - Unloads COM libraries #include "stdafx.h" int main(int argc, char* argv[]) { ::CoInitialize(NULL); IMapPtr ipMap(CLSID_Map); // Simple code to create and call COM objects int iLayers; ipMap->get_LayerCount(&iLayers); _tprint(“Number of layers: %i \n“, iLayers); ::CoUninitialize(); }

  8. Creating new ArcObjects objects • COM API – ::CoCreateInstance() • DTC smart pointers – Simplified but less control… // CoCreate a Map IMap* pMap; HRESULT hr = ::CoCreateInstance( CLSID_Map, // Class identifier (CLSID) of the object 0, // Pointer to outer unknown pointer CLSCTX_ALL, // Context for running executable code IID_IMap, // Reference to the interface identifier (void **) &pMap // Indirect pointer to requested interface ); if (FAILED(hr)) return hr; // Check HRESULT… // CoCreate a Map IMapPtr ipMap(CLSID_Map); if (ipMap == NULL) return E_POINTER; // Check for NULL

  9. Querying interfaces • COM API – IUnknown::QueryInterface() • DTC smart pointers – Use assignment operator // CoCreate a Map IMap* pIMap; ::CoCreateInstance(CLSID_Map, 0, CLSCTX_ALL, IID_IMap, (void **) &pMap); IActiveView* pActiveView; pMap->QueryInterface(IID_IActiveView, (void **) &pActiveView); // QI // CoCreate a Map IMapPtr ipMap(CLSID_Map); // QI IActiveViewPtr ipActiveView(ipMap); // QI // or use the assignment “=“ operator directly IActiveViewPtr ipActiveView; ipActiveView = ipMap; // QI

  10. Object lifetime control: Smart pointers // Smart pointer reference count test long refCount; // CoCreate the SimpleObject IUnknownPtr ipUnk(CLSID_SimpleObject); // AddRef ISimpleObjectPtr ipMagic(ipUnk); // AddRef ipMagic->get_ReferenceCount(&refCount); IAnotherInterfacePtr ipMagic2(ipMagic); // AddRef ipMagic->get_ReferenceCount(&refCount); ipMagic2 = NULL; // What happens? ipMagic->get_ReferenceCount(&refCount); ipMagic = NULL; // What happens? // What happens to ipUnk here? ::CoCreateInstance(CLSID_SimpleObject, 0, CLSCTX_ALL, IID_IUnknown, (void **) &ipUnk); ipUnk = NULL; Instructor Demo

  11. COM data type mapping Language IDL Microsoft C++ Visual Basic Microsoft Java Boolean unsigned char unsupported char byte unsigned char unsupported char small char unsupported char short short Integer short long long Long int Base hyper __int64 unsupported long Types float float Single float double double Double double char unsigned char unsupported char wchar_t wchar_t Integer short enum enum Enum int Interface Pointer Interface Pointer Interface Ref. Interface Ref. Extended VARIANT VARIANT Variant ms.com.Variant Types BSTR BSTR String java.lang.String VARIANT_BOOL short (-1 true/0 false) Boolean [true/false]

  12. BSTRs • COM API – SysAllocString, SysStringLen, SysFreeString • DTC smart type – _bstr_t int main(int argc, char* argv[]) { BSTR bstrDBPath = ::SysAllocString(L"..\\..\\..\\Data\\US.mdb"); BSTR bstrFCName = ::SysAllocString(L"States"); IFeatureClassPtr ipFeatureClass; SelectFeatureClass1(bstrDBPath, bstrFCName, &ipFeatureClass); ::SysFreeString(bstrDBPath); ::SysFreeString(bstrFCName); } int main(int argc, char* argv[]) { _bstr_t bstrDBPath(L"..\\..\\..\\Data\\US.mdb"); _bstr_t bstrFCName(L"States"); IFeatureClassPtr ipFeatureClass; SelectFeatureClass1(bstrDBPath, bstrFCName, &ipFeatureClass); }

  13. VARIANTs • COM API – VariantInit() and VariantClear() • DTC smart type – _variant_t long l = 1000; VARIANT vValue1; ::VariantInit(&vValue1); vValue1.vt = VT_R4; // Set variant type here vValue1.lVal = l; printf("The value is: %d\n", vValue1.lVal); ::VariantClear(&vValue1); long l = 1000; _variant_t vValue2(l); printf("The value is: %d\n", vValue2.lVal);

  14. Not so smart smart types • Understand the behavior beforehand // Variant and smart pointer test IUnknownPtr ipUnk(CLSID_SimpleObject); // Create an object #1 _variant_t vValue; vValue.vt = VT_UNKNOWN; vValue.punkVal = ipUnk;// What happens? ipMagic = ipUnk; ipMagic->get_ReferenceCount(&refCount); // Release these ipMagic = 0; ipUnk = 0; vValue.punkVal->QueryInterface(&ipMagic2); // What happens? ipMagic2 = 0; vValue.vt = VT_EMPTY; // What happens now?What is missing from this code? Instructor Demo

  15. HRESULTs • Always check HRESULTs returned by ArcObjects • Use SUCCEEDED() or FAILED() macros • Non-zero severity means failed HRESULT hr; IWorkspaceFactoryPtr ipWorkspaceFactory(CLSID_AccessWorkspaceFactory); if (ipWorkspaceFactory == NULL) return E_FAIL; IWorkspacePtr ipWorkspace; if (FAILED(hr = ipWorkspaceFactory->OpenFromFile(bstrDatabasePath, NULL, &ipWorkspace))) return hr; …

  16. Formatting HRESULTs • Possible to get and display the error code message int main(int argc, char* argv[]) { IMapPtr ipMap(CLSID_Map); IMxDocument ipMxDoc; if (FAILED(hr = ipMap->QueryInterface(&ipMxDoc)))// Force a failed HRESULT HRESULTMESSAGE(hr); } inline void HRESULTMESSAGE( HRESULT hr ) { LPVOID lpMsgBuf; ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr, // HRESULT MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL ); _TCHAR buf[256]; _stprintf( buf, "%s", (_TCHAR *) lpMsgBuf ); ::LocalFree( lpMsgBuf ); MessageBox(0, buf, _T("HRESULT ERROR MESSAGE"), MB_OK | MB_ICONINFORMATION ); }

  17. Exception handling for DTC types • Native DTC classes throw _com_error exceptions • _com_error • Wraps IErrorInfo object • Returns: Description, HelpContext, HelpFile, Source try { // Force smart pointer error... IMapPtr ipMap; IActiveViewPtr ipAV; ipMap->QueryInterface(&ipAV); } catch (_com_error & err) { ErrorHandler(err); } void ErrorHandler(_com_error err) { _bstr_t bstrError; if (&err == NULL) return; bstrError = _T("Smart type error:"+ err.Description().length() > 0 ? (LPCTSTR) err.Description() : err.ErrorMessage()); ::MessageBox(NULL, bstrError, _T("Generic Error"), MB_OK | MB_TASKMODAL); }

  18. Developing console applications • Database related – Adding, deleting, and updating • Utility applications – Print jobs, describe feature classes int main(int argc, char* argv[]) { CoInitialize(NULL); HRESULT hr; IFeatureClassPtr ipFeatureClass; _bstr_t bstrDBPath(L"..\\..\\..\\Data\\US.mdb"); _bstr_t bstrFCName(L"States"); hr = SelectFeatureClass1(bstrDBPath, bstrFCName, &ipFeatureClass); if (FAILED(hr)) return -1; ::MessageBox(0, _T("Found feature class!"), _T("Console Applicaiton"), MB_OK); hr = PrintFeatureClassInformation(ipFeatureClass); if (FAILED(hr)) return -1; ::MessageBox(0, _T("Printed feature class info!"), _T("Console Applicaiton"), MB_OK); CoUninitialize(); return 0; }

  19. Writing ArcObjects/Visual Studio exercises • Some VS projects are written from scratch • Format-related • All code inserts are prefixed with file name (e.g., File.h) • ‘…’ means ‘scroll down until you find’ • Some steps have ‘step insert numbers’ • Bold means ‘write code’ // MBFeature.h : Declaration of the CMBFeature … public: CMBFeature() : m_pInnerUnk(NULL) { } // ----------- Step 2.6 ---------- DECLARE_GET_CONTROLLING_UNKNOWN() … BEGIN_COM_MAP(CMBFeature) COM_INTERFACE_ENTRY(IMBFeature) COM_INTERFACE_ENTRY(ISupportErrorInfo) COM_INTERFACE_ENTRY(IFeatureDraw) END_COM_MAP() };

  20. More exercise hints… • Follow conventions • Project and class names • Project and file paths • Copy and paste ExerciseFunctions.h file • Use exercise shortcuts • Be careful cutting and pasting solutions

  21. Exercise 2 overview • Create a single ArcObjects COM client • Import the esriCore.olb correctly • Initialize the COM library • Accesses a geodatabase • Print featureclass name and field information • Challenge: Provide client-side error handling

  22. Review • What is the first thing you need to do to work with ArcObjects in VC++? • Why might you want to create an ArcObjects console-type application? • What are the dangers of using smart types? • True or False: VARIANT_TRUE = 1 and VARIANT_FALSE = 0?

More Related