Avatar of rjohnsonvtpinc
rjohnsonvtpincFlag for United States of America

asked on 

Namespace extension treeview create duplicate folder

In the left pane of explorer the treview shows my folder hierarchy.  If I expand the folder using the (+) then click on a subfolder, my right pane is populated but then a copy of the folder I clicked on gets put under the root folder.  Example: windows 7

Desktop
     UserFolder
            Folder1
             Folder2
                   SubFolder1
                   SubFolder2
             Folder3

If I click on Subfolder2  I get this:
Desktop
     UserFolder
            SubFolder2
            Folder1
             Folder2
                   SubFolder1
                   SubFolder2
             Folder3


Anyone have any Ideas?
CWindows OSC++

Avatar of undefined
Last Comment
Member_2_5069294
Avatar of rjohnsonvtpinc
rjohnsonvtpinc
Flag of United States of America image

ASKER

If I navigate via the right explorer pane it works just find and the address bar is correct.
computer\UserFolder\Folder2\Subfolder2

but if I navigate the treeview is looks like this
UserFolder\SubFolder2
Avatar of Member_2_5069294
Member_2_5069294

Hello rjohnsonvtpinc,

Not much to go on here.  As pure quess work I have two suspects, a bug in the handling of ITEMIDLISTs, or in the IShellFolder::GetDisplayNameOf and IShellFolder::ParseDisplayName loop.  Maybe something to do with the SHGDN_INFOLDER flag?  Can you breakpoint those functions when Explorer calls them and see what parameters its using?
Avatar of rjohnsonvtpinc

ASKER

Is  BindToObject recursively called?  Here is a trace of my code when I click on the folder and it appears it is.  BindToObject is the first time I see the wrong folder path.  Any Thoughts?

2011-07-11 16:15:00.687    -06:00|UserFolder|TRACE|2736|Digitiliti UserFolder VirtualFolder.cpp 96 Jul 11 2011 CVirtualFolder::GetCurFolder [Shared] [Shared\Public]
2011-07-11 16:15:00.687    -06:00|UserFolder|TRACE|2736|CVirtualFolder::BindToObject <{000214E6-0000-0000-C000-000000000046}>

Click
2011-07-11 16:15:00.687    -06:00|UserFolder|TRACE|2736|---->CVirtualFolder::BindToObject [Paul2]


2011-07-11 16:15:00.687    -06:00|UserFolder|TRACE|2736|CVirtualFolder::BindToObject <{000214E6-0000-0000-C000-000000000046}>
2011-07-11 16:15:00.687    -06:00|UserFolder|TRACE|2736|---->CVirtualFolder::BindToObject [Shared]
2011-07-11 16:15:00.687    -06:00|UserFolder|TRACE|2736|CVirtualFolder::BindToObject <{000214E6-0000-0000-C000-000000000046}>
2011-07-11 16:15:00.687    -06:00|UserFolder|TRACE|2736|---->CVirtualFolder::BindToObject [Shared]
2011-07-11 16:15:00.687    -06:00|UserFolder|TRACE|2736|new CVirtualFolder::m_pidlPath = <UserFolder\Shared>
2011-07-11 16:15:00.687    -06:00|UserFolder|TRACE|2736|new CVirtualFolder::m_pidlPath = <UserFolder\Shared\Public>
2011-07-11 16:15:00.687    -06:00|UserFolder|TRACE|2736|new CVirtualFolder::m_pidlPath = <UserFolder\Shared\Public\Paul2>
2011-07-11 16:15:00.703    -06:00|UserFolder|TRACE|2736|CVirtualFolder::BindToObject <{000214E6-0000-0000-C000-000000000046}>
2011-07-11 16:15:00.703    -06:00|UserFolder|TRACE|2736|---->CVirtualFolder::BindToObject [Paul2]

Problem Line
2011-07-11 16:15:00.703    -06:00|UserFolder|TRACE|2736|new CVirtualFolder::m_pidlPath = <UserFolder\Paul2>


