PlanetSquires Forums

Support Forums => José Roca Software => Topic started by: José Roca on August 25, 2016, 09:56:54 PM

Title: CWindow RC18
Post by: José Roca on August 25, 2016, 09:56:54 PM
CWindow Release Candidate 18

Incorporates all the previously discussed changes.

The most notable recent feature is the implementation of an OLE Container.
Title: Re: CWindow RC18
Post by: José Roca on August 25, 2016, 10:01:31 PM
The attached example demonstrates how to host the WebBrowser Control, connect to the events fired by it and use the IDocHostUIHandler interface to customize the control, in this case to make it DPI aware.
Title: Re: CWindow RC18
Post by: José Roca on August 26, 2016, 12:42:18 AM
GDI+ Examples

These are the examples that I have used to test the CGdiPlus classes.

Around 300 small examples demostrating the use of the methods.
Title: Re: CWindow RC18
Post by: James Fuller on August 26, 2016, 07:54:25 AM
Jose,
  I was just taking a peek at your AfxOleCon.inc.
Is this line correct with the double braces at the end???
CONST OC_IID = "{12520D52-F372-47FF-A74D-5FFA862BF4BA}}"   ' // Container's IID

James
Title: Re: CWindow RC18
Post by: José Roca on August 26, 2016, 12:51:49 PM
You can remove it. It is not used at all.
Title: Re: CWindow RC18
Post by: José Roca on August 27, 2016, 08:59:16 PM
I'm currently working in the another datatype missing in FB, VARIANTs. It is going very well.

When finished, I will be able to add support to several Windows COM technologies, such WMI and ADO.

Everything using FB code, without C++, Visual Basic or wathever.
Title: Re: CWindow RC18
Post by: José Roca on August 27, 2016, 09:03:59 PM
Because the FB headers don't provide support for PropSys.dll, an essential library to work seriously with variants, I'm loading it in the CVAR class and calling the functions dynamically, e.g.


' ========================================================================================
PRIVATE FUNCTION CVar.VariantToStringArray (BYVAL pvar AS VARIANT PTR, BYVAL prgsz AS PWSTR PTR, BYVAL crgsz AS ULONG, BYVAL pcElem AS ULONG PTR) AS HRESULT
   FUNCTION = E_POINTER
   IF psLib = NULL THEN EXIT FUNCTION
   DIM pVariantToStringArray AS FUNCTION (BYVAL pvar AS VARIANT PTR, BYVAL prgsz AS PWSTR PTR, BYVAL crgsz AS ULONG, BYVAL pcElem AS ULONG PTR) AS HRESULT
   pVariantToStringArray = DyLibSymbol(psLib, "VariantToStringArray")
   IF pVariantToStringArray THEN FUNCTION = pVariantToStringArray(pvar, prgsz, crgsz, pcElem)
END FUNCTION
' ========================================================================================

Title: Re: CWindow RC18
Post by: José Roca on August 28, 2016, 09:23:11 PM
CVar - Variant class

A wrapper class to deal with variants.

The constructors and LET operators only admit a string, a variant or another CVAR because if, for example, you assign a value of 1, there is no way to know if the variant type of the target variant has to be byte, long, single, etc. Therefore, to assign or cast a numeric value you have to use the various vtxxx properties, e.g. vtLong, vtSingle, etc.


DIM cv AS CVAR
cv.vtLong = 12345
print cv.vtLong


With strings, you can use a constructor


DIM cv AS CVAR = "This is a test string"
print cv.Str


or the Str property


DIM cv AS CVAR
cv.Str = "This is a test string"
print cv.Str


When calling a function with an OUT variant parameter you will use the @operator


Foo @cv


When wanting to pass it by value, you will use


Foo cv


where Foo is the name of the procedure.
Title: Re: CWindow RC18
Post by: José Roca on August 28, 2016, 10:39:37 PM
A default constructor for numbers could be added to allow to pass numbers by value to functions that have parameters declared as CVar, just as we can already do with strings, without having to declare first a variable as CVAR ans pass this variable. But which type to choose for the variant, double?
Title: Re: CWindow RC18
Post by: José Roca on August 28, 2016, 11:03:58 PM
I have added two new constructors for numbers, one for LONGs and another for DOUBLEs, that are the ones most used in COM. For other types, dim a CVAR variable, assign the correct type and pass the variable.
Title: Re: CWindow RC18
Post by: José Roca on August 29, 2016, 02:49:14 AM
There is a way but implies the use of casting, eg. CLNG(12),
Title: Re: CWindow RC18
Post by: José Roca on August 29, 2016, 03:43:32 AM
Be warned that this class is still evolving. I'm going to add new methods.

