|
Hello all,
I'm a C++/MFC programmer and I want to lurn how to build COM applications,
How to create and use COM objects, How to... .
How is the best way to do it
Thanks
Carlos Mariano
|
|
|
|
|
I recommend Developer's Workshop to COM and ATL 3.0 by Andrew Troelsen.
Kuphryn
|
|
|
|
|
Today is my first day of work, my vacations gone. Yes I must start to read something.
Thanks for your answer.
Carlos Mariano
|
|
|
|
|
Reading "Inside COM" by Dale Rogerson is a good way to start.
|
|
|
|
|
Today is my first day of work, my vacations gone. Yes I must start to read something.
Thanks for your answer.
Carlos Mariano
|
|
|
|
|
Hi all
Recent time ago i ask this question on other forum but don’t get explicit decision.
Matter of question is can I pass some pointers on COM object through another method of other COM object.
I.e.
Suppose I have
CoObjectInner – internal object which will be created another object , for handle CoObjectOuter.
CoObjectOuter, which have interface IObjectOuter and this interface has GetInnerObject([out,retval]CoObjectInner** pVal) method which retrieved pointer on internal object.
Formerly on this question I get suggestion that this not way of COM passed pointers on object through methods of an interfaces, and this may raised a lot of trouble, but when I use code like this fashion in my application all work fine. Moreover in any Microsoft Office applications (for instance Word) object model used methods what make same things. And if not use this way in COM then we can’t use hierarchy model, i.e. we can’t
pass internal object through outer, of cause it is possible expose a pointers to a interface of inner object but if inner object contained outbound interfaces then how we can use it in Visual Basic ???
So that VB can catch some events of an COM object necessary defined one with WithEvents word. Although we can declare COM object with WithEvents specification
But we can’t create its object because of this is internal object (we cant create it use new keyword) and also we cant create it within object library and expose one to client. Ultimately we can create outbound interface for outer object and charge to raise all events from internal object through one.
But its more complicated. Where is escape here???
Thought above actually regardless in order to typed so much , but major thing it is –“ why I can’t do this, although other do this???”
And more utilized question on this time.
I create ATL composed control in Visual C++ 6
All work fine but when I placed one on my MFC dialog box (in design mode) then this control appear not properly – simple grew rectangle, but when I run my application when this control view properly.
Thanks if you read this rave from the end.
And maybe some one give to me explicit decision of this trouble??
Sorry for bad eanglish.
|
|
|
|
|
Don't know where to post this because a whole bunch of stuff comes into play here.
First of all, I have a program that is in MFC that calls an MFC extension DLL (with UI components) which in turn calls another DLL to interface to Outlook using low level COM to access the MAPI information. I am using the restrict method to search for appointments for the next year, and I want to include recurring appointments. However, it only returns non-recurring appointments. I am also seeding the Outlook search with the sort property set for ascending, and the includerecurrences property set to true.
[edit]
I just checked the source code for the program that is working and it is a little different than I thought. Outlook calls an MFC DLL from it's Import/Export dialog which loads all the data, then calls an EXE to show data to select.
[/edit]
Here's where it gets interesting. We have an older application that is run directly from Outlook's file export function (it shows up in the list). This application is an MFC exectuable that calls a separate DLL (which is not an AFXDLL). The strange thing is that the restrict method gives me back all of the appointments (recurring and non-recurring).
Does anyone have any clue about what's going on? I checked my project settings, and aside from the DLL definitions, everything is the same...optimizations, files to link in, etc.
Brigg Thorp
Software Engineer
Timex Corporation
|
|
|
|
|
Hi,
I created a simple MFC dialog application and added a custom interface to the application via the wizard. I also included the typelib in the .rc file. This all seems to be rather easy, but when I try to query the interface of the COM object in a client application, the hresult is 0x80004002.
I registered the application and when I lookup the the coclass and typelib in the OLE/COM object Viewer, I can find both of them but the interface I cannot find. So it seems the interface is not registered (I also cannot find the IID in the registry).
Is the interface not always automatically registered when the typelib is registered? The application does not seem to have a proxy/stub makefile, so I also can not nmake that and register it.
Any one know what the cause of this problem is?
|
|
|
|
|
If your interface IDL looks like
[ uuid(7F24AABF-C822-4c18-9432-21433208F4DC) ]
interface ICOMServer : IUnknown
{
HRESULT Name([out, retval] BSTR* objectname);
}
Then make sure to add the oleautomation attribute to it so the interface gets registered. And of course, make sure to include the interface declaration within the library scope in the IDL file.
library LibCOMServer
{
...
[ uuid(7F24AABF-C822-4c18-9432-21433208F4DC),
oleautomation
] interface ICOMServer : IUnknown
{
HRESULT Name([out, retval] BSTR* objectname);
}
...
}
RSS feed
|
|
|
|
|
i am new to directx.
i want to use directx to capture screen , could you give me some examples (visual c++) or suggestions about this?
any hints will be helpful
thx
includeh10
|
|
|
|
|
I need to list the attributes of an autocad block reference :
_variant_t arrayAttrib; // array of AttributeRef objects
IAcadAttributeReferencePtr pAttribRef = NULL;
long lbound, ubound;
HRESULT result;
arrayAttrib = pAcadBlockRef->GetAttributes();
SafeArrayGetLBound(arrayAttrib.parray, 1, &lbound);
SafeArrayGetUBound(arrayAttrib.parray, 1, &ubound);
for (long i = lbound; i <= ubound; i++)
{
result = SafeArrayGetElement(arrayAttrib.parray, &i, pAttribRef);
...
}
GetAttributes() works : i get an array of attributes in a variant;
but SafeArrayGetElement return error code and pAttribRef is not initialized.
JPG
|
|
|
|
|
And the HRESULT is....
Steve S
|
|
|
|
|
IAcadAttributeReferencePtr pAttribRef = NULL;
...
result = SafeArrayGetElement(arrayAttrib.parray, &i, pAttribRef);
result = E_INVALIDARG : one of the arguments is invalid.
Of course the invalid argument must be pAttribRef, but i have no
idea of the way to persuade SafeArrayGetElement to put what i want
in this argument ...
I have already used SafeArrayGetElement to extract simple values
(int, char buffer, ...), but not a com object.
Perhaps my IAcadAttributeReferencePtr is 'hidden' in a variant ?
I try this :
_variant_t val;
result = SafeArrayGetElement(arrayAttrib.parray, &i, &val); // --> result = S_OK
but when looking inside this variant, I have no clue to extract what i want.
Autocad documentation gives only examples in VBA, where all seems so simple...
thank you for your help
|
|
|
|
|
Ah. Try
result = SafeArrayGetElement(arrayAttrib.parray, &i, &pAttribRef);
instead, and see if you get the same error.
I guess you won't...
Steve S
|
|
|
|
|
yes result is S_OK with your version, but ...
when i try to use the returned pAttribRef object :
if (result == S_OK)
strTag = pAttribRef->GetTagString();
i have an error msg box :
"The value of ESP was not properly saves across a function call.
This is usually a result of calling a function declared with one
calling convention with a function pointer declared with a different
calling convention."
so ..
|
|
|
|
|
One step forwards, two steps back.
This is generally due to a mismatch of __cdecl and __stdcall. COM methods are generally (always?) __stdcall, I think. At this point, I'd probably put a breakpoint on the strTag = ... line and then step in using the assembly view, to make sure the interface/vtable in pAttribRef was really OK.
Where are your definitions of the AutoCAD stuff coming from? Presumably you've '#import'-ed a typelib or DLL?
Steve S
|
|
|
|
|
once again tank you for your commitment, i must say i'm completely
lost at this point, but you seems to know what you're talking about ...
where do come from the autocad stuff :
in the class wizard of visual studio, i did 'import class from a type library'
and then choosed acad.tlb in the autocad directory. The class wizard generated then
the file acad.tlh (see attached file). This file contains definitions of all the functions
exposed by autocad.
the autocad program is started this way :
HRESULT hr;
// chercher un Acad en train de tourner
hr = m_acadApp.GetActiveObject("AutoCAD.Application.15");
if( FAILED(hr) )
{
TESTHR( hr= m_acadApp.CreateInstance( "AutoCAD.Application.15", NULL, CLSCTX_LOCAL_SERVER ));
if(hr == REGDB_E_CLASSNOTREG)
{
AfxMessageBox("AutoCAD is not registered on this machine");
goto End;
}
if(m_acadApp == NULL)
{
Erreur = 1;
goto End;
}
...
|
|
|
|
|
EH OH Steve,
did i say something very bad to you ?(in that case sorry, english is not my
first langage).
Or my previous mail was so stupid, you don't want to bother anymore ?
Or I was asking too much when i asked you to look inside the .tlh file ?
Or simply you don't see an explanation to my problem ?
I'm hanging ...
JPG
|
|
|
|
|
OK I have the answer to my previous post : it was option 2 (so stupid).
When receiving the mails from Codeproject in Outlook, i see 'Steve S' as the sender.
So I innocently sent my reply (with the attached file) back to the sender; it's
only now that I realize the sender was 'forums@codeproject.com' ... (i must say for my defense it's the first time i made a post on CodeProject).
Anyway... Steve, if you're still on the subject, here are the occurences of
GetAttributes that i find in acad.tlh :
struct __declspec(uuid("2928d4a2-ca93-11d1-b60f-0060b087e235"))
IAcadBlockReference : IAcadEntity
{
...
// Wrapper methods for error-handling
...
_variant_t GetAttributes ( );
...
// Raw methods provided by interface
...
virtual HRESULT __stdcall raw_GetAttributes (VARIANT * pAttrObjs ) = 0;
...
}
// Function implementation mapping
#pragma start_map_region("d:\polar32JPG\spacad\debug\acad.tli")
{
// Wrapper methods for error-handling
...
__declspec(implementation_key(1096)) _variant_t IAcadBlockReference::GetAttributes ( );
...
}
JPG
|
|
|
|
|
and, persevering in my 'monologue' (chat with myself),
here are the occurences of IAcadBlockReference (the object i'm trying to get of the array returned by GetAttributes() ) :
namespace AutoCAD {
...
struct __declspec(uuid("2928d4a2-ca93-11d1-b60f-0060b087e235"))
/* dual interface */ IAcadBlockReference;
...
}
// Smart pointer typedef declarations
_COM_SMARTPTR_TYPEDEF(IAcadBlockReference, __uuidof(IAcadBlockReference));
struct __declspec(uuid("2928d4a2-ca93-11d1-b60f-0060b087e235"))
IAcadBlockReference : IAcadEntity
{
...
...
}
struct __declspec(uuid("2928d4a3-ca93-11d1-b60f-0060b087e235"))
AcadBlockReference;
// [ default ] interface IAcadBlockReference
// [ default, source ] interface IAcadObjectEvents
|
|
|
|
|
(Fx: Wakes up, staring at screen thinking - I must try and work fewer hours this week...)
Your GetAttributes is returning a _variant_t. This is probably a safearray, so you need to check the vt member to determine the type.
if (vt == (VT_ARRAY|VT_UNKNOWN)) || vt == (VT_ARRAY|VT_DISPATCH))
This would mean it's a SAFEARRAY of either IUnknown or IDispatch values.
It's not clear from the context what the bounds of the array are, but there are functions to tell you (see SafeArrayGetDim), but chances are it's single dimension, so you can use SafeArrayGetUBound(1) and SafeArrayGetLBound(1) to find the max and min elements in it.
Then you should be able to use SafeArrayGetElement to get a copy of the interface. Don't forget that you pass the address of an index variable to SafeArrayGetElement, not the index itself.
If you want to iterate over the attributes, then SafeArrayAccessData and SafeArrayUnaccessData around a loop will be more efficient, but that deals with a pointer to the data, and you're responsible for doing your own copying.
The call can't directly return the interface you would expect, unless it's IUnknown or IDispatch, in which case it's either the punkVal (IUnknown) or pdispVal (IDispatch). Since they both support QueryInterface, it's no problem to use either of them the get the interface you actually want, but you absolutely must do that, rather than a simple assignment/cast.
It's probable that the pointer isn't pointing to an appropriate v-table anyway.
It's possible that GetAttributes() might return VT_ARRAY|VT_VARIANT, in which case you then have an extra step involved in examining the variant you get back.
Hope this helps
(and no, I wasn't offended by your email - sometimes work just gets in the way of things, like those stupid people who write viruses and worms...)
Steve S
|
|
|
|
|
In fact i have no problem with GetAttributes : i know it returns a valid safearray
(variant type = VT_ARRAY|VT_DISPATCH); SafeArrayGetLBound & SafeArrayGetUBound return
correct values.
The problem is extracting a IAcadAttributeReference * from that array :
if i try to extract a variant from the array (presuming that the IAcadAttributeReference * is a member of the variant) :
_variant_t val; // i tried also with _variant_t *val
result = SafeArrayGetElement(arrayAttrib.parray, &i, &val); // result = S_OK
switch(val.vt)
{
case VT_BYREF|VT_UNKNOWN: ...
break;
case VT_BYREF|VT_DISPATCH: ...
break;
case VT_UNKNOWN: ...
break;
case VT_DISPATCH: ...
break;
case VT_ARRAY: ...
break;
}
val.vt does not correspond to any case of the switch
and most members of val are clearly invalid (0xccccccc)
-------------------
i understand you have others things to do than finding solutions to other people
problems; what you have already done is very kind, so if you don't see an evident
solution, don't mind. Thanks.
|
|
|
|
|
Ah hah!
You're trying to retrieve into a variant. What you should do is retrieve into an IDispatch, because that's what's in the array.
CComPtr<idispatch> myDisp;
result = SafeArrayGetElement(arrayAttrib.parray, &i, &myDisp);
// Should give S_OK
CComQIPtr<iacadattributereference, &iid_iacadattributereference=""> myAttrib;
try
{
myAttrib = myDisp;
}
catch(_com_error& e)
{
result = E_NOINTERFACE;
}
catch(...)
{
result = E_FAIL;
}
if (result==S_OK)
{
// do your thing here...
}
Since the CComPtr and CComQIPtr are smart, they'll release when they go out of scope. SafeArrayGetElement will give you a copy of the element, and in this context means it will be a reference counted interface which you must release, CComPtr will do that bit for you.
You might need to modify your #import to generate the named guids for interfaces etc.
Hope this helps.
[Sorry if I seemed grouchy, I'm having a bad day...]
Steve S
|
|
|
|
|
Curse that HTML!
It should, of course, read...
CComPtr <myDisp>;
result = SafeArrayGetElement(arrayAttrib.parray, &i, &myDisp);
// Should give S_OK
CComQIPtr <myAttrib,&IID_AcadAttributeReference>;
try
{
myAttrib = myDisp;
}
catch(_com_error& e)
{
result = E_NOINTERFACE;
}
catch(...)
{
result = E_FAIL;
}
if (result==S_OK)
{
// do your thing here...
}
Steve S
|
|
|
|
|
there is progress, but ...
CComPtr<iacadattributereference> myDisp;
CComQIPtr<iacadattributereference ,&__uuidof(iacadattributereference)=""> myAttrib;
result = SafeArrayGetElement(arrayAttrib.parray, &i, &myDisp); // --> S_OK
try
{
myAttrib = myDisp;
if (result == S_OK)
myAttrib->GetColor(); //--> "access violation" in oleaut32.dll
...
What is strange is that, when looking inside myAttrib, it has type IAcadEntity,
and not IAcadAttributeReference; IAcadAttributeReference is derived from IAcadEntity.
GetColor() is a method of IAcadAttributeReference, and it did "access violation" in oleaut32.dll (the catch(_com_error& e) didn't catch anything).
If I try myAttrib->GetHeight(), where GetHeight() is a method of IAcadEntity, the
message is
"The value of ESP was not properly saved across a function call.
This is usually a result of calling a function declared with one
calling convention with a function pointer declared with a different
calling convention."
I don't know if it can give you some light : GetHeight() is :
inline double AutoCAD::IAcadAttributeReference::GetHeight ( )
{
double _result;
HRESULT _hr = get_Height(&_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _result;
}
and
struct __declspec(uuid("2928d4a0-ca93-11d1-b60f-0060b087e235"))
IAcadAttributeReference : IAcadEntity
{
...
virtual HRESULT __stdcall get_Height (double * Height ) = 0;
}
-------
My boss, who is a lot more aware of COM than me (but that's easy), has no clue.
So it's up to you, you grouchy
JPG
|
|
|
|
|