现在的位置: 首页 > 综合 > 正文

收藏《CnForums和已有系统的整合方案》《通过IViewObject接口,取浏览器的图象,实现SNAP 》《SNAP的另类实现,采用iFRAME,内嵌框架的形式.》等

2014年03月26日 ⁄ 综合 ⁄ 共 17255字 ⁄ 字号 评论关闭

CnForums和已有系统的整合方案
1  可能我们已经有了一个完整的系统,已经有了一套用户系统,而需要加上论坛,也就是和CnForums整合,希望能共享验证,共享用户资料。可能有很多种方案,以我以前写过的一套解决方案为例,说明一下思路和具体实现过程,抛砖引玉:

更多请点击这儿

先说说用户共享,最理想的做法是共享一个用户库,而一般都不太方便,所以最简单有效的方法就是保证两个用户库的同步,也就是以前系统的用户表数据在CnForums的表数据有一份拷贝,所有系统的注册/修改资料/登录在同一个入口,修改资料则同步修改,注册用户则同步插入。要注意CnForums中数据表有2个:forums_Users、forums_UserProfile ,以UserID关联,在同步用户数据的时候,最好直接使用CnForums现有的注册/修改资料的存储过程forums_User_CreateUpdateDelete,或者参考其实现。(特别注意一下,如果你想密码也同步,就要注意@PasswordFormat参数,如果以前系统的密码没有加密,那么该参数的值就设置为0,否则就设置一个10以后的数字)
具体实现就是将CnForums的所有表和存储过程安装在原来的数据库上,因为CnForums的所有存储过程和表都是forums_开头,所以很容易区分。用SQL调用CnForums的forums_User_CreateUpdateDelete存储过程或参考其实现,写个SQL或者导入程序把以前系统的用户数据导入到CnForums的用户表中,修改 修改资料和注册的程序,保证两个地方用户数据的同步。

