News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

IntPtr

Started by mabdelouahab, February 12, 2016, 08:15:21 AM

Previous topic - Next topic

mabdelouahab

hi all,
I've had some things that did not find resolved, so I want to discuss it with my teachers in this forum
I beat most of the problems of consensus between the .net and Masm, except for certain things, such as the problem of passing an argument of type system.IntPtr.
Any variable sends to/returne from .net method is a ptr to VARIANT,we can send any type without problems, but an exception (HRESULT: 80131604) has been thrown while using IntPtr Transformation
________
__Exept : [80131604]
__Method: [Void TestIntPtr(IntPtr)]
__Object: STATIC [0]
___________


this documentation explain how to marshal any object, it sed that  IntPtr transform  to variant of type VT_INT

My Helper (masm32ref) lets you insert an .net code (vb/csharp/JavaS) inside masm program, So I've created a program (Attachment) to illustrate the problem and help to resolve it,
I insert cs code, one static class with 5 function, the first is an empty proc by 1 arg (intptr) , just to facilitate the search for a solution
public static void  TestIntPtr(System.IntPtr iptr) { }
the second and the therd is the same proc, with diference argument, Fourth and fifth is the same proc, with difirent arg, and There are also other method to try
the sc code is compiled at runtim to tomporary dll,to use it as .net assembly
you can assembly by hjwasm a plase the ml

mabdelouahab



mabdelouahab

Quote from: dedndave on February 13, 2016, 08:46:29 AM
https://msdn.microsoft.com/en-us/library/system.intptr%28v=vs.110%29.aspx
dave
The problem is how to pass a variable of type System.IntPtr to .net methods
This link speaks in detail on the subject  https://msdn.microsoft.com/en-us/library/2x07fbw8%28v=vs.110%29.aspx

All types work well, but there are some species types that need special treats, like System.Decimal convert to Variant type VT_DECIMAL, but using the full variant
Quote
      VARIANT STRUCT                 
           wReserved           SWORD   VT_DECIMAL
          UNION
             signscale      SWORD   ?
            STRUCT                        
               scale      BYTE    ?         ;   Power of 10
               sign      BYTE    ?         ;   FALSE/TRUE (0,-1)
            ENDS
         ends
           Hi32              SDWORD   ?
          UNION
             Lo64         QWORD   ?
            STRUCT                        
               Lo32      SDWORD    ?
               Mid32      SDWORD    ?
            ENDS
         ends
       VARIANT ENDS
Also VT_RECORD using last QWORD of variant as 2 dword
Quote
VARIANT STRUCT 
      vt          WORD            VT_RECORD
      wReserved1  WORD            0
      wReserved2  WORD            0
      wReserved3  WORD            0
      pvRecord   DWORD ?
      pRecInfo   DWORD ?
VARIANT ENDS

As for type IntPtr I could not find a solution

dedndave

usually, API functions would receive a pointer to the structure
however, in the world of COM, they sometimes pass the entire structure

for VARIANT types, i find it's easier to work with (in ASM) if you prototype the functions with 4 DWORD's
for example...
;IUnknown interface vTable (structure)

IUnknown STRUCT
  METHOD(QueryInterface, _this:LPVOID,riid:LPVOID,ppvObj:LPVOID)
  METHOD(AddRef,         _this:LPVOID)
  METHOD(Release,        _this:LPVOID)
IUnknown ENDS

;IDispatch interface vTable (structure)

IDispatch STRUCT
    IUnknown                 <>
  METHOD(GetTypeInfoCount, _this:LPVOID,pctinfo:LPVOID)
  METHOD(GetTypeInfo,      _this:LPVOID,iTInfo:UINT,lcid:LCID,ppTInfo:LPVOID)
  METHOD(GetIDsOfNames,    _this:LPVOID,riid:LPVOID,rgszNames:LPOLESTR,cNames:UINT,lcid:LCID,rgDispId:LPVOID)
  METHOD(dInvoke,          _this:LPVOID,dispIdMember:DWORD,riid:LPVOID,lcid:LCID,wFlags:DWORD,pDispParams:LPVOID,pVarResult:LPVOID,pExcepInfo:LPVOID,puArgErr:LPVOID)
IDispatch ENDS

;IShellDispatch interface vTable (structure)
;       vDir VARIANT struct = vtDir:DWORD,vD0:DWORD,vstrDir:LPVOID,vDV0:DWORD
;vRootFolder VARIANT struct = vtRoot:DWORD,vR0:DWORD,vstrRoot:LPVOID,vRV0:DWORD

