//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
//
// CommonHelpers satellite library | Author: Sergei Y.Kitáev
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#include "Precompiled.h"
#include "SharedIncludes.h"

namespace CommonHelpers {
//==================================================================================================

static SysHelpers_ShellLinkProperties::SysHelpers_ShellLinkProperties()
{
   SystemLib::Access();
}

//==================================================================================================

SysHelpers_ShellLinkProperties::SysHelpers_ShellLinkProperties()
{
   HOperatingSystem::VerifyWindowsVistaOrLater();

   HRESULT hResult;

   pin_ptr<IShellLink*> pPSLInterface = &_PSLInterface_;
   if ( FAILED( hResult = ::CoCreateInstance(
      CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
      IID_IShellLink, ($PPVOID)pPSLInterface )))
      throw HCOMError::CreateOpFailedException_CantObtainInterface( "IShellLink", hResult );

   pin_ptr<IPersistFile*> pPPersistFileInterface = &_PPersistFileInterface_;
   if ( FAILED( hResult = PSLInterface -> QueryInterface(
      IID_IPersistFile, ($PPVOID)pPPersistFileInterface )))
   {
      try { this->!SysHelpers_ShellLinkProperties(); } catch (Exception^) {}
      throw HCOMError::CreateOpFailedException_CantObtainInterface( "IPersistFile", hResult );
   }

   pin_ptr<IShellLinkDataList*> pPSLDataListInterface = &_PSLDataListInterface_;
   if ( FAILED( hResult = PSLInterface->QueryInterface(
      IID_IShellLinkDataList, ($PPVOID)pPSLDataListInterface )))
   {
      try { this->!SysHelpers_ShellLinkProperties(); } catch (Exception^) {}
      throw HCOMError::CreateOpFailedException_CantObtainInterface(
         "IShellLinkDataList", hResult );
   }
}

SysHelpers_ShellLinkProperties::~SysHelpers_ShellLinkProperties()
{
   this -> !SysHelpers_ShellLinkProperties();
}

//--------------------------------------------------------------------------------------------------

SysHelpers_ShellLinkProperties::!SysHelpers_ShellLinkProperties()
{
   if ( _FinalizerAccessed_ ) return;
   _FinalizerAccessed_ = true;
   if ( PSLDataListInterface )
      HTPointer::NullValueExchange( _PSLDataListInterface_ ) -> Release();
   if ( PPersistFileInterface )
      HTPointer::NullValueExchange( _PPersistFileInterface_ ) -> Release();
   if ( PSLInterface )
      HTPointer::NullValueExchange( _PSLInterface_ ) -> Release();
}

//==================================================================================================

String^ SysHelpers_ShellLinkProperties::FileNameToAbsolute(String^ filePath)
{
   HArgChecking::VerifyNotNull( filePath );
   try { return ::Path::GetFullPath( filePath ); }
   catch (Exception^ e) {
      throw HOpFailedExceptionCreator::Create(
         HShellLinkProperties::Verbose::CAN_NOT_OBTAIN_FULL_PATH_TO_SHORTCUT_FILE_0__1,
         filePath, e->Message ); }
}

//--------------------------------------------------------------------------------------------------

void SysHelpers_ShellLinkProperties::Load( String^ filePath,
                                           [HOut] HShellLinkSpecialProps^% specialProps )
{
   specialProps = nullptr;
   HShellLinkSpecialProps^ sp = gcnew HShellLinkSpecialProps();
   HArgChecking::VerifyNotNull( filePath );
   HDisposableSZ dszFullPath( FileNameToAbsolute( filePath ) );
   HRESULT hResult; SHELL_LINK_DATA_FLAGS dataFlags;
   if ( FAILED( hResult = PPersistFileInterface -> Load( %dszFullPath, STGM_READ )) ||
        FAILED( hResult = PSLDataListInterface -> GetFlags( (PDWORD)&dataFlags )) )
      throw HCOMError::CreateOpFailedException( hResult );
   sp -> RunAsAdministrator = $BOOL( dataFlags & SLDF_RUNAS_USER );
   specialProps = sp;
}

//--------------------------------------------------------------------------------------------------

void SysHelpers_ShellLinkProperties::Save( String^ filePath,
                                           [HOptional] HShellLinkSpecialProps^ specialProps )
{
   HArgChecking::VerifyNotNull( filePath );
   HDisposableSZ dszFullPath( FileNameToAbsolute( filePath ) );
   HRESULT hResult;
   if ( FAILED( hResult = PPersistFileInterface -> Save( %dszFullPath, TRUE ) ) ||
        FAILED( hResult = PPersistFileInterface -> SaveCompleted( NULL ) ))
      throw HCOMError::CreateOpFailedException( hResult );
   SHELL_LINK_DATA_FLAGS dataFlags;
   if ( FAILED( hResult = PSLDataListInterface -> GetFlags( (PDWORD)&dataFlags ) ) )
      throw HCOMError::CreateOpFailedException( hResult );
   if ( specialProps )
      if ( specialProps->RunAsAdministrator )
         dataFlags |= SLDF_RUNAS_USER;
      else
         dataFlags &= ~SLDF_RUNAS_USER;
   if ( FAILED( hResult = PSLDataListInterface -> SetFlags( dataFlags ) ) ||
        FAILED( hResult = PPersistFileInterface -> Save( NULL, TRUE ) ) ||
        FAILED( hResult = PPersistFileInterface -> SaveCompleted( NULL ) ))
      throw HCOMError::CreateOpFailedException( hResult );
}

//==================================================================================================

HOperationFailedException^
SysHelpers_ShellLinkProperties::CreateOpFailedException_CantExtractSLProperty(
   String^ propertyName, String^ errorMessage )
{
   HArgChecking::VerifyNotNulls( propertyName, errorMessage );
   return HOpFailedExceptionCreator::Create(
      HShellLinkProperties::Verbose::CAN_NOT_EXTRACT_PROPERTY_0_INTERFACE_ISHELLLINK__1,
      propertyName, errorMessage );
}

HOperationFailedException^
SysHelpers_ShellLinkProperties::CreateOpFailedException_CantSetSLProperty(
   String^ propertyName, String^ errorMessage )
{
   HArgChecking::VerifyNotNulls( propertyName, errorMessage );
   return HOpFailedExceptionCreator::Create(
      HShellLinkProperties::Verbose::CAN_NOT_SET_PROPERTY_0_INTERFACE_ISHELLLINK__1,
      propertyName, errorMessage );
}

//--------------------------------------------------------------------------------------------------

HOperationFailedException^
SysHelpers_ShellLinkProperties::CreateOpFailedException_CantExtractSLProperty(
   String^ propertyName, String^ errorMessageFmt, ... array<Object^>^ parameters )
{
   HArgChecking::VerifyNotNulls( propertyName, errorMessageFmt, parameters );
   return CreateOpFailedException_CantExtractSLProperty( propertyName,
      String::Format( errorMessageFmt, parameters ) );
}

HOperationFailedException^
SysHelpers_ShellLinkProperties::CreateOpFailedException_CantSetSLProperty(
   String^ propertyName, String^ errorMessageFmt, ... array<Object^>^ parameters )
{
   HArgChecking::VerifyNotNulls( propertyName, errorMessageFmt, parameters );
   return CreateOpFailedException_CantSetSLProperty( propertyName,
      String::Format( errorMessageFmt, parameters ) );
}

//--------------------------------------------------------------------------------------------------

HOperationFailedException^
SysHelpers_ShellLinkProperties::CreateOpFailedException_CantExtractSLProperty(
   String^ propertyName, HRESULT hResult )
{
   HArgChecking::VerifyNotNull( propertyName );
   return CreateOpFailedException_CantExtractSLProperty(
      propertyName, HCOMError::HRToMessage( hResult ) );
}

HOperationFailedException^
SysHelpers_ShellLinkProperties::CreateOpFailedException_CantSetSLProperty(
   String^ propertyName, HRESULT hResult )
{
   HArgChecking::VerifyNotNull( propertyName );
   return CreateOpFailedException_CantSetSLProperty(
      propertyName, HCOMError::HRToMessage( hResult ) );
}

//==================================================================================================
} // CommonHelpers
