Office文档在线编辑的实现之二

在线编辑Office文档
本文介绍如何利用WebDAV协议实现在客户端直接编辑服务器或数据库中的Office文档,包括关键步骤及代码示例。
<iframe marginwidth="0" marginheight="0" src="http://218.16.120.35:65001/PC/Global/images/b.html" frameborder="0" width="728" scrolling="no" height="90"></iframe>
上篇文章讲述了如何通过iis的webdav支持实现客户端的office直接编辑服务器上的文件,
本篇将讲解如何实现客户端的office直接编辑数据库中的二进制形式保存的office文件。

实现的关键:模拟IIS,自己实现一个webdav的服务器端。

首先,我们简单了解一下webdav:
webdav,中文可以翻译为网络分布式协作协议,它解决了http协议中一个问题:http无法实现版本和单访问控制。
什么是单访问控制呢?假设我们有一个页面编辑某条数据,这个页面可以同时被多个用户使用,那么最终的数据是最后一个用户提交的数据,
而其他用户是不知道的.我们的99%的web程序都存在此问题,当然通过编码可以解决,但http协议本身并没有提供对这种情形的支持。

webdav协议在标准的http协议的基础上,扩展了以下请求动作(verb):
PUT:用于客户端推送二进制文件。(好像http有这个verb)
LOCK:用户锁定一个资源,保证资源的单访问
UNLOCK:解锁一个资源
OPTIONS:获取服务器可以支持的请求类型
DELETE:删除服务器文件
PROPFIND:查询文件属性
其他动作: OPTIONS, TRACE, GET, HEAD, DELETE, PUT, POST, COPY, MOVE, MKCOL, PROPFIND, PROPPATCH, LOCK, UNLOCK, SEARCH
要详细地了解webdav,大家可以google一下,或访问 http://en.wikipedia.org/wiki/WebDAV

笔者在实现这个解决方案的时候,是采用fiddler,debug IE的http请求,才搞懂了IIS本身的实现机制,为了形象化,可以看一下webdav请求相应的
数据:
发起一个OPTIONS请求
OPTIONS /PMDemo/Test/待办事务.doc HTTP/1.1
User-Agent: Fiddler
Host: localhost

响应如下:
HTTP/1.1 200 OK
Date: Wed, 27 Dec 2006 11:34:03 GMT
Server: Microsoft-IIS/6.0
MicrosoftOfficeWebServer: 5.0_Pub
X-Powered-By: ASP.NET
MS-Author-Via: DAV
Content-Length: 0
Accept-Ranges: bytes
DASL: <DAV:sql>
DAV: 1, 2
Public: OPTIONS, TRACE, GET, HEAD, DELETE, PUT, POST, COPY, MOVE, MKCOL, PROPFIND, PROPPATCH, LOCK, UNLOCK, SEARCH
Allow: OPTIONS, TRACE, GET, HEAD, DELETE, PUT, COPY, MOVE, PROPFIND, PROPPATCH, SEARCH, LOCK, UNLOCK
Cache-Control: private

搞清楚了这些,下面我们的任务就是如何在asp.net中实现一个wevdav服务器.
显然,这要求我们需要在底层截获http请求,幸运的是asp.net中支持这种技术:HttpHandler.它可以让我们自己的代码来处理http请求.

首先,我们在web.config中做如下配置:
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--> < httpHandlers >
< remove verb ="*" path ="*" />
< add verb ="GET,PUT,UNLOCK,LOCK,OPTIONS" path ="*.doc,*.xml" type ="Webdav.WebdavProtocolHandler, Webdav " />
</ httpHandlers >
通过这个配置,使我们的 WebdavProtocolHandler可以来处理webdav请求.

WebdavProtocolHandler类是一个标准的httphandler,实现了IHttpHandler接口,它按照客户端的请求类型,返回符合wevdav协议的数据.

WebdavProtocolHandler类需要按照不同的webdav请求动作,做不同的处理,那么怎么来实现这个类呢?
这里就要用到一个设计模式:命令模式.

首先定义一个接口:

<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--> public interface IVerbHandler
{
void Process(HttpContextcontext);
}

实现对Options请求的处理:
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--> class OptionsHandler:IVerbHandler
{
#region IVerbHandler成员

public void Process(System.Web.HttpContextcontext)
{
context.Response.AppendHeader(
" DASL " , " <DAV:sql> " );
context.Response.AppendHeader(
" DAV " , " 1,2 " );

context.Response.AppendHeader(
" Public " , " OPTIONS,TRACE,GET,HEAD,DELETE,PUT,POST,COPY,MOVE,MKCOL,PROPFIND,PROPPATCH,LOCK,UNLOCK,SEARCH " );

context.Response.AppendHeader(
" Allow " , " OPTIONS,TRACE,GET,HEAD,DELETE,PUT,COPY,MOVE,PROPFIND,PROPPATCH,SEARCH,LOCK,UNLOCK " );
}

#endregion
}
webdav的请求verb多达15个以上,大多数情况下,我们并不需要一个完整的webdav支持,故我们只要对其中的几个进行实现即可。

实现对LOCK的支持:
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--> class LockHandler:IVerbHandler
{
#region IVerbHandler成员

public void Process(System.Web.HttpContextcontext)
{
context.Response.ContentType
= " text/xml " ;

string token = Guid.NewGuid().ToString() + " : " + DateTime.Now.Ticks.ToString();

context.Response.AppendHeader(
" Lock-Token " , " <opaquelocktoken: " + token + " > " );

string xml = @" <?xmlversion=""1.0""?>
<a:propxmlns:a=""DAV:""><a:lockdiscovery>
<a:activelock><a:locktype><a:write/></a:locktype>
<a:lockscope><a:exclusive/></a:lockscope><ownerxmlns=""DAV:"">Administrator</owner><a:locktoken>
<a:href>opaquelocktoken:{0}</a:href></a:locktoken>
<a:depth>0</a:depth><a:timeout>Second-180</a:timeout></a:activelock></a:lockdiscovery>
</a:prop>
" ;

context.Response.Write(String.Format(xml,token));
context.Response.End();
}

#endregion
}

注意这篇文章的主题:实现在线编辑。并没有版本控制等其他内容,大家仔细看以上的代码,服务器并没有真正实现"锁定",只是假装告诉客户端,你要的资源已经给你锁定了,你可以放心的编辑了。当然,有兴趣的朋友可以实现真正的锁定,无非可以通过给数据做一个状态字段来实现。但注意,要考虑一些复杂的情况,如自动解锁(用户打开一个文档,然后关机了,文档岂不永远锁定了?)等等。

接着,我们实现UNLOCK,同样是假的:
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--> class UnLockHandler:IVerbHandler
{
#region IVerbHandler成员

public void Process(System.Web.HttpContextcontext)
{
}

#endregion
}

下面,我们将实现两个最重要的请求动作的处理:Get和Put, office请求打开一个服务器上的文件时,采用get请求,office保存一个文件到服务器上时,发送put请求。

首先,我们要考虑一种数据项标识的传递策略,即:客户端发起访问数据库的office文件行,那么如何确认数据行的主键?
有两种策略:
1)通过不同的文件名 , 如,请求http://localhost/weboffice/1.doc 这个请求主键 为1的文件。
2)通过文件路径, 如,请求http://localhost/weboffice/1/文件名.doc 这个请求主键为1的文件。
我们将采用策略2。

再返回到我们对web.config做的配置:

< add verb ="GET,PUT,UNLOCK,LOCK,OPTIONS" path ="*.doc,*.xml" type ="Webdav.WebdavProtocolHandler, Webdav " />

这个配置允许
WebdavProtocolHandler处理所有对doc和xml的请求处理,为什么要允许xml呢,因为office2003之后,支持xml格式,可以直接在
数据库重以xml的格式存放office文件。

接着,我们要确认我们的数据存储结构,即,office文件在数据库中时如何存放的。

