VS2019,新建ATL project.
名字ATLFindServer
在解决方案资源管理器里右键ATLFindServer工程,添加新项目
选择ATL 简单对象ATLFindObject,创建在启动里面,勾选“连接点”
在类视图里,接口IATLFindObject右键添加方法FindObject,参数BSTR name,如下图:
在ATLFindServer.idl中IATLFIndObjectEvents中添加NotifyFindObject函数
然后再_IATLFindObjectEvents_CP.h中添加函数Fire_NotifyFindObject,代码见图下方代码
HRESULT Fire_NotifyFindObject(BSTR name)
{
T* pT = static_cast<T*>(this);
int nConnectionIndex;
CComVariant* pvars = new CComVariant[2];
int nConnections = m_vec.GetSize();
for (nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++)
{
pT->Lock();
CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex);
pT->Unlock();
IDispatch* pDispatch = reinterpret_cast<IDispatch*>(sp.p);
if (pDispatch != NULL)
{
pvars[0].vt = VT_BSTR;
pvars[0].bstrVal = name;
DISPPARAMS disp = { pvars, NULL, 1, 0 };
pDispatch->Invoke(0x1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, NULL, NULL, NULL);
}
}
delete[] pvars;
return S_OK;
}
在ATLFindObject.h中添加方法
void FindSomethingToClient(BSTR name);
在ATLFindObject.h中添加实现:
#include <thread>
// CATLFindObject
void CATLFindObject::FindSomethingToClient(BSTR name)
{
WIN32_FIND_DATA ffd;
LARGE_INTEGER filesize;
TCHAR szDir[MAX_PATH];
size_t length_of_arg;
HANDLE hFind = INVALID_HANDLE_VALUE;
DWORD dwError = 0;
// If the directory is not specified as a command-line argument,
// print usage.
// Find the first file in the directory.
hFind = FindFirstFile(name, &ffd);
if (INVALID_HANDLE_VALUE == hFind)
{
CComBSTR a(TEXT("FindFirstFile invalid."));
Fire_NotifyFindObject(a);
return;
}
// List all the files in the directory with some info about them.
do
{
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
_tprintf(TEXT(" %s <DIR>\n"), ffd.cFileName);
}
else
{
CComBSTR a(ffd.cFileName);
Fire_NotifyFindObject(a);
}
} while (FindNextFile(hFind, &ffd) != 0);
CComBSTR a(TEXT("FindFirstFile end."));
Fire_NotifyFindObject(a);
FindClose(hFind);
return;
}
STDMETHODIMP CATLFindObject::FindObject(BSTR name)
{
// TODO: 在此处添加实现代码
//std::thread a(&CATLFindObject::FindSomethingToClient, this, name);
//a.detach();
FindSomethingToClient(name);
return S_OK;
}
编译,至此server建立完毕,管理员身份运行以下命令注册server。
/RegServer
建立客户端进行测试,建立TestAtlFindServer
修改代码,添加EventSink和main函数。EventSink是回调的代码。main来调用server,并注册回调。
#include <iostream>
#include <atlcomcli.h>
#include "../ATLFindServer/ATLFindServer_i.h"
#include "../ATLFindServer/ATLFindServer_i.c"
struct EventSink : _IATLFindObjectEvents
{
virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount(__RPC__out UINT* pctinfo)
{
return E_NOTIMPL;
}
virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT iTInfo, LCID lcid, __RPC__deref_out_opt ITypeInfo** ppTInfo)
{
return E_NOTIMPL;
}
virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames(__RPC__in REFIID riid, __RPC__in_ecount_full(cNames) LPOLESTR* rgszNames, __RPC__in_range(0, 16384) UINT cNames, LCID lcid, __RPC__out_ecount_full(cNames) DISPID* rgDispId)
{
return E_NOTIMPL;
}
virtual HRESULT STDMETHODCALLTYPE Invoke(_In_ DISPID dispIdMember, _In_ REFIID riid, _In_ LCID lcid, _In_ WORD wFlags, _In_ DISPPARAMS* pDispParams, _Out_opt_ VARIANT* pVarResult, _Out_opt_ EXCEPINFO* pExcepInfo, _Out_opt_ UINT* puArgErr)
{
if (pDispParams->cArgs >= 1 && pDispParams->rgvarg[0].vt == VT_BSTR)
std::cout << CW2A(pDispParams->rgvarg[0].bstrVal) << std::endl;
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject)
{
if (!ppvObject)
return E_POINTER;
if (IsEqualIID(riid, IID_IUnknown))
*ppvObject = (IUnknown*)this;
else if (IsEqualIID(riid, DIID__IATLFindObjectEvents))
*ppvObject = (_IATLFindObjectEvents*)this;
else
return E_NOTIMPL;
((IUnknown*)(*ppvObject))->AddRef();
return S_OK;
}
virtual ULONG STDMETHODCALLTYPE AddRef(void)
{
return 2;
}
virtual ULONG STDMETHODCALLTYPE Release(void)
{
return 1;
}
};
int main()
{
//std::cout << "Hello World!\n";
CoInitialize(NULL);
{
CComPtr<IDispatch> pDisp;
if (FAILED(CoCreateInstance(CLSID_ATLFindObject, NULL, CLSCTX_LOCAL_SERVER, IID_IDispatch, (void**)&pDisp)))
return 0;
CComPtr<IConnectionPointContainer> pContainer;
pContainer = pDisp;
CComPtr<IConnectionPoint> pConnectionPoint;
//pFind->QueryInterface(&pConnectionPoint);
pContainer->FindConnectionPoint(DIID__IATLFindObjectEvents, &pConnectionPoint);
EventSink es;
DWORD cookie;
pConnectionPoint->Advise(&es, &cookie);
CComPtr<IATLFindObject> pFind;
if (SUCCEEDED(pDisp->QueryInterface(&pFind)))
{
CComBSTR folder(L"c:\\temp\\*");
pFind->FindObject(folder);
}
}
CoUninitialize();
}