2011-07-11 16:15:00.703    -06:00|UserFolder|TRACE|2736|CVirtualFolder::BindToObject <{000214E6-0000-0000-C000-000000000046}>
2011-07-11 16:15:00.703    -06:00|UserFolder|TRACE|2736|---->CVirtualFolder::BindToObject [Shared]
2011-07-11 16:15:00.703    -06:00|UserFolder|TRACE|2736|CVirtualFolder::BindToObject <{000214E6-0000-0000-C000-000000000046}>
2011-07-11 16:15:00.703    -06:00|UserFolder|TRACE|2736|---->CVirtualFolder::BindToObject [Shared]
2011-07-11 16:15:00.703    -06:00|UserFolder|TRACE|2736|new CVirtualFolder::m_pidlPath = <UserFolder\Shared>
2011-07-11 16:15:00.703    -06:00|UserFolder|TRACE|2736|new CVirtualFolder::m_pidlPath = <UserFolder\Shared\Public>
2011-07-11 16:15:00.703    -06:00|UserFolder|TRACE|2736|CVirtualFolder::BindToObject <{000214E6-0000-0000-C000-000000000046}>
2011-07-11 16:15:00.703    -06:00|UserFolder|TRACE|2736|---->CVirtualFolder::BindToObject [Paul2]
2011-07-11 16:15:00.703    -06:00|UserFolder|TRACE|2736|CVirtualFolder::BindToObject <{000214E6-0000-0000-C000-000000000046}>
2011-07-11 16:15:00.703    -06:00|UserFolder|TRACE|2736|---->CVirtualFolder::BindToObject [Shared]
2011-07-11 16:15:00.703    -06:00|UserFolder|TRACE|2736|CVirtualFolder::BindToObject <{000214E6-0000-0000-C000-000000000046}>
2011-07-11 16:15:00.703    -06:00|UserFolder|TRACE|2736|---->CVirtualFolder::BindToObject [Shared]
2011-07-11 16:15:00.718    -06:00|UserFolder|TRACE|2736|new CVirtualFolder::m_pidlPath = <UserFolder\Shared>
2011-07-11 16:15:00.718    -06:00|UserFolder|TRACE|2736|new CVirtualFolder::m_pidlPath = <UserFolder\Shared\Public>
2011-07-11 16:15:00.718    -06:00|UserFolder|TRACE|2736|new CVirtualFolder::m_pidlPath = <UserFolder\Shared\Public\Paul2>
Avatar of rjohnsonvtpinc

ASKER

I am thinking maybe my BindToObject function is not quite right.
I don't know the details of how explorer calls BindToObject, but I would expect that it calls BindToObject recursively.  Any process involving a data tree will tend to be recursive.  To my eyes the trace only show that problem occurs, not where it comes from.  At some point, BindToObject is called for 'UserFolder\Paul2'  the question is where is that path coming from.

Judging from the output 'UserFolder' is the root of your extensions namespace and 'Paul2' is an object at the end of the path tree.  I assume something is adding the root name to the last thing that was returned from a function. Is it possible that the system is recursing down the tree, gets to Paul2 and finds no more items, but a buffer or pointer is not cleared, preserving the reference to Paul2?

If you put a folder inside of Paul2 (lets call it 'Joe'), I guess it would try to BindToObject 'UserFolder\Joe'.  Are you not able to debug the extension?
Avatar of rjohnsonvtpinc

ASKER

Yes I am able to debug the extension, but the message are so many I can not get to where I want to be.

I do have folders below Paul2.  I added to to break when the bindtoobject finds paul2 in the name.  The caller of the function is always the shell.  Here is what I am thinking my problem is.  When In bindtoobject the pidl is for paul2 and the root pidl is UserFolder.  I have no in between pidl's so when the root pidl, pidlpath and pidl for paul2 are combined  it get the pidlpath of UserFolder\Paul2.  I am unable to prove that is the problem yet, because I can't figure out how to maintain the path I traversed by clicking the (+) signs.
My understanding is that every time the shell recurses through the tree calling BindToObject, you return a different IShellFolder object for each level of the tree.  Is that what your program does?

When it asks for the path of Paul2, it should be asking the IShellFolder object that is the parent of Paul2.  In which case, the object should now what its path is, or be able to get the path of its parent and add its own identifier.

Each of the IShellFolder objects has its own reference count and can have the same function table.  But they will need some other information to know what folder in the tree they represent.  It makes sense to allocate them with the Shell's allocator.
Avatar of rjohnsonvtpinc

ASKER

Yes I was doing that.  Here something new for you.  This all started because on Windows 7 my icons where not showing up in the tree like they where on windows xp.  So I searched online and found something saying to fix this I had to change       IPersistFolder to IPersistFolder2.  Changing this and implementing the new methods, the Icons showed up.  How ever then this duplicate folder off the root happened.  I changed back to IPersistFolder and everything works as I wanted except the Icons in the treeview on windows 7.  If I can fix that issue without implementing IPersistFolder2 that would be ok with me.  Any thoughts on that?
Sadly, that doesn't tell me anything.  I can't see why using IPersistFolder2 shuuld have an effect on the icon mechanism, but then MS do change things and I guess 7 might rely on IPersistFolder2.  Are you implementing IExtractIcon too?  Do you get the default Folder icon if don't implement IPersistFolder2?

The fact this goes wrong when you use IPersistFolder2 suggests the problem might be in IPersistFolder::GetCurFolder.  Given that it's the major difference between the two sets of code.  Is there some ITEMIDLIST manipulation in that function?  Can you check that it always returns the correct data?