我们有一个附件表:Document
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--> CREATE TABLE [ dbo ] . [ Document ] (
[ DocumentId ] [ int ] IDENTITY ( 1 , 1 ) NOT NULL ,
[ Name ] [ varchar ] ( 50 )COLLATEChinese_PRC_CI_AS NULL ,
[ Description ] [ text ] COLLATEChinese_PRC_CI_AS NULL ,
[ CreateTime ] [ datetime ] NULL ,
[ Size ] [ int ] NULL ,
[ CreatorId ] [ varchar ] ( 50 )COLLATEChinese_PRC_CI_AS NULL ,
[ CreatorName ] [ char ] ( 10 )COLLATEChinese_PRC_CI_AS NULL ,
[ CreateYear ] [ int ] NULL ,
[ ContentType ] [ varchar ] ( 50 )COLLATEChinese_PRC_CI_AS NULL ,
[ DeptId ] [ varchar ] ( 50 )COLLATEChinese_PRC_CI_AS NULL ,
[ DeptName ] [ varchar ] ( 50 )COLLATEChinese_PRC_CI_AS NULL ,
[ Content ] [ image ] NULL ,
[ ModifyTime ] [ datetime ] NULL ,
[ OwnerType ] [ varchar ] ( 50 )COLLATEChinese_PRC_CI_AS NULL ,
[ TemplateAble ] [ bit ] NULL
)
ON [ PRIMARY ] TEXTIMAGE_ON [ PRIMARY ]
GO
设计一个文裆实体:
[Serializable]
public class Document
{
public Document()
{}

static public DocumentFromPostFile(System.Web.HttpPostedFilefile,Useruser)
{
Documentdoc
= new Document(file);
doc.CreateTime
= DateTime.Now;
doc.CreatorId
= user.Id;
doc.CreatorName
= user.Name;
doc.DeptId
= user.OrgId;
doc.DeptName
= user.OrgName;
return doc;
}

public Document(System.Web.HttpPostedFilefile)
{
string []strs = file.FileName.Split( ' // ' );
this .Name = strs[strs.Length - 1 ];
Size
= file.ContentLength;
// 读取文件的数据
this .Content = new byte [Size];
StreamfileDataStream
= file.InputStream;
fileDataStream.Read(
this .Content, 0 ,Size);
ContentType
= file.ContentType;
}

private int _DocumentId;
/// <summary>
/// 任务名
/// </summary>
private string _Name;
/// <summary>
/// 任务描述
/// </summary>
private string _Description;
/// <summary>
/// 报表创建时间
/// </summary>
private DateTime_CreateTime = DateTime.Now;
private int _Size = 0 ;
private byte []_Data;
/// <summary>
/// 创建人Id
/// </summary>
private string _CreatorId;
/// <summary>
/// 创建人名
/// </summary>
private string _CreatorName;

private int _CreateYear;
private string _ContentType;
/// <summary>
/// 部门ID(便于统计)
/// </summary>
private string _DeptId;
/// <summary>
/// 部门名
/// </summary>
private string _DeptName;
// PropertyDocumentId
public int DocumentId
{
get
{
return _DocumentId;
}
set
{

this ._DocumentId = value;
}
}
// PropertyName
public string Name
{
get
{
return _Name;
}
set
{

this ._Name = value;
}
}
// PropertyDescription
public string Description
{
get
{
return _Description;
}
set
{

this ._Description = value;
}
}
// PropertyCreateTime
public DateTimeCreateTime
{
get
{
return _CreateTime;
}
set
{

this ._CreateTime = value;
}
}
private DateTime_ModifyTime = DateTime.Now;
public DateTimeModifyTime
{
get
{
return _ModifyTime;
}
set
{

this ._ModifyTime = value;
}
}
// PropertySize
public int Size
{
get
{
return _Size;
}
set
{

this ._Size = value;
}
}
// PropertyData
public byte []Content
{
get
{
return _Data;
}
set
{

this ._Data = value;
}
}
// PropertyCreatorId
public string CreatorId
{
get
{
return _CreatorId;
}
set
{

this ._CreatorId = value;
}
}

// PropertyCreatorName
public string CreatorName
{
get
{
return _CreatorName;
}
set
{

this ._CreatorName = value;
}
}
// PropertyCreateYear
public int CreateYear
{
get
{
return _CreateYear;
}
set
{

this ._CreateYear = value;
}
}
// PropertyContentType
// application/msword
// text/plain
public string ContentType
{
get
{
return _ContentType;
}
set
{

this ._ContentType = value;
}
}

// PropertyDeptId
public string DeptId
{
get
{
return _DeptId;
}
set
{
if ( this ._DeptId != value)
this ._DeptId = value;
}
}
// PropertyDeptName
public string DeptName
{
get
{
return _DeptName;
}
set
{

this ._DeptName = value;
}
}

private string _Type;
public string OwnerType
{
get
{
return _Type;
}
set
{

this ._Type = value;
}
}
private bool _TemplateAble;
/// <summary>
/// 是否可以作为模版
/// </summary>
public bool Templateable
{
get
{
return _TemplateAble;
}
set
{

this ._TemplateAble = value;
}
}
public override string ToString()
{
return Encoding.UTF8.GetString( this .Content);
}

public static DocumentFromString( string s,Useruser)
{
Documentdoc
= new Document();
doc.CreateTime
= DateTime.Now;
doc.CreatorId
= user.Id;
doc.CreatorName
= user.Name;
doc.DeptId
= user.OrgId;
doc.DeptName
= user.OrgName;
doc.Content
= Encoding.UTF8.GetBytes(s);
doc.Size
= doc.Content.Length;
doc.ContentType
= " text/plain " ;
return doc;
}
public static string ByteToString( byte []bytes)
{
return Encoding.UTF8.GetString(bytes);
}
public static byte []StringToByte( string s)
{
return Encoding.UTF8.GetBytes(s);
}
public string GetExtendName()
{
string []arr = this .Name.Split( ' . ' );

if (arr.Length < 1 ) return "" ;
else return arr[arr.Length - 1 ];
}
}

