Как будто вы пытаетесь получить доступ к объекту, который является null
. Рассмотрим ниже пример:
TypeA objA;
. В это время вы только что объявили этот объект, но не инициализировали или не инициализировали. И всякий раз, когда вы пытаетесь получить доступ к каким-либо свойствам или методам в нем, он будет генерировать NullPointerException
, что имеет смысл.
См. Также этот пример:
String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
Это - то, как я сделал это просто недавно. Добавьте интерфейс, который реализует IDispatch и coclass для того интерфейса к Вашему IDL:
[
object,
uuid(6EDA5438-0915-4183-841D-D3F0AEDFA466),
nonextensible,
oleautomation,
pointer_default(unique)
]
interface IServerEvents : IDispatch
{
[id(1)]
HRESULT OnServerEvent();
}
//...
[
uuid(FA8F24B3-1751-4D44-8258-D649B6529494),
]
coclass ServerEvents
{
[default] interface IServerEvents;
[default, source] dispinterface IServerEvents;
};
Это - объявление класса CServerEvents:
class ATL_NO_VTABLE CServerEvents :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CServerEvents, &CLSID_ServerEvents>,
public IDispatchImpl<IServerEvents, &IID_IServerEvents , &LIBID_YourLibrary, -1, -1>,
public IConnectionPointContainerImpl<CServerEvents>,
public IConnectionPointImpl<CServerEvents,&__uuidof(IServerEvents)>
{
public:
CServerEvents()
{
}
// ...
BEGIN_COM_MAP(CServerEvents)
COM_INTERFACE_ENTRY(IServerEvents)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(IConnectionPointContainer)
END_COM_MAP()
BEGIN_CONNECTION_POINT_MAP(CServerEvents)
CONNECTION_POINT_ENTRY(__uuidof(IServerEvents))
END_CONNECTION_POINT_MAP()
// ..
// IServerEvents
STDMETHOD(OnServerEvent)();
private:
CRITICAL_SECTION m_csLock;
};
Ключ здесь является реализацией интерфейсов IConnectionPointImpl и IConnectionPointContainerImpl и карты точки подключения. Определение метода OnServerEvent похоже на это:
STDMETHODIMP CServerEvents::OnServerEvent()
{
::EnterCriticalSection( &m_csLock );
IUnknown* pUnknown;
for ( unsigned i = 0; ( pUnknown = m_vec.GetAt( i ) ) != NULL; ++i )
{
CComPtr<IDispatch> spDisp;
pUnknown->QueryInterface( &spDisp );
if ( spDisp )
{
spDisp.Invoke0( CComBSTR( L"OnServerEvent" ) );
}
}
::LeaveCriticalSection( &m_csLock );
return S_OK;
}
Необходимо позволить, чтобы клиент указал их обработчик для событий. Можно сделать это со специализированным методом как "SetHandler" или что-то, но я предпочитаю делать обработчик аргументом методу, который называют асинхронно. Таким образом, пользователь только должен назвать один метод:
STDMETHOD(DoSomethingAsynchronous)( IServerEvents *pCallback );
Сохраните указатель на IServerEvents, и затем когда Вы хотите запустить свое событие, просто назовите метод:
m_pCallback->OnServerEvent();
Что касается кода VB, синтаксис для контакта с событиями немного отличается, чем, что Вы предложили:
Private m_server As Server
Private WithEvents m_serverEvents As ServerEvents
Private Sub MainMethod()
Set s = CreateObject("Server")
Set m_serverEvents = New ServerEvents
Call m_searchService.DoSomethingAsynchronous(m_serverEvents)
End Sub
Private Sub m_serverEvents_OnServerEvent()
MsgBox "Event handled"
End Sub
Я надеюсь, что это помогает.
Я являюсь немного туманным в деталях, но возможно ссылка ниже могла бы помочь:
http://msdn.microsoft.com/en-us/library/ms974564.aspx
Похоже, что Ваш серверный объект должен реализовать IProvideClassInfo
и затем Вы звоните ConnectObject
в Вашем коде VBScript.См. также:
http://blogs.msdn.com/ericlippert/archive/2005/02/15/373330.aspx