• Welcome to PlanetSquires Forums.
 

CWindow Release Candidate 27

Started by José Roca, March 19, 2017, 04:56:35 AM

Previous topic - Next topic

José Roca

#30
CWSTR.INC next vesion:

Modified the overloaded LEN operator. New code is faster, specially with long strings:


' ========================================================================================
' Returns the length, in characters, of the CWSTR.
' ========================================================================================
'PRIVATE OPERATOR LEN (BYREF cws AS CWSTR) AS UINT
'   CWSTR_DP("CWSTR OPERATOR LEN - len: " & .WSTR(.LEN(**cws)))
'   OPERATOR = .LEN(**cws)
'END OPERATOR
' ========================================================================================
' ========================================================================================
PRIVATE OPERATOR LEN (BYREF cws AS CWSTR) AS UINT
   CWSTR_DP("CWSTR OPERATOR LEN - len: " & .WSTR(cws.m_BufferLen \ 2))
   OPERATOR = cws.m_BufferLen \ 2
END OPERATOR
' ========================================================================================


ganlinlao

thanks,Look forward to the wonderful new version

José Roca

#32
I'm working in a WMI wrapper class.

Usage example:


#define UNICODE
#INCLUDE ONCE "Afx/CWindow.inc"
#INCLUDE ONCE "Afx/CWmiCli.inc"
USING Afx

DIM pWmi AS CWmiCli = "root\cimv2"
pWmi.ExecQuery("SELECT DeviceID, Description, Name FROM Win32_CDROMDrive")
IF pWmi.MoveNext THEN
   AfxMsg pWmi.GetStr("DeviceID")
   AfxMsg pWmi.GetStr("Description")
   AfxMsg pWmi.GetStr("Name")
END IF


Error codes can be retrieved calling the GetLastResult method, and a localized description of the error can be retrieved calling the GetErrorCodeText.

I'm testing it with my local computer only because I don'thave access to a server.

José Roca

Modified the WmiTimeToFileTime method, that wasn't returnig the correct value.

Usage example:


#define UNICODE
#INCLUDE ONCE "Afx/CWindow.inc"
#INCLUDE ONCE "Afx/CWmiCli.inc"
#INCLUDE ONCE "Afx/AfxTime.inc"
USING Afx

DIM pWmi AS CWmiCli = "root\cimv2"
pWmi.ExecQuery("SELECT * FROM Win32_BIOS")
IF pWmi.MoveNext THEN
   DIM cws AS CWSTR = pWmi.GetStr("ReleaseDate")
   print cws
   DIM FT as FILETIME = pWmi.WmiTimeToFileTime(*cws)
   print AfxFileTimeToDateStr(ft, "dd-MM-yyyy")
   print AfxFileTimeToTimeStr(ft, "hh':'mm':'ss")
END IF


Richard Kelly

Thank you Jose. I'm always downloading the latest version, and, have not yet had any issues with the project I'm working on.

Rick

José Roca

I wanted to have an easy to use WMI wrapper class because WMI is a powerful technology to get management information. Writing wrapper functions with this class is a piece of cake: usually we only need to change the WMI class name and the property name in the query.

A few quick examples:


' ========================================================================================
' Retrieves the baseboard (also known as a motherboard or system board) serial number.
' ========================================================================================
FUNCTION AfxGetBaseBoardSerialNumber () AS CWSTR
   DIM pWmi AS CWmiCli = "root\cimv2"
   pWmi.ExecQuery("SELECT SerialNumber FROM Win32_BaseBoard")
   IF pWmi.MoveNext THEN RETURN pWmi.GetStr("SerialNumber")
END FUNCTION
' ========================================================================================

' ========================================================================================
' Retrieves the Bios serial number.
' ========================================================================================
FUNCTION AfxGetBiosSerialNumber () AS CWSTR
   DIM pWmi AS CWmiCli = "root\cimv2"
   pWmi.ExecQuery("SELECT SerialNumber FROM Win32_BIOS")
   IF pWmi.MoveNext THEN RETURN pWmi.GetStr("SerialNumber")
