PlanetSquires Forums

Support Forums => José Roca Software => Topic started by: José Roca on October 03, 2016, 03:04:12 PM

Title: CWindow RC 23
Post by: José Roca on October 03, 2016, 03:04:12 PM
CWindow Release Candidate 23

I have finished the CWebBrowser class.

Besides allowing to call all the relevant methods of the IWebBrowser2 interface, you can sink to the wanted events in a similar way as with VB6.

Events of the IDochHostUIHandler2 inteface are also supported for easy customization.

Events from the loaded page are supported in a generic way, i.e. there is not a callback for every possible event (there are too many) but just a function in which you can decide what to do according to the passe identifier of the event.

The most common need is to detect if a certain element in the web page, e.g. a button, has been clicked. You can do it by subscribing to the web page events


pwb.SetEventProc("HtmlDocumentEvents", @WebBrowser_HtmlDocumentEventsProc)


and then processing the event


PRIVATE FUNCTION WebBrowser_HtmlDocumentEventsProc (BYVAL hwndContainer AS HWND, BYVAL dispid AS LONG, BYVAL pEvtObj AS IHTMLEventObj PTR) AS BOOLEAN

   SELECT CASE dispid

      CASE DISPID_HTMLELEMENTEVENTS2_ONCLICK   ' // click event
         ' // Get a reference to the element that has fired the event
         DIM pElement AS IHTMLElement PTR
         IF pEvtObj THEN pEvtObj->lpvtbl->get_srcElement(pEvtObj, @pElement)
         IF pElement = NULL THEN EXIT FUNCTION
         DIM cbsHtml AS CBSTR   ' // Outer html
         pElement->lpvtbl->get_outerHtml(pElement, @cbsHtml)
'         DIM cbsId AS CBSTR   ' // identifier
'         pElement->lpvtbl->get_id(pElement, @cbsID)
         pElement->lpvtbl->Release(pElement)
         AfxMsg cbsHtml
         RETURN TRUE

   END SELECT

   RETURN FALSE

END FUNCTION


Full example


' ########################################################################################
' Microsoft Windows
' Contents: WebBrowser customization test
' Compiler: FreeBasic 32 & 64 bit
' Copyright (c) 2016 Jose Roca. Freeware. Use at your own risk.
' THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
' EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
' MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
' ########################################################################################

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

CONST IDC_WEBBROWSER = 1001
CONST IDC_SATUSBAR = 1002

DECLARE FUNCTION WinMain (BYVAL hInstance AS HINSTANCE, _
                          BYVAL hPrevInstance AS HINSTANCE, _
                          BYVAL szCmdLine AS ZSTRING PTR, _
                          BYVAL nCmdShow AS LONG) AS LONG

   END WinMain(GetModuleHandleW(NULL), NULL, COMMAND(), SW_NORMAL)

DECLARE FUNCTION WndProc (BYVAL hwnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT

' // Forward declarations
DECLARE SUB WebBrowser_StatusTextChangeProc (BYVAL hwndContainer AS HWND, BYVAL pwszText AS WSTRING PTR)
DECLARE SUB WebBrowser_DocumentCompleteProc (BYVAL hwndContainer AS HWND, BYVAL pdisp AS IDispatch PTR, BYVAL vUrl AS VARIANT PTR)
DECLARE SUB WebBrowser_BeforeNavigate2Proc (BYVAL hwndContainer AS HWND, BYVAL pdisp AS IDispatch PTR, _
    BYVAL vUrl AS VARIANT PTR, BYVAL Flags AS VARIANT PTR, BYVAL TargetFrameName AS VARIANT PTR, _
    BYVAL PostData AS VARIANT PTR, BYVAL Headers AS VARIANT PTR, BYVAL pbCancel AS VARIANT_BOOL PTR)
DECLARE FUNCTION WebBrowser_HtmlDocumentEventsProc (BYVAL hwndContainer AS HWND, BYVAL dispId AS LONG, BYVAL pEvtObj AS IHTMLEventObj PTR) AS BOOLEAN
DECLARE FUNCTION DocHostUI_ShowContextMenuProc (BYVAL hwndContainer AS HWND, BYVAL dwID AS DWORD, BYVAL ppt AS POINT PTR, BYVAL pcmdtReserved AS IUnknown PTR, BYVAL pdispReserved AS IDispatch PTR) AS HRESULT
DECLARE FUNCTION DocHostUI_GetHostInfo (BYVAL hwndContainer AS HWND, BYVAL pInfo AS DOCHOSTUIINFO PTR) AS HRESULT
DECLARE FUNCTION DocHostUI_TranslateAccelerator (BYVAL hwndContainer AS HWND, BYVAL lpMsg AS LPMSG, BYVAL pguidCmdGroup AS const GUID PTR, BYVAL nCmdID AS DWORD) AS HRESULT

' ========================================================================================
' Main
' ========================================================================================
FUNCTION WinMain (BYVAL hInstance AS HINSTANCE, _
                  BYVAL hPrevInstance AS HINSTANCE, _
                  BYVAL szCmdLine AS ZSTRING PTR, _
                  BYVAL nCmdShow AS LONG) AS LONG

   ' // Set process DPI aware
   ' // The recommended way is to use a manifest file
   AfxSetProcessDPIAware

   ' // Creates the main window
   DIM pWindow AS CWindow
   ' -or- DIM pWindow AS CWindow = "MyClassName" (use the name that you wish)
   DIM hwndMain AS HWND = pWindow.Create(NULL, "Embedded WebBrowser control with events and customization", @WndProc)
   ' // Sizes it by setting the wanted width and height of its client area
   pWindow.SetClientSize(750, 450)
   ' // Centers the window
   pWindow.Center

   ' // Add a status bar
   DIM hStatusbar AS HWND = pWindow.AddControl("Statusbar", , IDC_SATUSBAR)

   ' // Add a WebBrowser control
   DIM pwb AS CWebBrowser = CWebBrowser(@pWindow, IDC_WEBBROWSER, 0, 0, pWindow.ClientWidth, pWindow.ClientHeight)
   ' // Connect events
   pwb.Advise
   ' // Set event callback procedures
   pwb.SetEventProc("StatusTextChange", @WebBrowser_StatusTextChangeProc)
   pwb.SetEventProc("DocumentComplete", @WebBrowser_DocumentCompleteProc)
   pwb.SetEventProc("BeforeNavigate2", @WebBrowser_BeforeNavigate2Proc)
   pwb.SetEventProc("HtmlDocumentEvents", @WebBrowser_HtmlDocumentEventsProc)
   ' // Set the IDocHostUIHandler interface
   pwb.SetUIHandler
   ' // Set event callback procedures
   pwb.SetUIEventProc("ShowContextMenu", @DocHostUI_ShowContextMenuProc)
   pwb.SetUIEventProc("GetHostInfo", @DocHostUI_GetHostInfo)
   pwb.SetUIEventProc("TranslateAccelerator", @DocHostUI_TranslateAccelerator)
   ' // Navigate to a URL
   pwb.Navigate("http://com.it-berater.org/")
'   pwb.Navigate("http://www.jose.it-berater.org/smfforum/index.php")

   ' // Display the window
   ShowWindow(hWndMain, nCmdShow)
   UpdateWindow(hWndMain)

   ' // Dispatch Windows messages
   DIM uMsg AS MSG
   WHILE (GetMessageW(@uMsg, NULL, 0, 0) <> FALSE)
      IF AfxForwardMessage(GetFocus, @uMsg) = FALSE THEN
         IF IsDialogMessageW(hWndMain, @uMsg) = 0 THEN
            TranslateMessage(@uMsg)
            DispatchMessageW(@uMsg)
         END IF
      END IF
   WEND
   FUNCTION = uMsg.wParam

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

' ========================================================================================
' Main window procedure
' ========================================================================================
FUNCTION WndProc (BYVAL hwnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT

   SELECT CASE uMsg

      CASE WM_COMMAND
         SELECT CASE LOWORD(wParam)
            CASE IDCANCEL
               ' // If ESC key pressed, close the application by sending an WM_CLOSE message
               IF HIWORD(wParam) = BN_CLICKED THEN
                  SendMessageW hwnd, WM_CLOSE, 0, 0
                  EXIT FUNCTION
               END IF
         END SELECT

      CASE WM_SIZE
         ' // Optional resizing code
         IF wParam <> SIZE_MINIMIZED THEN
            ' // Resize the status bar
            DIM hStatusBar AS HWND = GetDlgItem(hwnd, IDC_SATUSBAR)
            SendMessage hStatusBar, uMsg, wParam, lParam
            ' // Calculate the size of the status bar
            DIM StatusBarHeight AS DWORD, rc AS RECT
            GetWindowRect hStatusBar, @rc
            StatusBarHeight = rc.Bottom - rc.Top
            ' // Retrieve a pointer to the CWindow class
            DIM pWindow AS CWindow PTR = AfxCWindowPtr(hwnd)
            ' // Move the position of the control
            IF pWindow THEN pWindow->MoveWindow GetDlgItem(hwnd, IDC_WEBBROWSER), _
               0, 0, pWindow->ClientWidth, pWindow->ClientHeight - StatusBarHeight / pWindow->ryRatio, CTRUE
         END IF

    CASE WM_DESTROY
         ' // Ends the application by sending a WM_QUIT message
         PostQuitMessage(0)
         EXIT FUNCTION

   END SELECT

   ' // Default processing of Windows messages
   FUNCTION = DefWindowProcW(hwnd, uMsg, wParam, lParam)

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

' ========================================================================================
' Process the WebBrowser StatusTextChange event.
' ========================================================================================
SUB WebBrowser_StatusTextChangeProc (BYVAL hwndContainer AS HWND, BYVAL pwszText AS WSTRING PTR)
   IF pwszText THEN StatusBar_SetText(GetDlgItem(GetParent(hwndContainer), IDC_SATUSBAR), 0, pwszText)
END SUB
' ========================================================================================

' ========================================================================================
' Process the WebBrowser DocumentComplete event.
' ========================================================================================
SUB WebBrowser_DocumentCompleteProc (BYVAL hwndContainer AS HWND, BYVAL pdisp AS IDispatch PTR, BYVAL vUrl AS VARIANT PTR)
   ' // The vUrl parameter is a VT_BYREF OR VT_BSTR variant
   ' // It can be a VT_BSTR variant or a VT_ARRAY OR VT_UI1 with a pidl
   DIM varUrl AS VARIANT
   VariantCopyInd(@varUrl, vUrl)
   StatusBar_SetText(GetDlgItem(GetParent(hwndContainer), IDC_SATUSBAR), 0, "Document complete: " & AfxVarToStr(@varUrl))
   VariantClear(@varUrl)
END SUB
' ========================================================================================

' ========================================================================================
' Process the IDocHostUIHandler ShowContextMenu event.
' ========================================================================================
FUNCTION DocHostUI_ShowContextMenuProc (BYVAL hwndContainer AS HWND, BYVAL dwID AS DWORD, BYVAL ppt AS POINT PTR, BYVAL pcmdtReserved AS IUnknown PTR, BYVAL pdispReserved AS IDispatch PTR) AS HRESULT
   ' // This event notifies that the user has clicked the right mouse button to show the
   ' // context menu. We can anulate it returning %S_OK and show our context menu.
   ' // Do not allow to show the context menu
'   AfxMsg "Sorry! Context menu disabled"
'   RETURN S_OK
   ' // Host did not display its UI. MSHTML will display its UI.
   RETURN S_FALSE
END FUNCTION
' ========================================================================================

' ========================================================================================
' Process the IDocHostUIHandler GetHostInfo event.
' ========================================================================================
PRIVATE FUNCTION DocHostUI_GetHostInfo (BYVAL hwndContainer AS HWND, BYVAL pInfo AS DOCHOSTUIINFO PTR) AS HRESULT
   IF pInfo THEN
      pInfo->cbSize = SIZEOF(DOCHOSTUIINFO)
      pInfo->dwFlags = DOCHOSTUIFLAG_NO3DBORDER OR DOCHOSTUIFLAG_THEME OR DOCHOSTUIFLAG_DPI_AWARE
      pInfo->dwDoubleClick = DOCHOSTUIDBLCLK_DEFAULT
      pInfo->pchHostCss = NULL
      pInfo->pchHostNS = NULL
   END IF
   RETURN S_OK
END FUNCTION
' ========================================================================================

' ========================================================================================
' Process the IDocHostUIHandler TranslateAccelerator event.
' ========================================================================================
PRIVATE FUNCTION DocHostUI_TranslateAccelerator (BYVAL hwndContainer AS HWND, BYVAL lpMsg AS LPMSG, BYVAL pguidCmdGroup AS const GUID PTR, BYVAL nCmdID AS DWORD) AS HRESULT
   ' // When you use accelerator keys such as TAB, you may need to override the
   ' // default host behavior. The example shows how to do this.
    IF lpMsg->message = WM_KEYDOWN AND lpMsg->wParam = VK_TAB THEN
       RETURN S_FALSE   ' S_OK to disable tab navigation
    END IF
   ' // Return S_FALSE if you don't process the message
   RETURN S_FALSE
END FUNCTION
' ========================================================================================

' ========================================================================================
' Fires before navigation occurs in the given object (on either a window or frameset element).
' ========================================================================================
SUB WebBrowser_BeforeNavigate2Proc (BYVAL hwndContainer AS HWND, BYVAL pdisp AS IDispatch PTR, _
    BYVAL vUrl AS VARIANT PTR, BYVAL Flags AS VARIANT PTR, BYVAL TargetFrameName AS VARIANT PTR, _
    BYVAL PostData AS VARIANT PTR, BYVAL Headers AS VARIANT PTR, BYVAL pbCancel AS VARIANT_BOOL PTR)

'   ' // Sample code to redirect navigation to another url
'   IF AfxVarToStr(vUrl) = "http://com.it-berater.org/" THEN
'      ' // Get a reference to the Afx_IWebBrowser2 interface
'      DIM pwb AS Afx_IWebBrowser2 PTR = cast(Afx_IWebBrowser2 PTR, cast(ULONG_PTR, pdisp))
'      IF pwb THEN
'         ' // Stop loading the page
'         pwb->Stop
'         ' // Cancel the navigation operation
'         *pbCancel = VARIANT_TRUE
'         ' // Navigate to another new url
'         DIM cvNewUrl AS CVARIANT = "http://www.planetsquires.com/protect/forum/index.php"
'         pwb->Navigate2(@cvNewUrl)
'      END IF
'   END IF

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

' ========================================================================================
' For cancelable document events return TRUE to indicate that Internet Explorer should
' perform its own event processing or FALSE to cancel the event.
' ========================================================================================
PRIVATE FUNCTION WebBrowser_HtmlDocumentEventsProc (BYVAL hwndContainer AS HWND, BYVAL dispid AS LONG, BYVAL pEvtObj AS IHTMLEventObj PTR) AS BOOLEAN

   SELECT CASE dispid

      CASE DISPID_HTMLELEMENTEVENTS2_ONCLICK   ' // click event
         ' // Get a reference to the element that has fired the event
         DIM pElement AS IHTMLElement PTR
         IF pEvtObj THEN pEvtObj->lpvtbl->get_srcElement(pEvtObj, @pElement)
         IF pElement = NULL THEN EXIT FUNCTION
         DIM cbsHtml AS CBSTR   ' // Outer html
         pElement->lpvtbl->get_outerHtml(pElement, @cbsHtml)
'         DIM cbsId AS CBSTR   ' // identifier
'         pElement->lpvtbl->get_id(pElement, @cbsID)
         pElement->lpvtbl->Release(pElement)
         AfxMsg cbsHtml
         RETURN TRUE

   END SELECT

   RETURN FALSE

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


I have reuploaded the headers incorporating the changes posted in reply #12.
Title: Re: CWindow RC 23
Post by: José Roca on October 03, 2016, 07:02:21 PM
Because of the lack of response, I think that I'm going to stop posting, unless I find bugs that require an update.

I would like to know if it is because...

1) There is not much interest in Free Basic among the members of this forum.

2) There is not interest in this framework.

