Author Topic: Documentation  (Read 65848 times)

0 Members and 1 Guest are viewing this topic.

Aurel

  • Guest
Re: Documentation
« Reply #60 on: October 02, 2018, 08:02:57 AM »
Quote
I hope that Charles will understand what I mean, because you have no clue

Jose..
I can easy say for myself that i don't have a clue about the things you present here .
Well i don't create such a type of programs But from a small mind perspective such is mine  :D
i don't care to much about that.
Anyway ...this VARIANTS are what .... POINTER type built in language ..RIGHT?
because i don't see what else might be. ::)
And also i think that some things can work in o2 in a little bit different way probably not all.

  • Guest
Re: Documentation
« Reply #61 on: October 02, 2018, 08:04:52 AM »
I'm talking of a completely different thing and you reply with "Charles is already on the v-table COM bandwagon with the work done for DLLC."

You still don't know that O2 has vtable support from many years ago?

What do you think that this sapi demo that comes with the compiler uses?

Code: [Select]
  uses com\voice

  dim as GUID          VoiceObjGuid, ISpVoiceGuid
  dim as HRESULT       hr
  dim as ISpVoice *    voice
  dim as LPUNKNOWN     pUnkOuter


  guidval VoiceObjGuid, "96749377-3391-11D2-9EE3-00C04F797396"
  guidval ISpVoiceGuid, "6C44DF74-72B9-4992-A1EC-EF996E0422D4"

  @ pUnkouter=0

  CoInitialize null

  hr=CoCreateInstance VoiceObjGuid, pUnkouter, context, ISpVoiceGuid, voice

  if hr then print "SAPI Error " hex(hr) : CoUninitialize()
  bstring2 s="Hello Everyone!"

  voice.Speak s,0,null
  voice.WaitUntilDone 0xFFFFFFFF
  voice.Release : @ voice=0

  CoUninitialize()

What I'm talking about has not any relation with vtables and COM, but about creating objects that are garbage collected.

« Last Edit: October 02, 2018, 10:26:21 AM by José Roca »

  • Guest
Re: Documentation
« Reply #62 on: October 02, 2018, 08:14:10 AM »
Imagine that instead of using

Code: [Select]
pDisp.Put("Pattern") = ".is"

I have to use something like

Code: [Select]
dim v1 AS VARIANT
v1.vt = VT_BSTR
v1.bstrVal = SysAllocString("Pattern")

dim v2 AS VARIANT
v2.vt = VT_BSTR
v2.bstrVal = SysAllocString(".is")

pDisp.Put(v1, v2)

VariantClear @v1
VariantClear @v2

I have seen ansi C programmers working this way, but I'm not as masochistic as they are.

Charles Pegge

  • Guest
Re: Documentation
« Reply #63 on: October 02, 2018, 09:24:53 AM »
Thanks for the additional details, José,

Now I have a clearer picture of what is required. I've been through a few schemes for implementing higher operations and eventually came up with the macro system, solving the performance-problem, and was coherent though a little funky on the syntax.

But this is a sketch for object-based operations:

Operations using accumulators which are transient objects, with optional destructors, and polymorphic constructors, so you can mix your types within the expression.

Code: [Select]
class tt
========
  '
  double x,y
  '
  'operations are identified as methods with the name in "" quotes
  '
  'they use 'this' as the accumulator
  '
  'the accum is auomatically created before the operator is called
  '
  'its destructor is invoked when the expression is complete
  '
  'operations return a pointer to 'this' accumulator
  '
  method destructor()
    ...
  end method
  '
  method constructor()
  x=0 : y=0
  end method
  '
  method constructor(tt*a)
  x=a.x : y=a.y
  end method
  '
  method constructor(double ax,ay)
  x=ax : y=ay
  end method
  '
  method construcor(string ax,ay)
  x=val(ax) : y=val(ay)
  end method
  '
  method "save" (tt*a)
  a.destructor
  copy @tt,@this,sizeof this
  end method
  '
  method "save" (abc*a) 'another type
  a.destructor 'if destructor exists
  copy @tt,@this,sizeof this
  end method
  '
  method "+" (tt*a)
  x+=a.x
  y+=a.y
  end method
  '
end class

internal logistics:
===================
'op     operator
'typ    class of operation
'acc    accumulator
'v      operand expression
'saved  flag
if typ has constructors
  if op=0 'load
    typ acc
    acc.constructor()
    clear saved flag
  elseif op=2 'save
    acc."save"(v) 'using polymorphic saves
    set saved flag
    goto done
  end if
  if typeof(v)<>typeof(acc)
    typ b
    b.constructor(v) 'using polymorphic constructors
    acc.op(b)
    if destructor exists then b.destructor
  else
    acc.op(v)
  end if
  '
  done:
  '
  if not saved then
    if destructor exists then acc.destructor
  else
    if destructor exists then log v to local/global destructors
    if typeof(v)<>typeof(acc)
      if destructor exists then acc.destructor
  end if