END FUNCTION
' ========================================================================================

' ========================================================================================
' Retrieves the manufacturer serial number.
' Requires Windows Vista+.
' ========================================================================================
FUNCTION AfxGetManufacturerSerialNumber () AS CWSTR
   DIM pWmi AS CWmiCli = "root\cimv2"
   pWmi.ExecQuery("SELECT SerialNumber FROM Win32_PhysicalMedia")
   IF pWmi.MoveNext THEN RETURN pWmi.GetStr("SerialNumber")
END FUNCTION
' ========================================================================================

' ========================================================================================
' Retrieves the disk drive serial number.
' Returns the same number that AfxGetManufacturerSerialNumber.
' Requires Windows Vista+.
' ========================================================================================
FUNCTION AfxGetDiskDriveSerialNumber () AS CWSTR
   DIM pWmi AS CWmiCli = "root\cimv2"
   pWmi.ExecQuery("SELECT SerialNumber FROM Win32_DiskDrive")
   IF pWmi.MoveNext THEN RETURN pWmi.GetStr("SerialNumber")
END FUNCTION
' ========================================================================================

' ========================================================================================
' Retrieves the address width of the processor. On a 32-bit operating system, the value is
' 32 and on a 64-bit operating system it is 64. This function can be used to determine if
' the processor is 32 or 64 bit.
' ========================================================================================
FUNCTION AfxGetAddressWidth () AS USHORT
   DIM pWmi AS CWmiCli = "root\cimv2"
   pWmi.ExecQuery("SELECT AddressWidth FROM Win32_Processor")
   DIM vRes AS VARIANT
   IF pWmi.MoveNext THEN
      IF pWmi.GetVar("AddressWidth", @vRes) = S_OK THEN
         RETURN vRes.uiVal
      END IF
   END IF
END FUNCTION
' ========================================================================================

' ========================================================================================
' Retrieves the system running on the Windows-based computer. The following list identifiers
' the returned value: "X86-based PC", "MIPS-based PC", "Alpha-based PC", "Power PC",
' "SH-x PC", "StrongARM PC", "64-bit Intel PC", "64-bit Alpha PC", "Unknown", "X86-Nec98 PC".
' ========================================================================================
FUNCTION AfxGetSystemType () AS CWSTR
   DIM pWmi AS CWmiCli = "root\cimv2"
   pWmi.ExecQuery("SELECT SystemType FROM Win32_ComputerSystem")
   IF pWmi.MoveNext THEN RETURN pWmi.GetStr("SystemType")
END FUNCTION
' ========================================================================================

' ========================================================================================
' Retrieves the architecture of the operating system, as opposed to the processor.
' Example: "64 bits".
' Not available in Windows Server 2003, Windows 2000, Windows NT 4.0, Windows XP, and Windows Me/98/95.
' ========================================================================================
FUNCTION AfxGetOSArchitecture () AS CWSTR
   DIM pWmi AS CWmiCli = "root\cimv2"
   pWmi.ExecQuery("SELECT OSArchitecture FROM Win32_OperatingSystem")
   IF pWmi.MoveNext THEN RETURN pWmi.GetStr("OSArchitecture")
END FUNCTION
' ========================================================================================

' ========================================================================================
' Retrieves the type of the computer in use, such as laptop, desktop, or Tablet.
' Not available in Windows Server 2003, Windows XP, Windows 2000, Windows NT 4.0, and Windows Me/98/95.
' Value   Meaning
' ------- --------------------------------------------
' 0 (&H0) Unspecified
' 1 (&H1) Desktop
' 2 (&H2) Mobile
' 3 (&H3) Workstation
' 4 (&H4) Enterprise Server
' 5 (&H5) Small Office and Home Office (SOHO) Server
' 6 (&H6) Appliance PC
' 7 (&H7) Performance Server
' 8 (&H8) Maximum
' ========================================================================================
FUNCTION AfxGetPCSystemType () AS USHORT
   DIM pWmi AS CWmiCli = "root\cimv2"
   pWmi.ExecQuery("SELECT PCSystemType FROM Win32_ComputerSystem")
   DIM vRes AS VARIANT
   IF pWmi.MoveNext THEN
      IF pWmi.GetVar("PCSystemType", @vRes) = S_OK THEN
         RETURN vRes.uiVal
      END IF
   END IF
