2009-06-01 48 views
0

質問parrayを含むCOM [OUT] VARIANTの*解決:私はIDLのような方法を使用してCOMサーバを有する:ヘッダファイルでC#.NETでBSTR者のSAFEARRAYとして

[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は絵を完了するために、ここに追加され(CComVariant * pList) { HRESULT hr = S_OK; BOOL bRet = FALSE; HRESULT hres = S_OK; C位

public void ExtractScanners(ref ListBox listBox1) 
    { 
     String[] oNames = {"LS1/LiteUe", "Sagem"}; 

//   object oResult = new IntPtr(Int32); 
//   Object oGeneric;// = new object(); 
//   System.Array oResult; 
//   IntPtr i = (IntPtr)8;// 27; 
//   Object oResult = Marshal.GetObjectForNativeVariant(i); 
//   Object oResult;// = null; 
//   String[] oResult; 
//   IntPtr oResult; 
     try 
     { 
      iRet = myCom.ExtractAvailableScanners(oNames, out oResult); 

      listBox1.Items.Add("GetAvailableDevices ok"); 
     } 
     catch (COMException comEx) 
     { 
      ReportCOMError(comEx, ref listBox1); 
     } 
     catch (ArgumentException argEx) 
     { 
      ReportArgError(argEx, ref listBox1); 
     } 
    } 

点におけるCSファイル内

// 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; 

}

'はアウトoresultを戻し' オブジェクトのいずれも動作しないことです。

アドバイスは大歓迎です。

+0

私はしようとしています:pScanners-> vt = VT_SAFEARRAY | VT_BSTR; – arul

答えて

3

C++の実装が間違っているようです。 retValはどこにも設定されておらず、間違った値をscanPresentにコピーしています。呼び出しコードには、newを使用して割り当てられていることを知る方法がなく、C#であるため、たとえ実行しても呼び出しコードが解放されません。通常は、VariantInitを使用してVARIANTを割り当てます(CComVariantはこれを囲むラッパーです)。次に、フィールドをresultパラメーターに直接コピーします。さらに、私は戻り値のための安全な配列を作成する方法を見ることができません。

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; 
} 
+0

詳細はクラスCInternalsにあります。あなたが見ることができるように、私はこのサイトではまったく新しいものであり、質問の詳細をどのように展開するかはわかりません。 retValのInfoは問題に影響しません。 あなたの他のコメントは有効です。この特定の例では、C#の "out oResult"はどのような方法でも初期化されておらず、新しいものを使用してヒープにparmを置いています。 oResultオブジェクトの型を知っていたら、それをVARIANT構造体として使用し、scanPresent-> vt = VT_SAFEARRAYを設定し、通常通りBSTRをロードするなどの通常の操作を行う必要があります。 ? –

+0

私は新しいあなたの治療は少し不明だと思います。 VariantInit()は何も割り当てません。単に既存のストレージを初期化します。このシナリオでは、pScannerはローカルなので、Softbeeは自由に選択することができます(私はそうしません)が、通常のように返却前に削除する必要があります。ヒープ割り当てされたVariant(VARIANT ** out引数を持っているかのように)を本当に返す必要があった場合は、CoTaskMemAlloc()でスペースを割り当ててからVariantInitを呼び出してください。あなたが質問を編集したい場合は –

+0

、「編集」ボタンをクリックしてください - それは質問が終わるところの底部付近にあると回答がpScannersは、呼び出し側の結果で必要とされる情報を運ぶことを、あなたが見ることができる追加CInternalsを持つ –

0

[1800 INFORMATION]の優れた投稿を参照してください。

2つの詳細を明確にしましょう。彼が言うとき:

// why set this here? 
    scanners.vt = VT_SAFEARRAY; 

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; 
+0

を開始。問題は、オブジェクトの型がCOMに渡されるときにオブジェクトの型をどうすべきか、ポインタの転送が合法でない場合にscanPresent(その型がVARIANT *である場合)自体に答えを代入する必要があります。 これに私と一緒に滞在してくれてありがとう。 –

関連する問題