Skip to content

Instantly share code, notes, and snippets.

@SaitoAtsushi
Created October 26, 2014 08:22
Show Gist options
  • Save SaitoAtsushi/aa975a93646f6a7b4334 to your computer and use it in GitHub Desktop.
Save SaitoAtsushi/aa975a93646f6a7b4334 to your computer and use it in GitHub Desktop.
同期モードなら大丈夫なのに非同期にすると status 1 のときにしかハンドラが呼ばれない
#define sync_mode true // 非同期モード。 これを false にすると動く。
#include <windows.h>
#include <msxml2.h>
#include <comutil.h>
#include <cstdio>
#include <iostream>
#pragma comment(lib, "oleaut32.lib")
#pragma comment(lib, "msxml2.lib")
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "ole32.lib")
#pragma comment(lib, "comsuppw.lib")
class MetadataRequest :public IDispatch {
private:
long count;
IXMLHttpRequest* req;
IXMLHttpRequest* createInstance(void);
public:
STDMETHODIMP QueryInterface(REFIID, void**) override;
ULONG STDMETHODCALLTYPE AddRef(void) override;
ULONG STDMETHODCALLTYPE Release(void) override;
STDMETHODIMP GetTypeInfoCount(UINT*) override;
STDMETHODIMP GetTypeInfo(UINT, LCID, ITypeInfo**) override;
STDMETHODIMP GetIDsOfNames(REFIID, LPOLESTR *, UINT, LCID, DISPID*) override;
STDMETHODIMP Invoke(DISPID, REFIID, LCID, WORD, DISPPARAMS*, VARIANT *,
EXCEPINFO *, UINT*) override;
HANDLE completedEvent;
MetadataRequest(BSTR) throw(HRESULT);
virtual ~MetadataRequest(void);
};
ULONG STDMETHODCALLTYPE MetadataRequest::AddRef(void) {
return count++;
}
ULONG STDMETHODCALLTYPE MetadataRequest::Release(void) {
if (--count == 0) {
req->Release();
delete this;
return 0;
}
return count;
}
STDMETHODIMP MetadataRequest::QueryInterface(REFIID riid, void** ppvObj) {
*ppvObj = NULL;
if (IsEqualIID(riid, IID_IUnknown))
*ppvObj = dynamic_cast<IUnknown*>(this);
if (IsEqualIID(riid, IID_IDispatch))
*ppvObj = dynamic_cast<IDispatch*>(this);
else
return E_NOINTERFACE;
AddRef();
return S_OK;
}
STDMETHODIMP MetadataRequest::GetTypeInfoCount(unsigned int FAR* pctinfo) {
*pctinfo=1;
return NOERROR;
}
STDMETHODIMP
MetadataRequest::GetTypeInfo(unsigned int, LCID, ITypeInfo FAR* FAR*) {
return NOERROR;
}
STDMETHODIMP
MetadataRequest::GetIDsOfNames(REFIID, OLECHAR FAR* FAR*,
unsigned int, LCID, DISPID FAR*) {
return NOERROR;
}
IXMLHttpRequest* MetadataRequest::createInstance(void) {
IXMLHttpRequest* pReq;
HRESULT hr = CoCreateInstance(CLSID_XMLHTTP30,
NULL,
CLSCTX_ALL,
IID_IXMLHttpRequest,
reinterpret_cast<PVOID*>(&pReq));
if(FAILED(hr)) throw hr;
return pReq;
}
MetadataRequest::MetadataRequest(BSTR url)
: req(createInstance()),
count(1),
completedEvent(CreateEvent(NULL, FALSE, FALSE, NULL)) {
_bstr_t method = L"GET";
_variant_t async = sync_mode;
HRESULT hr = req->open(method, url, async, _variant_t(), _variant_t());
if(FAILED(hr)) throw hr;
req->put_onreadystatechange(this);
if(FAILED(hr)) throw hr;
hr = req->send(_variant_t());
if(FAILED(hr)) throw hr;
}
MetadataRequest::~MetadataRequest(void) {
req->Release();
}
STDMETHODIMP
MetadataRequest::Invoke(DISPID dispIdMember, const IID &riid, LCID lcid,
WORD wFlags, DISPPARAMS *pDispParams,
VARIANT *pVarResult, EXCEPINFO *pExcepInfo,
UINT *puArgErr) {
if(dispIdMember != DISPID_VALUE) return DISP_E_MEMBERNOTFOUND;
long state;
req->get_readyState(&state);
std::wcout << L"state" << state << std::endl;
if(state == 4) {
long status;
req->get_status(&status);
if(status==200) {
_bstr_t body;
req->get_responseText(body.GetAddress());
std::wcout << body << std::endl;
SetEvent(completedEvent);
}
}
return S_OK;
}
int main(void) {
CoInitializeEx(0, COINIT_APARTMENTTHREADED);
MetadataRequest* req = nullptr;
try {
_bstr_t url = "https://www.google.co.jp/";
req = new MetadataRequest(url);
WaitForSingleObject(req->completedEvent, INFINITE);
req->Release();
} catch(HRESULT hr) {
printf("result = %d\n", hr);
}
CoUninitialize();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment