こんにちは。
環境 Windows 7/Excel 2010
ISAXXMLReader* pRdr;
HRESULT hr = CoCreateInstance( CLSID_SAXXMLReader60,
NULL,
CLSCTX_ALL,
IID_ISAXXMLReader,(void**)&pRdr);
if(FAILED(hr)) return;
上記の様なC++と等価な呼び出しを行いたくて、タイプライブラリを作成して、
(規定インターフェースをISAXXMLReaderに設定)
VBAでインスタンス化しています。
(引数のdocは、MSXML2.DOMDocument)
IStreamはきちんと得られているのですが
> rdr.Parse doc
で、
---
実行時エラー '5':
プロシージャの呼び出し、または引数が不正です。
---
となります。
どなたか、お分かりになる方がいらっしゃいましたら、アドバイスを頂けませんでしょうか。
Sub Indentation(strPath, doc)
Dim hr As Long
Dim stm As IUnknown
Dim wrt As Object
Dim rdr As hoge.ISAXXMLReader
Set stm = hoge.API_ole32.CreateStreamOnHGlobal(0, 1)
'STGM_READWRITE Or STGM_SHARE_DENY_WRITE Or STGM_CREATE
hr = hoge.API_shlwapi.SHCreateStreamOnFileW(strPath, 4130&, stm)
If hr < 0 Then Err.Raise hr
If stm Is Nothing Then Err.Raise 7
Set wrt = CreateObject("MSXML2.MXXMLWriter.6.0")
wrt.Version = "1.0"
wrt.Encoding = "utf-8"
wrt.indent = True
wrt.output = stm
Set rdr = New hoge.SAXXMLReader60
rdr.putContentHandler wrt
rdr.Parse doc
End Sub
長いのですが。
hoge.idl
[
uuid(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx),
version(1.0),
helpstring ("hoge")
]
library hoge
{
importlib("stdole2.tlb");
interface ISAXXMLReader;
[
odl,
uuid(A4F96ED0-F829-476E-81C0-CDC7BD2A0802),
helpstring ("ISAXXMLReader interface")
]
interface ISAXXMLReader : IUnknown {
HRESULT _stdcall getFeature(
[in] unsigned short* pwchName,
[out, retval] VARIANT_BOOL* pvfValue);
HRESULT _stdcall putFeature(
[in] unsigned short* pwchName,
[in] VARIANT_BOOL vfValue);
HRESULT _stdcall getProperty(
[in] unsigned short* pwchName,
[out, retval] VARIANT* pvarValue);
HRESULT _stdcall putProperty(
[in] unsigned short* pwchName,
[in] VARIANT varValue);
HRESULT _stdcall getEntityResolver([out, retval] long** ppResolver);
HRESULT _stdcall putEntityResolver([in] long* pResolver);
HRESULT _stdcall getContentHandler([out, retval] IUnknown** ppHandler);
HRESULT _stdcall putContentHandler([in] IUnknown* pHandler);
HRESULT _stdcall getDTDHandler([out, retval] long** ppHandler);
HRESULT _stdcall putDTDHandler([in] long* pHandler);
HRESULT _stdcall getErrorHandler([out, retval] long** ppHandler);
HRESULT _stdcall putErrorHandler([in] long* pHandler);
HRESULT _stdcall getBaseURL([out, retval] unsigned short** ppwchBaseUrl);
HRESULT _stdcall putBaseURL([in] unsigned short* pwchBaseUrl);
HRESULT _stdcall getSecureBaseURL([out, retval] unsigned short** ppwchSecureBaseUrl);
HRESULT _stdcall putSecureBaseURL([in] unsigned short* pwchSecureBaseUrl);
HRESULT _stdcall parse([in, optional] VARIANT varInput);
HRESULT _stdcall parseURL([in] unsigned short* pwchUrl);
};
[
uuid(88d96a0c-f192-11d4-a65f-0040963251e5),
helpstring ("SAX XML Reader 6.0")
]
coclass SAXXMLReader60
{
[default] interface ISAXXMLReader;
};
[
dllname ("Shlwapi.dll")
]
module API_shlwapi {
[entry("SHCreateStreamOnFileW")]
long _stdcall SHCreateStreamOnFileW(
[in] LPWSTR pszFile,
[in] long grfMode,
[out] IUnknown **ppstm);
};
[
dllname ("ole32.dll")
]
module API_ole32 {
[entry("CreateStreamOnHGlobal")]
HRESULT _stdcall CreateStreamOnHGlobal(
[in] long hGlobal,
[in] long fDeleteOnRelease,
[out, retval] IUnknown **ppstm );
};
};
参考)
http://web.archive.org/web/20060721221948/http://forums.belution.com/ja/xml/000/000/52s.shtml
タイプライブラリを作成しているとの事ですが、
MSXML6.DLL では都合が悪いのでしょうか?
> 環境 Windows 7/Excel 2010
同じ環境が無いので、とりあえず WinXP + Excel 2007 で動作確認。
Option Explicit
'参照設定
'[Microsoft ActiveX Data Objects 2.8 Library]
'[Microsoft XML, v6.0]
Public Sub Test()
Dim stm As ADODB.Stream
Set stm = New ADODB.Stream
stm.Type = adTypeBinary
stm.Open
Dim wrt As MSXML2.MXXMLWriter60
Set wrt = New MSXML2.MXXMLWriter60
wrt.Version = "1.0"
wrt.Encoding = "UTF-8"
wrt.indent = True
wrt.standalone = True
wrt.omitXMLDeclaration = False
wrt.output = stm
wrt.flush
Dim doc As MSXML2.DOMDocument60
Set doc = New MSXML2.DOMDocument60
doc.async = False
doc.preserveWhiteSpace = False
Dim root As MSXML2.IXMLDOMElement
Set root = doc.createElement("root")
Dim element As IXMLDOMElement
Set element = doc.createElement("ParentElement")
element.setAttribute "atr1", "1"
element.setAttribute "atr2", "xxxxx"
root.appendChild element
doc.appendChild root
Dim irdr As MSXML2.ISAXXMLReader
Dim ordr As MSXML2.SAXXMLReader60
Set ordr = New MSXML2.SAXXMLReader60
Set irdr = ordr
irdr.putContentHandler wrt
ordr.Parse doc
stm.SaveToFile "C:\result.xml", adSaveCreateOverWrite
stm.Close
End Sub
熊谷隆史さん、こんにちは。
この件は別の場所でも拝見いたしました。
xmlには無知ですが、今回の件で少し興味を持ち、
上記のidlにてTlbファイルを作って参照設定してみました。
(引数の型指定問題は論外にします。)
(環境)WindowXP(SP3)、Excel2003(SP3)
しかし、 Set rdr = New hoge.SAXXMLReader60
の直後、msgbox typename(rdr)
で確認したら、ISAXXMLReaderではなく、「IVBSAXXMLReader」
インターフェイスですね。
IVBSAXXMLReaderはIDispatch Interfaceを継承しているので
折角作ったTypLibのVTableがおかしくなっているかと思います。
Windows7の環境がないので、検証は出来ませんが、当方の
環境では下記のような方法で問題ありませんでした。
Private Declare Function SHCreateStreamOnFileW& Lib "Shlwapi" _
(ByVal pszFile&, ByVal grfMode&, ByVal ppstm&)
Sub Indentation2(strPath, doc)
Dim hr As Long
Dim stm As IUnknown 'IStream
Dim wrt As Object
Dim rdr As Object 'IVBSAXXMLReader
'STGM_READWRITE Or STGM_SHARE_DENY_WRITE Or STGM_CREATE
hr = SHCreateStreamOnFileW(StrPtr(strPath), 4130&, VarPtr(stm))
If hr < 0 Then Err.Raise hr
If stm Is Nothing Then Err.Raise 7
Set wrt = CreateObject("MSXML2.MXXMLWriter")
wrt.Version = "1.0"
wrt.Encoding = "utf-8"
wrt.indent = True
wrt.output = stm
Set rdr = CreateObject("MSXML2.SAXXMLReader") 'New SAXXMLReader60
Set rdr.contentHandler = wrt
rdr.Parse doc
End Sub
魔界の仮面弁士さん、回答ありがとうございます。
載せて頂きましたコードでバッチリです。
> ADODB.Stream
QueryInterfaceを呼び出して、IStreamを取り出さなくてもいいのですね。
(IDispatchとIStreamを実装したオブジェクトでないとダメと言う意味なのか、
IUnknown型だとvtメンバがきちんと指定されないのかとも思いました)
何か色々、脱帽です。
しっかりと勉強させて頂きます。
Abyssさん、回答ありがとうございます。
こちらでは、
> rdr.Parse doc
おなじみの実行時エラーになります。
実行時エラー '-1072898019 (c00ce01d)':
XPとWindows 7では動作の振る舞いに違いがあると認識しました。
> 上記のidlにてTlbファイルを作って参照設定してみました。
お手数掛けます。
//importlib("stdole2.tlb");
importlib("msxml6.dll");
とすると参照設定するのと変わらなかったので
あらためて自前でISAXXMLReaderを定義したのですが、
結局、私の考え違いでした。
> しかし、 Set rdr = New hoge.SAXXMLReader60
>
> の直後、msgbox typename(rdr)
> で確認したら、ISAXXMLReaderではなく、「IVBSAXXMLReader」
> インターフェイスですね。
確認不足で失礼しました。
> Set rdr = CreateObject("MSXML2.SAXXMLReader") 'New SAXXMLReader60
XPにはもう随分、まともに触れていないのでよく分かりませんが、
XPのCreateObject関数では、上位のバージョンから参照されるのでしょうか。
これは何故かと言うと今回、Parseメソッドが
それぞれ参照してるライブラリのバージョンによってちょっとずつ、
違うエラーメッセージを返して来ることから分かりました。
(こちらでは下位のバージョンが参照されています)
私が載せたコード中で、
> Set wrt = CreateObject("MSXML2.MXXMLWriter.6.0")
などとしてるのもきちんと意味があります。
> QueryInterfaceを呼び出して、IStreamを取り出さなくてもいいのですね。
IStream を実装したオブジェクトであれば OK です。
ADO の Stream でも ASP の Response でも MSXML2 の DOMDocument でも。
もちろん、SHCreateStreamOnFileW や CreateStreamOnHGlobal も可です。
それ以外では文字列(or Empty)も指定できますね。
文字列を使った場合には encoding 指定が出力されませんけれども…。
Dim wrt As Object
Set wrt = CreateObject("MSXML2.MXXMLWriter.6.0")
wrt.Version = "1.0"
wrt.Encoding = "UTF-8"
wrt.indent = True
wrt.standalone = True
wrt.omitXMLDeclaration = False
wrt.output = Empty
wrt.flush
Dim rdr As Object
Set rdr = CreateObject("MSXML2.SAXXMLReader.6.0")
Set rdr.ContentHandler = wrt
rdr.Parse doc
Debug.Print wrt.output
なお、ContentHandler を指定する場合には、ISAXXMLReader.putContentHandler メソッドを
使うよりも、SAXXMLReader.ContentHandler プロパティの方が便利かもしれません。
(参照設定無しですむので、VBA のみならず VBScript からでも利用できますし)
> これは何故かと言うと今回、Parseメソッドが
> それぞれ参照してるライブラリのバージョンによってちょっとずつ、
> 違うエラーメッセージを返して来ることから分かりました。
これらは通常、サイドバイサイドモードにてインストールされる仕様です。
http://support.microsoft.com/kb/303207/ja
バージョンによってサポートしている "動的プロパティ" が異なったりもしますから、
これらをレイトバインドで使う場合には、バージョン指定の ProgID を
利用した方が安全ですね。もしくは参照設定。
> XPのCreateObject関数では、上位のバージョンから参照されるのでしょうか。
すみません。これは一個人の癖です。下位優先志向なので。
現在のXPでVersionIndependenceClsidが見てるのがmsxml3.dllですから、
当然、Window7ではそれ以上だと思ったので。
> それぞれ参照してるライブラリのバージョンによってちょっとずつ、
> 違うエラーメッセージを返して来ることから分かりました。
MSXMLには詳しくないので、そこまで頭が回りませんでした。
魔界の仮面弁士さん、Abyssさん、回答ありがとうございます。
Abyssさんの載せられてるコードでバッチリでした。m(_ _)m
原因はXMLファイルにありました。orz
> VersionIndependenceClsid
初聞きの言葉です。調べてみます。
> それ以外では文字列(or Empty)も指定できますね。
> 文字列を使った場合には encoding 指定が出力されませんけれども…。
追加情報ありがとうございます。同時に載せて頂いたコードも動作しました。
> これらは通常、サイドバイサイドモードにてインストールされる仕様です。
> http://support.microsoft.com/kb/303207/ja
参考リンク先のご紹介、ありがとうございます。
件のオブジェクトにXPとWindows 7で、動作の違いはありません。取り下げます。
魔界の仮面弁士さんには当初から、そこまで見透かされていた様です。
あらためて感謝します。
> VersionIndependenceClsid
> 初聞きの言葉です。調べてみます。
VersionIndependentProgIDでした。
Abyssさん、ありがとうございます。
> VersionIndependentProgID
http://msdn.microsoft.com/en-us/library/dd542717(VS.85).aspx
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{079AA557-4A18-424A-8EEE-E39F0A8D41B9}\VersionIndependentProgID\
を参照したら、
Msxml2.SAXXMLReader
が取れました。