gpt4 book ai didi

c++ - 读取包含SAFEARRAY的UDT的SAFEARRAY

转载 作者:行者123 更新时间:2023-12-02 10:24:02 25 4
gpt4 key购买 nike

我正在尝试创建和读取SAFEARRAY(MyUDT)*,其中MyUDT包含SAFEARRAY,但是当我尝试读取它时,出现了“访问冲突”异常。

我定义了以下结构和枚举:

typedef [uuid(...)]
enum CollisionDetectorMoveType
{
CollisionDetectorMoveType_Unknown = -1,
CollisionDetectorMoveType_Move = 0,
CollisionDetectorMoveType_Measure
} CollisionDetectorMoveType;

typedef [uuid(...)]
struct CollisionDetectorXYZ
{
double X;
double Y;
double Z;
} CollisionDetectorXYZ;

typedef [uuid(...)]
struct CollisionDetectorMultiPosition
{
SAFEARRAY(CollisionDetectorXYZ) pos;
CollisionDetectorMoveType type;
} CollisionDetectorMultiPosition;


bool createTestCollisionDetectorMultiPositionSafeArray(SAFEARRAY** psa)
{

IRecordInfoPtr recordset_info = nullptr;
HRESULT hr = GetRecordInfoFromGuids(LIBID_CollisionDetectorLib, 1, 0, 0, UUID_CollisionDetectorMultiPosition, &recordset_info);
if (FAILED(hr))
{
return false;
}

SAFEARRAYBOUND safearray_bound;
memset(&safearray_bound, 0, sizeof(safearray_bound));
safearray_bound.cElements = 10;
safearray_bound.lLbound = 0;
*psa = ::SafeArrayCreateEx(VT_RECORD, 1, &safearray_bound, (PVOID)recordset_info);

for (size_t i = 0; i < 10; ++i)
{
CollisionDetectorMultiPosition multiPosition;
multiPosition.type = i % 2 == 0 ? CollisionDetectorMoveType_Move : CollisionDetectorMoveType_Measure;
if (!createTestCollisionDetectorXYZSafeArray(&multiPosition.pos))
{
return false;
}

LONG current_position = i;
::SafeArrayPutElement(*psa, &current_position, &multiPosition);
}

::SafeArrayUnaccessData(*psa);

return true;
}
}

bool createTestCollisionDetectorXYZSafeArray(SAFEARRAY** psa)
{

IRecordInfoPtr recordset_info = nullptr;
HRESULT hr = GetRecordInfoFromGuids(LIBID_CollisionDetectorLib, 1, 0, 0, UUID_CollisionDetectorXYZ, &recordset_info);
if (FAILED(hr))
{
return false;
}

SAFEARRAYBOUND safearray_bound;
memset(&safearray_bound, 0, sizeof(safearray_bound));
safearray_bound.cElements = 10;
safearray_bound.lLbound = 0;
*psa = ::SafeArrayCreateEx(VT_RECORD, 1, &safearray_bound, (PVOID)recordset_info);

for (size_t i = 0; i < 10; ++i)
{
CollisionDetectorXYZ current_point;
current_point.X = i;
current_point.Y = i;
current_point.Z = i;
LONG current_position = i;
::SafeArrayPutElement(*psa, &current_position, &current_point);
}

::SafeArrayUnaccessData(*psa);

return true;
}

然后,我尝试创建并阅读SAFEARRAY:
    SAFEARRAY* psa2 = NULL;
if (!createTestCollisionDetectorMultiPositionSafeArray(&psa2))
{
*retVal = SYSERR;
return S_OK;
}

CollisionDetectorMultiPosition* current_pointer_to_element;
auto access_result = ::SafeArrayAccessData(psa2, (void **)&current_pointer_to_element);
if (FAILED(access_result))
{
return S_OK;
}
LONG upper_bound, lower_bound;
::SafeArrayGetLBound(psa2, 1, &lower_bound);
::SafeArrayGetUBound(psa2, 1, &upper_bound);

std::vector<CollisionDetectorMultiPosition> multiPositionVector;
LONG size = upper_bound - lower_bound + 1;
for (LONG i = 0; i < size; i++)
{
CollisionDetectorMultiPosition this_value;
::SafeArrayGetElement(psa2, &i, (void *)&this_value);

multiPositionVector.push_back(this_value);
}

