Difference between revisions of "COM Tutorial"
(Created page with "mIRC supports interaction with COM through dynamic binding. COM in mIRC is an advanced topic and usually requires knowledge in strongly typed language. Knowledge of C++ is a ...") |
m (Broke code formatting there...) |
||
Line 86: | Line 86: | ||
alias titleof { | alias titleof { | ||
if (!$isid) { return } | if (!$isid) { return } | ||
− | + | ||
; Instantiate the class | ; Instantiate the class | ||
.comopen titleof InternetExplorer.Application | .comopen titleof InternetExplorer.Application | ||
− | + | ||
; Call Navigate. Pass it one parameter of type bstr (string) - the URL we were passed. 1 = DISPATCH_METHOD because we are calling a method | ; Call Navigate. Pass it one parameter of type bstr (string) - the URL we were passed. 1 = DISPATCH_METHOD because we are calling a method | ||
noop $com(titleof, Navigate, 1, bstr, $1-) | noop $com(titleof, Navigate, 1, bstr, $1-) | ||
− | + | ||
; [[$com]](<dispatch>).result returns the value the last call returned. Loop until it is 4 ([https://msdn.microsoft.com/en-us/library/bb268229(v=vs.85).aspx READYSTATE_COMPLETE]) | ; [[$com]](<dispatch>).result returns the value the last call returned. Loop until it is 4 ([https://msdn.microsoft.com/en-us/library/bb268229(v=vs.85).aspx READYSTATE_COMPLETE]) | ||
while ($com(titleof).result != 4) { | while ($com(titleof).result != 4) { | ||
Line 99: | Line 99: | ||
; Now we'll loop again and check the value to see if it was 4 or not. | ; Now we'll loop again and check the value to see if it was 4 or not. | ||
} | } | ||
− | + | ||
; Get the value of the LocationName property | ; Get the value of the LocationName property | ||
noop $com(titleof, LocationName, 2) | noop $com(titleof, LocationName, 2) | ||
− | + | ||
; Save it so we can cleanup | ; Save it so we can cleanup | ||
var %value = $com(titleof).result | var %value = $com(titleof).result | ||
− | + | ||
; Quit closes InternetExplorer's background tasks | ; Quit closes InternetExplorer's background tasks | ||
noop $com(titleof, Quit, 1) | noop $com(titleof, Quit, 1) | ||
− | + | ||
; Close the COM object to tidy up | ; Close the COM object to tidy up | ||
.comclose titleof | .comclose titleof | ||
− | + | ||
; Return what we saved | ; Return what we saved | ||
return %value | return %value | ||
} | } | ||
− | |||
==Example 2: Using the managed stack== | ==Example 2: Using the managed stack== |
Revision as of 23:58, 19 July 2015
mIRC supports interaction with COM through dynamic binding. COM in mIRC is an advanced topic and usually requires knowledge in strongly typed language. Knowledge of C++ is a big plus.
For this tutorial to make sense, you should at a minimum know
- How to use Identifiers in mIRC
- About identifier properties (e.g. $identifier().prop)
- That the noop command will execute but not print or take an action
- What objects are in object oriented programming
- Basics of strongly typed languages (e.g. int vs short vs string)
If you aren't sure you know each of these things, turn around and save yourself the time.
Contents
What is COM?
COM stands for Component Object Model and the details of this are quite complicated. We will be skipping over too many specifics, but MSDN has more.
To speak generally, COM is a Windows technology for creating and accessing Objects no matter what language. For example, you could create an object with methods and properties in C++ and use it in mIRC.
Specific Object-Oriented Concepts
mIRC allows us to create an instance of a class using comopen and to call methods, get the value of properties, or set the value of properties using $com and $comcall.
$com and $comcall are basically identical except that $comcall is asynchronous and will call an alias (like a callback function) when the call completes.
Where a language such as Java might an infinite number of types (String, Socket, Integer, InputStream, etc) COM has only a handful - albeit a large handful. In COM, every variable is represented as VARIANT. This is a C structure and it can be used to represent many things. The way this works in C that the "vt" member is set to the type of variable the Variant is to represent, and then the corresponding field is set to the value.
For example, a Variant can represent a byte like this:
VARIANT v; v.vt = VT_BYTE; v.bVal = 4;
Or, it can be changed to a float like this:
v.vt = VT_FLOAT; v.fltVal = 4.0f;
If you are familiar with the common types, you will probably recognize most of them. What you might not recognize is dispatch and unknown and these are very important.
Unknown (IUnknown) is a COM specific construct that is beyond the scope of this tutorial. If you need it, you probably know what it is (and if you do, know that you can call QueryService/Release/AddRef through $com and $comcall - this is only useful though if you eventually get a dispatch back (see below))
Methods
There are 4 things you can do to a COM object via Dispatches
- Call a method on them
- Get the value of a property they have
- Set the value of a property they have
- Set the value of a property they have to a reference
The third parameter of $com allows you to pick from one of these 4 things by passing it in either 1 (call a method), 2 (get a property), 4 (put a property) or 8 (put a property reference). We'll see an example of this soon.
Dispatch
In COM, a dispatch is how we support complex types. It represents an IDispatch object in C, which is important because it has the Invoke method which lets you call members.
Ok let's back up. You know how Java and C# represent all complex types as "Object" - sort of like a super-class? A String is an Object, an InputStream is an Object, etc? In COM, IDispatch serves a similar function. It represents a COM object what you can call methods or get and set properties on. If you have one, you can pass it as an argument to $com and $comopen.
Still lost on what a Dispatch is? It's OK - move on and use the examples to help gain an understanding.
Programmatic and Class IDs
In order to get started in COM, you need a [ProgID]. A ProgID essentially represents the name of a class that supports COM instantiation via dynamic binding (which is what we are doing here).
In C#, you might do this
var nameOfStack = new System.Collections.Stack()
If Stack was exported as a com object with a prog ID (and it is!) you would do this in mIRC
comopen nameOfStack System.Collections.Stack
Details
You can skip this part - it's just some extra info
Internally, program IDs are mapped to GUIDs in the Registry. For example, check out HKEY_CLASSES_ROOT\System.Collections.Stack\CLSID - this is the Class ID for the Stack class.
If you want to do this same thing in C++, you would use code like the following:
CLSID id; CLSIDFromProgID(L"System.Collections.Stack", &id); IDispatch *disp; CoCreateInstance(id, nullptr, CLSCX_INPROC_SERVER,IID_IDispatch, (LPVOID*)&disp);
Example 1, titleof
Enough theory, let's jump in. Here are some things you need to know
- Internet Explorer exports it's IWebBrowser2 interface as the progid InternetExplorer.Application
- It has a method called Navigate which takes a string and goes there
- Navigate is asynchronous. It will return as soon as the loading has started.
- It has a property called ReadyState. This is an enum which is set to 4 when it is done.
- It has a property called LocationName This is a String set to the title of the page.
We're going to make an identifier that takes a URL and returns the title of the page. For example:
$titleof(google.com) == Google $titleof(facebook.com) == Welcome to Facebook - Log In, Sign Up or Learn More
Disclaimer: Titles may have changed since I wrote this
We're going to do this by instantiating WebBrowser2, navigating to the URL we are passed, waiting until the page is loaded, then returning the location.
alias titleof { if (!$isid) { return } ; Instantiate the class .comopen titleof InternetExplorer.Application ; Call Navigate. Pass it one parameter of type bstr (string) - the URL we were passed. 1 = DISPATCH_METHOD because we are calling a method noop $com(titleof, Navigate, 1, bstr, $1-) ; $com(<dispatch>).result returns the value the last call returned. Loop until it is 4 (READYSTATE_COMPLETE) while ($com(titleof).result != 4) { ; Get (2 = DISPATCH_PROPERTYGET) the value of the ReadyState property noop $com(titleof, ReadyState, 2) ; Now we'll loop again and check the value to see if it was 4 or not. } ; Get the value of the LocationName property noop $com(titleof, LocationName, 2) ; Save it so we can cleanup var %value = $com(titleof).result ; Quit closes InternetExplorer's background tasks noop $com(titleof, Quit, 1) ; Close the COM object to tidy up .comclose titleof ; Return what we saved return %value }
Example 2: Using the managed stack
Now let's use System.Collections.Stack
This page not yet completed...Sorry!