2008/12/07

レガシASPでサイトを作ってると、Shift-JISなサイトを作るのが基本になると思います。なんでかというと、FileSystemObjectが基本的にShift-JISの読み書きにしか対応しておらず(UTF-16もいけますが)、いまどきのUTF-8を使うのはちょっと面倒です(FSOの代わりにADODB.Streamを使えば行けますけどどうでしょうねー?私はあんまり好きじゃないです)。

ただ、UTF-8な他のWebサイト/サービスと連携する場合はどうしても避けて通れません。そこでレガシASPでShift-JISなページを作る際、UTF-8文字列を扱う上で知っておくべきこと。

1. escape関数を使うとShift-JISでURLエンコードがされる

ASPはだいたいVBScriptで書くと思うんですが、隠し関数であるescape関数を使うとURLエンコードができます。ですが、escape関数は呼び出し元のページコードの文字コードでエンコードします。なのでShift-JISなページで呼び出すとShift-JISのエンコードURLを出力します。(ちなみにWSHで使うとUTF-16のものになる)

JScriptのencodeURIComponent関数はどんな場合でもUTF-8文字列を出力するので、これを使うといいでしょう。使い方はこうです。

Set sc = CreateObject("ScriptControl")
sc.Language = "JScript"
Set js = sc.CodeObject
Response.Write js.encodeURIComponent("文字列") 

逆にShift-JISなページでShift-JISなエンコードURL文字列を取得したい場合は単にescape関数を呼び出せばいいです。
さらに別なケースですがUTF-8なページでShift-JISなエンコードURLを取得したい場合は、こんな関数を使うといいんじゃないでしょうか

2. XMLHTTPでPostメソッドでSendする際は必ずUTF-8でURLエンコードがされる

Set xh = CreateObject("MSXML2.XMLHTTP")
xh.Open "POST", "http://hogehoge/hoge.aspx", False
xh.Send "文字列"

このように何も考えずに書いても、勝手にUTF-8でURLエンコードされてPostされるので大丈夫です。

3. UTF-8なページのHTMLを読み込む際

標準機能だけでやろうと思うとADODB.Streamを使うしかないと思います。
ちなみに読み込むページの文字コードが不明の場合は判定した上で変換する必要がありますが、これはかなり面倒なので、BASP21を使うといいんじゃないでしょうか。

Function GetPageString(strUrl)
 Set bobj = CreateObject("basp21")
 Set oHTTP = CreateObject("Msxml2.XMLHTTP")
 oHTTP.Open "GET", strUrl, False
 oHTTP.Send
 GetPageString = bobj.Kconv (oHTTP.responseBody,4)
End Function

これは引数にURLを与えるとそのHTMLを文字列として取得します。対象の文字コードが何であってもOKなのがミソ。

4. UTF-8のURLエンコードされたクエリ、あるいはPOSTされたデータを受ける際

これのやり方が分からない!具体的にはトラックバックpingなんかを受け取る際に困ります(さすがにShift-JISでトラックバックpingを送れ!というのはゴーマンだと思います)。私はここだけASP.NETを使って逃げました。どなたかやり方わかります?

追記。Request.BinaryReadしたやつをADODB.Streamにかけたあと&でsplitして=でsplitしてDictionaryに入れてdecodeURIComponentすればいけるかな?

ただし、ここだけASP.NETを使う際にも注意が必要です。まずweb.configの<system.web>セクションに

<globalization
requestEncoding="Shift-JIS" responseEncoding="Shift-JIS" fileEncoding="Shift-JIS"/>

というのを埋め込んで、まずレスポンスエンコーディングをShift-JISにしておきます。IISの設定でもいいですが。

続いてコーディング。Request.QueryStringやRequest.Formは使えないので、Request.InputStreamを使ってごりごり読まないと駄目じゃないかな・・・。なぜかVB.NETですがUTF-8なトラックバックpingをShift-JISなページで受けるサンプルコードを。

Dim str As System.IO.Stream
Dim counter, strLen, strRead As Integer
str = Request.InputStream
strLen = CInt(str.Length)
Dim strArr(strLen) As Byte
strRead = str.Read(strArr, 0, strLen)

Dim Forms As New Dictionary(Of String, String)

