How do I access COM objects?

  • Thread starter Thread starter Dan
  • Start date Start date
D

Dan

Sounds simple enough - problem is there seems to be WAY too much
documentation and can't seem to find the right one.

I created a VC++ .NET Windows Form application, and I'm trying to add
TAPI3 to it. I've gotten as far as adding a reference to the
TAPI3.dll, which gets me all the type information, but now I'm stuck
in trying to figure out how to create a TAPI object.

In my WinMain, I figured I'd just have to do
TAPIClass myObject=new TAPIClass()
but even with tapi3.h included, TAPIClass is undefined.

I guess I'm looking for a simple example of a VC++ .NET that simply
creates an object so I know that I have all the right steps in there.
After one creates the reference in the project, what comes next? Is
there something other than just the tapi.h that needs to be included,
etc...

Thanks.

Desperatly!
-Dan
 
From your message, it was not clear to me whether you are accessing
the DLL by setting the reference (through TLBIMP path) or using the
C++ type header file for your COM class. If you follow the former way,
there is header file involved in the process. Can you please further
clarify the scenario.

Regards
Rao TRN
 
From your message, it was not clear to me whether you are accessing
the DLL by setting the reference (through TLBIMP path) or using the
C++ type header file for your COM class. If you follow the former way,
there is header file involved in the process. Can you please further
clarify the scenario.


I can try! :) Really need to get a book on this stuff.

Based on some post on usenet or the web, in the solution explorer, I
went to references, Add Reference and selected the TAPI30.DLL. I'm
guessing that imports it via the first way you mentioned.

I tried to include <tapi3.h> as well, but that did not help. In my
very short code I have (stolen out of MSDN help or off the net)
During compilation, I get

Form1.cpp(17) : error C2065: 'TAPI' : undeclared identifier
Form1.cpp(17) : error C2146: syntax error : missing ';' before
identifier 'tapi'
Form1.cpp(17) : error C2065: 'tapi' : undeclared identifier
Form1.cpp(17) : error C3861: 'TAPI': identifier not found, even with
argument-dependent lookup
Form1.cpp(17) : error C2059: syntax error : ';'
Form1.cpp(18) : error C2228: left of '.Initialize' must have
class/struct/union type
type is ''unknown-type''
Form1.cpp(18) : error C3861: 'tapi': identifier not found, even with
argument-dependent lookup

though intellisense has no problem showing me the members of the TAPI
class, such as the tapi.Initialize() member. I guess I just need to
figure out what the compiler is looking for to know what the class is.

#include "stdafx.h"
#include "Form1.h"
#include <windows.h>
using namespace tapinet;
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
System::Threading::Thread::CurrentThread->ApartmentState =
System::Threading::ApartmentState::STA;


TAPI tapi=new(TAPI());
tapi.Initialize();

Application::Run(new Form1());
return 0;
}
 
Dan said:
Sounds simple enough - problem is there seems to be WAY too much
documentation and can't seem to find the right one.

I thought twice about replying. But I saw that you said you were desperate.
So, I'm gonna do it but be warned that this drips with personal opinion.

I have to tell you upfront that I am not a big fan of COM. It is not that I
don't appreciate what it does. It came into being, in my view, so that
components could be used by "developers" whose preferred language is not
_the_ one true language. <gd&r> My attitude to those folks is a lot like
Marie Antoinette's was to her subjects - let them use C++.

(Just by the way, .Net addresses COM's issues in a sensible way as all .Net
languages share the same object model so _ultimately_ we won't need a
different and strange component object model).

And just to make it interesting, there are is "raw" COM where everyone and
his brother has to consider what effect his usage of a component has on its
reference count and then the COM often used by C++ developers.

The link below describes the #import compiler directive which causes the C++
compiler to read a COM object's type library and then to create wrapper
classes so you can think in C++ terms rather than in COM terms. Using the
wrappers, for example, insures that when one of these objects is destroyed
its reference count is automatically decremented.

http://msdn.microsoft.com/library/d...e98/HTML/_predir_the_.23.import_directive.asp

Not to be outdone, .Net provides Runtime Callable Wrappers (RCW) for the
same purpose - i.e. so that code in member functions of .Net classes can
make use of the services provided by COM objects. About a year or so ago,
Helen Warn, posted in the TAPI group that there was "some" problem with the
RCW's for TAPI3. I don't remember the issue but I do know that she created
her own wrappers for TAPI (v2?) and was encouraged to post them here:

http://www.gotdotnet.com/Community/...mpleGuid=5d893af6-b340-49d8-9162-b90bf6932414

Finally, the view of lots of types (at least in my experience) who do much
TAPI is that the version 2 procedural API is a better choice than the COM
based stuff of 3.0.

