Megosztás a következőn keresztül:


Áttelepítési útmutató: COM Spy

Ez a témakör egy cikksorozat második része, amely bemutatja a régebbi Visual Studio C++-projektek a Visual Studio legújabb verziójára való frissítésének folyamatát. A jelen témakör példakódját legutóbb a Visual Studio 2005-ben fordították le.

COMSpy

A COMSpy egy olyan program, amely figyeli és naplózza a gép szervizelt összetevőinek tevékenységét. A szervizelt összetevők olyan COM+ összetevők, amelyek egy rendszeren futnak, és ugyanazon a hálózaton lévő számítógépek is használhatók. Ezeket a Windows Vezérlőpult Component Services funkciója kezeli.

1. lépés. A projektfájl konvertálása

A projektfájl egyszerűen konvertálható, és migrálási jelentést készít. A jelentés tartalmaz néhány bejegyzést, amelyek tájékoztatnak minket azokról a problémákról, amelyekkel esetleg foglalkozni kell. Íme egy jelentett probléma (vegye figyelembe, hogy a jelen témakör során a hibaüzenetek időnként rövidülnek az olvashatóság érdekében, például a teljes elérési utak eltávolításához):

ComSpyAudit\ComSpyAudit.vcproj: MSB8012: $(TargetPath) ('C:\Users\UserName\Desktop\spy\spy\ComSpyAudit\.\XP32_DEBUG\ComSpyAudit.dll') does not match the Librarian's OutputFile property value '.\XP32_DEBUG\ComSpyAudit.dll' ('C:\Users\UserName\Desktop\spy\spy\XP32_DEBUG\ComSpyAudit.dll') in project configuration 'Unicode Debug|Win32'. This may cause your project to build incorrectly. To correct this, please make sure that $(TargetPath) property value matches the value specified in %(Lib.OutputFile).

A projektek frissítésének egyik gyakori problémája, hogy a Projekt tulajdonságai párbeszédpanel Linker OutputFile beállítását esetleg felül kell vizsgálni. A Visual Studio 2010 előtti projektek esetében az OutputFile az egyik beállítás, amellyel az automatikus átalakítási varázslónak problémái vannak, ha nem szabványos értékre van állítva. Ebben az esetben a kimeneti fájlok elérési útjai nem szabványos mappára lettek állítva, XP32_DEBUG. Ha többet szeretne megtudni erről a hibáról, a Visual Studio 2010 projektfrissítésével kapcsolatos blogbejegyzésben olvashattunk. Ez volt az a frissítés, amely a vcbuildről az msbuildre való váltást érintette, ami jelentős változás. Ezen információk szerint a Kimeneti fájl beállítás alapértelmezett értéke egy új projekt $(OutDir)$(TargetName)$(TargetExt)létrehozásakor, de ez nem a konvertálás során van beállítva, mivel a konvertált projektek nem ellenőrizhetik, hogy minden helyes-e. Próbáljuk meg azonban ezt az OutputFile-ban elhelyezni, és nézzük meg, hogy működik-e. Igen, így továbbléphetünk. Ha nincs különös ok a nem szabványos kimeneti mappa használatára, javasoljuk, hogy a szabványos helyet használja. Ebben az esetben úgy döntöttünk, hogy a portolás és frissítés során a kimeneti helyet a nem szabványos beállításnál hagyjuk; $(OutDir) a Debug konfigurációban az XP32_DEBUG mappára, és a Release konfigurációban a ReleaseU mappára oldódik fel.

2. lépés. A build folyamatának indítása

A portolt projekt létrehozása során számos hiba és figyelmeztetés jelenik meg.

ComSpyCtl nem fordul le a következő fordítóhiba miatt:

atlcom.h(611): error C2664: 'HRESULT CComSpy::IPersistStreamInit_Save(LPSTREAM,BOOL,ATL::ATL_PROPMAP_ENTRY *)': cannot convert argument 3 from 'const ATL::ATL_PROPMAP_ENTRY *' to 'ATL::ATL_PROPMAP_ENTRY *'atlcom.h(611): note: Conversion loses qualifiersatlcom.h(608): note: while compiling class template member function 'HRESULT ATL::IPersistStreamInitImpl<CComSpy>::Save(LPSTREAM,BOOL)'\spy\spy\comspyctl\ccomspy.h(28): note: see reference to class template instantiation 'ATL::IPersistStreamInitImpl<CComSpy>' being compiled

A hiba az Save osztály IPersistStreamInitImpl metódusára hivatkozik az atlcom.h fájlban.

STDMETHOD(Save)(_Inout_ LPSTREAM pStm, _In_ BOOL fClearDirty)
{
     T* pT = static_cast<T*>(this);
     ATLTRACE(atlTraceCOM, 2, _T("IPersistStreamInitImpl::Save\n"));
     return pT->IPersistStreamInit_Save(pStm, fClearDirty, T::GetPropertyMap());
}