3) Other reasons.
Title: Re: CWindow RC 23
Post by: Richard Kelly on October 04, 2016, 01:13:29 AM
I'm at the beginning of my transition to FB and I follow your posts with much interest. It is your work that convinced me I could make a go of FB. I have a large toolbox of stuff (classes like PDF creation, SMTP, tcp/ip, SQLite client/server, etc) to port, cCalendar being the first before I begin the rewrite of my applications. I'm counting on Paul to integrate cWindows as completely as possible to provide the foundation for first rate Windows apps. I'm not into all the technical details as you are - my area is the end game and developing software that uniquely solutions commercial lines of business. For that, I need you and Paul and appreciate all that the both of you do.
Title: Re: CWindow RC 23
Post by: José Roca on October 04, 2016, 02:21:20 AM
So, if I haven't misunderstood you, you're waiting for a visual designer.
Title: Re: CWindow RC 23
Post by: Marc Pons on October 04, 2016, 06:39:43 AM
Jose

As always you are doing a very valuable job.

Be sure , I'm very interrested on FreeBasic , on your Framework and globally on your posts.

I'm still "absorbing" the big amount of code you are producing.

What I'm less interrested is  in the CWebBrowser  : for me it is more a way ( a sample )on how to use the COM.

As you know,i'm more interrested on the generic tools to facilitate the use of COM under Freebasic.

I'm currently converting to freebasic an application i've previously done with powerbasic interfacing pfdcreator to convert to pfd many types of documents ( because pdfcreator changed completly their COM interfaces), i will use lot of your solutions.

The generation code of your typelib browser will play a big role.
Still do not understand how to use your Colecon class on  IUNKNOWN interface  and how to fire IUNKNOWN event interface...


If you think your Freebasic contribution not enougth followed here, why not extend it on  posting on the official Freebasic Forum , and / or in this one  https://www.freebasic-portal.de/ (https://www.freebasic-portal.de/) german but no problem to put english info.
Title: Re: CWindow RC 23
Post by: James Fuller on October 04, 2016, 07:37:29 AM
Jose,
  I understand your reluctance to continue posting, but the sheer volume of your contributions, takes a while to absorb. Please continue your FreeBasic research and post your findings here.
I believe a majority of advanced Fb coders are Linux centric. Novice Fb Windows coders may very well just be overwhelmed with the material you have posted here.
Much of your code is not very BASIC in appearance. I know you are not a big MACRO fan but maybe that is a direction that would interest more people.
  Thank you for your dedication.

James


Title: Re: CWindow RC 23
Post by: Klaas Holland on October 04, 2016, 07:52:21 AM
Jose,

Thank you for your contribution to the FreeBasic world.
Your knowledge of programming is far beyond mine.

I converted almost all of my FF-PB programs into FF-FreeBasic thanks to the help of Paul.
However these programs are not High DPI Aware.

It would be great if Paul implements all of your work in FireFly, so we will be able to use it in FireFly.

