Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
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