UWSCで構造体がもうあんまり怖くないmodule

以下の記事ちょっとごちゃっとしすぎてるのであまりみても面白くありません
こっちにもう少しさっぱりしたものがあります
結局ごちゃっとしてるんですけどね


きっかけはWTSEnumerateSessionsExのWTS_SESSION_INFO_1構造体
肝心のセッション情報がuwscからだと取れない!ファック!みたいな出来事があり
自前の構造体を作る、構造体からデータを読み出す、が出来るモジュールを書いてみた
とりあえずは想定通りに動いてはいるけどそのうちボロが出るぞきっとこれ
まぁでもuwscだって頑張ればこんなことも出来るよって話…てことで、ね

ifb GET_UWSC_NAME = "Module_Struct.uws" then
  try
    try
      print "構造体を作ってデータを格納し、そこらから値を読むテスト"
      print
      
      hashtbl hTestStruct
      Struct.AddMember(hTestStruct, "int", Struct.TYPE_INT, 1234)
      Struct.AddMember(hTestStruct, "long", Struct.TYPE_LONG, 5678)
      Struct.AddMember(hTestStruct, "word", Struct.TYPE_WORD, $FFFF)
      Struct.AddMember(hTestStruct, "byte", Struct.TYPE_BYTE, $FF)
      Struct.AddMember(hTestStruct, "string", Struct.TYPE_STRING, "hello world")
      Struct.AddMember(hTestStruct, "double", Struct.TYPE_DOUBLE, 3.1415)
      Struct.AddMember(hTestStruct, "float", Struct.TYPE_FLOAT, 3.1415)
      
      dim pTestStruct
      testStructSize = Struct.CreateStruct(hTestStruct, pTestStruct)
      if testStructSize then
        print "Address of testStruct: " + pTestStruct
        print "Size of testStruct: " + testStructSize + "byte"
        if Struct.GetStructValues(pTestStruct, hTestStruct) then
          for i = 0 to length(hTestStruct) - 1
            name = hTestStruct[i, HASH_KEY]
            print "pTestStruct." + name + " = " + Struct.GetMember(hTestStruct, name)
          next
        else
          print Struct.GetLastErrorString()
        endif
        Struct.FreeStruct(pTestStruct)
      else
        print Struct.GetLastErrorString()
      endif
      
      print 
      print "構造体を作ってdll関数に渡し、値を読むテスト"
      print
      def_dll GetWindowRect(hwnd, dword):long:user32
      hashtbl hRect
      dim pRect
      Struct.AddMember(hRect, "left", Struct.TYPE_LONG, 0)
      Struct.AddMember(hRect, "top", Struct.TYPE_LONG, 0)
      Struct.AddMember(hRect, "right", Struct.TYPE_LONG, 0)
      Struct.AddMember(hRect, "bottom", Struct.TYPE_LONG, 0)
      
      StructSize = Struct.CreateStruct(hRect, pRect)
      id = exec("notepad")
      GetWindowRect(idtohnd(id), pRect)
      if StructSize > 0 then
        print "Address of pRect: " + pRect
        print "Size of pRect: " + StructSize + "byte"
        if Struct.GetStructValues(pRect, hRect) then
          for i = 0 to length(hRect) - 1
            name = hRect[i, HASH_KEY]
            print "pRect." + name + " = " + Struct.GetMember(hRect, name)
          next
          print
          print "比較用"
          print "status(id, ST_X) = " + status(id, ST_X)
          print "status(id, ST_Y) = " + status(id, ST_Y)
          print "status(id, ST_X) + status(id, ST_WIDTH) = " + (status(id, ST_X) + status(id, ST_WIDTH))
          print "status(id, ST_Y) + status(id, ST_HEIGHT)= " + (status(id, ST_Y) + status(id, ST_HEIGHT))
        else
          print Struct.GetLastErrorString()
        endif
        Struct.FreeStruct(pTestStruct)
      else
        print Struct.GetLastErrorString()
      endif
      ctrlwin(id, close)
      print
      
      print "WTSEnumerateSessionsExに挑戦"
      print "第4引数がWTS_SESSION_INFO_1構造体の配列のアドレスを格納した変数のポインタ"
      print "なので、def_dll宣言時に通常の{ }展開では値が取れない"
      print
      
      def_dll WTSEnumerateSessionsExA(dword, var dword, dword, var dword, var dword):bool:Wtsapi32
      dim PWTS_SESSION_INFO_1, COUNT
      dim pLevel = 1, Filter = 0
      hashtbl hWtsSessionInfoType
      Struct.AddMember(hWtsSessionInfoType, "ExecEnvId", Struct.TYPE_DWORD, 0)
      Struct.AddMember(hWtsSessionInfoType, "State", Struct.TYPE_DWORD, 0)
      Struct.AddMember(hWtsSessionInfoType, "SessionId", Struct.TYPE_DWORD, 0)
      Struct.AddMember(hWtsSessionInfoType, "pSessionName", Struct.TYPE_DWORD, 0)
      Struct.AddMember(hWtsSessionInfoType, "pHostName", Struct.TYPE_DWORD, 0)
      Struct.AddMember(hWtsSessionInfoType, "pUserName", Struct.TYPE_DWORD, 0)
      Struct.AddMember(hWtsSessionInfoType, "pDomainName", Struct.TYPE_DWORD, 0)
      Struct.AddMember(hWtsSessionInfoType, "pFarmName", Struct.TYPE_DWORD, 0)
      
      sizeOfWtsSessionInfoType = Struct.GetSizeOfStruct(hWtsSessionInfoType)
      
      if WTSEnumerateSessionsExA(null, pLevel, Filter, PWTS_SESSION_INFO_1, COUNT) then
        for i = 0 to COUNT - 1
          ptr = PWTS_SESSION_INFO_1 + (i * sizeOfWtsSessionInfoType)
          if Struct.GetStructValues(ptr, hWtsSessionInfoType) then
            for i = 0 to length(hWtsSessionInfoType) - 1
              name = hWtsSessionInfoType[i, HASH_KEY]
              value = Struct.GetMember(hWtsSessionInfoType, name)
              print name + " = " + value
              if pos("p", name) = 1 then   //p*****はstringのポインタなので値も取る
                value = Struct.GetValueFromPointer(value, Struct.TYPE_STRING)
                print "  " + copy(name, 2) + " = " + value
              endif
            next
          endif
          print
        next
      endif
      
      exit
    except
      print TRY_ERRLINE
      print TRY_ERRMSG
    endtry
  finally
    pid = getid(GET_LOGPRINT_WIN)
    while status(pid, ST_VISIBLE)
      sleep(0.1)
    wend
  endtry