If the variant is of the type VT_ARRAY, I will add methods to return the number of dimensions of the underlying safe array, the lower and upper bounds, and if the underlying safe array is an array of variants, a method to get individual elements as a CVAR.

I will also add new constructors and operators for each data type, but if you pass a number instead of a variable, you will have to cast it with CLNG, CBYTE, etc.

This is going to be another great new data type. I'm already using it to implement an associative array of variants. Such an array can be added to CWindow to store all kind of indexed data available at any time from any part of the application.

If I ever implement a safearray class (a one-dimensional is not too difficult) we will have all we need to work with COM.
Title: Re: CWindow RC18 - PropSys.dll : lib interface
Post by: Marc Pons on August 29, 2016, 05:33:48 AM
Jose

QuoteBecause the FB headers don't provide support for PropSys.dll

if you are still interrested i've managed to make the libpropsys.dll.a (32bits)
as i understood, James Fuller has already done a working 64bits version,
and with your propvautil.bi file you normally have everything to use propsys.dll,
without calling dynamically each function...

even in win xp ( wich does not have the propsys.dll), i've put a vista version in my system32

and tested like that (following your proposal on other post)

#include "windows.bi"
#include once "win/ole2.bi"


#INCLIB "propsys"

extern "Windows"

DECLARE FUNCTION VariantGetElementCount (BYVAL varIn AS VARIANT PTR) AS ULONG
DECLARE FUNCTION VariantToInt16(BYVAL varIn AS VARIANT PTR, BYVAL piRet AS SHORT PTR) AS HRESULT

end extern

PRIVATE FUNCTION VariantFromInt16(BYVAL iVal AS SHORT, BYVal pvar AS VARIANT PTR) AS HRESULT
pvar->vt = VT_I2
   pvar->iVal = iVal
   return S_OK
END FUNCTION




'CoInitialize NULL

DIM v AS VARIANT
VariantFromInt16(-32000,@v)
DIM n AS ULONG = VariantGetElementCount(@v)
DIM m AS short
VariantToInt16(@v, @m)
'CoUninitialize
print n
print m
sleep


i've also done tests with your propvautil.bi , its seems ok

here the attached file with libpropsys.dll.a and the def file used to make it
Title: Re: CWindow RC18
Post by: José Roca on August 29, 2016, 06:09:17 AM
Thanks very much, but I no longer need it since I already have implemented the functions in CVar.inc. It has the advantage of not having to force the users of copying the libraries and includes to the FB lib and inc folders. Another advantage is not to have to deal with libraries, that I find annoying: one for 32 bit, another for 64 bit, one function exists in one library but not in the other...

IMO the best system is the one used by other BASICs, but with delay loading, that is what I have done. If implemented in the compiler, only declares will we needed, with a clause like "DELAY".

I have added constructors and operators for all the types, and several additional methods. Testing will tell us if more methods will be needed.

The attached file contains the current CVar.inc.

Title: Re: CWindow RC18
Post by: José Roca on August 29, 2016, 06:16:13 AM
And for testing it, I have written another class, CDicObj, that implements an associative array with variants.

Usage example:


#include "Afx/CDicObj.inc"
using Afx

' // Create an instance of the CDicObj class
DIM pDic AS CDicObj

DIM cv AS CVAR

pDic.Add "a", "Athens"
pDic.Add "b", "Madrid"
pDic.Add "c", "Roma"

print pDic.Count
print pDic.Exists("a")
print pDic.Item("a").Str

print "-------------"

DIM cvItems AS CVAR = pDic.Items
FOR i AS LONG = cvItems.GetLBound TO cvItems.GetUBound
   print cvItems.GetVariantElem(i).Str
NEXT

PRINT
PRINT "Press any key..."
SLEEP


As it uses variants, both the keys and items can be any type, and also can be mixed.

The code of CDicObj also demonstrates how to use CVar effectively.
Title: Re: CWindow RC18
Post by: Marc Pons on August 29, 2016, 07:02:49 AM
Jose , sincerly your code flow is like the Amazonia River...

