結局、NodeJS+V8に押された形で、JavaScript(Chakrart)のネイティブアプリ採用を公に認めた。
今までは煮え切らない態度で、IActiveScriptを作ったもののそれ以上何もしてこなかった。
セキュリティの問題が発生しやすいので、本当はあまりプッシュしたくないのだろうと思う。

JSRTサンプルにあるechoという手抜きしている関数を直したechoexを作成。

JavaScript Runtime Hosting Sample


var b = {"a":1, "b":2, "c":[1,2,3] };
host.echo(b); // [object Object]
host.echoex(b); // {a:1, b:2, c:[1,2,3]}


#include "stdafx.h"
#include
#include
#include
#include
#include

void ValueVariantToString( std::wstringstream& sm, VARIANT& v );


JsValueRef CALLBACK EchoEx(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
{
for (unsigned int index = 1; index < argumentCount; index++)
{
if (index > 1)
{
wprintf(L" ");
}

_variant_t vx;
JsValueRef x = arguments[index];
JsValueToVariant(x, &vx );

std::wstringstream sm;

ValueVariantToString( sm, vx );

wprintf( sm.str().c_str() );
}
wprintf(L"\n");

return JS_INVALID_REFERENCE;
}

HRESULT InvokeGetProperty( IDispatch* disp, DISPID id, VARIANT& val )
{
EXCEPINFO ex; UINT er; DISPPARAMS pm = { NULL,0,0,0 };
return disp->Invoke( id, IID_NULL,LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &pm, &val, &ex, &er );
}
HRESULT InvokeGetDISPID( IDispatch* disp, LPCWSTR nm, DISPID& id )
{
LPOLESTR nma[1]; nma[0] = (LPOLESTR)nm;

return disp->GetIDsOfNames( IID_NULL, nma, 1,LOCALE_USER_DEFAULT, &id );
}
HRESULT InvokeGetProperty( IDispatch* disp, LPCWSTR nm, VARIANT& val )
{
DISPID id;
HRESULT hr = InvokeGetDISPID( disp, nm, id );
if ( SUCCEEDED(hr))
hr = InvokeGetProperty( disp, id, val );
return hr;
}


static void ValueVariantToString( std::wstringstream& sm, VARIANT& v )
{
if ( v.vt == VT_DISPATCH )
{
IDispatch* disp = v.pdispVal;

DISPPARAMS pm = {NULL,0,0,0};

CComPtr px;
auto hr = disp->QueryInterface( &px );
_ASSERT( hr == S_OK );

_variant_t v;
hr = InvokeGetProperty( disp, L"length", v );
if ( hr == S_OK && v.vt == VT_I4 )
{
sm << L"[";
for( LONG i = 0; i < v.intVal; i++ )
{
if ( i != 0 )
sm << L", ";

DISPPARAMS dispParamsNoArgs = {0};

WCHAR strIndex[64];
wsprintf( strIndex, L"%d", i);

// Convert to BSTR, as GetDispID() wants BSTR's
CComBSTR bstrIndex(strIndex);
DISPID dispidIndex;
hr = px->GetDispID(bstrIndex, fdexNameCaseSensitive, &dispidIndex);
if (FAILED(hr))
break;

// Get array item value using InvokeEx()
CComVariant varItem;
hr = px->InvokeEx(dispidIndex, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &dispParamsNoArgs, &varItem, // Arrayからデータゲット
NULL, NULL);

if (FAILED(hr))
break;

ValueVariantToString( sm, varItem );


}
sm << L"]";
}
else
{
// 多分 key-value
DISPID dispid;

sm << L"{";
int i = 0;

HRESULT hr = px->GetNextDispID(fdexEnumAll, DISPID_STARTENUM, &dispid);
while( hr == S_OK)
{
DISPPARAMS dispParamsNoArgs = {0};

if ( i != 0 )
sm << L", ";

// get key
CComBSTR key;
if ( S_OK != px->GetMemberName( dispid, &key ) )
break;

// get value
CComVariant varItem;
if ( S_OK == px->InvokeEx(dispid, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &dispParamsNoArgs, &varItem, NULL, NULL))
{
sm << (LPCWSTR)key << L":";
ValueVariantToString( sm, varItem );
}

hr = px->GetNextDispID(fdexEnumAll, dispid, &dispid);
i++;
}
sm << L"}";
}
}
else
{
_variant_t vd;
if ( S_OK == ::VariantChangeType( &vd, &v, 0, VT_BSTR ) )
sm << (LPCWSTR)vd.bstrVal;
}
}

JSRTをブログにしている日本人がほとんどいないので、もうこのレイヤーのエンジニアは絶滅危惧種のようだ。
ざっと国内に5人くらいだと思う。

Metro, ユニバーサルアプリ, HWND


ユニバーサルアプリでHWNDを必要とする例は滅多にないだろうけど、こんな方法で取得できるらしい。


extern "C" int __stdcall GetWindowTextW(HWND hwnd, PWSTR text, int count);
#pragma comment (lib, "user32.lib")

struct __declspec(uuid("45D64A29-A63E-4CB6-B498-5781D298CB4F")) __declspec(novtable)
ICoreWindowInterop : IUnknown
{
virtual HRESULT __stdcall get_WindowHandle(HWND* hwnd) = 0;
virtual HRESULT __stdcall put_MessageHandled(unsigned char) = 0;
};

// AppはWindows::ApplicationModel::Core::IFrameworkViewを継承したクラス
void App::SetWindow(CoreWindow^ window)
{
...

// Metroアプリのウインドウハンドル
HWND hWnd;
Microsoft::WRL::ComPtr interop;

HRESULT hr = ( (IUnknown*)window)->QueryInterface(interop.GetAddressOf());

interop->get_WindowHandle(&hWnd);

  // 試しにTextを取得してみる、user32.libをリンク
WCHAR text[100];
GetWindowTextW(hWnd, text, 100 ); // text is equal to app name.

}


Windowsコントロールで一番難関のTextboxを作成、アップしました。ここです。
Direct2Dですべてを実装しているためHWNDレスです。TSFによる漢字変換に対応しています。
SingleLineのみですが、一見すると普通のTextboxと見分けが使いないはずです。

なお、TSFの元ソースはWindows7 SDKに含まれるサンプル(以下)を改造したものです。(8.1のSDKには含まれていません)
TSFに関して、他にまともなサンプルは見当たりません。


C:\Program Files\Microsoft SDKs\Windows\v7.1\Samples\winui\input\tsf\tsfapps\tsfpad-step1


BSTRは::SysFreeString(x); を実行しても直ぐには消えない。
デバッグの時ににこれが厄介になる場合がある。
下の関数を一度実行するとキャッシュを切ることができる。


#ifdef _DEBUG
typedef int (*SETOANOCACHE)(void); // 昔は非公開関数だった?

// BSTRのcacheを止める
void DisableBSTRCache()
{
HINSTANCE hLib = LoadLibrary(L"OLEAUT32.DLL");
if (hLib != NULL)
{
SETOANOCACHE SetOaNoCache = (SETOANOCACHE)GetProcAddress(hLib, "SetOaNoCache");
if (SetOaNoCache != NULL)
SetOaNoCache();
FreeLibrary(hLib);
}
}
#endif

bmp,gif,jpg,pngの画像ファイルをID2D1Bitmapへ変換するサンプルです。
LoadImage内でファイルをbinaryで取得しStreamへ変換しID2D1Bitmapを作成します。
なお、ID2D1RenderTargetを再構築するとID2D1Bitmapも作り直しが必要なので、StreamかFileNameは
どこかで保持する必要があります。

Binaryクラスはここです。


#include "stdafx.h"
#include "binary.h"
#include

bool LoadImage( LPCWSTR filename, ID2D1RenderTarget* target, ID2D1Bitmap** ret )
{
CComPtr sm;
CComPtr bmp;

Binary bin;
bool bl;
bl = BinaryFromFile(filename, bin);
bl = BinaryToIStream( bin, &sm );
bl = LoadImageFromIStream1( target, sm, &bmp);

*ret = bmp.Detach();
(*ret)->AddRef();

return true;
}



bool BinaryFromFile( LPCWSTR fnm, Binary& ret )
{
HANDLE h = CreateFile( fnm, GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL );

if ( h != INVALID_HANDLE_VALUE )
{
DWORD len = GetFileSize( h, NULL );

Binary bin(0,len);
DWORD lx=0;

::ReadFile( h,bin.get(), len,&lx,0);

ret = bin;

::CloseHandle(h);
return true;
}

return false;
}
bool BinaryToIStream( const Binary& bin, IStream** ret )
{
HGLOBAL hMem = ::GlobalAlloc(GMEM_MOVEABLE, bin.length());
LPVOID pImage = ::GlobalLock(hMem);
memcpy(pImage, bin.get(), bin.length());
::GlobalUnlock(hMem);

CComPtr spStream;
if ( S_OK == ::CreateStreamOnHGlobal(hMem,TRUE, &spStream ))
{
*ret = spStream;
(*ret)->AddRef();
return true;
}
return false;
}



bool LoadImageFromIStream1( ID2D1RenderTarget* target, IStream* sm, ID2D1Bitmap** bmp )
{
HRESULT hr;
CComPtr pStream;
CComPtr pWICFactory;

hr = CoCreateInstance( CLSID_WICImagingFactory, NULL, CLSCTX_ALL, __uuidof(IWICImagingFactory), (void**)&pWICFactory );
if ( hr != S_OK ) return false;

hr = pWICFactory->CreateStream( &pStream );
if ( hr != S_OK ) return false;

hr = pStream->InitializeFromIStream( sm ); // bmp,gif,jpg,png OK
if ( hr != S_OK ) return false;

CComPtr pDecoder;
CComPtr pSource;
CComPtr pConverter;

hr = pWICFactory->CreateDecoderFromStream( pStream, 0, WICDecodeMetadataCacheOnLoad, &pDecoder );
if ( hr != S_OK ) return false;
hr = pDecoder->GetFrame(0, &pSource);
if ( hr != S_OK ) return false;

// Convert the image format to 32bppPBGRA
// (DXGI_FORMAT_B8G8R8A8_UNORM + D2D1_ALPHA_MODE_PREMULTIPLIED).
hr = pWICFactory->CreateFormatConverter(&pConverter);
if ( hr != S_OK ) return false;
hr = pConverter->Initialize( pSource, GUID_WICPixelFormat32bppPBGRA,WICBitmapDitherTypeNone,NULL,0.f,WICBitmapPaletteTypeMedianCut);
if ( hr != S_OK ) return false;
hr = target->CreateBitmapFromWicBitmap(pConverter,NULL,bmp );

return ( hr == S_OK );
}

ID2D1HwndRenderTargetとID2D1DeviceContext比較してみました。
以下はID2D1DeviceContextを使用した例です。
USE_DEVICECONTEXTをコメントにするとID2D1HwndRenderTargetになります。



#include "stdafx.h"
#include "Win32Project.h"
#define MAX_LOADSTRING 100

HINSTANCE hInst; // 現在のインターフェイス
TCHAR szTitle[MAX_LOADSTRING]; // タイトル バーのテキスト
TCHAR szWindowClass[MAX_LOADSTRING]; // メイン ウィンドウ クラス名

ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);