考虑到数据操作逻辑的可变性,不同的项目里面附件表设计的不同,这里引入一个数据操作接口:
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--> public interface IWebdavDocumentHandler
{
DocumentGetDocument(
int id);//获取文档数据
void ModifyDocContent( int docId, byte []data);//修改文档内容
}

具体的实现这里就不写了。

好了,我们的数据访问逻辑已经有了,那么首先看get动作处理的实现:
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--> class GetHandler:IVerbHandler
{
#region IVerbHandler成员
public void Process(System.Web.HttpContextcontext)
{
int id = WebdavProtocolHandler.GetDocumentId(context); //获取到主键

IWebdavDocumentHandler docSvr = new DefaultWebdavDocumentHandler() ; //修改此处代码,实现不同的数据操作逻辑,可引入工厂模式
Documentdoc
= docSvr.GetDocument(id);

if (doc == null )
{
context.Response.Write(
" 文档不存在! " );
return ;
}

context.Response.Clear();
context.Response.ContentType
= doc.ContentType;
// 下载文件名限制32字符16汉字
int maxlength = 15 ;
string fileName = doc.Name; // att.FileName;
if (fileName.Length > maxlength)
{
fileName
= " - " + fileName.Substring(fileName.Length - maxlength,maxlength);
}

fileName
= HttpUtility.UrlEncode(fileName,System.Text.Encoding.UTF8); // 必须编码,不然文件名会出现乱码
context.Response.AppendHeader( " Content-Disposition " , " attachment;filename= " + fileName + "" );

if (doc.Content != null && doc.Content.Length > 0 )
context.Response.BinaryWrite(doc.Content);

context.Response.End();
}
#endregion
}
很简单吧,跟我们普通实现文档下载的代码一样。