IShellDispatch STRUCT
    IDispatch                <>
  METHOD(Application,      _this:LPVOID,ppid:LPVOID)
  METHOD(Parent,           _this:LPVOID,ppid:LPVOID)
  METHOD(NameSpace,        _this:LPVOID,vtDir:DWORD,vD0:DWORD,vstrDir:LPVOID,vDV0:DWORD,ppsdf:LPVOID)
  METHOD(BrowseForFolder,  _this:LPVOID,Hwnd:DWORD,lpTitle:LPVOID,Options:DWORD,vtRoot:DWORD,vR0:DWORD,vstrRoot:LPVOID,vRV0:DWORD,ppsdf:LPVOID)
  METHOD(Windows,          _this:LPVOID,ppid:LPVOID)
  METHOD(Open,             _this:LPVOID,vtDir:DWORD,vD0:DWORD,vstrDir:LPVOID,vDV0:DWORD)
  METHOD(Explore,          _this:LPVOID,vtDir:DWORD,vD0:DWORD,vstrDir:LPVOID,vDV0:DWORD)
  METHOD(MinimizeAll,      _this:LPVOID)
  METHOD(UndoMinimizeALL,  _this:LPVOID)
  METHOD(FileRun,          _this:LPVOID)
  METHOD(CascadeWindows,   _this:LPVOID)
  METHOD(TileVertically,   _this:LPVOID)
  METHOD(TileHorizontally, _this:LPVOID)
  METHOD(ShutdownWindows,  _this:LPVOID)
  METHOD(Suspend,          _this:LPVOID)
  METHOD(EjectPC,          _this:LPVOID)
  METHOD(SetTime,          _this:LPVOID)
  METHOD(TrayProperties,   _this:LPVOID)
  METHOD(Help,             _this:LPVOID)
  METHOD(FindFiles,        _this:LPVOID)
  METHOD(FindComputer,     _this:LPVOID)
  METHOD(RefreshMenu,      _this:LPVOID)
  METHOD(ControlPanelItem, _this:LPVOID,bstrDir:LPVOID)


now let me find out about IntPtr
i think it's a single DWORD for 32-bit code (QWORD for 64-bit)

dedndave

oh ok
it's a VARIANT structure - do what i did, it will make life easier   :t

mabdelouahab

dave
This is the way to call .net methods, Any method in .net:  MethodBase.Invoke Method (Object, BindingFlags, Binder, Object[], CultureInfo)
I translate it to be available to users of Masm in DotNetHelper.inc:
__Private_BasicInvoke proc  c uses ECX EDX ebx ESI EDI   ParamsCount:dword,mtd__:DWORD,Object__:DWORD,lpRetVal,Params:VARARG
    LOCAL __hParam,exept_
    LOCAL P_data:DWORD
    LOCAL __InvokevtMethod :VARIANT
    LOCAL __Exc_MethodStr :VARIANT
    LOCAL __Exc_ObjectStr :VARIANT
.data
__ParamInvokeSAFEARRAY SAFEARRAY <>
__BasicInvokeSAFEARRAY SAFEARRAY <>
__InvokepvData VARIANT  2 dup(<>)
__InvokevtRetValue VARIANT <>
.code
.if !ParamsCount
    xor EAX, EAX                 
    mov edx, [ebp+4]             
    cmp WORD PTR[edx], 0C483h   
    jne  @F
    MOVZX EAX, BYTE PTR [EDX+2]   
    SHR EAX, 2 
SUB eax,4
MOV ParamsCount,eax
  @@:
.endif
.IF !__Basic_Invoke
CALL __Private_GetBasicMethods
.ENDIF
.IF __Basic_Invoke
.IF ParamsCount
MOV EAX,16
MOV ECX,ParamsCount
Mul ECX
MOV ECX,EAX
invoke CoTaskMemAlloc ,ECX
MOV P_data,EAX
MOV EDI,EAX
MOV ECX,ParamsCount
xor EDX,edx
@@:
cmp ECX,edx
je @F 
PUSH ECX
PUSH EDX
;---------------------
    MOV ECX, Params[EDX*4]   
    .IF ECX    
    INVOKE RtlMoveMemory,EDI,ECX,16
    .ELSE
    INVOKE RtlZeroMemory,EDI,SIZEOF VARIANT
    .ENDIF
ADD EDI,16
;---------------------
POP EDX
POP ECX
inc EDX
jmp @B
@@:
.ELSE
MOV P_data,FALSE
.ENDIF
LEA ECX,__ParamInvokeSAFEARRAY
MOV [ECX].SAFEARRAY.cDims            ,1
MOV [ECX].SAFEARRAY.fFeatures        ,0
        MOV [ECX].SAFEARRAY.cbElements      ,16
