• Welcome to PlanetSquires Forums.
 

CWindow Release Candidate 30

Started by José Roca, July 20, 2017, 12:17:28 AM

Previous topic - Next topic

José Roca

Unrar the Afx folder in the inc folder of your compiler(s).

This is a big update:

On-line help: http://www.jose.it-berater.org/CWindow/CWindowFramework.html

Added support for BSTR: CBSTR class in CWSTR.inc.
Added suport for variants: CVAR class in CVAR.inc.
CDispInvoke class in CDispInvoke.inc: Allows to work with COM Automation.
CSafeArray class in CSafeArray.inc: Safe arrays support.
CDicObj class in CDicObj.inc: Dictionary objet (associative arrays).
CWmiDisp class to work with WMI.
ADO classes in various files: folder Afx/CADODB.
CWinHttpRequest: Modified to work with CBSTR.
CTextStream: Modified to work with CBSTR.
CFileSys: Modified to work with CBSTR.
CRegExp: Modified to work with CBSTR.
CShortcut and CUrlShortcut: Modified to wirh with CBSTR

CWStrArray and CWStrDic are no longer needed since CSafeArray and CDicObj can use all data types.
CWmiCli is now obsolete since CWmiDisp can work both with the local computer and remote servers.

21 Jul 2017: Small update.
21 Jul 2017: CVAR update.
22 Jul 2017: CVAR update, GDI+ classes update
23 Jul 2017: Added the GrowSize property to CWSTR
28 Jul 2017: Added support for SAPI
28 Jul 2017: Modified the LET operators of CDispInvoke
28 Jul 2017: Added the bstr and cbstr methods to CWSTR
1 Aug 2017: New function, AfxWstrAlloc, and new methods, CBStr.wchar and  CWStr.wchar
2 Aug 2017: Modified some declares in Afx_Sapi.bi
2 Aug 2017: Modified the TypeLib Browser to generate AFX_ prefixes for the abstract interfaces. Still more work to do because there are not abstract interface declarations in the FB includes.
4 Aug 2917: New class: CSQlite3 (in CSQlite3.inc).

José Roca

#1
What we have:

GUI

CWindow, CLayout, CScrollWindow, CTabPage, hundreds of Windows API procedures.

STRINGS

CWSTR, CBSTR, CWStrArray, CWStrDic, CRegExp and string manipulation procedures.

VARIANTS

CVAR, CSafeArray, CDicObj

FILES

CFileSys, CTextStream, CFindFile and many procedures. Contrarily to the FB intrinsic functions that only work with ansi filenames and paths, these ones work with unicode.

GRAPHICS

CGraphCtx (now supports OpenGL optionally), CMemBmp, CImageCtx, GDI+ classes and procedures.

AUDIO

CCDAudio, CDSAudio.

DATABASES

CADODB, CODBC, CSQLITE3.

COM

COLECON (OLE Container), CWebBrowser, CDispInvoke, CCDOMessage, CShortcut, CUrlShortcut, CWinHttpRequest, CWmiDisp, helper procedures.

CDispInvoke and CWmiDisp will allow me to develop new classes to use COM technologies.




José Roca

Doing testing to improve the new classes if needed. I'm going to make an small change to CDispInvoke to allow to call methods that don't have parameters.

With just a line of code we can get all the properties of a printer and/or call methods to, e.g. set it as the default printer, pause/resume the print queue, cancel all jobs, etc.


' // Connect with WMI in the local computer and get the properties of the specified printer
DIM pDisp AS CDispInvoke = CWmiServices( _
   $"winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2:" & _
   "Win32_Printer.DeviceID='OKI B410'").ServicesObj


See all the methods and properties of the Win32_Printer class:
https://msdn.microsoft.com/en-us/library/aa394363(v=vs.85).aspx

Example:


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

' // Connect with WMI in the local computer and get the properties of the specified printer
DIM pDisp AS CDispInvoke = CWmiServices( _
   $"winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2:" & _
   "Win32_Printer.DeviceID='OKI B410'").ServicesObj

