使用C ++为Crystal报表编写UFL我可以选择实现UF5SaveState和UF5RestoreState函数,COM接口无法实现这些函数,导致存在这些函数需要解决的问题。
我必须实现的UF5SaveState函数具有以下签名: -
HGLOBAL __stdcall UF5SaveState (UFTInt32u jobId)
我的问题是我不确定如何形成它预期返回的HGLOBAL。
文档只说这个: -
UF5SaveState此过程必须是 只有你的UFL有一个 具有副作用的功能 [确实如此] 。它是 由Crystal Reports调用获取 来自UFL的状态给定 点。 Crystal Reports作业号 被传递给函数。该 函数返回UFL状态二进制 在第二个参数中流,和 返回中的状态大小 第三个参数。
我最困惑,尤其是因为它谈到了在第二个甚至第三个参数中返回的东西。我不是一个真正的Windows用户,所以对我来说HGLOBAL看起来很像一个无效指针,所以我希望它对windows人更有意义。我试过传回一个GlobalAlloc的结果,尝试从它创建一个流(CreateStreamOnHGlobal)并传回来,只尝试了一个char *,所有结果都是一个未处理的异常: -
0x7c92a978处的未处理异常 crw32.exe中的(ntdll.dll):0xC0000005: 访问违规写入位置 0x00030fa4。
我毫不怀疑这是因为它期待别的东西,但是......
一大堆代码,只是为了帮助你们全力以赴: -
HGLOBAL __stdcall UF5SaveState (UFTInt32u jobId)
{
ULONG bytesWritten;
HGLOBAL result = GlobalAlloc(GHND, 2048);
LPSTREAM stream = LPSTREAM();
CreateStreamOnHGlobal(result, false, &stream);
stream->Write("ABC", 3, &bytesWritten);
stream->Release();
return result;
}
所以,想象一下我想保存一个只有三个字符的状态“ABC”零终结器可选,我该怎么做?
答案 0 :(得分:0)
我在一百万年前写过一个自定义CR函数。 uffuncs.h头文件包含以下定义:
HGLOBAL CR_EXPORT UF5SaveState (UFTInt32u jobId);
UFError CR_EXPORT UF5RestoreState (UFTInt32u jobId,
HGLOBAL savedState);
你发现的文档引人注目,HGLOBAL还不足以在报告中保留。它是一个指针,当在另一个会话中再次加载报表时,它无法正常恢复。那些神秘的额外论点将允许这一点。
此头文件具有1997时间戳。我只能建议您尝试查找uffuncs.h头文件的更新版本。无论它在哪里,我都不记得从哪里得到它。网站文档和链接完全不合适。相当典型的CR损失,我决定在经历了痛苦之后再也不会使用CR。
答案 1 :(得分:0)
在设置Windows剪贴板时,仍然使用常用的HGLOBAL内存句柄。 Crystal Reports可能期望与您使用的句柄完全相同。
以下是创建带有“ABC”的HGLOBAL的相关代码:
const char *szInput = "ABC";
size_t cchBufLen = strlen(szInput) + 1; // +1 for the null-terminator.
size_t cbBufSize = cchBufLen * sizeof(char); // Len==Size, but wouldn't if you were using wchar_t instead of char.
bool bSuccess = false;
HGLOBAL hGlobalClipMem = ::GlobalAlloc(GHND, cbBufSize);
if (hGlobalClipMem != NULL)
{
// Since the "GHND" flags include GMEM_MOVEABLE we must use GlobalLock to
// get a pointer to the buffer, and later GlobalFree to get back to normal.
char *pGlobalBuffer = reinterpret_cast<char *>( ::GlobalLock(hGlobalClipMem) );
if (pGlobalBuffer != NULL)
{
strcpy(pGlobalBuffer, szInput);
bSuccess = true; // Set false if anything fails here, so you clean-up.
::GlobalUnlock(hGlobalClipMem); // You unlock the hGlobal, not the pointer that came out of GlobalLock.
}
// Error-handling path.
if (!bSuccess)
{
::GlobalFree(hGlobalClipMem);
hGlobalClipMem = NULL;
}
}
return hGlobalClipMem; // Returns NULL on failure.