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


HSPTV!掲示板


未解決 解決 停止 削除要請

2020
0622
こいる環境依存文字を含んだコマンドライン文字列を取得したい16解決


こいる

リンク

2020/6/22(Mon) 14:37:59|NO.90834

実行ファイルでファイルを開いたときに、
そのファイルが存在するかを確認して、存在した場合にのみ処理をする、
というようなものを作っています。

とりあえず作れたのですが、
ファイル名に環境依存文字(unicodeなど)が含まれている場合に、
hspが環境依存文字を扱えないのか、正常に機能しません。

#packopt name "これにファイルをドロップ" exist dir_cmdline // コマンドライン文字列に、ドロップされたファイルの絶対パスが入っている if strsize!=-1{ // なにかしらの処理をする mes "存在する" }

環境依存文字を含んだコマンドライン文字列を取得できれば、解決しそうなのですが、
どうすれば取得できるのでしょうか?

ご教示お願いします。



この記事に返信する


TOMATO

リンク

2020/6/22(Mon) 16:53:21|NO.90835

試してませんが、

・UTF-8対応版ランタイムを使用する
・標準ランタイムでUTF-16版のWin32APIを呼び出す

になるのでは?

GetCommandLineW 関数
https://docs.microsoft.com/en-us/windows/win32/api/processenv/nf-processenv-getcommandlinew

PathFileExistsW 関数
https://docs.microsoft.com/en-us/windows/win32/api/shlwapi/nf-shlwapi-pathfileexistsw



X

リンク

2020/6/22(Mon) 16:56:10|NO.90836

CommandLineToArgvWとGetCommandLineWと使えば対応できるようにはなりますが
取得できる文字列がUTF16(多分LEだったかと)となるためそれに合わせた文字コードの変換が必要になり割と面倒ではあります。

こちらのスレの暇人様のソースが参考になるかと思います。
http://hsp.tv/play/pforum.php?mode=pastwch&num=47162

もしくは電子の言霊様のHPで配布されているmod_unicodeとモジュールにuni_getcmdline uni_getcmdlinelist という命令があるため
それを使うと楽かもしれません。
http://www31.tok2.com/home/tt/hsp/module/module.html



ゆうやん

リンク

2020/6/22(Mon) 17:39:54|NO.90837

一部の環境依存文字(♡や「ゔ」や「㋿」など)はShift-JISに存在しない文字なので、UTF-8 のランタイムを使用しないと使えません。
スクリプトの先頭に

#include "hsp3utf.as"
と記述しておけば、環境依存文字を含んだファイル名を取得することが可能です。

ただし、エディタがUnicode(環境依存文字)に対応していないので、スクリプトの文字列に環境依存文字を使用したいのであれば、Unicode対応のスクリプトエディタを使うことになりますが。

https://ux.getuploader.com/tds12_hsp/download/1
(hsed3u8.exeをHSP3のインストールフォルダにコピー(または移動)すればOK)



こいる

リンク

2020/6/22(Mon) 18:58:48|NO.90838

皆さん返信ありがとうございます。

TOMATOさんとゆうやんさんがおっしゃるように、
UTF-8のランタイムを使用することで、解決しました。

#packopt name "utf-8_runtime_version" #include "hsp3utf.as" mes dir_cmdline exist dir_cmdline mes "exist "+strsize if strsize!=-1 : mes"存在する"

しかし、このランタイムを使うと
実行ファイルのサイズが大きくなってしまうのが気になります…


なので、Win32APIを使う方法も試してみたいです。

Xさんが提供してくださったスレの、暇人さんのソースを使って、
それっぽいものを作ってみたのですが、上手くいきません。

とりあえず、通常文字に変換したものと、変換前のUnicodeのものを指定したのですが、どちらも上手くいきませんでした。

Xさんが、UTF16LEから変換しなくてならないとおっしゃりましたが、
何に、どうやって変換するのでしょうか?