' // Get the values of some properties and display them
PRINT "Port name: "; pDisp.Get("PortName").ToStr
PRINT "Attributes: "; pDisp.Get("Attributes").ToStr
PRINT "Paper sizes supported: "; pDisp.Get("PaperSizesSupported").ToStr

PRINT
PRINT "Press any key..."
SLEEP


José Roca

Another small WMI example:


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

' // Connect with WMI in the local computer and get the properties of the specified file
DIM FileName AS STRING = ExePath & "\" & "x.bas"   ' --> change me
DIM pDisp AS CDispInvoke = CWmiServices( _
   $"winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2:" & _
   "CIM_DataFile.Name='" & FileName & "'").ServicesObj
IF pDisp.DispPtr = NULL THEN END

' // Get the values of some properties and display them
PRINT "File name: "; pDisp.Get("FileName").ToStr
PRINT "File extension: "; pDisp.Get("Extension").ToStr
PRINT "Drive: "; pDisp.Get("Drive").ToStr
PRINT "File size: "; pDisp.Get("FileSize").ToStr
PRINT "File type: "; pDisp.Get("FileType").ToStr
PRINT "Creation date: "; AfxWmiTimeToDateStr(pDisp.Get("CreationDate").ToStr, "dd-MM-yyyy")
PRINT "Last modified: "; AfxWmiTimeToDateStr(pDisp.Get("LastModified").ToStr, "dd-MM-yyyy")
PRINT "Last accessed: "; AfxWmiTimeToDateStr(pDisp.Get("LastAccessed").ToStr, "dd-MM-yyyy")

PRINT
PRINT "Press any key..."
SLEEP


For a list of methods and properties see:
https://msdn.microsoft.com/en-us/library/aa387236(v=vs.85).aspx

Isn't this technology wonderful?

Johan Klassen

thank you Jose, thats an amazing amount of work.  :)

José Roca

I have reuploaded the files in the first post.

Changes:

- There was a mistyped constant in COdbcStmt.inc

- Modified the Invoke method of the CDispInvoke class to allow to call methods that don't have parameters.

José Roca

#6
If you have reuploaded the files, you can now test this little WMI script, that sets the specified printer as the default printer.


' // Connect with WMI in the local computer and get the properties of the specified printer
DIM pDisp AS CDispInvoke = CWmiServices( _
   $"winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2:" & _
   "Win32_Printer.DeviceID='OKI B410'").ServicesObj

' // Set the printer as the default printer
DIM cvRes AS CVAR = pDisp.Invoke("SetDefaultPrinter")