This could be the way to persuade the PB-people to switch to FreeBasic.

Klaas

Title: Re: CWindow RC 23
Post by: Richard Kelly on October 04, 2016, 09:11:05 AM
Quote from: Jose Roca on October 04, 2016, 02:21:20 AM
So, if I haven't misunderstood you, you're waiting for a visual designer.

Yes - that is the logical endgame for your work.
Title: Re: CWindow RC 23
Post by: José Roca on October 04, 2016, 12:33:24 PM
Quote
Still do not understand how to use your Colecon class on  IUNKNOWN interface  and how to fire IUNKNOWN event interface...

And I still don't understand what you mean. I never have seen a visual OCX which inherits directly from IUnknown instead of IDispatch. Can you give me an example?

The OLE Container is a class to host visual ActiveX controls. Non visual ActiveX don't need an OLE Container.

Quote
What I'm less interrested is  in the CWebBrowser  : for me it is more a way ( a sample )on how to use the COM.

Probably you don't realize all that can be done with it.
Title: Re: CWindow RC 23
Post by: José Roca on October 04, 2016, 02:03:37 PM
Quote from: Richard Kelly on October 04, 2016, 09:11:05 AM
Quote from: Jose Roca on October 04, 2016, 02:21:20 AM
So, if I haven't misunderstood you, you're waiting for a visual designer.

Yes - that is the logical endgame for your work.

If a visual designer is a prerequisite to use the framework then we are screwed because we don't know if this will ever happen or when.

Any project without participants dies because of lack of motivation.
Title: Re: CWindow RC 23
Post by: Jean-pierre Leroy on October 04, 2016, 03:05:27 PM
Jose,

You have done a huge work with your framework; almost everything is avaible including ODBC (which is nice to replace SQLtools usually used with PB).

I read each of your posts with great attention.

Currently I'm still using FireFly+PowerBASIC+SQLitening+SQLTools+VPE (Virtual Print Engine) to create 32 bits only, ansi only, client/serveur windows software (business applications).

It will be easier (at least for me) to switch to FreeBasic when a visual designer coupled with your framework will be available.
Title: Re: CWindow RC 23
Post by: Richard Kelly on October 04, 2016, 08:17:39 PM
Quote from: Jose Roca on October 04, 2016, 02:03:37 PM
Quote from: Richard Kelly on October 04, 2016, 09:11:05 AM
Quote from: Jose Roca on October 04, 2016, 02:21:20 AM
So, if I haven't misunderstood you, you're waiting for a visual designer.

Yes - that is the logical endgame for your work.

If a visual designer is a prerequisite to use the framework then we are screwed because we don't know if this will ever happen or when.

Any project without participants dies because of lack of motivation.

There is much in the framework I will use as part of the classes I have yet to port over. cWindows is the key integration into a visual designer and I hope to see something this year.

I do understand participation. You are the only one who posted on my cCalendar effort over much of the past months and I spent roughly 50 hours on it. Perhaps this forum is in decline.
Title: Re: CWindow RC 23
Post by: José Roca on October 05, 2016, 02:37:02 AM
Modified the following wrapper functions in which the parameter was being wrongly cast to the address of the passed pointer (I still make this error sometimes because I have used @ with pointers so many times with PowerBASIC).

ComboBoxEx_InsertItem
Syslink_GetItem
SysLink_HitTest
SysLink_SetItem
TreeView_GetItemEx

I have reuploaded the headers incorporating these changes.
Title: Re: CWindow RC 23
Post by: Petrus Vorster on October 06, 2016, 02:51:46 PM
I read each and every post you make, although I don't understand half of it.
Many of us are dependent on a visual designer and we truly hope that it would happen because this massive amount of stuff you develop combined with a visual designer from Paul will enable the rest of us to excel like never before.

I mean, you made Powerbasic Rock. You and Paul made it accessible to me and now I hope that you two will combine once again with all your lovely inspiring computer voodoo you do so a dummy like me can do cool stuff too.

We are here, every day. Please don't stop with your magic.
I just don't post anything because I cant contribute any value to your work!!!

All of us appreciate the stuff you do. Without it most will be lost!! thanks a million.
Title: Re: CWindow RC 23
Post by: José Roca on October 06, 2016, 08:02:15 PM
Thanks to all for answering my questions.

As I'm not willing to officially release something that has not been thoroughly tested, I'm going to prepare a stripped version with all the COM stufff removed. I will keep CWindow, the wrappers for the Windows API and controls, the string functions, the GDI+ helpers (not the classes) and the CWSTR data type. Maybe something more that I'm forgetting. Everything else will be removed. That is, I'm only going to keep what Paul will need to finish his editor.

Title: Re: CWindow RC 23
Post by: Marc Pons on October 07, 2016, 06:09:02 AM
Jose, 
i'm very sad :'(

All the knowledge and passion you have for COM technology must not desapear !

You are one of the people who gave me the possibility to understand and work at certain extend with COM outside VC/VB .

For a vb6 guy as i was, it was so frustating to not be able to play as simple, as it was on the vb6 era.
For that reason, i've investigated a lot on Autoit wich has the flavor of basic and giving almost the same easy support to COM as VB6.
You on PowerBasic, Loe and Aloberoger on the freebasic forum ( who were also inspired by you) gave me almost the same possibilities (not as simpler) and i have to thank you so much for that.

Even making the last TypeLib browser functionnal for freebasic! And sharing your source code!

I hope, the frustration you feel by the "lack of interrest" will not persiste...

For my part, I will continue to investigate, improving my small competences on using activeX components,
it is a deep mine for curious people.

Hope, if i have stupid questions you can continue to give me some help, here or somewhere else...

Please receive my best regards, Marc.

Note : be sure, i have and will archive your precious posts   8)
Title: Re: CWindow RC 23
Post by: David Warner on October 07, 2016, 07:04:12 AM
Hi Jose,

I too am sad to read of your disappointment with the lack of interaction and feedback about your amazing efforts. I imagine the lack of feedback is largely to do with the fact that your accomplishments are so far ahead of where the rest of us 'mere mortals' are at. It is immensely difficult for the silent majority to contribute as you operate at a level so far beyond ours. What might seem obvious and straightforward to you is somewhat obscure and impenetrable to others and it is hugely reassuring to know that Jose the master has blazed a trail for the rest and made everything simple to use.

It is a frequent source of pleasure and admiration for me that you are kind and gracious enough to share your efforts with those of us who would never be able to originate such tremendous software. Whatever your choice may be about what you publish in the future, I would just like to express my thanks to you for all that you have already done. You have demonstrated not only how to write the best software but how to be a decent, generous and inspirational human being. Thank you.
Title: Re: CWindow RC 23
Post by: José Roca on October 07, 2016, 04:50:44 PM
What it remains still contains a lot of useful stuff. I mainly have removed the COM parts, so those that never use COM won't miss it. The COM wrappers were an attempt to make this technology more accessible, but I don't really need them.

I will continue exploring what I can do with the WebBrowser control using HTML and javascript. With the OLE Container and the CWebBrowser class I can start to attempt to make GUIs using HTML instead of / or mixing with Windows controls. This is an exciting possibility to make cool GUIs, taking the best of both technologies.


Title: Re: CWindow RC 23
Post by: Wilko Verweij on October 07, 2016, 05:45:12 PM
Dear Jose,
I just recently started exploring FreeBasic, as I have a project written in FireFly/PowerBasic which I want to finish before quitting PowerBasic entirely. So my lack of interest is because I am late in switching to FreeBasic, not because I am not interested in your work. On the contrary, I really appreciate your expertise and the huge amount of work you spent on developing and testing these includes for FireFly/Powerbasic and FreeBasic. So I hope you do not stop this work...
Wilko
Title: Re: CWindow RC 23
Post by: Paul Squires on October 07, 2016, 10:28:34 PM
Quote from: Jose Roca on October 07, 2016, 04:50:44 PM
...With the OLE Container and the CWebBrowser class I can start to attempt to make GUIs using HTML instead of / or mixing with Windows controls. This is an exciting possibility to make cool GUIs, taking the best of both technologies.

That would be a very cool project for GUI's. I wrote an ecommerce site last year and it was my first big project using Javascript, HTML/CSS, PHP, MYSQL and other libraries. Web technologies have come a long way. These days there is a push to create standalone cross platform applications. Take a look at projects like the Atom code editor that uses the Electron framework. Amazing what can be created these days with web technologies.
Title: Re: CWindow RC 23
Post by: Petrus Vorster on October 08, 2016, 02:55:25 AM
Paul, let me please ask a question i think many here is waiting for.

Would you consider using this cwindow developments of Jose in a future firefly for FB?
There are so much new developments that if you two throw this together, you will build one serious development tool.

I for one would love to have a Firefly that has all this new stuff from Jose as well.

Ps. Checked out ATOM, very cool.
Title: Re: CWindow RC 23
Post by: Paul Squires on October 08, 2016, 03:03:30 PM
Hi Peter, yes, of course I would use Jose's CWindow in FireFly for FB. That is not too difficult to do at all. I did it for the PB version a long time ago. The "problem" is that I want FireFly to be unicode based and Jose has done tremendous work in that area with regards to FreeBasic and unicode. I would want the visual designer to be 100% unicode based while also using CWindow for the code generation. As you probably already know, I have been working on code editors for FB (FBE) and one version is pretty much done with the other version almost done. Both are unicode and CWindow based. The next step after that would be to add a visual designer that integrates with the code editor.
Title: Re: CWindow RC 23
Post by: José Roca on October 08, 2016, 04:53:25 PM
Now that we have CWSTR, there is not excuse to not use unicode. It is super fast and dynamic. I learned years ago that using ansi in an application that you later plain to convert to unicode is the wrong way. For what we need a framework with both ansi and unicode versions if only the unicode one is needed? Although FB has not full unicode suport, at least it deals with unicode transparently, allowing to pass ansi strings to functions that have WSTRING parameters and doing an automatic conversion.