#packopt name "win32api_version" #uselib "kernel32" #func GetCommandLineW "GetCommandLineW" #func LocalFree "LocalFree" sptr #uselib "shell32" #func CommandLineToArgvW "CommandLineToArgvW" wptr,wptr #uselib "shlwapi.dll" #func PathFileExists "PathFileExistsA" sptr GetCommandLineW lpCmdLineW=stat CommandLineToArgvW lpCmdLineW, varptr(NumArgs) if stat=0 {dialog "リストが無い":end} pCmdList=stat dupptr p, pCmdList, 4*NumArgs, vartype("int") repeat NumArgs dupptr temp_CmdLineW, p(cnt), 256, vartype("str") CmdLinesA(cnt) = cnvwtos(temp_CmdLineW) mes CmdLinesA(cnt) if cnt==1{ PathFileExists varptr(temp_CmdLineW) mes "\nUnicode PathFileExists "+stat if stat==1 : mes" 存在する" exist temp_CmdLineW mes "\nUnicode exist "+strsize if strsize!=-1 : mes" 存在する" PathFileExists varptr( CmdLinesA(1) ) mes "\n通常文字 PathFileExists "+stat if stat==1 : mes" 存在する" exist CmdLinesA(1) mes "\n通常文字 exist "+strsize if strsize!=-1 : mes" 存在する" } loop mes LocalFree pCmdList mes "LocalFree "+stat stop

また、Xさんが提示してくださったmod_unicodeモジュールですが、
ファイル名をクリックしても、"500 Internal Server Error"と出て、ダウンロードできませんでした。



沢渡

リンク

2020/6/22(Mon) 20:03:22|NO.90840

UTF-16の文字列に対してSJIS版のPathFileExistsAを使っているのだから、ファイルの存在チェックが
上手くいかないのでしょう。
UTF-16版のPathFileExistsWなら上手くいくと思います。

#packopt name "win32api_version" #uselib "kernel32" #func GetCommandLineW "GetCommandLineW" #func LocalFree "LocalFree" sptr #cfunc lstrlenW "lstrlenW" int #uselib "shell32" #func CommandLineToArgvW "CommandLineToArgvW" wptr,wptr #uselib "shlwapi.dll" #func PathFileExistsA "PathFileExistsA" sptr //SJIS版 #func PathFileExistsW "PathFileExistsW" sptr //UTF-16版 #uselib "gdi32.dll" #func TextOutW "TextOutW" int,int,int,int,int font msgothic,16 //デフォルトのフォントだとUnicode文字は表示されない模様 GetCommandLineW lpCmdLineW=stat CommandLineToArgvW lpCmdLineW, varptr(NumArgs) if stat=0 {dialog "リストが無い":end} pCmdList=stat dupptr p, pCmdList, 4*NumArgs, vartype("int") repeat NumArgs dupptr temp_CmdLineW, p(cnt), 256, vartype("str") CmdLinesA(cnt) = cnvwtos(temp_CmdLineW) mes CmdLinesA(cnt) //SJISの文字列を表示 TextOutW hdc,ginfo_cx,ginfo_cy,p(cnt),lstrlenW(p(cnt)) //UTF-16の文字列を表示 mes "" if cnt==1{ //ファイルが存在するかどうかを調べる処理 //↓UTF-16の文字列は、UTF-16版のPathFileExistsWを使えば上手く行く PathFileExistsW varptr(temp_CmdLineW) mes "\nUnicode PathFileExistsW "+stat if stat==1 : mes" 存在する" //↓UTF-16の文字列に対してSJIS版HSPのexist命令を使っているので、これは失敗する exist temp_CmdLineW mes "\nUnicode exist "+strsize if strsize!=-1 : mes" 存在する" //↓SJISに変換した場合は、対象となる文字列がSJISで扱える文字でのみ構成されているのなら、 // SJIS版のPathFileExistsAでも上手くいく。 PathFileExistsA varptr( CmdLinesA(1) ) mes "\n通常文字 PathFileExists "+stat if stat==1 : mes" 存在する" //↓上と同様、対象となる文字列がSJISで扱える文字でのみ構成されているのなら、 // SJIS版HSPのexist命令でも上手くいく。 exist CmdLinesA(1) mes "\n通常文字 exist "+strsize if strsize!=-1 : mes" 存在する" } loop mes LocalFree pCmdList mes "LocalFree "+stat redraw 1 stop

>Xさんが、UTF16LEから変換しなくてならないとおっしゃりましたが、
>何に、どうやって変換するのでしょうか?
UTF16LE(UTF-16 リトルエンディアン)というのはここで使っているUnicodeデータの形式ですから、
変換するというのはこのソースでもやっているcnvwtosを使ってのUTF-16→SJISの変換のことです。



こいる

リンク

2020/6/23(Tue) 12:42:44|NO.90842

