Tutorial on Accessing COM objects in ASM link
Tutorial on Accessing COM objects in ASM link
Hi
I dont know nothing of ASM but for anyone who knows it it could be interesant to see this info, its a Tutorial on Accessing COM objects in ASM :
http://com4me.net/win32asm/tutes/genera ... &idTute=38
I dont know nothing of ASM but for anyone who knows it it could be interesant to see this info, its a Tutorial on Accessing COM objects in ASM :
http://com4me.net/win32asm/tutes/genera ... &idTute=38
ARGENTINA WORLD CHAMPION
> could be the asm macro converted to pb?, i know we have
> the callcom lib but it would be very interesting to understand
> how com works.
I understood it... and made CallCOM() for using OOP with PureBasic..
You want to know how it works internally ??
Make a coffey, sit down and read slowly and carefully...
..i will try to explain.
Here is an example that shows a little bit what a 'COM-Object'
is internally.
The object itself is a variable (long) that holds a pointer to
a pointer to a list.
This list has entries to all procedures in it.
What is very important here is that the first parameter
of every procedure/method in the class must be "this".
This first parameter is the object itself.
If you look at this code carefully, you will see how the Constants
for CallCOM() are made.
The constant for a function/method is the 'index in the list * 4'
('*4' because its LONG, 4 bytes).
The command CallCOM() is good because it has variable argument count.
We dont have this for PureBasic-Procedures now, so we must
make separate procedures for every count.
Lets name the procedures myCallCOMx() - where x is the number of arguments:
Now, this should give you the rest and enlighten you guys... 
The people who fully understand the above code, know how
simple object oriented programming (OOP) works internally.
Now, the above example-class is very wrong, because all classes
inherit from a standard class with the 3 methods
QueryInterface, AddRef and Release.
EVERY class has this 3 standard-methods, so the interface
definition begins always with:
Oh well... sorry, its not easy for me to explain all this in english.
I hope somebody could understand it...
The hardest thing to explain is how you get/make the constants
for interfaces used by windows.
For this, you must have the MS Platform SDK and search the
C/C++ headers ( in psdk\include\ ) for the interface definition.
For completeness sake, here my examples again:
Example 1 - Create Shell-Links:
Example 2 - Hide Window from Taskbar:
Direct Examples:
Here some examples how to call/use DirectX directly: DOWNLOAD PureDX
CallCOM() is the same as CallDX() internally.
Whatever you want to call.... ATL,ActiveX,OLE,DirectX,whatever..
(all together = COM, Component Object Model) -
it works all the same way internally.
Please... somebody tell me he understood my class-code... please...

> the callcom lib but it would be very interesting to understand
> how com works.
I understood it... and made CallCOM() for using OOP with PureBasic..

