When you declare an interface pointer variable, initially it is 0. That is, it does not refer to an object. Before using it to call COM object functions, need to create new object or get existing object. For this purpose, you can use functions described in this topic. Common syntax is:
ip.function(parameters)
Here ip is interface pointer variable. Each function returns ip itself.
ip._create([class] [dll])
Creates new COM object of class type and populates ip with object's address.
If class is omitted or 0, uses class of ip (finds it in the type library, if possible). As class, you can use CLSID or ProgId of object's class. It can be either GUID* (see uuidof), or GUID string like "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}", or ProgID string like "Application.Class".
QM 2.3.4. If the COM component is in a dll file, you can specify the dll. Then don't need to register the component. However it works not with all components. If dll not found, tries to create as registered. In exe, if dll begins with "$qm$", searches for the dll in exe folder; if not found there, searches in QM folder if QM is installed on that computer.
QM 2.3.5. To create COM components without registration, you can use manifest and __ComActivator class. It works with .NET COM components too.
The COM component must be registered, unless you use dll or __ComActivator. Else QM tries to register the component automatically, but this should be used only while testing a new component. To register automatically, need administrator privileges. For this reason, auto registration will not work on user accounts with limited privileges and on Windows Vista/7/8/10 if QM is running not as administrator. Also, it does not work in exe. Read here about installing/registering and using COM components.
To create object that must exist while dialog is running, declare the variable in dialog procedure, under WM_INITDIALOG, as thread variable (with -), e.g., Typelib.Class- obj._create. Or, you can declare it before ShowDialog. If you declare it as local (without -) in dialog procedure, it will be quickly destroyed, because dialog procedure is called multiple times while the dialog is displayed. Actually, thread variables are destroyed when thread ends (macro ends), not when destroying dialog. If it is important to delete the object immediately when dialog is closed, under WM_DESTROY assign 0, e.g., obj=0.
Not all COM classes support creating objects using this function. Assume there are Class1 and Class2 in the type library. If you cannot create object of Class2, try to create object of Class1 and get object of Class2 using a function of Class1.
This function is not used to create ActiveX controls for dialogs, but it can be used to create ActiveX controls that provide useful functions without being visible.
QM 2.2.1. Some ActiveX controls created using this function will not work anymore. Place them in a dialog. Some others will work better.
QM 2.3.4. Supports QM interfaces IStringMap, ICsv and IXml. Use without arguments.
ip._getactive([class] [flags] [moniker])
Gets currently active object of class type and populates ip with object's address.
class - object's class (see _create). If omitted or 0, uses class of ip.
0 (default) | If there is no active object, generate error. |
1 | If there is no active object, create new. |
16 | Display monikers of all running objects. Example: IUnknown u._getactive(0 16 "."); err |
moniker (QM 2.2.0) - object's name in the system Running Object Table (ROT).
This function may fail on Windows Vista/7/8/10. There are several workarounds.
ip._getfile(file [class])
Gets object from file, and populates ip with object's address.
If class not specified (omitted or 0), uses CoGetObject. It starts associated application and opens the file. If the file is already open, gets object of the open file (like _getactive).
If class specified, uses different method. Creates object of class type (like _create) and loads the file using IPersistFile.Load. Does not try to get an open file object.
ip._getcontrol(hwndcontrol)
Retrieves ActiveX control object that is hosted by hwndcontrol in a dialog. An ActiveX control is created and hosted by a child window of class "ActiveX", so hwndcontrol must be handle of that child window. To get it, use function id. For example, if control id in dialog is 3, then you can use id(3 hDlg). Usually it is not the id you see in QM status bar, because an ActiveX control also creates its own child window that covers the host child window. The id is shown in the dialog definition (it is the first number in the green line with "ActiveX"). This function is inserted when you click the Events button in the Dialog Editor.
ip._setevents([eventfolder] [flags])
Activates or deactivates object's events.
You also can use other ways to create/get COM objects. You can use universal or specialized API functions (example 4). Objects that are not externally creatable, usually are retrieved using properties (functions) of other objects of that component (example 3). Functions acc, htm and web also return interface pointer.
1. Create Excel Application object and make window visible: typelib Excel {00020813-0000-0000-C000-000000000046} 1.2 Excel.Application a._create a.Visible=TRUE; err 2. You can specify class, although usually this is not necessary. Several examples how can be specified class: Excel.Application b c d b._create("Excel.Application") c._create(uuidof(Excel.Application)) d._create("{00024500-0000-0000-C000-000000000046}") 3. Get Excel Workbook object from file; get pointers to other interfaces; make window and document visible: Excel.Workbook x._getfile("$desktop$\Book5.xls") Excel.Application a=x.Application a.Visible=TRUE; err Excel.Windows ws=a.Windows Excel.Window w=ws.Item(1) w.Visible=TRUE 4. Use dll function to get interface pointer: IAccessible a if(AccessibleObjectFromWindow(hwnd 0 uuidof(IAccessible) &a)) ret out a.accName(0)