Not
Åtkomst till denna sida kräver auktorisation. Du kan prova att logga in eller byta katalog.
Åtkomst till denna sida kräver auktorisation. Du kan prova att byta katalog.
Filformatet för manifestfilerna lånar så mycket från C++ och IDL som möjligt. Därför är det ganska enkelt att ta en vanlig C++ SDK-huvudfil och ändra den till en manifestfil. Parsern har fullt stöd för kommentarer i C- och C++-format som hjälper dig att organisera och dokumentera filen.
Om du försöker lägga till en manifestfil eller göra ändringar i en befintlig fil är det bästa sättet att göra det att bara experimentera. När du utfärdar kommandot !logexts.logi eller !logexts.loge i felsökningsprogrammet försöker Logger parsa manifestfilerna. Om det uppstår ett problem visas ett felmeddelande som kan tyda på misstaget.
En manifestfil består av följande grundläggande element: moduletiketter, kategorietiketter, funktionsdeklarationer, COM-gränssnittsdefinitioner och typdefinitioner. Det finns även andra typer av element, men de är de viktigaste.
Moduletiketter
En moduletikett deklarerar helt enkelt vad DLL exporterar de funktioner som deklareras därefter. Om manifestfilen till exempel är till för att logga en grupp funktioner från Comctl32.dllskulle du inkludera följande moduletikett innan du deklarerar några funktionsprototyper:
module COMCTL32.DLL:
En moduletikett måste visas före alla funktionsdeklarationer i en manifestfil. En manifestfil kan innehålla valfritt antal moduletiketter.
Kategorietiketter
På samma sätt som en moduletikett identifierar en kategorietikett vilken "kategori" alla efterföljande funktioner och/eller COM-gränssnitt tillhör. Om du till exempel skapar en Comctl32.dll manifestfil kan du använda följande som kategorietikett:
category CommonControls:
En manifestfil kan innehålla valfritt antal kategorietiketter.
Funktionsdeklarationer
En funktionsdeklaration är det som faktiskt uppmanar Logger att logga något. Den är nästan identisk med en funktionsprototyp som finns i en C/C++-huvudfil. Det finns några viktiga tillägg i formatet, som bäst kan illustreras i följande exempel:
HANDLE [gle] FindFirstFileA(
LPCSTR lpFileName,
[out] LPWIN32_FIND_DATAA lpFindFileData);
Funktionen FindFirstFileA tar två parametrar. Den första är lpFileName, som är en fullständig sökväg (vanligtvis med jokertecken) som definierar var du ska söka efter en fil eller filer. Den andra är en pekare till en WIN32_FIND_DATAA struktur som ska användas för att innehålla sökresultaten. Det returnerade HANDLE används för framtida anrop till FindNextFileA. Om FindFirstFileA returnerar INVALID_HANDLE_VALUE misslyckades funktionsanropet och en felkod kan hämtas genom att anropa funktionen GetLastError .
HANDLE-typen deklareras på följande sätt:
value DWORD HANDLE
{
#define NULL 0 [fail]
#define INVALID_HANDLE_VALUE -1 [fail]
};
Om värdet som returneras av den här funktionen är 0 eller -1 (0xFFFFFFFF), förutsätter Logger att funktionen misslyckades eftersom sådana värden har en [fail]-modifierare i värdedeklarationen. (Se avsnittet Värdetyper senare i det här avsnittet.) Eftersom det finns en [gle]-modifierare precis före funktionsnamnet, identifierar Logger att den här funktionen använder GetLastError för att returnera felkoder, så den samlar in felkoden och loggar den till loggfilen.
[out]-modifieraren på parametern lpFindFileData informerar Logger om att datastrukturen fylls i av funktionen och bör loggas när funktionen returneras.
COM-gränssnittsdefinitioner
Ett COM-gränssnitt är i princip en vektor med funktioner som kan anropas av ett COM-objekts klient. Manifestformatet lånar kraftigt från det gränssnittsdefinitionsspråk (IDL) som används i COM för att definiera gränssnitt.
Tänk på följande exempel:
interface IDispatch : IUnknown
{
HRESULT GetTypeInfoCount( UINT pctinfo );
HRESULT GetTypeInfo(
UINT iTInfo,
LCID lcid,
LPVOID ppTInfo );
HRESULT GetIDsOfNames(
REFIID riid,
LPOLECHAR* rgszNames,
UINT cNames,
LCID lcid,
[out] DISPID* rgDispId );
HRESULT Invoke(
DISPID dispIdMember,
REFIID riid,
LCID lcid,
WORD wFlags,
DISPPARAMS* pDispParams,
VARIANT* pVarResult,
EXCEPINFO* pExcepInfo,
UINT* puArgErr );
};
Detta deklarerar ett gränssnitt med namnet IDispatch som härleds från IUnknown. Den innehåller fyra medlemsfunktioner som deklareras i specifik ordning inom gränssnittets klammerparenteser. Logger fångar upp och loggar dessa medlemsfunktioner genom att ersätta funktionspekarna i gränssnittets vtable (den faktiska binära vektorn för funktionspekare som används vid körning) med sina egna. Mer information om hur Logger samlar in gränssnitt när de delas ut finns i avsnittet COM_INTERFACE_PTR Typer senare i det här avsnittet.
Typdefinitioner
Att definiera datatyper är den viktigaste (och mest omständliga) delen av manifestfilens utveckling. Med manifestspråket kan du definiera läsbara etiketter för numeriska värden som skickas in eller returneras från en funktion.
Winerror.h definierar till exempel en typ som kallas "WinError" som är en lista över felvärden som returneras av de flesta Microsoft Win32-funktioner och deras motsvarande etiketter som kan läsas av människor. På så sätt kan Logger och LogViewer ersätta oinformativa felkoder med meningsfull text.
Du kan också märka enskilda bitar i en bitmask så att Logger och LogViewer kan dela upp en DWORD-bitmask i dess komponenter.
Det finns 13 grundläggande typer som stöds av manifestet. De visas i följande tabell.
| Typ | Längd | Visningsexempel |
|---|---|---|
Pekare |
4 byte |
0x001AF320 |
OGILTIG |
0 byte |
|
byte |
1 byte |
0x32 |
ORD |
2 byte |
0x0A23 |
DWORD |
4 byte |
-234323 |
BOOL |
1 byte |
SANN |
LPSTR |
Längdbyte plus valfritt antal tecken |
Snabb, brun räv |
LPWSTR |
Längdbyte plus valfritt antal Unicode-tecken |
"Hoppade över den lata hunden" |
Globalt unikt identifierare (GUID) |
16 byte |
{0CF774D0-F077-11D1-B1BC-00C04F86C324} |
COM_INTERFACE_PTR |
4 byte |
0x0203404A |
värde |
Beroende på bastyp |
ERROR_FÖR_MÅNGA_ÖPPNA_FILÖRER |
mask |
Beroende på bastyp |
WS_MAXIMIZED | WS_ALWAYSONTOP |
Struktur |
Beroende på storleken på inkapslade typer |
+ lpRect nLeft 34 nRight 54 nTop 100 nBottom 300 |
Typdefinitioner i manifestfiler fungerar som C/C++-typedefs. Följande uttryck definierar till exempel PLONG som en pekare till en LONG.
typedef LONG *PLONG;
De flesta grundläggande typedefs har redan deklarerats i Main.h. Du bör bara behöva lägga till typedefs som är specifika för din komponent. Strukturdefinitioner har samma format som C/C++-structtyper.
Det finns fyra specialtyper: värde, mask, GUID och COM_INTERFACE_PTR.
Värdetyper
Ett värde är en grundläggande typ som är uppdelad i etiketter som kan läsas av människor. De flesta funktionsdokumentationen refererar bara till #define värdet för en viss konstant som används i en funktion. De flesta programmerare vet till exempel inte vad det faktiska värdet är för alla koder som returneras av GetLastError, vilket gör det ohjälpsamt att se ett kryptiskt numeriskt värde i LogViewer. Manifestvärdet övervinner detta genom att tillåta värdedeklarationer som i följande exempel:
value LONG ChangeNotifyFlags
{
#define SHCNF_IDLIST 0x0000 // LPITEMIDLIST
#define SHCNF_PATHA 0x0001 // path name
#define SHCNF_PRINTERA 0x0002 // printer friendly name
#define SHCNF_DWORD 0x0003 // DWORD
#define SHCNF_PATHW 0x0005 // path name
#define SHCNF_PRINTERW 0x0006 // printer friendly name
};
Detta deklarerar en ny typ med namnet "ChangeNotifyFlags" som härleds från LONG. Om detta används som en funktionsparameter visas de mänskligt läsbara aliasen i stället för de rena talen.
Masktyper
På samma sätt som värdetyper är en masktyp en grundläggande typ (vanligtvis en DWORD) som är uppdelad i etiketter som kan läsas av människor för var och en av de bitar som har betydelse. Se följande exempel:
mask DWORD DirectDrawOptSurfaceDescCapsFlags
{
#define DDOSDCAPS_OPTCOMPRESSED 0x00000001
#define DDOSDCAPS_OPTREORDERED 0x00000002
#define DDOSDCAPS_MONOLITHICMIPMAP 0x00000004
};
Detta deklarerar en ny typ härledd från DWORD som, om den används som en funktionsparameter, får de enskilda värdena uppdelade för användaren i LogViewer. Så om värdet är 0x00000005 visas LogViewer:
DDOSDCAPS_OPTCOMPRESSED | DDOSDCAPS_MONOLITHICMIPMAP
GUID-typer
GUID:er är 16 byte globalt unika identifierare som används i stor utsträckning i COM. De deklareras på två sätt:
struct __declspec(uuid("00020400-0000-0000-C000-000000000046")) IDispatch;
eller
class __declspec(uuid("11219420-1768-11D1-95BE-00609797EA4F")) ShellLinkObject;
Den första metoden används för att deklarera en gränssnittsidentifierare (IID). När det visas av LogViewer läggs "IID_" till i början av visningsnamnet. Den andra metoden används för att deklarera en klassidentifierare (CLSID). LogViewer lägger till "CLSID_" i början av visningsnamnet.
Om en GUID-typ är en parameter till en funktion jämför LogViewer värdet med alla deklarerade IID:er och CLSID:er. Om en matchning hittas kommer det att visa det vänliga IID-namnet. Annars visas det 32-teckniga hexadecimala värdet i standard-GUID-notation.
COM_INTERFACE_PTR typer
Den COM_INTERFACE_PTR typen är bastypen för en COM-gränssnittspekare. När du deklarerar ett COM-gränssnitt definierar du faktiskt en ny typ som härleds från COM_INTERFACE_PTR. Därför kan en pekare till en sådan typ vara en parameter till en funktion. Om en COM_INTERFACE_PTR grundläggande typ deklareras som en OUT-parameter till en funktion och det finns en separat parameter som har en [iid]-etikett jämför Logger det skickade IID:t mot alla deklarerade GUID:er. Om det finns en matchning och ett COM-gränssnitt har deklarerats som har samma namn som IID:t, kommer Logger att koppla alla funktioner i gränssnittet och logga dem.
Här är ett exempel:
STDAPI CoCreateInstance(
REFCLSID rclsid, //Class identifier (CLSID) of the object
LPUNKNOWN pUnkOuter, //Pointer to controlling IUnknown
CLSCTX dwClsContext, //Context for running executable code
[iid] REFIID riid, //Reference to the identifier of the interface
[out] COM_INTERFACE_PTR * ppv
//Address of output variable that receives
//the interface pointer requested in riid
);
I det här exemplet har riid en [iid]-modifierare. Detta anger för Logger att pekaren som returneras i ppv är en COM-gränssnittspekare för gränssnittet som identifieras av riid.
Det är också möjligt att deklarera en funktion på följande sätt:
DDRESULT DirectDrawCreateClipper( DWORD dwFlags, [out] LPDIRECTDRAWCLIPPER *lplpDDClipper, IUnknown *pUnkOuter );
I det här exemplet definieras LPDIRECTDRAWCLIPPER som en pekare till gränssnittet IDirectDrawClipper . Eftersom Logger kan identifiera vilken gränssnittstyp som returneras i parametern lplpDDClipper behöver du ingen [iid]-modifierare för någon av de andra parametrarna.