🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: borland.public.cppbuilder.nativeapi
Article #5251

Re: COM not initializing in custom compenent dropped on form

#5251
From: Remy Lebeau (TeamB)
Date: Wed, 21 Sep 2005 08:10
314 lines
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-mail
References: <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