I don't want this to sound negative - C++ rocks, TAPI2 rocks, NET rocks. COM
and TAPI3 well that's something else in my view.

However, if you are looking for a .Net-targeting Managed C++ sample that
uses TAPI3, and if you are willing to use the compiler's COM support then
take a look at the hack below.

It makes a call on a line - here the one with the name "56Kbps Internal
Modem" to the MoviePhone service - here (212) 777-3456.

Note that a proper TAPI application would look for a line which is capable
of carrying a call of the type in question - TAPIMEDIATYPE_AUDIO - and use
it instead of a hard-coded line. You'll need to use the name of whatever
device you have handy.

Regards,
Will

// Don't forget to link against UUID.LIB

#define _WIN32_WINNT 0x0400
#include <windows.h>

#import <tapi3.dll>
using namespace TAPI3Lib;

#using <mscorlib.dll>
using namespace System;

extern "C" const CLSID CLSID_TAPI;

void MakeTapiCall(_bstr_t &, _bstr_t &);

int main()
{
// Look ma, it really is .Net ...

Console::WriteLine(S"Hello World");

// ... but I can have COM too

CoInitializeEx(0, COINIT_MULTITHREADED);

// ... and use COM to call on TAPI 3

MakeTapiCall( _bstr_t("56Kbps Internal Modem"),
_bstr_t("2127773456") );

CoUninitialize();

return 0;
}

// Searches for a line and makes a call to the requested number on it

void MakeTapiCall(_bstr_t &bstrLine, _bstr_t &bstrNumber)
{
ULONG ul;
_bstr_t name;
HRESULT hr;
ITTAPIPtr pTapi;
ITAddressPtr pAddress;
IEnumAddressPtr pEnumAddress;
ITBasicCallControlPtr pCall;

// Initialize TAPI

hr = pTapi.CreateInstance(CLSID_TAPI);
hr = pTapi->Initialize();

// Look for the requested line

pEnumAddress = pTapi->EnumerateAddresses();

while ( pEnumAddress->Next(1, &pAddress, &ul) == S_OK )
{
name = pAddress->AddressName;

if ( name == bstrLine )
break;

pAddress.Release();
pAddress = 0;
}

// If the line was found, then make a call

if ( pAddress )
{
pCall = pAddress->CreateCall(bstrNumber,
LINEADDRESSTYPE_PHONENUMBER,
TAPIMEDIATYPE_AUDIO);

// Make the call

hr = pCall->Connect(true);

// Wait a while - do something sensible here
// while the call is ongoing

Sleep(10000);

// Hangup

hr = pCall->Disconnect(DC_NORMAL);
}

// Shutdown TAPI

hr = pTapi->Shutdown();
pTapi.Release();
}
 
I don't want this to sound negative - C++ rocks, TAPI2 rocks, NET rocks. COM
and TAPI3 well that's something else in my view.

I've been using TAPI2 and going to the COM version has been, well as
someone mentioned about MFC once - I feel like I'm fighting against
the compiler. I'm too much of a procedural type person for all these
macros and interfaces, etc... Guess I need to replace my pillow with
a book on COM and let osmosis take over.
However, if you are looking for a .Net-targeting Managed C++ sample that
uses TAPI3, and if you are willing to use the compiler's COM support then
take a look at the hack below.

Thanks. I'll be glad to take a look at it, but I think my officemates
goal of having everything as .Net may not happen in this case - YIKES!
Note that a proper TAPI application would look for a line which is capable
of carrying a call of the type in question - TAPIMEDIATYPE_AUDIO - and use
it instead of a hard-coded line. You'll need to use the name of whatever
device you have handy.

Yes. Usually wehn just goofing around with the API before I get
going, I hardcode just enough to get it working in and then clean up.

Thanks again. I didn't think the some of the COM stuff would be
needed with .Net, but as you said, there appears to be issues with
TAPI3.
 
#import <tapi3.dll>
using namespace TAPI3Lib;
extern "C" const CLSID CLSID_TAPI;
hr = pTapi.CreateInstance(CLSID_TAPI);
hr = pTapi->Initialize();

Those were the critical lines. Based on some other examples, I didn't
think the CreateInstance would still be needed.

I think I'm going to go back to the shallow end for a while.
Something simple like Unix network programming :)

Thanks for the help.
 
Dan said:
Those were the critical lines. Based on some other examples, I didn't
think the CreateInstance would still be needed.

If your samples didn't show a

#import ...

line then they didn't take advantage of the compiler's ability to read the
metadata and create C++ wrapper classes on the fly. IMO, using the wrappers
is less painful than taking COM straight-up with no chaser. :-)

You might want to take a look at the .tli and .tlh files to see what the
compiler did.

Regards,
Will
 
Back
Top