Windows2003-3790/windows/appcompat/shims/general/forceworkingdirectorytoexepath.cpp

375 lines
9.4 KiB
C++
Raw Permalink Normal View History

2001-01-01 00:00:00 +01:00
/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
ForceWorkingDirectoryToEXEPath.cpp
Abstract:
This shim forces the working directory to match the executables path in a
short cut link. This shim is used in the case of the working directory
in the link being incorrect and causing the application to work
incorrectly. When this shim is applied the call to SetWorkingDirectory will
be ignored and will be executed when SetPath is called.
Notes:
This is a general purpose shim.
History:
09/27/2000 a-brienw Created
11/15/2000 a-brienw added some error checking as precautionary measure.
--*/
#include "precomp.h"
IMPLEMENT_SHIM_BEGIN(ForceWorkingDirectoryToEXEPath)
#include "ShimHookMacro.h"
APIHOOK_ENUM_BEGIN
APIHOOK_ENUM_ENTRY_COMSERVER(SHELL32)
APIHOOK_ENUM_END
IMPLEMENT_COMSERVER_HOOK(SHELL32)
HRESULT MySetWorkingDirectoryW( PVOID pThis, const CString & pszDir, const CString & pszFile );
HRESULT MySetWorkingDirectoryA( PVOID pThis, const CString & csDir, const CString & csFile );
/*++
Hook IShellLinkA::SetWorkingDirectory and call local
SetWorkingDirectoryA to handle the input.
--*/
HRESULT STDMETHODCALLTYPE
COMHOOK(IShellLinkA, SetWorkingDirectory)(
PVOID pThis,
LPCSTR pszDir
)
{
CSTRING_TRY
{
CString csDummyPath;
return MySetWorkingDirectoryA( pThis, pszDir, csDummyPath);
}
CSTRING_CATCH
{
DPFN( eDbgLevelError,"Exception encountered");
}
_pfn_IShellLinkA_SetWorkingDirectory pfnSetWorkingDir =
ORIGINAL_COM(IShellLinkA, SetWorkingDirectory, pThis);
return((*pfnSetWorkingDir)(pThis, pszDir));
}
/*++
Hook IShellLinkW::SetWorkingDirectory and call local
SetWorkingDirectoryW to handle the input.
--*/
HRESULT STDMETHODCALLTYPE
COMHOOK(IShellLinkW, SetWorkingDirectory)(
PVOID pThis,
LPCWSTR pszDir
)
{
return MySetWorkingDirectoryW( pThis, pszDir, NULL );
}
/*++
Hook IShellLinkA::SetPath and call local
SetWorkingDirectoryA to handle the input.
--*/
HRESULT STDMETHODCALLTYPE
COMHOOK(IShellLinkA, SetPath)(
PVOID pThis,
LPCSTR pszFile
)
{
CSTRING_TRY
{
CString csDummyPath;
return MySetWorkingDirectoryA( pThis, csDummyPath, pszFile);
}
CSTRING_CATCH
{
DPFN( eDbgLevelError,"Exception encountered");
}
_pfn_IShellLinkA_SetPath pfnSetPath = ORIGINAL_COM(IShellLinkA, SetPath, pThis);
return (*pfnSetPath)(pThis, pszFile);
}
/*++
Hook IShellLinkW::SetPath and call local
SetWorkingDirectoryW to handle the input.
--*/
HRESULT STDMETHODCALLTYPE
COMHOOK(IShellLinkW, SetPath)(
PVOID pThis,
LPCWSTR pszFile
)
{
if (pszFile == NULL)
{
return S_OK; // We will fault later otherwise.
}
return MySetWorkingDirectoryW( pThis, NULL, pszFile );
}
/*++
This routine handles the input of SetPath and
SetWorkingDirectory and determines what path
to really place in the short cut link's working
directory.
--*/
HRESULT
MySetWorkingDirectoryA(
PVOID pThis,
const CString & csDir,
const CString & csFile
)
{
HRESULT hReturn = NOERROR;
CSTRING_TRY
{
char szDir[_MAX_PATH+1];
CString csStoredDir;
bool doit = false;
if( csFile.IsEmpty())
{
// handle passed in working directory
IShellLinkA *MyShellLink = (IShellLinkA *)pThis;
// now call IShellLink::GetWorkingDirectory
hReturn = MyShellLink->GetWorkingDirectory(
szDir,
_MAX_PATH+1);
// if the stored working directory has not
// been stored use the one passed in.
csStoredDir = szDir;
if (csStoredDir.GetLength() < 1 )
{
csStoredDir = csDir;
}
doit = true;
hReturn = NOERROR;
}
else
{
_pfn_IShellLinkA_SetPath pfnSetPath;
// Look up IShellLink::SetPath
pfnSetPath = (_pfn_IShellLinkA_SetPath)
ORIGINAL_COM( IShellLinkA, SetPath, pThis);
// build working directory from exe path & name
int len;
csStoredDir = csFile;
// now search backwards from the end of the string
// for the first \ and terminate the string there
// making that the new path.
len = csStoredDir.ReverseFind(L'\\');
if (len > 0)
{
doit = true;
csStoredDir.Truncate(len);
if(csStoredDir[0] == L'"')
{
csStoredDir += L'"';
}
}
// now call the IShellLink::SetPath
hReturn = (*pfnSetPath)( pThis, csFile.GetAnsi());
}
// if there was no error
if (hReturn == NOERROR)
{
// and we have a working directory to set
if( doit == true )
{
_pfn_IShellLinkA_SetWorkingDirectory pfnSetWorkingDirectory;
// Look up IShellLink::SetWorkingDirectory
pfnSetWorkingDirectory = (_pfn_IShellLinkA_SetWorkingDirectory)
ORIGINAL_COM( IShellLinkA, SetWorkingDirectory, pThis);
// now call the IShellLink::SetWorkingDirectory
if( pfnSetWorkingDirectory != NULL )
{
hReturn = (*pfnSetWorkingDirectory)(
pThis,
csStoredDir.GetAnsi());
}
else
{
hReturn = E_OUTOFMEMORY;
}
}
}
}
CSTRING_CATCH
{
}
// return the error status
return( hReturn );
}
/*++
This routine handles the input of SetPath and
SetWorkingDirectory and determines what path
to really place in the short cut link's working
directory.
--*/
HRESULT
MySetWorkingDirectoryW(
PVOID pThis,
const CString & csDir,
const CString & csFile
)
{
HRESULT hReturn = NOERROR;
CSTRING_TRY
{
wchar_t szDir[_MAX_PATH+1];
bool doit = false;
CString csStoredDir;
if( csFile.IsEmpty())
{
// handle passed in working directory
IShellLinkW *MyShellLink = (IShellLinkW *)pThis;
// now call IShellLink::GetWorkingDirectory
hReturn = MyShellLink->GetWorkingDirectory(
szDir,
_MAX_PATH);
// if the stored working directory has not
// been stored use the one passed in.
csStoredDir = szDir;
if( csStoredDir.GetLength() < 1 )
{
csStoredDir = csDir;
}
doit = true;
hReturn = NOERROR;
}
else
{
_pfn_IShellLinkW_SetPath pfnSetPath;
// Look up IShellLink::SetPath
pfnSetPath = (_pfn_IShellLinkW_SetPath)
ORIGINAL_COM( IShellLinkW, SetPath, pThis);
// build working directory from exe path & name
int len;
csStoredDir = csFile;
len = csStoredDir.ReverseFind(L'\\');
// now search backwards from the end of the string
// for the first \ and terminate the string there
// making that the new path.
if (len > 0)
{
doit = true;
csStoredDir.Truncate(len);
if(csStoredDir[0] == L'"')
{
csStoredDir += L'"';
}
}
// now call the IShellLink::SetPath
hReturn = (*pfnSetPath)( pThis, csFile.Get());
}
// if there was no error
if (hReturn == NOERROR)
{
// and we have a working directory to set
if( doit == true )
{
_pfn_IShellLinkW_SetWorkingDirectory pfnSetWorkingDirectory;
// Look up IShellLink::SetWorkingDirectory
pfnSetWorkingDirectory = (_pfn_IShellLinkW_SetWorkingDirectory)
ORIGINAL_COM( IShellLinkW, SetWorkingDirectory, pThis);
// now call the IShellLink::SetWorkingDirectory
if( pfnSetWorkingDirectory != NULL )
{
hReturn = (*pfnSetWorkingDirectory)(
pThis,
csStoredDir.Get());
}
else
{
hReturn = E_OUTOFMEMORY;
}
}
}
}
CSTRING_CATCH
{
}
// return the error status
return( hReturn );
}
/*++
Register hooked functions
--*/
HOOK_BEGIN
APIHOOK_ENTRY_COMSERVER(SHELL32)
COMHOOK_ENTRY(ShellLink, IShellLinkA, SetWorkingDirectory, 9)
COMHOOK_ENTRY(ShellLink, IShellLinkW, SetWorkingDirectory, 9)
COMHOOK_ENTRY(ShellLink, IShellLinkA, SetPath, 20)
COMHOOK_ENTRY(ShellLink, IShellLinkW, SetPath, 20)
HOOK_END
IMPLEMENT_SHIM_END