2021-06-27 21:25:29 +00:00
/***
2024-10-16 13:45:07 +00:00
Copyright ( C ) 2021 Jamie Reece Wilson ( a / k / a " Reece " ) . All rights reserved .
2021-06-27 21:25:29 +00:00
2022-11-17 07:46:07 +00:00
File : AuOpen . Win32 . cpp
2021-06-27 21:25:29 +00:00
Date : 2021 - 6 - 12
Author : Reece
* * */
2021-09-30 14:57:41 +00:00
# include <Source/RuntimeInternal.hpp>
2022-11-17 07:46:07 +00:00
# include "AuProcesses.hpp"
# include "AuOpen.Win32.hpp"
2021-10-23 18:42:05 +00:00
# include <Source/IO/FS/FS.hpp>
2023-09-17 20:33:14 +00:00
# define COINIT_APARTMENTTHREADED 0x2
# define COINIT_DISABLE_OLE1DDE 0x4
2021-10-23 18:42:05 +00:00
2021-06-27 21:25:29 +00:00
namespace Aurora : : Processes
{
2024-11-17 15:48:24 +00:00
static AuList < AuPair < AuString , int > > gOpenItems ;
2023-12-26 21:01:29 +00:00
static AuConditionMutex gCondMutex ;
static AuConditionVariable gCondVariable ( AuUnsafeRaiiToShared ( gCondMutex . AsPointer ( ) ) ) ;
2021-11-05 17:34:23 +00:00
static AuThreads : : ThreadUnique_t gOpenerThread ;
2021-10-23 18:42:05 +00:00
static void RunTasks ( )
{
AU_LOCK_GUARD ( gCondMutex ) ;
2024-11-17 15:48:24 +00:00
while ( AuIsThreadRunning ( ) | | gOpenItems . size ( ) )
2021-10-23 18:42:05 +00:00
{
2021-11-22 16:16:02 +00:00
try
2021-10-23 18:42:05 +00:00
{
2024-10-16 13:45:07 +00:00
while ( gOpenItems . size ( ) )
2021-11-22 16:16:02 +00:00
{
2024-10-16 13:45:07 +00:00
auto & [ uri , type ] = gOpenItems [ 0 ] ;
2023-09-17 20:33:14 +00:00
bool bDirExists { } ;
bool bFileExists { } ;
if ( uri . empty ( ) )
{
continue ;
}
if ( ! pShellExecuteW )
{
SysPushErrorUninitialized ( " Cannot open URIs yet " ) ;
continue ;
}
bFileExists = AuIOFS : : FileExists ( uri ) ;
2024-11-17 15:48:24 +00:00
if ( type )
2023-09-17 20:33:14 +00:00
{
bDirExists = AuIOFS : : DirExists ( uri ) ;
if ( ! bFileExists & &
! bDirExists )
{
SysPushErrorGeneric ( " Exploit attempt? Attempted to open non-existent file/directory. (request: {}) " , uri ) ;
continue ;
}
2024-11-23 06:46:26 +00:00
if ( bFileExists & & ! gRuntimeConfig . processesConfig . bBypassInternetBlockCheckOpenFile )
2023-09-17 20:33:14 +00:00
{
2024-01-20 20:20:57 +00:00
if ( AuFS : : IsFileBlocked ( uri ) )
2023-09-17 20:33:14 +00:00
{
SysPushErrorGeneric ( " Exploit attempt? Attempted to open untrusted file/directory. (request: {}) " , uri ) ;
continue ;
}
}
}
else
{
if ( bFileExists )
{
SysPushErrorGeneric ( " Exploit attempt? Attempted to open existing file/directory via URI ({}) " , uri ) ;
continue ;
}
}
2024-10-16 13:45:07 +00:00
auto u16OpenURI = Locale : : ConvertFromUTF8 ( uri ) ;
auto pOpenType = bDirExists ? L " explore " : L " open " ;
2024-11-17 15:48:24 +00:00
bool bReveal = type = = 2 & &
pILCreateFromPathW & &
pSHOpenFolderAndSelectItems & &
pILFree ;
2024-10-16 13:45:07 +00:00
gCondMutex - > Unlock ( ) ;
2024-11-17 15:48:24 +00:00
if ( bReveal )
{
if ( auto pIL = pILCreateFromPathW ( u16OpenURI . c_str ( ) ) )
{
pSHOpenFolderAndSelectItems ( pIL , 0 , nullptr , 0 ) ;
pILFree ( pIL ) ;
}
}
else
{
pShellExecuteW ( nullptr ,
pOpenType ,
u16OpenURI . c_str ( ) ,
nullptr ,
nullptr ,
SW_SHOWNORMAL ) ;
}
2024-10-16 13:45:07 +00:00
gCondMutex - > Lock ( ) ;
2024-11-17 15:48:24 +00:00
// Work mostly in-place and move all N-1 elements for each N, vs do all in place and clear all later (requires uninterrupted mutex lock?), vs making a copy of the work queue (requires another alloc unless AuExchanged in-place, + needs another nested indentation for a for itr loop).
// The former is pretty much the same as the latter with an AuExchange, except we use .erase(itr) moves to single step through the queue instead of batching & erasing all at once.
// We can just do ShellExecuteW outside of the lock and access a locally owned U16-translated string container, without bothering the write side mutex or mutable work container.
2024-10-16 13:45:07 +00:00
// A work queue buffer could solve this, but eh.
gOpenItems . erase ( gOpenItems . begin ( ) ) ;
2021-11-22 16:16:02 +00:00
}
2023-09-17 20:33:14 +00:00
2021-11-22 16:16:02 +00:00
gCondVariable - > WaitForSignal ( ) ;
}
catch ( . . . )
{
2024-10-16 13:45:07 +00:00
SysPushErrorCatch ( " An error occurred while dispatching a ShellExecute runner frame " ) ;
2021-10-23 18:42:05 +00:00
}
}
}
2021-10-23 22:37:18 +00:00
static void OpenerThread ( )
2021-10-23 18:42:05 +00:00
{
2023-09-17 20:33:14 +00:00
if ( pCoInitializeEx )
{
( void ) pCoInitializeEx ( nullptr , COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE ) ;
}
2021-10-23 18:42:05 +00:00
RunTasks ( ) ;
2023-09-17 20:33:14 +00:00
if ( pCoUninitialize )
{
pCoUninitialize ( ) ;
}
2021-10-23 18:42:05 +00:00
}
void InitWin32Opener ( )
{
2021-11-05 17:34:23 +00:00
gOpenerThread = AuThreads : : ThreadUnique ( AuThreads : : ThreadInfo (
AuMakeShared < AuThreads : : IThreadVectorsFunctional > ( AuThreads : : IThreadVectorsFunctional : : OnEntry_t ( std : : bind ( OpenerThread ) ) ,
AuThreads : : IThreadVectorsFunctional : : OnExit_t { } ) ,
2021-10-23 18:42:05 +00:00
" COM ShellExecute Runner "
) ) ;
2022-01-24 18:37:06 +00:00
SysAssert ( gOpenerThread ) ;
2021-10-23 18:42:05 +00:00
gOpenerThread - > Run ( ) ;
}
void DeinitWin32Opener ( )
{
2023-10-24 17:33:25 +00:00
if ( ! gOpenerThread )
{
return ;
}
2021-10-23 18:42:05 +00:00
gOpenerThread - > SendExitSignal ( ) ;
2023-09-09 22:09:28 +00:00
gCondVariable - > Signal ( ) ;
2021-10-23 18:42:05 +00:00
gOpenerThread . reset ( ) ;
}
2024-04-19 03:33:57 +00:00
AUKN_SYM void OpenUri ( const AuROString & uri )
2021-06-27 21:25:29 +00:00
{
2024-09-09 01:47:38 +00:00
AU_LOCK_GLOBAL_GUARD ( gCondMutex ) ;
2024-11-17 15:48:24 +00:00
AuTryInsert ( gOpenItems , AuMakePair ( AuString ( uri ) , 0 ) ) ;
2023-09-09 22:09:28 +00:00
gCondVariable - > Signal ( ) ;
2021-06-27 21:25:29 +00:00
}
2024-04-19 03:33:57 +00:00
AUKN_SYM void OpenFile ( const AuROString & file )
2021-06-27 21:25:29 +00:00
{
2023-09-09 22:09:28 +00:00
auto path = AuIOFS : : NormalizePathRet ( file ) ;
2023-09-12 19:48:35 +00:00
if ( path . empty ( ) )
{
SysPushErrorMemory ( ) ;
return ;
}
2023-09-09 22:09:28 +00:00
{
2024-09-09 01:47:38 +00:00
AU_LOCK_GLOBAL_GUARD ( gCondMutex ) ;
2024-11-17 15:48:24 +00:00
AuTryInsert ( gOpenItems , AuMove ( AuMakePair ( AuMove ( path ) , 1 ) ) ) ;
gCondVariable - > Signal ( ) ;
}
}
AUKN_SYM void RevealInDirectory ( const AuROString & file )
{
auto path = AuIOFS : : NormalizePathRet ( file ) ;
if ( path . empty ( ) )
{
SysPushErrorMemory ( ) ;
return ;
}
{
AU_LOCK_GLOBAL_GUARD ( gCondMutex ) ;
AuTryInsert ( gOpenItems , AuMove ( AuMakePair ( AuMove ( path ) , 2 ) ) ) ;
2023-09-09 22:09:28 +00:00
gCondVariable - > Signal ( ) ;
}
2021-06-27 21:25:29 +00:00
}
2022-09-15 19:48:50 +00:00
}