我编写了一个带有接口的c#包装器类,用于使用GemBox.Document进行文档转换。在课程中,我有以下方法来保存文档:
public string SourcePath{get;set;}
public string DestinationType{get;set;}
public string DestinationPath{get;set;}
private static DocumentModel document;
public void ConvertDocument()
{
try
{
string filename = Path.GetFileNameWithoutExtension(SourcePath);
ComponentInfo.SetLicense(GemboxLicence);
string savePath = String.Format("{0}\\{1}.{2}", DestinationPath, filename, DestinationType);
document = DocumentModel.Load(SourcePath);
document.Save(savePath);
}
catch (Exception e)
{
throw (new Exception("An error occured while saving the document: " + e.Message ));
}
}
当我从另一个c#程序调用它时,该类工作正常。
我注册了班级' dll to com并使用regasm创建了一个tlb文件,如下所示:
regasm MBD.GemBox.Document.dll /tlb
我想通过com从delphi访问dll,所以我将tlb文件导入Delphi 2009.然后我创建了一个调用c#dll的包装器delphi库:
procedure ConvertDocument(sourcePath : string ; destinationType : string ; destinationPath : string);
var
doc : TDocumentConvertor;
begin
try
OleInitialize(nil);
doc := TDocumentConvertor.Create(nil);
doc.Connect;
doc.SourcePath := sourcePath ;
doc.DestinationType := destinationType;
doc.DestinationPath := destinationPath;
doc.ConvertDocument;
doc.Disconnect;
doc.Free;
CoUninitialize;
except
on E:Exception do
begin
Writeln(E.Classname, ': ', E.Message);
end;
end;
end;
然而,我得到了
"未处理的类型' System.StackOverflowException'发生在GemBox.Document.dll"
当我尝试通过delphi调用该方法时。有谁知道为什么会这样?
答案 0 :(得分:1)
我通过将Gembox文档转换部分移动到c#代码中的单独线程来解决了这个问题:
string filename = Path.GetFileNameWithoutExtension(SourcePath);
ComponentInfo.SetLicense(GemboxLicence);
string savePath = String.Format("{0}\\{1}.{2}", DestinationPath, filename, DestinationType);
document = DocumentModel.Load(SourcePath);
document.Save(savePath);
解决方案,我创建了一个单独的类,它产生一个单独的线程来处理文档转换:
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Threading;
using GemBox.Document;
using System.Runtime.InteropServices;
namespace GB.Document
{
public class GbWorkItem
{
public string Source;
public string Destination;
}
internal class GbThreadData
{
public bool Running;
public Queue WorkQueue = Queue.Synchronized(new Queue());
}
public class GemBox : IDisposable
{
private static GbThreadData _data = new GbThreadData();
private bool _disposed = false;
public GemBox()
{
Thread thread = new Thread(ThreadExec);
thread.Start(_data);
}
internal static void ThreadExec(object o)
{
_data = o as GbThreadData;
_data.Running = true;
while (_data.Running)
{
if (_data.WorkQueue.Count == 0) Thread.Sleep(250);
else
{
lock (_data.WorkQueue.SyncRoot)
{
try
{
GbWorkItem work = _data.WorkQueue.Dequeue() as GbWorkItem;
DocumentModel document = DocumentModel.Load(work.Source);
document.Save(work.Destination);
}
catch (InvalidOperationException) { }
}
}
}
}
public void QueueDocument(GbWorkItem item)
{
lock (_data)
{
_data.WorkQueue.Enqueue(item);
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (_disposed)
return;
if (disposing)
{
_data.Running = false;
}
_disposed = true;
}
}
}
然后我对初始类进行以下更改:
public string SourcePath{get;set;}
public string DestinationType{get;set;}
public string DestinationPath{get;set;}
private static DocumentModel document;
private GemBox _gemBox;
public DocumentConvertor()
{
Initialise();
}
public void ConvertDocument()
{
try
{
// string filename = Path.GetFileNameWithoutExtension(SourcePath);
//ComponentInfo.SetLicense(GemboxLicence);
string savePath = String.Format("{0}\\{1}.{2}", DestinationPath, filename, DestinationType);
// document = DocumentModel.Load(SourcePath);
// document.Save(savePath);
_gemBox.QueueDocument(new GbWorkItem { Source = SourcePath, Destination = savePath });
}
catch (Exception e)
{
throw (new Exception("An error occured while saving the document: " + e.Message ));
}
finally
{
Destroy();
}
}
private void Initialise()
{
_gemBox = new GemBox();
}
private void Destroy()
{
_gemBox.Dispose();
}
Delphi代码保持不变。