解析包含parray作为BSTR'的安全数组的COM[out]变量*;c#net中的s
问题:我有一个方法为IDL的COM服务器:解析包含parray作为BSTR'的安全数组的COM[out]变量*;c#net中的s,c#,c++,com,atl,C#,C++,Com,Atl,问题:我有一个方法为IDL的COM服务器: [id(2), helpstring("method ExtractAvailableScanners")] HRESULT ExtractAvailableScanners( [in] VARIANT scanFilter, [out] VARIANT* scanPresent, [out,retval] LONG* retVal); 在头文件中,它变成: STDMETHO
[id(2), helpstring("method ExtractAvailableScanners")]
HRESULT ExtractAvailableScanners(
[in] VARIANT scanFilter, [out] VARIANT* scanPresent,
[out,retval] LONG* retVal);
在头文件中,它变成:
STDMETHOD(ExtractAvailableScanners)
(VARIANT scanFilter, VARIANT* scanPresent, LONG* retVal);
实施:
STDMETHODIMP CSBIdentify::ExtractAvailableScanners
(VARIANT scanFilter, VARIANT* scanPresent, LONG* retVal)
{
// TODO: Return the available scanners given a scanner lookup filter
CInternals ints;
//Find all the device strings
CComVariant Result;
ints.CollectDeviceStrings(&Result);
//Extraction of the wanted ones
CComVariant* pScanners = new CComVariant;
pScanners->vt = VT_SAFEARRAY;
ints.FilterScanners(scanFilter, &Result, pScanners);
// Cleanup
// ========
scanPresent = pScanners;
return S_OK;
}
//类CInternals被添加到这里来完成图片
int CInternals::CollectDeviceString(CComVariant*pList)
{
HRESULT hr=S_正常;
布尔-布雷特=假;
HRESULT hres=S_正常
// Step 3: ---------------------------------------------------
// Obtain the initial locater to WMI -------------------------
IWbemLocator *pLoc = NULL;
hres = CoCreateInstance(
CLSID_WbemLocator,
0,
CLSCTX_INPROC_SERVER,
IID_IWbemLocator, (LPVOID *) &pLoc);
if (FAILED(hres))
{
CError::PresetError( "Failed to create IWbemLocator object in SBIdentify::GetDevices", E_FAIL );
return hres;
}
// Step 4: -----------------------------------------------------
// Connect to WMI through the IWbemLocator::ConnectServer method
IWbemServices *pSvc = NULL;
// Connect to the root\cimv2 namespace with
// the current user and obtain pointer pSvc
// to make IWbemServices calls.
hres = pLoc->ConnectServer(
_bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace
NULL, // User name. NULL = current user
NULL, // User password. NULL = current
0, // Locale. NULL indicates current
NULL, // Security flags.
0, // Authority (e.g. Kerberos)
0, // Context object
&pSvc // pointer to IWbemServices proxy
);
if (FAILED(hres))
{
CError::PresetError( "Could not connect to IWbemServices proxy in SBIdentify::GetDevices", E_FAIL );
pLoc->Release();
return hres;
}
// CTraceLog::TraceMsg( "Connected to ROOT\\CIMV2 WMI namespace" );
// Step 5: --------------------------------------------------
// Set security levels on the proxy -------------------------
hres = CoSetProxyBlanket(
pSvc, // Indicates the proxy to set
RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx
RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx
NULL, // Server principal name
RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx
RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
NULL, // client identity
EOAC_NONE // proxy capabilities
);
if (FAILED(hres))
{
CError::PresetError( "Could not set proxy blanket in SBIdentify::GetDevices", E_FAIL );
pSvc->Release();
pLoc->Release();
return hres;
}
// Step 6: --------------------------------------------------
// Use the IWbemServices pointer to make requests of WMI ----
// Use WBEM_FLAG_BIDIRECTIONAL flag to ensure the enumerator is resettable
IEnumWbemClassObject* pEnumerator = NULL;
hres = pSvc->ExecQuery(
bstr_t("WQL"),
bstr_t("SELECT * FROM Win32_PnPEntity"),
WBEM_FLAG_BIDIRECTIONAL | WBEM_FLAG_RETURN_IMMEDIATELY,
NULL,
&pEnumerator);
if (FAILED(hres))
{
CError::PresetError( "Query on Win32_PnPEntity failed in SBIdentify::GetDevices", E_FAIL );
pSvc->Release();
pLoc->Release();
return hres;
}
// Step 7: -------------------------------------------------
// Get the data from the query in step 6 -------------------
int n = 0;
CComPtr< IWbemClassObject > pclsObj;
ULONG uReturn = 0;
//Read the list to determine its length
while (pEnumerator)
{
pclsObj = NULL;
hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
if(0 == uReturn)
break;
n++;
}
pEnumerator->Reset();
//The full read mechanism
VARIANT Result;
Result.vt = VT_SAFEARRAY | VT_BSTR;
VARIANT* pResult = &Result;
SAFEARRAYBOUND rgsabound[1];
rgsabound[0].lLbound = 0;
rgsabound[0].cElements = n;
LONG ix[] = {0};
int i = -1;
pResult->parray = ::SafeArrayCreate(VT_BSTR, 1, rgsabound);
if(pResult->parray == NULL)
{
CError::PresetError( "SafeArrayCreate() failed in SBIdentify::GetDevices", E_OUTOFMEMORY );
pSvc->Release();
pLoc->Release();
return E_OUTOFMEMORY;
}
while (pEnumerator)
{
pclsObj = NULL;
pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
if(0 == uReturn)
break;
i++;
VARIANT vtProp;
// Get the value of the Name property
hr = pclsObj->Get(L"Name", 0, &vtProp, 0, 0);
if(hr != S_OK)
{
CError::PresetError( "<Get> failed in SBIdentify::GetDevices", hr );
pSvc->Release();
pLoc->Release();
pEnumerator->Release();
return hr;
}
wcout << " Name : " << vtProp.bstrVal << endl;
ix[0] = i;
hr = SafeArrayPutElement(pResult->parray, ix, vtProp.bstrVal);
if(hr != S_OK)
{
CError::PresetError( "SafeArrayPutElement() failed in SBIdentify::GetDevices", hr );
pSvc->Release();
pLoc->Release();
pEnumerator->Release();
return hr;
}
VariantClear(&vtProp);
}
pList->Attach(pResult);
return hr;
关键是“out-oResult”对象都不起作用
任何建议都是受欢迎的。
< P>看起来你的C++实现是错误的。你不设置任何代码> ReValue/COD>任何地方,也就是你复制错误的值到<代码> ScStime。调用代码不知道你使用了<代码>新< /COD>分配它,并且因为它是C,所以它甚至没有办法释放它。首先,您可以使用VariantInit
(该CComVariant
是一个包装器)分配变量,然后直接将字段复制到结果参数中。此外,我看不出您是如何为返回创建安全数组的
STDMETHODIMP CSBIdentify::ExtractAvailableScanners
(VARIANT scanFilter, VARIANT* scanPresent, LONG* retVal)
{
// TODO: Return the available scanners given a scanner lookup filter
CInternals ints;
//Find all the device strings
CComVariant Result;
ints.CollectDeviceStrings(&Result);
//Extraction of the wanted ones
CComVariant Scanners;
// why set this here?
pScanners.vt = VT_SAFEARRAY;
// what does this call do? It should be allocating the new safe array
// using the normal methods for creating safe arrays
ints.FilterScanners(scanFilter, &Result, &Scanners);
// Cleanup
// ========
Scanners.Detach(scanPresent);
// what to put in here?
*retVal = something;
return S_OK;
}
看起来你的C++实现是错误的。你不设置任何代码> ReValue/Cube >,也就是你把错误的值复制到<代码> ScScVest[/COD]。调用代码不知道你使用了<代码>新的< /CODE >分配它,并且因为它是C*,它甚至无法释放它。通常,你分配变量。使用
VariantInit
(CComVariant
是一个包装器),然后直接将字段复制到结果参数中。此外,我看不出您是如何为返回创建安全数组的
STDMETHODIMP CSBIdentify::ExtractAvailableScanners
(VARIANT scanFilter, VARIANT* scanPresent, LONG* retVal)
{
// TODO: Return the available scanners given a scanner lookup filter
CInternals ints;
//Find all the device strings
CComVariant Result;
ints.CollectDeviceStrings(&Result);
//Extraction of the wanted ones
CComVariant Scanners;
// why set this here?
pScanners.vt = VT_SAFEARRAY;
// what does this call do? It should be allocating the new safe array
// using the normal methods for creating safe arrays
ints.FilterScanners(scanFilter, &Result, &Scanners);
// Cleanup
// ========
Scanners.Detach(scanPresent);
// what to put in here?
*retVal = something;
return S_OK;
}
请查看[1800信息]的优秀帖子以供参考 让我澄清几个细节。当他说:
// why set this here?
scanners.vt = VT_SAFEARRAY;
他这样问是因为这还不足以创建一个安全数组。在不同的函数中初始化类的各个部分是非常糟糕的做法。FilterScanners()无论如何都需要在内部完成这项工作,还有更多:
// Local dimension bounds
// 'x' is the number of dimensions, as in this VB6:
// Dim Abc(a,b,c) 'has three dimensions
SAFEARRAYBOUND sab[x];
// Set the dimensions, as in:
// Dim Abc(0 TO TOTAL_BOUND_0, 0 TO TOTAL_BOUND_1, ...) 'VB6
sab[0].lLbound = 0;
sab[0].cElements = TOTAL_BOUND_0;
sab[1].lLbound = 0;
sab[1].cElements = TOTAL_BOUND_1;
// ... etc.
// This API creates the actual SafeArray in the COM Heap.
// Replace proper VT_VARIANT below with your type
SAFEARRAY * pSA = SafeArrayCreate(VT_VARIANT, x, sab); // x same as before
// Fill-in the elements of the array as required.
// Remember to use SafeArrayAccessData() and SafeArrayUnaccessData()
// Stuff the pointer to the SAFEARRAY in the VARIANT output argument:
// "OR" whatever the type of the array is. Think in VB6 terms!
// Dim scanners(...) As Variant ' VT_SAFEARRAY | VT_VARIANT
// Dim scanners(...) As String ' VT_SAFEARRAY | VB_BSTR
// etc.
VariantInit(pScanners); // Always recommended to clear the VARIANT before using it
pScanners->vt = VT_SAFEARRAY | VT_VARIANT; // set the type
pScanners->pparray = pSA;
请查看[1800信息]的优秀帖子以供参考 让我澄清几个细节。当他说:
// why set this here?
scanners.vt = VT_SAFEARRAY;
他这样问是因为这还不足以创建一个安全数组。在不同的函数中初始化类的各个部分是非常糟糕的做法。FilterScanners()无论如何都需要在内部完成这项工作,还有更多:
// Local dimension bounds
// 'x' is the number of dimensions, as in this VB6:
// Dim Abc(a,b,c) 'has three dimensions
SAFEARRAYBOUND sab[x];
// Set the dimensions, as in:
// Dim Abc(0 TO TOTAL_BOUND_0, 0 TO TOTAL_BOUND_1, ...) 'VB6
sab[0].lLbound = 0;
sab[0].cElements = TOTAL_BOUND_0;
sab[1].lLbound = 0;
sab[1].cElements = TOTAL_BOUND_1;
// ... etc.
// This API creates the actual SafeArray in the COM Heap.
// Replace proper VT_VARIANT below with your type
SAFEARRAY * pSA = SafeArrayCreate(VT_VARIANT, x, sab); // x same as before
// Fill-in the elements of the array as required.
// Remember to use SafeArrayAccessData() and SafeArrayUnaccessData()
// Stuff the pointer to the SAFEARRAY in the VARIANT output argument:
// "OR" whatever the type of the array is. Think in VB6 terms!
// Dim scanners(...) As Variant ' VT_SAFEARRAY | VT_VARIANT
// Dim scanners(...) As String ' VT_SAFEARRAY | VB_BSTR
// etc.
VariantInit(pScanners); // Always recommended to clear the VARIANT before using it
pScanners->vt = VT_SAFEARRAY | VT_VARIANT; // set the type
pScanners->pparray = pSA;
我会尝试:pScanners->vt=vt|u SAFEARRAY | vt|BSTR;我会尝试:pScanners->vt=vt|u SAFEARRAY | vt|BSTR;详细信息在类内。正如你看到的,我在这个网站上是全新的,我不知道如何扩展问题的详细信息。retVal中的信息对问题没有影响。你的其他评论是有效的。C#“out oResult”在这个特定的例子中没有以任何方式初始化,并且-是的-我已经使用new将parm放在堆上。如果我知道对象或结果的类型,我应该能够将其用作变量结构,并执行通常的操作,例如设置scanPresent->vt=vt_SAFEARRAY,然后按照通常的方式使用BSTR加载它。但是这是如何实现的呢?我认为您对new的处理有点不清楚。Variatinition()不分配任何内容;它只是初始化现有存储。在这种情况下,PSCanner是本地的,因此Softbee可以自由使用new,如果他选择(我不会),但他必须像往常一样在返回之前删除它。如果他真的需要返回堆分配的变体(如有VARIANT**out参数),则必须使用CoTaskMemAlloc()分配空间,然后使用它调用VariantInit。如果要编辑问题,请单击“编辑”按钮-靠近问题结束和答案开始的底部。详细信息在课堂内容中。正如你所看到的,我在这个网站上是全新的,我不知道如何扩展问题的详细信息。retVal中的信息对问题没有影响。你的其他评论是有效的。C#“out oResult”在这个特定的例子中没有以任何方式初始化,并且-是的-我已经使用new将parm放在堆上。如果我知道对象或结果的类型,我应该能够将其用作变量结构,并执行通常的操作,例如设置scanPresent->vt=vt_SAFEARRAY,然后按照通常的方式使用BSTR加载它。但是这是如何实现的呢?我认为您对new的处理有点不清楚。Variatinition()不分配任何内容;它只是初始化现有存储。在这种情况下,PSCanner是本地的,因此Softbee可以自由使用new,如果他选择(我不会),但他必须像往常一样在返回之前删除它。如果他真的需要返回堆分配的变体(如有VARIANT**out参数),则必须使用CoTaskMemAlloc()分配空间,然后使用它调用VariantInit。如果要编辑问题,请单击“编辑”按钮-靠近问题结束和答案开始的底部。通过添加内部,您可以看到PSCanner携带调用方结果中所需的信息。问题仍然是,在传递给COM时对象的类型应该是什么,应该是scanPresent(如果其类型是变体*)然后,如果指针的传输不合法,它本身就会被填充答案。感谢您一直支持我。添加了CInternals后,您可以看到PSCanner携带调用方结果中所需的信息。问题仍然是,传递给COM的对象的类型应该是什么(如果它的类型是VARIANT*)本身,那么如果指针的传输是不合法的,那么就用答案填充它。我感谢您在这方面与我在一起。