impressive, and as always excellent.
Title: Re: CWindow RC18
Post by: Marc Pons on August 29, 2016, 07:14:34 AM
Jose in your CVar.inc :
QuoteNote: Requires Windows XP SP2 or superior.

I am under XP SP3 and that propsys.dll is not part of the system ( it is normally beginning with vista  , I think)
if needed, has to be placed a downloaded version on system32 folder for 32bits  !

is it what i've done, and seems to work ...
Title: Re: CWindow RC18
Post by: José Roca on August 29, 2016, 08:17:28 AM
I have modified some comments and added the AnsiStr property to convert to ansi. The CAST () AS STRING operator returns an ansi string that contains unicode. This is a hack to workaround the problem of not being able of returning a CBSTR in an operator.

Therefore, we can use


print pDic.Item("a")


or


print pDic.Item("a").Str


that will print an unicode string,

or


print pDic.Item("a").AnsiStr


that will print an ansi string.

We can also use UTF8:


pDic.Add "a", AfxUcode("Αθήνα", CP_UTF8)

Title: Re: CWindow RC18
Post by: José Roca on August 29, 2016, 08:20:19 AM
Quote from: Marc Pons on August 29, 2016, 07:14:34 AM
Jose in your CVar.inc :
QuoteNote: Requires Windows XP SP2 or superior.

I am under XP SP3 and that propsys.dll is not part of the system ( it is normally beginning with vista  , I think)
if needed, has to be placed a downloaded version on system32 folder for 32bits  !

is it what i've done, and seems to work ...

That is what Microsoft says...

Minimum supported client
Windows XP with SP2, Windows Vista [desktop apps only]

https://msdn.microsoft.com/en-us/library/windows/desktop/bb776584(v=vs.85).aspx

Title: Re: CWindow RC18
Post by: José Roca on August 29, 2016, 08:44:55 AM
Quote from: Marc Pons on August 29, 2016, 07:02:49 AM
Jose , sincerly your code flow is like the Amazonia River...

impressive, and as always excellent.

I'm becoming old and can't wait years. Every day counts...

Each new class that I write opens new possibilities, but also the need for more classes.

I have almost finished a class for WINHTTP, but I need support for streams, so I will have to write a CStream class some day to finish it...

The new variant class will allow me to write classes for ADO, and the ADO classes will allow me to write classes for CDO.
Title: Re: CWindow RC18
Post by: José Roca on August 29, 2016, 10:21:53 AM
shlwapi.dll provides API functions to work with streams, but, of course, they aren't declared in the FB headers. What a surprise! Well, it doesn't matter.
Title: Re: CWindow RC18
Post by: James Fuller on August 29, 2016, 11:35:59 AM
Quote from: Jose Roca on August 29, 2016, 10:21:53 AM
shlwapi.dll provides API functions to work with streams, but, of course, they aren't declared in the FB headers. What a surprise! Well, it doesn't matter.

Jose,
  Just a FYI.
Peter of BaCon fame switched to dynamic loading of shared libraries quite some time ago.
With the number of linux distros you never know exactly which version of a shared library is available.
Also this way you can call the parameters just about any thing you want ala PowerBASIC. :)

Fred also did this with his TCLib.


James
Title: Re: CWindow RC18
Post by: José Roca on August 29, 2016, 12:57:38 PM
And now I'm doing it with FreeBASIC. I had a lot of problems with GdiPlus. Some functions are supported in 32 bit and not in 64 bit, and viceversa. The problem is that GdiPlus has more than 600 functions...
Title: Re: CWindow RC18
Post by: José Roca on August 29, 2016, 01:04:21 PM
Another test for the new CVA data type.

CWinHTTPRequest class

Microsoft Windows HTTP Services (WinHTTP) provides developers with a server-supported, high-level interface to the HTTP/1.1 Internet protocol. WinHTTP is designed to be used primarily in server-based scenarios by server applications that communicate with HTTP servers.

https://msdn.microsoft.com/en-us/library/windows/desktop/aa382925(v=vs.85).aspx
Title: Re: CWindow RC18
Post by: Paul Squires on August 29, 2016, 01:04:43 PM
Thanks Jose for all your incredible hard work. You have driven forward FreeBasic Windows development exponentially.
Title: Re: CWindow RC18
Post by: José Roca on August 29, 2016, 01:07:48 PM
Some examples:


' ========================================================================================
' The following example checks if the current platform is supported.
' ========================================================================================

#include "windows.bi"
#include "Afx/CWinHttpRequest.inc"
using Afx

IF AfxWinHttpCheckPlatform THEN
   PRINT "This platform is supported by WinHTTP."
ELSE
   PRINT "This platform is NOT supported by WinHTTP."
END IF

PRINT
PRINT "Press any key..."
SLEEP



' ========================================================================================
' The following example shows how to open an HTTP connection, send an HTTP request, and
' returns the "Date" header from the response.
' ========================================================================================

#include "windows.bi"
#include "Afx/CWinHttpRequest.inc"
using Afx

' // Create an instance of the CWinHttp class
DIM pWHttp AS CWinHttpRequest

' // Open an HTTP connection to an HTTP resource
pWHttp.Open "GET", "http://microsoft.com"

' // Send an HTTP request to the HTTP server
pWHttp.Send

' // Wait for response with a timeout of 5 seconds
DIM iSucceeded AS LONG = pWHttp.WaitForResponse(5)

' // Get the response headers
DIM cbsResponseHeader AS CBSTR = pWHttp.GetResponseHeader("Date")
PRINT cbsResponseHeader

PRINT
PRINT "Press any key..."
SLEEP



' ========================================================================================
' The following example shows how to open an HTTP connection, send an HTTP request, and
' returns all of the headers from the response.
' ========================================================================================

#include "windows.bi"
#include "Afx/CWinHttpRequest.inc"
using Afx

' // Create an instance of the CWinHttp class
DIM pWHttp AS CWinHttpRequest

' // Open an HTTP connection to an HTTP resource
pWHttp.Open "GET", "http://microsoft.com"

' // Send an HTTP request to the HTTP server
pWHttp.Send

' // Wait for response with a timeout of 5 seconds
DIM iSucceeded AS LONG = pWHttp.WaitForResponse(5)

' // Get the response headers
DIM cbsResponseHeaders AS CBSTR = pWHttp.GetAllResponseHeaders
PRINT cbsResponseHeaders

PRINT
PRINT "Press any key..."
SLEEP

Title: Re: CWindow RC18
Post by: José Roca on August 29, 2016, 01:09:25 PM

' ========================================================================================
' The following example shows how to open an HTTP connection, send an HTTP request, and
' returns the response body.
' ========================================================================================

#include "windows.bi"
#include "Afx/CWinHttpRequest.inc"
using Afx

' // Create an instance of the CWinHttp class
DIM pWHttp AS CWinHttpRequest

' // Open an HTTP connection to an HTTP resource
pWHttp.Open "GET", "http://microsoft.com"

' // Send an HTTP request to the HTTP server
pWHttp.Send

' // Wait for response with a timeout of 5 seconds
DIM iSucceeded AS LONG = pWHttp.WaitForResponse(5)

' // Get the response body
DIM cbsResponseBody AS CBSTR = pWHttp.GetResponseBody
PRINT cbsResponseBody

PRINT
PRINT "Press any key..."
SLEEP



' ========================================================================================
' The following example shows how to open an HTTP connection, send an HTTP request, and
' returns the response body as a stream of bytes.
' ========================================================================================

#include "windows.bi"
#include "Afx/CWinHttpRequest.inc"
using Afx

' // Create an instance of the CWinHttp class
DIM pWHttp AS CWinHttpRequest

' // Open an HTTP connection to an HTTP resource
pWHttp.Open "GET", "http://www.microsoft.com/library/homepage/images/ms-banner.gif"

' // Send an HTTP request to the HTTP server
pWHttp.Send

' // Wait for response with a timeout of 5 seconds
DIM iSucceeded AS LONG = pWHttp.WaitForResponse(5)

' // Get the response body
DIM strResponseBody AS STRING = pWHttp.GetResponseStream

' // Save the buffer into a file
IF LEN(strResponseBody) THEN
   DIM fn AS LONG = FREEFILE
   OPEN "ms-banner.gif" FOR OUTPUT AS #fn
   PUT #fn, 1, strResponseBody
   CLOSE #fn
   PRINT "File saved"
ELSE
   PRINT "Failure"
END IF

