Article View: borland.public.cppbuilder.nativeapi
Article #5251Re: COM not initializing in custom compenent dropped on form
From: Remy Lebeau (TeamB)
Date: Wed, 21 Sep 2005 08:10
Date: Wed, 21 Sep 2005 08:10
314 lines
11358 bytes
11358 bytes
"Maurice Anderson" <mauriceanderson@hotmail.com> wrote in message
news:4330f48c@newsgroups.borland.com...
> In the first function "InitializeCOM()", I divert to a separate
> TThread object to initialize COM.
That will not work for the code you have shown. You are only initializing
the TThread, not the thread that owns the component. Your WMI operations
are being performed in the context of the thread that owns the component,
not in the context of the TThread. Get rid of the TThread altogether. It
is completely useless in the code you have shown.
> I do this so I can set CoInitFlags=COINIT_MULTITHREADED.
> That way a developer doesn't have to worry about setting the flag
> in his/her project application.
You should not be changing the CoInitFlags. That only applies to the VCL's
own COM initializing, which you are not utilizing in your code. Besides,
your code can specify COINIT_MULTITHREADED when calling CoInitializeEx()
directly. Though, there is no need to do so since the code you have shown
does not need to be multi-threaded in the first place.
> To test the component, I created a basic application with a single form
> (Form1). I then explicitly create the TWmi object using the new keyword
as
> in Wmi2 = new TWmi(this); It is created in the OnShow event of Form1.
> And presto!, it works great; COM gets initialized and I am able to execute
> a WMI Query.
The only way that can work, given the code you have shown, is if the thread
that owns the component was already COM-initialized prior to you creating
the TWmi instance. There are areas of the VCL that will call
CoInitialize/Ex() for their own purposes, but you should not rely on that.
Your TWmi class should be calling CoInitialize/Ex() as well, in the context
of the owning thread, just to make sure that it is really initialized
properly.
> Does anyone know what could be the problem?
Your code is fundamentally flawed to begin with. Try the following code
instead (untested):
--- TWmi.h ---
#ifndef TWmiH
#define TWmiH
//--------------------------------------------------------------------------
-
#include <SysUtils.hpp>
#include <Controls.hpp>
#include <Classes.hpp>
#include <Forms.hpp>
#include "Wbemidl.h"
//--------------------------------------------------------------------------
-
class PACKAGE TWmi : public TDataSource
{
private:
bool bDidCoInit;
IWbemServices *pSvc;
IWbemLocator *pLoc;
IEnumWbemClassObject* pEnumerator;
void __fastcall Initialize(void);
void __fastcall Cleanup(void);
public:
__fastcall TWmi(TComponent* Owner);
__fastcall ~TWmi(void);
void __fastcall ConnectToRoot(const AnsiString &Path);
void __fastcall ExecuteQuery(const AnsiString &Query);
};
#endif
--- TWmi.cpp ---
#include <vcl.h>
#pragma hdrstop
#include "TWmi.h"
# pragma comment(lib, "wbemuuid.lib")
#pragma package(smart_init)
//--------------------------------------------------------------------------
-
// ValidCtrCheck is used to assure that the components created do not
have
// any pure virtual functions.
//
static inline void ValidCtrCheck(TWmi *)
{
new TWmi(NULL);
}
//--------------------------------------------------------------------------
-
__fastcall TWmi::TWmi(TComponent* Owner)
: TDataSource(Owner)
{
Initialize();
try
{
ConnectToRoot("ROOT\\CIMV2");
ExecuteQuery("SELECT * FROM Win32_NetworkAdapter");
}
catch(const Exception &)
{
Cleanup();
throw;
}
}
//--------------------------------------------------------------------------
-
__fastcall TWmi::~TWmi(void)
{
Cleanup();
}
//--------------------------------------------------------------------------
-
void __fastcall TWmi::Cleanup(void)
{
// Cleanup
// ========
if( pSvc )
{
pSvc->Release();
pSvc = NULL;
}
if( pLoc )
{
pLoc->Release();
pLoc = NULL;
}
if( pEnumerator )
{
pEnumerator->Release();
pEnumerator = NULL;
}
if( bDidCoInit )
{
CoUninitialize();
bDidCoInit = false;
}
}
//--------------------------------------------------------------------------
-
void __fastcall TWmi::Initialize()
{
// Step 1: --------------------------------------------------
// Initialize COM. ------------------------------------------
HRESULT hres = CoInitialize(NULL);
if( FAILED(hres) )
throw Exception("Failed to initialize COM");
// Step 2: --------------------------------------------------
// Set general COM security levels --------------------------
// Note: If you are using Windows 2000, you need to specify -
// the default authentication credentials for a user by using
// a SOLE_AUTHENTICATION_LIST structure in the pAuthList ----
// parameter of CoInitializeSecurity ------------------------
HRESULT hres = CoInitializeSecurity(
NULL,
-1, // COM authentication
NULL, // Authentication services
NULL, // Reserved
RPC_C_AUTHN_LEVEL_DEFAULT, // Default authentication
RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation
NULL, // Authentication info
EOAC_NONE, // Additional capabilities
NULL // Reserved
);
if( FAILED(hres) )
{
CoUninitialize();
throw Exception("Failed to initialize COM security");
}
// Step 3: ---------------------------------------------------
// Obtain the initial locator to WMI -------------------------
HRESULT hres = CoCreateInstance(
CLSID_WbemLocator,
0,
CLSCTX_INPROC_SERVER,
IID_IWbemLocator,
(LPVOID *) &pLoc
);
if( FAILED(hres) )
{
CoUninitialize();
throw Exception("Failed to create WMI locator");
}
// all ok
bDidCoInit = true;
}
//--------------------------------------------------------------------------
-
void __fastcall TWmi::ConnectToRoot(const AnsiString &Path)
{
// Step 4: -----------------------------------------------------
// Connect to WMI through the IWbemLocator::ConnectServer method
// Connect to the namespace with the current user and obtain pointer
pSvc
// to make IWbemServices calls.
if( !pLoc )
throw Exception("The WMI locator has not been created yet");
if( pSvc )
{
// disconnect from the current server
pSvc->Release();
pSvc = NULL;
}
HRESULT hres = pLoc->ConnectServer(
WideString(Path), // 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) )
throw Exception("Failed to connect to WMI Root");
// Step 5: --------------------------------------------------
// Set security levels on the proxy -------------------------
HRESULT 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) )
{
pSvc->Release();
pSvc = NULL;
throw Exception("Failed to set WMI services proxy security");
}
}
//--------------------------------------------------------------------------
-
void __fastcall TWmi::ExecuteQuery(const AnsiString &Query)
{
// Step 6: --------------------------------------------------
// Use the IWbemServices pointer to make requests of WMI ----
// For example, get the name of the operating system
if( !pSvc )
throw Exception("The WMI services proxy has not been created
yet");
if( pEnumerator )
{
// disconnect from the current query
pEnumerator->Release();
pEnumerator = NULL;
}
HRESULT hres = pSvc->ExecQuery(
WideString("WQL"),
WideString(Query),
WBEM_FLAG_BIDIRECTIONAL | WBEM_FLAG_RETURN_IMMEDIATELY,
NULL,
&pEnumerator
);
if( FAILED(hres) )
throw Exception("Failed on ExecuteCOMQuery");
}
//--------------------------------------------------------------------------
-
namespace Twmi
{
void __fastcall PACKAGE Register()
{
TComponentClass classes[1] = {__classid(TWmi)};
RegisterComponents("Maurice", classes, 0);
}
}
//--------------------------------------------------------------------------
-
Gambit
Technical Details
Message-ID:
<4331154b$1@newsgroups.borland.com>Path:
arc1-ca.pugleaf.net!g2news1.google.com!news4.google.com!border1.nntp.dca.giganews.com!nntp.giganews.com!feed6.newsreader.com!newsreader.com!news-out2.kabelfoon.nl!newsfeed.kabelfoon.nl!xindi.nntp.kabelfoon.nl!194.25.134.62.MISMATCH!newsfeed00.sul.t-online.de!newsfeed01.sul.t-online.de!t-online.de!newsgroups.borland.com!not-for-mailReferences:
<4330f48c@newsgroups.borland.com>Show Full Headers
Complete Article Headers
X-Google-Thread: 10cc67,83e8798583d6ac12 X-Google-Attributes: gid10cc67,public X-Google-Language: ENGLISH,ASCII-7-bit From: "Remy Lebeau \(TeamB\)" <no.spam@no.spam.com> Newsgroups: borland.public.cppbuilder.nativeapi References: <4330f48c@newsgroups.borland.com> Subject: Re: COM not initializing in custom compenent dropped on form Date: Wed, 21 Sep 2005 01:10:21 -0700 Lines: 316 X-Priority: 3 X-MSMail-Priority: Normal X-Newsreader: Microsoft Outlook Express 6.00.2800.1409 X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2800.1409 NNTP-Posting-Host: 68.69.17.41 Message-ID: <4331154b$1@newsgroups.borland.com> X-Trace: newsgroups.borland.com 1127290187 68.69.17.41 (21 Sep 2005 01:09:47 -0700) Path: arc1-ca.pugleaf.net!g2news1.google.com!news4.google.com!border1.nntp.dca.giganews.com!nntp.giganews.com!feed6.newsreader.com!newsreader.com!news-out2.kabelfoon.nl!newsfeed.kabelfoon.nl!xindi.nntp.kabelfoon.nl!194.25.134.62.MISMATCH!newsfeed00.sul.t-online.de!newsfeed01.sul.t-online.de!t-online.de!newsgroups.borland.com!not-for-mail