MOV [ECX].SAFEARRAY.cLocks          ,0
m2m [ECX].SAFEARRAY.pvData          ,P_data
MOV EAX,ParamsCount
MOV [ECX].SAFEARRAY.rgsabound.cElements ,EAX
MOV [ECX].SAFEARRAY.rgsabound.lLbound   ,0 

LEA ECX,__BasicInvokeSAFEARRAY
MOV [ECX].SAFEARRAY.cDims            ,1
MOV [ECX].SAFEARRAY.fFeatures        ,0
        MOV [ECX].SAFEARRAY.cbElements      ,16
MOV [ECX].SAFEARRAY.cLocks          ,0
LEA EAX,__InvokepvData
m2m [ECX].SAFEARRAY.pvData          ,EAX
MOV EAX,ParamsCount
MOV [ECX].SAFEARRAY.rgsabound.cElements ,2
MOV [ECX].SAFEARRAY.rgsabound.lLbound   ,0 

LEA EDI,__InvokepvData
.IF Object__
INVOKE RtlMoveMemory,EDI,Object__,SIZEOF VARIANT
.ELSE
INVOKE RtlZeroMemory,EDI,SIZEOF VARIANT
.ENDIF
ADD EDI,SIZEOF VARIANT
MOV [EDI].VARIANT.vt,0200CH
LEA EAX,__ParamInvokeSAFEARRAY
m2m [EDI].VARIANT.parray,EAX
MOV cx,__vtOfMethods
MOV __InvokevtMethod.vt,cx
PUSH mtd__
POP __InvokevtMethod.punkVal
LEA EAX,__InvokevtRetValue
PUSH EAX
LEA EAX ,__BasicInvokeSAFEARRAY
PUSH EAX
    LEA EDI,__InvokevtMethod
PUSH DWORD PTR [EDI+12]
PUSH DWORD PTR [EDI+8]
PUSH DWORD PTR [EDI+4]
PUSH DWORD PTR [EDI]
MOV EDX, __Basic_Invoke
PUSH EDX   
MOV EDX,[EDX]   
CALL DWORD PTR [EDX+148]
.IF !EAX
.IF lpRetVal
INVOKE RtlMoveMemory,lpRetVal,addr __InvokevtRetValue,SIZEOF VARIANT
MOV EAX,lpRetVal
.ENDIF
MOV EAX,TRUE
.ELSE
mov exept_,eax
.data
__pInvoke_ErrBuf db 128*2*3 dup(?)
.code
invoke RtlZeroMemory,addr __pInvoke_ErrBuf,128*2*3
invoke lstrcat,addr __pInvoke_ErrBuf,BSTR$(13,10,"___________",13,10,"__Exept : [")
invoke lstrcat,addr __pInvoke_ErrBuf,_rv(__Hex,exept_)
invoke lstrcat,addr __pInvoke_ErrBuf,BSTR$("]")

LEA EAX,__Exc_MethodStr
PUSH EAX
LEA EAX,__InvokevtMethod
PUSH EAX
CALL __Private_BasicToString
.IF EAX
invoke lstrcat,addr __pInvoke_ErrBuf,BSTR$(13,10,"__Method: [")
invoke lstrcat,addr __pInvoke_ErrBuf,__Exc_MethodStr.punkVal
.ELSE
invoke lstrcat,addr __pInvoke_ErrBuf,BSTR$(13,10,"__Method: [?")
.ENDIF
invoke lstrcat,addr __pInvoke_ErrBuf,BSTR$("]")
.IF Object__
LEA EAX,__Exc_ObjectStr
PUSH EAX
PUSH Object__
CALL __Private_BasicToString
.IF EAX
invoke lstrcat,addr __pInvoke_ErrBuf,BSTR$(13,10,"__Object: [")
invoke lstrcat,addr __pInvoke_ErrBuf,__Exc_ObjectStr.punkVal
invoke lstrcat,addr __pInvoke_ErrBuf,BSTR$("]")
.ELSE
invoke lstrcat,addr __pInvoke_ErrBuf,BSTR$(13,10,"__Object:  [???] ")
.ENDIF
.ELSE
invoke lstrcat,addr __pInvoke_ErrBuf,BSTR$(13,10,"__Object: STATIC [0] ")
.ENDIF
invoke lstrcat,addr __pInvoke_ErrBuf,BSTR$(13,10,"___________")
__ExeptionMsg addr __pInvoke_ErrBuf
MOV EAX,FALSE
.ENDIF
PUSH EAX
.IF ParamsCount
invoke CoTaskMemFree,P_data
.ENDIF
POP  EAX
.ELSE
MOV EAX,FALSE
.ENDIF
ret
__Private_BasicInvoke ENDP


see :    object[] parameters; Is a array (SAFEARRAY) of the VARIANT, Any argument must be in the form of a VARIANT to pass.