但是当我调用:: SafeArrayGetElement(psa2,&i,(void *)&this_value);我有异常(exception)。

我做错了什么?

如果我简单地打电话
CollisionDetectorMultiPosition multiPosition;
multiPosition.type = CollisionDetectorMoveType_Move;
if (!createTestCollisionDetectorXYZSafeArray(&multiPosition.pos))
{
*retVal = SYSERR;
return S_OK;
}

我可以毫无问题地阅读multiPosition.pos SAFEARRAY。

谢谢你的帮助。

解决了

我找到了解决方案,我为可能有相同问题的所有用户报告了代码。基本上,诀窍是创建一个SAFEARRAY of VARIANT,然后用CollisionDetectorMultiPosition填充VARIANT结构。
CComVariant variant;
variant.vt = VT_RECORD;
variant.pvRecord = &multiPosition;
variant.pRecInfo = recordset_info;

创建SAFEARRAY
bool createTestCollisionDetectorMultiPositionSafeArray(SAFEARRAY** psa)
{

IRecordInfoPtr recordset_info;
HRESULT hr = GetRecordInfoFromGuids(LIBID_CollisionDetectorLib, 1, 0, 0, UUID_CollisionDetectorMultiPosition, &recordset_info);
if (FAILED(hr))
{
return false;
}

SAFEARRAYBOUND safearray_bound;
memset(&safearray_bound, 0, sizeof(safearray_bound));
safearray_bound.cElements = 10;
safearray_bound.lLbound = 0;

*psa = SafeArrayCreate(VT_VARIANT, 1, &safearray_bound);


for (size_t i = 0; i < 10; ++i)
{
CollisionDetectorMultiPosition multiPosition;
multiPosition.type = i % 2 == 0 ? CollisionDetectorMoveType_Move : CollisionDetectorMoveType_Measure;
if (!createTestCollisionDetectorXYZSafeArray(&multiPosition.pos))
{
return false;
}

CComVariant variant;
variant.vt = VT_RECORD;
variant.pvRecord = &multiPosition;
variant.pRecInfo = recordset_info;


LONG current_position = i;
::SafeArrayPutElement(*psa, &current_position, &variant);

variant.vt = VT_EMPTY;

}

::SafeArrayUnaccessData(*psa);

return true;
}

阅读SAFEARRAY
    SAFEARRAY* psa2 = NULL;
if (!createTestCollisionDetectorMultiPositionSafeArray(&psa2))
{
*retVal = AC3SYSERR;
return S_OK;
}

LONG upper_bound, lower_bound;
::SafeArrayGetLBound(psa2, 1, &lower_bound);
::SafeArrayGetUBound(psa2, 1, &upper_bound);

std::vector<std::pair<CollisionDetectorMoveType, std::vector<CollisionDetectorXYZ>>> multiPositionVector;
LONG size = upper_bound - lower_bound + 1;
for (LONG i = 0; i < size; i++)
{
VARIANT this_value;
VariantInit(&this_value);
VariantClear(&this_value);

::SafeArrayGetElement(psa2, &i, (void *)&this_value);

CollisionDetectorMultiPosition* this_value2 = (CollisionDetectorMultiPosition *)this_value.pvRecord;

CollisionDetectorXYZ* current_pointer_to_element;
auto access_result = ::SafeArrayAccessData(this_value2->pos, (void **)&current_pointer_to_element);
if (FAILED(access_result))
{
return S_OK;
}

LONG upper_bound, lower_bound;
::SafeArrayGetLBound(this_value2->pos, 1, &lower_bound);
::SafeArrayGetUBound(this_value2->pos, 1, &upper_bound);

std::vector<CollisionDetectorXYZ> moves;
LONG size = upper_bound - lower_bound + 1;
for (LONG i = 0; i < size; i++)
{
CollisionDetectorXYZ this_value;
::SafeArrayGetElement(this_value2->pos, &i, (void *)&this_value);

moves.push_back(this_value);
}

multiPositionVector.push_back(std::make_pair(this_value2->type, moves));

::SafeArrayUnaccessData(this_value2->pos);
}

最佳答案