END FUNCTION
' ========================================================================================


José Roca

Look at this C++ example and you will appreciate what the CWmiCli class is doing for us:


#define _WIN32_DCOM
#include <iostream>
using namespace std;
#include <comdef.h>
#include <Wbemidl.h>

#pragma comment(lib, "wbemuuid.lib")

int main(int argc, char **argv)
{
    HRESULT hres;

    // Step 1: --------------------------------------------------
    // Initialize COM. ------------------------------------------

    hres =  CoInitializeEx(0, COINIT_MULTITHREADED);
    if (FAILED(hres))
    {
        cout << "Failed to initialize COM library. Error code = 0x"
            << hex << hres << endl;
        return 1;                  // Program has failed.
    }

    // Step 2: --------------------------------------------------
    // Set general COM security levels --------------------------

    hres =  CoInitializeSecurity(
        NULL,
        -1,                          // COM authentication
        NULL,                        // Authentication services
        NULL,                        // Reserved
        RPC_C_AUTHN_LEVEL_DEFAULT,   // Default authentication
        RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation 
        NULL,                        // Authentication info
        EOAC_NONE,                   // Additional capabilities
        NULL                         // Reserved
        );

                     
    if (FAILED(hres))
    {
        cout << "Failed to initialize security. Error code = 0x"
            << hex << hres << endl;
        CoUninitialize();
        return 1;                    // Program has failed.
    }
   
    // Step 3: ---------------------------------------------------
    // Obtain the initial locator to WMI -------------------------

    IWbemLocator *pLoc = NULL;

    hres = CoCreateInstance(
        CLSID_WbemLocator,             
        0,
        CLSCTX_INPROC_SERVER,
        IID_IWbemLocator, (LPVOID *) &pLoc);

    if (FAILED(hres))
    {
        cout << "Failed to create IWbemLocator object."
            << " Err code = 0x"
            << hex << hres << endl;
        CoUninitialize();
        return 1;                 // Program has failed.
    }

    // Step 4: -----------------------------------------------------
    // Connect to WMI through the IWbemLocator::ConnectServer method

    IWbemServices *pSvc = NULL;

    // Connect to the root\cimv2 namespace with
    // the current user and obtain pointer pSvc
    // to make IWbemServices calls.
    hres = pLoc->ConnectServer(
         _bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace
         NULL,                    // User name. NULL = current user
         NULL,                    // User password. NULL = current
         0,                       // Locale. NULL indicates current
         NULL,                    // Security flags.
         0,                       // Authority (for example, Kerberos)
         0,                       // Context object
         &pSvc                    // pointer to IWbemServices proxy
         );
   
    if (FAILED(hres))
    {
        cout << "Could not connect. Error code = 0x"
             << hex << hres << endl;
        pLoc->Release();     
        CoUninitialize();
        return 1;                // Program has failed.
    }

    cout << "Connected to ROOT\\CIMV2 WMI namespace" << endl;


    // Step 5: --------------------------------------------------
    // Set security levels on the proxy -------------------------

    hres = CoSetProxyBlanket(
       pSvc,                        // Indicates the proxy to set
       RPC_C_AUTHN_WINNT,           // RPC_C_AUTHN_xxx
       RPC_C_AUTHZ_NONE,            // RPC_C_AUTHZ_xxx
       NULL,                        // Server principal name
       RPC_C_AUTHN_LEVEL_CALL,      // RPC_C_AUTHN_LEVEL_xxx
       RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
       NULL,                        // client identity
       EOAC_NONE                    // proxy capabilities
    );

    if (FAILED(hres))
    {
        cout << "Could not set proxy blanket. Error code = 0x"
            << hex << hres << endl;
        pSvc->Release();
        pLoc->Release();     
        CoUninitialize();
        return 1;               // Program has failed.
    }

    // Step 6: --------------------------------------------------
    // Use the IWbemServices pointer to make requests of WMI ----

    // For example, get the name of the operating system
    IEnumWbemClassObject* pEnumerator = NULL;
    hres = pSvc->ExecQuery(
        bstr_t("WQL"),
        bstr_t("SELECT * FROM Win32_OperatingSystem"),
        WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
        NULL,
        &pEnumerator);
   
    if (FAILED(hres))
    {
        cout << "Query for operating system name failed."
            << " Error code = 0x"
            << hex << hres << endl;
        pSvc->Release();
        pLoc->Release();
        CoUninitialize();
        return 1;               // Program has failed.
    }

    // Step 7: -------------------------------------------------
    // Get the data from the query in step 6 -------------------

    IWbemClassObject *pclsObj = NULL;
    ULONG uReturn = 0;
   
    while (pEnumerator)
    {
        HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1,
            &pclsObj, &uReturn);

        if(0 == uReturn)
        {
            break;
        }

        VARIANT vtProp;

        // Get the value of the Name property
        hr = pclsObj->Get(L"Name", 0, &vtProp, 0, 0);
        wcout << " OS Name : " << vtProp.bstrVal << endl;
        VariantClear(&vtProp);

        pclsObj->Release();
    }

    // Cleanup
    // ========
   
    pSvc->Release();
    pLoc->Release();
    pEnumerator->Release();
    CoUninitialize();

    return 0;   // Program successfully completed.

}


