Re: Animated gif
"Joseph M. Newcomer" <newcomer@flounder.com> wrote in message
news:4iim151b1kn6vo1dn1ortkrho942bnaloo@4ax.com...
I've never become a COM expert for that reason: to create a COM control is
gratuitously
complex. But to *use* an existing one has been very straightforward, and
I've never had a
problem. We started using some COM controls back in NT4, and that same
code has migrated
at least to XP without my touching it at all in that area (in fact, the
only changes were
enhancements requested by the client, such as supporting their new line of
controllers).
So the answer is that COM is much easier to use than to create, and is
remarkably robust
and reliable.
Really? You must like calling Release() a lot! ;) This code is from
Raymond Chen's OldNewThing blog, discussing manipulating Explorer Windows
using COM. http://blogs.msdn.com/oldnewthing/archive/2004/07/20/188696.aspx
---
#include <shlobj.h>
#include <exdisp.h>
TCHAR g_szPath[MAX_PATH];
TCHAR g_szItem[MAX_PATH];
void CALLBACK RecalcText(HWND hwnd, UINT, UINT_PTR, DWORD)
{
HWND hwndFind = GetForegroundWindow();
g_szPath[0] = TEXT('\0');
g_szItem[0] = TEXT('\0');
IShellWindows *psw;
if (SUCCEEDED(CoCreateInstance(CLSID_ShellWindows, NULL, CLSCTX_ALL,
IID_IShellWindows, (void**)&psw))) {
VARIANT v;
V_VT(&v) = VT_I4;
IDispatch *pdisp;
BOOL fFound = FALSE;
for (V_I4(&v) = 0; !fFound && psw->Item(v, &pdisp) == S_OK;
V_I4(&v)++) {
IWebBrowserApp *pwba;
if (SUCCEEDED(pdisp->QueryInterface(IID_IWebBrowserApp, (void**)&pwba)))
{
HWND hwndWBA;
if (SUCCEEDED(pwba->get_HWND((LONG_PTR*)&hwndWBA)) &&
hwndWBA == hwndFind) {
fFound = TRUE;
IServiceProvider *psp;
if (SUCCEEDED(pwba->QueryInterface(IID_IServiceProvider,
(void**)&psp))) {
IShellBrowser *psb;
if (SUCCEEDED(psp->QueryService(SID_STopLevelBrowser,
IID_IShellBrowser, (void**)&psb))) {
IShellView *psv;
if (SUCCEEDED(psb->QueryActiveShellView(&psv))) {
IFolderView *pfv;
if (SUCCEEDED(psv->QueryInterface(IID_IFolderView,
(void**)&pfv))) {
IPersistFolder2 *ppf2;
if (SUCCEEDED(pfv->GetFolder(IID_IPersistFolder2,
(void**)&ppf2))) {
LPITEMIDLIST pidlFolder;
if (SUCCEEDED(ppf2->GetCurFolder(&pidlFolder))) {
if (!SHGetPathFromIDList(pidlFolder, g_szPath)) {
lstrcpyn(g_szPath, TEXT("<not a directory>"),
MAX_PATH);
}
int iFocus;
if (SUCCEEDED(pfv->GetFocusedItem(&iFocus))) {
LPITEMIDLIST pidlItem;
if (SUCCEEDED(pfv->Item(iFocus, &pidlItem))) {
IShellFolder *psf;
if (SUCCEEDED(ppf2->QueryInterface(IID_IShellFolder,
(void**)&psf))) {
STRRET str;
if (SUCCEEDED(psf->GetDisplayNameOf(pidlItem,
SHGDN_INFOLDER,
&str))) {
StrRetToBuf(&str, pidlItem, g_szItem, MAX_PATH);
}
psf->Release();
}
CoTaskMemFree(pidlItem);
}
}
CoTaskMemFree(pidlFolder);
}
ppf2->Release();
}
pfv->Release();
}
psv->Release();
}
psb->Release();
}
psp->Release();
}
}
pwba->Release();
}
pdisp->Release();
}
psw->Release();
}
InvalidateRect(hwnd, NULL, TRUE);
----
This doesn't look particularly easy or robust to me. It's easy to forget
calling Release(), for example. Granted, using ATL CComPtr and CComQIPtr
helps a lot, but still there's all this crap about CoTaskMemFree() and other
stuff.
And get this... in VB, this does roughly the same thing:
http://blogs.msdn.com/oldnewthing/archive/2005/07/05/435657.aspx
var shellWindows = new ActiveXObject("Shell.Application").Windows();
for (var i = 0; i < shellWindows.Count; i++) {
var w = shellWindows.Item(i);
WScript.StdOut.WriteLine(w.LocationName + "=" + w.LocationURL);
}
COM and ActiveX were meant to be used by VB or JScript, or .NET, but not
C++. As you say, if it is required then we need to do it, but it's insane
to knowingly walk into something like this.
-- David