CoInitialize(0);

// TODO: ここにコードを挿入してください。
MSG msg;
HACCEL hAccelTable;

LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_WIN32PROJECT6, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);

if (!InitInstance (hInstance, nCmdShow))
return FALSE;

hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WIN32PROJECT6));

while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}

ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WIN32PROJECT6));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_WIN32PROJECT6);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

return RegisterClassEx(&wcex);
}

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance;
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

if (!hWnd)
return FALSE;

ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}


#include
#include
#include


#pragma comment(lib,"d2d1.lib")
#pragma comment(lib,"d3d11.lib")


using namespace D2D1;
CComPtr d2d1Factory;
CComPtr d2D1RenderTarget;
CComPtr dXGISwapChain1;

void CreateHwndRenderTarget( HWND hWnd, ID2D1Factory* d2d1Factory, ID2D1RenderTarget** ptarget );
void CreateDeviceContextRenderTarget( HWND hWnd,ID2D1Factory1* d2d1Factory, ID2D1RenderTarget** ptarget, IDXGISwapChain1** pdxgiSwapChain );


#define USE_DEVICECONTEXT // 切り替え

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;

switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// 選択されたメニューの解析:
switch (wmId)
{
case IDM_ABOUT:
//DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
{
hdc = BeginPaint(hWnd, &ps);

d2D1RenderTarget->BeginDraw();
{
D2D1_MATRIX_3X2_F mat = Matrix3x2F::Identity();
d2D1RenderTarget->SetTransform(mat);
d2D1RenderTarget->Clear(ColorF(ColorF::White));

D2D1_RECT_F rc;
rc.left=10;
rc.top=10;
rc.right=100;
rc.bottom=100;

CComPtr br;
auto hr = d2D1RenderTarget->CreateSolidColorBrush( ColorF(ColorF::Red), &br );

d2D1RenderTarget->FillRectangle( rc, br );// 赤い四角
}

auto hr =d2D1RenderTarget->EndDraw();
if ( hr != S_OK )
{
// ERROR
}

EndPaint(hWnd, &ps);

#ifdef USE_DEVICECONTEXT
dXGISwapChain1->Present(1, 0);
#endif
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;

case WM_ERASEBKGND:
return 1;
break;
case WM_CREATE:
{
D2D1_FACTORY_OPTIONS options;
options.debugLevel = D2D1_DEBUG_LEVEL_NONE;

D2D1CreateFactory( D2D1_FACTORY_TYPE_SINGLE_THREADED,__uuidof(ID2D1Factory1),&options,(void**)&d2d1Factory );

#ifndef USE_DEVICECONTEXT
CreateHwndRenderTarget( hWnd, d2d1Factory,&d2D1RenderTarget );
#endif
}
break;
case WM_SIZE:
{
#ifdef USE_DEVICECONTEXT
d2D1RenderTarget.Release();
dXGISwapChain1.Release();

CreateDeviceContextRenderTarget( hWnd, d2d1Factory, &d2D1RenderTarget, &dXGISwapChain1 );
#else
CComPtr d2d1HwndRenderTagrget;
d2D1RenderTarget.p->QueryInterface( IID_ID2D1HwndRenderTarget, (void**)&d2d1HwndRenderTagrget);
d2d1HwndRenderTagrget->Resize( D2D1::SizeU( LOWORD(lParam), HIWORD(lParam) ));
#endif
}
break;

default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}

inline void ThrowIfFailed( HRESULT hr, LPCWSTR msg, UINT line, LPCSTR fnm )
{
if (FAILED(hr))
{
// Do something.
//General access denied error 0x80070005
}
}
#define THROWIFFAILED(hr,msg) ThrowIfFailed(hr,msg, __LINE__, __FILE__)

static void CreateHwndRenderTarget( HWND hWnd, ID2D1Factory* d2d1Factory, ID2D1RenderTarget** ptarget )
{
CComPtr d2d1HwndRenderTagrget;

THROWIFFAILED(d2d1Factory->CreateHwndRenderTarget(D2D1::RenderTargetProperties(), D2D1::HwndRenderTargetProperties(hWnd, D2D1::SizeU(1, 1), D2D1_PRESENT_OPTIONS_NONE), &d2d1HwndRenderTagrget), L"D2DContext::CreateHwndRenderTarget");

d2d1HwndRenderTagrget->QueryInterface( IID_ID2D1RenderTarget, (void**)ptarget );
}

static void CreateDeviceContextRenderTarget( HWND hWnd,ID2D1Factory1* d2d1Factory, ID2D1RenderTarget** ptarget, IDXGISwapChain1** pdxgiSwapChain )
{
RECT rc;
GetClientRect(hWnd, &rc);

// UINT width = ::GetSystemMetrics( SM_CXFULLSCREEN );
// UINT height = ::GetSystemMetrics( SM_CYFULLSCREEN );

UINT width = rc.right;
UINT height = rc.bottom;

CComPtr d2d1DeviceContext;
CComPtr dxgiSwapChain1;
//CComPtr d2d1Factory;

CComPtr d2d1Device;
CComPtr d2d1Bitmap;

CComPtr d3d11DeviceContext;
CComPtr d3d11Device;
CComPtr dxgiSurface;
CComPtr dxgiAdapter;
CComPtr dxgiFactory;
CComPtr dxgiDevice;

UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;

UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;

D3D_FEATURE_LEVEL returnedFeatureLevel;

D3D_FEATURE_LEVEL featureLevels[] =
{
D3D_FEATURE_LEVEL_11_1,
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
D3D_FEATURE_LEVEL_9_3,
D3D_FEATURE_LEVEL_9_2,
D3D_FEATURE_LEVEL_9_1
};


THROWIFFAILED( D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, 0, creationFlags, featureLevels, ARRAYSIZE(featureLevels), D3D11_SDK_VERSION,
&d3d11Device, &returnedFeatureLevel, &d3d11DeviceContext),L"CreateDeviceContextRenderTarget");


THROWIFFAILED(d3d11Device->QueryInterface(&dxgiDevice),L"CreateDeviceContextRenderTarget");
THROWIFFAILED(d2d1Factory->CreateDevice(dxgiDevice.p, &d2d1Device),L"CreateDeviceContextRenderTarget");
THROWIFFAILED(d2d1Device->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_NONE, &d2d1DeviceContext),L"CreateDeviceContextRenderTarget");
THROWIFFAILED(dxgiDevice->GetAdapter(&dxgiAdapter),L"CreateDeviceContextRenderTarget");
THROWIFFAILED(dxgiAdapter->GetParent(IID_PPV_ARGS(&dxgiFactory)),L"CreateDeviceContextRenderTarget");

DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0};
swapChainDesc.Width = width;
swapChainDesc.Height = height;
swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
swapChainDesc.Stereo = false;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = 2;
swapChainDesc.Scaling = DXGI_SCALING_NONE;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
swapChainDesc.Flags = 0;

THROWIFFAILED(dxgiFactory->CreateSwapChainForHwnd(d3d11Device,
hWnd,
&swapChainDesc,
nullptr,
nullptr,
&dxgiSwapChain1),L"!!CreateSwapChainForHwnd"); // よくここでエラーになる
_ASSERT( dxgiSwapChain1 );

THROWIFFAILED(dxgiDevice->SetMaximumFrameLatency(1),L"CreateDeviceContextRenderTarget");
THROWIFFAILED(dxgiSwapChain1->GetBuffer(0, IID_PPV_ARGS(&dxgiSurface)),L"CreateDeviceContextRenderTarget");

auto bmp_property = D2D1::BitmapProperties1(D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW, D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE));
THROWIFFAILED(d2d1DeviceContext->CreateBitmapFromDxgiSurface(dxgiSurface.p, &bmp_property, &d2d1Bitmap),L"CreateDeviceContextRenderTarget");
d2d1DeviceContext->SetTarget(d2d1Bitmap.p);

auto sz = d2d1Bitmap->GetSize();

