从_variant_t提取字符串数组:OpenDSS C++总线名称获取失败
问题解决:从OpenDSS COM接口的_variant_t中提取总线名称字符串数组
问题分析
你的核心问题有两个:
- 电路拓扑定义错误,导致总线列表为空
- 从
_variant_t提取字符串数组的逻辑错误,错误地将SAFEARRAY中的元素当作_variant_t类型处理,而实际是BSTR数组
修复步骤
1. 修正电路拓扑的命令错误
原代码中变压器的绕组定义重复使用了wdg=1,导致第二个绕组未正确创建,总线200不会被添加到电路中。修改变压器的命令:
DSSText->Command = "New Transformer.t1 phases=3 windings=2 xhl=5"; DSSText->Command = "~ wdg=1 bus=100 conn=delta kv=115 kva=5000"; DSSText->Command = "~ wdg=2 bus=200 conn=delta kv=4.16 kva=5000"; // 将wdg=1改为wdg=2
2. 重写字符串数组提取函数
OpenDSS的GetAllBusNames()返回的是BSTR类型的一维SAFEARRAY,而非_variant_t数组。原代码错误地尝试读取_variant_t元素,导致无法正确提取字符串。修改后的提取函数如下:
std::vector<std::wstring> GetArrayOfStrings(const _variant_t& varData) { std::vector<std::wstring> result; try { // 验证输入类型是否为BSTR数组 if ((V_VT(&varData) & (VT_ARRAY | VT_BSTR)) != (VT_ARRAY | VT_BSTR)) { throw _com_error(E_INVALIDARG, L"输入不是有效的BSTR数组"); } SAFEARRAY* psa = V_ARRAY(&varData); BSTR* pData = nullptr; // 直接锁定SAFEARRAY获取数据指针,高效且避免索引问题 HRESULT hr = SafeArrayAccessData(psa, reinterpret_cast<void**>(&pData)); if (FAILED(hr)) { throw _com_error(hr); } long lLBound, lUBound; SafeArrayGetLBound(psa, 1, &lLBound); SafeArrayGetUBound(psa, 1, &lUBound); long elementCount = lUBound - lLBound + 1; // 遍历数组,将BSTR转换为wstring for (long i = 0; i < elementCount; ++i) { if (pData[i] != nullptr) { result.emplace_back(pData[i]); } } // 解锁SAFEARRAY SafeArrayUnaccessData(psa); } catch (const _com_error& e) { std::cerr << "提取字符串数组出错: " << e.ErrorMessage() << std::endl; } return result; }
关键改进点
- 直接读取SAFEARRAY中的BSTR元素,跳过不必要的
_variant_t中转 - 使用
SafeArrayAccessData/SafeArrayUnaccessData直接操作数组指针,比循环调用SafeArrayGetElement更高效 - 添加类型校验,确保输入是预期的BSTR数组
测试验证
修改后运行代码,GetAllBusNames()应该返回包含100、200、300的总线名称列表,提取后的向量会正确输出这些名称。
内容的提问来源于stack exchange,提问作者armanib
相关产品推荐
相关产品推荐

