|
I am reading up on some COM sample.. I have problem understanding the way they do casting:
//
STDMETHODIMP CUserInfo::QueryInterface(REFIID iid, LPVOID *ppv)
{
*ppv = NULL;
if (IID_IUnknown == iid)
*ppv = (LPVOID)(IUnknown *)this;
else if (IID_IUserInfo == iid)
*ppv = (LPVOID)(IUserInfo *)this;
else
return E_NOINTERFACE; //Interface not supported
//Perform reference count through the returned interface
((IUnknown *)*ppv)->AddRef();
return NOERROR;
}//QueryInterface
QUESTION: Casting. I can understand:
long nLong;
double nDouble;
nLong = 10;
nDouble = (double) nLong;
But I have no idea what's the different between:
*ppv = (LPVOID)(IUnknown *)this;
*ppv = (LPVOID)(IUserInfo *)this;
*ppv = this;
*ppv = (LPVOID)this;
Thanks!
norm
|
|
|
|
|
A coclass that implements IUnknown and IUserInfo has two different vtables, one for each interface. Thus (IUknown*) this is a different address from (IUserInfo*) this .
The cast to LPVOID is unnecessary, as the language allows implicit conversion of any pointer type to void* .
--Mike--
"alyson hannigan is so cute it's crazy" -- Googlism
Just released - 1ClickPicGrabber - Grab & organize pictures from your favorite web pages, with 1 click!
My really out-of-date homepage
Sonork-100.19012 Acid_Helm
|
|
|
|
|
Given that they are casting to a LPVOID by default, the middle steps seem pointless. I try to use smart pointers instead of this sort of ugliness, or C++ casts at least.
Christian
No offense, but I don't really want to encourage the creation of another VB developer. - Larry Antram 22 Oct 2002
Hey, at least Logo had, at it's inception, a mechanical turtle. VB has always lacked even that... - Shog9 04-09-2002
During last 10 years, with invention of VB and similar programming environments, every ill-educated moron became able to develop software. - Alex E. - 12-Sept-2002
|
|
|
|
|
All that's going on here is the code is returning the proper interface requested through the QueryInterface call. What may be confusing you is the double cast, e.g., first a cast to an IUnknown* , then to LPVOID .
They're first casting to the proper interface (the one that was requested), then "stuffing" the ppv return variable with that interface. They have to cast to LPVOID because that's the variable type, even though its unecessary since casting to void* is native.
"Casting" is just making one thing appear to be another and is used quite often in C / C++ programming, though it may be "unsafe" because you could lose things in the translation.
In C++, some programmers consider it better to explicitly state that you are casting, such as using reinterpret_cast . That way the intent is clear:
IUserInfo* pUI = reinterpret_cast<IUserInfo*>(this);
*ppv = reinterpret_cast<LPVOID>(pUI);
Either way is acceptable. I try not to cast as much as possible, but if I do, tend to use the latter unless I'm feeling carpal tunnel from all the extra typing /:]
|
|
|
|
|
it seems that casting has no effect except that it changes the option available thru "Intellisense" and the method that the object can invoke thru the pointers...
but there must be a reason why they cast the pointers...
here's some simple code i used to test this out:
// TryCasting.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "stdio.h"
#include "iostream.h"
class C
{
public:
DisplayC() { cout << "C" << endl; }
};
class B : public C
{
public:
DisplayB() { cout << "B" << endl; }
};
class A : public B
{
public:
DisplayA() { cout << "A" << endl; }
};
//So:
//(1) A is B (since A inherits from B)
//(2) A is C
int main(int argc, char* argv[])
{
A * pA = new A;
cout << "pA = " << pA << endl;
cout << "(B*) pA = " << (B*) pA << endl;
cout << "(C*) pA = " << pA << endl;
cout << "(void*) pA = " << (void*) pA << endl;
B * pB = pA;
C * pC = pA;
//check and see the options registered with Intellisense:
pA->DisplayA(); //thru pA, all three methods DisplayA/B/C are available
pB->DisplayB(); //thru pB, only DisplayB/C are available
pC->DisplayC(); //thru pC, only DisplayC is available.
return 0;
}
anyway, this confirm "your" perspective. but there must be a reason.... otherwise:
if (IID_IUnknown == iid)
*ppv = (LPVOID)(IUnknown *)this;
else if (IID_IUserInfo == iid)
*ppv = (LPVOID)(IUserInfo *)this;
else
QueryInterface will always return "this"!! why the if-else statement in the first place?
norm
|
|
|
|
|
Technically, you do not have to do the casting of this to (eventually, however convoluted) void** . However, the if block is to see what interface a caller is requesting. In COM, you can "aggregate" or "contain" another object (and your class itself may be similarly "aggregated" or "contained",) and make it part of your object, thus sometimes a caller will request something that's not in your class signature, and you'd use that pointer instead of this . So your safest bet is to do at least the interface cast.
Also, it's important to AddRef() on the correct interface in COM. It seems from the example, their class is simply derived from IUnknown , so they use the base IUnknown::AddRef() . Other COM objects may use different referencing depending on the interface, e.g., if they're "containing" or "aggregating" another object whose lifetime may not be the same as the parent object, and so the last call to IUnknown::AddRef is the safest bet for all interfaces that your object may return.
Perhaps that's whats confusing is that COM object lifetime isn't necessarily the same per interface that is exposed by an object, and the first cast to a specific interface is safe, in order to get it to the increment the correct AddRef on the correct object.
Besides that, yes, the autocompletion of code is nifty. COM isn't the clearest thing with casting, and that's due to the nature of the COM standard.
Example: Your class contains a custom data object, that doesn't necessarily have to be around as long as your parent object, but you wish to expose it's interface. You have a pointer to the object m_pMyContained :
STDMETHODIMP CMyCOMObject::QueryInterface(REFIID iid, LPVOID* ppv)
{
*ppv = NULL;
if (IID_IUnknown == iid)
*ppv = (IUnknown*)this;
elseif (IID_IMyObject == iid)
*ppv = (IMyObject*)this;
elseif (IID_IMyContained)
*ppv = (IMyContained*)m_pMyContained;
else return E_NOINTERFACE;
((IUnknown*)*ppv)->AddRef();
return S_OK;
}
<div style="width: 360px; background-color: rgba(208, 208, 240, 1); margin: 4px; padding: 4px; font-family: monotype bold; font-size: 7pt; font-variant: ; font-weight: ; font-style: ; line-height:">"The greatest danger to humanity is humanity without an open mind."<br> - Ian Mariano - <a href="http://www.ian-space.com" target="_blank">http:
</div>
|
|
|
|
|
okay, your example makes sense:
*ppv = NULL;
if (IID_IUnknown == iid)
*ppv = (IUnknown*)this; // redundant since it's this, but safe because we may be contained ourselves
elseif (IID_IMyObject == iid)
*ppv = (IMyObject*)this; // redundant since it's this, but safe because we may be contained ourselves
elseif (IID_IMyContained)
*ppv = (IMyContained*)m_pMyContained; //different object, different "lifecycle"
else
return E_NOINTERFACE; // AddRef() correct IUnknowninterface // Note IMyContained's IUnknown is DIFFERENT from this' // so we use whatever object's IUnknown to do the AddRef
((IUnknown*)*ppv)->AddRef();
return S_OK;
Just want to reconfirm that my understanding is indeed correct...
STDMETHODIMP CUserInfo::QueryInterface(REFIID iid, LPVOID *ppv)
{
*ppv = NULL;
if (IID_IUnknown == iid)
*ppv = (LPVOID)(IUnknown *)this; //THE CAST HERE, ...
else if (IID_IUserInfo == iid)
*ppv = (LPVOID)(IUserInfo *)this; //AND HERE ARE POINTLESS/IRRELEVANT. Am I correct?
else
return E_NOINTERFACE; //Interface not supported
//Perform reference count through the returned interface
((IUnknown *)*ppv)->AddRef();
return NOERROR;
}//QueryInterface
Thanks for your feedback!
norm
|
|
|
|
|
Hi!
Thanks for your advice. But all I want to solve is just and MFC custom control not COM:
CEdit
A
|
|
CParsedEdit
A
|
|
CParsedEditExport
Using this pattern, everything went well.
Now I use pure abstract class as interfaces. As Stroustrup says "What is important is interfaces." So I change the design pattern threoretically:
CEdit IEdit(abstract)
A A
| /
| /
CParsedEdit
A
|
|
CParsedEditExport
But this time the problem exist: Please see my code in the my original message.
Thanks,
Sovann.
Why waste time learning while ignorence is instantaneous ? [Hobbes]
|
|
|
|
|
Hi, everyone!
I want to know whether I can download MSDN iso file
from somewhere? Where to download?
I often buy MSDN iso cdroms (3 CDs per month) from local
vendor. And I think it is not efficient and somewhat waste
money. Is MSDN free to download?
Cheers,
George
|
|
|
|
|
MSDN comes out every three months.
Given that Microsoft *sell* it on CD, if you can't find it at www.microsoft.com, downloading from anywhere else would be stealing. AFAIK they only offer it online. You can go to msdn.microsoft.com, and I doubt you'll use up 2 gig a quarter browsing it, so it's bound to be cheaper, too.
Christian
No offense, but I don't really want to encourage the creation of another VB developer. - Larry Antram 22 Oct 2002
Hey, at least Logo had, at it's inception, a mechanical turtle. VB has always lacked even that... - Shog9 04-09-2002
During last 10 years, with invention of VB and similar programming environments, every ill-educated moron became able to develop software. - Alex E. - 12-Sept-2002
|
|
|
|
|
Thanks, Christian!
Cheers,
George
|
|
|
|
|
Hi everyone,
I have a problem with all these different wrappers available for variants, smart pointers and bstrs...
i need advice on which to use and when? and does it make a lot of difference as to which one's are used?
smart pointers
1. _com_ptr_t
2. CComPtr
3. CComQIPtr
variants and bstrs
1. CComVariant, CComBSTR
2. COleVariant, COleBSTR
3. _variant_t, _bstr_t
|
|
|
|
|
Use _bstr_t where you need it's methods, CComBSTR otherwise as it's less likely to run you out of stack space.
Use COM smart pointers, as in IMyInterfact spInterface(__uuidof(MyInterface)).
Use variants only when absolutely forced to, and then use whatever wrapper someone else tells you to.
The thing is, they all have pluses and minuses, if it was just a case of always using the one thing, there would not be 7 of them. Too bad they can never write one that covers all the bases in one hit.
Christian
No offense, but I don't really want to encourage the creation of another VB developer. - Larry Antram 22 Oct 2002
Hey, at least Logo had, at it's inception, a mechanical turtle. VB has always lacked even that... - Shog9 04-09-2002
During last 10 years, with invention of VB and similar programming environments, every ill-educated moron became able to develop software. - Alex E. - 12-Sept-2002
|
|
|
|
|
I got a POP3/SMTP server (MerakMail) running here. What i want is that whenever mail arrive at POP 3 server, i get notified i.e some external application automatically starts or event gets generated e.t.c.
Any idea?? Do i nedd to trap port 110?? do i need to design a hook app or something else ??
|
|
|
|
|
I don't know if MerakMail has an API for this, but a generic solution could be creating a "proxy" server that listens on port 110 and forwards all data to other machine. This way you could generate events to notify other applications of mail arriving in an unobtrusive way.
lazy isn't my middle name.. its my first.. people just keep calling me Mel cause that's what they put on my drivers license. - Mel Feik
|
|
|
|
|
When notifying a person, the check granularity is not so fine as to preclude simply running a program that connects to the POP server and queries for the UIDLs, sending notification when new email is found. This is nice because it can be used on your machine if you can get email from there at all-- it doesn't depend upon many particulars.
Just check every few minutes or so right?
|
|
|
|
|
Hi All,I wrote a screensaver ,I want to debug it,How can I do that?
thanx for any hints.
|
|
|
|
|
Don't suppose you have a 2nd machine ? If not, depending on what you want to debug, you could write log files and check your assumptions there.
Christian
No offense, but I don't really want to encourage the creation of another VB developer. - Larry Antram 22 Oct 2002
Hey, at least Logo had, at it's inception, a mechanical turtle. VB has always lacked even that... - Shog9 04-09-2002
During last 10 years, with invention of VB and similar programming environments, every ill-educated moron became able to develop software. - Alex E. - 12-Sept-2002
|
|
|
|
|
Thank Christian Graus.
I dont have 2nd machine, But,if I have a 2nd monitor,can I debug it without writing log files? Could you give me more hints?
|
|
|
|
|
Either use remote debugging, via a second machine, or make the debug version display at a smaller resolution than the screen (say 600x400), not topmost, and not dismissable via mouse/keyboard/active window/etc.
Regards, Larry Antram
Stardust Software
"Those who choose to sacrifice freedom in order to gain security shall not have, nor do they deserve, either one"
-- Benjamin Franklin
|
|
|
|
|
Thank you advanced for your cue;)!!
|
|
|
|
|
If you do some painting in your Screensaver than you can 'OutputText' there.
Try it @ home. (~B&B)
|
|
|
|
|
Let's say I have a view, and I make some checking in CView::OnInitialUpdate() and found out it can't load some resources for some reason, so I decide to destroy the view and try to reopen the view.
How to close the view and then recreate a new view, all happening inside OnInitialUpdate() ? (is it possible?)
Thanx in advance...
|
|
|
|
|
|
|