我的以前的测试报告程序需要在倒完测试数据报告后,在文件摘要中加上一些类似版权说明的文字等等. 因此需要对文件摘要信息进行编辑. 我的记忆中以前好像只有office文档才可以又摘要信息, 现在看来基本上所有文件(windows2000以上的平台)都可以有摘要信息..

在网络上搜寻一番发现一些有用的网址 1.如何编辑文件的摘要 http://groups.google.com/group/microsoft.public.dotnet.framework/msg/99a5dd5c80c084b5?hl=zh-CN&lr=&ie=UTF-8&oe=UTF-8&rnum=4 2.微软知识库关于ole32.dll 中函数的说明 http://msdn2.microsoft.com/en-us/library/aa380328.aspx 3.新手对COM的认识及疑惑 http://www.cn-doc.com/_soft_visual_c_tech_doc/2005_08_18_23/20050818230216780.htm[原处]http://dev.csdn.net/user/putongren

下面是对本问题的总结:

刚开始,我以为是shell32里面的方法可以完成,因此引用了Microsoft Shell Controls And Automation, (shell32.dll),但经过分析后没有找到相关的方法. shell32是COM可以托管引用. 引用shell32可以查出文件的摘要信息,但无法编辑保存,下面是关于这个问题的答案. 如何用C#获得文件信息以及扩展信息

多次网上查询后,我发现这篇在微软讨论组的文章(居然用google搜出来,没有用msdn搜出),实际已经解决我的问题 setting file comment attribute programmatically

主要思路定义相关结构体(以接口方式定义)及输入参数的枚举值 引入ole32.dll 定义静态方法对应函数 通过静态方法返回接口, 此接口实际上就是一个指针(可以调用它的函数) 调用接口函数

开始我以为ole32.dll是一个COM,一直想引用,结果发现它只是一个函数库, 必须对它进行dllimport.具体代码可以看后面. 另外,我还发现以前微软的virsual studio 6 里面的Depends工具,依然在virsual studio 2005中提供了,目录在?:/Program Files/Microsoft Visual Studio 8/Common7/Tools 用这个工具可以查看一个函数库有哪些公开方法.

补充点知识,先

