I have done OOP programming the last years (using C#), and I was very pleased to hear that the new PB9 compiler supports OOP. I got the new compiler a few days ago, and started converting an old PB project to use classes. The project is made of a GUI front end and a utility DLL, BOTH written using PB. It didn't take too long until I faced a big problem - I need to pass a string array from the front end to a method in the Dll. The method is using the string array elements as buffers for holding other data, so the strings must not be converted to unicode and back. The method can also re-dim the passed array.
Any known workarounds for this?
Many thanks - Gil.
You can't redim the array, but you can do something like what so many API functions do, e.g. add a method that returns the number of elements needed before calling the method that needs it and dim you array accordingly:
#COMPILE EXE
#DIM ALL
CLASS CFoo
INTERFACE IFoo
INHERIT IUnknown
' Return the number of elements needed for the array
METHOD NumElements () AS LONG
METHOD = 5 ' <-- change me
END METHOD
METHOD Foo ( _
BYREF rgBstrNames AS STRING, _ ' BSTR FAR* rgBstrNames
BYREF cNames AS DWORD _ ' Number of elements in the array
)
DIM rgBstrNamesX (1 TO cNames) AS STRING AT VARPTR(rgBstrNames)
rgBstrNamesX(1) = "Test string 1"
' ...
' ...
END METHOD
END INTERFACE
END CLASS
FUNCTION PBMAIN () AS LONG
DIM pFoo AS IFoo
DIM n AS LONG
pFoo = CLASS "CFoo"
n = pFoo.NumElements
DIM rgBstrNames (1 TO n) AS STRING
pFoo.Foo rgBstrNames(1), n
MSGBOX rgBstrNames(1)
END FUNCTION
Otherwise, you will need to use safe arrays.
Hi Jose –
Many thanks for your advice – your help is much appreciated.
I examined your sample, but unfortunately it only does half of what I need... In my project the caller (the exe file) and the callee (class in the DLL) need to redim "preserve" the array. This is a common situation - I have done this many times using C#, so I did not anticipate such a hurdle. I think that this problem demonstrates a serious limitation (or a major design flaw) in the current PB OOP implementation.
Do you have a sample of using safe-arrays as you suggested? This will help me a lot!
Thanks again –
Gil.
This seems to be going against OOP technique. An object should be self contained so why are you keeping an array of strings outside the object and then passing it to the object to get the object to resize it? If the object is supposed to deal with this array, shouildn't it be an instance variable of the object and then your program calls methods of the object to get/set one/some/all of the array elements?
I'm no OOP expert, though, and there probably is a reason why you want or need this ability.
Also, I'm thinking that PB only does conversions of strings being passed to COM objects so if you don't write your object as a COM server then it shouldn't do any conversions of your strings but then I'm not sure you can call a PB object that has been compiled into a DLL. You would have to include the source for your PB object with your main program. Again, you might be wanting to create an object that is usable by other languages so you would pretty much need to create a COM server.
Hi Jeff –
The object is a self contained translation machine which operates on an external input data (a very large string array), and converts each element of the array in-place into a compact and very efficient binary-image which represents the original text data.
The array to be translated is not a part of the object. It can be copied of course into a string array inside the object by using methods for setting / getting the array elements, but it will slow down the process (since there are typically more than 500,000 elements in the array) and double the amount of used memory.
There is no problem in using PB classes from inside a dll, but currently you can't define a method with an array as a parameter even if you are not going to use COM, and this is part of the problem I am facing.
Thanks –
Gil.
You can do something like that:
#COMPILE EXE
#DIM ALL
CLASS CFoo
INTERFACE IFoo
INHERIT IUnknown
METHOD Foo (BYREF vArray AS VARIANT)
DIM rgArray(0) AS STRING
rgArray() = vArray
REDIM PRESERVE rgArray(5)
rgArray(3) = "Test string 3"
rgArray(4) = "Test string 4"
rgArray(5) = "Test string 5"
vArray = rgArray()
END METHOD
END INTERFACE
END CLASS
FUNCTION PBMAIN () AS LONG
DIM pFoo AS IFoo
DIM rgArray(2) AS STRING
DIM vArray AS VARIANT
pFoo = CLASS "CFoo"
rgArray(0) = "Test string 0"
rgArray(1) = "Test string 1"
rgArray(2) = "Test string 2"
vArray = rgArray()
pFoo.Foo vArray
rgArray() = vArray
MSGBOX rgArray(5)
END FUNCTION
Quote
I think that this problem demonstrates a serious limitation (or a major design flaw) in the current PB OOP implementation.
Could be if PB had implemented OOP, but it has not. What it happens is that many people when see the word CLASS only thinks about OOP. I'm tired of saying that what PB has implemented are COM classes to build COM servers. You can do some kind of OOP programming with them, but I will repeat it: They are COM classes.
Therefore, it is not a design flaw. You can't pass PB arrays from and to a method directly because COM doesn't know anything about PB arrays and can't marshal them.
If you want to take advantage of PB COM classes, learn COM programming, not OOP.
To elaborate what happens here, internally PB copies the PB array into the variant as safearray.
safearrays are often used in programs like a VB6 and so but often not noticed.
Question: in short, what is the difference between OOP and COM?
I am aware com has limits or slight differences to other programming languages, if you mean that?
To me OOP is not much more than a class, if it's a com class, VB or a C# class, both are objects.
I am so glad PB came up with this, i am still very happy with these COM classes.
Hi Jose –
Many thanks for your help!
You are probably right when you say that PB classes are COM-only, but unfortunately this is not what I understood from what I have read in PowerBASIC forums.
They are promoting the new features in the Programming with Objects forum as "User to user discussions about programming with objects, including COM objects." In the sticky post (and in the on-line documentation) there are a few sections that explain PB objects:
1) In "What is an object, anyway?" COM is not mentioned.
2) In "Where are objects located?" it is only mentioned that "Whenever an object is accessed outside of your program, PowerBASIC uses the COM (Component Object Model) services...".
3) In "Why should I use objects?" it is only mentioned that COM is the only way to access objects that are returned by some API functions.
Best Regards -
Gil.