_ASSERT( sz.width == width );
_ASSERT( sz.height == height );
//////////////////////////////////////////////////////////////////////////////////////////////

d2d1DeviceContext->QueryInterface( IID_ID2D1RenderTarget, (void**)ptarget );

*pdxgiSwapChain = dxgiSwapChain1.p;
(*pdxgiSwapChain)->AddRef();
}

ID2D1DeviceContextではWM_SIZEでのDestroy->Createさせてますが画面フルサイズでbmpを作成すれば不要になます。
なお、RenderTargetをDestroy->Createするとこれを引数で作成したオブジェクト(Brushなど)はすべて使えなくなります。
ID2D1DeviceContextはDirect3Dと絡むため頻繁にアップデートされるドライバーのバグにはまるような気がします。


最新のxml paserはmsxml6。でもリリースからだいぶ時間もたち忘れられそうでメモしておく。使い方に癖があって、
#includeではなく、#importでライブラリ情報を動的に取得しなければならない。
しかも、COMは自動的にスマートポインタになる。


#include "stdafx.h"
#import // .NETframework3.0からインストール済み。msxml6.tlh, msxml6.tliを自動生成。

int _tmain(int argc, _TCHAR* argv[])
{
CoInitialize(0);

MSXML2::IXMLDOMDocument3Ptr doc; // IXML***Ptrは全てスマートポインタ

doc.CreateInstance( __uuidof(MSXML2::DOMDocument60) );

auto hr = doc->loadXML( L"test" );

auto root = doc->GetdocumentElement();

auto nd = root->firstChild;

// 同じ関数が3種類もある。
auto c = nd->text; // c is "test"

auto c1 = nd->Gettext(); // c1 is "test"

BSTR c2;
nd->get_text(&c2);
::SysFreeString(c2); // c2 is "test"

return 0;
}

