HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2017
1025
volatile7-zip32.dllでUNICODE文字列を扱いたい4解決


volatile

リンク

2017/10/25(Wed) 23:29:23|NO.81675

過去ログを参照して、7-zip32.dllを


#uselib "7-zip32.dll" #cfunc SevenZip "SevenZip" int, str, var, int #func SevenZipSetBackGroundMode "SevenZipSetBackGroundMode" int

のように宣言して使っているのですが、ファイル名に機種依存文字(ハートマークなど)を含む
ファイル名を渡すとエラーになってしまい困ってます。
文字列としてはUTF16で受け取っているのをDrawTextWで表示して確認済ですが、
SevenZipにどう渡してもエラーになってしまいます。

よろしくお願いします。



この記事に返信する


kanahiron

リンク

2017/10/25(Wed) 23:56:39|NO.81676

私は7-zip32.dllを知らないので的の外れた回答だったらすみません
解凍部分を含めた関数定義以外の部分も貼っていただければ一発で回答できたかもしれませんが…

SevenZipの第二引数のstrがファイル名を渡しているとして、そこをsptrやintに変え、
UTF-16な文字列が入った変数をvarptrを使い関数に渡したらどうなるでしょうか

※もしかしたらSevenZipの第二引数をwptrに変えるだけで出来るかもしれません?



volatile

リンク

2017/10/27(Fri) 00:31:24|NO.81685

では、ソースです。


#include "gdi32.as" #packopt name "ZipCleaner" #packopt last "1" #include "user32.as" #module #deffunc mesW var p1 p2.0=ginfo_cx,ginfo_cy,ginfo_winx,ginfo_winy DrawTextW hdc,varptr(p1),-1,varptr(p2),0 mes : redraw 1 return #global #include "kernel32.as" #define CP_UTF8 65001 #uselib "shell32.dll" #func DragAcceptFiles "DragAcceptFiles" int,int #func DragQueryFile "DragQueryFileA" int,int,int,int ;#func DragQueryFile "DragQueryFileW" int,int,int,int #func DragQueryPoint "DragQueryPoint" int,int #func DragFinish "DragFinish" int #define WM_DROPFILES 0x0233 #uselib "7-zip32.dll" #cfunc SevenZip "SevenZip" int, str, var, int #func SevenZipSetBackGroundMode "SevenZipSetBackGroundMode" int #define SIZE_MAX 4096 sdim filename, 260 sdim zipName, 256 * 2 sdim result, 32000 sdim selected sdim del_filename sdim attr dim SIZE, 2 del_state = 0 SevenZipSetBackGroundMode( 0 ) oncmd gosub *OnDropFiles, WM_DROPFILES DragAcceptFiles hwnd, 1 title "ウィンドウにZIPファイルをドロップしてください" font "MS P 明朝", 12 button "削除", *del_item py = ginfo_cy mes "" mes " Date Time Attr Size Compressed Name" winobj "listbox", "", $200, $50000001 | $100000 | $200000 | $800, 620, 400 oListbox = stat hListbox = objinfo(oListbox, 2) GetStockObject 17 hFont = stat sendmsg hListbox, $30, hFont SelectObject hdc, hFont stop *OnDropFiles hdrop = wParam DragQueryFile hdrop, -1, 0, 0 ndrop = stat syscolor 5 : boxf syscolor 8 : pos 0,py DragQueryFile hdrop, 0, varptr(filename), 260 mes getpath(filename, 8) ;mesW filename mes " Date Time Attr Size Compressed Name" gosub *ziplist ; ドロップファイル情報をクリア (これをしないとメモリリークになる) DragFinish hdrop return *ziplist ; リストボックス内のアイテム削除 gosub *del_all_item ; 拡張子判別 zipExt = getpath(filename, 2) if zipExt != ".zip" : dialog "ZIPではありません" :return zipName = filename result = "" lstCmd = "l -r \"" + zipName + "\"" if SevenZip( hwnd, lstCmd, result, 32000 ) { dialog "取得失敗" return } notesel result idx = 0 sw = 0 repeat notemax noteget b, idx idx++ if (instr(b, 0, "------------------- ") = 0) : sw ^= 1 : continue if sw = 0 : continue sendmsg hListbox, $180, , b GetTextExtentPoint32 hdc, b, strlen(b), varptr(SIZE) if SIZE > maxSIZE { sendmsg hListbox, $194, SIZE + 3 maxSIZE = SIZE } loop noteunsel return *del_all_item sendmsg hListbox, $18B itemNum = stat n = itemNum - 1 repeat itemNum sendmsg hListbox, $187, n if stat : sendmsg hListbox, $185, 0, n sendmsg hListbox, $182, n n-- loop return *del_item sendmsg hListbox, $18B itemNum = stat n = itemNum - 1 repeat itemNum sendmsg hListbox, $187, n if stat { sendmsg hListbox, $189, n, varptr(selected) attr = strmid(selected, 20, 5) del_filename = strmid(selected, 53, 256) sendmsg hListbox, $185, 0, n if instr(attr, 0, "D") = 0 : continue gosub *del_file if del_state = 0 { sendmsg hListbox, $182, n } } n-- loop stop *del_file delCmd = "d -hide \"" + zipName + "\" \"" + del_filename + "\"" del_state = SevenZip( hwnd, delCmd, result, 32000 ) if del_state : dialog result return