elseif typ is general udt
  use macro system
elseif typ is primitive
  use primite expression evaluation
end if




JRS

  • Guest
Re: Documentation
« Reply #64 on: October 02, 2018, 10:47:03 AM »
Quote
You still don't know that O2 has vtable support from many years ago?

Charles made his DLLC COM functionality available to O2 users in a generic form at the same time. Much of O2's magic is users like me an you asking the Wizard to conjure a fix.

Sorry I missed your point. The VARIANT word got me excited and had tunnel vision.
« Last Edit: October 02, 2018, 01:12:55 PM by John »

  • Guest
Re: Documentation
« Reply #65 on: October 02, 2018, 02:36:33 PM »
With Free Basic, the constructor is always called. The default constructor has no parameters. Which constructor is called depends of the type of the parameter(s), if any, that you pass when you create an instance of the class. You can create an instance of the class with DIM or NEW.

If you use NEW, what you get is a pointer to the class:

DIM pObj AS MyClass PTR = NEW (<parameters>)

Being a pointer, you have to use the pointer syntax (->) with Free Basic:

<result> = pObj-><method name> (<parameters)

And free it with DEL, i.e, DEL pObj

With DIM, whitout NEW

DIM pObj AS MyClass   ' default constructor
--or--
DIM pObj AS MyClass = <parameter>   ' if there is only a parameter
--or--
DIM pObj AS MyClass = MyClass(<parameters>)   ' if there are more than one parameter

You use the dotted syntax:

pObj.<method name>(<parameters>)

The object will destroy itself and call the destructor when it goes out of scope.

You can wrap it between SCOPE/END SCOPE if you want:

SCOPE
   DIM pObj AS MyClass
   pObj.<method name>
END SCOPE

and it will be destroyed as soon as the SCOPE block ends.

FUNCTION = needs of a copy constructor. Free Basic uses the overloaded operator LET (=).

OPERATOR LET (parameter)

This allows to return a copy of the class before it is destroyed.

FUNCTION Foo () AS MyClass
   DIM pObj AS MyClass
   ....
   FUNCTION = pObj
   ....
END FUNCTION

or, if you have a constructor that accepts, lets say, an string:

FUNCTION Foo () AS MyClass
   DIM s AS STRING2
   ....
   FUNCTION = s
   ....
END FUNCTION

It creates a temporary instance of the class and calls the LET operator to allow you to make a copy of the local string, that will be destroyed when the method ends.

RETURN also creates a temporary instance of the class, but instead of LET, it calls the appropriate constructor.

FUNCTION Foo () AS MyClass
   DIM s AS STRING2
   ....
   RETURN s
END FUNCTION

What you use depends of what you are going to return. STRING2 is garbage collected, so we don't need to worry to free it. But if we want to return a data type that we have to free, for example a VARIANT, if we use RETURN then VARIANT won't be cleared. Therefore, we can use:

FUNCTION Foo () AS MyClass
   DIM v AS VARIANT
   ....
   FUNCTION = v
   VariantClear @v
END FUNCTION

Hope this helps.

I have used classes (in FB they are called TYPE) extensively, and my WinFBX framework has many of them that you can browse to see how they work.
« Last Edit: October 02, 2018, 04:00:40 PM by José Roca »

  • Guest
Re: Documentation
« Reply #66 on: October 02, 2018, 02:46:15 PM »
With Free Basic, I almost never use NEW.

For example, I have written GDI+ classes that provide the same functionality that the C++ GDI+ classes. This makes very easy to translate C++ GDI+ examples.

Code: [Select]
' ========================================================================================
' The following example creates a SolidBrush object, clones it, and then uses the clone
' to fill a rectangle.
' ========================================================================================
SUB Example_CloneBrush (BYVAL hdc AS HDC)

   ' // Create a graphics object from the window device context
   DIM graphics AS CGpGraphics = hdc
   ' // Get the DPI scaling ratio
   DIM rxRatio AS SINGLE = graphics.GetDpiX / 96
   ' // Set the scale transform
   graphics.ScaleTransform(rxRatio, rxRatio)

   ' // Create a SolidBrush object
   DIM solidBrush AS CGpSolidBrush = GDIP_ARGB(255, 255, 0, 0)

   ' // Create a clone of solidBrush
   DIM cloneBrush AS CGpSolidBrush
   solidBrush.Clone(@cloneBrush)
   ' // You can also use:
   ' DIM cloneBrush AS CGpSolidBrush = @solidBrush

   ' // Use cloneBrush to fill a rectangle
   graphics.FillRectangle(@cloneBrush, 0, 0, 100, 100)

END SUB
' ========================================================================================

I have added my "little touch" to make it DPI aware:

Code: [Select]
   ' // Get the DPI scaling ratio
   DIM rxRatio AS SINGLE = graphics.GetDpiX / 96
   ' // Set the scale transform
   graphics.ScaleTransform(rxRatio, rxRatio)

As you can see, I don't have to worry about freeing objects. They free themselves when they go out of scope.

José Roca

  • Guest
Re: Documentation
« Reply #67 on: October 02, 2018, 02:52:41 PM »
Of course, Free Basic TYPEs aren't the same that O2 classes. I'm only explaining how to use them and what you can do with them.

  • Guest
Re: Documentation
« Reply #68 on: October 02, 2018, 02:58:28 PM »
> Charles made his DLLC COM functionality available to O2 users in a generic form at the same time.

O2 users only may need to use DLCC to work with COM Automation, but if O2 classes worked like the Free Basic ones, I could write a class like my FB's CDispInvoke that is much more flexible and easy to use, and doesn't need an external DLL.

Anyway, most "decent" COM Automation servers (Office applications excluded) have dual interfaces, so you can use them with O2 without DLCC.
« Last Edit: October 03, 2018, 01:53:07 AM by José Roca »

  • Guest
Re: Documentation
« Reply #69 on: October 02, 2018, 03:13:34 PM »
Overloaded operators in Free Basic can be privative of the class, e.g.

Code: [Select]
OPERATOR CVar.+= (BYREF cv AS CVAR)
   IF vd.vt = VT_BSTR AND cv.vd.vt = VT_BSTR THEN
      ' // Both values are strings, so concatenate
      VarCat(@vd, @cv.vd, @vd)
   ELSE
      ' // Add
      DIM vRes AS VARIANT
      IF VarAdd(@vd, @cv.vd, @vRes) = S_OK THEN VariantCopy(@vd, @vRes)
   END IF
END OPERATOR

Notice the use of the name of the class "CVar", followed by a "." and the simbol of the operator (+=).

Or global operators:

Code: [Select]
' ========================================================================================
OPERATOR & (BYREF cv1 AS CVAR, BYREF cv2 AS CVAR) AS CVAR
   DIM cvRes AS CVAR
   VarCat(@cv1.vd, @cv2.vd, cvRes.vptr)
   OPERATOR = cvRes
END OPERATOR
' ========================================================================================
« Last Edit: October 02, 2018, 04:04:14 PM by José Roca »

JRS

  • Guest
Re: Documentation
« Reply #70 on: October 02, 2018, 03:21:58 PM »
DLLC is a Script BASIC extension module written in O2. SB extension modules are DLLs but only callable from SB.

  • Guest
Re: Documentation
« Reply #71 on: October 02, 2018, 03:27:20 PM »
Notice that in all cases, the value returned is a temporary instance of the class, not a pointer to an existing one, that will destroy itself.

If you use:

DIM cv1 AS CVAR = "String"
DIM cv2 aS CVAR = "12345"
DIM cvRes AS CVAR = cv1 & cv2

It will concatenate the two variants and return a temporary instance of CVAR that will self destroy after the assignent is made.

If instead of two CVAR variables, you use another data type allowed by the constructors, e.g.

DIM cvRes AS CVAR = "Test string " & 12345

Two additional temporary instances of the class will be created by the compiler to convert the passed parameters to CVAR and destroyed when the method ends.

« Last Edit: October 02, 2018, 03:41:29 PM by José Roca »

  • Guest
Re: Documentation
« Reply #72 on: October 02, 2018, 03:37:13 PM »
When speed/efficiency is wanted/needed, we can write methods like this one:

Code: [Select]
' ========================================================================================
' Attaches a variant to this class. The source variant is marked as empty.
' ========================================================================================
FUNCTION CVar.Attach (BYVAL pvar AS VARIANT PTR) AS HRESULT
   IF pvar = NULL THEN RETURN E_INVALIDARG
   VariantClear @vd
   ' // Copy the contents and give control to CVar
   DIM pdest AS ANY PTR = memcpy(@vd, pvar, SIZEOF(VARIANT))
   IF pdest = NULL THEN RETURN E_FAIL
   ' // Mark the source variant as VT_EMPTY instead of clearing it with VariantClear
   ' // because we aren't making a duplicate of the contents, but transfering ownership.
   pvar->vt = VT_EMPTY
   RETURN S_OK
END FUNCTION
' ========================================================================================

JRS

  • Guest
Re: Documentation
« Reply #73 on: October 02, 2018, 04:03:07 PM »
Charles,

For us non-COM gurus, Eros posted a great reference.

COM in plain C

José,

Do you know if VB6 OCX.DLL's provide a dual interface by default or do I need to embed the typelib via a utility?
« Last Edit: October 02, 2018, 04:46:31 PM by John »

José Roca

  • Guest
Re: Documentation
« Reply #74 on: October 03, 2018, 02:06:48 AM »
Sorry, John, but I never have used VB6.