A probléma az, hogy a fordító egy régebbi verziója által elfogadott átalakítás már nem érvényes. A C++ szabványnak való megfelelés érdekében a korábban engedélyezett kódok némelyike már nem engedélyezett. Ebben az esetben nem biztonságos egy nem const mutatót átadni egy függvénynek, amely const mutatót vár. A megoldás az, hogy megkeressük a IPersistStreamInit_Save osztályon belül a CComSpy deklarációját, és hozzáadjuk a const módosítót a harmadik paraméterhez.

HRESULT CComSpy::IPersistStreamInit_Save(LPSTREAM pStm, BOOL /* fClearDirty */, const ATL_PROPMAP_ENTRY* pMap)

És hasonló változás a IPersistStreamInit_Load.

HRESULT IPersistStreamInit_Load(LPSTREAM pStm, const ATL_PROPMAP_ENTRY* pMap);

A következő hiba a regisztrációval foglalkozik.

error MSB3073: The command "regsvr32 /s /c "C:\Users\username\Desktop\spy\spy\ComSpyCtl\.\XP32_DEBUG\ComSpyCtl.lib"error MSB3073: echo regsvr32 exec. time > ".\XP32_DEBUG\regsvr32.trg"error MSB3073:error MSB3073: :VCEnd" exited with code 3.

Már nincs szükségünk erre a build utáni regisztrációs parancsra. Ehelyett egyszerűen eltávolítjuk az egyéni buildelési parancsot, és a Linker beállításaiban megadjuk, hogy regisztrálja a kimenetet.

Figyelmeztetések kezelése

A projekt a következő linker-figyelmeztetést hozza létre.

warning LNK4075: ignoring '/EDITANDCONTINUE' due to '/SAFESEH' specification

A /SAFESEH fordító beállítás nem hasznos hibakeresési módban, amikor viszont a /EDITANDCONTINUE az, ezért a megoldás az, hogy csak a /SAFESEH konfigurációk esetén tiltsuk le a -t. Ehhez a tulajdonság-párbeszédpanelen megnyitjuk a hibát okozó projekt tulajdonság-párbeszédpanelét, és először hibakeresésre (valójában Unicode hibakeresésre) állítjuk be a Konfigurációt, majd a Csatolás speciális szakaszában állítjuk vissza a Kép biztonságos kivételkezelői tulajdonságátNem (/SAFESEH:NO) értékre.

A fordító figyelmeztet minket, hogy az PROP_ENTRY_EX elavult. Ez nem biztonságos, és a javasolt helyettesítő a PROP_ENTRY_TYPE_EX.

BEGIN_PROPERTY_MAP(CComSpy)
     PROP_ENTRY_EX( "LogFile", DISPID_LOGFILE, CLSID_ComSpyPropPage, IID_IComSpy)
     PROP_ENTRY_EX( "ShowGridLines", DISPID_GRIDLINES, CLSID_ComSpyPropPage, IID_IComSpy)
     PROP_ENTRY_EX( "Audit", DISPID_AUDIT, CLSID_ComSpyPropPage, IID_IComSpy)
     PROP_ENTRY_EX( "ColWidth", DISPID_COLWIDTH, CLSID_ComSpyPropPage, IID_IComSpy)
     PROP_PAGE(CLSID_StockFontPage)
END_PROPERTY_MAP()

Ennek megfelelően módosítjuk a ccomspy.h kódját, és szükség szerint com-típusokat adunk hozzá.

BEGIN_PROPERTY_MAP(CComSpy)
     PROP_ENTRY_TYPE_EX( "LogFile", DISPID_LOGFILE, CLSID_ComSpyPropPage, IID_IComSpy, VT_BSTR)
     PROP_ENTRY_TYPE_EX( "ShowGridLines", DISPID_GRIDLINES, CLSID_ComSpyPropPage, IID_IComSpy, VT_BOOL)
     PROP_ENTRY_TYPE_EX( "Audit", DISPID_AUDIT, CLSID_ComSpyPropPage, IID_IComSpy, VT_BOOL)
     PROP_ENTRY_TYPE_EX( "ColWidth", DISPID_COLWIDTH, CLSID_ComSpyPropPage, IID_IComSpy, VT_UINT)
     PROP_PAGE(CLSID_StockFontPage)
END_PROPERTY_MAP()

Elérkeztünk az utolsó néhány figyelmeztetéshez, amelyeket a fordítóprogram szigorúbb megfelelőségi ellenőrzései okoznak.

\spy\comspyctl\usersub.h(70): warning C4457: declaration of 'var' hides function parameter\spy\comspyctl\usersub.h(48): note: see declaration of 'var'\spy\comspyctl\usersub.h(94): warning C4018: '<': signed/unsigned mismatch  ComSpy.cpp\spy\comspyctl\comspy.cpp(186): warning C4457: declaration of 'bHandled' hides function parameter\spy\spy\comspyctl\comspy.cpp(177): note: see declaration of 'bHandled'

