IUrlHistoryStg2::ClearHistory() does not work from a service?
The IUrlHistoryStg2::ClearHistory() method is documented as Per-User.
http://msdn.microsoft.com/en-us/library/aa767715(VS.85).aspx
When calling it from a service running under the SYSTEM account, I am unable to target particular logged-on users. I have successfully impersonated the users via WindowsIdentity.Impersonate() but the call to ClearHistory() always returns 0 for success but does not clear the history of the user.
This applies on both XP and Win7 so appears to be not a session isolation issue.
Perhaps because it is COM, something is looking at the Process token of the caller rather than its Thread token when impersonating?
I am confused why impersonating the user does not simply lead to success of this method?
using System;
using System.Runtime.InteropServices;
/**
* wrapper for IUrlHistory
*/
public struct STATURL
{
public static uint SIZEOF_STATURL = (uint)Marshal.SizeOf( typeof(STATURL) );
public uint cbSize;
[MarshalAs(UnmanagedType.LPWStr)] public string pwcsUrl;
[MarshalAs(UnmanagedType.LPWStr)] public string pwcsTitle;
public System.Runtime.InteropServices.ComTypes.FILETIME
ftLastVisited,
ftLastUpdated,
ftExpires;
public uint dwFlags;
}
[ComImport, Guid("3C374A42-BAE4-11CF-BF7D-00AA006946EE"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IEnumSTATURL
{
[PreserveSig]
uint Next(uint celt, out STATURL rgelt, out uint pceltFetched);
void Skip(uint celt);
void Reset();
void Clone(out IEnumSTATURL ppenum);
void SetFilter(
[MarshalAs(UnmanagedType.LPWStr)] string poszFilter,
uint dwFlags);
}
[ComImport, Guid("AFA0DC11-C313-11d0-831A-00C04FD5AE38"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IUrlHistoryStg2
{
#region IUrlHistoryStg methods
void AddUrl(
[MarshalAs(UnmanagedType.LPWStr)] string pocsUrl,
[MarshalAs(UnmanagedType.LPWStr)] string pocsTitle,
uint dwFlags);
void DeleteUrl(
[MarshalAs(UnmanagedType.LPWStr)] string pocsUrl,
uint dwFlags);
void QueryUrl(
[MarshalAs(UnmanagedType.LPWStr)] string pocsUrl,
uint dwFlags,
ref STATURL lpSTATURL);
void BindToObject(
[MarshalAs(UnmanagedType.LPWStr)] string pocsUrl,
ref Guid riid,
[MarshalAs(UnmanagedType.IUnknown)] out object ppvOut);
IEnumSTATURL EnumUrls();
#endregion
void AddUrlAndNotify(
[MarshalAs(UnmanagedType.LPWStr)] string pocsUrl,
[MarshalAs(UnmanagedType.LPWStr)] string pocsTitle,
uint dwFlags,
[MarshalAs(UnmanagedType.Bool)] bool fWriteHistory,
[MarshalAs(UnmanagedType.IUnknown)] object /*IOleCommandTarget*/
poctNotify,
[MarshalAs(UnmanagedType.IUnknown)] object punkISFolder开发者_如何学Go);
void ClearHistory();
}
[ComImport, Guid("3C374A40-BAE4-11CF-BF7D-00AA006946EE")]
public class UrlHistory /* : IUrlHistoryStg[2] */ {}
public class test
{
static void Main()
{
IUrlHistoryStg2 stg = (IUrlHistoryStg2) new UrlHistory();
stg.ClearHistory();
}
}
If a service or an application impersonates a user, the system does not load the user's profile. Try call LoadUserProfile first.
IUrlHistoryStg2 eventually uses the Wininet APIs such as CommitUrlCacheEntryW
Microsoft documentation states that:
Like all other aspects of the WinINet API, this function cannot be safely called from within DllMain or the constructors and destructors of global objects. Note WinINet does not support server implementations. In addition, it should not be used from a service. For server implementations or services use Microsoft Windows HTTP Services (WinHTTP).
I reversed those API and found out the they have check for
- Impersonation
- Running from a service
If either is true, the API exists with error code 0x80070078
So, fortunately what you are trying to achieve is not possible from a service and you must use CreateProcessAsUser
精彩评论