[Fat-develop] FAT/src/FAT.Web/HtmlDetails HtmlDetailsEnhancer.cs,NONE,1.1 HtmlDetailsRequestContext.
Brought to you by:
exortech
Update of /cvsroot/fat/FAT/src/FAT.Web/HtmlDetails In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv13246/src/FAT.Web/HtmlDetails Added Files: HtmlDetailsEnhancer.cs HtmlDetailsRequestContext.cs HtmlDetailsRequestHandler.ashx HtmlDetailsRequestHelper.cs HtmlDetailsStore.cs IEnumIDList.cs IExtractImage.cs IHtmlDetailsRequestContext.cs IHtmlDetailsStore.cs ISession.cs IShellFolder.cs Session.cs Shell32.cs Shell32Exception.cs Log Message: Can now add HtmlDetails to TestLogger in FATFixtures. Details are dislayed in test results as clickable thumbnails in FAT.Web --- NEW FILE: HtmlDetailsEnhancer.cs --- using System; using System.Drawing; using System.IO; using System.Runtime.InteropServices; namespace FAT.Web.HtmlDetails { public class HtmlDetailsEnhancer { private const int screenWidth = 1400; private const int screenHeight = 1050; private const int scalingFactor = 8; private static Size size = new Size(screenWidth/scalingFactor, screenHeight/scalingFactor); private const int bitsPerPixel = 32; private string html; private string url; public HtmlDetailsEnhancer(string url, string html) { this.url = url; this.html = html; } public string Url { get {return url;} } public string Html { get {return html;} } public string HtmlWithAbsoluteUrls { // TODO: expand all urls in the html to be absolute url so that the page functions correctly (in most cases) when fetched from the FAT site. get {return html;} } public Image Thumbnail { get {return CreateImage();} } private Image CreateImage() { string temporaryFileName = GetTemporaryFileName(); WriteHtmlToFile(temporaryFileName); Image image = CreateImageFromFile(temporaryFileName); DeleteTemporaryFile(temporaryFileName); return image; } private string GetTemporaryFileName() { return Path.GetTempFileName() + ".html"; } private void WriteHtmlToFile(string fileName) { StreamWriter writer = new StreamWriter(fileName); writer.Write(html); writer.Close(); } private void DeleteTemporaryFile(string temporaryFileName) { File.Delete(temporaryFileName); File.Delete(Path.GetDirectoryName(temporaryFileName) + "\\" + Path.GetFileNameWithoutExtension(temporaryFileName)); } private Bitmap CreateImageFromFile(String path) { String folder = Path.GetDirectoryName(path); String file = Path.GetFileName(path); IShellFolder desktopFolder = GetDesktopShellFolder(); IShellFolder targetFolder = GetShellFolder(desktopFolder, folder); IExtractImage image = GetImageForFile(targetFolder, file); return GetBitmap(image); } private IShellFolder GetDesktopShellFolder() { IShellFolder desktopFolder = null; UInt32 hr = Shell32.SHGetDesktopFolder(out desktopFolder); CheckReturnAndConditionForFailure(hr, desktopFolder == null, "SHGetDesktopFolder failed."); return desktopFolder; } private IShellFolder GetShellFolder(IShellFolder desktopFolder, string folder) { IntPtr folderPidl = GetPIDLForFolder(desktopFolder, folder); Object shellFolder = null; Guid guid = typeof(IShellFolder).GUID; UInt32 hr = desktopFolder.BindToObject(folderPidl, IntPtr.Zero, ref guid, out shellFolder); CheckReturnAndConditionForFailure(hr, shellFolder == null, "BindToObject (ShellFolder) failed"); return (IShellFolder)shellFolder; } private IExtractImage GetImageForFile(IShellFolder targetFolder, string file) { IntPtr filePidl = GetPIDLForFolder(targetFolder, file); Guid guid = typeof(IExtractImage).GUID; UInt32 prfgInOut = 0; object extractedImage = null; UInt32 hr = targetFolder.GetUIObjectOf(IntPtr.Zero, 1, new IntPtr[] {filePidl}, ref guid, ref prfgInOut, out extractedImage); CheckReturnAndConditionForFailure(hr, extractedImage == null, "GetUIObjectOf (ExtractImage) failed"); return (IExtractImage)extractedImage; } [DllImport("Gdi32.dll")] private static extern Boolean DeleteObject(IntPtr hObject); private Bitmap GetBitmap(IExtractImage extract) { String retPath = ""; UInt32 pdwPriority = 0; UInt32 flags = Convert.ToUInt32(IEIFLAG.QUALITY); UInt32 hr = extract.GetLocation(out retPath, 1, ref pdwPriority, ref size, bitsPerPixel, ref flags); CheckReturnAndConditionForFailure(hr, false, "GetLocation failed"); IntPtr hBitmap = IntPtr.Zero; hr = extract.Extract(out hBitmap); CheckConditionForFailure(hr, (!Success(hr) && hr!=1) || hBitmap == IntPtr.Zero, "Extract failed"); Bitmap result = Bitmap.FromHbitmap(hBitmap); DeleteObject(hBitmap); return result; } private IntPtr GetPIDLForFolder(IShellFolder desktopFolder, string folder) { Int32 pchEaten = 0; UInt32 attr =0; IntPtr folderPidl; UInt32 hr = desktopFolder.ParseDisplayName(IntPtr.Zero, 0, folder, ref pchEaten, out folderPidl, ref attr); CheckReturnAndConditionForFailure(hr, folderPidl == IntPtr.Zero, "ParseDisplayName failed for folder " + folder); return folderPidl; } private void CheckReturnAndConditionForFailure(UInt32 hr, bool failureCondition, string message) { ThrowExceptionOncondition(!Success(hr) || failureCondition, hr, message); } private void CheckConditionForFailure(UInt32 hr, bool failureCondition, string message) { ThrowExceptionOncondition(failureCondition, hr, message); } private void ThrowExceptionOncondition(bool failureCondition, UInt32 hr, string message) { if (failureCondition) { throw new Shell32Exception(hr, message); } } private static Boolean Success(UInt32 hr) { return (hr==0); } } } --- NEW FILE: HtmlDetailsRequestContext.cs --- using System.Web; using System.Web.SessionState; using System.IO; using System.Drawing; using System.Drawing.Imaging; namespace FAT.Web.HtmlDetails { public class HtmlDetailsRequestContext : IHtmlDetailsRequestContext { private HttpContext context; public HtmlDetailsRequestContext(HttpContext context) { this.context = context; } public string DetailsType { get {return (string)request[HtmlDetailsRequestHelper.DETAILS_TYPE_PARAMETER_NAME];} } public Image Thumbnail {get {return htmlDetails.Thumbnail;}} public string Html { get {return htmlDetails.Html;}} public string HtmlWithAbsoluteUrls {get {return htmlDetails.HtmlWithAbsoluteUrls;}} public string ContentType { set {response.ContentType = value;}} public void StreamImage(Image image) { image.Save(response.OutputStream, ImageFormat.Jpeg); } public void StreamText(string text) { StreamWriter writer = new StreamWriter(response.OutputStream); writer.Write(text); writer.Close(); } private HtmlDetailsEnhancer htmlDetails { get {return HtmlDetailsStore.Instance(new Session(session)).Get(detailsId);} } private string detailsId { get {return (string)request[HtmlDetailsRequestHelper.ID_PARAMETER_NAME];} } private HttpRequest request { get {return context.Request;}} private HttpResponse response { get {return context.Response;}} private HttpSessionState session { get {return context.Session;}} } } --- NEW FILE: HtmlDetailsRequestHandler.ashx --- <!- file: ImageHandler.asph --> <%@ WebHandler Language="C#" Class="FAT.Web.HtmlDetails.HtmlDetailsRequestHandler" %> using System; using System.Web; using System.Web.SessionState; namespace FAT.Web.HtmlDetails { public class HtmlDetailsRequestHandler : IHttpHandler, IRequiresSessionState { public void ProcessRequest(HttpContext context) { HtmlDetailsRequestHelper.ReplyWithAppropriateHtmlDetails(new HtmlDetailsRequestContext(context)); } public bool IsReusable {get {return true;}} } } --- NEW FILE: HtmlDetailsRequestHelper.cs --- using System.Drawing.Imaging; using System.IO; using System.Web.SessionState; namespace FAT.Web.HtmlDetails { public class HtmlDetailsRequestHelper { public const string DETAILS_HANDLER_RELATIVE_URL = "HtmlDetails/HtmlDetailsRequestHandler.ashx"; public const string ID_PARAMETER_NAME = "id"; public const string DETAILS_TYPE_PARAMETER_NAME = "type"; private const string IMAGE = "image"; private const string HTML_WITH_ABSOLUTE_URLS = "htmlWithAbsoluteUrls"; private const string HTML = "html"; public static void ReplyWithAppropriateHtmlDetails(IHtmlDetailsRequestContext context) { switch (context.DetailsType) { case IMAGE: context.ContentType="image/jpeg"; context.StreamImage(context.Thumbnail); break; case HTML: context.ContentType="text/plain"; // how to launch notepad? context.StreamText(context.Html); break; case HTML_WITH_ABSOLUTE_URLS: context.ContentType="text/html"; context.StreamText(context.HtmlWithAbsoluteUrls); break; default: break; } } public static string CreateImageUrl(string id) { return DETAILS_HANDLER_RELATIVE_URL + "?" + CreateImageParameter() + "&" + CreateHtmlDetailsIdParameter(id); } public static string CreateHtmlUrl(string id) { return DETAILS_HANDLER_RELATIVE_URL + "?" + CreateHtmlParameter() + "&" + CreateHtmlDetailsIdParameter(id); } public static string CreateHtmlWithAbsoluteUrlsUrl(string id) { return DETAILS_HANDLER_RELATIVE_URL + "?" + CreateHtmlWithAbsoluteUrlsParameter() + "&" + CreateHtmlDetailsIdParameter(id); } private static string CreateImageParameter() { return DETAILS_TYPE_PARAMETER_NAME + "=" + IMAGE; } private static string CreateHtmlParameter() { return DETAILS_TYPE_PARAMETER_NAME + "=" + HTML; } private static string CreateHtmlWithAbsoluteUrlsParameter() { return DETAILS_TYPE_PARAMETER_NAME + "=" + HTML_WITH_ABSOLUTE_URLS; } private static string CreateHtmlDetailsIdParameter(string id) { return ID_PARAMETER_NAME + "=" + id; } } } --- NEW FILE: HtmlDetailsStore.cs --- using System; using System.Collections; using System.Web.SessionState; namespace FAT.Web.HtmlDetails { public class HtmlDetailsStore : IHtmlDetailsStore { private const string SESSION_KEY = "HtmlDetailsStore"; private Hashtable cache = new Hashtable(); private static int currentId = 1; private HtmlDetailsStore() {} public static void CreateInstance(ISession session) { session[SESSION_KEY] = new HtmlDetailsStore(); } public static IHtmlDetailsStore Instance(ISession session) { return (IHtmlDetailsStore)session[SESSION_KEY]; } public HtmlDetailsEnhancer Get(string id) { return (HtmlDetailsEnhancer)cache[id]; } public string Add(HtmlDetailsEnhancer htmlDetailsEnhancer) { string id = GetNextId(); cache.Add(id, htmlDetailsEnhancer); return id; } private string GetNextId() { lock (this) { return (currentId++).ToString(); } } } } --- NEW FILE: IEnumIDList.cs --- using System; using System.Runtime.InteropServices; namespace FAT.Web.HtmlDetails { /// <summary> /// Summary description for IEnumIDList. /// </summary> [ ComImport(), Guid("000214F2-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown) ] internal interface IEnumIDList { [PreserveSig()] uint Next( int celt, [MarshalAs(UnmanagedType.LPArray)] IntPtr[] rgelt, out int pceltFetched); void Skip( int celt); void Reset(); void Clone( out IEnumIDList ppenum); } } --- NEW FILE: IExtractImage.cs --- using System; using System.Drawing; using System.Runtime.InteropServices; namespace FAT.Web.HtmlDetails { /// <summary> /// Flags used for IExtractImage.GetLocation /// </summary> [Flags()] public enum IEIFLAG : uint { /// <summary> /// Used to ask the object if it supports asynchronous (free-threaded) extraction. If this flag is set, IExtractImage::GetLocation may return E_PENDING, indicating the wish to run the extract on another thread. If E_PENDING is returned, the priority of the item is returned in pdwPriority. /// </summary> ASYNC = 0x0001, /// <summary> /// Returned by the object to indicate that it will not cache the image. If this flag is returned, the Shell will cache a copy of the image. /// </summary> CACHE = 0x0002, /// <summary> /// Used to ask the object to use the supplied aspect ratio. If this flag is set, a rectangle with the desired aspect ratio will be passed in prgSize. This flag cannot be used with IEIFLAG_SCREEN. /// </summary> ASPECT = 0x0004, /// <summary> /// Used to tell the object to use only local content for rendering. /// </summary> OFFLINE = 0x0008, /// <summary> /// Not Supported. /// </summary> GLEAM = 0x0010, /// <summary> /// Used to tell the object to render as if for the screen. This flag cannot be used with IEIFLAG_ASPECT. /// </summary> SCREEN = 0x0020, /// <summary> /// Used to tell the object to render the image to the approximate size passed in prgSize, but crop it if necessary. /// </summary> ORIGSIZE = 0x0040, /// <summary> /// Not Supported. /// </summary> NOSTAMP = 0x0080, /// <summary> /// Not Supported. /// </summary> NOBORDER = 0x0100, /// <summary> /// Passed to the IExtractImage.Extract method to indicate that a higher quality image is requested. /// </summary> QUALITY = 0x0200 } /// <summary> /// The IExtractImage interface is used to request a thumbnail image from a Shell folder. /// </summary> [ ComImport(), Guid("BB2E617C-0920-11d1-9A0B-00C04FC2D6C1"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown) ] internal interface IExtractImage { /// <summary> /// Used to request the path description of an image and specify how the image should be rendered. /// </summary> /// <remarks><a href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/iextractimage/GetLocation.asp">See MSDN.</a></remarks> [PreserveSig()] UInt32 GetLocation( [Out(), MarshalAs(UnmanagedType.LPWStr, SizeParamIndex=1)] out String path, UInt32 cchMax, [In(),Out()] ref UInt32 pdwPriority, [In()] ref Size size, UInt32 depth, [In()][Out()] ref UInt32 flags); /// <summary> /// Used to request an image from an object, such as an item in a Shell folder. /// </summary> /// <remarks><a href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/iextractimage/Extract.asp">See MSDN.</a></remarks> [PreserveSig()] UInt32 Extract(out System.IntPtr hbmp); } } --- NEW FILE: IHtmlDetailsRequestContext.cs --- using System.IO; using System.Drawing; namespace FAT.Web.HtmlDetails { public interface IHtmlDetailsRequestContext { string DetailsType { get; } string Html {get;} string HtmlWithAbsoluteUrls {get;} Image Thumbnail {get;} string ContentType { set ;} void StreamText(string text); void StreamImage(Image image); } } --- NEW FILE: IHtmlDetailsStore.cs --- using System; using System.Collections; namespace FAT.Web.HtmlDetails { public interface IHtmlDetailsStore { HtmlDetailsEnhancer Get(string id); string Add(HtmlDetailsEnhancer htmlDetailsEnhancer); } } --- NEW FILE: ISession.cs --- using System; using System.Web.SessionState; namespace FAT.Web.HtmlDetails { public interface ISession { object this[string stringIndex] {get; set;} } } --- NEW FILE: IShellFolder.cs --- using System; using System.Runtime.InteropServices; namespace FAT.Web.HtmlDetails { [ ComImport(), Guid("000214E6-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown) ] internal interface IShellFolder { /// <summary> /// Translates a file object's or folder's display name into an item identifier list. /// </summary> /// <remarks><a href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/ishellfolder/ParseDisplayName.asp">See MSDN.</a></remarks> [PreserveSig()] UInt32 ParseDisplayName( IntPtr hwnd, Int32 pdcReserved, String displayName, ref Int32 pchEaten, out IntPtr ppidl, ref UInt32 attr); /// <summary> /// Allows a client to determine the contents of a folder by creating an item identifier enumeration object and returning its IEnumIDList interface. The methods supported by that interface can then be used to enumerate the folder's contents. /// </summary> /// <remarks><a href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/ishellfolder/EnumObjects.asp">See MSDN.</a></remarks> [PreserveSig()] UInt32 EnumObjects( IntPtr hwnd, SHCONTF grfFlags, out IEnumIDList pidl); /// <summary> /// Retrieves an IShellFolder object for a subfolder. /// </summary> /// <remarks><a href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/ishellfolder/BindToObject.asp">See MSDN.</a></remarks> [PreserveSig()] UInt32 BindToObject( IntPtr pidl, IntPtr pdcReserved, [In()]ref System.Guid riid, [MarshalAs(UnmanagedType.Interface)] out object ppv); /// <summary> /// Requests a pointer to an object's storage interface. /// </summary> /// <remarks><a href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/ishellfolder/BindToStorage.asp">See MSDN.</a></remarks> [PreserveSig()] UInt32 BindToStorage( IntPtr pidl, IntPtr pdcReserved, ref System.Guid riid, ref IntPtr ppvOut); /// <summary> /// Determines the relative order of two file objects or folders, given their item identifier lists. /// </summary> /// <remarks><a href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/ishellfolder/CompareIDs.asp">See MSDN.</a></remarks> [PreserveSig()] UInt32 CompareIDs( Int32 lParam, IntPtr pidl1, IntPtr pidl2); /// <summary> /// Requests an object that can be used to obtain information from or interact with a folder object. /// </summary> /// <remarks><a href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/ishellfolder/CreateViewObject.asp">See MSDN.</a></remarks> [PreserveSig()] UInt32 CreateViewObject( IntPtr hwnd, System.Guid riid, ref IntPtr ppvOut); /// <summary> /// Retrieves the attributes of one or more file objects or subfolders. /// </summary> /// <remarks><a href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/ishellfolder/GetAttributesOf.asp">See MSDN.</a></remarks> [PreserveSig()] UInt32 GetAttributesOf( Int32 cidl, IntPtr apidl, ref Int32 rgfInOut); /// <summary> /// Retrieves an OLE interface that can be used to carry out actions on the specified file objects or folders. /// </summary> /// <remarks><a href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/ishellfolder/GetUIObjectOf.asp">See MSDN.</a></remarks> [PreserveSig()] UInt32 GetUIObjectOf( IntPtr hwnd, UInt32 cidl, [In(), MarshalAs(UnmanagedType.LPArray)] IntPtr[] apidl, [In()] ref System.Guid riid, ref UInt32 prfgInOut, [Out()][MarshalAs(UnmanagedType.Interface)] out object ppvOut); /// <summary> /// Retrieves the display name for the specified file object or subfolder. /// </summary> /// <remarks><a href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/ishellfolder/GetDisplayNameOf.asp">See MSDN.</a></remarks> [PreserveSig()] UInt32 GetDisplayNameOf( IntPtr pidl, SHGDN uFlags, out STRRET lpName); /// <summary> /// Sets the display name of a file object or subfolder, changing the item identifier in the process. /// </summary> /// <remarks><a href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/ishellfolder/SetNameOf.asp">See MSDN.</a></remarks> [PreserveSig()] UInt32 SetNameOf( IntPtr hwnd, IntPtr pidl, String lpszName, Int32 uFlags, ref Int32 ppidlOut); } } --- NEW FILE: Session.cs --- using System; using System.Web.SessionState; namespace FAT.Web.HtmlDetails { public class Session : ISession { private HttpSessionState session; public Session(HttpSessionState session) { this.session = session; } public object this[string stringIndex] { get {return session[stringIndex];} set {session[stringIndex] = value;} } } } --- NEW FILE: Shell32.cs --- using System; using System.Runtime.InteropServices; namespace FAT.Web.HtmlDetails { /// <summary> /// Contains strings returned from the IShellFolder interface methods. /// </summary> [StructLayout(LayoutKind.Explicit)] public struct STRRET { /// <summary> /// Value that specifies the desired format of the string. /// </summary> [FieldOffset(0)] public int uType; /// <summary> /// Pointer to the OLE string. This memory must be allocated with the Shell's allocator (see SHGetMalloc). It is the calling application's responsibility to free this memory when it is no longer needed. The Shell's allocator must be used to free the memory. /// </summary> [FieldOffset(4)] public IntPtr pOleStr; /// <summary> /// Offset into item identifier list. /// </summary> [FieldOffset(4)] public uint uOffset; /// <summary> /// Buffer to receive the display name. /// </summary> [FieldOffset(8)] [MarshalAs(UnmanagedType.ByValArray, SizeConst=260)] char[] cStr; } /// <summary> /// Determines the type of items included in an enumeration. These values are used with the IShellFolder.EnumObjects method. /// </summary> [Flags()] public enum SHCONTF { /// <summary> /// Include items that are folders in the enumeration. /// </summary> FOLDERS = 0x20, /// <summary> /// Include items that are not folders in the enumeration. /// </summary> NONFOLDERS = 0x40, /// <summary> /// Include hidden items in the enumeration. /// </summary> INCLUDEHIDDEN = 0x80, /// <summary> /// IShellFolder.EnumObjects can return without validating the enumeration object. Validation can be postponed until the first call to IEnumIDList.Next. Use this flag when a user interface might be displayed prior to the first IEnumIDList.Next call. For a user interface to be presented, hwnd must be set to a valid window handle. /// </summary> INIT_ON_FIRST_NEXT = 0x100, /// <summary> /// The caller is looking for printer objects. /// </summary> NETPRINTERSRCH = 0x200, /// <summary> /// The caller is looking for remote shares. /// </summary> SHAREABLE = 0x400, /// <summary> /// Include items with accessible storage and their ancestors. /// </summary> STORAGE = 0x800 } /// <summary> /// Defines the values used with the IShellFolder.GetDisplayNameOf and IShellFolder.SetNameOf methods. /// </summary> [Flags()] public enum SHGDN { /// <summary> /// Full name. The name is relative to the desktop and not to a specific folder. This name is used for generic display. /// </summary> NORMAL = 0x0000, /// <summary> /// Relative name. The name is relative to the folder that is processing it. /// </summary> INFOLDER = 0x0001, /// <summary> /// The name is used for in-place editing when the user renames the item. /// </summary> FOREDITING = 0x1000, /// <summary> /// The name is displayed in an address bar combo box. /// </summary> FORADDRESSBAR = 0x4000, /// <summary> /// The name is used for parsing. That is, it can be passed to IShellFolder::ParseDisplayName to recover the object's pointer to an item identifier list (PIDL). The form this name takes depends on the particular object. /// </summary> FORPARSING = 0x8000 , }; /// <summary> /// Provides static methods for interop with shell32.dll. /// </summary> internal class Shell32 { /// <summary> /// Retrieves the IShellFolder interface for the desktop folder, which is the root of the Shell's namespace. /// </summary> /// <param name="folder">Used to return IShellFolder object for desktop folder.</param> /// <returns>Returns NOERROR if successful, or an OLE-defined error result otherwise.</returns> [DllImport("shell32.dll")] public static extern UInt32 SHGetDesktopFolder([MarshalAs(UnmanagedType.Interface)] [Out()]out IShellFolder folder); } } --- NEW FILE: Shell32Exception.cs --- using System; namespace FAT.Web.HtmlDetails { public class Shell32Exception : ApplicationException { public Shell32Exception(UInt32 hr, String message) : base(String.Format("HRESULT = {0}: {1}", hr, message)) { } } } |