José Roca

#37
Since connecting with remote servers requires much more work: computer name, user name, password, authority, encrypted credentials, different flags to initialize the security and set the proxy blanket..., and I don't have the means of testing, I'm limiting this class for use with the local computer only, at least for now.

José Roca

#38
I have finished a class, CCdoMessage, that easily allows to send email messages using CDO.

Example


' // Create an instance of the CCdoMessage class
DIM pMsg AS CCdoMessage

' // Configuration
pMsg.ConfigValue(cdoSendUsingMethod, CdoSendUsingPort)
pMsg.ConfigValue(cdoSMTPServer, "smtp.xxxxx.xxx")
pMsg.ConfigValue(cdoSMTPServerPort, 25)
pMsg.ConfigValue(cdoSMTPAuthenticate, 1)
pMsg.ConfigValue(cdoSendUserName, "xxxx@xxxx.xxx")
pMsg.ConfigValue(cdoSendPassword, "xxxxxxxx")
pMsg.ConfigValue(cdoSMTPUseSSL, 1)
pMsg.ConfigUpdate

' // Recipient name --> change as needed
pMsg.Recipients("xxxxx@xxxxx")
' // Sender mail address --> change as needed
pMsg.From("xxxxx@xxxxx")
' // Subject --> change as needed
pMsg.Subject("This is a sample subject")
' // Text body --> change as needed
pMsg.TextBody("This is a sample message text")
' // Add the attachment (use absolute paths).
' // Note  By repeating the call you can attach more than one file.
pMsg.AddAttachment ExePath & "\xxxxx.xxx"
' // Send the message
pMsg.Send
IF pMsg.GetLastResult = S_OK THEN PRINT "Message sent" ELSE PRINT "Failure"


To send messages using gmail, simply change the values of the server name and the server port:


pMsg.ConfigValue(cdoSMTPServer, "smtp.gmail.com")
pMsg.ConfigValue(cdoSMTPServerPort, 465)


ganlinlao

Thanks, jose, the content of the framework is getting richer,
I suggest that the "for each in" syntax should be added through the macro

Richard Kelly

I really like the CDO email. That makes things so easily incorporated into an application.

Rick

José Roca

Changed the AfxSafeRelease function to set the passed pointer to null.