For the "Spectre" version of the framework, I'm going to rescue some stuff like the OLE Container and the CWebBrowser class. There are only a few wrappers that use CBSTRings and I can adapt them to use CWSTR instead, doing the needed conversions in the internal code. I'm going to use it extensively and don't want to have a version of the framework for general use and another for private use.

Regarding CBSTR, I wasn't fully satisfied with this data type because I had to use a couple of hacks. Anyway, if I'm the only one that is going to use COM, I have no problem to use it at low-level.

I'm also going to rescue some COM related stuff, like AfxCOM.inc, that does not use CBSTR, CVARIANT or CSafeArray. I need it and its use is optional.

Title: Re: CWindow RC 23
Post by: José Roca on October 09, 2016, 06:14:41 PM
I have discovered a curious thing.

If I use a CWSTR in a line such


PRINT "Line " & WSTR(curLine) & ", Column " &  WSTR(curColumn) & ": " & **cwsText


I have to use **cwsText (double indirection)

But if I use + instead of &, I don't need the **


PRINT "Line " & WSTR(curLine) & ", Column " &  WSTR(curColumn) & ": " + cwsText


It also happens when concatenating strings:


cws = WSTR(curLine) + ", Column " +  WSTR(curColumn) + ": " + cwsText

Title: Re: CWindow RC 23
Post by: Johan Klassen on October 09, 2016, 09:56:32 PM
Hi Jose
at the risk of being wrong, could it be that the + operator is overloaded ?
Title: Re: CWindow RC 23
Post by: José Roca on October 09, 2016, 10:26:26 PM
Both are overloaded. The difference is that whereas the two expressions concatenated by the + operator must be strings, the & operator also accepts numbers and tries to do the conversion.
Title: Re: CWindow RC 23
Post by: Paul Squires on October 09, 2016, 10:55:17 PM
Jose, I have also noticed that several times in the code that I've written. Sometimes the "&" concatenation does not work. I have always used the "&" rather than "+".
Title: Re: CWindow RC 23
Post by: José Roca on October 09, 2016, 11:11:53 PM
Using ** or the + operator always works. Maybe the & operator sometimes can't ascertain if it is a pointer to a string or a number that must be converted to a string.
Title: Re: CWindow RC 23
Post by: José Roca on October 09, 2016, 11:24:25 PM
I have managed to get most of the framework working without using CBSTR and CVARIANT.
Title: Re: CWindow RC 23
Post by: Marc Pons on October 10, 2016, 11:33:08 AM
Quote from: Jose Roca on October 09, 2016, 10:26:26 PM
Both are overloaded. The difference is that whereas the two expressions concatenated by the + operator must be strings, the & operator also accepts numbers and tries to do the conversion.

in fact when using operator "&" , it will implicitly make a conversion to string using str()
the operator "+" will expect true strings so it will not make implicit conversion

that explain :
QuoteIf I use a CWSTR in a line such

Code: [Select]

PRINT "Line " & WSTR(curLine) & ", Column " &  WSTR(curColumn) & ": " & **cwsText


I have to use **cwsText (double indirection)

because cwsText is a class and str() function does not understand how to do with it.

i think you can define a new overload operator "&" to use cwstr directly  without **cwsText
for string result
Operator & (ByRef ust1 as string , ByVal cwst2 as CWSTR) as string
      return ust1 & **cwst2  'using here the implicit cast to string to convert cwst2 content to string
'or      return ust1 & str(**cwst2) 'explicit conversion
end operator

easier way but more operations !
could also be duplicated to CWSTR  or WSTRING
Title: Re: CWindow RC 23
Post by: Marc Pons on October 10, 2016, 11:41:21 AM
it is not complete answer:

why  operrator "+" works correctly in that case?
because that operator expect a string after it and the compiler use the implicit cast implemented by the cwstr class to make the job.

in reality the convertion task is done but not seen by the user.
Title: Re: CWindow RC 23
Post by: José Roca on October 10, 2016, 02:13:02 PM
Quote
i think you can define a new overload operator "&" to use cwstr directly  without **cwsText
for string result


Operator & (ByRef ust1 as string , ByVal cwst2 as CWSTR) as string
      return ust1 & **cwst2  'using here the implicit cast to string to convert cwst2 content to string
'or      return ust1 & str(**cwst2) 'explicit conversion
end operator


easier way but more operations !
could also be duplicated to CWSTR  or WSTRING

No way. Converting it to ansi with STR will screw the unicode contents. Better to use +.
Title: Re: CWindow RC 23
Post by: José Roca on October 10, 2016, 04:11:05 PM
Modified an small bug in one of the Add methods of CWSTR. Didn't noticed before because I was not using UTF-8.


PRIVATE SUB CWstr.Add (BYREF ansiStr AS STRING, BYVAL nCodePage AS UINT = 0)
   CWSTR_DP("CWSTR Add STRING Code page = " & WSTR (nCodePage))
'   DIM AS LONG nLenString = .LEN(ansiStr) * 2
'   IF nLenString = 0 THEN RETURN
   IF LEN(ansiStr) = 0 THEN RETURN
   ' Create the wide string from the incoming ansi string
   DIM pbstr AS BSTR
   IF nCodePage = 0 THEN nCodePage = m_CodePage
   IF nCodePage = CP_UTF8 THEN
      DIM dwLen AS DWORD = MultiByteToWideChar(CP_UTF8, 0, STRPTR(ansiStr), LEN(ansiStr), NULL, 0)
      IF dwLen THEN
         pbstr = SysAllocString(WSTR(SPACE(dwLen)))
         MultiByteToWideChar(CP_UTF8, 0, STRPTR(ansiStr), LEN(ansiStr), pbstr, dwLen * 2)
      END IF
   ELSE
      pbstr = SysAllocString(WSTR(ansiStr))
      MultiByteToWideChar(m_CodePage, MB_PRECOMPOSED, STRPTR(ansiStr), -1, pbstr, LEN(ansiStr) * 2)
   END IF
   IF pbstr THEN
      ' Copy the string into the buffer and update the length
'      this.AppendBuffer(pbstr, nLenString)
      this.AppendBuffer(pbstr, SysStringLen(pbstr) * 2)
      SysFreeString(pbstr)
   END IF
END SUB


When used with UTF-8, it was passing the length in UTF-8 instead of UTF-16.
Title: Re: CWindow RC 23
Post by: José Roca on October 10, 2016, 05:20:55 PM
The problem with the intrinsic FB functions that don't work directly with CWSTR seems to be that they don't trigger the casting operators of the class.

AfxMsg LEFT(cws, 10) fails with an ambiguous call error, but AfxMsg LEFT("" & cws, 10) works. The concatenation triggers the cast operator.
Title: Re: CWindow RC 23
Post by: Marc Pons on October 11, 2016, 04:46:43 AM
Quote from: Jose Roca on October 10, 2016, 02:13:02 PM



No way. Converting it to ansi with STR will screw the unicode contents. Better to use +.
its true but as i also said can be extended to wstring and cwstr
hope it work like that: (not tested!)

Operator & (ByRef wst1 as wstring , ByVal cwst2 as CWSTR) as wstring
      return wst1 & **cwst2
end operator
Operator & (ByRef cwst1 as CWSTR , ByVal cwst2 as CWSTR) as CWSTR
      return cwst1 & **cwst2
end operator


I know + is working but it is not coherent with the freebasic convention
+ normaly to concatenate string or wstrings only
& helper to convert to "string" and concatenate
Title: Re: CWindow RC 23
Post by: Marc Pons on October 11, 2016, 04:59:21 AM
QuoteAfxMsg LEFT(cws, 10) fails with an ambiguous call error, but AfxMsg LEFT("" & cws, 10) works. The concatenation triggers the cast operator.
it is normal behaviour, your cast in cwstr class are the following :
' ========================================================================================
' Returns a pointer to the CWSTR buffer.
' ========================================================================================
PRIVATE OPERATOR CWstr.CAST () BYREF AS WSTRING
   CWSTR_DP("CWSTR CAST BYREF AS WSTRING - buffer: " & WSTR(m_pBuffer))
   OPERATOR = *cast(WSTRING PTR, m_pBuffer)
END OPERATOR
' ========================================================================================
' ========================================================================================
PRIVATE OPERATOR CWstr.CAST () AS ANY PTR
   CWSTR_DP("CWSTR CAST ANY PTR - buffer: " & WSTR(m_pBuffer))
   OPERATOR = cast(ANY PTR, m_pBuffer)
END OPERATOR
' ========================================================================================


probably the cast for any ptr is the trick here
Title: Re: CWindow RC 23
Post by: José Roca on October 11, 2016, 10:35:40 AM
Implementing & as an overloded operator for CWSTR works, of course (I have tried it before)


PRIVATE Operator & (ByRef cwst1 as CWSTR , ByRef cwst2 as CWSTR) as CWSTR
   CWSTR_DP("CWSTR Operator &")
   RETURN **cwst1 & **cwst2
END OPERATOR


but it is pretty innefficient, and my goal is to be as fast as possible.

A line like this


cws = "Line " & WSTR(1) & ", Column " &  WSTR(2) & ": " & **cwsText