put动作的实现:
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--> class PutHandler:IVerbHandler
{
#region IVerbHandler成员

public void Process(System.Web.HttpContextcontext)
{
int docId = WebdavProtocolHandler.GetDocumentId(context);

Documentdoc
= GetDocFromInput(context.Request);

doc.DocumentId
= docId;

IWebdavDocumentHandler docSvr = new DefaultWebdavDocumentHandler() ; //修改此处代码,实现不同的数据操作逻辑,可引入工厂模式

docSvr.ModifyDocContent(doc.DocumentId,doc.Content);
}

private DocumentGetDocFromInput(System.Web.HttpRequestrequest)
{
Documentdoc
= new Document();
// 读取文件的数据
doc.Content = new byte [request.ContentLength];
doc.Size
= request.ContentLength;
StreamfileDataStream
= request.InputStream;
fileDataStream.Read(doc.Content,
0 ,doc.Size);
doc.ContentType
= request.ContentType;
return doc;
}
#endregion
}

OK,主要的动作都实现了,下面,我们需要WebdavProtocolHandler将各命令处理对象整合到一起:
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--> public class WebdavProtocolHandler:IHttpHandler
{
public static int GetDocumentId(HttpContextcontext)//按照前面确定的主键策略返回主键
{
string url = context.Request.Url.ToString();
string []arr = url.Split( ' / ' );
string id = arr[arr.Length - 2 ];
return Convert.ToInt32(id);
}
public void ProcessRequest(HttpContextcontext)
{
HttpRequestRequest
= context.Request;
context.Response.AppendHeader(
" OpenWebDavServer " , " 1.0 " );
string verb = Request.HttpMethod;
// Log.Write(verb);
IVerbHandlervh
= GetVerbHandler(verb);

if (vh == null )
return ;

vh.Process(context);
}

private IVerbHandlerGetVerbHandler( string verb)
{
switch (verb)
{
case " LOCK " :
return new LockHandler();
case " UNLOCK " :
return new UnLockHandler();
case " GET " :
return new GetHandler();
case " PUT " :
return new PutHandler();
case " OPTIONS " :
return new OptionsHandler();
default :
return null ;
}
}

public bool IsReusable
{
get { return false ;}
}

}

到这里呢,已经基本上算game over了,基于以上代码设计,可以完全实现office文档的在线编辑。若要通过链接直接打开编辑,可以
采用 Office文档在线编辑的实现之一Document_Edit2函数触发office编辑。

