大激震
Mark Davis
Heidi Housten
Dan Mohr
Kusuma Vellanki
Microsoft Corporation
March 5, 2001 日本語版最終更新日 2001年5月14日
私たちの神経は、Microsoft Earthquake ベータ 1 の最初の公開デモンストレーション以後ようやく回復したところです。私たちはおそらく出力をわずかに変更する必要がるようです。ソルトレーク市ではベータ版としては地震の影響がほとんどなかったようですので。
チームは、混乱の段階から、かろうじてよいリズムに移行しました。今月は、XSL を使用してエレメント ビヘイビアをユーザーのデータ領域に生成する方法から、イメージを自動的に保存することまで、興味深い質問がいくつか寄せられました。じっくりとお読みください。
どんな些細な疑問点でも、Web Team にメールすることを忘れないでください。来月のコラムの目次を探して求めているときは、コラムの読者のコメントの分野は問いません。
目次
スタイルでのビヘイビア - XSL を使用するエレメント ビヘイビアの出力
最新の GIF の保存 - イメージの保存
ストレージでのキャッシング - クライアントでのデータの格納
ゾーンに入る - ホストされた Web ブラウザ コントロールに対するゾーン処理
Web Team の Q & A
スタイルでのビヘイビア
Web Team の皆さんへ
Microsoft Internet Explorer 5.5 の DHTML エレメント ビヘイビアは、本当に優れた機能ですが、XSL を使ってエレメント ビヘイビアを使用するために必要な宣言を出力する方法はありますか ?
Chan Wei Min
Web Team の回答
XML に関して飛び交っている噂話をお聞きになったことがありますか ?
XSL (eXtensible Stylesheet Language) は XML (eXtensible Markup Language) ドキュメントの構造を変換するための言語です。おそらく、XML を HTML に変換することは、最も一般的な XSL の応用方法です。この場合、データを構造化するために XML が使用されていて、XSL は HTML/CSS の形式でデータを表現する作業を行います。この技法は、データ構造とデータのプレゼンテーションを分離できるので、うまく機能します。その言語はテキスト ベースなので、Web アプリケーションにとっては理想的です。
エレメント ビヘイビアは Internet Explorer 5.5 で導入されました。エレメント
ビヘイビアは DHTML ビヘイビアの機能を拡張したもので、開発者がすべての機能を備えた HTML オブジェクトを実装するカスタム要素を定義できるようにしています。
以下のサンプル コードは、スクリプト HTML コンポーネントを使用して実装される簡単なエレメント ビヘイビアを示しています。詳細については、MSDN Online
Web Workshop のドキュメント、「エレメント ビヘイビア」を参照してください。
<PUBLIC:COMPONENT TAGNAME="highlight" LIGHTWEIGHT="true" >
<PUBLIC:PROPERTY NAME="color" />
<PUBLIC:ATTACH EVENT="onmouseover" FOR="element" ONEVENT="on()" />
<PUBLIC:ATTACH EVENT="onmouseout" FOR="element" ONEVENT="off()" />
</PUBLIC:COMPONENT>
<SCRIPT Language="JScript">
function on()
{
element.runtimeStyle.color = color;
}
function off()
{
element.runtimeStyle.color = "";
}
</SCRIPT>
以下の HTML は、Web ページでこのエレメント ビヘイビアを使用する方法を示しています。ここでは、ビヘイビアがファイル名 highlight.htc に実装されたと仮定しています。
<HTML xmlns:ext>
<HEAD>
<?IMPORT NAMESPACE="ext" IMPLEMENTATION="highlight.htc">
</HEAD>
<BODY>
<ext:highlight color="red">赤</ext:highlight>
<ext:highlight color="green">緑</ext:highlight>
<ext:highlight color="blue">青</ext:highlight>
</BODY>
</HTML>
ここで問題になるのは、HTML が適切な XML の規則に準拠する必要がないことです。ただし、XSL は XML として記述されます。
おそらく初めてのことでしょうが、実際に HTML を出力する XSL を記述する場合は、すべての HTML 要素を閉じ、属性値を引用符で囲むことになります。上記の HTML リストを注意深く見てみると、整形式の XML の規則に一致しない部分が 3 個所あります。
- HTML 要素の名前空間属性の値の代入が引用符で囲まれていません。
- インポート宣言に無効な文字 '?' が含まれています。また、要素が閉じられていません。
- カスタム要素に未知の名前空間が含まれています。
私たちは XSL を使用し、かつ有効な XML でない HTML を出力したいので、どのようにして 2 つのテクノロジを混合すればよいでしょうか ? その答えは、XSL が出力をより細かく制御できる要素をいくつか提供することにあります。
希望する出力を生成するために、エレメント ビヘイビアごとに XSL 要素を使用できます。
- HTML 要素の名前空間属性は、XSL <xsl:attribute> 要素を使用して出力できます。Internet Explorer は、ここで指定した値を無視します。
- IMPORT 宣言は処理指示なので、XSL <xsl:pi> 要素を使用して、このエレメントを出力できます。
- 名前空間 ext は不明なので、カスタム要素はリテラルのエレメントとして出力できませんが、XSL <xsl:element> 要素を使用してこれらのエレメントを出力に書き込むことができます。
以下の XML は作成したエレメント ビヘイビアを使用してレンダリングしたいデータを含んでいます。Internet Explorer は XML を変換するために、<xml:stylesheet> エレメントが指定する XSL を使用するでしょう。
<?xml version="1.0"?>
<?xml:stylesheet type="text/xsl" href="presentation.xsl"?>
<root>
<text>バラは<color>赤</color>、すみれは<color>青</color>です。</text>
<text>私の<color>緑</color>と<color>黄色</color>のセーターはほどよい色合いです。</text>
</root>
最終的には、以下の XSL が希望する HTML 出力を生成する 1 つの方法になります。これを、presentation.xsl というファイルに保存して、上記の XML データを変換します。
<xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">
<xsl:template match="/">
<HTML>
<xsl:attribute name="xmlns:ext"/>
<HEAD>
<xsl:pi name="IMPORT">NAMESPACE="ext" IMPLEMENTATION="highlight.htc"</xsl:pi>
</HEAD>
<BODY>
<xsl:apply-templates/>
</BODY>
</HTML>
</xsl:template>
<xsl:template match="root">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="text">
<xsl:apply-templates/><BR/>
</xsl:template>
<xsl:template match="color">
<xsl:element name="ext:highlight">
<xsl:attribute name="color"><xsl:value-of select="."/></xsl:attribute>
<xsl:value-of select="."/></xsl:element></xsl:template>
<xsl:template match="text()">
<xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>
最新の GIF の保存
Web Team の皆さんへ
私は、Windows® 2000 Advanced Server PC で VB6 [Visual Basic® 6.0]
を使用して、ドキュメント ウィンドウ内の特定の HTM、JPG、および GIF ファイルを
"自動的に" 選択し、ローカル ハード ディスクに保存するために、 WebBrowser
コントロールをホストするアプリケーションを作成しています。私は、メインの HTML ページをディスクに保存するために次の DHTML メソッドを使用しました。
document.execCommand("saveas",false,path&filename)
しかし、"False" 引数を使用したにも関わらず、希望しないダイアログ ボックスが常に表示されます。これは、もちろんユーザーの入力を要求しているのですが、これをプログラムから提供する方法がわかりません。また、どんな場合でも埋め込まれたイメージが保存されません。私は、サーバーから再度要求しないで、ドキュメントに埋め込まれた JPG や
GIF を選択して、保存する似たようなコマンドを使用したいのですが、適切な構文が見つかりません。これらのファイルをユーザーの介入なしに効果的かつ自動的に保存する最善の方法を教えてください。
よろしくお願いします。 Donald Cruttenden
Web Team の回答
セキュリティとは両刃の刃ですね ? ドキュメントでもイメージでも (controlRange
オブジェクトまたは IHTMLControlRange を使用して) execCommand
メソッドを使用できますが、SaveAs コマンドは showUI パラメータを無視して、常にユーザーに問い合わせを行います。つまり、あなたも推測したかもしれませんが、悪意のあるページが 500,000 もの画像 (たとえば私の笑顔とか) をあなたに断りなく、あなたのハード ドライブに保存することを防ぐように設計されています。たとえ、あなたがよかれと思っていても、ユーザーに問い合わせが行われるでしょう。結局のところ実際には execCommand メソッドは IOleCommandTarget::Exec()
のある種のラッパです。IOleCommandTarget::Exec() もプログラムから
(OLECMDID_SAVE または OLECMDID_SAVEAS のいずれかを使用して) 項目を保存するために呼び出されるときは、ユーザーに問い合わせを行います。これは、このメソッドの別のラッパである IWebBrowser2::ExecWB でも同じことです。現在は、私たちは記述中に「保存」という言葉があるあらゆる関数を Web Workshop のサイト上から実際に除去してしまったので、希望はすべて失われてしまったのでしょうか ?
そんなことはありません。ここで、私たちを援助して貰うために私たちの友人である
URLMON を呼び出す必要があります。これらの項目をユーザーの介入なしに保存することを WebBrowser コントロールに求めることができないのであれば、私たち自身でそれを行うことになるので、これを補助するために URLMON API の
UrlDownloadToFile を使用することになるでしょう。Q244757 - HOWTO: Download a File Without Prompting で説明されているように、この関数を使用して、URL だけを指定し、ユーザーの介入なしにディスク上の特定の場所にファイルをダウンロードできます。そこで、これを行う方法を説明するために、簡単な
Visual Basic のサンプルを示します。このサンプルは、プログラムからページ上のすべてのイメージをユーザーの介入なしに保存する方法を示しています。このコードをテストするために、まず新しい VB EXE プロジェクトを作成し、WebBrowser コントロールを追加し wbMain という名前を付けます。その後以下のコードをフォームに貼り付けます。
Private Declare Function URLDownloadToFile Lib "urlmon" Alias _
"URLDownloadToFileA" (ByVal pCaller As Long, ByVal szURL As String, ByVal _
szFileName As String, ByVal dwReserved As Long, ByVal lpfnCB As Long) As Long
Const BASE_DIR = "C:\images\"
Private Sub Form_Load()
wbMain.Navigate "http://msdn.microsoft.com/ie"
End Sub
Private Sub wbMain_DocumentComplete(ByVal pDisp As Object, URL As Variant)
Dim collImages As IHTMLElementCollection
Dim img As IHTMLImgElement
Dim strFileName As String
Dim strExtension As String
Dim lResult As Long
Dim i As Long
Dim nAnomalies As Long
Set collImages = pDisp.Document.getElementsByTagName("IMG")
For i = 0 To collImages.length - 1
Set img = collImages.Item(i)
strFileName = Right(img.src, Len(img.src) - InStrRev(img.src, "/"))
strExtension = LCase(Right(strFileName, Len(strFileName) - InStrRev(strFileName, ".")))
If strExtension = "gif" Or strExtension = "jpg" Or strExtension = "jpeg" Then
lResult = URLDownloadToFile(0, img.src, BASE_DIR & strFileName, 0, 0)
Else
' ファイルは動的に生成されるかもしれません。またファイル名が
' 拡張子を持たないかもしれません。
' そこで、最後の手段として mimeType プロパティを調べ、
' 独自のファイル名を考案します。
If InStr(1, img.mimeType, "GIF", vbTextCompare) Then
lResult = URLDownloadToFile(0, img.src, BASE_DIR & "anomaly" & nAnomalies & ".gif", 0, 0)
ElseIf InStr(1, img.mimeType, "JPG", vbTextCompare) Then
lResult = URLDownloadToFile(0, img.src, BASE_DIR & "anomaly" & nAnomalies & ".jpg", 0, 0)
End If
End If
Set img = Nothing
Next i
Set collImages = Nothing
End Sub
最後の Else 句で示したように、イメージがサーバー側のコード (ASP ページまたは ISAPI DLL)
により動的に生成される場合は、ファイル名の観点から問題が生じる可能性があります。ただし、大部分の場合 mimeType プロパティを使用することで問題を解決できるでしょう。
[INPUT TYPE=IMAGE 要素をフェッチするコードの実装は、読者への課題として残しておきましょう。]
ストレージでのキャッシュ
Web Team の皆さんへ
私は、特に Internet Explorer 5.0 (以降) で実行するために設計されたソフトウェア製品を開発しています。私は、Internet Explorer の仕様書を探しています。たとえば、1 つの問題はブラウザがキャッシュできるデータ容量です。キャッシュできる最大データ容量はどのぐらいですか ? 複数のウィンドウを開くと格納できるデータのサイズが増加しますか ? この情報を説明している適切なオンライン ソースはありますか ?
よろしくお願いします。 Brian Simon Cupertino, CA
Web Team の回答
Persistence には価値があります ! userData や Internet Explorer
5.0 以降のその他の Persistence ビヘイビアに関してあなたが知りたいすべての情報は、以下の URL で見つかります。既定の Persistence ビヘイビアを使用する方法を示す優れたサンプルも存在します。
http://msdn2.microsoft.com/en-us/library/ms533007.aspx
http://msdn2.microsoft.com/en-us/library/ms531424.aspx
http://msdn2.microsoft.com/en-us/library/ms531070.aspx
http://www.microsoft.com/mind/1299/inside/inside1299.asp
ドキュメントおよびドメインごとに保存できるデータ量には制限があります。その制限は、ドメインのセキュリティ ゾーンに依存します。一般的にインターネット ゾーンの制限は、ドキュメントごとに 128 KB、ドメインごとに 1024 KB です。URL のゾーンを決定できない場合は、制限はドキュメントごとに 64 KB、ドメインごとに 640 KB です。保存するデータ量を増加したいが、1 ページだけでもユーザーシームレスに表示したい場合は非表示のフレームを使用できます。
userData Persistence 機能を使用することは、次の 2 つの点で
cookie を使用するよりもはるかに優れています。
- クライアントとサーバー間で情報を互いに送信することを避けることになります。そのため、ナビゲーションとページの読み込み時間を軽減できます。これは、サーバーのパフォーマンスを向上することにも役に立ちます。
- userData Persistence ビヘイビアはストレージとして XML を使用するので、構造化されたデータを格納できます。
ゾーンに入る
Web Team の皆さんへ
私は、アプリケーションで関数 CoGetClassObjectFromURL() を使い始めましたが、インターフェイス IInternetHostSecurityManager を処理できません。ダウンロード プロセスが開始されると、この関数は IBindStatusCallback
の実装で QueryInterface を実行して、IInternetHostSecurityManager
インターフェイスを取得します。その後、そのインターフェイスの実装へのポインタを返します。関数が ProcessUrlAction メソッドを呼び出すと、私の実装は常に pPolicy 引数に URLPOLICY_ALLOW
を返しますが、これは無視されているようで、関数は Internet Explorer の設定を尊重しているようです。何が起こっているのでしょうか ?
よろしくお願いします。 Marcos Cesar
Web Team の回答
あなたの問題点の説明からは、Q246227 - SAMPLE: SECUMGR Overrides Security Manager for WebBrowser Host に記載されている制限事項に抵触しているように思えます。プログラムから
URLACTION_DOWNLOAD_UNSIGNED_ACTIVEX アクションのセキュリティ設定を緩和することはできません。これを回避する唯一の方法は、あなたのダウンロード サイトを一時的にセキュリティ ゾーンに追加し、その後そのゾーンのポリシーを変更し、ユーザーの介入なしにこのアクションが発生できるようにすることです。これをプログラムから行う方法を説明する前に、これには潜在的なセキュリティ上のリスクが含まれていることを認識しておくことが重要です (これは、たとえ一時的にせよ、Internet Explorer のグローバルなセキュリティ設定を緩和することになります)。 コーダーへの警告
- プログラムがしようとしていることをユーザーに認識させないでプログラムからユーザーのセキュリティ設定を操作してはいけません。さらに、このセキュリティ上のリスクを受け入れるかどうかの選択肢をユーザーに提供する必要があります (これを提供しない場合は、ユーザーへの問い合わせを残しておく必要があります)。さて、セキュリティの危険については強調したので、興味深いコードをいくつか記述してみましょう。
セキュリティ ゾーンにサイトを追加することは、比較的直接的な手続きで、最もよく行われるのは IInternetSecurityManager インターフェイスと IInternetZoneManager インターフェイスを使用することです。これらのインターフェイスはレジストリに格納されているセキュリティ ゾーンの情報を間接的に修正するので、ユーザーが元になるレジストリ キーを変更する権限を持たないような状況では使用できません。レジストリ キーを直接変更することにより同じ効果が得られますが、これらのレジストリ構造は次期バージョンの Internet Explorer では変更される可能性があることを覚えておいてください。セキュリティとゾーンのマネージャの抽象化は、レジストリ構造の変更が生じたときでもユーザーのコードをまったく書き直す必要がないようにしています。
私たちの作業を実行するコードは、次の 3 つのセクションに分けることができます。
- グローバル変数 (現在のセキュリティ設定を格納します。したがって、使い終わったときに、この変数を使って再設定できます)。
- CoGetClassObjectFromURL を呼び出す前に実行するコード。
- CoGetClassObjectFromURL を呼び出した後に実行るコード。
以下はグローバル変数セクションです (グローバル変数を使うことの罪の意識で夜な夜な眠れない場合は、代わりにクラス メンバをお使いください)。
#define DOWNLOAD_SITE TEXT("http://myserver")
DWORD g_dwOldTemplate = URLTEMPLATE_LOW;
DWORD g_dwOldFlags = 0;
DWORD g_dwOldPolicy = URLPOLICY_QUERY;
以下は、CoGetClassObjectFromURL を呼び出す前に実行するコードです。
IInternetSecurityManager *pSecurityMgr = NULL;
IInternetZoneManager *pZoneMgr = NULL;
DWORD dwNewPolicy = URLPOLICY_ALLOW;
HRESULT hr = S_OK;
ZONEATTRIBUTES za;
za.cbSize = sizeof(za);
hr = CoCreateInstance(CLSID_InternetSecurityManager, NULL, CLSCTX_INPROC_SERVER,
IID_IInternetSecurityManager, (void**)&pSecurityMgr);
hr = CoCreateInstance(CLSID_InternetZoneManager, NULL, CLSCTX_INPROC_SERVER,
IID_IInternetZoneManager, (void**)&pZoneMgr);
hr = pZoneMgr->GetZoneAttributes(URLZONE_TRUSTED, &za);
g_dwOldTemplate = za.dwTemplateCurrentLevel;
g_dwOldFlags = za.dwFlags;
za.dwFlags &= ~ZAFLAGS_REQUIRE_VERIFICATION;
za.dwTemplateCurrentLevel = URLTEMPLATE_CUSTOM;
hr = pZoneMgr->SetZoneAttributes(URLZONE_TRUSTED, &za);
hr = pSecurityMgr->SetZoneMapping(URLZONE_TRUSTED, DOWNLOAD_SITE, SZM_CREATE);
hr = pZoneMgr->GetZoneActionPolicy(URLZONE_TRUSTED, URLACTION_DOWNLOAD_UNSIGNED_ACTIVEX,
(BYTE*)&g_dwOldPolicy, sizeof(DWORD), URLZONEREG_DEFAULT);
hr = pZoneMgr->SetZoneActionPolicy(URLZONE_TRUSTED, URLACTION_DOWNLOAD_UNSIGNED_ACTIVEX,
(BYTE*)&dwNewPolicy, sizeof(DWORD), URLZONEREG_DEFAULT);
pZoneMgr->Release();
pSecurityMgr->Release();
最後に、CoGetClassObjectFromURL を呼び出した後に実行するコードです。
IInternetSecurityManager *pSecurityMgr = NULL;
IInternetZoneManager *pZoneMgr = NULL;
HRESULT hr = S_OK;
ZONEATTRIBUTES za;
za.cbSize = sizeof(za);
hr = CoCreateInstance(CLSID_InternetSecurityManager, NULL, CLSCTX_INPROC_SERVER,
IID_IInternetSecurityManager, (void**)&pSecurityMgr);
hr = CoCreateInstance(CLSID_InternetZoneManager, NULL, CLSCTX_INPROC_SERVER,
IID_IInternetZoneManager, (void**)&pZoneMgr);
hr = pZoneMgr->SetZoneActionPolicy(URLZONE_TRUSTED, URLACTION_DOWNLOAD_UNSIGNED_ACTIVEX,
(BYTE*)&g_dwOldPolicy, sizeof(DWORD), URLZONEREG_DEFAULT);
hr = pSecurityMgr->SetZoneMapping(URLZONE_TRUSTED, DOWNLOAD_SITE, SZM_DELETE);
hr = pZoneMgr->GetZoneAttributes(URLZONE_TRUSTED, &za);
za.dwTemplateCurrentLevel = g_dwOldTemplate;
za.dwFlags = g_dwOldFlags;
hr = pZoneMgr->SetZoneAttributes(URLZONE_TRUSTED, &za);
pZoneMgr->Release();
pSecurityMgr->Release();
HTTPS を使用しない信頼されているサイトを追加することを防ぐために、ZAFLAGS_REQUIRE_VERIFICATION フラグをクリアする必要があることに注意してください。また、コンポーネントのダウンロードが完了した後に元の設定に戻していることにも注意してください。しかし、非同期ダウンロードには一定の時間がかかるので、その間に実行される Internet Explorer の別のインスタンスはすべて変更されているセキュリティ設定を使用することになります。このわずかな時間に、この手続きから悪影響を受ける可能性があります。別の潜在的な危険は、ダウンロード プロセスで何らかの障害が発生した場合です。セキュリティの設定が変更されたままにならないように、すべてのコード パスが終了するときにクリーンアップと設定復元のコードが必ず実行されるようにします。
Internet Explorer のセキュリティ ゾーンのレジストリ設定の詳細については、Q182569 - Description of Internet Explorer Security Zones Registry Entries を調べるか、専門家に相談してください。
Web Team の Q & A
CSS と cellpadding
Q: CSS を使って表の cellpadding と cellspacing
を設定する方法を教えてください。(ペルーの Rolando)
A: TD に対して CSS padding を使用して cellpadding を設定できます。CSS2 は表の cell-spacing プロパティを指定しますが、CSS を使用する大部分のブラウザは CSS1
だけを完全にサポートします。したがって、Internet Explorer や Netscape ではまだ CSS2 は利用できません。また、Internet Explorer 5 以降でサポートされている、CSS2 の border-collapse 属性は利用できます。この属性は、表とセルの境界線の間の余白を取り除きます。
Word とブラウザのどちらが起動される ?
Q: Microsoft Word の文書を Internet Explorer ではなく Word で確実に開く方法を教えてください。 (Jimmy)
A: 必要なことは KB 記事 Q259970 - PRB: In-Place Activating Document Servers in Internet Explorer
に記載されています。
ストリーミングと IHTMLDocument2 オブジェクト
Q: Internet Explorer 5.5 で IpersistStreamInit および
IStream を使用した障害について教えてください。(Ajit)
A: この問題を回避するには KB の記事 Q271868 - BUG: IPersistStreamInit Not Available for a FRAME in a FRAMESET が役に立ちます。
前回の同期スクロールのサンプル
Q: iframe を同期してスクロールする方法説明した、機能するサンプル コードを入手しましたが障害が発生しました。(Erik)
A: そのサンプル用のテキストでは、親ウィンドウとは異なるドメインを指すフレームにアクセスするセキュリティの問題を説明しています。iframe のソース属性を変更せずに、記事のコードを直接使用している場合は、コードを .htm ファイルではなく .hta ファイルとしてファイルを保存する必要があります。
Web Team へのメールは、webtalk@microsoft.com までお願いいたします。
|