实际上,我遇到了类似的问题,该线程对我有很大帮助,但是MFC ActiveX的一些特定细节使我花了几天的时间才能揭开神秘面纱,我想与社区分享。
我的目标是在MFC / ATL ActiveX中添加一个方法,该方法会将UDT数组返回到启用COM的编程语言。
我的第一个问题是将UDT的UUID暴露给C++代码。由于某种原因,尽管给UDT提供了GUID,但它并未生成,也无法用于C++。我发现必须在IDL中添加 cpp_quote 才能强制执行此操作。

[
uuid(GUID_LIBRARY),
version(VERSION)
...
]
library WebKitXCEF3Lib
{
importlib(STDOLE_TLB);

typedef [public, uuid(<your guid here>)] struct Cookie
{
BSTR Name;
BSTR Domain;
BSTR Path;
BSTR Value;
VARIANT_BOOL HttpOnly;
VARIANT_BOOL Secure;
VARIANT_BOOL Expires;
VARIANT ExpiryDateUTC;

} Cookie;

cpp_quote("struct __declspec(uuid(\"{<your guid here>}\")) Cookie;")
...
}
接下来,返回UDT数组的方法的返回类型必须为 VARIANT :
[id(100)] VARIANT GetCookies(BSTR Domain);
DISPATCH MAP也应该将返回类型也定义为 VT_VARIANT :
BEGIN_DISPATCH_MAP(CMyCtrl, COleControl)
DISP_FUNCTION_ID(CMyCtrl, "GetCookies", dispidGetCookies, GetCookies, VT_VARIANT, VTS_BSTR)
END_DISPATCH_MAP()
最后,C++代码必须使用 SafeArrayCreateEx 创建SAFEARRAY,并提供UDT的 IRecordInfo ,最后将其包装为:
VARIANT CMyCtrl::GetCookies(LPCTSTR Domain)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());

SAFEARRAY* psaCookies = nullptr;

if(AmbientUserMode() && !Unloading || BROWSER_READY)
{
LONG L = Cookies.size();

SAFEARRAYBOUND rgsabound[1];
rgsabound[0].lLbound = 0;
rgsabound[0].cElements = L;

IRecordInfoPtr pRecInfo = nullptr; // DO NOT RELEASE !!!
if(SUCCEEDED(GetRecordInfoFromGuids(LIBID_MyLib, VERSION_MAJOR, VERSION_MINOR, 0, __uuidof(Cookie), &pRecInfo)))
{
psaCookies = ::SafeArrayCreateEx(VT_RECORD, 1, rgsabound, pRecInfo);

if(psaCookies)
{
Cookie* pCookies = NULL;

if(SUCCEEDED(SafeArrayAccessData(psaCookies, reinterpret_cast<PVOID*>(&pCookies))))
{
for(LONG i = 0; i < L; i++)
{
pCookies[i].Name = WSTR_to_BSTR(Cookies[i].Name);
pCookies[i].Domain = WSTR_to_BSTR(Cookies[i].Domain);
pCookies[i].Path = WSTR_to_BSTR(Cookies[i].Path);
pCookies[i].Value = WSTR_to_BSTR(Cookies[i].Value);
pCookies[i].HttpOnly = Cookies[i].HttpOnly;
pCookies[i].Secure = Cookies[i].Secure;
pCookies[i].Expires = Cookies[i].Expires;
VariantCopy(&(pCookies[i].ExpiryDateUTC), &(Cookies[i].ExpiryDateUTC));
}

SafeArrayUnaccessData(psaCookies);
}
}
}
}

VARIANT result;
VariantInit(&result);
if(psaCookies)
{
result.vt = VT_ARRAY | VT_RECORD;
result.parray = psaCookies;
}

return result;
}
注意不要释放IRecordInfo,返回的VARIANT必须为 VT_ARRAY | VT_RECORD
VB6代码如下所示:
Private Sub wxDesigner_OnPageComplete(ByVal URL As String)    
Dim Cookies As Variant
Cookies = wxDesigner.GetCookies("foo.com")
End Sub
在Watches中,VARIANT如下所示:
enter image description here

关于c++ - 读取包含SAFEARRAY的UDT的SAFEARRAY,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54513252/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com