generates this trace code


CWSTR OPERATOR * buffer: 6632152
CWSTR LET WSTRING PTR
CWSTR Clear
CWSTR ResizeBuffer - Value = 27
CWSTR ResizeBuffer - pNewBuffer = 6631952 - old buffer = 6632688
CWSTR Add WSTRING
CWSTR AppendBuffer 0 54
CWSTR ResizeBuffer - Value = 108
CWSTR ResizeBuffer - pNewBuffer = 6632688 - old buffer = 6631952
--END - CWSTR AppendBuffer 54


Using the operator +


cws = "Line " & WSTR(1) + ", Column " &  WSTR(2) & ": " + cwsText


generates this trace code


CWSTR CAST BYREF AS WSTRING - buffer: 2634456
CWSTR LET WSTRING PTR
CWSTR Clear
CWSTR ResizeBuffer - Value = 27
CWSTR ResizeBuffer - pNewBuffer = 2634288 - old buffer = 2634992
CWSTR Add WSTRING
CWSTR AppendBuffer 0 54
CWSTR ResizeBuffer - Value = 108
CWSTR ResizeBuffer - pNewBuffer = 2634992 - old buffer = 2634288
--END - CWSTR AppendBuffer 54


Changing it to


cws = "Line " & WSTR(1) & ", Column " &  WSTR(2) & ": " & cwsText


with the overloaded & operator implemented, generates this trace code


+++BEGIN- CWSTR CONSTRUCTOR WSTRING - 4255888
CWSTR ResizeBuffer - Value = 520
CWSTR ResizeBuffer - pNewBuffer = 8533768 - old buffer = 0
CWSTR Add WSTRING
CWSTR AppendBuffer 0 36
--END - CWSTR AppendBuffer 36
-END- CWSTR CONSTRUCTOR WSTRING - 8533768
CWSTR Operator &
CWSTR OPERATOR * buffer: 8532696
CWSTR OPERATOR * buffer: 8533768
+++BEGIN- CWSTR CONSTRUCTOR WSTRING - 8532432
CWSTR ResizeBuffer - Value = 520
CWSTR ResizeBuffer - pNewBuffer = 8534304 - old buffer = 0
CWSTR Add WSTRING
CWSTR AppendBuffer 0 54
--END - CWSTR AppendBuffer 54
-END- CWSTR CONSTRUCTOR WSTRING - 8534304
CWSTR LET CWSTR
CWSTR Clear
CWSTR OPERATOR * buffer: 8534304
CWSTR OPERATOR LEN - len: 27
CWSTR OPERATOR * buffer: 8534304
CWSTR ResizeBuffer - Value = 27
CWSTR ResizeBuffer - pNewBuffer = 8532432 - old buffer = 8533232
CWSTR OPERATOR @ - buffer: 8534304
CWSTR Add CWSTR - LEN = 27
CWSTR OPERATOR @ - buffer: 8534304
CWSTR CAST ANY PTR - buffer: 8534304
CWSTR AppendBuffer 0 54
CWSTR ResizeBuffer - Value = 108
CWSTR ResizeBuffer - pNewBuffer = 8532472 - old buffer = 8532432
--END - CWSTR AppendBuffer 54
***CWSTR DESTRUCTOR - buffer: 8533768
***CWSTR DESTRUCTOR - buffer: 8534304


Both ** and + generate identical code, except the first line: ** calls the operator * ( CWSTR OPERATOR * buffer: 6632152 ) and + calls the operator CAST ( CWSTR CAST BYREF AS WSTRING - buffer: 2634456 ).

The overloaded operator & has to create three instances of the CWSTR class, two to concatenate and another one to return the result.

We have not worked so hard to get a superfast unicode dynamic string to spoil it using innefficient techniques.
Title: Re: CWindow RC 23
Post by: Marc Pons on October 11, 2016, 12:13:08 PM
Jose

