Aracılığıyla paylaş


Bildirim Dosyası Biçimi

Bildirim dosyalarının dosya biçimi C++ ve IDL'den mümkün olduğunca çok ödünç alır. Sonuç olarak, normal bir C++ SDK üst bilgi dosyasını alıp bildirim dosyası olarak değiştirmek oldukça kolaydır. Ayrıştırıcı, dosyayı düzenlemenize ve belgelemenize yardımcı olmak için C ve C++ stili açıklamaları tam olarak destekler.

Bir bildirim dosyası eklemeye veya var olan bir dosyada değişiklik yapmaya çalışırsanız, bunu gerçekleştirmenin en iyi yolu yalnızca deneme yapmaktır. Hata ayıklayıcıda bir !logexts.logi veya !logexts.loge komutu gönderdiğinizde, Logger bildirim dosyalarını ayrıştırmak için çaba gösterir. Bir sorunla karşılaşırsa, hatayı gösterebilecek bir hata iletisi oluşturur.

Bildirim dosyası şu temel öğelerden oluşur: modül etiketleri, kategori etiketleri, işlev bildirimleri, COM arabirim tanımları ve tür tanımları. Diğer öğe türleri de vardır, ancak bunlar en önemli öğelerdir.

Modül Etiketleri

Modül etiketi, bundan sonra bildirilen işlevleri dışarı aktaran DLL'yi bildirir. Örneğin, bildirim dosyanız Comctl32.dll'den bir işlev grubu günlüğe kaydetmeye yönelikse, işlev prototiplerini bildirmeden önce aşağıdaki modül etiketini eklersiniz:

module COMCTL32.DLL:

Bildirim dosyasındaki işlev bildirimlerinden önce bir modül etiketi görünmelidir. Bildirim dosyası herhangi bir sayıda modül etiketi içerebilir.

Kategori Etiketleri

Modül etiketine benzer şekilde, kategori etiketi de sonraki tüm işlevlerin ve/veya COM arabirimlerinin hangi "kategoriye" ait olduğunu tanımlar. Örneğin, bir Comctl32.dll bildirim dosyası oluşturuyorsanız, kategori etiketi olarak aşağıdakileri kullanabilirsiniz:

category CommonControls:

Bildirim dosyası herhangi bir sayıda kategori etiketi içerebilir.

İşlev Bildirimleri

Bir işlev bildirimi, Logger'ın gerçekten bir şeyi günlüğe kaydetmesini sağlayan şeydir. C/C++ üst bilgi dosyasında bulunan işlev prototipi ile neredeyse aynıdır. Biçime birkaç önemli ekleme vardır ve bu eklemeler aşağıdaki örnekte en iyi şekilde gösterilebilir:

HANDLE [gle] FindFirstFileA(
       LPCSTR lpFileName,
       [out] LPWIN32_FIND_DATAA lpFindFileData);

FindFirstFileA işlevi iki parametre alır. İlk olarak, lpFileName, bir dosya veya dosyanın nerede aranacağını tanımlayan tam yoldur (genellikle joker karakterlerle). İkincisi, arama sonuçlarını içermek için kullanılacak bir WIN32_FIND_DATAA yapısının işaretçisidir. Döndürülen HANDLE, gelecekteki FindNextFileA çağrıları için kullanılır. FindFirstFileA INVALID_HANDLE_VALUE döndürürse işlev çağrısı başarısız olur ve GetLastError işlevi çağrılarak hata kodu temin edilebilir.

HANDLE türü aşağıdaki gibi olarak bildirilir:

value DWORD HANDLE
{
#define NULL                       0 [fail]
#define INVALID_HANDLE_VALUE      -1 [fail]
};

Bu işlev tarafından döndürülen değer 0 veya -1 (0xFFFFFFFF) ise, günlükçü işlevin başarısız olduğunu varsayar çünkü bu değerlerin değer bildiriminde [fail] değiştiricisi vardır. (Bu bölümün devamında yer alan Değer Türleri bölümüne bakın.) İşlev adından hemen önce bir [gle] değiştiricisi olduğundan, Günlükçü bu işlevin hata kodlarını döndürmek için GetLastError kullandığını algılar, bu nedenle hata kodunu yakalar ve günlük dosyasına kaydeder.

lpFindFileData parametresindeki [out] değiştiricisi, günlükçüye veri yapısının işlev tarafından doldurulduğunu ve işlev döndürdüğünde günlüğe kaydedilmesi gerektiğini bildirir.

COM Arabirim Tanımları

COM arabirimi temelde bir COM nesnesinin istemcisi tarafından çağrılabilen bir işlev vektördür. Bildirim biçimi, arabirimleri tanımlamak için COM'da kullanılan Arabirim Tanım Dili'nden (IDL) büyük ölçüde yararlanır.

Aşağıdaki örneği göz önünde bulundurun:

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 );
};

Bu, IUnknown'dan türetilen IDispatch adlı bir arabirim bildirir. Arabirim parantezleri içinde belirli bir sırada bildirilen dört üye fonksiyon içerir. Günlükçü, arabirimin vtable'ında işlev işaretçilerini (çalışma zamanında kullanılan işlev işaretçilerinin gerçek ikili vektörünü) kendi işlev işaretçileriyle değiştirerek bu üye işlevleri durdurur ve günlüğe kaydeder. Logger'ın arabirimleri dağıtılırken nasıl yakaladığı hakkında daha fazla bilgi için bu bölümün devamında yer alan COM_INTERFACE_PTR Türleri bölümüne bakın.

Tür Tanımları

Veri türlerini tanımlamak, bildirim dosyası geliştirmenin en önemli (ve en sıkıcı) parçasıdır. Bildirim dili, bir işlevden geçirilen veya döndürülen sayısal değerler için okunabilir etiketler tanımlamanızı sağlar.

Örneğin Winerror.h, Microsoft Win32 işlevlerinin çoğu tarafından döndürülen hata değerlerinin ve bunlara karşılık gelen insan tarafından okunabilir etiketlerin listesi olan "WinError" adlı bir tür tanımlar. Bu, Günlükçü ve LogViewer'ın bilgilendirici olmayan hata kodlarını anlamlı bir metinle değiştirmesine olanak tanır.

Logger ve LogViewer'ın DWORD bit maskesini bileşenlerine ayırmasına izin vermek için bit maskesi içindeki tek tek bitleri de etiketleyebilirsiniz.

Bildirim tarafından desteklenen 13 temel tür vardır. Bunlar aşağıdaki tabloda listelenmiştir.

Türü Uzunluk Örnek Görüntüle

İşaretçi

4 bayt

0x001AF320

BOŞLUK

0 bayt

BYTE

1 bayt

0x32

KELİME

2 bayt

0x0A23

DWORD

4 bayt

-234323

BOOL

1 bayt

DOĞRU

LPSTR

Uzunluk baytı artı herhangi bir sayıda karakter

"Hızlı kahverengi tilki"

LPWSTR

Uzunluk baytının yanı sıra istediğiniz sayıda Unicode karakteri

Tembel köpeğin üzerinden atladı

GUID

16 bayt

{0CF774D0-F077-11D1-B1BC-00C04F86C324}

COM_INTERFACE_PTR

4 bayt

0x0203404A

değer

Temel türe bağımlı

Çok Fazla Açık Dosya Hatası

maske

Temel türe bağımlı

WS_MAXIMIZED | WS_ALWAYSONTOP

yapı

Kapsüllenmiş türlerin boyutuna bağlı

+ lpRect nLeft 34 nRight 54 nTop 100 nBottom 300

Bildirim dosyalarındaki tür tanımları C/C++ tür tanımları gibi çalışır. Örneğin, aşağıdaki deyim PLONG'u LONG işaretçisi olarak tanımlar:

typedef LONG *PLONG;

Temel tür tanımlarının çoğu Main.h'de zaten bildirilmiştir. Yalnızca bileşeninize özgü tür tanımları eklemeniz gerekir. Yapı tanımları C/C++ yapı türleriyle aynı biçime sahiptir.

Dört özel tür vardır: değer, maske, GUID ve COM_INTERFACE_PTR.

Değer Türleri
Değer, insan tarafından okunabilen etiketlere ayrılmış temel bir türdür. İşlev belgelerinin çoğu yalnızca bir işlevde kullanılan belirli bir sabitin #define değerini ifade eder. Örneğin, çoğu programcı GetLastError tarafından döndürülen tüm kodlar için gerçek değerin ne olduğunu fark etmediğinden LogViewer'da şifreli bir sayısal değer görmek yararlı değildir. Bildirim değeri, aşağıdaki örnekte olduğu gibi değer bildirimlerine izin vererek bunun üstesinden gelir:

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
};