A C4018 figyelmeztetés a következő kódból származik:

for (i=0;i<lCount;i++)
    CoTaskMemFree(pKeys[i]);

A probléma az, hogy i-t UINT-nak/nek deklarálták, és lCount-t long-nak/nek deklarálták, így az aláírt/aláíratlan eltérés létrejön. Nem lenne célszerű a lCount típusát UINT-ra módosítani, mivel az értékét a IMtsEventInfo::get_Count típust használó long-ből kapja, amely nem szerepel a felhasználói által írt kódban. Ezért hozzáadunk egy szereplőt a kódhoz. A C-stílusú kaszt is megfelelne ilyen numerikus kaszt esetén, de a static_cast az ajánlott stílus.

for (i=0;i<static_cast<UINT>(lCount);i++)
    CoTaskMemFree(pKeys[i]);

Ezek a figyelmeztetések olyan esetek, amikor egy változót deklaráltak egy olyan függvényben, amely azonos nevű paraméterrel rendelkezik, ami potenciálisan zavaró kódhoz vezet. Ezt a helyi változók nevének módosításával javítottuk.

3. lépés. Tesztelés és hibakeresés

Először teszteltük az alkalmazást a különböző menük és parancsok futtatásával, majd az alkalmazás bezárásával. Az egyetlen feljegyzett probléma egy hibakeresési állítás volt az alkalmazás bezárásakor. A probléma az alkalmazás fő COM-összetevőjének, az CWindowImpl objektum alaposztályának destruktorában CSpyConjelent meg. Az állítási hiba az atlwin.h következő kódjában történt.

virtual ~CWindowImplRoot()
{
     #ifdef _DEBUG
     if(m_hWnd != NULL)// should be cleared in WindowProc
     {
          ATLTRACE(atlTraceWindowing, 0, _T("ERROR - Object deleted before window was destroyed\n"));
          ATLASSERT(FALSE);
     }
     #endif //_DEBUG
}

A hWnd függvény általában nulla WindowProc értékre van állítva, de ez nem történt meg, mert az alapértelmezett WindowProchelyett egy egyéni kezelőt hív meg a rendszer az ablakot bezáró Windows-üzenethez (WM_SYSCOMMAND). Az egyéni kezelő nem nullára állítja a hWnd beállítást. Az MFC CWnd osztályában található hasonló kód mutatja, hogy amikor egy ablakot elpusztítanak, OnNcDestroy meghívásra kerül, és az MFC-ben a dokumentáció javasolja, hogy a felülbíráláskor a bázis CWnd::OnNcDestroy-t hívjuk meg annak érdekében, hogy a megfelelő tisztítási műveletek történjenek. Ez magában foglalja az ablak fogópontjának leválasztását, vagy más szóval a NcDestroy nullára állítását. Ez az állítás a minta eredeti verziójában is aktiválódhatott, mivel ugyanaz az állítási kód volt jelen az atlwin.h régi verziójában.

Az alkalmazás működésének teszteléséhez létrehoztunk egy serviced összetevőt az ATL-projektsablon használatával, amely com+ támogatás hozzáadását választotta az ATL projektvarázslóban. Ha korábban még nem dolgozott a szervizelt összetevőkkel, nem nehéz létrehozni egyet, és regisztrálni és elérhetővé tenni a rendszeren vagy a hálózaton más alkalmazások számára. A COM Spy alkalmazás úgy lett kialakítva, hogy diagnosztikai segédeszközként monitorozza a szervizelt összetevők tevékenységét.

Ezután hozzáadtunk egy osztályt, kiválasztottuk az ATL-objektumot, és az objektum nevét a következőként Doghatároztuk meg: . Ezután a dog.h-ban és a dog.cpp-ben hozzáadtuk a megvalósítást.

STDMETHODIMP CDog::Wag(LONG* lDuration)
{
    // TODO: Add your implementation code here
    *lDuration = 100l;
    return S_OK;
}

Ezután létrehoztuk és regisztráltuk (rendszergazdaként futtatnia kell a Visual Studiót), és aktiváltuk a Windows Vezérlőpult Serviced Component alkalmazásával. Létrehoztunk egy C#-alapú Windows Forms-projektet, az eszközkészletből egy gombot húztunk az űrlapra, majd duplán kattintottunk, hogy létrehozzunk egy kattintás eseménykezelőt. Az alábbi kódot adtuk hozzá a Dog összetevő példányosításához.

private void button1_Click(object sender, EventArgs e)
{
    ATLProjectLib.Dog dog1 = new ATLProjectLib.Dog();
    dog1.Wag();
}

Ez probléma nélkül futott, és a COM Spy működik, valamint a Dog összetevő felügyeletére konfigurálva sok adat jelenik meg a tevékenységről.

Lásd még

Portolás és frissítés: Példák és esettanulmányok
Következő példa: Spy++
Előző példa: MFC Scribble