哦,IIS还需要做一点小配置:
1)将.doc , .xml 加入到站点虚拟目录的isapi映射, 不要选中 "确认文件是否存在",动作要选全部动作,
2)禁用IIS本身的Webdav扩展,
3)删除虚拟目录HTTP头中的自定义HTTP头: MicrosoftOfficeWebServer,如果有的话。
版本修改记录: V2.2.0.2修改: 修改了HttpPost相对路径的一些问题。 V2.2.0.0增加: [id(0x00010041), helpstring("Get Rev Index")] HRESULT GetRevCount( [out,retval] long * pbool); [id(0x00010042), helpstring("Get Rev Index Info")] HRESULT GetRevInfo([in] long lIndex, [in] long lType, [out,retval] BSTR* pbool); [id(0x00010043), helpstring("Set Doc Prop")] HRESULT SetValue([in] BSTR strValue, [in] BSTR strName, [out,retval] long* pbool); [id(0x00010044), helpstring("Set Doc Variable")] HRESULT SetDocVariable([in] BSTR strVarName, [in] BSTR strValue,[in] long lOpt, [out,retval] long* pbool); [id(0x00010045), helpstring("Save page To Doc")] HRESULT SetPageAs([in] BSTR strLocalFile, [in] long lPageNum, [in] long lType,[out,retval] long* pbool); ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- LoadDso.js var s = "" s += "" s += "" document.write(s) ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- 接口文档: /* 1.新建 */ //新建Word document.all.FramerControl1.CreateNew("Word.Document"); //新建Excel document.all.FramerControl1.CreateNew("Excel.Sheet"); /* 2.打开文件 */ //打开制定的本地文件 document.all.FramerControl1.Open("C:\\TestBook.xls"); //制定用Word来打开c:\plain.txt文件 document.all.FramerControl1.Open("C:\\Plain.txt",false, "Word.Document"); //打开服务器的文件 document.all.FramerControl1.Open "https://secureserver/test/mytest.asp?id=123",true, "Excel.Sheet", "MyUserAccount", "MyPassword"); //打开服务器的文件 document.all.FramerControl1.Open("http://localhost/1.doc", true); /* 3.保存文件 */ //到本地 document.all.FramerControl1.Save("c:\\1.doc",true); //服务器 /*增加Http协议Post上传接口,可以Post一个动态页面(jsp,asp,php...),由动态页面负责解析数据 bool HttpInit(); bool HttpAddPostString(BSTR strName, BSTR strValue); bool HttpAddPostCurrFile(BSTR strFileID, BSTR strFileName); BSTR HttpPost(BSTR bstr); */ //初始化Http引擎 document.all.FramerControl1.HttpInit(); //增加Post变量 document.all.FramerControl1.HttpAddPostString("RecordID","20060102200"); document.all.FramerControl1.HttpAddPostString("UserID","李局长"); //上传打开的文件 document.all.FramerControl1.HttpAddPostCurrFile("FileData", "文档名.doc"); //执行上传动作 document.all.FramerControl1.HttpPost("http://xxxx.com/uploadfile.asp"); /* 4.修订留痕 */ //进入留痕状态 document.all.FramerControl1.SetTrackRevisions(1); //进入非留痕状态 document.all.FramerControl1.SetTrackRevisions(0); //接受当前修订 document.all.FramerControl1.SetTrackRevisions(4); /* 5.设置当前用户 */ document.all.FramerControl1.SetCurrUserName("张三"); /* 6.设置当前时间(笔迹留痕会显示("Like 2006:02:07 11:11:11") */ document.all.FramerControl1.SetCurrTime("2006:02:07 11:11:11"); /* 7.设置和创建书签,此功能比较强大,设置书签数据、添加书签和添加红头文件就靠他了 SetFieldValue(BSTR strFieldName, BSTR strValue, BSTR strCmdOrSheetName) strFieldName:书签名 strValue:要设置的值 strCmdOrSheetName: 命令 ::ADDMARK:: 添加BookMark ::DELMARK:: 删除这个BookMark ::GETMARK:: 定位到这个BookMark ::FILE:: 插入的是文件 ::JPG:: 插入的是图片 一般来说:WORD中书签是做好的,可以通过此接口把外界数据设置进书签中去。 */ //在当前WORD位置插入标签,标签名为"book1",数值为"test" document.all.FramerControl1.SetFieldValue("book1","test","::ADDMARK::"); //设置书签"Time",数值为"2006-03-16 22:22:22" document.all.FramerControl1.SetFieldValue("Time","2006-03-16 22:22:22",""); //在书签位置"hongtou",插入红头文件"http://222.222.222.222/hongtou1.doc" 这样,红头就自动插进去了 document.all.FramerControl1.SetFieldValue("hongtou","http://222.222.222.222/hongtou1.doc","::FILE::"); /* 8.设置菜单显示情况 BOOL SetMenuDisplay(long lMenuFlag) lMenuFlag为以下数值的组合 #define MNU_NEW 0x01 #define MNU_OPEN 0x02 #define MNU_CLOSE 0x04 #define MNU_SAVE 0x08 #define MNU_SAVEAS 0x16 #define MNU_PGSETUP 0x64 #define MNU_PRINT 0x256 #define MNU_PROPS 0x32 #define MNU_PRINTPV 0x126 */ //只有“新建”菜单可用 document.all.FramerControl1..SetMenuDisplay(1); //只有“打开”菜单可用 document.all.FramerControl1.SetMenuDisplay(2); //只有“打开”和“新建”菜单可用 document.all.FramerControl1.SetMenuDisplay(3); /* 9.保护文档和解保护文档 lProOrUn:1:保护文档;0:解除保护 lProType: wdNoProtection = -1, wdAllowOnlyRevisions = 0, wdAllowOnlyComments = 1, wdAllowOnlyFormFields = 2 strProPWD:密码 */ //完全保护文档,密码为"pwd" document.all.FramerControl1.ProtectDoc(1,1,"pwd"); //解除文档保护 document.all.FramerControl1.ProtectDoc(0,1,"pwd"); /* 10.显示或隐藏修订内容 ShowRevisions(long nNewValue) nNewValue = 0 则隐藏修订 = 1 则显示修订 */ //显示修订留痕 document.all.FramerControl1.ShowRevisions(1); //隐藏修订留痕 document.all.FramerControl1.ShowRevisions(0); /* 11.插入合并文件, strFieldPath 文件路径,可以是http,ftp的路径 pPos = 0 //当前鼠标位置 1;文件开头 2;文件末尾 pPos的第4位为1的时候,代表插入的是图片 InSertFile(BSTR strFieldPath, long lPos) */ //文件头部插入文件 document.all.FramerControl1.InSertFile("http://XX.com/XX.doc",1); //文件尾部插入文件 document.all.FramerControl1.InSertFile("http://XX.com/XX.doc",2); //当前光标位置插入文件 document.all.FramerControl1.InSertFile("http://XX.com/XX.doc",0); //文件头部插入图片 document.all.FramerControl1.InSertFile("http://XX.com/XX.jpg",9); //文件尾部插入图片 document.all.FramerControl1.InSertFile("http://XX.com/XX.jpg",10); //当前光标位置插入图片 document.all.FramerControl1.InSertFile("http://XX.com/XX.jpg",8); /* 0x31. 文档另存为 HRESULT SaveAs([in] VARIANT strFileName, [in] VARIANT dwFileFormat, [out,retval] long* pbool); 参数: strFileName:文件本地路径,如c:\\11.doc dwFileFormat: 文件格式 dwFileFormat的数值为: Excel: Type enum XlFileFormat { xlAddIn = 18, xlCSV = 6, xlCSVMac = 22, xlCSVMSDOS = 24, xlCSVWindows = 23, xlDBF2 = 7, xlDBF3 = 8, xlDBF4 = 11, xlDIF = 9, xlExcel2 = 16, xlExcel2FarEast = 27, xlExcel3 = 29, xlExcel4 = 33, xlExcel5 = 39, xlExcel7 = 39, xlExcel9795 = 43, xlExcel4Workbook = 35, xlIntlAddIn = 26, xlIntlMacro = 25, xlWorkbookNormal = -4143, xlSYLK = 2, xlTemplate = 17, xlCurrentPlatformText = -4158, xlTextMac = 19, xlTextMSDOS = 21, xlTextPrinter = 36, xlTextWindows = 20, xlWJ2WD1 = 14, xlWK1 = 5, xlWK1ALL = 31, xlWK1FMT = 30, xlWK3 = 15, xlWK4 = 38, xlWK3FM3 = 32, xlWKS = 4, xlWorks2FarEast = 28, xlWQ1 = 34, xlWJ3 = 40, xlWJ3FJ3 = 41, xlUnicodeText = 42, xlHtml = 44 }; Word: Type enum WdSaveFormat { wdFormatDocument = 0, wdFormatTemplate = 1, wdFormatText = 2, wdFormatTextLineBreaks = 3, wdFormatDOSText = 4, wdFormatDOSTextLineBreaks = 5, wdFormatRTF = 6, wdFormatUnicodeText = 7, wdFormatEncodedText = 7, wdFormatHTML = 8 }; PPT: enum PpSaveAsFileType { ppSaveAsPresentation = 1, ppSaveAsPowerPoint7 = 2, ppSaveAsPowerPoint4 = 3, ppSaveAsPowerPoint3 = 4, ppSaveAsTemplate = 5, ppSaveAsRTF = 6, ppSaveAsShow = 7, ppSaveAsAddIn = 8, ppSaveAsPowerPoint4FarEast = 10, ppSaveAsDefault = 11, ppSaveAsHTML = 12, ppSaveAsHTMLv3 = 13, ppSaveAsHTMLDual = 14, ppSaveAsMetaFile = 15, ppSaveAsGIF = 16, ppSaveAsJPG = 17, ppSaveAsPNG = 18, ppSaveAsBMP = 19 }; */ /* 0x32. 删除本地文件 HRESULT DeleteLocalFile([in] BSTR strFilePath); 参数: strFileName:文件本地路径,如c:\\11.doc */ /* 0x33.创建临时文件 HRESULT GetTempFilePath([out,retval] BSTR* strValue); 返回: 临时文件的路径地址。使用完后,用DeleteLocalFile 删除 */ /* 0x34.设置文档显示模式 HRESULT ShowView([in] long dwViewType, [out,retval] long * pbool); dwViewType的可取值为: enum WdViewType { wdNormalView = 1, wdOutlineView = 2, wdPrintView = 3, wdPrintPreview = 4, wdMasterView = 5, //这个是大纲 wdWebView = 6 }; */ //大纲模式 document.all.FramerControl1.ShowView(5); /* 0x39:下载远程文件 HRESULT DownloadFile( [in] BSTR strRemoteFile, [in] BSTR strLocalFile, [out,retval] BSTR* strValue); 参数: strRemoteFile:远程路径地址,http or Ftp strLocalFile: 本地保存地址,if strLocalFile == NULL then Create Temp File and return TempFile's Path */ /* 0x40:增加Http上传时候的,附加其他文件 HRESULT HttpAddPostFile([in] BSTR strFileID, [in] BSTR strFileName, [out,retval] long* pbool); 参数: strFileID:文件的ID,供服务器端页面解析 strFileName: 本地文件地址 */ /* 0x41,0x42.获取详细的修订信息。 GetRevCount( [out,retval] long * pbool); GetRevInfo([in] long lIndex, [in] long lType, [out,retval] BSTR* pbool); 例子如下 */ var vCount; vCount = document.all.FramerControl1.GetRevCount(); alert(vCount); var vOpt = 0; var vDate; for(var i=1; i<= vCount; i++){ vOpt = document.all.FramerControl1.GetRevInfo(i,2); if("1" == vOpt){ vOpt = "插入"; }else if("2" == vOpt){ vOpt = "删除"; }else{ vOpt = "未知操作"; } vDate = new String(document.all.FramerControl1.GetRevInfo(i,1)); vDate = parseFloat(vDate); alert(vDate); dateObj = new Date(vDate); alert(dateObj.getYear() + "年" + dateObj.getMonth() + 1 + "月" + dateObj.getDate() +"日" + dateObj.getHours() +"时" + dateObj.getMinutes() +"分" + dateObj.getSeconds() +"秒" ); alert("用户:"+document.all.FramerControl1.GetRevInfo(i,0) + "\r\n操作:" + vOpt + "\r\n内容:" + document.all.FramerControl1.GetRevInfo(i,3)); } /* 0x43.设置基本信息: HRESULT SetValue([in] BSTR strValue, [in] BSTR strName, [out,retval] long* pbool); 1.设置文件只读密码 SetValue("password","::DOCPROP:PassWord"); 2.设置文件修改密码 SetValue("password","::DOCPROP:WritePW"); 返回值: 0 正确 -1:不支持此命令,请确定您的第二个参数没有传错 -127:异常 */ //设置文件只读密码 document.all.FramerControl1.SetValue("password","::DOCPROP:PassWord"); //设置文件修改密码 document.all.FramerControl1.SetValue("password","::DOCPROP:WritePW"); /* 0x44.设置文档变量,这个很少能用到 HRESULT SetDocVariable([in] BSTR strVarName, [in] BSTR strValue,[in] long lOpt, [out,retval] long* pbool); strVarName: 变量名 strVlaue:变量值 lOpt: 操作类型, 按位 第一位为1: 表示update域关联的 第二位为1: 表示如果没有这个变量则添加 第三位为1: 未来支持 return: 0:OK -127:异常 */ /* 0x45: 分页保存 HRESULT SetPageAs([in] BSTR strLocalFile, [in] long lPageNum, [in] long lType,[out,retval] long* pbool); strLocalFile:本地路径 lPageNum:页数 */
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值