AJAX 때문에 유명해진 XMLHTTPRequest 입니다 ^^;
사실 저같은 Windows 개발자들은 http 통신을 하는데 수많은 방법이 있지요.
Win32의 HttpOpenRequest 함수나 MFC의 CHttpConection 클래스, 그리고 WinHttp 등..
(일설에 의하면.. XMLHTTPRequest는 WinHttp 를 래핑해서 만들어졌다고 하는군요.)
따라서 사실 굳이 XMLHTTPRequest 를 쓰지 않아도 됩니다.
비동기 통신? 스레드로 돌리면 간단하지요 -_-;
그럼 왜 하필 이런 코드를 올리느냐!
..그냥 왠지 써보고 싶어서 -_-;
Windows 개발자들은 원래 유행에 덜 민감한 편이고 또 그래야 하죠 ;;
괜히 이런 신기술 쪽을 쓰다보면 구버전의 OS에서는 안돌아가고 막 그러니까요.
그럼에도 불구하고.. 이 넘치는 호기심을 주체하지 못하는지라..
어쨌든 서론은 접어두고, 코드 올라갑니다.
장점이라면.. 도메인과 경로를 분리해서 작업하지 않아도 되고,
비동기 통신을 자체적으로 지원한다는 정도일 것 같네요.
(open 하실 때 세번째 인자를 true 로 주면 된다고 합니다. 해보진 않았지만 ;;)
#import "msxml3.dll" using namespace MSXML2; BOOL GetHtml(LPCTSTR tszUrl, LPTSTR tszBuffer, DWORD cbBuffer) { USES_CONVERSION; BOOL bRet = FALSE; HRESULT hr = S_FALSE; IXMLHTTPRequestPtr pIXMLHTTPRequest = NULL; _bstr_t bstrHtml = _T(""); hr = CoInitialize(NULL); if (FAILED(hr)) goto cleanup; hr = pIXMLHTTPRequest.CreateInstance( _T("Msxml2.XMLHTTP.3.0")); if (FAILED(hr)) goto cleanup; hr = pIXMLHTTPRequest->open(_T("GET"), tszUrl, false); if (FAILED(hr)) goto cleanup; hr = pIXMLHTTPRequest->send(); if (FAILED(hr)) goto cleanup; bstrHtml = pIXMLHTTPRequest->responseText; if (bstrHtml.length() == 0) goto cleanup; hr = StringCbCopy(tszBuffer, cbBuffer, OLE2T(bstrHtml)); if (FAILED(hr)) goto cleanup; bRet = TRUE; cleanup: pIXMLHTTPRequest.Release(); CoUninitialize(); return bRet; }
와, 12월 데브피아 활동왕에 선정되었습니다.
이거 대략 가문의 영광
...그런데
1등이잖아? -_-;;
헉, 가..감사합니다 ;ㅁ; 앞으로도 열심히 할께요!
12월 초에는 별로 활동을 못했는데, 11월말까지 한 활동으로 선정되었나 보네요.
덕분에 왠지 다가오는 2009년, 행복한 한 해가 될 것 같습니다 >ㅁ<
모두들 즐거운 연말되시고, 희망찬 새해 되세요!
일반적인 경우 별로 사용할 일은 없지만..
가끔가다 내가 만든 프로그램이 돌아가기 위해 필수적으로 실행중이어야 할 서비스가 실행중이 아닐 경우가 있습니다. 그렇다면 별수없이.. 실행시켜줘야죠 ^^;
Windows에서 서비스들은 SCM(Service Control Manager)이라는 녀석에 의해 관리됩니다. 당연히 이녀석을 제어하는 API도 존재하죠.
다음과 같이 코딩하면 특정 윈도우 서비스를 실행할 수 있습니다.
BOOL MyStartService(LPCTSTR tszServiceName) { BOOL bRet = TRUE; // Open SCM SC_HANDLE schSCManager = NULL; schSCManager = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS); if (schSCManager == NULL) { bRet = FALSE; goto cleanup; } // Open Service SC_HANDLE schService = NULL; schService = OpenService(schSCManager, tszServiceName, SERVICE_ALL_ACCESS); if (schService == NULL) { bRet = FALSE; goto cleanup; } // Change Service Type if (!ChangeServiceConfig(schService, SERVICE_NO_CHANGE, SERVICE_AUTO_START, SERVICE_NO_CHANGE, NULL, NULL, NULL, NULL, NULL, NULL, NULL)) { bRet = FALSE; goto cleanup; } // Start Service if (!StartService(schService, 0, NULL)) { bRet = FALSE; goto cleanup; } cleanup: CloseServiceHandle(schService); CloseServiceHandle(schSCManager); return bRet; }
실행하려면.. 인자로 서비스명을 지정하시면 되겠네요.
MyStartService(_T("winmgmt"))
WMI는 은근히 재미있는 주제입니다. COM을 사용하는 방법과 WMI에 접근하는 방법을 같이 공부할 수 있거든요.
또한, AD를 사용한다면, 에이전트 없이 원격 클라이언트의 정보를 상당량 수집할 수 있구요.
WMI에 대한 자세한 설명은 MSDN을 참조해주시구요, 전체적인 과정을 살펴보면 대략 다음과 같습니다.
1. CoInitialize로 COM을 초기화한다.
2. CoInitializeSecurity로 보안 레벨을 설정한다.
3. CoCreateInstance로 WMI 의 COM Object 를 생성한다.
4. ConnectServer로 "root\\cimv2" 네임스페이스로 접속한다.
5. ExecQuery 로 WQL 구문을 실행한다.
6. 실행결과 Enumerator 를 분석하고, 제조번호를 파싱한다.
그리하여, 전체 코드는 다음과 같이 되겠습니다.
#include "stdafx.h" int _tmain(int argc, _TCHAR* argv[]) { int nRet = 0; HRESULT hr = S_OK; TCHAR tszMsg[1024] = {0, }; try { if (_tsetlocale(LC_ALL, _T("")) == NULL) throw _T("_tsetlocale"); hr = CoInitializeEx(0, COINIT_MULTITHREADED); if (FAILED(hr)) throw _T("CoInitialize"); hr = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL); if (FAILED(hr)) throw _T("CoInitializeSecurity"); CComPtr<IWbemLocator> wbemLocater = NULL; hr = CoCreateInstance( CLSID_WbemAdministrativeLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&wbemLocater); if (FAILED(hr)) throw _T("CoCreateInstance"); CComPtr<IWbemServices> wbemServices = NULL; hr = wbemLocater->ConnectServer(L"root\\cimv2", NULL, NULL, NULL, WBEM_FLAG_CONNECT_USE_MAX_WAIT, NULL, NULL, &wbemServices); if (FAILED(hr)) throw _T("ConnectServer"); CComPtr<IEnumWbemClassObject> wbemEnumerator = NULL; hr = wbemServices->ExecQuery(L"WQL", L"SELECT * FROM Win32_ComputerSystemProduct", WBEM_FLAG_FORWARD_ONLY, NULL, &wbemEnumerator); if (FAILED(hr)) throw _T("ExecQuery"); ULONG uReturned; while (wbemEnumerator) { CComPtr<IWbemClassObject> wbemObject = NULL; hr = wbemEnumerator->Next( WBEM_INFINITE, 1, &wbemObject, &uReturned); if (FAILED(hr)) throw _T("Next"); if (uReturned == 0) break; _variant_t vtProp; hr = wbemObject->Get(L"IdentifyingNumber", 0, &vtProp, 0 ,0); if (FAILED(hr)) throw _T("Get"); wprintf(_T("%s\n"), (LPCTSTR)vtProp.bstrVal); } } catch (LPTSTR tszErr) { DWORD dwErr = GetLastError(); FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, hr, 0, tszMsg, sizeof(tszMsg), NULL); if (*tszMsg == 0) { BSTR bstrErr; IErrorInfo* pErrInfo; GetErrorInfo(0, &pErrInfo); pErrInfo->GetDescription(&bstrErr); if (*bstrErr == 0) { if (*tszMsg == 0) { FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, 0, dwErr, 0, tszMsg, sizeof(tszMsg), NULL); } } } _tprintf(_T("Error: [%s] %s\n"), tszErr, tszMsg); nRet = 1; } catch (...) { FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError(), 0, tszMsg, sizeof(tszMsg), NULL); _tprintf(_T("Error: [UnExpected], %s\n"), tszMsg); nRet = 1; } CoUninitialize(); return nRet; }
가끔 코딩하다 보면 버퍼에 들어있는 내용 중
4바이트만 뽑아서 int 형 변수로 저장해야 할 일이 생깁니다.
간단한 비트 연산이지만.. 급하면 또 생각이 안나죠 -_-;
int n = (data[0] << 24) + ((data[1] & 0xFF) << 16) + ((data[2] & 0xFF) << 8) + (data[3] & 0xFF);