Bu, LONG'dan türetilen "ChangeNotifyFlags" adlı yeni bir tür bildirir. Bu bir işlev parametresi olarak kullanılırsa, ham sayılar yerine insan tarafından okunabilen diğer adlar görüntülenir.

Maske Türleri
Değer türlerine benzer şekilde, maske türü de anlamı olan bitlerin her biri için insan tarafından okunabilir etiketlere ayrılmış temel bir türdür (genellikle DWORD). Aşağıdaki örneğe göz atın:

mask DWORD DirectDrawOptSurfaceDescCapsFlags
{
#define DDOSDCAPS_OPTCOMPRESSED                 0x00000001
#define DDOSDCAPS_OPTREORDERED                  0x00000002
#define DDOSDCAPS_MONOLITHICMIPMAP              0x00000004
};

Bu, DWORD'den türetilen ve bir işlevin parametresi olarak kullanıldığında, kullanıcıya LogViewer'da ayrı ayrı değerler olarak gösterilecek yeni bir türü tanımlar. Bu nedenle, değer 0x00000005 ise LogViewer şunları görüntüler:

DDOSDCAPS_OPTCOMPRESSED | DDOSDCAPS_MONOLITHICMIPMAP

GUID Türleri
GUID'ler, COM'da yaygın olarak kullanılan 16 baytlık genel olarak benzersiz tanımlayıcılardır. Bunlar iki şekilde bildirilir:

struct __declspec(uuid("00020400-0000-0000-C000-000000000046")) IDispatch;

veya

class __declspec(uuid("11219420-1768-11D1-95BE-00609797EA4F")) ShellLinkObject;

İlk yöntem bir arabirim tanımlayıcısı (IID) bildirmek için kullanılır. LogViewer tarafından görüntülendiğinde, görünen adın başına "IID_" eklenir. İkinci yöntem bir sınıf tanımlayıcısı (CLSID) bildirmek için kullanılır. LogViewer görünen adın başına "CLSID_" ekler.

GUID türü bir işlevin parametresiyse, LogViewer değeri bildirilen tüm IID'ler ve CLSID'lerle karşılaştırır. Eşleşme bulunursa, IID dostu adı görüntülenir. Aksi takdirde, standart GUID gösteriminde 32 onaltılık karakter değerini görüntüler.

COM_INTERFACE_PTR Türleri
COM_INTERFACE_PTR türü, COM arabirim işaretçisinin temel türüdür. Bir COM arabirimi bildirdiğinizde, aslında COM_INTERFACE_PTR'den türetilmiş yeni bir tür tanımlarsınız. Bu nedenle, böyle bir tür işaretçisi bir işlevin parametresi olabilir. COM_INTERFACE_PTR temel türü, bir işlevde çıkış (OUT) parametresi olarak bildirilirse ve [iid] etiketine sahip ayrı bir parametre varsa, Logger sistemi, geçirilen IID değerini bildirilen tüm GUID'lerle karşılaştırır. Eşleşme varsa ve IID ile aynı ada sahip bir COM arabirimi bildirildiyse, Günlükçü bu arabirimdeki tüm işlevleri bağlar ve günlüğe kaydeder.

Aşağıda bir örnek verilmiştir:

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
);

Bu örnekte riid bir [iid] değiştiriciye sahiptir. Bu, Log modülüne ppv içinde döndürülen işaretçinin riid tarafından tanımlanan arabirim için bir COM arabirim işaretçisi olduğunu gösterir.

Bir işlevi aşağıdaki gibi bildirmek de mümkündür:

DDRESULT DirectDrawCreateClipper( DWORD dwFlags, [out] LPDIRECTDRAWCLIPPER *lplpDDClipper, IUnknown *pUnkOuter );

Bu örnekte LPDIRECTDRAWCLIPPER, IDirectDrawClipper arabirimine bir işaretçi olarak tanımlanır. Logger lplpDDClipper parametresinde hangi arabirim türünün döndürüldüğünü tanımlayabildiğinden, diğer parametrelerin hiçbirinde [iid] değiştiricisine gerek yoktur.