Programming ArcObjects with VC++
description
Transcript of Programming ArcObjects with VC++
Copyright © 2002 ESRI. All rights reserved. Advanced ArcObjects Component Development II (C++)
Programming ArcObjects with VC++
2-2Advanced ArcObjects Component Development II (C++)Copyright © 2002 ESRI. All rights reserved.
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
2-3Advanced ArcObjects Component Development II (C++)Copyright © 2002 ESRI. All rights reserved.
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
2-4Advanced ArcObjects Component Development II (C++)Copyright © 2002 ESRI. All rights reserved.
Importing the ArcObjects library
#import modifiers 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
// 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 DemoInstructor Demo
2-5Advanced ArcObjects Component Development II (C++)Copyright © 2002 ESRI. All rights reserved.
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;…
// 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;…
2-6Advanced ArcObjects Component Development II (C++)Copyright © 2002 ESRI. All rights reserved.
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…
2-7Advanced ArcObjects Component Development II (C++)Copyright © 2002 ESRI. All rights reserved.
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();}
#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();}
2-8Advanced ArcObjects Component Development II (C++)Copyright © 2002 ESRI. All rights reserved.
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
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
// CoCreate a Map
IMapPtr ipMap(CLSID_Map);
if (ipMap == NULL) return E_POINTER; // Check for NULL
2-9Advanced ArcObjects Component Development II (C++)Copyright © 2002 ESRI. All rights reserved.
Querying interfaces
COM API – IUnknown::QueryInterface()
DTC smart pointers – Use assignment operator
// CoCreate a MapIMap* pIMap;::CoCreateInstance(CLSID_Map, 0, CLSCTX_ALL, IID_IMap, (void **) &pMap);
IActiveView* pActiveView;pMap->QueryInterface(IID_IActiveView, (void **) &pActiveView); // QI
// CoCreate a MapIMap* pIMap;::CoCreateInstance(CLSID_Map, 0, CLSCTX_ALL, IID_IMap, (void **) &pMap);
IActiveView* pActiveView;pMap->QueryInterface(IID_IActiveView, (void **) &pActiveView); // QI
// CoCreate a MapIMapPtr ipMap(CLSID_Map); // QI
IActiveViewPtr ipActiveView(ipMap); // QI
// or use the assignment “=“ operator directly
IActiveViewPtr ipActiveView;ipActiveView = ipMap; // QI
// CoCreate a MapIMapPtr ipMap(CLSID_Map); // QI
IActiveViewPtr ipActiveView(ipMap); // QI
// or use the assignment “=“ operator directly
IActiveViewPtr ipActiveView;ipActiveView = ipMap; // QI
2-10
Advanced ArcObjects Component Development II (C++)Copyright © 2002 ESRI. All rights reserved.
Object lifetime control: Smart pointers
// Smart pointer reference count test
long refCount;
// CoCreate the SimpleObjectIUnknownPtr ipUnk(CLSID_SimpleObject); // AddRef
ISimpleObjectPtr ipMagic(ipUnk); // AddRefipMagic->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;
// Smart pointer reference count test
long refCount;
// CoCreate the SimpleObjectIUnknownPtr ipUnk(CLSID_SimpleObject); // AddRef
ISimpleObjectPtr ipMagic(ipUnk); // AddRefipMagic->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 DemoInstructor Demo
2-11
Advanced ArcObjects Component Development II (C++)Copyright © 2002 ESRI. All rights reserved.
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]
2-12
Advanced ArcObjects Component Development II (C++)Copyright © 2002 ESRI. All rights reserved.
BSTRs
COM API – SysAllocString, SysStringLen, SysFreeString
DTC smart type – _bstr_t
int main(int argc, char* argv[]){ _bstr_t bstrDBPath(L"..\\..\\..\\Data\\US.mdb"); _bstr_t bstrFCName(L"States"); IFeatureClassPtr ipFeatureClass; SelectFeatureClass1(bstrDBPath, bstrFCName, &ipFeatureClass);}
int main(int argc, char* argv[]){ _bstr_t bstrDBPath(L"..\\..\\..\\Data\\US.mdb"); _bstr_t bstrFCName(L"States"); IFeatureClassPtr ipFeatureClass; SelectFeatureClass1(bstrDBPath, bstrFCName, &ipFeatureClass);}
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 bstrDBPath = ::SysAllocString(L"..\\..\\..\\Data\\US.mdb"); BSTR bstrFCName = ::SysAllocString(L"States"); IFeatureClassPtr ipFeatureClass; SelectFeatureClass1(bstrDBPath, bstrFCName, &ipFeatureClass);
::SysFreeString(bstrDBPath); ::SysFreeString(bstrFCName);}
2-13
Advanced ArcObjects Component Development II (C++)Copyright © 2002 ESRI. All rights reserved.
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 herevValue1.lVal = l;printf("The value is: %d\n", vValue1.lVal);
::VariantClear(&vValue1);
long l = 1000;
VARIANT vValue1;::VariantInit(&vValue1);
vValue1.vt = VT_R4; // Set variant type herevValue1.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);
long l = 1000;
_variant_t vValue2(l);printf("The value is: %d\n", vValue2.lVal);
2-14
Advanced ArcObjects Component Development II (C++)Copyright © 2002 ESRI. All rights reserved.
Not so smart smart types
// Variant and smart pointer testIUnknownPtr 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 theseipMagic = 0; ipUnk = 0;
vValue.punkVal->QueryInterface(&ipMagic2); // What happens?ipMagic2 = 0;
vValue.vt = VT_EMPTY;
// What happens now? What is missing from this code?
// Variant and smart pointer testIUnknownPtr 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 theseipMagic = 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 DemoInstructor Demo
Understand the behavior beforehand
2-15
Advanced ArcObjects Component Development II (C++)Copyright © 2002 ESRI. All rights reserved.
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;…
HRESULT hr;
IWorkspaceFactoryPtr ipWorkspaceFactory(CLSID_AccessWorkspaceFactory);if (ipWorkspaceFactory == NULL) return E_FAIL;
IWorkspacePtr ipWorkspace;if (FAILED(hr = ipWorkspaceFactory->OpenFromFile(bstrDatabasePath, NULL, &ipWorkspace))) return hr;…
2-16
Advanced ArcObjects Component Development II (C++)Copyright © 2002 ESRI. All rights reserved.
Formatting HRESULTs
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 );}
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 );}
int main(int argc, char* argv[]){ IMapPtr ipMap(CLSID_Map); IMxDocument ipMxDoc; if (FAILED(hr = ipMap->QueryInterface(&ipMxDoc))) // Force a failed HRESULT
HRESULTMESSAGE(hr);}
int main(int argc, char* argv[]){ IMapPtr ipMap(CLSID_Map); IMxDocument ipMxDoc; if (FAILED(hr = ipMap->QueryInterface(&ipMxDoc))) // Force a failed HRESULT
HRESULTMESSAGE(hr);}
Possible to get and display the error code message
2-17
Advanced ArcObjects Component Development II (C++)Copyright © 2002 ESRI. All rights reserved.
Exception handling for DTC types
Native DTC classes throw _com_error exceptions
_com_error Wraps IErrorInfo object
Returns: Description, HelpContext, HelpFile, Source
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);
}
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);
}
try { // Force smart pointer error... IMapPtr ipMap; IActiveViewPtr ipAV; ipMap->QueryInterface(&ipAV); } catch (_com_error & err) { ErrorHandler(err); }
try { // Force smart pointer error... IMapPtr ipMap; IActiveViewPtr ipAV; ipMap->QueryInterface(&ipAV); } catch (_com_error & err) { ErrorHandler(err); }
2-18
Advanced ArcObjects Component Development II (C++)Copyright © 2002 ESRI. All rights reserved.
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;}
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;}
2-19
Advanced ArcObjects Component Development II (C++)Copyright © 2002 ESRI. All rights reserved.
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()};
// 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()};
2-20
Advanced ArcObjects Component Development II (C++)Copyright © 2002 ESRI. All rights reserved.
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
2-21
Advanced ArcObjects Component Development II (C++)Copyright © 2002 ESRI. All rights reserved.
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
2-22
Advanced ArcObjects Component Development II (C++)Copyright © 2002 ESRI. All rights reserved.
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?