mshtml: Added support for connection point HTML notification.
This commit is contained in:
parent
19415addec
commit
1c5c822b07
|
@ -198,7 +198,7 @@ static const IConnectionPointVtbl ConnectionPointVtbl =
|
|||
ConnectionPoint_EnumConnections
|
||||
};
|
||||
|
||||
void ConnectionPoint_Init(ConnectionPoint *cp, ConnectionPointContainer *container, REFIID riid)
|
||||
void ConnectionPoint_Init(ConnectionPoint *cp, ConnectionPointContainer *container, REFIID riid, cp_static_data_t *data)
|
||||
{
|
||||
cp->lpConnectionPointVtbl = &ConnectionPointVtbl;
|
||||
cp->container = CONPTCONT(container);
|
||||
|
@ -206,6 +206,7 @@ void ConnectionPoint_Init(ConnectionPoint *cp, ConnectionPointContainer *contain
|
|||
cp->sinks_size = 0;
|
||||
cp->iid = riid;
|
||||
cp->next = NULL;
|
||||
cp->data = data;
|
||||
|
||||
cp->next = container->cp_list;
|
||||
container->cp_list = cp;
|
||||
|
|
|
@ -103,6 +103,7 @@ static REFIID tid_ids[] = {
|
|||
&DIID_DispHTMLTableRow,
|
||||
&DIID_DispHTMLUnknownElement,
|
||||
&DIID_DispHTMLWindow2,
|
||||
&DIID_HTMLDocumentEvents,
|
||||
&IID_IHTMLAnchorElement,
|
||||
&IID_IHTMLBodyElement,
|
||||
&IID_IHTMLBodyElement2,
|
||||
|
@ -304,6 +305,61 @@ static dispex_data_t *preprocess_dispex_data(DispatchEx *This)
|
|||
return data;
|
||||
}
|
||||
|
||||
static int id_cmp(const void *p1, const void *p2)
|
||||
{
|
||||
return *(DISPID*)p1 - *(DISPID*)p2;
|
||||
}
|
||||
|
||||
HRESULT get_dispids(tid_t tid, DWORD *ret_size, DISPID **ret)
|
||||
{
|
||||
unsigned i, func_cnt;
|
||||
FUNCDESC *funcdesc;
|
||||
ITypeInfo *ti;
|
||||
TYPEATTR *attr;
|
||||
DISPID *ids;
|
||||
HRESULT hres;
|
||||
|
||||
hres = get_typeinfo(tid, &ti);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
hres = ITypeInfo_GetTypeAttr(ti, &attr);
|
||||
if(FAILED(hres)) {
|
||||
ITypeInfo_Release(ti);
|
||||
return hres;
|
||||
}
|
||||
|
||||
func_cnt = attr->cFuncs;
|
||||
ITypeInfo_ReleaseTypeAttr(ti, attr);
|
||||
|
||||
ids = heap_alloc(func_cnt*sizeof(DISPID));
|
||||
if(!ids) {
|
||||
ITypeInfo_Release(ti);
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
for(i=0; i < func_cnt; i++) {
|
||||
hres = ITypeInfo_GetFuncDesc(ti, i, &funcdesc);
|
||||
if(FAILED(hres))
|
||||
break;
|
||||
|
||||
ids[i] = funcdesc->memid;
|
||||
ITypeInfo_ReleaseFuncDesc(ti, funcdesc);
|
||||
}
|
||||
|
||||
ITypeInfo_Release(ti);
|
||||
if(FAILED(hres)) {
|
||||
heap_free(ids);
|
||||
return hres;
|
||||
}
|
||||
|
||||
qsort(ids, func_cnt, sizeof(DISPID), id_cmp);
|
||||
|
||||
*ret_size = func_cnt;
|
||||
*ret = ids;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static CRITICAL_SECTION cs_dispex_static_data;
|
||||
static CRITICAL_SECTION_DEBUG cs_dispex_static_data_dbg =
|
||||
{
|
||||
|
|
|
@ -771,7 +771,7 @@ HTMLElement *HTMLBodyElement_Create(HTMLDocumentNode *doc, nsIDOMHTMLElement *ns
|
|||
|
||||
HTMLTextContainer_Init(&ret->textcont, doc, nselem, &HTMLBodyElement_dispex);
|
||||
|
||||
ConnectionPoint_Init(&ret->cp_propnotif, &ret->textcont.element.cp_container, &IID_IPropertyNotifySink);
|
||||
ConnectionPoint_Init(&ret->cp_propnotif, &ret->textcont.element.cp_container, &IID_IPropertyNotifySink, NULL);
|
||||
|
||||
nsres = nsIDOMHTMLElement_QueryInterface(nselem, &IID_nsIDOMHTMLBodyElement,
|
||||
(void**)&ret->nsbody);
|
||||
|
|
|
@ -1706,6 +1706,8 @@ static BOOL htmldoc_qi(HTMLDocument *This, REFIID riid, void **ppv)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static cp_static_data_t HTMLDocumentEvents_data = { HTMLDocumentEvents_tid };
|
||||
|
||||
static void init_doc(HTMLDocument *doc, IUnknown *unk_impl, IDispatchEx *dispex)
|
||||
{
|
||||
doc->lpHTMLDocument2Vtbl = &HTMLDocumentVtbl;
|
||||
|
@ -1727,9 +1729,9 @@ static void init_doc(HTMLDocument *doc, IUnknown *unk_impl, IDispatchEx *dispex)
|
|||
HTMLDocument_Hlink_Init(doc);
|
||||
|
||||
ConnectionPointContainer_Init(&doc->cp_container, (IUnknown*)HTMLDOC(doc));
|
||||
ConnectionPoint_Init(&doc->cp_propnotif, &doc->cp_container, &IID_IPropertyNotifySink);
|
||||
ConnectionPoint_Init(&doc->cp_htmldocevents, &doc->cp_container, &DIID_HTMLDocumentEvents);
|
||||
ConnectionPoint_Init(&doc->cp_htmldocevents2, &doc->cp_container, &DIID_HTMLDocumentEvents2);
|
||||
ConnectionPoint_Init(&doc->cp_propnotif, &doc->cp_container, &IID_IPropertyNotifySink, NULL);
|
||||
ConnectionPoint_Init(&doc->cp_htmldocevents, &doc->cp_container, &DIID_HTMLDocumentEvents, &HTMLDocumentEvents_data);
|
||||
ConnectionPoint_Init(&doc->cp_htmldocevents2, &doc->cp_container, &DIID_HTMLDocumentEvents2, NULL);
|
||||
}
|
||||
|
||||
static void destroy_htmldoc(HTMLDocument *This)
|
||||
|
@ -1839,6 +1841,7 @@ HRESULT create_doc_from_nsdoc(nsIDOMHTMLDocument *nsdoc, HTMLDocumentObj *doc_ob
|
|||
|
||||
HTMLDOMNode_Init(doc, &doc->node, (nsIDOMNode*)nsdoc);
|
||||
doc->node.vtbl = &HTMLDocumentNodeImplVtbl;
|
||||
doc->node.cp_container = &doc->basedoc.cp_container;
|
||||
|
||||
hres = CoInternetCreateSecurityManager(NULL, &doc->secmgr, 0);
|
||||
if(FAILED(hres)) {
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "winbase.h"
|
||||
#include "winuser.h"
|
||||
#include "ole2.h"
|
||||
#include "mshtmdid.h"
|
||||
|
||||
#include "mshtml_private.h"
|
||||
#include "htmlevent.h"
|
||||
|
@ -118,6 +119,7 @@ typedef struct {
|
|||
LPCWSTR name;
|
||||
LPCWSTR attr_name;
|
||||
DWORD type;
|
||||
DISPID dispid;
|
||||
DWORD flags;
|
||||
} event_info_t;
|
||||
|
||||
|
@ -126,24 +128,42 @@ typedef struct {
|
|||
#define EVENT_FORWARDBODY 0x0004
|
||||
|
||||
static const event_info_t event_info[] = {
|
||||
{beforeunloadW, onbeforeunloadW, EVENTT_NONE, EVENT_DEFAULTLISTENER|EVENT_FORWARDBODY},
|
||||
{blurW, onblurW, EVENTT_HTML, EVENT_DEFAULTLISTENER},
|
||||
{changeW, onchangeW, EVENTT_HTML, EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
|
||||
{clickW, onclickW, EVENTT_MOUSE, EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
|
||||
{dblclickW, ondblclickW, EVENTT_MOUSE, EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
|
||||
{dragW, ondragW, EVENTT_MOUSE, 0},
|
||||
{dragstartW, ondragstartW, EVENTT_MOUSE, 0},
|
||||
{focusW, onfocusW, EVENTT_HTML, EVENT_DEFAULTLISTENER},
|
||||
{keydownW, onkeydownW, EVENTT_KEY, EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
|
||||
{keyupW, onkeyupW, EVENTT_KEY, EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
|
||||
{loadW, onloadW, EVENTT_HTML, 0},
|
||||
{mousedownW, onmousedownW, EVENTT_MOUSE, EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
|
||||
{mouseoutW, onmouseoutW, EVENTT_MOUSE, EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
|
||||
{mouseoverW, onmouseoverW, EVENTT_MOUSE, EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
|
||||
{mouseupW, onmouseupW, EVENTT_MOUSE, EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
|
||||
{pasteW, onpasteW, EVENTT_NONE, 0},
|
||||
{readystatechangeW, onreadystatechangeW, EVENTT_NONE, 0},
|
||||
{selectstartW, onselectstartW, EVENTT_MOUSE, 0}
|
||||
{beforeunloadW, onbeforeunloadW, EVENTT_NONE, DISPID_EVMETH_ONBEFOREUNLOAD,
|
||||
EVENT_DEFAULTLISTENER|EVENT_FORWARDBODY},
|
||||
{blurW, onblurW, EVENTT_HTML, DISPID_EVMETH_ONBLUR,
|
||||
EVENT_DEFAULTLISTENER},
|
||||
{changeW, onchangeW, EVENTT_HTML, DISPID_EVMETH_ONCHANGE,
|
||||
EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
|
||||
{clickW, onclickW, EVENTT_MOUSE, DISPID_EVMETH_ONCLICK,
|
||||
EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
|
||||
{dblclickW, ondblclickW, EVENTT_MOUSE, DISPID_EVMETH_ONDBLCLICK,
|
||||
EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
|
||||
{dragW, ondragW, EVENTT_MOUSE, DISPID_EVMETH_ONDRAG,
|
||||
0},
|
||||
{dragstartW, ondragstartW, EVENTT_MOUSE, DISPID_EVMETH_ONDRAGSTART,
|
||||
0},
|
||||
{focusW, onfocusW, EVENTT_HTML, DISPID_EVMETH_ONFOCUS,
|
||||
EVENT_DEFAULTLISTENER},
|
||||
{keydownW, onkeydownW, EVENTT_KEY, DISPID_EVMETH_ONKEYDOWN,
|
||||
EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
|
||||
{keyupW, onkeyupW, EVENTT_KEY, DISPID_EVMETH_ONKEYUP,
|
||||
EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
|
||||
{loadW, onloadW, EVENTT_HTML, DISPID_EVMETH_ONLOAD,
|
||||
0},
|
||||
{mousedownW, onmousedownW, EVENTT_MOUSE, DISPID_EVMETH_ONMOUSEDOWN,
|
||||
EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
|
||||
{mouseoutW, onmouseoutW, EVENTT_MOUSE, DISPID_EVMETH_ONMOUSEOUT,
|
||||
EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
|
||||
{mouseoverW, onmouseoverW, EVENTT_MOUSE, DISPID_EVMETH_ONMOUSEOVER,
|
||||
EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
|
||||
{mouseupW, onmouseupW, EVENTT_MOUSE, DISPID_EVMETH_ONMOUSEUP,
|
||||
EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
|
||||
{pasteW, onpasteW, EVENTT_NONE, DISPID_EVMETH_ONPASTE,
|
||||
0},
|
||||
{readystatechangeW, onreadystatechangeW, EVENTT_NONE, DISPID_EVMETH_ONREADYSTATECHANGE,
|
||||
0},
|
||||
{selectstartW, onselectstartW, EVENTT_MOUSE, DISPID_EVMETH_ONSELECTSTART,
|
||||
0}
|
||||
};
|
||||
|
||||
eventid_t str_to_eid(LPCWSTR str)
|
||||
|
@ -738,17 +758,68 @@ static IHTMLEventObj *create_event(HTMLDOMNode *target, eventid_t eid, nsIDOMEve
|
|||
return HTMLEVENTOBJ(ret);
|
||||
}
|
||||
|
||||
static void call_event_handlers(HTMLDocumentNode *doc, IHTMLEventObj *event_obj, event_target_t *event_target,
|
||||
eventid_t eid, IDispatch *this_obj)
|
||||
static HRESULT call_cp_func(IDispatch *disp, DISPID dispid)
|
||||
{
|
||||
handler_vector_t *handler_vector;
|
||||
DISPPARAMS dp = {NULL,NULL,0,0};
|
||||
ULONG argerr;
|
||||
EXCEPINFO ei;
|
||||
VARIANT vres;
|
||||
HRESULT hres;
|
||||
|
||||
V_VT(&vres) = VT_EMPTY;
|
||||
memset(&ei, 0, sizeof(ei));
|
||||
hres = IDispatch_Invoke(disp, dispid, &IID_NULL, 0, DISPATCH_METHOD, &dp, &vres, &ei, &argerr);
|
||||
if(SUCCEEDED(hres) && V_VT(&vres) != VT_EMPTY) {
|
||||
FIXME("handle result %s\n", debugstr_variant(&vres));
|
||||
VariantClear(&vres);
|
||||
}
|
||||
|
||||
return hres;
|
||||
}
|
||||
|
||||
static BOOL is_cp_event(ConnectionPoint *cp, DISPID dispid)
|
||||
{
|
||||
cp_static_data_t *data;
|
||||
unsigned min, max, i;
|
||||
HRESULT hres;
|
||||
|
||||
data = cp->data;
|
||||
if(!data)
|
||||
return FALSE;
|
||||
|
||||
if(!data->ids) {
|
||||
hres = get_dispids(data->tid, &data->id_cnt, &data->ids);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
}
|
||||
|
||||
min = 0;
|
||||
max = data->id_cnt;
|
||||
while(min <= max) {
|
||||
i = (min+max)/2;
|
||||
if(data->ids[i] == dispid)
|
||||
return TRUE;
|
||||
|
||||
if(data->ids[i] < dispid)
|
||||
min = i+1;
|
||||
else
|
||||
max = i-1;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void call_event_handlers(HTMLDocumentNode *doc, IHTMLEventObj *event_obj, event_target_t *event_target,
|
||||
ConnectionPointContainer *cp_container, eventid_t eid, IDispatch *this_obj)
|
||||
{
|
||||
handler_vector_t *handler_vector = NULL;
|
||||
DWORD i;
|
||||
HRESULT hres;
|
||||
|
||||
if(!event_target || !(handler_vector = event_target->event_table[eid]))
|
||||
return;
|
||||
if(event_target)
|
||||
handler_vector = event_target->event_table[eid];
|
||||
|
||||
if(handler_vector->handler_prop) {
|
||||
if(handler_vector && handler_vector->handler_prop) {
|
||||
DISPID named_arg = DISPID_THIS;
|
||||
VARIANTARG arg;
|
||||
DISPPARAMS dp = {&arg, &named_arg, 1, 1};
|
||||
|
@ -764,7 +835,7 @@ static void call_event_handlers(HTMLDocumentNode *doc, IHTMLEventObj *event_obj,
|
|||
WARN("%s <<< %08x\n", debugstr_w(event_info[eid].name), hres);
|
||||
}
|
||||
|
||||
if(handler_vector->handler_cnt) {
|
||||
if(handler_vector && handler_vector->handler_cnt) {
|
||||
VARIANTARG arg;
|
||||
DISPPARAMS dp = {&arg, NULL, 1, 0};
|
||||
|
||||
|
@ -782,6 +853,26 @@ static void call_event_handlers(HTMLDocumentNode *doc, IHTMLEventObj *event_obj,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(cp_container) {
|
||||
ConnectionPoint *cp;
|
||||
|
||||
if(cp_container->forward_container)
|
||||
cp_container = cp_container->forward_container;
|
||||
|
||||
for(cp = cp_container->cp_list; cp; cp = cp->next) {
|
||||
if(cp->sinks_size && is_cp_event(cp, event_info[eid].dispid)) {
|
||||
for(i=0; i < cp->sinks_size; i++) {
|
||||
TRACE("cp %s [%d] >>>\n", debugstr_w(event_info[eid].name), i);
|
||||
hres = call_cp_func(cp->sinks[i].disp, event_info[eid].dispid);
|
||||
if(hres == S_OK)
|
||||
TRACE("cp %s [%d] <<<\n", debugstr_w(event_info[eid].name), i);
|
||||
else
|
||||
WARN("cp %s [%d] <<< %08x\n", debugstr_w(event_info[eid].name), i, hres);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void fire_event(HTMLDocumentNode *doc, eventid_t eid, nsIDOMNode *target, nsIDOMEvent *nsevent)
|
||||
|
@ -805,7 +896,8 @@ void fire_event(HTMLDocumentNode *doc, eventid_t eid, nsIDOMNode *target, nsIDOM
|
|||
do {
|
||||
node = get_node(doc, nsnode, FALSE);
|
||||
if(node)
|
||||
call_event_handlers(doc, event_obj, *get_node_event_target(node), eid, (IDispatch*)HTMLDOMNODE(node));
|
||||
call_event_handlers(doc, event_obj, *get_node_event_target(node), node->cp_container, eid,
|
||||
(IDispatch*)HTMLDOMNODE(node));
|
||||
|
||||
if(!(event_info[eid].flags & EVENT_BUBBLE))
|
||||
break;
|
||||
|
@ -831,14 +923,15 @@ void fire_event(HTMLDocumentNode *doc, eventid_t eid, nsIDOMNode *target, nsIDOM
|
|||
if(NS_SUCCEEDED(nsres) && nsbody) {
|
||||
node = get_node(doc, (nsIDOMNode*)nsbody, FALSE);
|
||||
if(node)
|
||||
call_event_handlers(doc, event_obj, *get_node_event_target(node), eid, (IDispatch*)HTMLDOMNODE(node));
|
||||
call_event_handlers(doc, event_obj, *get_node_event_target(node), node->cp_container,
|
||||
eid, (IDispatch*)HTMLDOMNODE(node));
|
||||
nsIDOMHTMLElement_Release(nsbody);
|
||||
}else {
|
||||
ERR("Could not get body: %08x\n", nsres);
|
||||
}
|
||||
}
|
||||
|
||||
call_event_handlers(doc, event_obj, doc->basedoc.doc_node->node.event_target, eid,
|
||||
call_event_handlers(doc, event_obj, doc->basedoc.doc_node->node.event_target, &doc->basedoc.cp_container, eid,
|
||||
(IDispatch*)HTMLDOC(&doc->basedoc));
|
||||
break;
|
||||
|
||||
|
|
|
@ -584,7 +584,7 @@ HTMLElement *HTMLTable_Create(HTMLDocumentNode *doc, nsIDOMHTMLElement *nselem)
|
|||
|
||||
HTMLElement_Init(&ret->element, doc, nselem, &HTMLTable_dispex);
|
||||
|
||||
ConnectionPoint_Init(&ret->cp, &ret->element.cp_container, &DIID_HTMLTableEvents);
|
||||
ConnectionPoint_Init(&ret->cp, &ret->element.cp_container, &DIID_HTMLTableEvents, NULL);
|
||||
|
||||
nsres = nsIDOMHTMLElement_QueryInterface(nselem, &IID_nsIDOMHTMLTableElement, (void**)&ret->nstable);
|
||||
if(NS_FAILED(nsres))
|
||||
|
|
|
@ -189,5 +189,5 @@ void HTMLTextContainer_Init(HTMLTextContainer *This, HTMLDocumentNode *doc, nsID
|
|||
|
||||
HTMLElement_Init(&This->element, doc, nselem, dispex_data);
|
||||
|
||||
ConnectionPoint_Init(&This->cp, &This->element.cp_container, &DIID_HTMLTextContainerEvents);
|
||||
ConnectionPoint_Init(&This->cp, &This->element.cp_container, &DIID_HTMLTextContainerEvents, NULL);
|
||||
}
|
||||
|
|
|
@ -80,6 +80,7 @@ typedef enum {
|
|||
DispHTMLTableRow_tid,
|
||||
DispHTMLUnknownElement_tid,
|
||||
DispHTMLWindow2_tid,
|
||||
HTMLDocumentEvents_tid,
|
||||
IHTMLAnchorElement_tid,
|
||||
IHTMLBodyElement_tid,
|
||||
IHTMLBodyElement2_tid,
|
||||
|
@ -158,6 +159,7 @@ void init_dispex(DispatchEx*,IUnknown*,dispex_static_data_t*);
|
|||
void release_dispex(DispatchEx*);
|
||||
BOOL dispex_query_interface(DispatchEx*,REFIID,void**);
|
||||
HRESULT dispex_get_dprop_ref(DispatchEx*,const WCHAR*,BOOL,VARIANT**);
|
||||
HRESULT get_dispids(tid_t,DWORD*,DISPID**);
|
||||
|
||||
typedef struct HTMLDocumentNode HTMLDocumentNode;
|
||||
typedef struct HTMLDocumentObj HTMLDocumentObj;
|
||||
|
@ -261,6 +263,12 @@ typedef enum {
|
|||
EDITMODE
|
||||
} USERMODE;
|
||||
|
||||
typedef struct {
|
||||
tid_t tid;
|
||||
DWORD id_cnt;
|
||||
DISPID *ids;
|
||||
} cp_static_data_t;
|
||||
|
||||
typedef struct ConnectionPointContainer {
|
||||
const IConnectionPointContainerVtbl *lpConnectionPointContainerVtbl;
|
||||
|
||||
|
@ -282,6 +290,7 @@ struct ConnectionPoint {
|
|||
DWORD sinks_size;
|
||||
|
||||
const IID *iid;
|
||||
cp_static_data_t *data;
|
||||
|
||||
ConnectionPoint *next;
|
||||
};
|
||||
|
@ -449,6 +458,7 @@ struct HTMLDOMNode {
|
|||
nsIDOMNode *nsnode;
|
||||
HTMLDocumentNode *doc;
|
||||
event_target_t *event_target;
|
||||
ConnectionPointContainer *cp_container;
|
||||
|
||||
HTMLDOMNode *next;
|
||||
};
|
||||
|
@ -620,7 +630,7 @@ void HTMLDocumentNode_SecMgr_Init(HTMLDocumentNode*);
|
|||
|
||||
HRESULT HTMLCurrentStyle_Create(HTMLElement*,IHTMLCurrentStyle**);
|
||||
|
||||
void ConnectionPoint_Init(ConnectionPoint*,ConnectionPointContainer*,REFIID);
|
||||
void ConnectionPoint_Init(ConnectionPoint*,ConnectionPointContainer*,REFIID,cp_static_data_t*);
|
||||
void ConnectionPointContainer_Init(ConnectionPointContainer*,IUnknown*);
|
||||
void ConnectionPointContainer_Destroy(ConnectionPointContainer*);
|
||||
|
||||
|
|
Loading…
Reference in New Issue