Aracılığıyla paylaş


TN039: MFC/OLE Otomasyon Uygulaması

Dekont

Aşağıdaki teknik not, çevrimiçi belgelere ilk kez eklendiğinden beri güncelleştirilmemiştir. Sonuç olarak, bazı yordamlar ve konular güncel olmayabilir veya yanlış olabilir. En son bilgiler için, çevrimiçi belge dizininde ilgilendiğiniz konuyu aramanız önerilir.

OLE IDispatch Arabirimine Genel Bakış

IDispatch Arabirim, uygulamaların Visual BASIC veya diğer diller gibi diğer uygulamaların uygulama özelliklerinden yararlanabileceği yöntemleri ve özellikleri kullanıma sunma yöntemidir. Bu arabirimin en önemli kısmı işlevidir IDispatch::Invoke . MFC, uygulamak IDispatch::Invokeiçin "dağıtım haritalarını" kullanır. Dağıtım eşlemesi, türetilmiş sınıflarınızın CCmdTargetdüzeni veya "şekli" üzerinde MFC uygulama bilgilerini sağlar; böylece nesnenin özelliklerini doğrudan işleyebilir veya istekleri karşılamak IDispatch::Invoke için nesnenizin içindeki üye işlevlerini çağırabilir.

Çoğunlukla ClassWizard ve MFC, OLE otomasyonu ayrıntılarının çoğunu uygulama programcısından gizlemek için işbirliği içindedir. Programcı uygulamada kullanıma sunmanın gerçek işlevselliğine odaklanır ve temel alınan tesisat konusunda endişelenmesi gerekmez.

Ancak, MFC'nin arka planda ne yaptığını anlamanın gerekli olduğu durumlar vardır. Bu not, çerçevenin üye işlevlerine ve özelliklerine DISPID'leri nasıl atayacağını ele alır. DISPIDatamak için MFC'nin kullandığı algoritma bilgisi, yalnızca uygulamanızın nesneleri için bir "tür kitaplığı" oluşturduğunuzda olduğu gibi kimlikleri bilmeniz gerektiğinde gereklidir.

MFC DISPID ataması

Otomasyonun son kullanıcısı (örneğin, visual basic kullanıcısı), kodunda otomasyon özellikli özelliklerin ve yöntemlerin gerçek adlarını (obj gibi) görür. ShowWindow), uygulaması IDispatch::Invoke gerçek adları almaz. İyileştirme nedenleriyle, erişilecek yöntemi veya özelliği tanımlayan 32 bit "sihirli tanımlama bilgisi" olan bir DISPID alır. Bu DISPID değerleri, adlı başka bir yöntem IDispatch::GetIDsOfNamesaracılığıyla uygulamadan IDispatch döndürülür. Bir otomasyon istemci uygulaması, erişmek istediği her üye veya özellik için bir kez çağırır GetIDsOfNames ve daha sonraki çağrıları için önbelleğe IDispatch::Invokealır. Bu şekilde pahalı dize araması, çağrı başına bir kez yerine nesne kullanımı başına IDispatch::Invoke yalnızca bir kez yapılır.

MFC, her yöntem ve özellik için DISPID'leri iki şeye göre belirler:

  • Gönderim haritasının en üstünden uzaklık (1 göreli)

  • Dağıtım eşlemesinin en çok türetilen sınıftan uzaklığı (0 göreli)

DISPID iki bölüme ayrılır. DISPID'nin LOWORD değeri, dağıtım eşlemesinin en üstünden uzaklık olan ilk bileşeni içerir. HIWORD, en türetilmiş sınıftan uzaklığı içerir. Örnek:

class CDispPoint : public CCmdTarget
{
public:
    short m_x, m_y;
    // ...
    DECLARE_DISPATCH_MAP()
    // ...
};

class CDisp3DPoint : public CDispPoint
{
public:
    short m_z;
    // ...
    DECLARE_DISPATCH_MAP()
    // ...
};

BEGIN_DISPATCH_MAP(CDispPoint, CCmdTarget)
    DISP_PROPERTY(CDispPoint, "x", m_x, VT_I2)
    DISP_PROPERTY(CDispPoint, "y", m_y, VT_I2)
END_DISPATCH_MAP()

BEGIN_DISPATCH_MAP(CDisp3DPoint, CDispPoint)
    DISP_PROPERTY(CDisp3DPoint, "z", m_z, VT_I2)
END_DISPATCH_MAP()

Gördüğünüz gibi, her ikisi de OLE otomasyon arabirimlerini kullanıma sunan iki sınıf vardır. Bu sınıflardan biri diğerinden türetilir ve bu nedenle OLE otomasyon bölümü ("x" ve "y" özellikleri dahil olmak üzere bu durumda temel sınıfın işlevselliğinden yararlanıyor.

MFC, CDispPoint sınıfı için DISPID'leriaşağıdaki gibi oluşturur:

property X    (DISPID)0x00000001
property Y    (DISPID)0x00000002

Özellikler bir temel sınıfta olmadığından, DISPID'nin HIWORD değeri her zaman sıfırdır (CDispPoint için en çok türetilen sınıftan uzaklık sıfırdır).

MFC, CDisp3DPoint sınıfı için DISPID'leriaşağıdaki gibi oluşturur:

property Z    (DISPID)0x00000001
property X    (DISPID)0x00010001
property Y    (DISPID)0x00010002

Z özelliğine, CDisp3DPoint özelliklerini ortaya çıkartan sınıfında tanımlandığından sıfır HIWORD içeren bir DISPID verilir. X ve Y özellikleri bir temel sınıfta tanımlandığından, bu özelliklerin tanımlandığı sınıf en türetilmiş sınıftan bir türetme uzaklığında olduğundan DISPID'nin HIWORD değeri 1'dir.

Dekont

LOWORD, haritada açık DISPID içeren girdiler olsa bile her zaman haritadaki konuma göre belirlenir (ve DISP_FUNCTION makrolarının _ID sürümleri hakkında bilgi için sonraki bölüme DISP_PROPERTY bakın).

Gelişmiş MFC Dağıtım Haritası Özellikleri

ClassWizard'ın Bu Visual C++ sürümünde desteklemediği bir dizi ek özellik vardır. ClassWizard, sırasıyla bir yöntemi, üye değişkeni özelliğini ve get/set member işlev özelliğini tanımlayan , DISP_PROPERTYve DISP_PROPERTY_EX 'yi desteklerDISP_FUNCTION. Bu özellikler genellikle çoğu otomasyon sunucusu oluşturmak için gereken özelliklerdir.

ClassWizard tarafından desteklenen makrolar yeterli olmadığında aşağıdaki ek makrolar kullanılabilir: DISP_PROPERTY_NOTIFYve DISP_PROPERTY_PARAM.

DISP_PROPERTY_NOTIFY — Makro Açıklaması

DISP_PROPERTY_NOTIFY(
    theClass,
    pszName,
    memberName,
    pfnAfterSet,
    vtPropType)

Parametreler

theClass
Sınıfın adı.

pszName
Özelliğin dış adı.

memberName
Özelliğin depolandığı üye değişkeninin adı.

pfnAfterSet
Özellik değiştirildiğinde çağrılacak üye işlevinin adı.

vtPropType
Özelliğin türünü belirten bir değer.

Açıklamalar

Bu makro DISP_PROPERTY çok benzer, ancak ek bir bağımsız değişken kabul eder. PfnAfterSet adlı ek bağımsız değişken , hiçbir şey döndüren ve 'void OnPropertyNotify()' parametresi almamış bir üye işlevi olmalıdır. Üye değişkeni değiştirildikten sonra çağrılır.

DISP_PROPERTY_PARAM — Makro Açıklaması

DISP_PROPERTY_PARAM(
    theClass,
    pszName,
    pfnGet,
    pfnSet,
    vtPropType,
    vtsParams)

Parametreler

theClass
Sınıfın adı.

pszName
Özelliğin dış adı.

memberGet
Özelliğini almak için kullanılan üye işlevinin adı.

memberSet
Özelliğini ayarlamak için kullanılan üye işlevinin adı.

vtPropType
Özelliğin türünü belirten bir değer.

vtsParams
Her parametre için ayrılmış bir boşluk dizesi VTS_.

Açıklamalar

DISP_PROPERTY_EX makroya çok benzer şekilde, bu makro da ayrı Get ve Set üye işlevleriyle erişilen bir özelliği tanımlar. Ancak bu makro özelliği için bir parametre listesi belirtmenize olanak tanır. Bu, dizine alınan veya başka bir şekilde parametrelendirilen özellikleri uygulamak için kullanışlıdır. Parametreler her zaman ilk sıraya yerleştirilir ve ardından özelliğin yeni değeri gösterilir. Örnek:

DISP_PROPERTY_PARAM(CMyObject, "item", GetItem, SetItem, VT_DISPATCH, VTS_I2 VTS_I2)

, üye işlevlerini alma ve ayarlamaya karşılık gelir:

LPDISPATCH CMyObject::GetItem(short row, short col)
void CMyObject::SetItem(short row, short col, LPDISPATCH newValue)

DISP_XXXX_ID — Makro Açıklamaları

DISP_FUNCTION_ID(
    theClass,
    pszName,
    dispid,
    pfnMember,
    vtRetVal,
    vtsParams)
DISP_PROPERTY_ID(
    theClass,
    pszName,
    dispid,
    memberName,
    vtPropType)
DISP_PROPERTY_NOTIFY_ID(
    theClass,
    pszName,
    dispid,
    memberName,
    pfnAfterSet,
    vtPropType)
DISP_PROPERTY_EX_ID(
    theClass,
    pszName,
    dispid,
    pfnGet,
    pfnSet,
    vtPropType)
DISP_PROPERTY_PARAM_ID(
    theClass,
    pszName,
    dispid,
    pfnGet,
    pfnSet,
    vtPropType,
    vtsParams)

Parametreler

theClass
Sınıfın adı.

pszName
Özelliğin dış adı.

Dıspıd
Özellik veya yöntem için sabit DISPID.

pfnGet
Özelliğini almak için kullanılan üye işlevinin adı.

pfnSet
Özelliğini ayarlamak için kullanılan üye işlevinin adı.

memberName
Özelliğine eşlenecek üye değişkeninin adı

vtPropType
Özelliğin türünü belirten bir değer.

vtsParams
Her parametre için ayrılmış bir boşluk dizesi VTS_.

Açıklamalar

Bu makrolar, MFC'nin otomatik olarak bir tane atamasına izin vermek yerine bir DISPID belirtmenize olanak sağlar. Bu gelişmiş makrolar, makro adına kimlik eklenmesi (örn. DISP_PROPERTY_ID) dışında aynı adlara sahiptir ve kimlik pszName parametresinden hemen sonra belirtilen parametre tarafından belirlenir. Bkz. AFXDISP. Bu makrolar hakkında daha fazla bilgi için H. _ID girişleri dağıtım eşlemesinin sonuna yerleştirilmelidir. Otomatik DISPID oluşturma işlemini makronun _ID olmayan bir sürümüyle aynı şekilde etkiler (DISPID'lerkonuma göre belirlenir). Örnek:

BEGIN_DISPATCH_MAP(CDisp3DPoint, CCmdTarget)
    DISP_PROPERTY(CDisp3DPoint, "y", m_y, VT_I2)
    DISP_PROPERTY(CDisp3DPoint, "z", m_z, VT_I2)
    DISP_PROPERTY_ID(CDisp3DPoint, "x", 0x00020003, m_x, VT_I2)
END_DISPATCH_MAP()

MFC, CDisp3DPoint sınıfı için DISPID'leri aşağıdaki gibi oluşturur:

property X    (DISPID)0x00020003
property Y    (DISPID)0x00000002
property Z    (DISPID)0x00000001

Sabit bir DISPID belirtmek, daha önce var olan bir dağıtım arabirimiyle geriye dönük uyumluluğu korumak veya belirli sistem tanımlı yöntemleri veya özellikleri (genellikle DISPID_NEWENUM koleksiyonu gibi negatif bir DISPID ile gösterilir) uygulamak için yararlıdır.

COleClientItem için IDispatch Arabirimini Alma

Birçok sunucu, OLE sunucusu işlevselliğiyle birlikte belge nesneleri içinde otomasyonu destekleyecektir. Bu otomasyon arabirimine erişim elde etmek için üye değişkenine COleClientItem::m_lpObject doğrudan erişmek gerekir. Aşağıdaki kod, öğesinden COleClientItemtüretilen bir nesnenin arabirimini alırIDispatch. Bu işlevin gerekli olduğunu düşünüyorsanız aşağıdaki kodu uygulamanıza ekleyebilirsiniz:

LPDISPATCH CMyClientItem::GetIDispatch()
{
    ASSERT_VALID(this);
    ASSERT(m_lpObject != NULL);

    LPUNKNOWN lpUnk = m_lpObject;

    Run();      // must be running

    LPOLELINK lpOleLink = NULL;
    if (m_lpObject->QueryInterface(IID_IOleLink,
        (LPVOID FAR*)&lpOleLink) == NOERROR)
    {
        ASSERT(lpOleLink != NULL);
        lpUnk = NULL;
        if (lpOleLink->GetBoundSource(&lpUnk) != NOERROR)
        {
            TRACE0("Warning: Link is not connected!\n");
            lpOleLink->Release();
            return NULL;
        }
        ASSERT(lpUnk != NULL);
    }

    LPDISPATCH lpDispatch = NULL;
    if (lpUnk->QueryInterface(IID_IDispatch, &lpDispatch) != NOERROR)
    {
        TRACE0("Warning: does not support IDispatch!\n");
        return NULL;
    }

    ASSERT(lpDispatch != NULL);
    return lpDispatch;
}

Bu işlevden döndürülen dağıtım arabirimi daha sonra doğrudan kullanılabilir veya türü güvenli erişim için öğesine COleDispatchDriver eklenebilir. Doğrudan kullanırsanız, işaretçi ile üzerinden geçtiğinde üyesini Release çağırdığınızdan COleDispatchDriver emin olun (yıkıcı bunu varsayılan olarak yapar).

Ayrıca bkz.

Sayıya Göre Teknik Notlar
Kategoriye Göre Teknik Notlar