sometime i've problems to understand or explain, probably because English is not my native language :'(

let me sumerize my purpose :

     I'm not saying "+" or "**" is wrong , they work perfectly to make the job , so it's a perfect true solution
     I'm just saying "&" could work also and for me the more important word is : also
     I think it is better to have that solution too than to have compilation problems
     I've said in my previous posts :  if  using "&"  it will be :
Quoteeasier way but more operations !
I've said also
QuoteI know + is working but it is not coherent with the freebasic convention
+ normaly to concatenate string or wstrings only
& helper to convert to "string" and concatenate

myself, i normally use without thinking more : "+" for "add" operation  and "&" for concatenation... probably coming from Fortran
i'm sure i'm not the only one doing that !

Last point, you are showing the extra operations if using overloaded "&" ,
but you know the way you have done the overload "&" to test it, could probably be optimized
as we are "derriere le rideau" / "behind the curtain", at level of operator we could directly play with the class functions...

At the end, it is not a big problem , these kind of overload operator does not need to be part of the class
it can be done everywhere in the code as you want it.

Probably you understood also, even i'm fare away of your knowledge, i like to go to the details :
the speed of concatenation was one of the aspects very important for me, if your remember our previous contacts.

I sincerely hope, you will not take that present post as a critic in any sort,
i just try to participate, showing at least my interest,
and at the end supporting as much as i can the very important job you are doing.

And, for all, please excuse my wording, if the syntax, grammar or tence are not perfect...

Marc


Title: Re: CWindow RC 23
Post by: José Roca on October 11, 2016, 04:57:29 PM
I appreciate any comments and suggestions, but while trading some speed for ease of use is acceptable or even convenient in many cases, in others not.

For example, in a procedure that must return a result, it is usually faster to pass a variable by reference to get the result that returning it as the result of a function. If we have to return an small string, then it doesn't matter, but if we are using big strings, it does. There was an initial version of the class in which I overloaded the & operator and it slowed string concatenations considerably. This is why I used Paul's string builder code, added several changes like marking the end of the string with a double null to make it compatible with the FB intrinsic string functions and removed the operators except += and &=. Overloading the & operator is an speed killer. Also, as you have pointed, it is not mandatory to add it to the class. You can add it anywere in your code.

VB6 was a beginner's tool in which ease of use took precedence over efficiency. This is why they got the slower compiler ever made. It has spoiled generations of programmers.

Title: Re: CWindow RC 23
Post by: José Roca on October 11, 2016, 05:19:28 PM
BTW I have implemented a new class, CWstrArray, to work with arrays of CWSTRs. Internally, it uses BSTRs because the safe array APIs work with this type of string, but the in and out parameters are CWSTRs. I have used low-level techniques to avoid copying data as much as possible: for example, when inserting or removing array elements, I don't copy the string data to expand or shrink the array, but I only move the BSTRs pointers.


' ========================================================================================
' * Deletes the specified element of the array.
' - nPos = Index of the array element to be removed.
' Return value: TRUE or FALSE.
' ========================================================================================
PRIVATE FUNCTION CWstrArray.DeleteItem (BYVAL nPos AS LONG) AS BOOLEAN
   CWSTRARRAY_DP("CWstrArray DeleteItem")
   DIM cElem AS LONG = nPos - this.LBound
   IF nPos < this.LBound OR nPos > this.UBound THEN RETURN FALSE
   DIM cElements AS LONG = this.UBound - this.LBound + 1
   DIM pvData AS AFX_BSTR PTR = this.AccessData
   IF pvData THEN
      ' // Save the element to be deleted
      DIM pTemp AS AFX_BSTR = pvData[cElem]
      ' // Move all the elements up
      FOR i AS LONG = cElem TO cElements - 1 STEP 1
         pvData[i] = pvData[i + 1]
      NEXT
      ' // Copy the element to be deleted to the end of the array
      pvData[cElements - 1] = pTemp
   END IF
   this.UnaccessData
   ' // Shrink the array by one element (will free the last element)
   IF this.Redim(cElements - 1) = S_OK THEN RETURN TRUE
END FUNCTION
' ========================================================================================


This makes a BIG difference regarding speed.

I also use direct access to get and set the string data instead of the slower SafeArrayGetElement / SafeArrayPutElement API functions.


' ========================================================================================
' * Gets an element of the array. If the function fails, it returns an empty string.
' - idx : The index of the array element.
' ========================================================================================
PRIVATE PROPERTY CWstrArray.Item (BYVAL idx AS LONG) AS CWSTR
   CWSTRARRAY_DP("PROPERTY ITEM [GET] - CWSTR")
   IF m_psa = NULL THEN EXIT PROPERTY
   SafeArrayLock(m_psa)
   DIM pvData AS AFX_BSTR PTR = this.PtrOfIndex(idx)
   IF pvData THEN PROPERTY = *pvData
   SafeArrayUnlock(m_psa)
END PROPERTY
' ========================================================================================

' ========================================================================================
' * Puts a string element at a given location in the array.
' - idx : The index of the array element.
' - cws : The string data to store.
' ========================================================================================
PRIVATE PROPERTY CWstrArray.Item (BYVAL idx AS LONG, BYREF cws AS CWSTR)
   CWSTRARRAY_DP("PROPERTY ITEM [PUT] - CWSTR")
   IF m_psa = NULL THEN EXIT PROPERTY
   SafeArrayLock(m_psa)
   DIM pvData AS AFX_BSTR PTR = this.PtrOfIndex(idx)
   IF pvData THEN *pvData = SysAllocString(**cws)
   SafeArrayUnlock(m_psa)
END PROPERTY
' ========================================================================================


This makes the internal code of many of my wrappers to look not very "BASIC", as James has pointed, but it is efficient.

Title: Re: CWindow RC 23
Post by: José Roca on October 11, 2016, 09:56:19 PM
>  I'm just saying "&" could work also and for me the more important word is : also

I kown what you mean, but this is like putting a red button with a label saying "don't push me"... If it must not be pushed, why you put it?

If they use & and it compiles, they will always use & and then complain that it is slow. If it does not compile, they will learn that have to use + or **.
Title: Re: CWindow RC 23
Post by: Marc Pons on October 22, 2016, 04:11:19 PM
I have done some modifications on the CWSTR.inc, i posted here because its some continuation of previous posts.

You can see it on the attached file with a test to verify and possibly compare with the existing one

the changes have affected different topics / behaviour: ( i've tried to mimic the string behaviour as much as possible)
the idea is if you know how to use string in specific situation it is the same with cwstr class!

@cwstr           : now gives the pointer of the cwstr var                      ( as cwstr ptr  )
varptr(cwstr)   : same as above                                             
strptr(cwstr)   : working and give the pointer to the internal buffer       ( as wstring ptr)
*cwstr         : dereference the internal pointer to wstring               ( byref as wstring)

new & operator to concatenate cwstr with wstring (both sides) or other cwstr  without **cwstr ( or any work-arround)

no more need to **cwstr ( or any work-arround) to use right and left functions they have been overloaded with new ones

and to finish : a bit faster at construction,  let operations and concatenation too

measured : 15 to 25 % faster, by optimization of operations (allocating only once when possible, avoiding intial alloc... )
and few tweeks more.

to test use the cwstr2.inc on the same folder as the test file and compile with console, you can trace the actions directly on the console.
remarks/comments appreciated as usual


Marc
Title: Re: CWindow RC 23
Post by: José Roca on October 22, 2016, 08:43:03 PM
I don't agree in removing the operator @ and changing the operator *. Besides breaking all my code and Paul's code, I think that you don't have understood why I have implemented it this way.

The purpose of the @ and * operators is to allow to pass a CWSTR to the Windows API functions that expect a WSTRING by reference. Whitout them, the compiler will pass a pointer to the CWSTR class instead of the underlying WSTRING and it will crash.

For example, in a function like this one


' ========================================================================================
' Gets the text of a window. This function can also be used to retrieve the text of buttons,
' and edit and static controls.
' Remarks: The function uses the WM_GETTEXT message because GetWindowText cannot retrieve
' the text of a window in another application.
' Example: DIM cws AS CWSTR = AfxGetWindowText(hwnd)
' ========================================================================================
PRIVATE FUNCTION AfxGetWindowText (BYVAL hwnd AS HWND) AS CWSTR
   DIM nLen AS LONG = SendMessageW(hwnd, WM_GETTEXTLENGTH, 0, 0)
   DIM cwsText AS CWSTR = SPACE(nLen + 1)
   SendMessageW(hwnd, WM_GETTEXT, nLen + 1, cast(LPARAM, *cwsText))
   RETURN cwsText
END FUNCTION
' ========================================================================================


I can use cast(LPARAM, *cwsText) or cast(LPARAM, @cwsText), but with your suggested changes, I will have to use cast(LPARAM, cwsText.m_pBuffer).

In an earlier version of CBSTR, I used an "Addr" method instead of "**", and the only user that gave his opinion was Paul, that liked more to use **cws than cws.Addr.

It is nice to use *cws instead of **cws, but it is not so nice to use cws.m_pBuffer (or cws.Addr) instead of @cws.

To work seamless with the intrinsic FB functions the only solution is to have a dynamic unicode data  type implemented in the compiler natively.
Title: Re: CWindow RC 23
Post by: José Roca on October 22, 2016, 09:02:14 PM
Regarding Right and Left, I didn't know that I could overload these intrinsic functions. I can add these functions to CWSTR:


PRIVATE FUNCTION RIGHT (BYREF cws AS CWSTR, BYREF n AS LONG) AS CWSTR
   RETURN RIGHT(**cws, n)
END FUNCTION

PRIVATE FUNCTION LEFT (BYREF cws AS CWSTR, BYREF n AS LONG) AS CWSTR
   RETURN LEFT(**cws, n)
END FUNCTION


I can also add:


PRIVATE FUNCTION VAL (BYREF cws AS CWSTR) AS DOUBLE
   RETURN VAL(**cws)
END FUNCTION


But, of course, using RIGHT(**cws) is faster than RIGHT(cws).
Title: Re: CWindow RC 23
Post by: José Roca on October 22, 2016, 11:08:34 PM
I don't understand the purpose of this function.


' ========================================================================================
' Write the number of bytes from the specified memory address to the buffer.     **** new function
' ========================================================================================
PRIVATE SUB CWstr.WriteBuffer (BYVAL addrMemory AS ANY PTR, BYVAL nNumBytes AS LONG)
   if nNumBytes < m_GrowSize /2  THEN nNumBytes += m_GrowSize/2
CWSTR_DP("CWSTR WriteBuffer " & WSTR(nNumBytes))
this.ResizeBuffer( nNumBytes * 2)
   memcpy(m_pBuffer , addrMemory, nNumBytes)
   m_BufferLen = nNumBytes
   ' Mark the end of the string with a double null
   m_pBuffer[m_BufferLen] = 0
   m_pBuffer[m_BufferLen + 1] = 0
   CWSTR_DP("--END - CWSTR WriteBuffer " & WSTR(m_BufferLen))
END SUB
' ========================================================================================


If I use


DIM wsz AS STRING = "abc"
DIM cws AS CWSTR = wsz
PRINT LEN(cws)


It returns a length of 123 instead of 3.
Title: Re: CWindow RC 23
Post by: Marc Pons on October 23, 2016, 06:53:56 AM
for the WriteBuffer function, my mistake the function should be: (thanks to point that mistake)
PRIVATE SUB CWstr.WriteBuffer (BYVAL addrMemory AS ANY PTR, BYVAL nNumBytes AS LONG)
   m_BufferLen = nNumBytes  '****  assign m_BufferLen before modifying nNumBytes
   if nNumBytes < m_GrowSize /2  THEN nNumBytes += m_GrowSize/2
   CWSTR_DP("CWSTR WriteBuffer " & WSTR(nNumBytes))
   this.ResizeBuffer( nNumBytes * 2)
   memcpy(m_pBuffer , addrMemory, nNumBytes)
   ' Mark the end of the string with a double null
   m_pBuffer[m_BufferLen] = 0
   m_pBuffer[m_BufferLen + 1] = 0
   CWSTR_DP("--END - CWSTR WriteBuffer " & WSTR(m_BufferLen))
END SUB


Overloaded functions right, left : of course you can overload them , they are already overloaded
not tested if your proposals are faster than mines but why not.

sure val function can also be overloaded.

the @cwstr   and *cwstr  your proposal  gives same result    a pointer to the buffer (AS WSTRING PTR)

QuoteI can use cast(LPARAM, *cwsText) or cast(LPARAM, @cwsText), but with your suggested changes, I will have to use cast(LPARAM, cwsText.m_pBuffer).
my proposal, you missed, it is : strptr(cwstr)    giving the  pointer to the buffer (AS WSTRING PTR)
similar way as used with normal string to get the pointer to data  ( as zstring ptr)
that's why i've undef the strptr macro and i've recreated them as functions

so the use for window api is like:
PRIVATE FUNCTION AfxGetWindowText (BYVAL hwnd AS HWND) AS CWSTR
   DIM nLen AS LONG = SendMessageW(hwnd, WM_GETTEXTLENGTH, 0, 0)
   DIM cwsText AS CWSTR = SPACE(nLen + 1)
   SendMessageW(hwnd, WM_GETTEXT, nLen + 1, cast(LPARAM, strptr(cwsText)))  ' **** notice the use of strptr as with string
   RETURN cwsText
END FUNCTION


i aggree strptr is longer than @ or * but it is more "conventionnal" to not mix the use of @ and *
normally : @ is the operator to get the pointer to the var and * is the operator to get the value pointed by the pointer ( or by extension as in string the value of data pointer)

I'm not saying it has to be like that, i'm just holding some time, and review the work done to verify if it is still coherent with the other existing behaviour.
I think, the exeptions (even for good reason) are the way for complexity and at the end for errors.
And taking the opportunity also, to review if some optimization could be found ( speed for me is crucial, i can trade in some extend with the  "simplicity" but not too much)

I understand completly the behaviours are different and can have impacts on the other part of your framework...

but as your framework is not totally freezed...

No comments for & and for speed ?
Title: Re: CWindow RC 23
Post by: Marc Pons on October 23, 2016, 08:13:56 AM
for right noticed a mistake on the logic in my proposal
corrected here

PRIVATE FUNCTION RIGHT( BYREF cwstr AS CWSTR, BYREF n AS LONG )AS CWSTR
CWSTR_DP("CWSTR -RIGHT FUNCTION-")
FUNCTION = cast(wstring ptr, cwstr.m_pBuffer + cwstr.m_BufferLen - (n * 2))
END FUNCTION


tested your overload proposal right and left : mines (after that correction) are a bit faster

and confirm also with my modified class , the speed has been improved at least 10%  up to 25%

even with the & new operator
Title: Re: CWindow RC 23
Post by: Marc Pons on October 23, 2016, 08:41:11 AM
QuoteBut, of course, using RIGHT(**cws) is faster than RIGHT(cws).
its true with your cwstr.inc  but with cwstr2.inc and with my overload proposal for left/right not true

in fact almost 2 time faster with my solution ( because I do not allocate 2 times...)


stop for today, family lunch now  :)
Title: Re: CWindow RC 23
Post by: José Roca on October 23, 2016, 09:46:23 AM
> the @cwstr   and *cwstr  your proposal  gives same result    a pointer to the buffer (AS WSTRING PTR)

Of course, but it is more intuitive, at least for me, to use @ with out parameters and * with in parameters. VARPTR and STRPTR also return the same value when used with WSTRINGs because there is only one address to return. These data types don't have a descriptor.

> i aggree strptr is longer than @ or * but it is more "conventionnal" to not mix the use of @ and *
normally : @ is the operator to get the pointer to the var and * is the operator to get the value pointed by the pointer ( or by extension as in string the value of data pointer

Not with ZSTRING, WSTRING of fixed length strings. See above.
And CWSTR is also a null terminated string without a descriptor.
Title: Re: CWindow RC 23
Post by: José Roca on October 23, 2016, 10:38:08 AM
> for the WriteBuffer function, my mistake the function should be: (thanks to point that mistake)

I still don't understand why do you do that. You pass numBytes to copy and you end copying 260 additional bytes of garbage?
Title: Re: CWindow RC 23
Post by: José Roca on October 23, 2016, 10:42:02 AM
> tested your overload proposal right and left : mines (after that correction) are a bit faster

I still have to check it. It is unsafe code because there are not checks for bounds. What if I pass a negative value or a value bigger than the buffer?
Title: Re: CWindow RC 23
Post by: Marc Pons on October 23, 2016, 12:46:56 PM
good some new input !

if you feel happy mixing @ and * , no problem for me

but "official" freebasic definition
QuoteOperator @ (Address of) returns the memory address of its operand
Operator * (Value of) returns a reference to the value stored at an address, and is often called the dereference operator
you can choose to overload to what you want, but at the end , it is more complexity

QuoteVARPTR and STRPTR also return the same value when used with WSTRINGs
true but both are dedicated to return a pointer not a value as * is supposed to
and with my proposal varptr and strptr give their respective true pointer( one to cwstr ptr, and other to wstring ptr (casted)

QuoteAnd CWSTR is also a null terminated string without a descriptor.
:o, for me CWSTR class is not really different than dynamic String, lets compare the structure elements
data as zstring ptr  for string          :         m_pBuffer    AS UBYTE PTR      for cwstr
len   as long          for string           :        m_BufferLen AS LONG              for cwstr
size  as long          for string          :         m_Capacity  AS LONG              for cwstr

data in the string type is obviously a null terminated string, so i do not see structure difference

again thanks to point the second mistakes on CWstr.WriteBuffer, i've replied to fast
the reason of that function is only: to not have all the cases done on the CWstr.AppendBuffer (avoiding initial setting for nothing)
and if the length is small enougth to increase it a bit to not have to resize after but not fully needed

last proposal
PRIVATE SUB CWstr.WriteBuffer (BYVAL addrMemory AS ANY PTR, BYVAL nNumBytes AS LONG)
   m_BufferLen = nNumBytes  '****  assign m_BufferLen before modifying nNumBytes
   ' the idea here is to have at least some buffer reserve to not have always to resize if append after
   if nNumBytes < m_GrowSize /2  THEN nNumBytes += m_GrowSize/2  ' can be avoided probably
   CWSTR_DP("CWSTR WriteBuffer " & WSTR(nNumBytes))
   this.ResizeBuffer( nNumBytes * 2)
   memcpy(m_pBuffer , addrMemory, m_BufferLen) ' nNumBytes '**** sure not needed to copy garbage thanks Jose
   ' Mark the end of the string with a double null
   m_pBuffer[m_BufferLen] = 0
   m_pBuffer[m_BufferLen + 1] = 0
   CWSTR_DP("--END - CWSTR WriteBuffer " & WSTR(m_BufferLen))
END SUB


and obviouly the right and left have  been secured
'New overload function right for cwstr
PRIVATE FUNCTION RIGHT( BYREF cwstr AS CWSTR, BYREF n AS LONG )AS CWSTR
CWSTR_DP("CWSTR -RIGHT FUNCTION-")
if cwstr.m_BufferLen = 0 or n <= 0 THEN
'RETURN ""
FUNCTION = "" '**** probably faster with return
elseif n > cwstr.m_BufferLen THEN
'RETURN CAST(WSTRING PTR, cwstr.m_pBuffer)
FUNCTION = cast(wstring ptr, cwstr.m_pBuffer)'**** probably faster with return
        else
'RETURN CAST(WSTRING PTR, cwstr.m_pBuffer + cwstr.m_BufferLen - (n * 2))
FUNCTION = cast(wstring ptr, cwstr.m_pBuffer + cwstr.m_BufferLen - (n * 2))'**** probably faster with return
END IF
END FUNCTION

'New overload function left for cwstr
PRIVATE FUNCTION LEFT( BYREF cwstr AS CWSTR, BYREF n AS LONG )AS CWSTR
CWSTR_DP("CWSTR -LEFT FUNCTION-")
IF cwstr.m_BufferLen = 0 or n <= 0 THEN
FUNCTION = ""
EXIT FUNCTION
ELSEIF  n > cwstr.m_BufferLen THEN
FUNCTION = CAST(WSTRING PTR, cwstr.m_pBuffer)
EXIT FUNCTION
END IF
DIM pNewBuffer AS WSTRING PTR = cast(WSTRING PTR , cwstr.m_pBuffer)
dim as ubyte u1, u2
u1 = cwstr.m_pBuffer[(n * 2)]
u2 = cwstr.m_pBuffer[(n * 2) + 1]
pNewBuffer[n] = 0
FUNCTION = pNewBuffer
cwstr.m_pBuffer[(n * 2)] = u1
cwstr.m_pBuffer[(n * 2) + 1] = u2
END FUNCTION 


all in the attachment : CWSTR2.inc and test extended

About speed, do you agree, in fact it is the most important thing
Title: Re: CWindow RC 23
Post by: José Roca on October 23, 2016, 05:27:16 PM
> for me CWSTR class is not really different than dynamic String, lets compare the structure elements

The difference if that the intrinsic functions of the FB compiler can access the members of the FB string structure through the string descriptor. With m_pBuffer alone, you don't have access to the other variables of the class.

My use of @ and * is consistent with other data types such CBSTR and CSafeArray. These data types need an operator to return the address of the variable that holds the pointer and another operator to return the pointer. Using a system with CWSTR and another with CBSTR and CSafeAray is inconsistent. Both BSTR and SafeArray have descriptors.

> About speed, do you agree, in fact it is the most important thing

The faster way is to use + or **

Anyway, the speed in LEFT, RIGHT is not very important because they are used sparely and usually to return small strings.

Title: Re: CWindow RC 23
Post by: Marc Pons on October 24, 2016, 07:55:32 AM
Jose ,

I'm speaking about speed of CWSTR class, globally , construction , let ...

I will send a meesage directly


I also noticed here as you before, event the CWSTR is a core element, because it gives the dynamic unicode string type,
only 2 people give it some attention!

:-\
Title: Re: CWindow RC 23
Post by: José Roca on October 25, 2016, 06:17:16 PM
Regarding the & operator, I have noticed the following

This works without having to use **cwsText


DIM cws AS CWSTR
DIM cwsText AS CWSTR = "test string"
cws = "Line " & 1 & ", Column " & 2 & ": " & cwsText
print cws


This also works


DIM cws AS CWSTR
DIM cwsText AS CWSTR = "test string"
cws = "Line " & STR(1) & ", Column " &  STR(2) & ": " & cwsText
print cws


This fails unless we use **cwsText


DIM cws AS CWSTR
DIM cwsText AS CWSTR = "test string"
cws = "Line " & WSTR(1) & ", Column " &  WSTR(2) & ": " & cwsText
print cws


The behavior of this operator is somewhat erratic. The + operator does not give problems.
Title: Re: CWindow RC 23
Post by: Marc Pons on October 27, 2016, 09:26:56 AM
Jose

my last evolution / optimized /simplified , DWSTR class

Renamed to be able to use it with your CWSTR class on same code to compare speed
the reference CWSTR is the one you post on the RC 24 evolution

i put it to simplify on the attached file with my_DWSTR.inc and code to compare
+ 2 screenshots of the results on my old XP machine (tested with 1 000 000 steps)


I've noticed also some "not so clear" points about index for insert , get charcode...
i've modified them in my code, but not traced everything : sorry

Title: Re: CWindow RC 23
Post by: José Roca on October 27, 2016, 02:50:46 PM
I have changed UBYTE to USHORT in the Char properties. Thanks for spotting it.
Title: Re: CWindow RC 23
Post by: José Roca on October 27, 2016, 11:24:44 PM
My use of the @ and * operators in the CWSTR class is in accordance with what other languages such C++ do. For example, the MFC CComBstr class (C++ uses the & operator instead of @): https://msdn.microsoft.com/en-us/library/5s6et3yb.aspx

Quote
CComBSTR::operator &
Returns the address of the BSTR stored in the m_str member

When we do DIM cws AS CWSTR, cws is NOT the string variable, but the class. We can't pass a pointer to cws to an external third party function because that function has no idea of what a CWSTR is. We have to pass a pointer to the null terminated string that is stored in the m_pBuffer member. Therefore, the @ operator returns the address of the stored null terminated variable, not a pointer to the class.

The * operator acts like STRPTR, that is, it returns the m_pBuffer pointer (a pointer to the beginning of the string data).

Using the FB string data type, we can do:


DIM s AS STRING = "Test string"
DIM p AS ZSTRING PTR = STRPTR(s)
PRINT *p


Using CWSTR, we can do:


DIM cws AS CWSTR = "Test string"
DIM p AS WSTRING PTR = *cws
PRINT *p


That is similar to the first one, but using * instead of STRPTR.

But we can also use the ** shortcut:


DIM cws AS CWSTR = "Test string"
PRINT **cws


that does


DIM p AS WSTRING PTR = *cws
PRINT *p


in a single step.

I always have found ANNOYING to have to use VARPTR and STRPTR (too much typing for my taste), and was jealous of C++ programers that can use & and *.

Anyway, with the latest changes you can use LEFT, RIGHT, VAL and & without having to use **cws.

Title: Re: CWindow RC 23
Post by: José Roca on October 27, 2016, 11:51:16 PM
The Capacity allows to preallocate the size of the buffer if you know the size of the result string or even an approximation to avoid multiple allocations.

The CodePage is not useless. Just because you can build a CWSTR concatenating strings with different code pages, doesn't mean that you have to. If you really need the use of a code page, you will have to use a function like AfxUcode, that allows to specify the code page. Free Basic should add an optional code page parameter to STR and WSTR.
Title: Re: CWindow RC 23
Post by: José Roca on October 28, 2016, 12:10:10 AM
These are the results of your test in my computer. As I said, using + or ** with CWSTR is faster than using &, so why not just use +?. The other differences are not significant: just a few milliseconds in a million of concatenations and assignments.
Title: Re: CWindow RC 23
Post by: José Roca on October 28, 2016, 01:01:56 AM
Finally, in your faster & version, if I'm not wrong you're creating memory leaks.

You allocate a buffer


pNewBuffer = allocate((ust1.m_BufferLen + ust2.m_BufferLen + 1) * sizeof(wstring))


and you return a string


RETURN DWSTR(cast(ubyte ptr, pNewBuffer), ust1.m_BufferLen + ust2.m_BufferLen)


constructed using this code


ResizeBuffer(size1)
m_BufferLen = len1
if len1 + 1 > size1 THEN m_BufferLen = size1 - 1
memcpy(m_pBuffer , cast(any ptr, pub), m_BufferLen * 2)
' Mark the end of the string with a double null
m_pBuffer[m_BufferLen] = 0


and pNewBuffer is never freed.

Title: Re: CWindow RC 23
Post by: Marc Pons on October 28, 2016, 06:53:36 AM
sorry Jose you are wrong, pNewBuffer is deallocated by the normal DWSTR destructor

check the code ,used  with the & constructor we dont put  size1 var ;   so  size1 = -1  ; so you  enter in the second condition
as you can see if you add the lines to print "here 1";"here 2";"here 3" on the constuctor
PRIVATE CONSTRUCTOR DWSTR (BYREF pub AS UBYTE PTR, BYREF len1 AS LONG, BYREF size1 AS LONG = -1) '****
   DWSTR_DP("+++BEGIN- DWSTR CONSTRUCTOR UBYTE - " & WSTR(pub))               
IF size1 = 0 THEN
this.ResizeBuffer(m_GrowSize)
print "here 1"
elseif size1 < 0 THEN ' we enter here with  my & operator
this.m_BufferLen = len1
this.m_pBuffer = cast(wstring ptr, pub)
this.m_Capacity = len1 + 1
print "here 2"
ELSE
ResizeBuffer(size1)
m_BufferLen = len1
if len1 + 1 > size1 THEN m_BufferLen = size1 - 1
memcpy(m_pBuffer , cast(any ptr, pub), m_BufferLen * 2)
' Mark the end of the string with a double null
m_pBuffer[m_BufferLen] = 0
print "here 3"
END IF
   DWSTR_DP("-END- DWSTR CONSTRUCTOR UBYTE - " & WSTR(this.m_pBuffer))
END CONSTRUCTOR


that means the pointer is not copied to another mem  , it is just affected to m_pBuffer and when the destructor will act the m_pBuffer ( so in fact the original pNewBuffer) will be deallocated normally

it would be even faster if we could avoid the following LET action wich reallocate again ( for nothing)
i've tried to avoid the LET after but it is too complex for the benefit...

see on your nice debug trace system
QuoteOPERATOR & DWSTR :  WSTRING & DWSTR
+++BEGIN- DWSTR CONSTRUCTOR UBYTE - 3361376
here 2
-END- DWSTR CONSTRUCTOR UBYTE - 3361376
DWSTR LET DWSTR
DWSTR Clear
DWSTR Add DWSTR - LEN = 26
DWSTR AppendBuffer 0 26
--END - DWSTR AppendBuffer 26
***DWSTR DESTRUCTOR - buffer: 3361376

DWSTR &  new operator : same or faster than de-referenced solution
DWSTR CAST BYREF AS WSTRING - buffer: 3359768
Title: Re: CWindow RC 23
Post by: Marc Pons on October 28, 2016, 08:08:18 AM
completing the analyse :
QuoteUsing the FB string data type, we can do:
   DIM s AS STRING = "Test string"
   DIM p AS ZSTRING PTR = STRPTR(s)
   PRINT *p

Using CWSTR, we can do:
   DIM cws AS CWSTR = "Test string"
   DIM p AS WSTRING PTR = *cws
   PRINT *p

Using DWSTR, we can do:
   DIM dws AS DWSTR = "Test string"
   DIM pw AS WSTRING PTR = STRPTR(dws)
   PRINT *pw

                  That is exactly as the first one

we can also use the ** shortcut:
   DIM cws AS CWSTR = "Test string"
   PRINT **cws 'explicit double dereferenced
   ' or better  PRINT cws     ' because the implicit cast : byref to wstring

let's see with DWSTR
   DIM dws AS DWSTR = "Test string"
   PRINT *dws     'explicit dereferenced       noticed only 1 dereferecing
   'or better  PRINT dws  'same implicit cast: byref to wstring

that does for CWSTR
   DIM p AS WSTRING PTR = *cws
   PRINT *p

with normal string
   DIM ps AS ZSTRING PTR = strptr(s)
   PRINT *ps

and for DWSTR
   DIM pdw AS WSTRING PTR = strptr(dws)   ' a agree  strptr is longuer to type than * 
   PRINT *pdw

        but with DWSTR : 
           STRPTR working as with normal string to get the WSTRING ptr
           VARPTR working as with normal string to get the DWSTR ptr, or even just : @DWSTR 

2 different approchs
     CWSTR more c++  behaviour , coherent with all your framework and their types construction
     DWSTR a dynamic WSTRING  with almost "native"  BASIC type behaviour

my purpose from the begining : to have a dynamic Wstring and use it as we do with normal string, without speed cost (or very marginal)
Title: Re: CWindow RC 23
Post by: Marc Pons on October 28, 2016, 08:30:14 AM
QuoteThe CodePage is not useless. Just because you can build a CWSTR concatenating strings with different code pages, doesn't mean that you have to.
If you really need the use of a code page, you will have to use a function like AfxUcode, that allows to specify the code page. Free Basic should add an optional code page parameter to STR and WSTR.

m_codePage on CWSTR type :
why is it needed to store it, as the resulting CWSTR can be a mix with possible different codepage ?
what the benefit for CWSTR , or for the output to convert it back if it could be completly wrong ?

AfxUcode is very good function , i've tried to overload the wstr with it but without sucess

in the reverse , converting CWSTR to ansi, the only way i can considere
    is defining explicitly the codepage if you want a specific one,
    or use the normal system codepage
so what the need for storing the codepage information into CWSTR, if we can't trust that info ,
and in fact it is not even needed , your afxAcode (if correct) is playing perfectly the role

Title: Re: CWindow RC 23
Post by: José Roca on October 28, 2016, 04:17:24 PM
I think that it is evident: it is used by the Add and Insert functions if you pass an ansi string and don't specify a code page when you call them. Which benefit will you have removing it?
Title: Re: CWindow RC 23
Post by: José Roca on October 28, 2016, 04:32:24 PM
> my purpose from the begining : to have a dynamic Wstring and use it as we do with normal string

I almost never use what you call a "normal" string, which is everything but normal, because its format is proprietary. The only use that I have for it is as a buffer for binary content if I don't want to allocate the memory using Allocate.

I ill see what I can do with the & operator.
Title: Re: CWindow RC 23
Post by: José Roca on October 28, 2016, 04:48:33 PM
You seem only interested in CWSTR, but I'm also interested in CBSTR, and what you suggest for CWSTR can't be applied to CBSTR, and I like consistency. If I have removed it from the posted framework is only because nobody is willing to test, so I will keep my research about COM programming with FB private. Doesn't make sense to inundate this forum with new code if only I use it.
Title: Re: CWindow RC 23
Post by: José Roca on October 29, 2016, 02:31:22 AM
> it would be even faster if we could avoid the following LET action wich reallocate again ( for nothing)
i've tried to avoid the LET after but it is too complex for the benefit...

It does not reallocate. It is called to assign the result to the CWSTR in "cws =". The problem with functions that return strings is that they must be copied to the target variable. The fastest way is to pass a variable by reference, as most Windows API functions do, but it is much less comfortable to use.

Title: Re: CWindow RC 23
Post by: Marc Pons on November 12, 2016, 01:42:23 PM
Jose,

just to let you know, my DWSTR , is posted on the FreeBasic Forum
http://www.freebasic.net/forum/viewtopic.php?f=17&t=24070&start=15#p226207 (http://www.freebasic.net/forum/viewtopic.php?f=17&t=24070&start=15#p226207)

intended to work with Windows & Linux

Thanks for all your support, I will see if some interrest on the subject.

Marc