Я пытаюсь встроить PDF-файл в документ Word, используя метод OLE, описанный здесь:
http://blogs.msdn.com/brian_jones/archive/2009/07/21/embedding-any-file-type-like-pdf-in-an-open-xml-file.aspx
Я пытался реализовать код C ++, предоставляемый в C #, чтобы весь проект находился в одном месте и был почти там, за исключением одного контрольно-пропускного пункта. Когда я пытаюсь передать сгенерированные двоичные данные объекта OLE в документ Word, я получаю IOException.
IOException: процесс не может получить доступ к файлу 'C: \ Wherever \ Whever.pdf.bin', поскольку он используется другим процессом.
Существует дескриптор файла, открывающий файл .bin («oleOutputFileName» ниже), и я не знаю, как от него избавиться. Я не очень разбираюсь в COM - я его здесь разрабатываю - и я не знаю, где находится дескриптор файла или как его выпустить.
Вот как выглядит мой код на C #. Чего мне не хватает?
public void ExportOleFile(string oleOutputFileName, string emfOutputFileName)
{
OLE32.IStorage storage;
var result = OLE32.StgCreateStorageEx(
oleOutputFileName,
OLE32.STGM.STGM_READWRITE | OLE32.STGM.STGM_SHARE_EXCLUSIVE | OLE32.STGM.STGM_CREATE | OLE32.STGM.STGM_TRANSACTED,
OLE32.STGFMT.STGFMT_DOCFILE,
0,
IntPtr.Zero,
IntPtr.Zero,
ref OLE32.IID_IStorage,
out storage
);
var CLSID_NULL = Guid.Empty;
OLE32.IOleObject pOle;
result = OLE32.OleCreateFromFile(
ref CLSID_NULL,
_inputFileName,
ref OLE32.IID_IOleObject,
OLE32.OLERENDER.OLERENDER_NONE,
IntPtr.Zero,
null,
storage,
out pOle
);
result = OLE32.OleRun(pOle);
IntPtr unknownFromOle = Marshal.GetIUnknownForObject(pOle);
IntPtr unknownForDataObj;
Marshal.QueryInterface(unknownFromOle, ref OLE32.IID_IDataObject, out unknownForDataObj);
var pdo = Marshal.GetObjectForIUnknown(unknownForDataObj) as IDataObject;
var fetc = new FORMATETC();
fetc.cfFormat = (short)OLE32.CLIPFORMAT.CF_ENHMETAFILE;
fetc.dwAspect = DVASPECT.DVASPECT_CONTENT;
fetc.lindex = -1;
fetc.ptd = IntPtr.Zero;
fetc.tymed = TYMED.TYMED_ENHMF;
var stgm = new STGMEDIUM();
stgm.unionmember = IntPtr.Zero;
stgm.tymed = TYMED.TYMED_ENHMF;
pdo.GetData(ref fetc, out stgm);
var hemf = GDI32.CopyEnhMetaFile(stgm.unionmember, emfOutputFileName);
storage.Commit((int)OLE32.STGC.STGC_DEFAULT);
pOle.Close(0);
GDI32.DeleteEnhMetaFile(stgm.unionmember);
GDI32.DeleteEnhMetaFile(hemf);
}
ОБНОВЛЕНИЕ 1: уточнил, какой файл я имел в виду под «.bin файл».
ОБНОВЛЕНИЕ 2: я не использую блоки "использование", потому что вещи, от которых я хочу избавиться, не одноразовые. (И, если честно, я не уверен, что мне нужно выпустить, чтобы удалить дескриптор файла, COM для меня - иностранный язык.)