🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: borland.public.cppbuilder.nativeapi
Article #12407

Re: Failed to resolve explorer lnk from the taskbar

#12407
From: Remy Lebeau (TeamB)
Date: Sun, 07 Dec 2003 10:02
230 lines
9720 bytes
"Angus" <aguspickton@yahoo.com> wrote in message
news:3fd298ae@newsgroups.borland.com...
> But when applied to certain taskbar icons, such as
> explorer, PathName comes out as NULL.

You're going to have to be a little more specific. "explorer" could mean
anything.  Are you referring to "Windows Explorer"?  "Internet Explorer"?
"Some Other Explorer"?

The issue is probably due the fact that not all desktop items are shortcuts
to begin with.  How exactly are you determining the initial filename for the
desktop items and then calling the ResolveDeskTopIcon function to begin
with?  You didn't show any of that code at all.

> bool MXMAPI::ResolveDeskTopIcon(HWND hwnd, LPCSTR
> pszShortcutFile,AnsiString& FileName,AnsiString& PathName,
> AnsiString& Arguments,AnsiString& Description, WORD& Hotkey,
> AnsiString& IconPath,AnsiString& GetWorkingDirectory,int& IconIndex,
> int& GetShowCommand){

That is a lot of parameters for a function to have.  You should seriously
consider storing the link information into a separate structure instead.
That way, you can pass in just a single parameter for the structure itself,
rather than separate parameters for the individual values.  Not only does
that make the code cleaner and easier to manage, but it also is much more
flexible should you want to add more return values later on.  For example:

    struct TLinkInfo
    {
        AnsiString FileName;
        AnsiString PathName;
        AnsiString Arguments;
        AnsiString Description;
        AnsiString IconPath;
        AnsiString WorkingDir;
        int IconIndex;
        int ShowCommand;
        WORD Hotkey;
    };

    bool MXMAPI::ResolveDeskTopIcon(HWND hwnd, LPCSTR pszShortcutFile,
TListInfo &Info)
    {
        // fill in the Info parameter as needed..
    }

>   if(SUCCEEDED(CoInitialize(NULL))){

I would suggest that you look at the TInitOle class in utilcls.h.  It will
allow you to initialize *and release* COM in a safe manner, in case an
exception occurs your current code would have a lot of leaks.

>      IShellLink* psl;// Shell Link Interface
>      IPersistFile *ppf; // Interface to Shortcut

For the same reason above, I would suggest you look at the TComInterface
wrapper class in utilcls.h as well.

>             AnsiString FilePath(pszShortcutFile);
>             wchar_t wFilePath[MAX_PATH];
>             FilePath.WideChar(wFilePath, MAX_PATH);

Rather than doing that, you could just use a WideString instead.  It will
handle the char*->wchar_t* conversion for you.

>       char filename[MAX_PATH];

You should initialize such a buffer to MAX_PATH+1, to make sure that there
is always room for a null-terminator even if the path happens to be exactly
MAX_PATH in length.  Its rare, but it is possible.  You should also zero out
the buffer contents prior to using it.

>                        if(pidl){
>                          delete pidl;
>                          pidl = NULL;
>                        }

That is completely wrong.  The ITEMIDLIST was allocated by the Shell's
memory allocator.  You can't simply 'delete' the memory, the 'delete'
operator does not use the same memory manager as the Shell, thus the
ITEMIDLIST memory will *not* be freed correctly.  You must use
IMalloc::Free() or CoTaskMemFree() instead in order to free the memory
correctly.

>                    else throw Exception("Unable to resolve lnk filename");

By throwing your own exceptions, you are leaking *all* of your interface
instances.  With the way you have your code set up, Release() will not be
called if an exception is thrown.  Either use TComInterface as I mentioned
above, or else you must change the way you are using your exception
handling, in order to make sure that Release() is always called no matter
what.

>    ppf->Release();      // Release pointer to IPersistFile interface.
>    psl->Release();    // Release pointer to IShellLink interface.

You are calling Release() on the IPersistFile instance even if the call to
QueryInterface() fails, thus you would be calling Release() on an invalid
pointer.  You need to move that call to Release() inside the if() block for
the QueryInterface() result, not outside of the block.

>  e.Message += "Error: -(ResolveIt) mxm";

I do not recommend that you *ever* alter any of the properties of an
Exception when you catch one.  Always copy the Exception's values to local
variables and use those instead.

>  Application->ShowException(&e);

Likewise, I would not suggest using ShowException().  It displays a default
message box that contains no meaninful information at all about the error.
You should display your own message box so that you can include more
meaningful info about why the error occured, etc.

With all of that said, try this code instead:

    #include <utilcls.h>
    #include <shellapi.h>

    struct TLinkInfo
    {
        AnsiString FileName;
        AnsiString PathName;
        AnsiString Arguments;
        AnsiString Description;
        AnsiString IconPath;
        AnsiString WorkingDir;
        int IconIndex;
        int ShowCommand;
        WORD Hotkey;
    };

    bool MXMAPI::ResolveDeskTopIcon(HWND hwnd, LPCSTR pszShortcutFile,
TLinkInfo &Info)
    {
        // initialize defaults
        Info.FileName = "";
        Info.PathName = "";
        Info.Arguments = "";
        Info.Description = "";
        Info.IconPath = "";
        Info.WorkingDir = "";
        Info.IconIndex = -1;
        Info.ShowCommand = 0;
        Info.Hotkey = 0;

        try
        {
            // Before creating our CoCreatInstance, we first must initialise
the com library!
            TInitOle ole;
            if( !ole )
                throw Exception("Unable to initialize COM");

            // Get a pointer to the IShellLink interface.
            TComInterface<IShellLink> psl;
            if( FAILED(CoCreateInstance(CLSID_ShellLink, NULL,
CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl)) )
                throw Exception("Unable to create IShellLink");

            // Get a pointer to the IPersistFile interface.
            TComInterface<IPersistFile> ppf;
            if( FAILED(psl->QueryInterface(IID_IPersistFile,
(LPVOID*)&ppf)) )
                throw Exception("Unable to request IPersistFile");

            // use the IPersistFile::Load function to load the shortcut
            if( FAILED(ppf->Load(WideString(pszShortcutFile), STGM_READ)) )
                throw Exception("Unable to load IShellLink");

            // use the IShellLink::Resolve function to resolve the link
            if( FAILED(psl->Resolve(NULL, SLR_INVOKE_MSI | SLR_NOUPDATE |
SLR_NO_UI)) )
                throw Exception("Unable to resolve IShellLink");

            // get the path of the link's target
            LPITEMIDLIST pidl = NULL;
            if( SUCCEEDED(psl->GetIDList(&pidl)) )
            {
                char buf[MAX_PATH+1] = {0};
                if( SHGetPathFromIDList(pidl, buf) )
                {
                    Info.PathName = buf;
                    Info.FileName = ExtractFileName(Info.PathName);
                }
                CoTaskMemFree(pidl);
            }

            if( Info.FileName.IsEmpty() )
                throw Exception("Unable to resolve lnk filename");

            char desc[MAX_PATH+1] = {0};
            if( FAILED(psl->GetDescription(desc, MAX_PATH)) )
                throw Exception("Unable to resolve lnk description");
            Info.Description = desc;

            char args[MAX_PATH+1] = {0};
            if( FAILED(psl->GetArguments(args, MAX_PATH)) )
                throw Exception("Unable to resolve lnk Arguments");
            Info.Arguments = args;

            if( FAILED(psl->GetHotkey(&Info.Hotkey)) )
                throw Exception("Error:Unable to resolve lnk Hotkey");

            char icon[MAX_PATH+1] = {0};
            if( FAILED(psl->GetIconLocation(icon, MAX_PATH,
&Info.IconIndex)) )
                throw Exception("Unable to resolve lnk IconLocation");
            Info.IconPath = icon;

            char workingdir[MAX_PATH+1] = {0};
            if( FAILED(psl->GetArguments(workingdir, MAX_PATH)) )
                throw Exception("Unable to resolve lnk IconLocation");
            Info.WorkingDir = workingdir;

            if( FAILED(psl->GetShowCmd(&Info.ShowCommand)) )
                throw Exception("Unable to resolve lnk IconLocation");
        }
        catch(const Exception &e)
        {
            MessageBox(hwnd, e.Message.c_str(), "Messenger", MB_OK |
MB_ICONERROR | MB_TOPMOST);
            return false;
        }
        return true;
    }


Gambit
Technical Details
Message-ID: <3fd2f996@newsgroups.borland.com>
Path: arc1-ca.pugleaf.net!archiver1.google.com!news2.google.com!fu-berlin.de!newsfeed01.sul.t-online.de!t-online.de!newsgroups.borland.com!not-for-mail
References: <3fd298ae@newsgroups.borland.com>

Show Full Headers
Complete Article Headers
X-Google-Language: ENGLISH,ASCII-7-bit
X-Google-Thread: 10cc67,ebe7a1f15ea83f48
X-Google-Attributes: gid10cc67,public
X-Google-ArrivalTime: 2003-12-07 02:09:29 PST
From: "Remy Lebeau \(TeamB\)" <gambit47.no.spam@no.spam.yahoo.com>
Newsgroups: borland.public.cppbuilder.nativeapi
References: <3fd298ae@newsgroups.borland.com>
Subject: Re: Failed to resolve explorer lnk from the taskbar
Date: Sun, 7 Dec 2003 02:02:14 -0800
Lines: 232
X-Priority: 3
X-MSMail-Priority: Normal
X-Newsreader: Microsoft Outlook Express 6.00.2800.1158
X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2800.1165
NNTP-Posting-Host: 67.23.78.224
Message-ID: <3fd2f996@newsgroups.borland.com>
X-Trace: newsgroups.borland.com 1070791062 67.23.78.224 (7 Dec 2003 01:57:42 -0700)
Path: arc1-ca.pugleaf.net!archiver1.google.com!news2.google.com!fu-berlin.de!newsfeed01.sul.t-online.de!t-online.de!newsgroups.borland.com!not-for-mail