Silverlight 4 应用程序的问题。在此应用程序中,每个客户端会话都会创建一个单独的进程,该进程调用一个 DLL。
与 DLL 的通信是在以下调用堆栈中构建的(对于两个函数:一个工作,另一个 - 不工作)。
DLL 中有 2 个函数(都可以正常工作):
extern "C" BOOL __stdcall DocRunExternPageDividions(const char *docId, int num_form, int PageNum, int *Vcols, int **Vvalues, int *Hcols, int **Hvalues)
{
LOG_START_FUNCTION
BOOL res = 1;
__try {
res = DocRunExternPageDividions1(docId, num_form, PageNum, Vcols, Vvalues, Hcols, Hvalues);
}
__except(ExFilter(GetExceptionInformation()))
{
AfxThrowUserException();
}
LOG_STOP_FUNCTION
return res;
}
extern "C" BOOL __stdcall DocRunExternPageBreakRects(const char *docId, int num_form, int PageNum)
{
LOG_START_FUNCTION
BOOL res = 1;
__try {
res = DocRunExternPageBreakRects1(docId, num_form, PageNum);
}
__except(ExFilter(GetExceptionInformation()))
{
AfxThrowUserException();
}
LOG_STOP_FUNCTION
return res;
}
要调用此函数,服务器有两个委托:
private delegate void DocRunExternPageBreakRectsDelegate(string docId, int DocNum, int PageNum);
private delegate void DocRunExternPageDividionsDelegate(
string docId, int DocNum, int PageNum, out int Vcols, out IntPtr VoutArray, out int Hcols,
out IntPtr HoutArray);
...两个委托实例和相应的功能:
private DocRunExternPageBreakRectsDelegate DocRunExternPageBreakRectsD;
DocRunExternPageBreakRectsD =
Marshal.GetDelegateForFunctionPointer(ptrDocRunExternPageBreakRects,
typeof (DocRunExternPageBreakRectsDelegate)) as
DocRunExternPageBreakRectsDelegate;
private DocRunExternPageDividionsDelegate DocRunExternPageDividionsD;
DocRunExternPageDividionsD =
Marshal.GetDelegateForFunctionPointer(ptrDocRunExternPageDividionsD,
typeof (DocRunExternPageDividionsDelegate)) as
DocRunExternPageDividionsDelegate;
public void DocRunExternPageDividions(string docId, int DocNum, int PageNum, out int[] vert, out int[] horz) {
IntPtr VoutArray, HoutArray;
int vcols, hcols;
DocRunExternPageDividionsD(docId, DocNum, PageNum, out vcols, out VoutArray, out hcols, out HoutArray);
marshal(VoutArray, out vert, vcols);
marshal(HoutArray, out horz, hcols);
}
public void DocRunExternPageBreakRects(string docId, int DocNum, int PageNum) {
DocRunExternPageBreakRectsD(docId, DocNum, PageNum);
}
这些函数中的每一个都在此处调用(服务器代码):
public bool PageBreakRects(string docId, int DocNum, int PageNum, out int[] vert, out int[] horz) {
bool result;
vert = null;
horz = null;
Program.WriteUserMessage("Called PageBreakRects(" + docId + ", " + DocNum + ", " + PageNum + ")");
try {
DocRunExternPageBreakRects(docId, DocNum, PageNum);
DocRunExternPageDividions(docId, 0, PageNum, out vert, out horz);
result = true;
} catch (Exception ex) {}
return result;
}
public bool GetPageDividions(string docID, int Id, int pageNumber, out int[] vert, out int[] horz) {
bool result = false;
vert = null;
horz = null;
try {
DocRunExternPageDividions(docID, Id, pageNumber, out vert, out horz);
result = true;
} catch (Exception) {}
return result;
}
他们每个人 - 在这里被称为:
public DocDividionsResult PageBreakRects(string docID, int DocNum, int pageNumber) {
var result = new DocDividionsResult();
int[] vert;
int[] horz;
result.Data = new List<object> { Program.DllWrapper.PageBreakRects(docID, DocNum, pageNumber, out vert, out horz) };
result.Vert = vert;
result.Horz = horz;
return result;
}
public DocDividionsResult GetPageDividions(string docID, int formId, int pageNumber) {
var result = new DocDividionsResult();
int[] vert;
int[] horz;
result.Data = new List<object>
{Program.DllWrapper.GetPageDividions(docID, formId, pageNumber, out vert, out horz)};
result.Vert = vert;
result.Horz = horz;
return result;
}
然后 - 在 lambda 表达式中:
public bool GetPageDividions(string docID, int formId, int pageNumber, out int[] vert, out int[] horz) {
bool result = false;
int []localVert = null;
int []localHorz = null;
if (_wp != null) {
if (Service<IWPCommunication>.Use(TestService =>
{
TestService.Test(UserId);
},
WPService =>
{
DocDividionsResult br = WPService.GetPageDividions(docID, formId, pageNumber);
if (br != null && br.Data != null && br.Data.Length == 1)
{
result = (bool)br.Data[0];
localVert = br.Vert;
localHorz = br.Horz;
}
}, Id, FS) == 0)
{
...
result = false;
}
}
vert = localVert;
horz = localHorz;
return result;
}
public bool PageBreakRects(string docId, int DocNum, int PageNum) {
bool result = false;
if (_wp != null)
{
if (Service<IWPCommunication>.Use(TestService =>
{
TestService.Test(UserId);
},
WPService =>
{
DocDividionsResult br = WPService.PageBreakRects(docId, DocNum, PageNum);
if (br != null && br.Data != null && br.Data.Length == 1) {
result = (bool)br.Data[0];
}
}, Id, FS) == 0)
{
...
result = false;
}
}
return result;
}
“使用”功能(上面使用过):
public static int Use(UseServiceDelegate<T> codeTest, UseServiceDelegate<T> codeBlock, string SessionId, FileStream fs, bool throwException) {
IClientChannel texy = (IClientChannel)_testFactory.CreateChannel(new EndpointAddress("net.pipe://localhost/X2WPServiceUID" + SessionId));
IClientChannel proxy = (IClientChannel)_channelFactory.CreateChannel(new EndpointAddress("net.pipe://localhost/X2WPServiceUID" + SessionId));
int returnCode = 0;
try {
if (codeTest != null) {
codeTest((T)texy);
texy.Close();
}
returnCode = 1;
if (codeBlock != null) {
codeBlock((T)proxy);
proxy.Close();
}
returnCode = 2;
} catch(Exception e) {
if (returnCode == 1 && throwException)
throw e;
} finally {
if (returnCode == 0 && codeTest != null)
texy.Abort();
else if (returnCode == 1 && codeBlock != null)
proxy.Abort();
}
return returnCode;
}
由于在服务器端引发异常,因此省略了客户端通信。GetPageDividions 函数工作正常,错误 PageBreakRects - 不是:行 DocDividionsResult br = WPService.PageBreakRects(docId, DocNum, PageNum); 抛出以下异常:
"The message with Action 'http://tempuri.org/IWPCommunication/PageBreakRects'
cannot be processed at the receiver, due to a ContractFilter mismatch at the EndpointDispatcher.
This may be because of either a contract mismatch (mismatched Actions between sender and receiver)
or a binding/security mismatch between the sender and the receiver.
Check that sender and receiver have the same contract and the same binding
(including security requirements, e.g. Message, Transport, None)."
更糟糕的是,如果在函数 PageBreakRects 中替换: DocDividionsResult br = WPService.PageBreakRects(docId, DocNum, PageNum); 与 DocDividionsResult br = WPService.GetPageDividions(docID, formId, pageNumber); 那么不会抛出异常。