PRINT
PRINT "Press any key..."
SLEEP



' ========================================================================================
' The following example shows how to open an HTTP connection, send an HTTP request, and
' returns the response text.
' ========================================================================================

#include "windows.bi"
#include "Afx/CWinHttpRequest.inc"
using Afx

' // Create an instance of the CWinHttp class
DIM pWHttp AS CWinHttpRequest

' // Open an HTTP connection to an HTTP resource
pWHttp.Open "GET", "http://microsoft.com"

' // Send an HTTP request to the HTTP server
pWHttp.Send

' // Wait for response with a timeout of 5 seconds
DIM iSucceeded AS LONG = pWHttp.WaitForResponse(5)

' // Get the response headers
DIM cbsResponseText AS CBSTR = pWHttp.GetResponseText
PRINT cbsResponseText

PRINT
PRINT "Press any key..."
SLEEP

Title: Re: CWindow RC18
Post by: José Roca on August 29, 2016, 01:29:22 PM
Another example:


' ========================================================================================
' The following example checks if the current platform is supported.
' ========================================================================================

#include "windows.bi"
#include "Afx/CWinHttpRequest.inc"
using Afx

' // Create an instance of the CWinHttp class
DIM pWHttp AS CWinHttpRequest

' // Open an HTTP connection to an HTTP resource
pWHttp.Open "GET", "http://microsoft.com"

' // Specify the user agent
pWHttp.SetOption(WinHttpRequestOption_UserAgentString, "A WinHttpRequest Example Program")

' // Send an HTTP request to the HTTP server
pWHttp.Send

IF pWHttp.GetLastResult = S_OK THEN
   ' // Get user agent string.
   DIM cvText AS CVAR = pWHttp.GetOption(WinHttpRequestOption_UserAgentString)
   PRINT cvText
   ' // Get URL
   cvText = pWHttp.GetOption(WinHttpRequestOption_URL)
   PRINT cvText
   ' // Get URL Code Page.
   cvText = pWHttp.GetOption(WinHttpRequestOption_URLCodePage)
   PRINT cvText
   ' // Convert percent symbols to escape sequences.
   cvText = pWHttp.GetOption(WinHttpRequestOption_EscapePercentInURL)
   PRINT IIF&(cvText.vd.boolVal, "true", "false")
END IF

PRINT
PRINT "Press any key..."
SLEEP

Title: Re: CWindow RC18
Post by: José Roca on August 29, 2016, 01:30:48 PM
As a demonstration of how wrappers can made things easy, see the original C++ code of the example above posted:



#include <windows.h>
#include <stdio.h>
#include <objbase.h>

#include "httprequest.h"

#pragma comment(lib, "ole32.lib")
#pragma comment(lib, "oleaut32.lib")

// IID for IWinHttpRequest.
const IID IID_IWinHttpRequest =
{
    0x06f29373,
    0x5c5a,
    0x4b54,
    {0xb0, 0x25, 0x6e, 0xf1, 0xbf, 0x8a, 0xbf, 0x0e}
};