对于使用COM或者函数库的总结,来之(http://dev.csdn.net/user/putongren), 引用一部分

1. 想办法知道 com 组件的 clsid (一个编号,16字节长,全球唯一);如果不知道 clsid,则要知道名字(progid),如 excel.application。

2. 开始与 ole32.dll 打交道吧 ! 如果进程尚未装载它,那就 loadlibrary,然后再 getprocaddress ...

3. 不管三七二十一,先运行调用 coinitializeex,ole32.dll 内的一个函数,以便 ole32.dll 内部为线程记录相应的数据,并允许你调用 ole32.dll 内的其他函数。

4. 如果已知道 clsid,则此步跳过。否则调用 clsidfromprogid 根据名字计算出 clsid。

这个 ole32.dll 内的函数实际上是在注册表中进行查找,位置在: /hkey_classes_root/名字(progid),其下有一个 /clsid,里面就是clsid,其实自己去注册表查找也可以。 excel.application 对应的 clsid = {00024500-0000-0000-c000-000000000046}。

5. 调用 ole32.dll 内的 cogetclassobject 建立一个 clsid 的 object。也可以调用 cocreateinstance / cocreateinstanceex。

这个 object 可以想象成操作系统在内存中加载了一个动态链接库,或独立启动了一个进程,它不返回 object 的句柄,所以不要想通过一个句柄进行进一步访问——像 getwindow(hwnd, ...),也趁早放弃通过 getprocaddress 取得函数入口位置进行进一步访问的想法。到底怎么访问呢,往下看...

6. 调用 cogetclassobject 建立一个 clsid 的 object 的同时,根据一个接口编号参数 iid_i... (全世界统一固定编号)返回一个接口指针,一个接口可以想象成一个函数的集合。

根据 clsid 产生的 object 可能有若干个不同的函数集合,每一个函数集合都有一个接口编号与其对应,iunknown 这个编号对应的接口是每个 object 都有的。每个函数集的前三个函数都一样:queryinterface、addref、release。把其他接口编号作为参数调用 queryinterface 就可以找到其对应的函数集。

7. 关于 clsid 和 接口 iid

clsid 是一个 16 字节长的全球唯一编号,ole32.dll 根据它在注册表中寻找对应的dll文件(也可以是exe文件)。参考程序与进程的概念,clsid 的实例化是加载一个 dll,或运行一个 exe 进程。dll 或 exe 被 ole32.dll 加载后,在 ole32.dll 的地址空间为其建立若干函数入口地址表(当然根据 dll 或 exe 的自身定义),并为每一个函数入口表建立一个保存其开始地址的指针(这个指针是地址中的一个长字)。

iid -- 接口,也是一个 16 字节长的全球唯一编号,ole32.dll 根据它在 clsid 的实例的所有 函数入口地址表的 指针 中找到一个对应的,返回来。所以接口的实例就是那个返回来的指针。

c 程序员可以把接口认为是一个结构,其成员是若干函数;c++ 程序员可以把接口认为是一个类 class。

至于通过 iid 找到的 函数入口表 中的各函数如何调用,去看那个 dll 或 exe 的开发接口文档吧。在调用一个具体的函数时,当然可以把参数压入堆栈,然后 call 那个函数,不过这好像是汇编中的低级做法,比较麻烦,在 vc 中定义一个类指针来保存接口返回来的指针,然后访问类成员,用起来比较方便——参数压入堆栈的问题编译器替你解决了。

8. com

所以 com,概括起来说,就是用两级编号,通过 ole32.dll 调用某个 dll 或 exe 提供的函数的方式。

当然在这基础上还有 automation 等,定义了更多标准的接口编号及访问方式,完成更复杂的功能。

调用方法SetProperty

 /*pls visit this article
* * http://msdn2.microsoft.com/en-us/library/aa380328.aspx
* To open an existing file, use the StgOpenStorageEx function instead.
notice:
Applications written for Windows 2000, Windows Server 2003 and Windows XP must use StgCreateStorageEx rather than StgCreateDocfile to take advantage of the enhanced Windows 2000 and Windows XP Structured Storage features.
* */ using System;
using System.Collections.Generic;
using System.Text;
using StructuredStorageWrapper; namespace WindowsApplication8
{
class FileSummary
{
public static void SetProperty(string filename,string msg , SummaryPropId summaryType)
{
// first you need to either create or open a file and its
// property set stream
//申明接口(指针)
IPropertySetStorage propSetStorage = null;
//com 组件的 clsid 参见IPropertySetStorage定义
Guid IID_PropertySetStorage = new
Guid("0000013A-0000-0000-C000-000000000046"); //Applications written for Windows 2000, Windows Server 2003 and Windows XP must use StgCreateStorageEx rather than StgCreateDocfile to take advantage of the enhanced Windows 2000 and Windows XP Structured Storage features
uint hresult = ole32.StgOpenStorageEx(
filename,
(int)(STGM.SHARE_EXCLUSIVE | STGM.READWRITE),
(int)STGFMT.FILE,
,
(IntPtr),
(IntPtr),
ref IID_PropertySetStorage,
ref propSetStorage); //返回指针 // next you need to create or open the Summary Information property set
Guid fmtid_SummaryProperties = new
Guid("F29F85E0-4FF9-1068-AB91-08002B27B3D9");
IPropertyStorage propStorage = null; hresult = propSetStorage.Create(
ref fmtid_SummaryProperties,
(IntPtr),
(int)PROPSETFLAG.DEFAULT,
(int)(STGM.CREATE | STGM.READWRITE |
STGM.SHARE_EXCLUSIVE),
ref propStorage); // next, you assemble a property descriptor for the property you
// want to write to, in our case the Comment property
PropSpec propertySpecification = new PropSpec();
propertySpecification.ulKind = ;
propertySpecification.Name_Or_ID = new
IntPtr((int)summaryType); //now, set the value you want in a property variant
PropVariant propertyValue = new PropVariant();
propertyValue.FromObject(msg); // Simply pass the property spec and its new value to the WriteMultiple
// method and you're almost done
propStorage.WriteMultiple(, ref propertySpecification, ref
propertyValue, ); // the only thing left to do is commit your changes. Now you're done!
hresult = propStorage.Commit((int)STGC.DEFAULT); //下面的很关键,如何关闭一个非托管的指针,如果不关闭,则本程序不关闭,文件被锁定!
System.Runtime.InteropServices.Marshal.ReleaseComObject(propSetStorage);
propSetStorage = null;
GC.Collect();
}
}
} 把ole32一些方法进行COM封装
using System;
using System.Text;
using System.Runtime.InteropServices; namespace StructuredStorageWrapper
{
public enum SummaryPropId : int
{
Title = 0x00000002,
Subject = 0x00000003,
Author = 0x00000004,
Keywords = 0x00000005,
Comments = 0x00000006,
Template = 0x00000007,
LastSavedBy = 0x00000008,
RevisionNumber = 0x00000009,
TotalEditingTime = 0x0000000A,
LastPrinted = 0x0000000B,
CreateDateTime = 0x0000000C,
LastSaveDateTime = 0x0000000D,
NumPages = 0x0000000E,
NumWords = 0x0000000F,
NumChars = 0x00000010,
Thumbnail = 0x00000011,
AppName = 0x00000012,
Security = 0x00000013
} public enum STGC : int
{
DEFAULT = ,
OVERWRITE = ,
ONLYIFCURRENT = ,
DANGEROUSLYCOMMITMERELYTODISKCACHE = ,
CONSOLIDATE =
} public enum PROPSETFLAG : int
{
DEFAULT = ,
NONSIMPLE = ,
ANSI = ,
UNBUFFERED = ,
CASE_SENSITIVE =
} public enum STGM : int
{
READ = 0x00000000,
WRITE = 0x00000001,
READWRITE = 0x00000002,
SHARE_DENY_NONE = 0x00000040,
SHARE_DENY_READ = 0x00000030,
SHARE_DENY_WRITE = 0x00000020,
SHARE_EXCLUSIVE = 0x00000010,
PRIORITY = 0x00040000,
CREATE = 0x00001000,
CONVERT = 0x00020000,
FAILIFTHERE = 0x00000000,
DIRECT = 0x00000000,
TRANSACTED = 0x00010000,
NOSCRATCH = 0x00100000,
NOSNAPSHOT = 0x00200000,
SIMPLE = 0x08000000,
DIRECT_SWMR = 0x00400000,
DELETEONRELEASE = 0x04000000
} public enum STGFMT : int
{
STORAGE = ,
FILE = ,
ANY = ,
DOCFILE =
} [StructLayout(LayoutKind.Explicit, Size = , CharSet = CharSet.Unicode)]
public struct PropSpec
{
[FieldOffset()]
public int ulKind;
[FieldOffset()]
public IntPtr Name_Or_ID;
} [StructLayout(LayoutKind.Explicit, Size = )]
public struct PropVariant
{
[FieldOffset()]
public short variantType;
[FieldOffset()]
public IntPtr pointerValue;
[FieldOffset()]
public byte byteValue;
[FieldOffset()]
public long longValue; public void FromObject(object obj)
{
if (obj.GetType() == typeof(string))
{
this.variantType = (short)VarEnum.VT_LPWSTR;
this.pointerValue = Marshal.StringToHGlobalUni((string)obj);
}
}
} [ComVisible(true), ComImport(),
Guid("0000013A-0000-0000-C000-000000000046"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IPropertySetStorage
{
uint Create(
[In, MarshalAs(UnmanagedType.Struct)] ref System.Guid rfmtid,
[In] IntPtr pclsid,
[In] int grfFlags,
[In] int grfMode,
ref IPropertyStorage propertyStorage); int Open(
[In, MarshalAs(UnmanagedType.Struct)] ref System.Guid rfmtid,
[In] int grfMode,
[Out] IPropertyStorage propertyStorage);
} [ComVisible(true), ComImport(),
Guid("00000138-0000-0000-C000-000000000046"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IPropertyStorage
{
int ReadMultiple(
uint numProperties,
PropSpec[] propertySpecifications,
PropVariant[] propertyValues); int WriteMultiple(
uint numProperties,
[MarshalAs(UnmanagedType.Struct)] ref PropSpec
propertySpecification,
ref PropVariant propertyValues,
int propIDNameFirst); uint Commit(
int commitFlags);
} public enum HResults : uint
{
S_OK = ,
STG_E_FILEALREADYEXISTS = 0x80030050
} public class ole32
{
[StructLayout(LayoutKind.Explicit, Size = ,
CharSet = CharSet.Unicode)]
public struct STGOptions
{
[FieldOffset()]
ushort usVersion;
[FieldOffset()]
ushort reserved;
[FieldOffset()]
uint uiSectorSize;
[FieldOffset(), MarshalAs(UnmanagedType.LPWStr)]
string
pwcsTemplateFile;
} [DllImport("ole32.dll", CharSet = CharSet.Unicode)]
public static extern uint StgCreateStorageEx(
[MarshalAs(UnmanagedType.LPWStr)] string name,
int accessMode, int storageFileFormat, int fileBuffering,
IntPtr options, IntPtr reserved, ref System.Guid riid,
[MarshalAs(UnmanagedType.Interface)] ref IPropertySetStorage
propertySetStorage); [DllImport("ole32.dll", CharSet = CharSet.Unicode)]
public static extern uint StgOpenStorageEx(
[MarshalAs(UnmanagedType.LPWStr)] string name,
int accessMode, int storageFileFormat, int fileBuffering,
IntPtr options, IntPtr reserved, ref System.Guid riid,
[MarshalAs(UnmanagedType.Interface)] ref IPropertySetStorage
propertySetStorage);
} }

C# 如何编辑文件的摘要信息的更多相关文章

  1. vim编辑文件警告Swap file already exists ,如何删除vim编辑产生的.swp文件?查看隐藏文件命令

    vim编辑文件警告Swap file already exists,如何删除vim编辑产生的.swp文件?查看隐藏文件命令 Linux(centos7)下多个用户同时编辑一个文件,或编辑时非正常关闭, ...

  2. [python爬虫] Selenium定向爬取PubMed生物医学摘要信息

    本文主要是自己的在线代码笔记.在生物医学本体Ontology构建过程中,我使用Selenium定向爬取生物医学PubMed数据库的内容.        PubMed是一个免费的搜寻引擎,提供生物医学方 ...

  3. vi编辑文件保存后,提示“Can't open file for writing Press ENTER or type command to continue”

    在linux上使用vi命令修改或者编辑一个文件内容的时候,最后发现使用<Esc+:+wq!>无法保存退出,却出现,如下提示: E212: Can't open file for writi ...

  4. 如何通过 terminal 查看一个文件的 meta信息

    如何通过 terminal 查看一个文件的 meta 信息 Linux shell stat 查看文件 meta 信息 stat stat指令:文件/文件系统的详细信息显示: 使用格式:stat 文件 ...

  5. 如何直接在ftp里编辑文件

    首先要连接ftp,如何链接ftp,这个我已经分享过,如果还有不懂的,可以查看下经验分享,打开ftp,并连接你要修改的站点!   下载安装代码编辑器,比如EditPlus.sublime text等,随 ...

  6. python 编辑文件时路径问题解决方法:文件或者目录不存在、文件编辑后无法保存等(以编辑xml文件为例)

    1.获取工程所在根路径:根路径=os.path.dirname(os.path.abspath('__file__')) 2.将获取的根路径和相对路径组合:组合路径=os.path.join(根路径, ...

  7. vs切换当前编辑文件时自动定位目录树

    在编辑区,切换当前编辑文件时(单击.cpp或.h文件选项卡),"解决方案资源管理器"目录树会自动定位当前编辑的文件,并以灰色标识,当一个解决方案中的工程数目数目很多,每个工程下面又 ...

  8. 哇 真的是一个好插件!!!Sublime Text编辑文件后快速刷新浏览器

    http://9iphp.com/web/html/sublime-text-refresh-browser.html这篇博文咯 来源:[Tips]Sublime Text编辑文件后快速刷新浏览器 - ...

  9. VS设置程序集属性(文件的详细信息)

    适用范围 本文方法适用于:C#创建的控制台程序,WinForm,WPF等VS创建的.Net工程信息设置. 方法步骤 1.在 项目 上点击鼠标右键选择 属性 ,进入这个页面,点击 程序集信息(重点关注 ...

随机推荐

  1. Windows下Cygwin中使用NCView

    1. 使用cygwin的setup.exe安装 NetCDF, HDF5, Curl, libXaw, libICE, udunits, libexpat 和 libpng: 在选择库界面搜索:&qu ...

  2. 对web日志文件实现按照人员、行为分类

    日志格式: method,time,name in,2015-05-06 17:37:46,Jenny1out,2015-05-06 17:37:46,Judith1in,2015-05-06 17: ...

  3. 【LeetCode】70 - Climbing Stairs

    You are climbing a stair case. It takes n steps to reach to the top. Each time you can either climb ...

  4. bzoj 1806 [Ioi2007]Miners 矿工配餐(DP)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1806 [题意] 给定一个权在1..3内的序列,在保持相对位置不变的情况下拆分成两个序列 ...

  5. Hadoop2学习记录(1) |HA完全分布式集群搭建

    准备 系统:CentOS 6或者RedHat 6(这里用的是64位操作) 软件:JDK 1.7.hadoop-2.3.0.native64位包(可以再csdn上下载,这里不提供了) 部署规划 192. ...

  6. 实现带有getMin的栈

    题目 实现一个特殊的栈,在实现栈的基础上,再实现返回栈中最小的元素的操作. 要求 pop.push.getMin的时间复杂度是O(1) 可以使用现成的栈类型 思路 如下图所示,在栈结构中,每次pop的 ...

  7. 生成500个0-1000的随机数&&数组查找—小练习

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  8. Delphi IOS环境安装

    RAD Delphi XE/10 Seattle 安装IOS.OSX环境安装,IOS模拟器,MAC X 真机可以调试 http://community.embarcadero.com/blogs/en ...

  9. 动软代码生成与 EntityFramework 实体生成模板

    有用到EntityFrameWork的同学们,可以用用. 实体工程中添加EF6的dll 还有 ValidBox4Mvc.ValidRules.dll应用到项目中,此dll下载地址:http://www ...

  10. 【126】win8的一些问题

    1.win8 窗口背景色修改 在Windows默认主题下,打开注册表编辑器(win键+R,即运行,输入regedit),依次双击打开HKEY_CURRENT_USER\Control Panel\Co ...