component_20object_20model_20programming
Differences
This shows you the differences between two versions of the page.
Next revision | Previous revision | ||
component_20object_20model_20programming [2018/03/31 13:19] – external edit 127.0.0.1 | component_20object_20model_20programming [2024/01/05 00:22] (current) – external edit 127.0.0.1 | ||
---|---|---|---|
Line 1: | Line 1: | ||
=====Component Object Model programming===== | =====Component Object Model programming===== | ||
- | //by Malcolm Marten, May 2008//\\ \\ The Component Object Model, or **COM** for short (not to be confused with COMmunication ports!), is a Microsoft protocol allowing programs to cooperate in sharing data.\\ \\ The key word in COM is **Object** which is the crux of the issue: **Object Oriented Programming**. Today most applications are programmed using objects. These are reusable bits of code with a well-defined input and output for communicating with the world around them. We use an **object** by getting a pointer to a copy of this code made available for our exclusive use. We can then use the **methods** and **properties** of the object in our program.\\ \\ OK, so let’s explain this object model in some physical terms so that we get a good understanding of what’s what. An object is a " | + | //by Malcolm Marten, May 2008//\\ \\ The Component Object Model, or **COM** for short (not to be confused with COMmunication ports!), is a Microsoft protocol allowing programs to cooperate in sharing data.\\ \\ The key word in COM is **Object** which is the crux of the issue: **Object Oriented Programming**. Today most applications are programmed using objects. These are reusable bits of code with a well-defined input and output for communicating with the world around them. We use an **object** by getting a pointer to a copy of this code made available for our exclusive use. We can then use the **methods** and **properties** of the object in our program.\\ \\ OK, so let’s explain this object model in some physical terms so that we get a good understanding of what’s what. An object is a " |
+ | |||
+ | <code bb4w> | ||
INSTALL @lib$+" | INSTALL @lib$+" | ||
PROC_cominit | PROC_cominit | ||
Xlapp% = FN_createobject(" | Xlapp% = FN_createobject(" | ||
- | Here **Xlapp%** will be the pointer to the object you are going to use exclusively. You have created an " | + | </ |
+ | |||
+ | Here **Xlapp%** will be the pointer to the object you are going to use exclusively. You have created an " | ||
+ | |||
+ | <code bb4w> | ||
PROC_putvalue(Xlapp%, | PROC_putvalue(Xlapp%, | ||
- | Now when you get that Excel program on the screen you are probably still disappointed because it is empty, just a shell. We need to add some pages before it is of any use. A look at the Excel object model shows that the Application object has a collection of Workbooks that contain a collection of Worksheets, that contain a collection of Rows and Columns and lots of other things. Now you can’t just start adding Rows, you have to start building things up.\\ \\ First we create a Workbook, for which we can use the " | + | </ |
+ | |||
+ | Now when you get that Excel program on the screen you are probably still disappointed because it is empty, just a shell. We need to add some pages before it is of any use. A look at the Excel object model shows that the Application object has a collection of Workbooks that contain a collection of Worksheets, that contain a collection of Rows and Columns and lots of other things. Now you can’t just start adding Rows, you have to start building things up.\\ \\ First we create a Workbook, for which we can use the " | ||
+ | |||
+ | <code bb4w> | ||
PROC_callmethod(Xlapp%, | PROC_callmethod(Xlapp%, | ||
PROC_putvalue(Xlapp%," | PROC_putvalue(Xlapp%," | ||
- | Here the (-4167) parameter to the Add method is defining a ‘type’ of workbook. In this case it gives you a workbook with a single worksheet object already in it. You could also have your workbook populated with charts, forms or macrosheets, | + | </ |
+ | |||
+ | Here the (-4167) parameter to the Add method is defining a ‘type’ of workbook. In this case it gives you a workbook with a single worksheet object already in it. You could also have your workbook populated with charts, forms or macrosheets, | ||
+ | |||
+ | <code bb4w> | ||
Xlbook% = FN_getobject(Xlapp%, | Xlbook% = FN_getobject(Xlapp%, | ||
PROC_putvalue(Xlbook%," | PROC_putvalue(Xlbook%," | ||
- | This does exactly the same thing as before. Which style you choose to use depends on how often you call up an object, whether you want to often switch between objects or like to be explicit.\\ \\ If we have an existing workbook file that we wish to load instead of generating a new blank workbook as we have just done then we can use:\\ \\ | + | </ |
+ | |||
+ | This does exactly the same thing as before. Which style you choose to use depends on how often you call up an object, whether you want to often switch between objects or like to be explicit.\\ \\ If we have an existing workbook file that we wish to load instead of generating a new blank workbook as we have just done then we can use: | ||
+ | |||
+ | <code bb4w> | ||
Xlbook%=FN_getobject(XLapp%," | Xlbook%=FN_getobject(XLapp%," | ||
- | If you know the exact structure of the pre-existing workbook then you can use sheet names, but it is probably safer to use indexed references rather than named references, which will at least return something.\\ \\ COMLIB V3.3 addendum.\\ | + | </ |
+ | |||
+ | If you know the exact structure of the pre-existing workbook then you can use sheet names, but it is probably safer to use indexed references rather than named references, which will at least return something.\\ \\ COMLIB V3.3 addendum.\\ | ||
+ | |||
+ | <code bb4w> | ||
| | ||
- | See [[/ | + | </ |
+ | |||
+ | See [[/ | ||
+ | |||
+ | <code bb4w> | ||
PROC_putvalue(Xlapp%," | PROC_putvalue(Xlapp%," | ||
- | | + | </ |
+ | or | ||
+ | <code bb4w> | ||
PROC_putvalue(Xlbook%," | PROC_putvalue(Xlbook%," | ||
- | We can refer to the Workbook Object **Xlbook%** or the Application Object **Xlapp%** as the root, but still have to specify exactly which sheet in the collection of Worksheets the property should be applied to (you know there is only one sheet but Excel wants it spelled out, all the same, or it won’t play). Since we have already named the first sheet we could even refer to it by its name: WorkSheets("" | + | </ |
+ | |||
+ | We can refer to the Workbook Object **Xlbook%** or the Application Object **Xlapp%** as the root, but still have to specify exactly which sheet in the collection of Worksheets the property should be applied to (you know there is only one sheet but Excel wants it spelled out, all the same, or it won’t play). Since we have already named the first sheet we could even refer to it by its name: WorkSheets("" | ||
+ | |||
+ | <code bb4w> | ||
PROC_callmethod(Xlbook%," | PROC_callmethod(Xlbook%," | ||
PROC_putvalue(Xlapp%," | PROC_putvalue(Xlapp%," | ||
- | A quick talk about Cells in Excel. They don’t appear as objects, as you might expect; they are a property. I am sure there must be a good reason for it, but it certainly is confusing. Cells is a **property** that returns a range **object**. So cells(2,4) is generating a range object, range("" | + | </ |
+ | |||
+ | A quick talk about Cells in Excel. They don’t appear as objects, as you might expect; they are a property. I am sure there must be a good reason for it, but it certainly is confusing. Cells is a **property** that returns a range **object**. So cells(2,4) is generating a range object, range("" | ||
+ | |||
+ | <code bb4w> | ||
PROC_putvalue(Xlapp%, | PROC_putvalue(Xlapp%, | ||
- | Here we are putting a value (which is a property) into every cell in the selection. The data is a literal " | + | </ |
+ | |||
+ | Here we are putting a value (which is a property) into every cell in the selection. The data is a literal " | ||
+ | |||
+ | <code bb4w> | ||
PROC_putvalue(Xlapp%, | PROC_putvalue(Xlapp%, | ||
PROC_putvalue(Xlapp%, | PROC_putvalue(Xlapp%, | ||
Line 34: | Line 74: | ||
PROC_putvalue(Xlapp%, | PROC_putvalue(Xlapp%, | ||
PROC_putvalue(Xlapp%, | PROC_putvalue(Xlapp%, | ||
- | PROC_putvalue(Xlapp%, | + | PROC_putvalue(Xlapp%, |
+ | </ | ||
- | It would seem that the majority of constants used to describe property values (and the index number, which defines which item in a collection that you want to address) are integers and so fit within 4 bytes and require no prefix. If you get an error, consider whether the number is of the right type and try the other possibilities, | + | It would seem that the majority of constants used to describe property values (and the index number, which defines which item in a collection that you want to address) are integers and so fit within 4 bytes and require no prefix. If you get an error, consider whether the number is of the right type and try the other possibilities, |
+ | |||
+ | <code bb4w> | ||
A$ = FN_getvaluestr(Xlapp%," | A$ = FN_getvaluestr(Xlapp%," | ||
- | Clearly this expects a string value to be returned or an empty string. The alternatives are\\ **FN_getvalueint** and **FN_getvaluefloat**. Since BB4W is fairly forgiving we can map all the integers types into a BB4W integer, and the 8 byte floating point format used in Excel is common to BB4W’s FLOAT 64 mode (but can be mapped to a FLOAT40 variable if that is the current mode).\\ \\ In Excel there are a couple of other data types that are not supported in BB4W such as date and currency, which have internationalized variations. The safest way to deal with these is to convert them to text with a code sequence something like this:\\ \\ | + | </ |
+ | |||
+ | Clearly this expects a string value to be returned or an empty string. The alternatives are\\ **FN_getvalueint** and **FN_getvaluefloat**. Since BB4W is fairly forgiving we can map all the integers types into a BB4W integer, and the 8 byte floating point format used in Excel is common to BB4W’s FLOAT 64 mode (but can be mapped to a FLOAT40 variable if that is the current mode).\\ \\ In Excel there are a couple of other data types that are not supported in BB4W such as date and currency, which have internationalized variations. The safest way to deal with these is to convert them to text with a code sequence something like this: | ||
+ | |||
+ | <code bb4w> | ||
PROC_callmethod(Xlbook%," | PROC_callmethod(Xlbook%," | ||
B$=FN_getvaluestr(Xlapp%," | B$=FN_getvaluestr(Xlapp%," | ||
Line 44: | Line 91: | ||
A$=FN_getvaluestr(Xlapp%," | A$=FN_getvaluestr(Xlapp%," | ||
PROC_putvalue(Xlapp%," | PROC_putvalue(Xlapp%," | ||
- | We select a range, get the format that already exists, which we preserve and store in B$. We change the property of the range to text and then read the text value into A$. If it is important, we can reinstate the original formatting using the style stored in B$. This method should always work and give a reasonable answer, that you then have to convert from a string to the appropriate numerical type.\\ \\ There is no reason why the data from one application should not be copied and pasted into yet another. Application objects will, more likely than not, support **Copy**, **Cut** and **Paste** Methods. The data from a copy is held in multiple formats in the clipboard and the accepting application selects which type suits it best, or ignores it!\\ \\ I’ll leave it to the reader to figure out how to open the applications and make the selection. Then use Selection.Copy in one application, | + | </ |
+ | |||
+ | We select a range, get the format that already exists, which we preserve and store in B$. We change the property of the range to text and then read the text value into A$. If it is important, we can reinstate the original formatting using the style stored in B$. This method should always work and give a reasonable answer, that you then have to convert from a string to the appropriate numerical type.\\ \\ There is no reason why the data from one application should not be copied and pasted into yet another. Application objects will, more likely than not, support **Copy**, **Cut** and **Paste** Methods. The data from a copy is held in multiple formats in the clipboard and the accepting application selects which type suits it best, or ignores it!\\ \\ I’ll leave it to the reader to figure out how to open the applications and make the selection. Then use Selection.Copy in one application, | ||
+ | |||
+ | <code bb4w> | ||
DEF PROCcleanup | DEF PROCcleanup | ||
Xlapp% += 0 : IF Xlapp% | Xlapp% += 0 : IF Xlapp% | ||
Line 52: | Line 103: | ||
PROC_comexit | PROC_comexit | ||
ENDPROC | ENDPROC | ||
+ | </ | ||
+ | |||
Releasing the objects frees the memory and then we need to exit COMLIB gracefully by calling **PROC_comexit**. A procedure like **PROCcleanup** should, ideally, be called from an ON ERROR and ON CLOSE event so that the COM processes are released before the program finally shuts no matter what the cause.\\ \\ So how does this all work at a technical level? Read about that [[http:// | Releasing the objects frees the memory and then we need to exit COMLIB gracefully by calling **PROC_comexit**. A procedure like **PROCcleanup** should, ideally, be called from an ON ERROR and ON CLOSE event so that the COM processes are released before the program finally shuts no matter what the cause.\\ \\ So how does this all work at a technical level? Read about that [[http:// | ||
===== **Caution: Direct use of variables in compiled programs** ===== | ===== **Caution: Direct use of variables in compiled programs** ===== | ||
- | \\ If we use a construction such as these code examples below, then when we compile the program with the default " | + | \\ If we use a construction such as these code examples below, then when we compile the program with the default " |
+ | |||
+ | <code bb4w> | ||
PROC_putvalue(XlNewSheet%, | PROC_putvalue(XlNewSheet%, | ||
PROC_putvalue(Xlapp%, | PROC_putvalue(Xlapp%, | ||
PROC_putobject(tts%, | PROC_putobject(tts%, | ||
- | What is the problem? The issue is that the variables in the parameters are not exposed to the " | + | </ |
+ | |||
+ | What is the problem? The issue is that the variables in the parameters are not exposed to the " | ||
+ | |||
+ | <code bb4w> | ||
REM!Keep row%,col% | REM!Keep row%,col% | ||
PROC_putvalue(XlNewSheet%, | PROC_putvalue(XlNewSheet%, | ||
Line 67: | Line 126: | ||
REM!Keep vobj% | REM!Keep vobj% | ||
PROC_putobject(tts%, | PROC_putobject(tts%, | ||
- | \\ | + | </ |
+ | |||
+ | A similar problem can arise if a static integer variable (A% to Z%) is passed in a parameter string. In this case the issue is that the specified variable may be used internally to the COMLIB library (for example as a LOCAL or PRIVATE variable, or as a formal parameter) in which case it will be the value of that internal variable that is used rather than the value intended. Both problems may be eliminated by replacing the variable references in the supplied parameter string with their numeric values. For example: | ||
+ | |||
+ | <code bb4w> | ||
PROC_putvalue(XlNewSheet%, | PROC_putvalue(XlNewSheet%, | ||
PROC_putvalue(Xlapp%, | PROC_putvalue(Xlapp%, | ||
PROC_putvalue(tts%, | PROC_putvalue(tts%, | ||
PROC_putobject(tts%, | PROC_putobject(tts%, | ||
+ | </ | ||
+ | |||
In this last example an added complication arises in that the variable is an Object which is a 32 bit address and forcing it to hexadecimal ensures that the STR$ function will not corrupt it.\\ \\ The choice of solution is yours but one of them __**must be employed**__ or the COMLIB function will return an error because it is being presented with a variable that has not been defined. The defined name having been crunched and most likely shortened.\\ \\ | In this last example an added complication arises in that the variable is an Object which is a 32 bit address and forcing it to hexadecimal ensures that the STR$ function will not corrupt it.\\ \\ The choice of solution is yours but one of them __**must be employed**__ or the COMLIB function will return an error because it is being presented with a variable that has not been defined. The defined name having been crunched and most likely shortened.\\ \\ | ||
===== The Practical Aspects ===== | ===== The Practical Aspects ===== | ||
- | \\ How do you know what methods and properties you need to tweak for the program to do what you want?\\ \\ There are two methods. First, all the Microsoft office applications use VBA (Visual Basic for Applications) as a macro language. They also have means of editing VBA with an Editor; this is accessed by Alt+F11. In the editor there is an Object Browser; it has an Icon of geometric shapes spewing out of a box! In the top drop down box select the application whose information you want to retrieve, such as " | + | \\ How do you know what methods and properties you need to tweak for the program to do what you want?\\ \\ There are two methods. First, all the Microsoft office applications use VBA (Visual Basic for Applications) as a macro language. They also have means of editing VBA with an Editor; this is accessed by Alt+F11. In the editor there is an Object Browser; it has an Icon of geometric shapes spewing out of a box! In the top drop down box select the application whose information you want to retrieve, such as " |
+ | |||
+ | <code vb> | ||
Set wrd = GetObject(, " | Set wrd = GetObject(, " | ||
wrd.Visible = True | wrd.Visible = True | ||
wrd.Documents.Open "C:\My Documents\Temp.doc" | wrd.Documents.Open "C:\My Documents\Temp.doc" | ||
Set wrd = Nothing | Set wrd = Nothing | ||
- | with BB4W / COMLIB:\\ \\ | + | </ |
+ | with BB4W / COMLIB: | ||
+ | <code bb4w> | ||
wrd% = FN_createobject(" | wrd% = FN_createobject(" | ||
PROC_putvalue(wrd%, | PROC_putvalue(wrd%, | ||
PROC_callmethod (wrd%, " | PROC_callmethod (wrd%, " | ||
PROC_releaseobject(wrd%) | PROC_releaseobject(wrd%) | ||
+ | </ | ||
+ | |||
One issue is that you will still need to learn about how to actually record meaningful macros and their limitations. Such as, when you record a macro in Word 2000, you can use the mouse to click commands and options, but the macro recorder doesn' | One issue is that you will still need to learn about how to actually record meaningful macros and their limitations. Such as, when you record a macro in Word 2000, you can use the mouse to click commands and options, but the macro recorder doesn' |
component_20object_20model_20programming.1522502350.txt.gz · Last modified: 2024/01/05 00:18 (external edit)