写一个模块调用Word打开一份文档,使用接口将Word的相关功能屏蔽(如保存、复制等)。为了使该Word文档无法被复制,需要让Word支持从内存打开一份文档或在Word打开文档后破坏该文件的内容(免得人家复制)。
所以有两个方向的思路:
1、使用某种方式模拟磁盘上的文件(类似于共享文件中的重定向功能)
2、使用某种特殊方法,在Word打开本地文件后删除文件或文件中的内容
补充:不希望使用Word提供的接口进行复制粘贴操作来实现,因为效率实在太低,现在需要优化,如果有其它思路也请大侠们指教,能够达到不自己写个软件便不能获取该文档的内容就行了。
对于第一种,我尝试过使用命名管道,但是在某些应用程序中能成,有的不成。具体原因我了解了下,因为我在管道这边写数据需要时间,而目标进程向来会使用Seek定位到hFile的末尾用以读取文件的大小,如果此时管道数据尚未完全写入,目标应用程序便会读取文件错误。
对于第二种,没什么思路。
12 个解决方案
#1
病毒??
#2
写完命名管道并关闭后再交给WORD试试。
#3
两种需求都可以通过API Hook来实现。
#4
启动空的word实例后不要执行open操作,而是让它从IStream中读取数据,这个IStream是你的程序提供出来的。你要从Application或Document对象中查询IPersistStreamInit接口。
禁用功能也能实现,直接访问word的commandBar对象(也是COM对象),禁用需要的CommandControl(比如打开、复制等等)就行了。
禁用功能也能实现,直接访问word的commandBar对象(也是COM对象),禁用需要的CommandControl(比如打开、复制等等)就行了。
#5
Hook的想法有过
1、Hook CreateFileW,如果特定字符串(我Open方法中传一个特定的字符串),就返回一个唯一标识(如Atom),然后Hook ReadFile和WriteFile,如果句柄是那个唯一标识就直接去FileMapping中读写数据。个人感觉比较费劲,不知道是否有更简洁的方式
2、Hook CreateFileW,留下文件句柄,在Open操作完成后给线程发一个关闭文件的消息,在Hook中强制关闭文件句柄(不知道后面会不会出问题,如果文档以只读方式打开的话应该还好),然后删除文件
个人还是倾向于IPersistStreamInit这东西,只可惜水平不够,需要查大部分E文资料及调试,不过感觉这个做法会正常一些,稳定一些。但是能不能实现很难说,因为我感觉IStream中的数据与doc文档并不是同一种东西,它似乎是OLE的一种特定数据,任何格式的东西都可以以这种数据进行Save和Load,正如我们嵌入Word中的图片是OLE对象的数据而并不是图片的文件数据,这意味着在打开Word前需要将Word的文件转换为OLE对象的数据。有没有大侠试过的?
1、Hook CreateFileW,如果特定字符串(我Open方法中传一个特定的字符串),就返回一个唯一标识(如Atom),然后Hook ReadFile和WriteFile,如果句柄是那个唯一标识就直接去FileMapping中读写数据。个人感觉比较费劲,不知道是否有更简洁的方式
2、Hook CreateFileW,留下文件句柄,在Open操作完成后给线程发一个关闭文件的消息,在Hook中强制关闭文件句柄(不知道后面会不会出问题,如果文档以只读方式打开的话应该还好),然后删除文件
个人还是倾向于IPersistStreamInit这东西,只可惜水平不够,需要查大部分E文资料及调试,不过感觉这个做法会正常一些,稳定一些。但是能不能实现很难说,因为我感觉IStream中的数据与doc文档并不是同一种东西,它似乎是OLE的一种特定数据,任何格式的东西都可以以这种数据进行Save和Load,正如我们嵌入Word中的图片是OLE对象的数据而并不是图片的文件数据,这意味着在打开Word前需要将Word的文件转换为OLE对象的数据。有没有大侠试过的?
#6
楼主有点误解。IStream本身只是为了访问二进制“流”数据而定义的一种通用访问方法,它面向的是一个连续的内存块(或者模拟的“连续”内存块),不关心内存中的数据格式,所以无论哪种数据文件都能简单地以二进制模式读入内存句柄,然后直接从内存句柄创建一个IStream指针。具体的文件格式或者数据格式由使用者来判断处理。在你的问题里面,word加载doc文档时内部也是使用的IStream(当然由于doc是复合文档,也会使用IStorage,这是另一个话题),现在的做法其实让word打开你提供的IStream。
当然IStream的好处并不止于此,由于它不是内存指针,所以不用担心跨进程地址空间调用时内存指针无效的问题,另一方面IStream作为一个标准的COM接口,能被系统正确列集数据,无需担心数据是在进程内、进程外还是其它机器上。
理解了COM的本质和一些常用的COM接口,能实现一些平时难以想象的事情。
当然IStream的好处并不止于此,由于它不是内存指针,所以不用担心跨进程地址空间调用时内存指针无效的问题,另一方面IStream作为一个标准的COM接口,能被系统正确列集数据,无需担心数据是在进程内、进程外还是其它机器上。
理解了COM的本质和一些常用的COM接口,能实现一些平时难以想象的事情。
#7
谢谢了,那我去找找相关文档然后试试,有问题可能还需要请教。
#8
谢谢了,那我去找找相关文档然后试试,有问题可能还需要请教。
#9
经过测试,Word的Document对象实现了IPersistFile、IPersistStorage,没有实现IPersistStream及IPersistStreamInit。
使用IPersistFile的Load方法从文件打开doc没问题,但是使用IPersistStorage的Load方法从FStorage却没反应
创建FStorage的代码如下
var
DataHandle: HGlobal;
Buffer: Pointer;
begin
DataHandle := GlobalAlloc(GMEM_MOVEABLE, Stream.Size);
if DataHandle = 0 then OutOfMemoryError;
try
Buffer := GlobalLock(DataHandle);
try
Stream.Read(Buffer^, Stream.Size);
finally
GlobalUnlock(DataHandle);
end;
OleCheck(CreateILockBytesOnHGlobal(DataHandle, True, FLockBytes));
DataHandle := 0;
OleCheck(StgOpenStorageOnILockBytes(FLockBytes, nil, STGM_READWRITE or
STGM_SHARE_EXCLUSIVE, nil, 0, FStorage));
except
if DataHandle <> 0 then GlobalFree(DataHandle);
end;
end;
FStorage是有数据的,使用OleLoad(FStorage, IOleObject, nil, obj)可以得到IOleObject的对象
但是我需要的不是从FStorage创建一个IOleObject,而是从已有的Document将FStorage装载进去
使用IPersistFile的Load方法从文件打开doc没问题,但是使用IPersistStorage的Load方法从FStorage却没反应
创建FStorage的代码如下
var
DataHandle: HGlobal;
Buffer: Pointer;
begin
DataHandle := GlobalAlloc(GMEM_MOVEABLE, Stream.Size);
if DataHandle = 0 then OutOfMemoryError;
try
Buffer := GlobalLock(DataHandle);
try
Stream.Read(Buffer^, Stream.Size);
finally
GlobalUnlock(DataHandle);
end;
OleCheck(CreateILockBytesOnHGlobal(DataHandle, True, FLockBytes));
DataHandle := 0;
OleCheck(StgOpenStorageOnILockBytes(FLockBytes, nil, STGM_READWRITE or
STGM_SHARE_EXCLUSIVE, nil, 0, FStorage));
except
if DataHandle <> 0 then GlobalFree(DataHandle);
end;
end;
FStorage是有数据的,使用OleLoad(FStorage, IOleObject, nil, obj)可以得到IOleObject的对象
但是我需要的不是从FStorage创建一个IOleObject,而是从已有的Document将FStorage装载进去
#10
既然有IPersistStorage,偶有个想法,楼主试试看:
先用StgOpenStorageEx从文件系统里载入.doc文件得到一个IStorage;
再用StgOpenStorageOnILockBytes生成内存IStorage;
最后用doc文件IStorage的CopyTo方法把它复制到内存IStorage中。
关闭doc的IStorage,这时应该可以删除doc文件了。
最最后:用IPersistStorage的Load载入这个内存IStorage。
ps,偶没试过,只是个想法:-P,楼主可以一试。
先用StgOpenStorageEx从文件系统里载入.doc文件得到一个IStorage;
再用StgOpenStorageOnILockBytes生成内存IStorage;
最后用doc文件IStorage的CopyTo方法把它复制到内存IStorage中。
关闭doc的IStorage,这时应该可以删除doc文件了。
最最后:用IPersistStorage的Load载入这个内存IStorage。
ps,偶没试过,只是个想法:-P,楼主可以一试。
#11
IPersistStorage去Load的时候只能是进行初始化,但是我添加一个Documnet之后该文档已经初始化好了,所以Load返回错误为“已进行初始化”。。。
为啥设计成这样,真没理解。
用IPersistFile去Load一个文件的时候,Word会自动添加一个Document,然后打开该文档,但IPersistStorage去Load就是报错。
为啥设计成这样,真没理解。
用IPersistFile去Load一个文件的时候,Word会自动添加一个Document,然后打开该文档,但IPersistStorage去Load就是报错。
#12
用文件过滤驱动应该可以解决。参考文件粉碎机的实现,就是删除已经打开的文件。在rin3下估计没办法
#1
病毒??
#2
写完命名管道并关闭后再交给WORD试试。
#3
两种需求都可以通过API Hook来实现。
#4
启动空的word实例后不要执行open操作,而是让它从IStream中读取数据,这个IStream是你的程序提供出来的。你要从Application或Document对象中查询IPersistStreamInit接口。
禁用功能也能实现,直接访问word的commandBar对象(也是COM对象),禁用需要的CommandControl(比如打开、复制等等)就行了。
禁用功能也能实现,直接访问word的commandBar对象(也是COM对象),禁用需要的CommandControl(比如打开、复制等等)就行了。
#5
Hook的想法有过
1、Hook CreateFileW,如果特定字符串(我Open方法中传一个特定的字符串),就返回一个唯一标识(如Atom),然后Hook ReadFile和WriteFile,如果句柄是那个唯一标识就直接去FileMapping中读写数据。个人感觉比较费劲,不知道是否有更简洁的方式
2、Hook CreateFileW,留下文件句柄,在Open操作完成后给线程发一个关闭文件的消息,在Hook中强制关闭文件句柄(不知道后面会不会出问题,如果文档以只读方式打开的话应该还好),然后删除文件
个人还是倾向于IPersistStreamInit这东西,只可惜水平不够,需要查大部分E文资料及调试,不过感觉这个做法会正常一些,稳定一些。但是能不能实现很难说,因为我感觉IStream中的数据与doc文档并不是同一种东西,它似乎是OLE的一种特定数据,任何格式的东西都可以以这种数据进行Save和Load,正如我们嵌入Word中的图片是OLE对象的数据而并不是图片的文件数据,这意味着在打开Word前需要将Word的文件转换为OLE对象的数据。有没有大侠试过的?
1、Hook CreateFileW,如果特定字符串(我Open方法中传一个特定的字符串),就返回一个唯一标识(如Atom),然后Hook ReadFile和WriteFile,如果句柄是那个唯一标识就直接去FileMapping中读写数据。个人感觉比较费劲,不知道是否有更简洁的方式
2、Hook CreateFileW,留下文件句柄,在Open操作完成后给线程发一个关闭文件的消息,在Hook中强制关闭文件句柄(不知道后面会不会出问题,如果文档以只读方式打开的话应该还好),然后删除文件
个人还是倾向于IPersistStreamInit这东西,只可惜水平不够,需要查大部分E文资料及调试,不过感觉这个做法会正常一些,稳定一些。但是能不能实现很难说,因为我感觉IStream中的数据与doc文档并不是同一种东西,它似乎是OLE的一种特定数据,任何格式的东西都可以以这种数据进行Save和Load,正如我们嵌入Word中的图片是OLE对象的数据而并不是图片的文件数据,这意味着在打开Word前需要将Word的文件转换为OLE对象的数据。有没有大侠试过的?
#6
楼主有点误解。IStream本身只是为了访问二进制“流”数据而定义的一种通用访问方法,它面向的是一个连续的内存块(或者模拟的“连续”内存块),不关心内存中的数据格式,所以无论哪种数据文件都能简单地以二进制模式读入内存句柄,然后直接从内存句柄创建一个IStream指针。具体的文件格式或者数据格式由使用者来判断处理。在你的问题里面,word加载doc文档时内部也是使用的IStream(当然由于doc是复合文档,也会使用IStorage,这是另一个话题),现在的做法其实让word打开你提供的IStream。
当然IStream的好处并不止于此,由于它不是内存指针,所以不用担心跨进程地址空间调用时内存指针无效的问题,另一方面IStream作为一个标准的COM接口,能被系统正确列集数据,无需担心数据是在进程内、进程外还是其它机器上。
理解了COM的本质和一些常用的COM接口,能实现一些平时难以想象的事情。
当然IStream的好处并不止于此,由于它不是内存指针,所以不用担心跨进程地址空间调用时内存指针无效的问题,另一方面IStream作为一个标准的COM接口,能被系统正确列集数据,无需担心数据是在进程内、进程外还是其它机器上。
理解了COM的本质和一些常用的COM接口,能实现一些平时难以想象的事情。
#7
谢谢了,那我去找找相关文档然后试试,有问题可能还需要请教。
#8
谢谢了,那我去找找相关文档然后试试,有问题可能还需要请教。
#9
经过测试,Word的Document对象实现了IPersistFile、IPersistStorage,没有实现IPersistStream及IPersistStreamInit。
使用IPersistFile的Load方法从文件打开doc没问题,但是使用IPersistStorage的Load方法从FStorage却没反应
创建FStorage的代码如下
var
DataHandle: HGlobal;
Buffer: Pointer;
begin
DataHandle := GlobalAlloc(GMEM_MOVEABLE, Stream.Size);
if DataHandle = 0 then OutOfMemoryError;
try
Buffer := GlobalLock(DataHandle);
try
Stream.Read(Buffer^, Stream.Size);
finally
GlobalUnlock(DataHandle);
end;
OleCheck(CreateILockBytesOnHGlobal(DataHandle, True, FLockBytes));
DataHandle := 0;
OleCheck(StgOpenStorageOnILockBytes(FLockBytes, nil, STGM_READWRITE or
STGM_SHARE_EXCLUSIVE, nil, 0, FStorage));
except
if DataHandle <> 0 then GlobalFree(DataHandle);
end;
end;
FStorage是有数据的,使用OleLoad(FStorage, IOleObject, nil, obj)可以得到IOleObject的对象
但是我需要的不是从FStorage创建一个IOleObject,而是从已有的Document将FStorage装载进去
使用IPersistFile的Load方法从文件打开doc没问题,但是使用IPersistStorage的Load方法从FStorage却没反应
创建FStorage的代码如下
var
DataHandle: HGlobal;
Buffer: Pointer;
begin
DataHandle := GlobalAlloc(GMEM_MOVEABLE, Stream.Size);
if DataHandle = 0 then OutOfMemoryError;
try
Buffer := GlobalLock(DataHandle);
try
Stream.Read(Buffer^, Stream.Size);
finally
GlobalUnlock(DataHandle);
end;
OleCheck(CreateILockBytesOnHGlobal(DataHandle, True, FLockBytes));
DataHandle := 0;
OleCheck(StgOpenStorageOnILockBytes(FLockBytes, nil, STGM_READWRITE or
STGM_SHARE_EXCLUSIVE, nil, 0, FStorage));
except
if DataHandle <> 0 then GlobalFree(DataHandle);
end;
end;
FStorage是有数据的,使用OleLoad(FStorage, IOleObject, nil, obj)可以得到IOleObject的对象
但是我需要的不是从FStorage创建一个IOleObject,而是从已有的Document将FStorage装载进去
#10
既然有IPersistStorage,偶有个想法,楼主试试看:
先用StgOpenStorageEx从文件系统里载入.doc文件得到一个IStorage;
再用StgOpenStorageOnILockBytes生成内存IStorage;
最后用doc文件IStorage的CopyTo方法把它复制到内存IStorage中。
关闭doc的IStorage,这时应该可以删除doc文件了。
最最后:用IPersistStorage的Load载入这个内存IStorage。
ps,偶没试过,只是个想法:-P,楼主可以一试。
先用StgOpenStorageEx从文件系统里载入.doc文件得到一个IStorage;
再用StgOpenStorageOnILockBytes生成内存IStorage;
最后用doc文件IStorage的CopyTo方法把它复制到内存IStorage中。
关闭doc的IStorage,这时应该可以删除doc文件了。
最最后:用IPersistStorage的Load载入这个内存IStorage。
ps,偶没试过,只是个想法:-P,楼主可以一试。
#11
IPersistStorage去Load的时候只能是进行初始化,但是我添加一个Documnet之后该文档已经初始化好了,所以Load返回错误为“已进行初始化”。。。
为啥设计成这样,真没理解。
用IPersistFile去Load一个文件的时候,Word会自动添加一个Document,然后打开该文档,但IPersistStorage去Load就是报错。
为啥设计成这样,真没理解。
用IPersistFile去Load一个文件的时候,Word会自动添加一个Document,然后打开该文档,但IPersistStorage去Load就是报错。
#12
用文件过滤驱动应该可以解决。参考文件粉碎机的实现,就是删除已经打开的文件。在rin3下估计没办法