そもそもMSXMLWindowsの標準ライブラリではなく、ブラウザなどに付属していた。
しかし、なかなか安定せず何度も小修正をくりかしている。http://support.microsoft.com/kb/269238/ja
.NET3.0以降(またはVista以降)から標準でmsxml6はインストールされるようになった。
パーサの規格はFIX(名前空間 MSXML)されていて変更できなくなったためMSXML2が作られたように記憶している。
また、歴史的な理由から重複しているような関数(上のGettext())が多数ある。
ちなみに昔の書き方だと割と面倒であった。

// 昔のプログラム
#include "stdafx.h"
#include

int _tmain(int argc, _TCHAR* argv[])
{
CoInitialize(0);

CComPtr doc;

CLSID clsid;

CLSIDFromProgID( L"MSXML.DOMDocument", &clsid );
::CoCreateInstance( clsid,0,CLSCTX_ALL,IID_IXMLDOMDocument, (void**)&doc);

VARIANT_BOOL bl;
auto hr = doc->loadXML( L"test", &bl );

CComPtr root;
hr = doc->get_documentElement( &root );

CComPtr nd;
hr = root->get_firstChild( &nd );

BSTR c2;
nd->get_text(&c2);
::SysFreeString(c2); // c2 is "test"

return 0;
}
// IE4の2000年頃

#include "msxml6.tlh" とすると環境を移動した時に問題が起きる。tlh内にtliが絶対パスで記述されているからで、必ず#import としなければならない。