int main()
{
    // Variable for return value
    HRESULT    hr;

    // Initialize COM
    hr = CoInitialize( NULL );

    IWinHttpRequest *  pIWinHttpRequest = NULL;

    BSTR            bstrResponse = NULL;
    VARIANT         varFalse;
    VARIANT         varEmpty;
    VARIANT         varUserAgent;

    CLSID           clsid;

    VariantInit(&varFalse);
    V_VT(&varFalse)   = VT_BOOL;
    V_BOOL(&varFalse) = VARIANT_FALSE;

    VariantInit(&varEmpty);
    V_VT(&varEmpty) = VT_ERROR;

    varUserAgent.vt = VT_BSTR;
    varUserAgent.bstrVal = NULL;

    hr = CLSIDFromProgID(L"WinHttp.WinHttpRequest.5.1", &clsid);

    if (SUCCEEDED(hr))
    {
        hr = CoCreateInstance(clsid,
                              NULL,
                              CLSCTX_INPROC_SERVER,
                              IID_IWinHttpRequest,
                              (void **)&pIWinHttpRequest);
    }
    if (SUCCEEDED(hr))
    {
        // Open WinHttpRequest.
        BSTR bstrMethod  = SysAllocString(L"GET");
        BSTR bstrUrl = SysAllocString(L"http://microsoft.com");
        hr = pIWinHttpRequest->Open(bstrMethod,
                                    bstrUrl,
                                    varFalse);
        SysFreeString(bstrMethod);
        SysFreeString(bstrUrl);
    }
    if (SUCCEEDED(hr))
    {
        // Specify the user agent.
        varUserAgent.vt = VT_BSTR;
        varUserAgent.bstrVal =
                   SysAllocString(
                           L"A WinHttpRequest Example Program");

        //varUserAgent is L"A WinHttpRequest Example Program");
        hr = pIWinHttpRequest->put_Option(
                                 WinHttpRequestOption_UserAgentString,
                                 varUserAgent);
    }
    if (SUCCEEDED(hr))
    {    // Send Request.
        hr = pIWinHttpRequest->Send(varEmpty);
    }
    if (SUCCEEDED(hr))
    {
        // Get user agent string.
        hr = pIWinHttpRequest->get_Option(
                                 WinHttpRequestOption_UserAgentString,
                                 &varUserAgent);
        // Print response to console.
        wprintf(L"%s\n\n", varUserAgent.bstrVal);

        // Get URL.
        hr = pIWinHttpRequest->get_Option(WinHttpRequestOption_URL,
                                          &varUserAgent);
        // Print response to console.
        wprintf(L"%s\n\n", varUserAgent.bstrVal);

        // Get URL Code Page.
        hr = pIWinHttpRequest->get_Option(
                                     WinHttpRequestOption_URLCodePage,
                                     &varUserAgent);
        // Print response to console.
        wprintf(L"%u\n\n", varUserAgent.lVal);

        // Convert percent symbols to escape sequences.
        hr = pIWinHttpRequest->get_Option(
                              WinHttpRequestOption_EscapePercentInURL,
                              &varUserAgent);
        // Print response to console.
        wprintf(L"%s\n", varUserAgent.boolVal?L"True":L"False");
    }

    // Release memory.
    if (pIWinHttpRequest)
        pIWinHttpRequest->Release();
    if (bstrResponse)
        SysFreeString(bstrResponse);
    if (varUserAgent.bstrVal)
        SysFreeString(varUserAgent.bstrVal);

    CoUninitialize();
    return 0;
}


All this


        // Open WinHttpRequest.
        BSTR bstrMethod  = SysAllocString(L"GET");
        BSTR bstrUrl = SysAllocString(L"http://microsoft.com");
        hr = pIWinHttpRequest->Open(bstrMethod,
                                    bstrUrl,
                                    varFalse);
        SysFreeString(bstrMethod);
        SysFreeString(bstrUrl);


becomes reduced to


pWHttp.Open "GET", "http://microsoft.com"

Title: Re: CWindow RC18
Post by: José Roca on August 29, 2016, 01:42:36 PM
Quote from: TechSupport on August 29, 2016, 01:04:43 PM
Thanks Jose for all your incredible hard work. You have driven forward FreeBasic Windows development exponentially.


In a few months I have posted more code than the entire FB community in ten years :)

At the beginning I was a bit slow because I still had not mastered the language and had not the new data types. Now everything is becoming very simple.

It takes me more time to do the testing and write the documentation than to write the code.

Now I need a safe array class to complete the toolbox.
Title: Re: CWindow RC18
Post by: José Roca on August 30, 2016, 12:25:02 AM
There was a mistake in the CWinHTTPRequest class and header. New file uploaded.
Title: Re: CWindow RC18
Post by: José Roca on August 30, 2016, 01:17:56 AM
An example for the dictionary object.


#include "Afx/CDicObj.inc"
using Afx

' // Creates an instance of the CDicObj class
DIM pDic AS CDicObj

' // Adds some key, value pairs
pDic.Add "a", "Athens"
pDic.Add "b", "Belgrade"
pDic.Add "c", "Cairo"

print "Count: "; pDic.Count
print pDic.Exists("a")
print

' // Retrieve an item and display it
print pDic.Item("b")
print

' // Change key "b" to "m" and "Belgrade" to "México"
pDic.Key("b") = "m"
pDic.Item("m") = "México"
print pDic.Item("m")
print

' // Get all the items and display them
DIM cvItems AS CVAR = pDic.Items
FOR i AS LONG = cvItems.GetLBound TO cvItems.GetUBound
   print cvItems.GetVariantElem(i)