Could you write a test application that creates it own tree view by recursing through the folder path?  I'd offer to do this except I'm not running 7 on any of my machines, the bug probably wouldn't happen.
If you are creating a new IShellFolder for each step down the tree, then surely you can trace the path being traversed?  The IShellFolder object knows it own path.
Avatar of rjohnsonvtpinc

ASKER

Yes,  I have implemented IExtractIcon.  No the icon that displays is blank white paper icon.

STDMETHODIMP CVirtualFolder::GetCurFolder( LPITEMIDLIST *ppidl)
{
    HRESULT hReturn = E_FAIL;
      try
    {
        if( _Module.m_pidlNSFROOT )
        {
            CXString sFullName = "";
            LPPIDLDATA pData1 =  NULL;
           *ppidl = CNWSPidlMgr::Copy( _Module.m_pidlNSFROOT);
            hReturn = *ppidl ? S_OK : E_OUTOFMEMORY;
        }
        else
        {
            *ppidl = NULL;
            hReturn = S_FALSE; //Success but empty
        }
    }
    catch(...)
    {
        Log::LogMessage( error ,MY_INFO, L"Unknown exception caught.");
    }
      return hReturn;
}
Avatar of rjohnsonvtpinc

ASKER

STDMETHODIMP CVirtualFolder::BindToObject(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppRetVal)
{
      HRESULT hr = E_FAIL;
      NOT_USED( pbcReserved );

    try
    {
        *ppRetVal = NULL;

        if( riid != IID_IShellFolder)
        {
              hr = E_NOINTERFACE;
            goto ExitLabel;
        }
       
        // If the passed pidl is not ours, fail.
        if (!m_PidlMgr.IsMine(pidl))
          return E_INVALIDARG;


        CComObject<CVirtualFolder> *pVFObj = 0;

        hr = CComObject<CVirtualFolder>::CreateInstance(&pVFObj);
        if(FAILED(hr))
             goto ExitLabel;

        pVFObj->AddRef();

        LPITEMIDLIST pidlNew = m_PidlMgr.Concatenate(m_pidlPath,pidl);
        pVFObj->m_pidlPath = m_PidlMgr.Copy(pidlNew);

        m_PidlMgr.Delete(pidlNew);

        hr = pVFObj->QueryInterface(riid, ppRetVal);
        pVFObj->Release();

    }
    catch(...)
    {
        Log::LogMessage( error ,MY_INFO, L"Unknown exception caught.");
    }
ExitLabel:
    return hr;
}
Avatar of rjohnsonvtpinc

ASKER

When I click the folder in the treeview the BindToObject is called, but the m_pidlPath is empty.  It is always correct in the ShellView
In the GetCurFolder code, does the slse part of the condition ever get run?  The part that happens if m_pidlNSFROOT is NULL.  I guess thats the root of your extension, why would it be NULL?  How does it return a sub folder path if it's the IPersistFolder of a sub folder?
Avatar of rjohnsonvtpinc

ASKER

Have not checked to see if that condition is ever hit.   This is URL is one I found during this process and my code is modeled after this discussion

http://us.generation-nt.com/answer/ipersistfolder2-getcurfolder-what-should-i-return-subfolders-help-37085512.html

IPersisitFolder initialize sets  m_pidlNSFROOT
and  GetCurFolder returns  m_pidlNSFROOT
ASKER CERTIFIED SOLUTION
Avatar of Member_2_5069294
Member_2_5069294

Blurred text
THIS SOLUTION IS ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
Avatar of rjohnsonvtpinc

ASKER

That was the missing piece.  If the pidlPath is was maintaining was null I combined the (http://bit.ly/mfl0Qh and the passed in pidl.  If it was not null I combined pidlPath and the passed in pidl.
Avatar of rjohnsonvtpinc

ASKER

Let me make my last response more clear.

I was maintaining a path from the root called pidlPath.  What I was missing in the GetCurFolder was if pidlPath was null I needed to combine pidlNSFROOT and the passed in pidl.  If it was not null I needed to add pidlPath and pidl and return that.   dThat is what I did and it works great.  Thanks for the help.
Glad it worked, though I'm not sure I got the right answer exactly.  Still, whatever solves the problem.  The second explanation did make a lot more sense.  Talking about the shell needs very precise language sometimes.
Windows OS
Windows OS

This topic area includes legacy versions of Windows prior to Windows 2000: Windows 3/3.1, Windows 95 and Windows 98, plus any other Windows-related versions including Windows Mobile.

129K
Questions
--
Followers
--
Top Experts
Get a personalized solution from industry experts
Ask the experts
Read over 600 more reviews

TRUSTED BY

IBM logoIntel logoMicrosoft logoUbisoft logoSAP logo
Qualcomm logoCitrix Systems logoWorkday logoErnst & Young logo
High performer badgeUsers love us badge
LinkedIn logoFacebook logoX logoInstagram logoTikTok logoYouTube logo