>沢渡さん
できました!ありがとうございます!

目的の、
>実行ファイルでファイルを開いたときに、
>そのファイルが存在するかを確認して、存在した場合にのみ処理をする。
が簡単にできるモジュールを作ったので、置いておきます。

; ; コマンドライン文字列のファイルが存在するかを確認するモジュール(Unicode対応) ; #module mod_command_line_file_exist #uselib "kernel32" #func GetCommandLineW "GetCommandLineW" #func LocalFree "LocalFree" sptr #uselib "shell32" #func CommandLineToArgvW "CommandLineToArgvW" wptr,wptr #uselib "shlwapi.dll" #func PathFileExistsW "PathFileExistsW" sptr ; 戻り値:0=存在しない 1=存在する #defcfunc CommandLineFileExist dim ret GetCommandLineW lpCmdLineW = stat CommandLineToArgvW lpCmdLineW, varptr(NumArgs) if stat=0 : return 0 pCmdList = stat dupptr p, pCmdList, 4*NumArgs, vartype("int") if NumArgs>=2{ dupptr temp_CmdLineW, p(1), 256, vartype("str") PathFileExistsW varptr(temp_CmdLineW) ret = stat DrawUnicode p(1) // 取得したUnicodeを表示 (確認用) } LocalFree pCmdList return ret // Unicodeの表示命令 #uselib "kernel32" #func lstrlenW "lstrlenW" wptr #uselib "gdi32.dll" #func TextOutW "TextOutW" int,int,int,int,int #deffunc DrawUnicode int lp font msgothic,16 TextOutW hdc, ginfo_cx, ginfo_cy, lp, lstrlenW(lp) pos 0, ginfo_cy+16 redraw 1 return #global ; サンプル mes "CommandLineFileExist "+CommandLineFileExist() if stat==1{ mes "存在する" }

少し疑問なのですが、
末尾にWがある関数は、Unicodeに対応しているということなのでしょうか?

そうだとするならば、Wの方が優秀な気がするのですが、
積極的にWを使っているのは見たことがないです。
なにか理由があったりするのでしょうか?


それと、このソースでは、コマンドライン文字列が途中で切れないように、
コマンドライン文字列の長さに合わせてdupptr命令を実行しており、確かに指定サイズより大きい引数を通常文字に変換した場合は途中で切れました。
https://archive.kerupani129.net/blog/posts/%e3%80%90%e5%8b%9d%e6%89%8b%e3%81%ab%e4%bf%ae%e6%ad%a3%e7%89%88%e3%80%91%e3%82%b3%e3%83%9e%e3%83%b3%e3%83%89%e3%83%a9%e3%82%a4%e3%83%b3%e6%96%87%e5%ad%97%e5%88%97%e3%82%92%e8%a7%a3%e6%9e%90%e3%81%97/
しかし、変換前のUnicodeは全く切れませんでした。
これはなぜなのでしょうか?



あらや

リンク

2020/6/23(Tue) 13:17:58|NO.90843

横から失礼します。

>末尾にWがある関数は、Unicodeに対応しているということなのでしょうか?
対応というよりもUnicode用です。

>積極的にWを使っているのは見たことがないです。
HSPの基本がSJIS(ANSI)なので
末尾がAのANSI系APIの方が使いやすいというだけですね。

以上、お邪魔しました。



osakana

リンク

2020/6/23(Tue) 16:05:52|NO.90844

>Xさん
>もしくは電子の言霊様のHPで配布されている...を使うと楽かもしれません
>http://www31.tok2.com/home/tt/...

>こいるさん
>Xさんが提示してくださったmod_unicodeモジュールですが...ダウンロードできませんでした

せっかく紹介してもらったのにリンク切れですみません。そのサイトは移転前のサイト(運営元が機能しなくなった)で、移転先は更新期限を忘れて消滅し現在ダウンロード出来なくなっています。
取り急ぎ別の場所へ上げ直してみたので、もし必要であればこちらからダウンロードしてご自由にお使いください。
http://winapple.blog49.fc2.com/blog-entry-93.html



こいる

リンク

2020/6/23(Tue) 20:31:49|NO.90848

>あらやさん
なるほど、ありがとうございます。

>osakanaさん
ありがとうございます。
また機会があれば使いたいと思います。



沢渡

リンク

2020/6/23(Tue) 21:09:11|NO.90849