用户同步后,就是共享登录验证,共享登录验证有两种方案,一种就是保证密码同步、另一种就是只采用一个系统的登录验证。
先说说第一种,CnForums可以支持多种密码验证方案,如果你以前密码没有加密,那么什么都不用改,只要注意在同步用户的时候用户资料的PasswordFormat字段为0。如果是自己的加密方式,那么就要修改一下CnForums的相关源码,在AspNetForums.Enumerations.UserPasswordFormat中增加枚举,枚举的数值和同步用户数据时@PasswordFormat参数参数的值一致,这就是为什么让你设置一个10以上的数字了。再在AspNetForums.Users.public static string Encrypt(UserPasswordFormat format, string cleanString, string salt)方法中增加您原来系统的加密算法
如果您嫌第一种复杂,那么就可以采用第二种,共用一个登录验证,CnForums使用的是asp.net的Forms验证,在登录成功授权的时候,记录登录的用户名(username)(祥见AspNetForums.Controls中的Login.cs:FormsAuthentication.SetAuthCookie(userToLogin.Username, autoLogin.Checked),以后每次获取用户资料都是根据这个登录用户名来取用户资料(具体参考AspNetForums.Users.GetUser()、AspNetForums.Users.GetLoggedOnUsername()和AspNetForums.ForumsHttpModule.Application_AuthenticateRequest(Object source, EventArgs e)方法,ForumContext.Current.UserName = context.User.Identity.Name;),所以我们如果要让CnForums共享主系统的登录验证,可以在主系统登录成功后,也记录当前登录的Username,也就是Login.cs中的FormsAuthentication.SetAuthCookie(userToLogin.Username, autoLogin.Checked),在CnForums中,只要表中有当前登录的这个用户,就会认为当前这个用户是登录过的(在CnForums的HttpModule里面,如果当前登录的Username在表中没记录,则会自动注销,所以一定要保持用户表的同步)。还有要注意就是Forms验证不能跨域,所以就要让CnForums免虚拟目录安装,具体方法可搜索以前的帖子。
第二种方案的具体实现:
免虚拟目录安装好CnForums;
在主系统的登录程序中,密码校验成功后,使用FormsAuthentication.SetAuthCookie(username, autoLogin)方法设置登录成功,这样,当主系统登录后,CnForums就也是成功登录的。

=====

通过IViewObject接口,取浏览器的图象,实现SNAP

今天又见到snap实现的文章,看来对此感兴趣的人挺多的.实现这个功能确实很'眩',我也来做一个把玩一下.
我的做法不是 Control.DrawToBitmap ,而是直接QueryInterface 浏览器Com对象的 IViewObject 接口,用它实现的Draw方法,画到图象上.

首先定义IViewObject的接口声名,如下:
IVewObject接口声明
using System;
using System.Collections.Generic;
using System.Text;
using System.Security;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;

namespace SnapLibrary
{
    /**//// <summary>
    /// 从 .Net 2.0 的 System.Windows.Forms.Dll 库提取
    /// 版权所有:微软公司
    /// </summary>
    [SuppressUnmanagedCodeSecurity]
    internal static class UnsafeNativeMethods
    {
        public static Guid IID_IViewObject = new Guid("{0000010d-0000-0000-C000-000000000046}");

        [ComImport, Guid("0000010d-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IViewObject
        {
            [PreserveSig]
            int Draw([In, MarshalAs(UnmanagedType.U4)] int dwDrawAspect, int lindex, IntPtr pvAspect, [In] NativeMethods.tagDVTARGETDEVICE ptd, IntPtr hdcTargetDev, IntPtr hdcDraw, [In] NativeMethods.COMRECT lprcBounds, [In] NativeMethods.COMRECT lprcWBounds, IntPtr pfnContinue, [In] int dwContinue);
            [PreserveSig]
            int GetColorSet([In, MarshalAs(UnmanagedType.U4)] int dwDrawAspect, int lindex, IntPtr pvAspect, [In] NativeMethods.tagDVTARGETDEVICE ptd, IntPtr hicTargetDev, [Out] NativeMethods.tagLOGPALETTE ppColorSet);
            [PreserveSig]
            int Freeze([In, MarshalAs(UnmanagedType.U4)] int dwDrawAspect, int lindex, IntPtr pvAspect, [Out] IntPtr pdwFreeze);
            [PreserveSig]
            int Unfreeze([In, MarshalAs(UnmanagedType.U4)] int dwFreeze);
            void SetAdvise([In, MarshalAs(UnmanagedType.U4)] int aspects, [In, MarshalAs(UnmanagedType.U4)] int advf, [In, MarshalAs(UnmanagedType.Interface)] IAdviseSink pAdvSink);
            void GetAdvise([In, Out, MarshalAs(UnmanagedType.LPArray)] int[] paspects, [In, Out, MarshalAs(UnmanagedType.LPArray)] int[] advf, [In, Out, MarshalAs(UnmanagedType.LPArray)] IAdviseSink[] pAdvSink);
        }
    }
}

该接口.net 自己带了,只是internal形式,所以只有想办法用Reflector 将它弄出来,相关的还有几个类,分别是tagLOGPALETTE,COMRECT,tagDVTARGETDEVICE.
定义如下:
相关定义
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Drawing;

namespace SnapLibrary
{
    /**//// <summary>
    /// 从 .Net 2.0 的 System.Windows.Forms.Dll 库提取
    /// 版权所有:微软公司
    /// </summary>
    internal static class NativeMethods
    {
        [StructLayout(LayoutKind.Sequential)]
        public sealed class tagDVTARGETDEVICE
        {
            [MarshalAs(UnmanagedType.U4)]
            public int tdSize;
            [MarshalAs(UnmanagedType.U2)]
            public short tdDriverNameOffset;
            [MarshalAs(UnmanagedType.U2)]
            public short tdDeviceNameOffset;
            [MarshalAs(UnmanagedType.U2)]
            public short tdPortNameOffset;
            [MarshalAs(UnmanagedType.U2)]
            public short tdExtDevmodeOffset;
        }

        [StructLayout(LayoutKind.Sequential)]
        public class COMRECT
        {
            public int left;
            public int top;
            public int right;
            public int bottom;
            public COMRECT()
            {
            }

            public COMRECT(Rectangle r)
            {
                this.left = r.X;
                this.top = r.Y;
                this.right = r.Right;
                this.bottom = r.Bottom;
            }

            public COMRECT(int left, int top, int right, int bottom)
            {
                this.left = left;
                this.top = top;
                this.right = right;
                this.bottom = bottom;
            }

            public static NativeMethods.COMRECT FromXYWH(int x, int y, int width, int height)
            {
                return new NativeMethods.COMRECT(x, y, x + width, y + height);
            }

            public override string ToString()
            {
                return string.Concat(new object[] { "Left = ", this.left, " Top ", this.top, " Right = ", this.right, " Bottom = ", this.bottom });
            }

        }

        [StructLayout(LayoutKind.Sequential)]
        public sealed class tagLOGPALETTE
        {
            [MarshalAs(UnmanagedType.U2)]
            public short palVersion;
            [MarshalAs(UnmanagedType.U2)]
            public short palNumEntries;
        }
    }
}

现在可以通过 Marshal.QueryInterface 将浏览器COM实例的IViewObject接口取出:
//获取接口
object hret = Marshal.QueryInterface(Marshal.GetIUnknownForObject(pUnknown),ref UnsafeNativeMethods.IID_IViewObject, out pViewObject);pUnknown为 com对象实例.

将IViewObject 指针对象 pViewObject 转化为接口对象.
ViewObject = Marshal.GetTypedObjectForIUnknown(pViewObject, typeof(SnapLibrary.UnsafeNativeMethods.IViewObject)) as SnapLibrary.UnsafeNativeMethods.IViewObject;
调用draw方法,绘制到图象上,以下是TakeSnapshot方法的完整代码:
Snapshot类
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Drawing;
using System.Windows.Forms;

namespace SnapLibrary
{
    /**//// <summary>
    /// ActiveX 组件快照类
    /// AcitveX 必须实现 IViewObject 接口
    ///
    /// 作者:随飞
    /// http://chinasf.cnblogs.com
    /// chinasf@hotmail.com
    /// </summary>
    public class Snapshot
    {
        /**//// <summary>
        /// 取快照
        /// </summary>
        /// <param name="pUnknown">Com 对象</param>
        /// <param name="bmpRect">图象大小</param>
        /// <returns></returns>
        public Bitmap TakeSnapshot(object pUnknown, Rectangle bmpRect)
        {
            if (pUnknown == null)
                return null;
            //必须为com对象
            if (!Marshal.IsComObject(pUnknown))
                return null;
            //IViewObject 接口
            SnapLibrary.UnsafeNativeMethods.IViewObject ViewObject = null;
            IntPtr pViewObject = IntPtr.Zero;
            //内存图
            Bitmap pPicture = new Bitmap(bmpRect.Width, bmpRect.Height);
            Graphics hDrawDC = Graphics.FromImage(pPicture);
            //获取接口
            object hret = Marshal.QueryInterface(Marshal.GetIUnknownForObject(pUnknown),
                ref UnsafeNativeMethods.IID_IViewObject, out pViewObject);
            try
            {
                ViewObject = Marshal.GetTypedObjectForIUnknown(pViewObject, typeof(SnapLibrary.UnsafeNativeMethods.IViewObject)) as SnapLibrary.UnsafeNativeMethods.IViewObject;
                //调用Draw方法
                ViewObject.Draw((int)DVASPECT.DVASPECT_CONTENT,
                    -1,
                    IntPtr.Zero,
                    null,
                    IntPtr.Zero,
                    hDrawDC.GetHdc(),
                    new NativeMethods.COMRECT(bmpRect),
                    null,
                    IntPtr.Zero,
                    0);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                throw ex;
            }
            //释放
            hDrawDC.Dispose();
            return pPicture;
        }
    }

}

到此既完成了对Com对象的图象抓取.那么现在给它提供一个浏览器的实例,让它实现对 web page 的快照吧.
.net 2.0提供了webbrowser对象,它是对activex对象的包装,它的使用很简单,这里就不详细说明.
WebBrowser 对象的实例的属性ActiveXInstance就是它的原生COM对象,获取它的IVewObject接口,即可调用它实现的Draw方法把网页绘制到指定的DC上.

以下是对webbrowser对象的包装类,结合Snapshot 类的类代码:
web 页面快照类
/**//// <summary>
    /// web 页面快照类
    /// </summary>
    public class WebPageSnapshot : IDisposable
    {
        string url = "about:blank";

        /**//// <summary>
        /// 简单构造一个 WebBrowser 对象
        /// 更灵活的应该是直接引用浏览器的com对象实现稳定控制
        /// </summary>
        WebBrowser wb = new WebBrowser();
        /**//// <summary>
        /// URL 地址
        /// http://www.cnblogs.com
        /// </summary>
        public string Url
        {
            get { return url; }
            set { url = value; }
        }
        int width = 1024;
        /**//// <summary>
        /// 图象宽度
        /// </summary>
        public int Width
        {
            get { return width; }
            set { width = value; }
        }
        int height = 768;
        /**//// <summary>
        /// 图象高度
        /// </summary>
        public int Height
        {
            get { return height; }
            set { height = value; }
        }

        /**//// <summary>
        /// 初始化
        /// </summary>
        protected void InitComobject()
        {
            try
            {
                wb.ScriptErrorsSuppressed = false;
                wb.ScrollBarsEnabled = false;
                wb.Size = new Size(1024, 768);
                wb.Navigate(this.url);
                //因为没有窗体,所以必须如此
                while (wb.ReadyState != WebBrowserReadyState.Complete)
                    System.Windows.Forms.Application.DoEvents();
                wb.Stop();
                if (wb.ActiveXInstance == null)
                    throw new Exception("实例不能为空");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                throw ex;
            }
        }

        /**//// <summary>
        /// 获取快照
        /// </summary>
        /// <returns>Bitmap</returns>
        public Bitmap TakeSnapshot()
        {
            try
            {
                InitComobject();
                //构造snapshot类,抓取浏览器ActiveX的图象
                SnapLibrary.Snapshot snap = new SnapLibrary.Snapshot();
                return snap.TakeSnapshot(wb.ActiveXInstance, new Rectangle(0, 0, this.width, this.height));
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                throw ex;
            }
        }

        public void Dispose()
        {
            wb.Dispose();
        }

    }
这里提供一个测试用的代码:
class Program
    {
        /**//// <summary>
        /// 测试
        /// </summary>
        /// <param name="args"></param>
        [STAThread]
        static void Main(string[] args)
        {
            //web 页面快照
            WebPageSnapshot wps = new WebPageSnapshot();

            if (args != null && args.Length > 1)
                wps.Url = args[0];
            else
                wps.Url = "http://www.cnblogs.com";

            try
            {
                //保存到文件
                wps.TakeSnapshot().Save("1.bmp");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.ReadLine();
            }
            wps.Dispose();
        }

    }
工程原始代码下载:
/Files/Chinasf/SnapLibrary.rar

当然,这样做可能太复杂了,因为.net 为我们简化了所有的工作,简单到任意的contrl对象都支持DrawToBitmap 方法.不过想要了解机制的朋友们,可以研究一下.

2006年12月26日 8:55:14 修正:请到Snapshot类中增加一句释放引用接口的代码.
Snapshot..
            try
            {
                //ViewObject = Marshal.GetObjectForIUnknown(pViewObject) as SnapLibrary.UnsafeNativeMethods.IViewObject;
                ViewObject = Marshal.GetTypedObjectForIUnknown(pViewObject, typeof(SnapLibrary.UnsafeNativeMethods.IViewObject)) as SnapLibrary.UnsafeNativeMethods.IViewObject;
                //调用Draw方法
                ViewObject.Draw((int)DVASPECT.DVASPECT_CONTENT,
                        -1,
                        IntPtr.Zero,
                        null,
                        IntPtr.Zero,
                        hDrawDC.GetHdc(),
                        new NativeMethods.COMRECT(bmpRect),
                        null,
                        IntPtr.Zero,
                        0);
               Marshal.Release(pViewObject);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                throw ex;
            }
红色加粗位置.
=======

提高 SNAP 网页预览图的采集速度

http://www.cnblogs.com/Chinasf/archive/2006/12/30/607545.html

 

SNAP的另类实现,采用iFRAME,内嵌框架的形式.

通过调整iframe对象style 的zoom 属性,将页缩小.有点象抓的缩略图;并且不需要后台程序的支持,完全前端javascript完成,不过还是有很多的问题的,如果目标地址写了防止在别人框架内的脚本代码或者目标页的脚本运行出错,都会有影响.

   提示:您可以先修改部分代码再运行

抱歉!评论已关闭.