If you compare it with what Pierre had to do many years ago ( https://forum.powerbasic.com/forum/user-to-user-discussions/source-code/24462-set-default-printer?t=23826 ) you will understand how powerful is WMI to manage the hardware.

It is also worth noting the greater syntax flexibility allowed by CDispInvoke over the PowerBASIC OBJECT CALL/GET/SET.

José Roca

I'm going to change the name of he AssignXXX methods to PutXXX, e.g. PutLong instead of AssignLong, etc. It is somewhat easier to write.


José Roca

Code reuploaded. Changed the AssignXXX functions to PutXXX. Added additional Put procedures for BYTE, LONG, etc.

José Roca

#9
This example uses WMI to launch Notepad and returns the process identifier. Not useful, but wanted to test calling a method with an OUT parameter.


#define UNICODE
#INCLUDE ONCE "Afx/CWmiDisp.inc"
USING Afx

' // Connect to WMI using a moniker
DIM pServices AS CWmiServices = ( _
   $"winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2:Win32_Process")
IF pServices.ServicesPtr = NULL THEN END
' // Assign the WMI services object pointer to CDispInvoke
' // CWmiServices.ServicesObj returns an AddRefed pointer, whereas CWmiServices.ServicesPtr not.
DIM pDispServices AS CDispInvoke = CDispInvoke(pServices.ServicesObj)
' // Note: Although the WMI documentation says that this OUT parameter is an UInt32,
' // it only works if I use "LONG".
DIM ProcessId AS LONG
pDispServices.Invoke("Create", 4, CVAR("notepad.exe"), , , CVAR(@ProcessId, "LONG"))
PRINT "Process id: ", ProcessId


James Klutho


José Roca

#11
This script returns all the .bas files from the specified drive and folder. I wasn't able to get it working until I found in the web that I had to use double backlashes in the path (weird!).


#include "Afx/CWmiDisp.inc"
using Afx

' // Connect to WMI using a moniker
' // Note: $ is used to avoid the pedantic warning of the compiler about escape characters
DIM pServices AS CWmiServices = $"winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2"
IF pServices.ServicesPtr = NULL THEN END

' // Execute a query (note that we have to use double backslashes "\\" in the path)
DIM cbsQuery AS CBSTR = "SELECT * FROM CIM_DataFile" & _
    $" WHERE Drive = 'C:' AND Path = '\\Users\\Pepe\\FreeBasic64\\AfxTests\\CWmiDisp\\'" & _
    " AND Extension = 'bas'"
DIM hr AS HRESULT = pServices.ExecQuery(cbsQuery)
IF hr <> S_OK THEN PRINT AfxWmiGetErrorCodeText(hr) : SLEEP : END

' // Get the number of objects retrieved
DIM nCount AS LONG = pServices.ObjectsCount
print "Count: ", nCount
IF nCount = 0 THEN PRINT "No objects found" : SLEEP : END

' // Enumerate the objects using the standard IEnumVARIANT enumerator (NextObject method)
' // and retrieve the properties using the CDispInvoke class.
FOR i AS LONG = 0 TO nCount - 1
   DIM pDispServ AS CDispInvoke = pServices.NextObject
   IF pDispServ.DispPtr THEN
      PRINT "File name "; pDispServ.Get("FileName").ToStr
   END IF
NEXT

PRINT
PRINT "Press any key..."
SLEEP


How it works:

- pServices.ExecQuery generates a collection of objects.

- pServices.NextObject returns the next object in the collection (or the first one if it is the first time that we call it) as a CVAR.

- The returned CVAR is assigned to an instance of the CDispInvoke class ( DIM pDispServ AS CDispInvoke = pServices.NextObject ), that assigns the pointer to its internal Dispatch pointer.

- pDispServ.Get("FileName") retrieves the value of the specified property and returns it as a CVAR.

José Roca

Quote from: James Klutho on July 21, 2017, 11:02:49 AM
Thanks Jose

You're welcome. Trying to get all right and taking notes of the weird things that I find for future reference. In the last two examples I thought for a moment that something in my class was not working properly.

Paul Squires

Quote from: Jose Roca on July 21, 2017, 08:04:25 AM
This example uses WMI to launch Notepad and returns the process identifier. Not useful, but wanted to test calling a method with an OUT parameter.


#define UNICODE
#INCLUDE ONCE "Afx/CWmiDisp.inc"
USING Afx

' // Connect to WMI using a moniker
DIM pServices AS CWmiServices = ( _
   $"winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2:Win32_Process")
IF pServices.ServicesPtr THEN END
' // Assign the WMI services object pointer to CDispInvoke
' // CWmiServices.ServicesObj returns an AddRefed pointer, whereas CWmiServices.ServicesPtr not.
DIM pDispServices AS CDispInvoke = CDispInvoke(pServices.ServicesObj)
' // Note: Although the WMI documentation says that this OUT parameter is an UInt32,
' // it only works if I use "LONG".
DIM ProcessId AS LONG
pDispServices.Invoke("Create", 4, CVAR("notepad.exe"), , , CVAR(@ProcessId, "LONG"))
PRINT "Process id: ", ProcessId



Hi Jose,

Small error in your test code:

IF pServices.ServicesPtr THEN END

Should be:

IF pServices.ServicesPtr = Null THEN END
Paul Squires
PlanetSquires Software
WinFBE Editor and Visual Designer

José Roca

#14
Indeed. Thanks very much. Of course the original test was different; otherwise would have not worked. I had IF pServices.ServicesPtr THEN [more lines of code] END IF.