すみません、文字数制限のことを考慮してませんでした。
NO.90840のうち、

dupptr temp_CmdLineW, p(cnt), 256, vartype("str")


dupptr temp_CmdLineW, p(cnt), lstrlenW(p(cnt))*2+2, vartype("str")
とした方がよかったですね。これで文字数制限は(OSで許される範囲内なら)なくなると思います。

>それと、このソースでは、コマンドライン文字列が途中で切れないように、
>コマンドライン文字列の長さに合わせてdupptr命令を実行しており、
>確かに指定サイズより大きい引数を通常文字に変換した場合は途中で切れました。
>しかし、変換前のUnicodeは全く切れませんでした。
>これはなぜなのでしょうか?
WinAPIはHSP上でデータがどのように扱われているのかは知りませんから、
たとえdupptr命令が「メモリ上にあるデータのうち256バイト分しか使わない」と宣言していても、
メモリ上にあるデータが256バイトを超えているのなら、WinAPIはそのデータを
そのまま取り扱うのではないかと。



こいる

リンク

2020/6/23(Tue) 21:43:48|NO.90850

>沢渡さん
返信ありがとうございます。

>lstrlenW(p(cnt))*2+2
lstrlenW関数で長さを取得しているのは分かるのですが、
その後にある、*2と+2は何のためにしているのでしょうか?

>WinAPIはHSP上でデータがどのように扱われているのかは知りませんから、
>たとえdupptr命令が「メモリ上にあるデータのうち256バイト分しか使わない」と宣言していても、
>メモリ上にあるデータが256バイトを超えているのなら、WinAPIはそのデータを
>そのまま取り扱うのではないかと。
なるほど。



あらや

リンク

2020/6/24(Wed) 04:02:19|NO.90853

深夜(早朝?)に再度横から。。。

>lstrlenW関数で長さを取得しているのは分かるのですが、
>その後にある、*2と+2は何のためにしているのでしょうか?
lstrlenW関数は文字数を返す関数で
Unicodeはほとんどの文字が2バイトです。
(サロゲートペアは4バイトですが)

つまり、基本的には文字数*2で文字列のバイト数が取得できます。
そして文字列の終端コード0も2バイトにしなければいけないので
+2をしているのかと。

勝手な解説失礼いたしました。



こいる

リンク

2020/6/24(Wed) 13:09:27|NO.90857

>あらやさん
なるほど!ありがとうございます。

また質問になるのですが、
「文字列の終端コード0」(ヌル終端文字列)は、なんのためにあるのでしょうか?



あらや

リンク

2020/6/25(Thu) 00:27:13|NO.90861

>「文字列の終端コード0」(ヌル終端文字列)は、なんのためにあるのでしょうか?
そのまんまですが、ここが文字列の終端ですよという目印のためです。

終端の目印が無いと、例えばmesで表示するときに
どこまでを表示すれば良いのか判別できなくなるので
終端が見つかるまでメモリを読み込み&表示してしまい
こちらが意図した文字列の後に文字化けしたような変な文字まで追加されてしまいます。

わざと終端コードが付かないようにするサンプルです。

sdim mojiretsu, 64; // 64バイトの文字列型変数 mojiretsu = "あいうえお\nかきくけこ\nさしすせそ\nたちつてと\nなにぬねの\nは"; // 62バイト文字列 wpoke mojiretsu, 62, 0xD082; // 終端コードが付かないように最後に『ひ』を追加 mes mojiretsu; // 文字列の後のメモリが偶然0になっていれば表示されるのが文字列だけだが、 // そうでなければ後ろに余計な物がつく



こいる

リンク

2020/6/25(Thu) 21:32:08|NO.90871

>あらやさん
なるほど!何度もありがとうございました!

他の方々もありがとうございました!
これにて解決です。



ゆうやん

リンク

2020/6/26(Fri) 23:52:08|NO.90877

もう解決済みになっていますが、Win32APIの文字列はUTF-16で管理されているため、varptrでは文字化けする場合があります。
UTF-8のランタイムのWin32APIでvarptrを使用する場合、cnvwtosで変換する必要があるので注意してください。

#include "hsp3utf.as" #include "user32.as" title "ユニコードテスト" sdim tex,259 GetWindowTextW hwnd,varptr(tex),259 tex=cnvwtos(tex);UTF16からUTF8へ mes tex



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