endif


module Struct
  
  procedure Struct
    _hashTypeName[TYPE_INT      ] = "TYPE_INT"
    _hashTypeName[TYPE_LONG     ] = "TYPE_LONG"
    _hashTypeName[TYPE_BOOL     ] = "TYPE_BOOL"
    _hashTypeName[TYPE_UINT     ] = "TYPE_UINT"
    _hashTypeName[TYPE_HWND     ] = "TYPE_HWND"
    _hashTypeName[TYPE_STRING   ] = "TYPE_STRING"
    _hashTypeName[TYPE_WSTRING  ] = "TYPE_WSTRING"
    _hashTypeName[TYPE_FLOAT    ] = "TYPE_FLOAT"
    _hashTypeName[TYPE_DOUBLE   ] = "TYPE_DOUBLE"
    _hashTypeName[TYPE_WORD     ] = "TYPE_WORD"
    _hashTypeName[TYPE_DWORD    ] = "TYPE_DWORD"
    _hashTypeName[TYPE_BYTE     ] = "TYPE_BYTE"
    _hashTypeName[TYPE_CHAR     ] = "TYPE_CHAR"
    _hashTypeName[TYPE_PCHAR    ] = "TYPE_PCHAR"
    _hashTypeName[TYPE_WCHAR    ] = "TYPE_WCHAR"
    _hashTypeName[TYPE_PWCHAR   ] = "TYPE_PWCHAR"
    _hashTypeName[TYPE_BOOLEAN  ] = "TYPE_BOOLEAN"
    _hashTypeName[TYPE_LONGLONG ] = "TYPE_LONGLONG"
    _hashTypeName[TYPE_EXTENDED ] = "TYPE_EXTENDED"
    _hashTypeName[TYPE_SAFEARRAY] = "TYPE_SAFEARRAY"
  fend
  
  dim _lastErrorDescription
  hashtbl _hashTypeName

  const TYPE_INT       = 0
  const TYPE_LONG      = 1
  const TYPE_BOOL      = 2
  const TYPE_UINT      = 3
  const TYPE_HWND      = 4
  const TYPE_STRING    = 5
  const TYPE_WSTRING   = 6
  const TYPE_FLOAT     = 7
  const TYPE_DOUBLE    = 8
  const TYPE_WORD      = 9
  const TYPE_DWORD     = 10
  const TYPE_BYTE      = 11
  const TYPE_CHAR      = 12
  const TYPE_PCHAR     = 13
  const TYPE_WCHAR     = 14
  const TYPE_PWCHAR    = 15
  const TYPE_BOOLEAN   = 16
  const TYPE_LONGLONG  = 17
  const TYPE_EXTENDED  = 18
  const TYPE_SAFEARRAY = 19
  
  const MEMBER_TYPE  = 0
  const MEMBER_VALUE = 1
  
  const MEM_COMMIT             = $1000
  const PAGE_READWRITE         = $4
  const PAGE_EXECUTE_READWRITE = $40
  Const MEM_RELEASE            = $8000
  const MEM_DECOMMIT           = $4000

  def_dll VirtualAlloc(dword, dword, dword, dword):dword:kernel32
  def_dll VirtualFree(dword, dword, dword):long:kernel32

  function CreateStruct(hashStruct[], var pStruct)
    structSize = GetSizeOfStruct(hashStruct)
    if structSize then
      result = structSize
      pStruct = VirtualAlloc(null, structSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE)
      ptr = pStruct
      for i = 0 to length(hashStruct) - 1
        mName = hashStruct[i, HASH_KEY]
        type = GetMember(hashStruct, mName, MEMBER_TYPE)
        value = GetMember(hashStruct, mName, MEMBER_VALUE)
        size = _copyVariableToPointer(ptr, value, type)
        if size then
          ptr = ptr + size
        else
          _setErrorString("CreateStruct: _copyVariableToPointer()が次のエラーを返しました -> " + GetLastErrorString())
          result = 0
          exit
        endif
      next
    else
      _setErrorString("CreateStruct: GetSizeOfStruct()が次のエラーを返しました -> " + GetLastErrorString())
      result = 0
    endif
    
  fend

  function GetStructValues(pStruct,var hashStruct[])
    result = true
    ptr = pStruct
    for i = 0 to length(hashStruct) - 1
      mName = hashStruct[i, HASH_KEY]
      type = GetMember(hashStruct, mName, MEMBER_TYPE)
      value = _getValueFromPointer(ptr, type)
      if value = empty then
        _setErrorString("GetStructValues: _getValueFromPointer()が次のエラーを返しました -> " + GetLastErrorString())
        result = false
        exit
      else
        _setMemberValue(hashStruct, mName, value)
        ptr = ptr + _getSize(type, value)
      endif
    next
  fend
  
  function GetValueFromPointer(pointer, type)
    if pointer then
      result = _getValueFromPointer(pointer, type)
      if result = empty then
        _setErrorString("GetValueFromPointer: _getValueFromPointer()が次のエラーを返しました -> " + GetLastErrorString())
      endif
    else
      _setErrorString("GetValueFromPointer: pointerが0です")
      result = empty
    endif
  fend
  
  function FreeStruct(hStruct, size = 0)
    result = VirtualFree(hStruct, size, MEM_RELEASE)
  fend
  
  function GetLastErrorString()
    result = _lastErrorDescription
  fend
  
  function GetSizeOfStruct(hashStruct[])
    result = 0
    for i = 0 to length(hashStruct) - 1
      mName = hashStruct[i, HASH_KEY]
      type = GetMember(hashStruct, mName, MEMBER_TYPE)
      select type
        case TYPE_STRING
          value = GetMember(hashStruct, mName, MEMBER_VALUE)
          size = _getSize(type, value)
        default
          size = _getSize(type)
      selend
      if size then
        result = result + size
      else
        _setErrorString("GetSizeOfStruct: 未対応の型[" + _hashTypeName[type] + "]")
        result = 0
        break
      endif
    next
  fend
  
  procedure AddMember(var hashStruct[], menberName, memberType, memberValue)
    sa = safearray(0,1)
    sa[MEMBER_TYPE]  = memberType
    sa[MEMBER_VALUE] = memberValue
    hashStruct[menberName] = sa
  fend
  
  function GetMember(hashStruct[], menberName, CONST_MEMBER = MEMBER_VALUE)
    sa = hashStruct[menberName]
    result = sa[CONST_MEMBER]
  fend
  
  procedure _setMemberValue(var hashStruct[], menberName, memberValue)
    sa = hashStruct[menberName]
    sa[MEMBER_VALUE] = memberValue
    hashStruct[menberName] = sa
  fend
  
  function _getSize(type, str = "")
    result = 0
    select type
      case TYPE_INT, TYPE_LONG, TYPE_BOOL, TYPE_UINT, TYPE_HWND, TYPE_DWORD
        result = 4
      case TYPE_STRING   
        result = lengthb(str)
        mod4 = result mod 4
        if mod4 then result = result + (4 - mod4)
    //  case TYPE_WSTRING  
      case TYPE_FLOAT
        result = 4
      case TYPE_DOUBLE
        result = 8
      case TYPE_WORD
        result = 2
      case TYPE_BYTE, TYPE_CHAR, TYPE_BOOLEAN
        result = 1
      case TYPE_PCHAR, TYPE_PWCHAR
        result = 4
    //  case TYPE_WCHAR
      case TYPE_LONGLONG 
        result = 8
    //  case TYPE_EXTENDED 
    //  case TYPE_SAFEARRAY
      default
        result = 0
    selend
  fend
  
  function _copyVariableToPointer(pointer, variable, const_type)

    try
      result = _getSize(const_type, variable)
      if result
        select const_type
          case TYPE_INT
            def_dll RtlMoveMemory(dword, var int, dword):kernel32
          case TYPE_LONG
            def_dll RtlMoveMemory(dword, var LONG, dword):kernel32
          case TYPE_BOOL
            def_dll RtlMoveMemory(dword, var BOOL, dword):kernel32
          case TYPE_UINT
            def_dll RtlMoveMemory(dword, var UINT, dword):kernel32
          case TYPE_HWND
            def_dll RtlMoveMemory(dword, var HWND, dword):kernel32
          case TYPE_STRING
            def_dll RtlMoveMemory(dword, var STRING, dword):kernel32
          case TYPE_WSTRING
            def_dll RtlMoveMemory(dword, var WSTRING, dword):kernel32
          case TYPE_FLOAT
            def_dll RtlMoveMemory(dword, var FLOAT, dword):kernel32
          case TYPE_DOUBLE
            def_dll RtlMoveMemory(dword, var DOUBLE, dword):kernel32
          case TYPE_WORD
            def_dll RtlMoveMemory(dword, var WORD, dword):kernel32
          case TYPE_DWORD
            def_dll RtlMoveMemory(dword, var DWORD, dword):kernel32
          case TYPE_BYTE
            def_dll RtlMoveMemory(dword, var BYTE, dword):kernel32
          case TYPE_CHAR
            def_dll RtlMoveMemory(dword, CHAR, dword):kernel32
          case TYPE_PCHAR
            def_dll RtlMoveMemory(dword, PCHAR, dword):kernel32
          case TYPE_WCHAR
            def_dll RtlMoveMemory(dword, WCHAR, dword):kernel32
          case TYPE_PWCHAR
            def_dll RtlMoveMemory(dword, PWCHAR, dword):kernel32
          case TYPE_BOOLEAN
            def_dll RtlMoveMemory(dword, var BOOLEAN, dword):kernel32
          case TYPE_LONGLONG
            def_dll RtlMoveMemory(dword, var LONGLONG, dword):kernel32
          case TYPE_EXTENDED
            def_dll RtlMoveMemory(dword, var EXTENDED, dword):kernel32
          case TYPE_SAFEARRAY
            def_dll RtlMoveMemory(dword, var SAFEARRAY, dword):kernel32
          default
            _setErrorString("_copyVariableToPointer: 型指定が不正 [" + const_type + "]")
            result = 0
            exit
        selend
        RtlMoveMemory(pointer, variable, result)
      else
        _setErrorString("_copyVariableToPointer: 未対応の型[" + _hashTypeName[const_type] + "]")
      endif
    except
      _setErrorString("_copyVariableToPointer: コピー失敗 - " + TRY_ERRMSG + " " + TRY_ERRLINE)
      result = 0
    endtry
  fend
  
  function _getValueFromPointer(pointer, const_type, buffer = "")
    select const_type
      case TYPE_INT
        def_dll RtlMoveMemory(var int, dword, dword):kernel32
      case TYPE_LONG
        def_dll RtlMoveMemory(var long, dword, dword):kernel32
      case TYPE_BOOL
        def_dll RtlMoveMemory(var bool, dword, dword):kernel32
      case TYPE_UINT
        def_dll RtlMoveMemory(var uint, dword, dword):kernel32
      case TYPE_HWND
        def_dll RtlMoveMemory(var hwnd, dword, dword):kernel32
      case TYPE_STRING
        def_dll RtlMoveMemory(var string, dword, dword):kernel32
        buffer = format(chr(0), 1024)
      case TYPE_WSTRING
        def_dll RtlMoveMemory(var wstring, dword, dword):kernel32
      case TYPE_FLOAT
        def_dll RtlMoveMemory(var float, dword, dword):kernel32
      case TYPE_DOUBLE
        def_dll RtlMoveMemory(var double, dword, dword):kernel32
      case TYPE_WORD
        def_dll RtlMoveMemory(var word, dword, dword):kernel32
      case TYPE_DWORD
        def_dll RtlMoveMemory(var dword, dword, dword):kernel32
      case TYPE_BYTE
        def_dll RtlMoveMemory(var byte, dword, dword):kernel32
      case TYPE_CHAR
        def_dll RtlMoveMemory(char, dword, dword):kernel32
      case TYPE_PCHAR
        def_dll RtlMoveMemory(pchar, dword, dword):kernel32
      case TYPE_WCHAR
        def_dll RtlMoveMemory(wchar, dword, dword):kernel32
      case TYPE_PWCHAR
        def_dll RtlMoveMemory(pwchar, dword, dword):kernel32
      case TYPE_BOOLEAN
        def_dll RtlMoveMemory(var boolean, dword, dword):kernel32
      case TYPE_LONGLONG
        def_dll RtlMoveMemory(var longlong, dword, dword):kernel32
      case TYPE_EXTENDED
        def_dll RtlMoveMemory(var extended, dword, dword):kernel32
      case TYPE_SAFEARRAY
        def_dll RtlMoveMemory(var safearray, dword, dword):kernel32
      default
        _setErrorString("_getValueFromPointer: 型指定が不正 [" + const_type + "]")
        result = 0
        exit
    selend
    try
      if lengthb(buffer) then
        result = buffer
        size = _getSize(const_type, buffer)
      else
        result = empty
        size = _getSize(const_type)
      endif
      if size
        RtlMoveMemory(result, pointer, size)
      else
        _setErrorString("_getValueFromPointer: 未対応の型[" + _hashTypeName[const_type] + "]")
      endif
    except
      _setErrorString("_getValueFromPointer: コピー失敗 - " + TRY_ERRMSG + " " + TRY_ERRLINE)
      result = empty
    endtry
  fend
  
  procedure _setErrorString(str)
    _lastErrorDescription = str
  fend

endmodule

UWSCで構造体がもうあんまり怖くないmodule」への2件のフィードバック

  1. ピンバック: じゅんじゅんのきまぐれ

  2. ピンバック: 続・UWSCで構造体がもうあんまり怖くないmodule | たっぷす庵

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中