• Welcome to Theos PowerBasic Museum 2017.

News:

Attachments are only available to registered users.
Please register using your full, real name.

Main Menu

Passing string arrays to a class method

Started by Gil Ben-Zvi, November 11, 2009, 08:45:00 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Gil Ben-Zvi

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.

José Roca

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.

Gil Ben-Zvi

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.

Jeff Blakeney

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.

Gil Ben-Zvi

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.

José Roca

 
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


José Roca

 
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.

Edwin Knoppert

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.

Gil Ben-Zvi

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.