You want to know how it works internally ??
Make a coffey, sit down and read slowly and carefully...
..i will try to explain.
Here is an example that shows a little bit what a 'COM-Object'
is internally.
The object itself is a variable (long) that holds a pointer to
a pointer to a list.
This list has entries to all procedures in it.
Code: Select all
;
; by Danilo, 17.03.2003
;
;
#Function1 = 0 * 4 ; 0
#Function2 = 1 * 4 ; 4
#ADDITION = 2 * 4 ; 8
;
Procedure Function1(this)
Beep_(800,100)
EndProcedure
;
Procedure Function2(this,string.s)
MessageRequester("INFO",string,0)
EndProcedure
;
Procedure Function3(this,a,b)
ProcedureReturn a+b
EndProcedure
;
Procedure CreateMyClass()
Shared x
Dim CreateMyClass_Interface.l(3)
CreateMyClass_Interface(0) = @Function1()
CreateMyClass_Interface(1) = @Function2()
CreateMyClass_Interface(2) = @Function3()
x = @CreateMyClass_Interface()
ProcedureReturn @x
EndProcedure
;
object = CreateMyClass()
;
CallCOM(#Function1,object)
CallCOM(#Function2,object,"Hello")
CallCOM(#Function1,object)
CallCOM(#Function2,object,"Hello World!")
CallCOM(#Function1,object)
MessageRequester("Result", Str( CallCOM(#ADDITION ,object,12,8) ),0)
of every procedure/method in the class must be "this".
This first parameter is the object itself.
If you look at this code carefully, you will see how the Constants
for CallCOM() are made.
The constant for a function/method is the 'index in the list * 4'
('*4' because its LONG, 4 bytes).
The command CallCOM() is good because it has variable argument count.
We dont have this for PureBasic-Procedures now, so we must
make separate procedures for every count.
Lets name the procedures myCallCOMx() - where x is the number of arguments:
Code: Select all
;
; by Danilo, 04.05.2003
;
;
;>---------
;>---------
;
;- CallCOM procedures
Structure LONG
l.l
EndStructure
;
Procedure myCallCOM0(index,*object.LONG)
*pointer_to_list.LONG = *object\l
*pointer_to_list + index
*address_of_procedure = *pointer_to_list\l
ProcedureReturn CallFunctionFast(*address_of_procedure,*object)
EndProcedure
;
Procedure myCallCOM1(index,*object.LONG,arg1)
*pointer_to_list.LONG = *object\l
*pointer_to_list + index
*address_of_procedure = *pointer_to_list\l
ProcedureReturn CallFunctionFast(*address_of_procedure,*object,arg1)
EndProcedure
;
Procedure myCallCOM2(index,*object.LONG,arg1,arg2)
*pointer_to_list.LONG = *object\l
*pointer_to_list + index
*address_of_procedure = *pointer_to_list\l
ProcedureReturn CallFunctionFast(*address_of_procedure,*object,arg1,arg2)
EndProcedure
;
;>---------
;>---------
;- Class Interface Definition
#Function1 = 0 * 4 ; 0
#Function2 = 1 * 4 ; 4
#ADDITION = 2 * 4 ; 8
#SUBTRACTION = 3 * 4 ; 12
;- Class methods/procedures
;- method 1
Procedure Function1(this)
Beep_(800,100)
EndProcedure
;
;- method 2
Procedure Function2(this,string.s)
MessageRequester("INFO",string,0)
EndProcedure
;
;- method 3
Procedure Function3(this,a,b)
ProcedureReturn a+b
EndProcedure
;
;- method 4
Procedure Subtraction(this,a,b)
ProcedureReturn a-b
EndProcedure
;- class creation
Procedure CreateMyClass()
Shared x
Dim CreateMyClass_Interface.l(4)
CreateMyClass_Interface(0) = @Function1()
CreateMyClass_Interface(1) = @Function2()
CreateMyClass_Interface(2) = @Function3()
CreateMyClass_Interface(3) = @Subtraction()
x = @CreateMyClass_Interface()
ProcedureReturn @x
EndProcedure
;
;
;- Program START
;
; create an object
object = CreateMyClass()
;
; call some functions/methods in the object
myCallCOM0(#Function1,object)
myCallCOM1(#Function2,object,@"Hello World!") ; (we must use '@' here, because its a pointer to the string)
myCallCOM0(#Function1,object)
MessageRequester("ADD", Str( myCallCOM2(#ADDITION ,object, 50,112) ),0)
myCallCOM0(#Function1,object)
MessageRequester("SUB", Str( myCallCOM2(#SUBTRACTION,object,118, 2) ),0)
myCallCOM0(#Function1,object)

The people who fully understand the above code, know how
simple object oriented programming (OOP) works internally.
Now, the above example-class is very wrong, because all classes
inherit from a standard class with the 3 methods
QueryInterface, AddRef and Release.
EVERY class has this 3 standard-methods, so the interface
definition begins always with:
Code: Select all
#QueryInterface = 0 * 4
#AddRef = 1 * 4
#Release = 2 * 4
I hope somebody could understand it...
The hardest thing to explain is how you get/make the constants
for interfaces used by windows.
For this, you must have the MS Platform SDK and search the
C/C++ headers ( in psdk\include\ ) for the interface definition.
For completeness sake, here my examples again:
Example 1 - Create Shell-Links:
Code: Select all
Procedure CreateLink(PATH$, LINK$, Argument$, DESCRIPTION$, WorkingDirectory$, ShowCommand.l, HotKey.l, IconFile$, IconIndexInFile.l)
;
; IShellLInk CONSTANTS for CallCOM
;
#ShellLink_QueryInterface = 0
#ShellLink_AddRef = 4
#ShellLink_Release = 8
#ShellLink_GetPath = 12
#ShellLink_GetIDList = 16
#ShellLink_SetIDList = 20
#ShellLink_GetDescription = 24
#ShellLink_SetDescription = 28
#ShellLink_GetWorkingDirectory = 32
#ShellLink_SetWorkingDirectory = 36
#ShellLink_GetArguments = 40
#ShellLink_SetArguments = 44
#ShellLink_GetHotkey = 48
#ShellLink_SetHotkey = 52
#ShellLink_GetShowCmd = 56
#ShellLink_SetShowCmd = 60
#ShellLink_GetIconLocation = 64
#ShellLink_SetIconLocation = 68
#ShellLink_SetRelativePath = 72
#ShellLink_Resolve = 76
#ShellLink_SetPath = 80
;
; Interface IPersistFile : IPersist
;
#PersistFile_QueryInterface = 0
#PersistFile_AddRef = 4
#PersistFile_Release = 8
#PersistFile_IsDirty = 16
#PersistFile_Load = 20
#PersistFile_Save = 24
#PersistFile_SaveCompleted = 28
#PersistFile_GetCurFile = 32
result = 0
CoInitialize_(0)
If CoCreateInstance_(?CLSID_ShellLink,0,1,?IID_IShellLink,@psl) = 0
Set_ShellLink_preferences:
; The file TO which is linked ( = target for the Link )
;
CallCOM(#ShellLink_SetPath, psl, PATH$)
; Arguments for the Target
;
CallCOM(#ShellLink_SetArguments, psl, Argument$)
; Working Directory
;
CallCOM(#ShellLink_SetWorkingDirectory, psl, WorkingDirectory$)
; Description ( also used as Tooltip for the Link )
;
CallCOM(#ShellLink_SetDescription, psl, DESCRIPTION$)
; Show command:
; SW_SHOWNORMAL = Default
; SW_SHOWMAXIMIZED = aehmm... Maximized
; SW_SHOWMINIMIZED = play Unreal Tournament
CallCOM(#ShellLink_SetShowCmd, psl, ShowCommand)
; Hotkey:
; The virtual key code is in the low-order byte,
; and the modifier flags are in the high-order byte.
; The modifier flags can be a combination of the following values:
;
; HOTKEYF_ALT = ALT key
; HOTKEYF_CONTROL = CTRL key
; HOTKEYF_EXT = Extended key
; HOTKEYF_SHIFT = SHIFT key
;
CallCOM(#ShellLink_SetHotkey, psl, HotKey)
; Set Icon for the Link:
; There can be more than 1 icons in an icon resource file,
; so you have to specify the index.
;
CallCOM(#ShellLink_SetIconLocation, psl, IconFile$, IconIndexInFile)
ShellLink_SAVE:
; Query IShellLink For the IPersistFile interface For saving the
; shortcut in persistent storage.
If CallCOM(#ShellLink_QueryInterface,psl,?IID_IPersistFile, @ppf) = 0
; Ensure that the string is Unicode.
mem.s = Space(1000) ;AllocateMemory(1,1000)
MultiByteToWideChar_(#CP_ACP, 0, LINK$, -1, mem, 1000)
;Save the link by calling IPersistFile::Save.
;hres = ppf->Save(wsz, TRUE);
hres = CallCOM(#PersistFile_SAVE,ppf,mem,#TRUE)
result = 1
CallCOM(#PersistFile_Release,ppf)
;FreeMemory_()
EndIf
CallCOM(#ShellLink_Release,psl)
EndIf
CoUninitialize_()
ProcedureReturn result
DataSection
CLSID_ShellLink:
; 00021401-0000-0000-C000-000000000046
Data.l $00021401
Data.w $0000,$0000
Data.b $C0,$00,$00,$00,$00,$00,$00,$46
IID_IShellLink:
; DEFINE_SHLGUID(IID_IShellLinkA, 0x000214EEL, 0, 0);
; C000-000000000046
Data.l $000214EE
Data.w $0000,$0000
Data.b $C0,$00,$00,$00,$00,$00,$00,$46
IID_IPersistFile:
; 0000010b-0000-0000-C000-000000000046
Data.l $0000010b
Data.w $0000,$0000
Data.b $C0,$00,$00,$00,$00,$00,$00,$46
EndDataSection
EndProcedure
; CreateLink
; - TARGET$ for the Link ("c:\PureBasic\purebasic.exe")
; - LINK$ - name of the Link ("c:\pb.lnk")
; - Argument$ for the target ("%1")
; - Description$ = Description and Tooltip ("Start PureBasic")
; - Working Directory ("c:\PureBasic\")
; - Show command: #SW_SHOWNORMAL or #SW_SHOWMAXIMIZED or #SW_SHOWMINIMIZED
; - HotKey - no need to use this :)
; - IconFile + Index ( "c:\PureBasic\purebasic.exe" , 1 )
If CreateLink("D:\BASIC\PureBasic\purebasic.exe","c:\PB.lnk","","Pure FUN","D:\BASIC\PureBasic\",#SW_SHOWMAXIMIZED,0,"%SystemRoot%\system32\SHELL32.dll",12)
beep_(800,100)
EndIf
WinDir$ = Space(100): GetSystemDirectory_(WinDir$,100)
If CreateLink(WinDir$+"\calc.exe","c:\CALC.lnk","","Calculator","",0,0,"%SystemRoot%\system32\SHELL32.dll",23)
beep_(800,100)
EndIf
Example 2 - Hide Window from Taskbar:
Code: Select all
;
; ITaskBarList CONSTANTS for CallCOM
;
#QueryInterface = 0
#AddRef = 4
#Release = 8
#HrInit = 12
#AddTab = 16
#DeleteTab = 20
#ActivateTab = 24
#SetActiveAlt = 28
;
; Open a Window
;
hWnd = OpenWindow(0,10,10,500,500,#PB_Window_SystemMenu,"Hello World")
;
; Create the OBJECT by using the GUIDs
;
CoInitialize_(0)
If CoCreateInstance_(?CLSID_TaskbarList,0,1,?IID_ITaskbarList,@myObject) = 0
;
; Call 2 Methods in the Object to hide the
; TAB for our window from the Taskbar
;
CallCOM(#HrInit,myObject) ; Init the Object
CallCOM(#DeleteTab,myObject,hWnd) ; Delete TAB for hWnd from Taskbar
;
; Our Window-Message loop: do nothing
;
Repeat
Until WaitWindowEvent() = #PB_EventCloseWindow
EndIf
;
; Release our Object (free memory for it)
;
CallCOM(#RELEASE,myObject)
;
; Thats it !! Have a nice day.... ;)
;
End
; For COM Programming, we need
; the GUID, that identify the CLASS and the INTERFACE
; we request from windows with CoCreateInstance_()
DataSection
CLSID_TaskbarList:
Data.l $56FDF344
Data.w $FD6D,$11D0
Data.b $95,$8A,$00,$60,$97,$C9,$A0,$90
IID_ITaskbarList:
Data.l $56fdf342
Data.w $FD6D,$11D0
Data.b $95,$8A,$00,$60,$97,$C9,$A0,$90
EndDataSection
Direct Examples:
Here some examples how to call/use DirectX directly: DOWNLOAD PureDX
CallCOM() is the same as CallDX() internally.
Whatever you want to call.... ATL,ActiveX,OLE,DirectX,whatever..
(all together = COM, Component Object Model) -
it works all the same way internally.
Please... somebody tell me he understood my class-code... please...


z x
And about the MS Platafform SDK... one question, i suppouse that contains the data about Microsoft controls, but what if i want to call a unknown activex?
A VERY NICE OPTION is the MS Ole Viewer (free!! and small to download!!) to get the same info of the SDK files
The Ole Viewer let you see very usefull info too... you can download it from http://www.microsoft.com/com/resources/oleview.asp its only 206 k
i run Ole Viewer and click the "View TypeLib" button, choose an OCX and wooow many many numbers are there!! Its beautifull i can see even the structures!!!
There are the GUID:
[
uuid(57B18084-FCCF-4D2C-968B-43A345DC13B0),
version(1.0),
helpstring("NCTAudioFile 1.0 Type Library"),
custom(DE77BA64-517C-11D1-A2DA-0000F8773CE9, 84082968),
custom(DE77BA63-517C-11D1-A2DA-0000F8773CE9, 1007803369)
]
How make the Datasection from this Danilo?
:lol::lol:
I think i can see the constants:
[id(0x00000002), helpstring("method CloseFile")]
Maybe using this tool (Ole Viewer) you can explain us Danilo how to make the datasection
or even make a small shreware tool that help us 
Yes and the Datasection... for me THATS (constants and Datasection) is the hardest thing here.Danilo wrote:The hardest thing to explain is how you get/make the constants
for interfaces used by windows.
For this, you must have the MS Platform SDK and search the
C/C++ headers ( in psdk\include\ ) for the interface definition.
And about the MS Platafform SDK... one question, i suppouse that contains the data about Microsoft controls, but what if i want to call a unknown activex?
A VERY NICE OPTION is the MS Ole Viewer (free!! and small to download!!) to get the same info of the SDK files
The Ole Viewer let you see very usefull info too... you can download it from http://www.microsoft.com/com/resources/oleview.asp its only 206 k
i run Ole Viewer and click the "View TypeLib" button, choose an OCX and wooow many many numbers are there!! Its beautifull i can see even the structures!!!
There are the GUID:
[
uuid(57B18084-FCCF-4D2C-968B-43A345DC13B0),
version(1.0),
helpstring("NCTAudioFile 1.0 Type Library"),
custom(DE77BA64-517C-11D1-A2DA-0000F8773CE9, 84082968),
custom(DE77BA63-517C-11D1-A2DA-0000F8773CE9, 1007803369)
]
How make the Datasection from this Danilo?

I think i can see the constants:
[id(0x00000002), helpstring("method CloseFile")]
Maybe using this tool (Ole Viewer) you can explain us Danilo how to make the datasection


ARGENTINA WORLD CHAMPION
I do, but have some questions... If i follow your example... i understand everything (comparing to a vbs code) but at this point i dont kn ow where or how you get that this need to be done:Danilo wrote:Please... somebody tell me he understood my class-code... please...![]()
If i compare to a vbs or vb code that does the same, all the first steps are almost the same, but here i find it different.
ShellLink_SAVE:
; Query IShellLink For the IPersistFile interface For saving the
; shortcut in persistent storage.
If CallCOM(#ShellLink_QueryInterface,psl,?IID_IPersistFile, @ppf) = 0
; Ensure that the string is Unicode.
mem.s = Space(1000) ;AllocateMemory(1,1000)
MultiByteToWideChar_(#CP_ACP, 0, LINK$, -1, mem, 1000)
;Save the link by calling IPersistFile::Save.
;hres = ppf->Save(wsz, TRUE);
hres = CallCOM(#PersistFile_SAVE,ppf,mem,#TRUE)
result = 1
CallCOM(#PersistFile_Release,ppf)
;FreeMemory_()
EndIf
CallCOM(#ShellLink_Release,psl)
EndIf
CoUninitialize_()
ProcedureReturn result
Lets see:
Code: Select all
Set oFSO = CreateObject("Scripting.FileSystemObject")
     Set oWshShell = WScript.CreateObject("WScript.Shell")
    Â
     Set oWshLink = oWshShell.CreateShortcut(sDesktop & "" & sLinkName & ".lnk")
    Â
     sCurDir = oFSO.GetAbsolutePathName(".")
     oWshLink.TargetPath = sCurDir
     oWshLink.WorkingDirectory = sCurDir
     oWshLink.Save
--------------------------------------------------------------------------------------
Of course i dont know either how to get this:
DataSection
CLSID_ShellLink:
; 00021401-0000-0000-C000-000000000046
Data.l $00021401
Data.w $0000,$0000
Data.b $C0,$00,$00,$00,$00,$00,$00,$46
IID_IShellLink:
; DEFINE_SHLGUID(IID_IShellLinkA, 0x000214EEL, 0, 0);
; C000-000000000046
Data.l $000214EE
Data.w $0000,$0000
Data.b $C0,$00,$00,$00,$00,$00,$00,$46
IID_IPersistFile:
; 0000010b-0000-0000-C000-000000000046
Data.l $0000010b
Data.w $0000,$0000
Data.b $C0,$00,$00,$00,$00,$00,$00,$46
EndDataSection
ARGENTINA WORLD CHAMPION
Danilo, there's something i don't understand,
if as you say the object is a pointer to a pointer to a list of function pointers(methods), why when i apply that logic to get the method address, using peekl() and using callfunctionfast() to call the method does not work?
in other words, it should be possible to use callfunctionfast() to call a method?
if as you say the object is a pointer to a pointer to a list of function pointers(methods), why when i apply that logic to get the method address, using peekl() and using callfunctionfast() to call the method does not work?
in other words, it should be possible to use callfunctionfast() to call a method?
I think its not possible, since its not redistributableJustin wrote:Is the MS SDK redistributable? , could someone share the includes in C/C++ headers ( in psdk\include\ ) ? , downloading all the sdk just for that is a bit heavy. it would be very appreciated. the com lib is almost unuseful without that info.

ARGENTINA WORLD CHAMPION