Post Reply 
 
Thread Rating:
  • 164 Votes - 2.94 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Win32API を利用するには?
04-23-2014, 04:06 PM
Post: #1
Win32API を利用するには?
Curl でWin32API を利用するにはどうすればいいですか?

具体的には、マックアドレスを取得するための「GetAdaptersInfo」を利用したいです。

Win32API を ActiveXObject として利用できたりするのでしょうか。

それとも、kernel.dll や、user.dll から、DLLインタフェースを個別に作成して利用するしかないのでしょうか。
Find all posts by this user
Quote this message in a reply
04-24-2014, 02:10 PM (This post was last modified: 04-24-2014 02:11 PM by hokada.)
Post: #2
RE: Win32API を利用するには?
DLL Interface を使えば、GetAdaptersInfo()、もしくはGetAdaptersAddresses()をコールできるはずです。

それ以外のMacアドレスを取得する方法としては、ipconfigコマンドをspawn-host-process を使って実行し、アウトプットをパースする方法もあると思います。
Find all posts by this user
Quote this message in a reply
04-24-2014, 09:41 PM (This post was last modified: 04-25-2014 12:57 PM by umemura.)
Post: #3
RE: Win32API を利用するには?
『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
}
}
Find all posts by this user
Quote this message in a reply
04-25-2014, 01:50 PM (This post was last modified: 04-25-2014 02:00 PM by umemura.)
Post: #4
RE: Win32API を利用するには?
下記サイト等を参考に、DLLインタフェースを、見よう見まねで作ってみましたが、
IP_ADAPTER_INFO が思ったように取得できず、お手上げ状態です。

■MSDN
http://msdn.microsoft.com/en-us/library/...s.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-...07-52.html


それとも、C++のDLLだからダメ、とかもありますかね?

■C++で作成したDLLについて
http://developers.curlap.com/faq/48-faq-...-cdll.html
Find all posts by this user
Quote this message in a reply
04-28-2014, 12:43 PM (This post was last modified: 04-28-2014 01:49 PM by umemura.)
Post: #5
RE: Win32API を利用するには?
下記のサイトの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
}
Find all posts by this user
Quote this message in a reply
12-12-2016, 10:32 AM
Post: #6
RE: Win32API を利用するには?
いつもお世話になっています。
私の方でも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プロセスを使用するやり方の方がお手軽な感じがしますね。
Find all posts by this user
Quote this message in a reply
Post Reply 

Forum Jump:


User(s) browsing this thread:
1 Guest(s)