' ========================================================================================
PRIVATE FUNCTION AfxSafeRelease (BYREF pv AS ANY PTR) AS ULONG
   IF pv = NULL THEN RETURN 0
   FUNCTION = cast(IUnknown PTR, pv)->lpvtbl->Release(pv)
   pv = NULL
END FUNCTION
' ========================================================================================


José Roca

Modified the AfxGdipImageFromFile function to use CreateFileW because FB OPEN function uses ansi filenames.


' ========================================================================================
' Loads an image from a file, converts it to an icon or bitmap and returns the handle.
' Parameters:
' - wszFileName   = [in] Path of the image to load and convert.
' - dimPercent    = Percent of dimming (1-99)
' - bGrayScale    = TRUE or FALSE. Convert to gray scale.
' - imageType     = IMAGE_ICON or IMAGE_BITMAP.
' - clrBackground = [in] The background color. This parameter is ignored if the image type
'                   is IMAGE_ICON or the bitmap is totally opaque.
' Return Value:
'   If the function succeeds, the return value is the handle of the created icon or bitmap.
'   If the function fails, the return value is NULL.
' Remarks:
' A quirk in the GDI+ GdipLoadImageFromFile function causes that dim gray images (often used
' for disabled icons) are converted to darker shades of gray. Therefore, instead of using it
' I'm getting here the image data opening the file with OPEN in binary mode.
' ========================================================================================
PRIVATE FUNCTION AfxGdipImageFromFile (BYREF wszFileName AS WSTRING, _
   BYVAL dimPercent AS LONG = 0, BYVAL bGrayScale AS LONG = FALSE, _
   BYVAL imageType AS LONG = IMAGE_ICON, BYVAL clrBackground AS ARGB = 0) AS HANDLE

   DIM fd AS WIN32_FIND_DATAW

   ' // Check for the existence of the file
   IF LEN(wszFileName) = 0 THEN EXIT FUNCTION
   DIM hFind AS HANDLE = FindFirstFileW(@wszFileName, @fd)
   IF hFind = INVALID_HANDLE_VALUE THEN EXIT FUNCTION
   FindClose hFind
   ' // Make sure that is not a directory or a temporary file
   IF (fd.dwFileAttributes AND FILE_ATTRIBUTE_DIRECTORY) = FILE_ATTRIBUTE_DIRECTORY OR _
      (fd.dwFileAttributes AND FILE_ATTRIBUTE_TEMPORARY) = FILE_ATTRIBUTE_TEMPORARY THEN
      EXIT FUNCTION
   END IF

'   ' // Open the file and store its contents into a buffer
'   DIM nFile AS LONG, bufferSize AS SIZE_T_
'   nFile = FREEFILE
'   OPEN wszFileName FOR BINARY AS nFile
'   IF ERR THEN EXIT FUNCTION
'   bufferSize = LOF(nFile)
'   DIM pBuffer AS UBYTE PTR
'   pBuffer = CAllocate(1, bufferSize)
'   GET #nFile, , *pBuffer, bufferSize
'   CLOSE nFile
'   IF pBuffer THEN
'      FUNCTION = AfxGdipImageFromBuffer(pBuffer, bufferSize, dimPercent, bGrayScale, imageType, clrBackground)
'      DeAllocate(pBuffer)
'   END IF

   ' // Use CreateFileW because Free Basic OPEN does not work with unicode file names.
   ' // Open the file and store its contents into a buffer
   DIM bSuccess AS LONG, dwFileSize AS DWORD, dwHighSize AS DWORD, dwBytesRead AS DWORD
   DIM hFile AS HANDLE = CreateFileW(@wszFileName, GENERIC_READ, FILE_SHARE_READ, NULL, _
                         OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL)
   IF hFile = INVALID_HANDLE_VALUE THEN EXIT FUNCTION
   ' // Get the size of the file
   dwFileSize = GetFileSize(hFile, @dwHighSize)
   IF dwHighSize THEN
      CloseHandle(hFile)
      EXIT FUNCTION
   END IF
   DIM pBuffer AS UBYTE PTR
   pBuffer = CAllocate(1, dwFileSize)
   bSuccess = ReadFile(hFile, pBuffer, dwFileSize, @dwBytesRead, NULL)
   CloseHandle(hFile)
   IF bSuccess THEN
      IF pBuffer THEN
         FUNCTION = AfxGdipImageFromBuffer(pBuffer, dwFileSize, dimPercent, bGrayScale, imageType, clrBackground)
         DeAllocate(pBuffer)
      END IF
   END IF

