朱祁林       zhuqilin   

跨浏览器很棘手的问题探讨

    最经遇到一个很棘手的问题,写出来大家探讨一下。

    工作流系统中存在很多自定义的表单,由于是老系统,这些表单只能支持IE。现在做移动应用,需要将这些自定义的aspx表单展示在mobile safari浏览器中。

    这些自定义表单用了大量的htc、只支持ie的javascript。而现在的任务是需要将这些表单展示在mobile safari浏览器中。

    想了很多办法感觉都不好。昨天突然想到一个办法就是根据Url将表单转换成图片,然后展示到移动客户端。大致流程是:在服务端创建一个WebBrowser实例,在这个WebBrowser加载这个表单Url。由于WebBrowser内置的是IE内核,所以htc,javascript、css都能很好的运行,然后将通过ActiveX 将这个WebBrowser转换成图片。代码如下:

IViewObject.cs

    [ComVisible(true), ComImport()]
    [GuidAttribute("0000010d-0000-0000-C000-000000000046")]
    [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IViewObject
    {
        [return: MarshalAs(UnmanagedType.I4)]
        [PreserveSig]
        int Draw(
            [MarshalAs(UnmanagedType.U4)] UInt32 dwDrawAspect,
            int lindex,
            IntPtr pvAspect,
            [In] IntPtr ptd,
            IntPtr hdcTargetDev,
            IntPtr hdcDraw,
            [MarshalAs(UnmanagedType.Struct)] ref Rectangle lprcBounds,
            [MarshalAs(UnmanagedType.Struct)] ref Rectangle lprcWBounds,
            IntPtr pfnContinue,
            [MarshalAs(UnmanagedType.U4)] UInt32 dwContinue);
        [PreserveSig]
        int GetColorSet([In, MarshalAs(UnmanagedType.U4)] int dwDrawAspect,
           int lindex, IntPtr pvAspect, [In] IntPtr ptd,
            IntPtr hicTargetDev, [Out] IntPtr 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);
    }

HtmlCapture.cs

    public class HtmlCapture
{
private WebBrowser web;
private Timer tready;
private Rectangle screen;
private Size? imgsize = null;

//an event that triggers when the html document is captured
public delegate void HtmlCaptureEvent(object sender,
Uri url, Bitmap image);
public event HtmlCaptureEvent HtmlImageCapture;

//class constructor
public HtmlCapture()
{
//initialise the webbrowser and the timer
web = new WebBrowser();
tready
= new Timer();
tready.Interval
= 2000;
screen
= Screen.PrimaryScreen.Bounds;
//set the webbrowser width and hight
web.Width = screen.Width;
web.Height
= screen.Height;
//suppress script errors and hide scroll bars
web.ScriptErrorsSuppressed = true;
web.ScrollBarsEnabled
= false;
//attached events
web.Navigating +=
new WebBrowserNavigatingEventHandler(web_Navigating);
web.DocumentCompleted
+= new
WebBrowserDocumentCompletedEventHandler(web_DocumentCompleted);
tready.Tick
+= new EventHandler(tready_Tick);
}

#region Public methods
public void Create(string url)
{
imgsize
= null;
web.Navigate(url);
}

public void Create(string url, Size imgsz)
{
this.imgsize = imgsz;
web.Navigate(url);
}
#endregion

#region Events
void web_DocumentCompleted(object sender,
WebBrowserDocumentCompletedEventArgs e)
{
//start the timer
tready.Start();
// string s = web.Document.GetElementById("").InnerHtml;


}

void web_Navigating(object sender, WebBrowserNavigatingEventArgs e)
{
//stop the timer
tready.Stop();
}



void tready_Tick(object sender, EventArgs e)
{
//stop the timer
tready.Stop();
//get the size of the document's body
Rectangle body = web.Document.Body.ScrollRectangle;

//check if the document width/height is greater than screen width/height
Rectangle docRectangle = new Rectangle()
{
Location
= new Point(0, 0),
Size
= new Size(body.Width > screen.Width ? body.Width : screen.Width,
body.Height
> screen.Height ? body.Height : screen.Height)
};
//set the width and height of the WebBrowser object
web.Width = docRectangle.Width;
web.Height
= docRectangle.Height;

//if the imgsize is null, the size of the image will
//be the same as the size of webbrowser object
//otherwise set the image size to imgsize
Rectangle imgRectangle;
if (imgsize == null)
imgRectangle
= docRectangle;
else
imgRectangle
= new Rectangle()
{
Location
= new Point(0, 0),
Size
= imgsize.Value
};
//create a bitmap object
Bitmap bitmap = new Bitmap(imgRectangle.Width, imgRectangle.Height);
//get the viewobject of the WebBrowser


IViewObject ivo
= web.Document.DomDocument as IViewObject;
ivo.ToString();
using (Graphics g = Graphics.FromImage(bitmap))
{
//get the handle to the device context and draw
IntPtr hdc = g.GetHdc();
ivo.Draw(
1, -1, IntPtr.Zero, IntPtr.Zero,
IntPtr.Zero, hdc,
ref imgRectangle,
ref docRectangle, IntPtr.Zero, 0);
g.ReleaseHdc(hdc);
}
//invoke the HtmlImageCapture event
HtmlImageCapture(this, web.Url, bitmap);
}
#endregion
}
}