NEXT

print

' // Get all the keys and display them
DIM cvKeys AS CVAR = pDic.Keys
FOR i AS LONG = cvKeys.GetLBound TO cvKeys.GetUBound
   print cvKeys.GetVariantElem(i)
NEXT

print

' // Remove key "m"
pDic.Remove "m"
IF pDic.Exists("m") THEN PRINT "Key m exists" ELSE PRINT "Key m doesn't exists"

' // Remove all keys
pDic.RemoveAll
print "All the keys must have been deleted"
print "Count: "; pDic.Count

PRINT
PRINT "Press any key..."
SLEEP

Title: Re: CWindow RC18
Post by: Marc Pons on August 30, 2016, 08:46:02 AM
an exemple of using the implicit cast capabilies of CVar class : in input or in output

#include once "Afx/CVar.inc"
using Afx


' ========================================================================================
' you can use implicit Casting in input/output for numeric values or string
' the casted output value  is depending on the type of the variable you assign the value
'
' if case of numeric type be carefull to use a variable type accepting the range of the supposed output
' if the value exceed the range of the var , the overflow will put 0 in var or negative value


'change here   with or without double quotes to see the differences
#define TESTVALUE -10001 'or test with  "  -10001 "    or - 10001 or "  +  10001 "  or + 10001 or whatever...


DIM cv AS CVar = TESTVALUE    'implicit casting in input can accept literal string/numeric

DIM l1 AS long = cv 'implicit casting in output
dim s1 as string = cv 'implicit casting in output

