Win32API を利用するには? - umemura - 04-23-2014
Curl でWin32API を利用するにはどうすればいいですか?
具体的には、マックアドレスを取得するための「GetAdaptersInfo」を利用したいです。
Win32API を ActiveXObject として利用できたりするのでしょうか。
それとも、kernel.dll や、user.dll から、DLLインタフェースを個別に作成して利用するしかないのでしょうか。
RE: Win32API を利用するには? - hokada - 04-24-2014
DLL Interface を使えば、GetAdaptersInfo()、もしくはGetAdaptersAddresses()をコールできるはずです。
それ以外のMacアドレスを取得する方法としては、ipconfigコマンドをspawn-host-process を使って実行し、アウトプットをパースする方法もあると思います。
RE: Win32API を利用するには? - umemura - 04-24-2014
『ipconfigコマンドをspawn-host-process を使って実行』するには、
cmd.exe を spawn-host-process に渡せばよいでしょうか。
また、その際に、『アウトプットをパース』するために、
spawn-host-process の実行結果を取得するには
どうすればよいですか?
下記のような方法で標準出力を取得しようと思いましたが、
「アプレット [9-121] - stdout が取得されていないか、既に開いています。の為、例外Errorで停止」
というエラーメッセージが出てしまいます。
Code: {import * from CURL.RUNTIME.HOST-PROCESS}
{def ta = {TextArea}}
{value ta}
{CommandButton
label = "ipconfig実行",
{on Action do
def cmd-exe-path =
{get-from-host-environment "windir"} & "\\system32\\cmd.exe"
{popup-message cmd-exe-path}
def hp = {spawn-host-process
read-stderr? = true,
cmd-exe-path ,
{StringArray "ipconfig"}
}
def tis = {hp.read-open-stdout}
def out = {tis.read}
{tis.close}
let str:String = ""
{for c in out do
set str = str & c
}
set ta.value = str
}
}
RE: Win32API を利用するには? - umemura - 04-25-2014
下記サイト等を参考に、DLLインタフェースを、見よう見まねで作ってみましたが、
IP_ADAPTER_INFO が思ったように取得できず、お手上げ状態です。
■MSDN
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365917(v=vs.85).aspx
そもそも、MACアドレス(物理アドレス)は、IP_ADAPTER_INFO のどのフィールドに入ってくるのかさえ、
よくわかっていません・・・。
Code: {define-C-struct public IP_ADDR_STRING
field public Next:{CArray-of IP_ADDR_STRING}
field public IpAddress:CString
field public IpMask:CString
field public Context:int
}
{define-C-struct public IP_ADAPTER_INFO
field public Next:{CArray-of IP_ADAPTER_INFO}
field public ComboIndex:int
field public AdapterName:CString
field public Description:CString
field public AddressLength:int
field public Address:int
field public Index:int
field public Type:int
field public DhcpEnabled:int
field public CurrentIpAddress:{CArray-of IP_ADDR_STRING}
field public IpAddressList:IP_ADDR_STRING
field public GatewayList:IP_ADDR_STRING
field public DhcpServer:IP_ADDR_STRING
field public HaveWins:int
field public PrimaryWinsServer:IP_ADDR_STRING
field public SecondaryWinsServer:IP_ADDR_STRING
field public LeaseObtained:int
field public LeaseExpires:int
}
{define-dll-class public Iphlpapi
{defaults
calling-convention = stdcall,
string-rep = CStringUTF16
}
{constructor public {default}
{construct-super {SharedLibrary "iphlpapi.dll"}}
}
{dll-method public {GetAdaptersInfo
pAdapterInfo:IP_ADAPTER_INFO,
pOutBufLen:int ||何を渡すべき?
}:int
}
}
{CommandButton
label = "Show MAC Adress",
{on Action do
let dll:Iphlpapi = {Iphlpapi}
def p = {IP_ADAPTER_INFO}
let result:int =
{dll.GetAdaptersInfo
p, 100000
}
{popup-message p}
}
}
型の定義の対応が間違っていますかね?
C言語の知識がなく、とくに下記のような内容は、おもいっきり無視してます。
■外部ライブラリ呼び出しに使うC構造体
http://developers.curlap.com/faq/49-faq-operation/650-2010-12-13-04-07-52.html
それとも、C++のDLLだからダメ、とかもありますかね?
■C++で作成したDLLについて
http://developers.curlap.com/faq/48-faq-specification/654-cdll.html
RE: Win32API を利用するには? - umemura - 04-28-2014
下記のサイトのDLL宣言文のフォーマットを対象にした、
簡易なDLLインタフェースの自動生成用ロジックを組んでみました。
■MSDN
http://msdn.microsoft.com/en-us/library/...s.85).aspx
DLLで定義される型が、Curl ではどんな型になるのかがわからないので、
もし知っている方がいらっしゃったら教えてください。
Code: ||DLLソースの種別
{define-enum public DLLType
struct, ||構造体
method, ||メソッド
interface ||インタフェースクラス
}
||DLL の型と、Curl の型の変換マップ
{def package type-map =
{{HashTable-of String, String}
||int
"DWORD", "int",
"COLORREF", "int",
||String
"LPCCTSTR", "#String",
"HWND", "CPointer",
"LPCCHOOKPROC", |"{StdcallCallback-to #WindowsHook}"|,
||++
||++ "", "",
||++ "", "",
||++ "", "",
||++ "", "",
"*", ""
}
}
||パラメータの形式
{define-enum public ParamType
out = "_Out_"
,out-option = "_Out_opt_"
,in-out = "_Inout_"
,in = "_In_"
,in-option = "_In_opt_"
}
||DLLの型に対応するCurlの型を返却する
||FIXME
||LPCT ごとに対応すべき?
||L:???
||P:ポインタ
||C :コンスタント
||T :???
{define-proc public {get-type-name
type-name:String
}:String
def ret-type-name =
{if {type-map.key-exists? type-name} then
type-map[type-name]
else
type-name
}
{return ret-type-name}
}
||(rep = CString-type [, max-size = size]) 等対応なし
{define-proc public {get-splited-ary str:String}:StringArray
||空白で区切られた文字を格納
def tmp = {str.split}
def ary = {StringArray}
{for s in tmp do
{if not s.empty? then
{ary.append s}
}
}
{return ary}
}
||特定の文字を削除する
{define-proc public {remove-strings str:String, remove-strings:StringArray}:String
let ret-str:String = str
{for s in remove-strings do
set ret-str = {ret-str.replace-clone s, ""}
}
{return ret-str}
}
||型と変数の名称を取得
{define-proc public {get-type-and-var
tgt-type-name:String,
tgt-var-name :String
}:(type-name:String, var-name:String)
let type-name:String = tgt-type-name
let var-name:String = {remove-strings tgt-var-name, {StringArray ";", ","}}
let pointer?:bool = false
||ポインタを表しているかどうかチェック
|| 型、もしくは変数にアスタリスクがついているかどうか
{if {var-name.find '*'} > -1 or
{type-name.find '*'} > -1
then
set type-name = {type-name.replace-clone "*", ""}
set var-name = {var-name.replace-clone "*", ""}
set pointer? = true
}
||型マップから変換
set type-name = {get-type-name tgt-type-name}
||ポインタ型の場合
{if pointer? then
set type-name = "\{CArray-of " & type-name & "\}"
}
{return type-name , var-name}
}
||構造体の変換
{define-proc public {gerate-curl-from-dll-struct
dll-source:String
}:String
||Curlのソース定義
let curl-source:String = |"{define-C-struct public "|
def clup-dll-source = {dll-source.trim-clone}
def dll-source-lines = {clup-dll-source.split split-chars = '\n'}
{for ln key idx:int in dll-source-lines do
||空白で区切られた文字を格納
def splt-source = {get-splited-ary ln}
{if idx == 0 then
||1行目は構造体の宣言
||①typedef ②struct ③型名 を想定
set curl-source = curl-source & splt-source[2]
else
||最初に「}」が来たら定義の終わりとして処理を終了
{if {splt-source[0].trim-clone}[0] == '\}' then
{break}
}
||①型名 ②変数名 を想定
|| ただし、①が「struct」の場合は、②型名 ③変数名になる(?)
||FIXME 未対応
||固定長、サイズ指定
||ポインタ(*)、アドレス(&)
||参考 http://bituse.info/c/10
let (tmp-type-name:String , tmp-var-name:String) =
{if splt-source[0] == "struct" then
(splt-source[1], splt-source[2])
else
(splt-source[0], splt-source[1])
}
def (type-name:String, var-name:String) =
{get-type-and-var tmp-type-name, tmp-var-name}
set curl-source = curl-source & " field public " & var-name & ":" & type-name
}
set curl-source = curl-source & "\n"
}
set curl-source = curl-source & "\}"
{return curl-source}
}
||メソッドの変換
{define-proc public {gerate-curl-from-dll-method
dll-source:String
}:String
||Curlのソース定義
let curl-source:String = |"{dll-method public "|
def clup-dll-source = {dll-source.trim-clone}
def dll-source-lines = {clup-dll-source.split split-chars = '\n'}
let return-var-name:String = ""
{for ln key idx:int in dll-source-lines do
||空白で区切られた文字を格納
def splt-source = {get-splited-ary ln}
{if idx == 0 then
||1行目はメソッドの宣言
||①戻り値型 ②メソッド名
||ただし、2番目の項目が「WINAPI」の場合、メソッド名は3番目
set return-var-name ={get-type-name splt-source[0]}
let method-name:String =
{if splt-source[1] == "WINAPI" then
splt-source[2]
else
splt-source[1]
}
set method-name = {method-name.replace-clone "(", ""}
set curl-source = curl-source &
{format |"{%s ("%s") "|, method-name, method-name}
else
||最初に「)」が来たら定義の終わりとして処理を終了
{if {splt-source[0].trim-clone}[0] == '\)' then
{break}
}
||①パラメータの形式 ②型 ③パラメータ変数名
def param-type = splt-source[0]
def (type-name:String, var-name:String) =
{get-type-and-var splt-source[1], splt-source[2]}
set curl-source = curl-source &
" " & var-name & ":" & type-name
{switch param-type
case ParamType.in.value ,
ParamType.in-out.value,
ParamType.out.value
do
case ParamType.in-option.value ,
ParamType.out-option.value
do
||オプションの場合は、初期値を指定
set curl-source = curl-source & " = null"
}
set curl-source = curl-source & ","
}
set curl-source = curl-source & "\n"
}
||引数の最後のカンマを削除
{if curl-source[curl-source.size - 2] == ',' then
def tmp-strb = {StringBuf curl-source}
{tmp-strb.remove curl-source.size - 2}
set curl-source = {tmp-strb.to-String}
}
set curl-source = curl-source & " \}:" & return-var-name & "\n\}"
{return curl-source}
}
||インターフェースの変換
{define-proc public {gerate-curl-from-dll-interface
dll-source:String
}:String
{return "インターフェース ┐(´Д`)┌ サッパリ ワカリマセン"}
}
||DLLの定義から、Curlのソースへ変換する
{define-proc public {gerate-curl-from-dll
dll-type:DLLType,
dll-source:String
}:String
let curl-source:String =
{switch dll-type
case DLLType.struct do
{gerate-curl-from-dll-struct dll-source}
case DLLType.method do
{gerate-curl-from-dll-method dll-source}
case DLLType.interface do
{gerate-curl-from-dll-interface dll-source}
else
""
}
{return curl-source}
}
||DLLソースの種別選択用ラジオボタン
{def rdb-strct = {RadioButton label = "構造体", radio-value = DLLType.struct}}
{def rdb-method = {RadioButton label = "メソッド", radio-value = DLLType.method}}
{def rdb-interface = {RadioButton label = "インタフェース", radio-value = DLLType.interface}}
{def rdfr =
{RadioFrame
{HBox
spacing = 10pt,
rdb-strct,
rdb-method,
rdb-interface
}
}
}
{def ta-dll-source =
{TextArea
width = 7in, height = 3in
}
}
{def ta-curl-source =
{TextArea
width = 7in, height = 3in
}
}
{def cb =
{CommandButton
label = "変換",
{on Action do
||DLLソースをCurlソースに変換
{if-non-null rdfr.value then
def curl-source =
{gerate-curl-from-dll
rdfr.value asa DLLType,
ta-dll-source.value
}
set ta-curl-source.value = curl-source
}
}
}
}
{VBox
{HBox spacing = 10pt, rdfr,cb },
ta-dll-source, ta-curl-source
}
RE: Win32API を利用するには? - kay - 12-12-2016
いつもお世話になっています。
私の方でもMACアドレスを取得したい件があったので確認してみました。
(04-24-2014, 09:41 PM)umemura Wrote: 「アプレット [9-121] - stdout が取得されていないか、既に開いています。の為、例外Errorで停止」
というエラーメッセージが出てしまいます。 こちらはパラメーターに誤りがあったようです。(ご提示の例だとread-stdout?がfalseになっていると思います)
cmdプロセスを実行する部分を以下のように変更することでipconfig /allの結果が取得できました。
Code: def hp = {spawn-host-process cmd-exe-path, {StringArray "/A /Q /S /C ipconfig /all"}, read-stdout? = true, read-stderr? = true, suppress-console-window? = true }def tis = {hp.read-open-stdout character-encoding = "shift-jis"}
cmdプロセスを使用するやり方の方がお手軽な感じがしますね。
|