zipファイルの中身の一部分だけを削除するツールです。

機種依存文字はSJIS扱いだと"?"に化けるので、7zipのeコマンドやlコマンドは
補完が利いて動作しますが、aコマンドやdコマンドだとエラーになってしまいます。

コメントアウトしているDragQueryFileWの方を有効にしてやると、
UTF16でファイル名が取得できますが、ご提案いただいた方法では
解決できませんでした。



kanahiron

リンク

2017/10/27(Fri) 03:41:06|NO.81688

7-zip32.dllって割と面倒ですね…
Windowsで言うUnicodeはUTF-16LEな文字列の事を指しますが、7-zip32.dllはUTF-8文字列の事をUnicodeと呼んでいます。
間違いということでは無いのですが、非常にややこしいです。

UTF-8文字列はHSP3utfランタイムを使えば簡単に扱えるのですが、逆にそれを使わないと非常に面倒です。
途中までやりましたが諦めました。
以下はHSP3utfランタイムを使った例です。

…とここまで書いて、どうもHSP3utfランタイム側のバグで動作が不安定なので標準ランタイムでやってやりました
二度とやりたくありません


#include "gdi32.as" #packopt name "ZipCleaner" #packopt last "1" #include "user32.as" #module #deffunc mesW var p1 p2.0=ginfo_cx,ginfo_cy,ginfo_winx,ginfo_winy DrawTextW hdc,varptr(p1),-1,varptr(p2),0 mes : redraw 1 return #global #include "kernel32.as" #define CP_UTF8 65001 #uselib "shell32.dll" #func DragAcceptFiles "DragAcceptFiles" int,int #func DragQueryFile "DragQueryFileW" int,int,int,int #func DragQueryPoint "DragQueryPoint" int,int #func DragFinish "DragFinish" int #define WM_DROPFILES 0x0233 #uselib "7-zip32.dll" #cfunc SevenZip "SevenZip" int, str, var, int #func SevenZipSetBackGroundMode "SevenZipSetBackGroundMode" int #define SIZE_MAX 4096 //文字コード変換周りで使います #include "encode.as" sdim filename, 260 sdim zipName, 256 * 2 sdim result, 32000 sdim selected, 1024 sdim del_filename sdim attr sdim tempString, 2048 //UTF16やUTF8を渡したり受け取るときのバッファ dim SIZE, 2 del_state = 0 SevenZipSetBackGroundMode( 0 ) oncmd gosub *OnDropFiles, WM_DROPFILES DragAcceptFiles hwnd, 1 title "ウィンドウにZIPファイルをドロップしてください" font "MS P 明朝", 12 button gosub "削除", *del_item py = ginfo_cy mes "" mes " Date Time Attr Size Compressed Name" //winobj "listbox", "", $200, $50000001 | $100000 | $200000 | $800, 620, 400 //oListbox = stat CreateWindowExW $200, "listbox", "", $50000001 | $100000 | $200000 | $800, ginfo_cx, ginfo_cy, 620, 400, hwnd, 0, 0 ,0 hListbox = stat GetStockObject 17 hFont = stat sendmsg hListbox, $30, hFont SelectObject hdc, hFont stop *OnDropFiles hdrop = wParam DragQueryFile hdrop, -1, 0, 0 ndrop = stat syscolor 5 : boxf syscolor 8 : pos 0,py DragQueryFile hdrop, 0, varptr(tempString), 1023 //DragQueryFileが返す文字列はUTF-16LEの為UTF-8に変換 WideCharToMultiByte 65001, 0, varptr(tempString), -1, varptr(filename), 260, 0, 0 //filenameはHSP標準のS-JISではなくUTF-8のまま格納されています 注意 mes getpath(utf8n2sjis(filename), 8) ;mesW filename mes " Date Time Attr Size Compressed Name" gosub *ziplist ; ドロップファイル情報をクリア (これをしないとメモリリークになる) DragFinish hdrop return *ziplist ; リストボックス内のアイテム削除 gosub *del_all_item ; 拡張子判別 zipExt = getpath(utf8n2sjis(filename), 2) if zipExt != ".zip" : dialog "ZIPではありません" :return zipName = filename result = "" //lstCmd = "l -r \"" + zipName + "\"" // -sccスイッチを指定しないと何故かS-JISとしてファイル名を解釈したUTF-8文字列を返してくる // sjisとUTF-8では英数字記号の部分が共通なので「l -sccUTF-8 -r 」などはUTF-8に変換する必要はない lstCmd = "l -sccUTF-8 -r \""+ zipName + "\"" if SevenZip( hwnd, lstCmd, result, 32000 ) { dialog "取得失敗" return } notesel result idx = 0 sw = 0 repeat notemax noteget b, idx idx++ if (instr(b, 0, "------------------- ") = 0) : sw ^= 1 : continue if sw = 0 : continue //bにはUTF-8な文字列が入っているがこれをUTF-16LEに変換しないと //ListBoxで化けてしまう MultiByteToWideChar 65001, 0, varptr(b), -1,varptr(tempString), 1023 SendMessageW hListbox, $180, 0, varptr(tempString) GetTextExtentPoint32 hdc, b, strlen(b), varptr(SIZE) if SIZE > maxSIZE { sendmsg hListbox, $194, SIZE + 3 maxSIZE = SIZE } loop noteunsel return *del_all_item sendmsg hListbox, $18B itemNum = stat n = itemNum - 1 repeat itemNum sendmsg hListbox, $187, n if stat : sendmsg hListbox, $185, 0, n sendmsg hListbox, $182, n n-- loop return *del_item sendmsg hListbox, $18B itemNum = stat n = itemNum - 1 repeat itemNum sendmsg hListbox, $187, n if stat { //sendmegだとご丁寧にsjisに変換してくれるが文字が化けるため SendMessageW hListbox, $189, n, varptr(tempString) //ListboxはUnicode版のCreateWindowExされているのでUTF-16LE文字列を返す //selectedやdel_filenameにはUTF-8文字列が入るが+結合子やstrmidなどはそのまま使える //dialogやmesで内容を確認したいときはutf8n2sjisを使おう WideCharToMultiByte 65001, 0, varptr(tempString), -1, varptr(selected), 1023, 0, 0 attr = strmid(selected, 20, 5) del_filename = strmid(selected, 53, 256) //dialog ""+utf8n2sjis(del_filename) //unicodeでしか表現できないものは?になる sendmsg hListbox, $185, 0, n if instr(attr, 0, "D") = 0 : continue gosub *del_file if del_state = 0 { sendmsg hListbox, $182, n } } n-- loop return *del_file delCmd = "d -sccUTF-8 -hide \"" + zipName + "\" \"" + del_filename + "\"" del_state = SevenZip( hwnd, delCmd, result, 32000 ) if del_state : dialog result //私のDLしたdllだと削除に失敗しても0が帰る… return

一部UTF-8文字列のままHSPの標準関数を使っていますが、問題はないはずです。
UTF-8はバイト単位のキャラクターセットで終端nullとして扱う分にはSJISと同じだからです。
(逆にUTF-16は2バイト単位で見る必要があり非常に面倒です プリミティブ型しか無いような言語で扱うものではない…)



volatile

リンク

2017/11/3(Fri) 00:40:58|NO.81768

ご教示、ありがとうございました。
うちの環境ではなぜか-sccUTF-8を指定すると正常に動作しないようです。
問題点の切り分けには時間がかかりそうなので、一旦解決済みとさせていただきます。



ONION software Copyright 1997-2021(c) All rights reserved.