For Each item As String In Split(Encoding.UTF8.GetString(strArr),"&")
	If InStr(item, "=") Then
		Dim s As String() = Split(item, "=")
		If s.Length = 2 And Not Forms.ContainsKey(s(0)) Then
			Forms.Add(s(0), HttpUtility.HtmlEncode(HttpUtility.UrlDecode(s(1), Encoding.UTF8)).Trim().Replace(vbNullChar, ""))
		End If
	End If
Next

↑自分でも謎なコードを書いてたのでちょっとマシなのに修正。コンパイル通るかどうかわかりませんが・・・さらにゴミコードが残ってたのでバッサリ切りました。

ただし!これの問題は改行コードが消えることなんです。対処法は見つけていません(勘違いでした)。もっといい方法があったら教えてください。そもそもInputStreamを使わないでRequest.Formとか使いたいんですが、Shift-JISのところにUTF-8が来るとうまくいかないですねぇー。

というわけで長々と書きましたが、Shift-JISにこだわらなければこんなに苦労することはないです。FileSystemObjectがUTF-8を読み書きできないので私はSJISにこだわってるだけです。FSOはWSHからも使いますので・・・

元記事:http://blogs.wankuma.com/mutaguchi/archive/2008/12/07/162931.aspx

2007/06/24

Vistaにおいてコンソールアプリケーションを立ち上げるとconime.exeという日本語入力アプリが立ち上がります。conime.exeが実行中はAlt+全角/半角キーで日本語入力が可能になります。が、DigitalPersona Password Manager(DPAgnt.exe)(Microsoft製指紋認証ハードウェアに付属のソフト)が起動していると、Alt+全角/半角キーを入力してもIMEが立ち上がりません。おそらくDPAgnt.exeのバグでしょう。

対処法としては、一度コンソールアプリを立ち上げconime.exeが実行されると、常駐するので、二度目にコンソールアプリを立ち上げるとAlt+全角/半角キーを入力するとIMEが立ち上がるようになります。

元記事:http://blogs.wankuma.com/mutaguchi/archive/2007/06/24/81884.aspx

2007/06/09

20070609-gwmi-error

なんだこりゃ 

 set-psdebug -trace 2;してもよくわからないなぁ

PS C:\Windows\System32> set-psdebug -trace 2;
デバッグ:    1+ set-psdebug -trace 2;
PS C:\Windows\System32> gwmi win32_product
デバッグ:    1+ gwmi win32_product
デバッグ:    1+ $_.PSStandardMembers.DefaultDisplayPropertySet
デバッグ:    1+ $_.PSStandardMembers.DefaultDisplayPropertySet

IdentifyingNumber : {C63E7C60-25EB-11D3-8EDA-00A0C911E8E5}
Name              : Microsoft Outlook 個人用フォルダ バックアップ
Vendor            : Microsoft Corporation
Version           : 1.10.0.0
Caption           : Microsoft Outlook 個人用フォルダ バックアップ
デバッグ:    2+                                     if ($ErrorView -ne "CategoryView") {
デバッグ:    3+                                        $myinv = $_.InvocationInfo
デバッグ:     ! SET $myinv = 'System.Management.Automation.InvocationInfo'.
デバッグ:    4+                                        switch -regex ($myinv.MyCommand.CommandType)
デバッグ:   24+                                                if ($myinv.MyCommand.Name)
デバッグ:   26+                                                    $myinv.MyCommand.Name + " : "; break;
デバッグ:   26+                                                    $myinv.MyCommand.Name + " : "; break;
デバッグ:    2+                                     if ($_.InvocationInfo) {
デバッグ:    3+                                         $posmsg = $_.InvocationInfo.PositionMessage
デバッグ:     ! SET $posmsg = '
発生場所 行:1 文字:5
+ gwmi  <<<< win32_product'.
デバッグ:    7+                                     if ($ErrorView -eq "CategoryView") {
デバッグ:   11+                                         $_.Exception.Message + $posmsg
Get-WmiObject : エラーです
発生場所 行:1 文字:5
+ gwmi  <<<< win32_product

PS C:\Windows\System32>

こんな感じ

10/05追記。

荒井省三のBlog : [PS]WMIの取り扱いについて
http://blogs.msdn.com/shozoa/archive/2007/10/02/ps-wmi.aspx

ここに対処法が載せられています。

元記事:http://blogs.wankuma.com/mutaguchi/archive/2007/06/09/80179.aspx


Copyright © 2005-2018 Daisuke Mutaguchi All rights reserved
mailto: mutaguchi at roy.hi-ho.ne.jp
プライバシーポリシー

Twitter

Books