END FUNCTION
' ========================================================================================


José Roca

Added a new method to the Graphic Control: LoadImageFromRes.


' ========================================================================================
' Loads the specified image from a resource file in the Graphic Control.
' Parameters:
' - hInstance     = [in] A handle to the module whose portable executable file or an accompanying
'                   MUI file contains the resource. If this parameter is NULL, the function searches
'                   the module used to create the current process.
' - wszImageName  = [in] Name of the image in the resource file (.RES). If the image resource uses
'                   an integral identifier, wszImage should begin with a number symbol (#)
'                   followed by the identifier in an ASCII format, e.g., "#998". Otherwise,
'                   use the text identifier name for the image. Only images embedded as raw data
'                   (type RCDATA) are valid. These must be icons in format .png, .jpg, .gif, .tiff.
' - dimPercent    = Percent of dimming (1-99)
' - bGrayScale    = TRUE or FALSE. Convert to gray scale.
' - clrBackground = [in] The background color. This parameter is ignored if the image type
'                   is IMAGE_ICON or the bitmap is totally opaque.
' ========================================================================================
PRIVATE SUB CGraphCtx.LoadImageFromRes (BYVAL hInst AS HINSTANCE, BYREF wszImageName AS WSTRING, _
   BYVAL dimPercent AS LONG = 0, BYVAL bGrayScale AS LONG = FALSE, BYVAL clrBackground AS ARGB = 0)
   ' // Initialize Gdiplus
'   DIM token AS ULONG_PTR = AfxGdipInit
'   IF token = NULL THEN EXIT SUB
   DIM hbmp AS HBITMAP = AfxGdipBitmapFromRes(hInst, wszImageName, dimPercent, bGrayScale, clrBackground)
   IF hbmp THEN
      DIM bm AS BITMAP, hMemDC AS HDC
      hMemDC = .CreateCompatibleDC(m_hMemDC)
      IF hMemDC THEN
         IF .GetObject(hbmp, SIZEOF(BITMAP), @bm) THEN
            this.SetVirtualBufferSize(bm.bmWidth, bm.bmHeight)
            this.Clear m_bkcolor
            DIM Oldbmp AS HBITMAP
            Oldbmp = .SelectObject(hMemDC, hbmp)
            .BitBlt m_hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, hMemDC, 0, 0, SRCCOPY
            .SelectObject(hMemDC, Oldbmp)
         END IF
         DeleteDC hMemDC
      END IF
      DeleteObject hbmp
   END IF
   ' // Shutdown Gdiplus
'   GdiplusShutdown token
END SUB
' ========================================================================================


José Roca

#44
...and also the DrawBitmap method, to work with the new CMemBmp class.

The CMemBmp class implements a memory bitmap.

You can create an empty bitmap of the specified width an height, e.g.


DIM pMemBmp AS CMemBmp = CMemBmp(500, 400)


or loading an image


DIM pMemBmp AS CMemBmp = CMemBmp("C:\Users\Pepe\Pictures\Cole_Kyla_01.jpg")


You can manipulate its contents using GDI+ or GDI, e.g.


Rectangle pMemBmp.GetMemDC, 10, 10, 150, 150
LineTo pMemBmp.GetMemDC, 30, 180


And you can display it in a Graphic Control, e.g.


pGraphCtx.DrawBitmap pMemBmp


The bitmap can be saved to a file with


SaveBitmap
SaveBitmapAsBmp
SaveBitmapAsJpeg
SaveBitmapAsPng
SaveBitmapAsGif
SaveBitmapAsTiff


Finally, the PrintBitmap method prints the bitmap in the default printer.