Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

How to get selected file(s)/folder(s) from Windows Explorer?



  • Hey All,

    I've done a fair bit of Googling and searching this forum, and I can't seem to find the answer I need.

    I want to do a couple of things for a Windows specific exe:

    • Find the currently active window on the desktop
    • Determine if it is a Windows Explorer window
    • Get a list of files/folders that the user has currently selected in that window

    Could someone point me in the right direction please?

    Thank you!

    Steve Q :-)



  • Qt doesn't have API for that. So it is not possible by Qt.
    You'd better to ask at other windows API related forums.



  • @Bonnie I was really hoping this wasn't going to be the answer.

    Thanks so much for your reply.

    -SQ :-)



  • @steveq
    First, Qt is designed to be platform/windowing system independent. Its API hides windowing system specific stuff. So, by and large, as soon as you want something window-system-specific Qt is not the level to access that --- you need to drop down to the platform's windowing system API.

    Second, I may be wrong (I often am!), but I would have thought what you want to do will be difficult.

    If you write a Windows Explorer "addin"/"plugin", which runs inside Explorer, you have access to calls like "what files are selected in this Explorer window". However, you want to do it from the opposite direction. You want find a Windows window handle for a running application which happens to be Windows Explorer and then go: "Knock, knock, Mr Windows Explorer process, could you tell me what is selected in your window". I don't know how you would establish such communication with a running Explorer and no addin.

    Can you name any other program you know of which can access a running Explorer to discover this, without there being an Explorer addin to service it?


  • Lifetime Qt Champion

    Hi
    i needed a tool to sort/move some file and wanted to it via Explorer and my own little app.
    It turns out that talking to Explorer.exe is done via windows COM api / interfaces and
    for me, it was a horrible experience to dig into, and very easy to crash it all.

    So I did something else.

    I used autoit3
    https://www.autoitscript.com/forum/topic/162905-automating-windows-explorer/

    and simply made it save a file with the stuff i needed. Took maybe 30 mins to get it working.

    I dont know if you can do the same as you don't tell why you need this but maybe it can be useful too.

    the autoit3 can make the script into self-contained exe so its easy to use on other pc's and you can call it via QProcess.



  • @mrjj said in How to get selected file(s)/folder(s) from Windows Explorer?:

    It turns out that talking to Explorer.exe is done via windows COM api / interfaces

    The OP wishes to pick

    Find the currently active window on the desktop
    Determine if it is a Windows Explorer window

    to communicate with. Given that there may be multiple Explorer windows/processes running, how will you succeed in picking/talking to the right one via COM?

    IIRC, our experience was that if multiple processes run with offering the same Automation/COM CLSID (or whatever it is) you get connected to a random one. Only changing the CLSID for a particular instance allowed connection to that instance?


  • Lifetime Qt Champion

    @JonB

    No idea. I just used autoit3 to avoid digging around in that COM
    garbage.

    It does find the Explorer window that has focus.

    I didn't dig into details as the task was not to get to know how to talk to explorer but other stuff :)



  • @mrjj said in How to get selected file(s)/folder(s) from Windows Explorer?:

    autoit3

    Yes, I see, there's quite a bit of code going on in that, no wonder you used that code instead of writing your own! :)


  • Lifetime Qt Champion

    @JonB

    Yes it was quite crazy how ugly and how much code Windows COM
    interfaces demanded such a task.
    So when AutoIt script just worked, i used that instead.
    Would not work for a plugin etc. but for me, it was fine as i just wanted the selected filenames from explorer.



  • @JonB @mrjj thanks for your responses.

    I have moved my little project over to Visual Studio :-(
    Basically I want to be able to select files in Explorer, right click on the window, and select my program which will copy all of the names of the files into the clipboard buffer.
    I have now figured out how to do this in VS. If only I could do it in QT, but alas, never mind.
    The vast majority of this code was taken from here:

    Querying information from an Explorer window

    I added the ability to loop through all the selected files, not just the first one found.
    For the sake of completeness, here is my code. At the moment, this code will find the first open Explorer window, get all the selected file names, and display them one at a time in a message box.
    Now all I have to do is copy it to the clipboard, and then add my program to the Explorer context menu.
    Hope this helps, remember, this code is for Visual Studio!

    // This code is for Microsoft Visual Studio, NOT QT!
    
    	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 ( true ) // For testing purposes, just use the first Explorer window found.
    //				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 );
    											}
    
    											// This section added by SQ to loop through all selected files rather than just the first one
    											IShellItemArray *items;
    
    											HRESULT res = pfv->Items( SVGIO_SELECTION, IID_IShellItemArray, ( void ** ) &items );
    
    											DWORD count;
    											items->GetCount( &count );
    
    											for ( DWORD i = 0; i < count; i++ )
    											{
    												IShellItem *pRet;
    
    												LPWSTR nameBuffer;
    
    												items->GetItemAt( i, &pRet );
    
    												pRet->GetDisplayName( SIGDN_DESKTOPABSOLUTEPARSING, &nameBuffer );
    
    												CString name = PathFindFileName( nameBuffer );
    
    												AfxMessageBox( name );
    
    												pRet->Release();
    
    												CoTaskMemFree( nameBuffer );
    											}
    
    											items->Release();
    
    /*
    This section commented out as it only displays the first selected file. - SQ
    
    											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 );
    
    															AfxMessageBox( g_szItem );
    														}
    
    														psf->Release();
    													}
    
    													CoTaskMemFree( pidlItem );
    												}
    											}
    */
    
    											CoTaskMemFree( pidlFolder );
    										}
    
    										ppf2->Release();
    									}
    
    									pfv->Release();
    								}
    
    								psv->Release();
    							}
    
    							psb->Release();
    						}
    
    						psp->Release();
    					}
    				}
    
    				pwba->Release();
    			}
    
    			pdisp->Release();
    		}
    
    		psw->Release();
    	}
    

    Thanks again,

    -SQ :-)


Log in to reply