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::Invoke
için "dağıtım haritalarını" kullanır. Dağıtım eşlemesi, türetilmiş sınıflarınızın CCmdTarget
dü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::GetIDsOfNames
aracı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::Invoke
alı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_PROPERTY
ve 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_NOTIFY
ve 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 COleClientItem
tü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).