【发布时间】:2018-11-21 06:58:24
【问题描述】:
我已经接管了 C++ 中遗留的 MFC OCX 控件的维护工作。该项目现在在VS2013中。我试图了解 DoPropExchange 方法的功能。此方法似乎正在为控件中的几乎所有数据成员调用 PX_?????(member) ????是类型(Bool,Short,Long ...)我的理解是这些是为了提供属性的持久存储而调用的。但是根据我对 OCX 控件操作的理解,没有持久属性。还有其他理由打电话给PX_????对于 DoPropExchange 中的所有数据成员,除了支持持久属性?我还试图了解这些持久属性的加载/存储位置。用于加载/存储持久属性值的序列化文件在哪里指定?
这是 DoPropExchange 的来源
// CSigPlusCtrl::DoPropExchange - Persistence support
void CSigPlusCtrl::DoPropExchange(CPropExchange* pPX)
{
DWORD Version;
long BaudRate;
short ComPort;
BOOL Rv;
LOG(("DoPropExchange Entry"));
ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
COleControl::DoPropExchange(pPX);
Version = pPX->GetVersion();
if (pPX->IsLoading())
{
LoadDefaultProperties();
LoadIniParameters();
}
if ((Version & 0xFFFF0000) == (DWORD)MAKELONG(0, _wVerMajor))
{
Rv = PX_Short(pPX, _T("ImageFileFormat"), ImageFileFormat, 0);
Rv = PX_Short(pPX, _T("ImageXSize"), ImageXSize, 0);
Rv = PX_Short(pPX, _T("ImageYSize"), ImageYSize, 0);
Rv = PX_Short(pPX, _T("ImagePenWidth"), ImagePenWidth, 1);
. . .
Rv = PX_Short(pPX, _T("ZoomY"), ZoomY, 0);
Rv = PX_Short(pPX, _T("ZoomPower"), ZoomPower, 1);
if (pPX->IsLoading())
{
if (SigBlob != NULL)
{
GlobalFree(SigBlob);
SigBlob = NULL;
}
}
else
{
if (SigBlob == NULL)
{
SigBlobType* SigBlobPtr;
SigBlob = GlobalAlloc(GMEM_MOVEABLE, sizeof(DWORD));
SigBlobPtr = (SigBlobType*)GlobalLock(SigBlob);
SigBlobPtr->Size = 0;
GlobalUnlock(SigBlob);
}
}
if ((Version & 0xFFFF) == Version223)
{
Rv = PX_Blob(pPX, _T("SigBlob"), SigBlob, NULL);
}
if ((Version & 0xFFFF) >= Version224)
{
CString SigStr;
if (!pPX->IsLoading())
{
SigStr = BlobToString();
}
Rv = PX_String(pPX, _T("SigStringStored"), SigStr, _T(""));
if (pPX->IsLoading())
{
BlobFromString(SigStr);
}
}
}
else
{
SigMessageBox("Warning Incompatable Versions of SigPlus Control");
}
LoadTabletParameters();
LOG(("DoPropExchange Exit"));
}
编辑于 2018 年 6 月 21 日添加
在调试器中运行我观察到,当调用 DoPropExchange 时,VS2013 会显示堆栈并显示下面的堆栈帧可能不正确的消息。而上面调用 DoPropExchange 的一帧来自 mfc120d.dll,它没有可用的符号文件 mfc120d.i386.pdb。
这个Microsoft Forum Post 似乎表明符号文件不适用于VS2015,我想知道VS2013 是否也是这种情况。到目前为止,我还没有找到下载 MFC120 符号进行调试的地方。
今天开始赏金寻找可以解释通常如何以及在何处为 OLE 控件序列化属性以及使用哪些方法来指定序列化数据存储位置/媒体的人。这是值得关注的,因为此控件在终端感知程序中的 Citrix ZenDesk 网络环境中运行,如果属性存储在某处,则每个客户端都需要指定该客户端唯一的位置。
【问题讨论】:
-
我不明白这个问题。显然,您正在调用
COleControl::DoPropExchange(pPX),因此您正在序列化基类的持久属性。您还在序列化自定义属性。你为什么认为没有持久属性?我不知道,除了持久化信息之外,您是否正在使用序列化支持。但它也可以用于跨公寓编组控制状态。我并不是说这种情况正在发生,但流不仅仅代表磁盘上的文件。 -
"你为什么假设没有持久属性..." 因为我从用例中知道 OCX 控件的操作,它没有持久的属性。我试图了解上面的代码是否试图将属性存储在某个地方,如果是,那么在哪里。或者它只是用于在启动时加载默认值。这是旧版 OCX,专门使用 INI 文件,不使用注册表。执行 OCX 时,INI 文件不会更改。因此,如果它试图持久化属性,那么这些值的存储位置就是一个谜。
-
不清楚,为什么您认为知道数据存储在哪里会帮助您理解代码。它显然正在存储持久数据(例如
ImageFileFormat)。如果您想了解有关代码的更多信息,请在调试器下运行它,设置断点/跟踪点等。您提出的问题似乎并没有让您更接近您的目标,这显然是理解您的代码。 -
控件所有属性的值要么由 LoadDefaultProperties() 方法中的硬编码值设置,要么在称为 LoadIniProperties 的方法中从 INI 文件中读取。来自容器应用程序的任何修改属性的调用都不会在控制实例或系统重新启动之间持续存在。并且 OCX 控件不会将任何值写回 INI 文件。所以我试图理解为什么最初的开发者创建了一个看起来正在加载/存储属性的 DoPropExchange。
-
我已经在调试器中广泛运行了代码。挑战在于对 DoPropExchange 的调用来自 MFC 框架,目前 VS2013 不允许我进入或跟踪调用者 MFC 代码。因此,此时无法访问调用 DoPropExchange 之前和调用 PX_Short/Long 等之后发生的情况。
标签: c++ mfc persistence ocx