if s1 <> "" THEN
print : print "Test value = """ ; TESTVALUE;"""" : print
else
print : print "Test value = " ; TESTVALUE : print
END IF


if l1> 0 THEN
print "  l1 > 0 s1 = [" & s1 & "]   l1 = " & l1
elseif l1 = 0 THEN
print "  l1 = 0 s1 = [" & s1 & "]   l1 = " & l1
else
print "  l1 < 0 s1 = [" & s1 & "]   l1 = " & l1
END IF
PRINT
PRINT "Press any key..."
SLEEP


the beauty of that : the string representation of  numeric value assigned to CVar
can give the right value when assigning that Cvar to numeric var, just carefull on overflow

on the exemple : change the value on the define to see the effect
or change  DIM l1 AS long = cv   by different numeric type

Thanks again Jose for that huge code collection!
Title: Re: CWindow RC18
Post by: Richard Kelly on August 30, 2016, 10:30:55 PM
With all this good stuff, it's time to take a look at FB. Will FF ever catch up and include all the gadgets?
Title: Re: CWindow RC18
Post by: José Roca on August 31, 2016, 09:09:09 AM
We are going to have the one datatype that was missing, safe arrays...

I already have implemented a class, CSafeArray, that works with arrays of any type and dimensions.


' // Two-dimensional array of BSTR
' // 1D: elements = 5, lower bound = 1
' // 1D: elements = 3, lower bound = 1
DIM rgsabounds(0 TO 1) AS SAFEARRAYBOUND = {(5, 1), (3, 1)}
DIM csa AS CSafeArray = CSafeArray(VT_BSTR, 2, @rgsabounds(0))
DIM cbs1 AS CBSTR = "Test string 1"
' // array index: first dimension, first element
DIM rgidx(0 TO 1) AS LONG = {1, 1}
' // Put the value
csa.PutElement(@rgidx(0), *cbs1)
' // Get the value
DIM cbsOut AS CBSTR
csa.GetElement(@rgidx(0), @cbsOut)
print cbsOut
' // array index: second dimension, first element
rgidx(0) = 2 : rgidx(0) = 1
' // Put the value
DIM cbs2 AS CBSTR = "Test string 2"
csa.PutElement(@rgidx(0), *cbs2)
' // Get the value
csa.GetElement(@rgidx(0), @cbsOut)
print cbsOut


Now I'm going to add overloaded functions to ease its use with one-dimensional arrays, like


' // One-dimensional array of VT_VARIANT
DIM csa AS CSafeArray = CSafeArray(VT_VARIANT, 1, 5)
DIM cv1 AS CVAR = "Test variant 1"
csa.PutElement(1, @cv1)
DIM cvOut AS CVAR
csa.GetElement(1, @cvOut)
print cvOut
DIM cv2 AS CVAR = "Test variant 2"
csa.PutElement(1, @cv2)
csa.GetElement(1, @cvOut)
print cvOut


And add overloaded functions to GetElement and PutElement.

In COM programming, about 90% of the safe arrays are one-dimensional. I only have seen a two-dimensional safe array in the GetRows method of ADO.

Safe vectors are not-resizable one-dimensional safe arrays allocated in contiguous memory for efficiency.
Title: Re: CWindow RC18
Post by: José Roca on August 31, 2016, 11:34:40 AM
I'm not satisfied with the name of CVar for the variant class and I'm going to change it to CVariant.
Title: Re: CWindow RC18
Post by: José Roca on August 31, 2016, 05:02:41 PM
I have changed CVAR to CVARIANT and have finished the SAFEARRAY class.

Tomorrow I will post a new release candidate package and an updated help file.

The safe arrays can be multidimensional and there are overloaded functions to ease the use of the one and to dimensional safe arrays.

Usage example of a one-dimensional array of variants:


' ========================================================================================
' CSafeArray test
' ========================================================================================

#include "Afx/CSafeArray.inc"
using Afx

' // One-dimensional array of VT_VARIANT
DIM csa AS CSafeArray = CSafeArray(VT_VARIANT, 1, 2)
DIM cv1 AS CVARIANT = "Test variant 1"
csa.PutElement(1, @cv1)
DIM cvOut AS CVARIANT
csa.GetElement(1, @cvOut)
print cvOut

DIM cv2 AS CVARIANT = "Test variant 2"
csa.PutElement(1, @cv2)
csa.GetElement(1, @cvOut)
print cvOut

' // Redim (preserve) the safe array
csa.Redim(1, 3)
DIM cv3 AS CVARIANT = "Test variant 3"
csa.PutElement(3, @cv3)
csa.GetElement(3, @cvOut)
print cvOut

PRINT
PRINT "Press any key..."
SLEEP


Usage example of a two-dimensional safe array of BSTRs.


' ========================================================================================
' CSafeArray test
' ========================================================================================

#include "Afx/CSafeArray.inc"
using Afx

' // Two-dimensional array of BSTR
' // 1D: elements = 5, lower bound = 1
' // 1D: elements = 3, lower bound = 1
DIM rgsabounds(0 TO 1) AS SAFEARRAYBOUND = {(5, 1), (3, 1)}
DIM csa AS CSafeArray = CSafeArray(VT_BSTR, 2, @rgsabounds(0))
' or we can use:
' DIM csa AS CSafeArray = CSafeArray(VT_BSTR, 5, 1, 3, 1)

' // array index: first element, first dimension
DIM rgidx(0 TO 1) AS LONG = {1, 1}
' // Put the value
DIM cbs1 AS CBSTR = "Test string 1.1"
csa.PutElement(@rgidx(0), *cbs1)

' // array index: second element, first dimension
rgidx(0) = 2 : rgidx(1) = 1
' // Put the value
DIM cbs2 AS CBSTR = "Test string 2.1"
csa.PutElement(@rgidx(0), *cbs2)

' // array index: first element, second dimension
rgidx(0) = 1 : rgidx(1) = 2
' // Put the value
DIM cbs3 AS CBSTR = "Test string 1.2"
csa.PutElement(@rgidx(0), *cbs3)

' // array index: second element, second dimension
rgidx(0) = 2 : rgidx(1) = 2
' // Put the value
DIM cbs4 AS CBSTR = "Test string 2.2"
csa.PutElement(@rgidx(0), *cbs4)

DIM hr AS HRESULT, cbsOut AS CBSTR
hr = csa.GetElement(1, 1, @cbsOut)
print cbsOut
hr = csa.GetElement(2, 1, @cbsOut)
print cbsOut
print

hr = csa.GetElement(1, 2, @cbsOut)
print cbsOut
hr = csa.GetElement(2, 2, @cbsOut)
print cbsOut

PRINT
PRINT "Press any key..."
SLEEP


For the two-dimensional arrays in the example above, we can use


csa.PutElement(1, 1, *cbs1)
csa.PutElement(2, 1, *cbs2)


instead of

DIM rgidx(0 TO 1) AS LONG = {1, 1}
-or-
rgidx(0) = 2 : rgidx(1) = 1