下面我们使用上面代码可以截图工作流表单的图片了:

       void hc_HtmlImageCapture(object sender, Uri url, Bitmap image)
        {
           image.Save("C:/test.bmp");
        }
        private void button1_Click(object sender, EventArgs e)
        {
         HtmlCapture hc = new HtmlCapture();
         hc.HtmlImageCapture += new HtmlCapture.HtmlCaptureEvent(hc_HtmlImageCapture);
         hc.Create("http://10.5.23.117:8011/Recipe1.aspx");
    
       }

这样效果和PC端展示一样。

截取百度快照:

获取的图片:

尽管展示和pc端一样,但是图片存在的问题主要有:

1、不支持复制粘贴

2、不支持多标签页的切换(移动端不需要支持表单编辑功能)

3、不支持超链接点击

总结:由于WebBrowser支持htc、已经写好的javascript代码,而js和htc做了不少业务逻辑处理,所以在服务端使用WebBrowser去处理表单的思路是正确的。但是进一步如何解决上面的三个问题。需要进一步探讨。在不大量修改之前存在的工作流表单的前提下,如果你有更好的想法,期待你的告诉我。

附:根据url抓取图片代码

作者:朱祁林
出处:http://zhuqil.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

 



posted @ 2011-08-17 20:03 麒麟 阅读(1539) 评论(10) 编辑 收藏

 回复 引用 查看   
#1楼2011-08-18 01:19 | Gray Zhang      
典型的用错误去弥补错误……去招个专业点的前端带队花点时间改造下不就好了,不愿意下成本的公司真是可悲……
 回复 引用 查看   
#2楼[楼主]2011-08-18 08:08 | 麒麟      
引用Gray Zhang:典型的用错误去弥补错误……去招个专业点的前端带队花点时间改造下不就好了,不愿意下成本的公司真是可悲……

如果一遇到点问题就想到去招人,那公司要你是干什么的呢。再者说这种情况前端怎么去搞定呢?

 回复 引用 查看   
#3楼2011-08-18 10:37 | Gray Zhang      
@麒麟
你们能做出给IE看的页面,就做不出给Safari看的?还是说你们公司真没人会写HTML了?htc是啥,没用ActiveX的话也就是javascript而已。只要你们没用上ActiveX,有啥东西是不能改造成w3标准模式,做到全浏览器兼容的?

 回复 引用 查看   
#4楼[楼主]2011-08-18 11:47 | 麒麟      
@Gray Zhang
htc是ie特有的东西。
不是不会写html,而是系统已经卖出去很多了,工作流表单不能修改。就算是重写工作流也巨大,不可取。

 回复 引用 查看   
#5楼[楼主]2011-08-18 11:47 | 麒麟      
@Gray Zhang
htc是IE特有的东西。

 回复 引用 查看   
#6楼2011-08-18 11:48 | Gray Zhang      
@麒麟
你有打开htc看看里面是啥不?只要你没用上ActiveX的相关API,htc里面就是个XML和javascript,指定javascript的执行目标,明白不?
算了,不说了,期待你可取的“从图片上复制粘贴文字”的代价有多大吧

 回复 引用 查看   
#7楼[楼主]2011-08-18 11:54 | 麒麟      
@Gray Zhang
额,htc我确实不是特别懂。
我可没有说“从图片上复制粘贴文字”。
我说用IE控件去执行页面的js和htc是条好出路。
这样就可以得到执行过js和htc之后的html,返回给移动客户端。这是我现在的思路。

 回复 引用 查看   
#8楼2011-08-18 15:45 | i.Net      
以前的项目有用过htc的,现在全部extjs
 回复 引用 查看   
#9楼[楼主]2011-08-18 16:53 | 麒麟      
引用i.Net:以前的项目有用过htc的,现在全部extjs

我们就是一整套erp系统,大概02年就开发了的,每个角落都用了htc,很杯具。。

 回复 引用 查看   
#10楼2011-08-19 14:31 | A区炸蛋已安放      
不懂。。。