Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

374 lines
9.4 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. ForceWorkingDirectoryToEXEPath.cpp
  5. Abstract:
  6. This shim forces the working directory to match the executables path in a
  7. short cut link. This shim is used in the case of the working directory
  8. in the link being incorrect and causing the application to work
  9. incorrectly. When this shim is applied the call to SetWorkingDirectory will
  10. be ignored and will be executed when SetPath is called.
  11. Notes:
  12. This is a general purpose shim.
  13. History:
  14. 09/27/2000 a-brienw Created
  15. 11/15/2000 a-brienw added some error checking as precautionary measure.
  16. --*/
  17. #include "precomp.h"
  18. IMPLEMENT_SHIM_BEGIN(ForceWorkingDirectoryToEXEPath)
  19. #include "ShimHookMacro.h"
  20. APIHOOK_ENUM_BEGIN
  21. APIHOOK_ENUM_ENTRY_COMSERVER(SHELL32)
  22. APIHOOK_ENUM_END
  23. IMPLEMENT_COMSERVER_HOOK(SHELL32)
  24. HRESULT MySetWorkingDirectoryW( PVOID pThis, const CString & pszDir, const CString & pszFile );
  25. HRESULT MySetWorkingDirectoryA( PVOID pThis, const CString & csDir, const CString & csFile );
  26. /*++
  27. Hook IShellLinkA::SetWorkingDirectory and call local
  28. SetWorkingDirectoryA to handle the input.
  29. --*/
  30. HRESULT STDMETHODCALLTYPE
  31. COMHOOK(IShellLinkA, SetWorkingDirectory)(
  32. PVOID pThis,
  33. LPCSTR pszDir
  34. )
  35. {
  36. CSTRING_TRY
  37. {
  38. CString csDummyPath;
  39. return MySetWorkingDirectoryA( pThis, pszDir, csDummyPath);
  40. }
  41. CSTRING_CATCH
  42. {
  43. DPFN( eDbgLevelError,"Exception encountered");
  44. }
  45. _pfn_IShellLinkA_SetWorkingDirectory pfnSetWorkingDir =
  46. ORIGINAL_COM(IShellLinkA, SetWorkingDirectory, pThis);
  47. return((*pfnSetWorkingDir)(pThis, pszDir));
  48. }
  49. /*++
  50. Hook IShellLinkW::SetWorkingDirectory and call local
  51. SetWorkingDirectoryW to handle the input.
  52. --*/
  53. HRESULT STDMETHODCALLTYPE
  54. COMHOOK(IShellLinkW, SetWorkingDirectory)(
  55. PVOID pThis,
  56. LPCWSTR pszDir
  57. )
  58. {
  59. return MySetWorkingDirectoryW( pThis, pszDir, NULL );
  60. }
  61. /*++
  62. Hook IShellLinkA::SetPath and call local
  63. SetWorkingDirectoryA to handle the input.
  64. --*/
  65. HRESULT STDMETHODCALLTYPE
  66. COMHOOK(IShellLinkA, SetPath)(
  67. PVOID pThis,
  68. LPCSTR pszFile
  69. )
  70. {
  71. CSTRING_TRY
  72. {
  73. CString csDummyPath;
  74. return MySetWorkingDirectoryA( pThis, csDummyPath, pszFile);
  75. }
  76. CSTRING_CATCH
  77. {
  78. DPFN( eDbgLevelError,"Exception encountered");
  79. }
  80. _pfn_IShellLinkA_SetPath pfnSetPath = ORIGINAL_COM(IShellLinkA, SetPath, pThis);
  81. return (*pfnSetPath)(pThis, pszFile);
  82. }
  83. /*++
  84. Hook IShellLinkW::SetPath and call local
  85. SetWorkingDirectoryW to handle the input.
  86. --*/
  87. HRESULT STDMETHODCALLTYPE
  88. COMHOOK(IShellLinkW, SetPath)(
  89. PVOID pThis,
  90. LPCWSTR pszFile
  91. )
  92. {
  93. if (pszFile == NULL)
  94. {
  95. return S_OK; // We will fault later otherwise.
  96. }
  97. return MySetWorkingDirectoryW( pThis, NULL, pszFile );
  98. }
  99. /*++
  100. This routine handles the input of SetPath and
  101. SetWorkingDirectory and determines what path
  102. to really place in the short cut link's working
  103. directory.
  104. --*/
  105. HRESULT
  106. MySetWorkingDirectoryA(
  107. PVOID pThis,
  108. const CString & csDir,
  109. const CString & csFile
  110. )
  111. {
  112. HRESULT hReturn = NOERROR;
  113. CSTRING_TRY
  114. {
  115. char szDir[_MAX_PATH+1];
  116. CString csStoredDir;
  117. bool doit = false;
  118. if( csFile.IsEmpty())
  119. {
  120. // handle passed in working directory
  121. IShellLinkA *MyShellLink = (IShellLinkA *)pThis;
  122. // now call IShellLink::GetWorkingDirectory
  123. hReturn = MyShellLink->GetWorkingDirectory(
  124. szDir,
  125. _MAX_PATH+1);
  126. // if the stored working directory has not
  127. // been stored use the one passed in.
  128. csStoredDir = szDir;
  129. if (csStoredDir.GetLength() < 1 )
  130. {
  131. csStoredDir = csDir;
  132. }
  133. doit = true;
  134. hReturn = NOERROR;
  135. }
  136. else
  137. {
  138. _pfn_IShellLinkA_SetPath pfnSetPath;
  139. // Look up IShellLink::SetPath
  140. pfnSetPath = (_pfn_IShellLinkA_SetPath)
  141. ORIGINAL_COM( IShellLinkA, SetPath, pThis);
  142. // build working directory from exe path & name
  143. int len;
  144. csStoredDir = csFile;
  145. // now search backwards from the end of the string
  146. // for the first \ and terminate the string there
  147. // making that the new path.
  148. len = csStoredDir.ReverseFind(L'\\');
  149. if (len > 0)
  150. {
  151. doit = true;
  152. csStoredDir.Truncate(len);
  153. if(csStoredDir[0] == L'"')
  154. {
  155. csStoredDir += L'"';
  156. }
  157. }
  158. // now call the IShellLink::SetPath
  159. hReturn = (*pfnSetPath)( pThis, csFile.GetAnsi());
  160. }
  161. // if there was no error
  162. if (hReturn == NOERROR)
  163. {
  164. // and we have a working directory to set
  165. if( doit == true )
  166. {
  167. _pfn_IShellLinkA_SetWorkingDirectory pfnSetWorkingDirectory;
  168. // Look up IShellLink::SetWorkingDirectory
  169. pfnSetWorkingDirectory = (_pfn_IShellLinkA_SetWorkingDirectory)
  170. ORIGINAL_COM( IShellLinkA, SetWorkingDirectory, pThis);
  171. // now call the IShellLink::SetWorkingDirectory
  172. if( pfnSetWorkingDirectory != NULL )
  173. {
  174. hReturn = (*pfnSetWorkingDirectory)(
  175. pThis,
  176. csStoredDir.GetAnsi());
  177. }
  178. else
  179. {
  180. hReturn = E_OUTOFMEMORY;
  181. }
  182. }
  183. }
  184. }
  185. CSTRING_CATCH
  186. {
  187. }
  188. // return the error status
  189. return( hReturn );
  190. }
  191. /*++
  192. This routine handles the input of SetPath and
  193. SetWorkingDirectory and determines what path
  194. to really place in the short cut link's working
  195. directory.
  196. --*/
  197. HRESULT
  198. MySetWorkingDirectoryW(
  199. PVOID pThis,
  200. const CString & csDir,
  201. const CString & csFile
  202. )
  203. {
  204. HRESULT hReturn = NOERROR;
  205. CSTRING_TRY
  206. {
  207. wchar_t szDir[_MAX_PATH+1];
  208. bool doit = false;
  209. CString csStoredDir;
  210. if( csFile.IsEmpty())
  211. {
  212. // handle passed in working directory
  213. IShellLinkW *MyShellLink = (IShellLinkW *)pThis;
  214. // now call IShellLink::GetWorkingDirectory
  215. hReturn = MyShellLink->GetWorkingDirectory(
  216. szDir,
  217. _MAX_PATH);
  218. // if the stored working directory has not
  219. // been stored use the one passed in.
  220. csStoredDir = szDir;
  221. if( csStoredDir.GetLength() < 1 )
  222. {
  223. csStoredDir = csDir;
  224. }
  225. doit = true;
  226. hReturn = NOERROR;
  227. }
  228. else
  229. {
  230. _pfn_IShellLinkW_SetPath pfnSetPath;
  231. // Look up IShellLink::SetPath
  232. pfnSetPath = (_pfn_IShellLinkW_SetPath)
  233. ORIGINAL_COM( IShellLinkW, SetPath, pThis);
  234. // build working directory from exe path & name
  235. int len;
  236. csStoredDir = csFile;
  237. len = csStoredDir.ReverseFind(L'\\');
  238. // now search backwards from the end of the string
  239. // for the first \ and terminate the string there
  240. // making that the new path.
  241. if (len > 0)
  242. {
  243. doit = true;
  244. csStoredDir.Truncate(len);
  245. if(csStoredDir[0] == L'"')
  246. {
  247. csStoredDir += L'"';
  248. }
  249. }
  250. // now call the IShellLink::SetPath
  251. hReturn = (*pfnSetPath)( pThis, csFile.Get());
  252. }
  253. // if there was no error
  254. if (hReturn == NOERROR)
  255. {
  256. // and we have a working directory to set
  257. if( doit == true )
  258. {
  259. _pfn_IShellLinkW_SetWorkingDirectory pfnSetWorkingDirectory;
  260. // Look up IShellLink::SetWorkingDirectory
  261. pfnSetWorkingDirectory = (_pfn_IShellLinkW_SetWorkingDirectory)
  262. ORIGINAL_COM( IShellLinkW, SetWorkingDirectory, pThis);
  263. // now call the IShellLink::SetWorkingDirectory
  264. if( pfnSetWorkingDirectory != NULL )
  265. {
  266. hReturn = (*pfnSetWorkingDirectory)(
  267. pThis,
  268. csStoredDir.Get());
  269. }
  270. else
  271. {
  272. hReturn = E_OUTOFMEMORY;
  273. }
  274. }
  275. }
  276. }
  277. CSTRING_CATCH
  278. {
  279. }
  280. // return the error status
  281. return( hReturn );
  282. }
  283. /*++
  284. Register hooked functions
  285. --*/
  286. HOOK_BEGIN
  287. APIHOOK_ENTRY_COMSERVER(SHELL32)
  288. COMHOOK_ENTRY(ShellLink, IShellLinkA, SetWorkingDirectory, 9)
  289. COMHOOK_ENTRY(ShellLink, IShellLinkW, SetWorkingDirectory, 9)
  290. COMHOOK_ENTRY(ShellLink, IShellLinkA, SetPath, 20)
  291. COMHOOK_ENTRY(ShellLink, IShellLinkW, SetPath, 20)
  292. HOOK_END
  293. IMPLEMENT_SHIM_END