This section provides a few simple examples that demonstrate how to use the StarTeam COM interfaces in C++.
Note that when using the COM interfaces from C++, you must include the following header file:
#include "StarTeamSDK.h
This header contains the declarations of the StarTeam COM interfaces. It should be located in the subfolder of the StarTeam SDK installation folder.
In addition, you will need to compile the file and link it into your project. This file defines the various class IDs (CLSIDs) and Interface IDs (IIDs) for the StarTeam COM APIs. This file is also located in the SDK subfolder.
The following example shows how to create a Server object, and establish a connection to a StarTeam Server, using the StarTeam COM interfaces in C++.
int main(int argc, char *argv[ ], char *envp[ ]) {
USES_CONVERSION;
CoInitialize(NULL);
const char* strAddress = "localhost";
int nPort = 49201;
const char* strUser = "SampleUser";
const char* strPassword = "MyPassword";
HRESULT hr = S_OK;
IStServerFactory* Factory = NULL;
IStServer* Server = NULL;
try {
// Instantiate an StServerFactory object.
hr = CoCreateInstance(
CLSID_StServerFactory,
NULL,
CLSCTX_SERVER,
IID_IStServerFactory,
(void**)&Factory);
// Use it to create an StServer object.
if (SUCCEEDED(hr)) {
hr = Factory->Create(
T2OLE(strAddress),
nPort,
&Server);
}
// Establish a connection to the server.
// Optional - logOn() connects if necessary.
if (SUCCEEDED(hr)) {
hr = Server->connect();
}
// LogOn as a specific user.
if (SUCCEEDED(hr)) {
long userID = -1;
hr = Server->logOn(
T2OLE(strUser),
T2OLE(strPassword),
&userID);
}
// Use the Server object to enumerate
// Projects, Views, etc.
// . . .
// Disconnect when finished.
if (SUCCEEDED(hr)) {
hr = Server->disconnect();
}
// Clean up.
if (Server != NULL) {
Server->Release();
Server = NULL;
}
if (Factory != NULL) {
Factory->Release();
Factory = NULL;
}
}
// Error handling.
catch(...) {
if (Server != NULL) {
Server->Release();
}
if (Factory != NULL) {
Factory->Release();
}
}
CoUninitialize();
return(0);
}
|
As you can see, using the StarTeam interfaces from C++ is much more complex than using them from other programming environments. This is not really due to any added complexity in the StarTeam APIs themselves, but is the nature of using COM from C++.
Describing COM functions such as , ), and is beyond the scope of this document. Consult the reference documentation in the Win32 platform SDK.
The examples above use to enhance readability. and are macros, defined by the Microsoft Foundation Classes (MFC), that simplify the conversion of ASCII text to Unicode, which is required by COM. If you are not programming natively in Unicode, and you are not using MFC, then you can convert to Unicode using the Win32 APIs. For example:
int nLen = MultiByteToWideChar(
CP_ACP, 0, strAddress,
strlen(strAddress), NULL, 0);
if (SysReAllocStringLen(&bstrAddress, NULL, nLen)) {
MultiByteToWideChar(
CP_ACP, 0,
strAddress, strlen(strAddress),
bstrAddress, nLen);
hr = Factory->Create(bstrAddress, nPort, &Server);
SysFreeString(bstrAddress);
bstrAddress = NULL;
}
|
When using the COM interfaces from C++, be sure that you use and to maintain the proper reference counts on the various StarTeam objects. The most common problems encountered while using the COM interfaces are a result of releasing an object prematurely or leaving an outstanding reference to an object when it is no longer needed.
You can simplify the management of object references in C++ by using smart pointers. Smart pointers are essentially C++ wrappers that maintain reference counts as the objects go in and out of scope. Microsoft Visual C++ supports an implementation of smart pointers that is easy to use. Consult your Visual C++ documentation for further details.
The following example shows how to enumerate the projects that are available on a given server, searching for the project with a given name.
IStProject* FindProject(IStServer* pServer, LPCTSTR szName)
{
HRESULT hr = S_OK;
IStProject* pProject = NULL;
IStCollection* pCollect = NULL;
LPDISPATCH pDispatch = NULL;
IEnumVARIANT* pEnum = NULL;
LPUNKNOWN pUnknown = NULL;
IStProject* pNext = NULL;
BSTR bstrName = NULL;
try {
// Get the value of the Projects property.
hr = pServer->get_Projects(&pCollect);
// The value is a StarTeam collection object,
// which supports the standard get__NewEnum()
// method of an automation collection.
if (SUCCEEDED(hr)) {
hr = pCollect->get__NewEnum(&pDispatch);
pCollect->Release();
pCollect = NULL;
}
// Now that we have an automation collection,
// query for the IEnumVARIANT interface.
if (SUCCEEDED(hr)) {
hr = pDispatch->QueryInterface(
IID_IEnumVARIANT,
(void**)&pEnum);
pDispatch->Release();
pDispatch = NULL;
}
// Use IEnumVARIANT to iterate over
// the members of the collection.
while (SUCCEEDED(hr) && (pProject == NULL))
{
USES_CONVERSION;
// Retrieve the next element.
VARIANT v;
VariantInit(&v);
hr = pEnum->Next(1, &v, NULL);
// Are we at the end of the collection?
if (hr == S_FALSE)
break;
// Get the project object from
// the VARIANT record.
pUnknown = NULL;
hr = VariantChangeType(&v, &v, 0, VT_UNKNOWN);
if (SUCCEEDED(hr)) {
pUnknown = v.punkVal;
}
if (pUnknown == NULL) {
hr = E_INVALIDARG;
}
// Query for the IStProject interface.
if (SUCCEEDED(hr)) {
hr = pUnknown->QueryInterface(
IID_IStProject,
(void**)&pNext);
}
if (pUnknown != NULL) {
pUnknown->Release();
pUnknown = NULL;
}
// Get the value of the Name property.
if (SUCCEEDED(hr)) {
hr = pNext->get_Name(&bstrName);
}
// See if the project name matches
// the one we're looking for.
if (SUCCEEDED(hr)) {
LPCTSTR szNext = OLE2T(bstrName);
SysFreeString(bstrName);
bstrName = NULL;
if (strcmp(szName, szNext) == 0) {
// It's a match; save a reference to the
// project object, since we'll be returning
// it to the caller.
pProject = pNext;
pProject->AddRef();
}
}
if (pNext != NULL) {
pNext->Release();
pNext = NULL;
}
}
if (pEnum != NULL) {
pEnum->Release();
pEnum = NULL;
}
}
catch(...) {
if (bstrName != NULL) {
SysFreeString(bstrName);
}
if (pUnknown != NULL) {
pUnknown->Release();
}
if (pNext != NULL) {
pNext->Release();
}
if (pEnum != NULL) {
pEnum->Release();
}
if (pDispatch != NULL) {
pDispatch->Release();
}
if (pCollect != NULL) {
pCollect->Release();
}
throw;
}
return(pProject);
}
|
Once again, using the StarTeam interfaces from C++ is much more complex than using them from other programming environments. In Visual Basic, this same example required about a dozen lines of code!
Although the code required to manipulate a collection is extensive, the concepts involved are reasonably straightforward. Remember to keep the following points in mind:
Handle reference counting with care. In particular, remember that when the method of returns a variant of type or , there is an outstanding reference to the enclosed interface pointer that must be released by the caller.
The StarTeam COM APIs support rich error messages through the use of the standard interface. The following example demonstrates how to get a descriptive error message when one of the StarTeam APIs fails.
BSTR GetErrorMessage(HRESULT hr, REFIID riid, LPUNKNOWN p)
{
BSTR pErrorMessage = NULL;
// If the return code indicates an error ...
if (!SUCCEEDED(hr)) {
// If the object that generated the error supports
// the standard ISupportErrorInfo interface ...
ISupportErrorInfo* pSEI = NULL;
if (SUCCEEDED(p->QueryInterface(
IID_ISupportErrorInfo,
(void**)&pSEI))) {
// And supports error information on the
// interface that generated the error ...
if (pSEI->InterfaceSupportsErrorInfo(riid) == S_OK) {
// Get the IErrorInfo interface.
IErrorInfo* pEI = NULL;
if (GetErrorInfo(0, &pEI) == S_OK) {
// Get the error message.
pEI->GetDescription(&pErrorMessage);
pEI->Release();
}
}
pSEI->Release();
}
}
return(pErrorMessage);
}
|
Back
Home
|