First COM attempt: IFileOpenDialog

Started by José Roca, April 06, 2016, 02:13:57 PM

Previous topic - Next topic

James Fuller

Quote from: Jose Roca on July 17, 2016, 05:31:22 PM
What makes you think that it is for Windows 8? I'm using Windows 7.
If I change #define _WIN32_WINNT &h0602
To
#define _WIN32_WINNT &h0601
a number of errors.

James

José Roca

Currently, FreeBasic only supports &h0400, &h0502 and &h0602.

James Fuller

Quote from: Jose Roca on July 17, 2016, 05:48:53 PM
Currently, FreeBasic only supports &h0400, &h0502 and &h0602.

I have no idea what that means?

James

José Roca

#18
Just like the FB headers, that don't have idea of what &h0601 means.

They don't check for _WIN32_WINNT >= &H0601, but, most of the times, they use #if _WIN32_WINNT = &h0602.

Checking the include files, they only use &H0502 (for XP) and &H0602 (for Windows 7 and beyond). It saves them the headache of having to support so many values of the C++ headers.

If you only want to support up to XP, use #define _WIN32_WINNT &h0502, else use #define _WIN32_WINNT &h0602, and forget any other numbers.

Paul Squires

Hi Jose,

I am successfully using your IFileOpenDialog to single and multiple files. Do you code for "open folder" ? That would be awesome :)

Paul Squires
PlanetSquires Software

José Roca

> Do you code for "open folder" ? That would be awesome :)

I'm working in an AfxShell.inc file that will include two browse for folder functions.

José Roca

#21
Browse for folder dialog


' ========================================================================================
' Displays a dialog box that enables the user to select a folder.
' - pwszTitle       = A string value that represents the title displayed inside the Browse dialog box.
' - pwszStartFolder = The initial folder that the dialog will show.
' - nFlags          = Optional. A LONG value that contains the options for the method. This can be a
'                     combination of the values listed under the ulFlags member of the BROWSEINFO structure.
'                     See: http://msdn.microsoft.com/en-us/library/windows/desktop/bb773205%28v=vs.85%29.aspx
'                     Default value = BIF_RETURNONLYFSDIRS OR BIF_DONTGOBELOWDOMAIN OR BIF_USENEWUI OR BIF_RETURNFSANCESTORS
' Note: To display the old style dialog, pass -1 in the dwFlags parameter.
' ========================================================================================
' // Browse for folder dialog procedure
PRIVATE FUNCTION AfxBrowseForFolderProc (BYVAL hwnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT

   DIM wszBuffer AS WSTRING * MAX_PATH

   IF uMsg = BFFM_INITIALIZED THEN
      SendMessageW hwnd, BFFM_SETSELECTIONW, CTRUE, cast(LPARAM, lParam)
   ELSEIF uMsg = BFFM_SELCHANGED THEN
      SHGetPathFromIDListW(cast(ITEMIDLIST PTR, wParam), @wszBuffer)
      IF wParam = 0 OR _ ' // No id number
         LEN(wszBuffer) = 0 OR _ ' // No name
         (GetFileAttributesW(wszBuffer) AND FILE_ATTRIBUTE_DIRECTORY) <> FILE_ATTRIBUTE_DIRECTORY OR _ ' // Not a real directory
         MID(wszBuffer, 2, 1) <> ":" THEN ' // Not a local or mapped drive
            SendMessageW hwnd, BFFM_ENABLEOK, FALSE, FALSE
      ELSEIF ((GetFileAttributesW(wszBuffer) AND FILE_ATTRIBUTE_SYSTEM) = FILE_ATTRIBUTE_SYSTEM) AND _
            RIGHT(wszBuffer, 2) <> ":\" THEN   ' // Exclude system folders, allow root directories
         SendMessageW hwnd, BFFM_ENABLEOK, FALSE, FALSE
      END IF
   END IF
   RETURN 0

END FUNCTION

PRIVATE FUNCTION AfxBrowseForFolder (BYVAL hwnd AS HWND, BYVAL pwszTitle AS WSTRING PTR = NULL, _
   BYVAL pwszStartFolder AS WSTRING PTR = NULL, BYVAL nFlags AS LONG = 0) AS CWSTR

   DIM wszBuffer AS WSTRING * MAX_PATH, bi AS BROWSEINFOW, pidl AS ITEMIDLIST PTR
   IF nFlags = 0 THEN nFlags = BIF_RETURNONLYFSDIRS OR BIF_DONTGOBELOWDOMAIN OR BIF_USENEWUI OR BIF_RETURNFSANCESTORS
   IF nFlags = -1 THEN nFlags = BIF_RETURNONLYFSDIRS OR BIF_DONTGOBELOWDOMAIN OR BIF_RETURNFSANCESTORS

   bi.hWndOwner = hwnd
   bi.lpszTitle = pwszTitle
   bi.ulFlags   = nFlags
   bi.lpfn      = cast(BFFCALLBACK, @AfxBrowseForFolderProc)
   bi.lParam    = cast(LPARAM, pwszStartFolder)
   pidl         = SHBrowseForFolderW(@bi)

   IF pidl THEN
      SHGetPathFromIDListW(pidl, @wszBuffer)
      CoTaskMemFree pidl
   END IF
   RETURN wszBuffer

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


José Roca

#22
Added a cast to

bi.lpfn = cast(BFFCALLBACK, @AfxBrowseForFolderProc)

otherwise, the 64 bit compiler complains.

José Roca

COM version using the Shell interfaces. Remember to call CoInitialize NULL at the very beginning of your application and CoUninitialize at the end.


' ========================================================================================
' Displays a dialog box that enables the user to select a Shell folder.
' Paramaters:
' - hwnd       = The handle to the parent window of the dialog box. This value can be zero.
' - pwszTitle  = A string value that represents the title displayed inside the Browse dialog box.
' - Options    = Optional. A LONG value that contains the options for the method. This can be zero or a
'                combination of the values listed under the ulFlags member of the BROWSEINFO structure.
'                See: http://msdn.microsoft.com/en-us/library/windows/desktop/bb773205%28v=vs.85%29.aspx
' - RootFolder = Optional. The root folder to use in the dialog box. The user cannot browse
'                higher in the tree than this folder. If this value is not specified, the
'                root folder used in the dialog box is the desktop. This value can be a
'                string that specifies the path of the folder or one of the
'                ShellSpecialFolderConstants values.
'                See: http://msdn.microsoft.com/en-us/library/windows/desktop/bb774096%28v=vs.85%29.aspx
' Return Value:
'   The path of the selected folder or an empty string if the dialog has been canceled.
' ========================================================================================
PRIVATE FUNCTION AfxShellBrowseForFolder OVERLOAD (BYVAL hwnd AS HWND, BYVAL pwszTitle AS WSTRING PTR, _
   BYVAL Options AS LONG = 0, BYVAL pwszRootFolder AS WSTRING PTR = NULL) AS CBSTR

   DIM cbs AS CBSTR

   ' // Create an instance of the IShellDispatch interface
   DIM pShell AS IShellDispatch PTR
   CoCreateInstance(@CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, @IID_IShellDispatch, @pShell)
   IF pShell = NULL THEN RETURN cbs

   '// Call BrowseForFolder and get a reference to the Folder2 interface
   DIM pFolder2 AS Folder2 PTR
   DIM bstrTitle AS BSTR = SysAllocString(pwszTitle)
   DIM vRootFolder AS VARIANT
   V_VT(@vRootFolder) = VT_BSTR
   V_BSTR(@vRootFolder) = SysAllocString(pwszRootFolder)
   pShell->lpvtbl->BrowseForFolder(pShell, cast(LONG_PTR, hwnd), bstrTitle, Options, vRootFolder, cast(Folder PTR PTR, @pFolder2))
   SysFreeString bstrTitle
   VariantClear @vRootFolder
   IF pFolder2 = NULL THEN
      IUnknown_Release(pShell)
      RETURN cbs
   END IF

   ' // Get a reference tp the FolderItem interface
   DIM pItem AS FolderItem PTR
   pFolder2->lpvtbl->get_Self(pFolder2, @pItem)
   IF pItem THEN pItem->lpvtbl->get_Path(pItem, @cbs)

   ' // Cleanup
   IF pShell THEN IUnknown_Release(pShell)
   IF pFolder2 THEN IUnknown_Release(pFolder2)
   IF pItem THEN IUnknown_Release(pItem)

   RETURN cbs

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

' ========================================================================================
' Same as above but accepting a shell special folder constant.
' See https://msdn.microsoft.com/en-us/library/windows/desktop/bb774096(v=vs.85).aspx
' for a list of the constants.
' ========================================================================================
PRIVATE FUNCTION AfxShellBrowseForFolder OVERLOAD (BYVAL hwnd AS HWND, BYVAL pwszTitle AS WSTRING PTR, _
   BYVAL Options AS LONG = 0, BYVAL RootFolder AS LONG = 0) AS CBSTR

   DIM cbs AS CBSTR

   ' // Create an instance of the IShellDispatch interface
   DIM pShell AS IShellDispatch PTR
   CoCreateInstance(@CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, @IID_IShellDispatch, @pShell)
   IF pShell = NULL THEN RETURN cbs

   '// Call BrowseForFolder and get a reference to the Folder2 interface
   DIM pFolder2 AS Folder2 PTR
   DIM vRootFolder AS VARIANT
   V_VT(@vRootFolder) = VT_I4
   V_I4(@vRootFolder) = RootFolder
   pShell->lpvtbl->BrowseForFolder(pShell, cast(LONG_PTR, hwnd), pwszTitle, Options, vRootFolder, cast(Folder PTR PTR, @pFolder2))
   VariantClear @vRootFolder
   IF pFolder2 = NULL THEN
      IUnknown_Release(pShell)
      RETURN cbs
   END IF

   ' // Get a reference tp the FolderItem interface
   DIM pItem AS FolderItem PTR
   pFolder2->lpvtbl->get_Self(pFolder2, @pItem)
   IF pItem THEN pItem->lpvtbl->get_Path(pItem, @cbs)

   ' // Cleanup
   IF pShell THEN IUnknown_Release(pShell)
   IF pFolder2 THEN IUnknown_Release(pFolder2)
   IF pItem THEN IUnknown_Release(pItem)

   RETURN cbs

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


Paul Squires

Hi Jose, please take a look at the attached screenshot. It says that it is an Open Folder dialog but I wonder is it really just a Open File dialog with some parameters changed? What do you think?
Paul Squires
PlanetSquires Software

José Roca

It is a customized instance of Explorer. I posted an example of embedding it into a Tab control. I have yet to explore the events interfaces of this control.


' ########################################################################################
' Microsoft Windows
' File: CW_ExplorerBrowser.fbtpl
' Contents: Resizable CWindow with an Explorer Browser control embedded in a tab page.
' 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
#define _WIN32_WINNT &h0602
#INCLUDE ONCE "Afx/CWindow.inc"
#INCLUDE ONCE "Afx/AfxCtl.inc"
#INCLUDE ONCE "win/shlobj.bi"
USING Afx
' $FB_RESPATH = "FBRES.rc"

' // Main window user data zero-based indices
ENUM AFX_USERDATA
   AFX_EXPLORER_BROWSER_PTR = 0
END ENUM

' // Control identifiers
ENUM
   IDC_TAB = 1001
   IDC_BTNSUBMIT
   IDC_LISTBOX
   IDC_SELECTION
END ENUM

' // Forward declarations
DECLARE FUNCTION WndProc (BYVAL hwnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT
DECLARE FUNCTION TabPage1_WndProc(BYVAL hwnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT
DECLARE FUNCTION TabPage2_WndProc(BYVAL hwnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT

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)

' ========================================================================================
' 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
   AfxSetProcessDPIAware

   ' // Initialize the COM library
   OleInitialize(NULL)

   ' // Create the main window
   DIM pWindow AS CWindow
   pWindow.Create(NULL, "CWindow: Explorer Browser in a Tab Control", @WndProc)
   pWindow.SetClientSize(550, 370)
   pWindow.Center

   ' // Add a tab control
   DIM hTab AS HWND = pWindow.AddControl("Tab", , IDC_TAB, "", 10, 10, pWindow.ClientWidth - 20, pWindow.ClientHeight - 42)

   ' // Create the first tab page
   DIM pTabPage1 AS CTabPage PTR = NEW CTabPage
   pTabPage1->InsertPage(hTab, 0, "Explorer Browser", -1, @TabPage1_WndProc)
   ' // Create the second tab page
   DIM pTabPage2 AS CTabPage PTR = NEW CTabPage
   pTabPage2->InsertPage(hTab, 1, "Selected Items", -1, @TabPage2_WndProc)

   ' // Add buttons
   pWindow.AddControl("Button", , IDC_SELECTION, "&Selection")
   pWindow.AddControl("Button", , IDCANCEL, "&Close")

   ' // Display the first tab page
   ShowWindow pTabPage1->hTabPage, SW_SHOW
   ' // Set the focus to the first tab
   SendMessageW hTab, TCM_SETCURFOCUS, 0, 0

   

   ' // Dispatch messages
   FUNCTION = pWindow.DoEvents(nCmdShow)

   ' // Uninitialize the COM library
   CoUninitialize

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

' ========================================================================================
' Main window callback 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)
            ' // If ESC key pressed, close the application sending an WM_CLOSE message
            CASE IDCANCEL
               IF HIWORD(wParam) = BN_CLICKED THEN
                  SendMessageW hwnd, WM_CLOSE, 0, 0
                  EXIT FUNCTION
               END IF
            CASE IDC_SELECTION
               IF HIWORD(wParam) = BN_CLICKED THEN
                  ' // Get a reference to the 2nd tab page
                  DIM pTabPage AS CTabPage PTR = AfxCTabPagePtr(GetDlgItem(hwnd, IDC_TAB), 1)
                  ' // Get the handle of the listbox control
                  DIM hListBox AS HWND = GetDlgItem(pTabPage->hTabPage, IDC_LISTBOX)
                  ' // Get the number of items in the listbox
                  DIM nItems AS LONG = ListBox_GetCount(hListBox)
                  ' // Delete all items
                  DIM i AS LONG
                  FOR i = 0 TO nItems - 1
                     ListBox_DeleteString(hListBox, 0)
                  NEXT
                  ' // Get a reference to the CWindow class
                  DIM pWindow AS CWindow PTR = AfxCWindowPtr(hwnd)
                  IF pWindow = NULL THEN EXIT FUNCTION
                  ' // Get the pointer to IExplorerBrowser previously stored in the user data
                  DIM peb AS IExplorerBrowser PTR = cast(IExplorerBrowser PTR, pWindow->UserData(AFX_EXPLORER_BROWSER_PTR))
                  IF peb = NULL THEN EXIT FUNCTION
                  ' // Get a reference to the IShellView interface for the current view
                  DIM psv AS IShellView PTR
                  DIM hr AS HRESULT = peb->lpvtbl->GetCurrentView(peb, @IID_IShellView, @psv)
                  IF psv THEN
                     ' // Get a reference to the IDataObject interface
                     DIM pDataObject AS IDataObject PTR
                     psv->lpvtbl->GetItemObject(psv, SVGIO_SELECTION, @IID_IDataObject, @pDataObject)
                     If pDataObject = NULL THEN MessageBox hwnd, "No files selected", "", MB_OK
                     IF pDataObject THEN
                        ' // Get filenames from the clipboard
                        DIM fmt AS FORMATETC = (CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL)
                        DIM stg AS STGMEDIUM
                        stg.tymed = TYMED_HGLOBAL
                        IF SUCCEEDED(pDataObject->lpvtbl->GetData(pDataObject, @fmt, @stg)) THEN
                           ' // Lock the global memory handle
                           DIM hDrop AS HDROP = GlobalLock(stg.hGlobal)
                           ' // Get the number of selected files
                           DIM uNumFiles AS UINT = DragQueryFile(hDrop, &hFFFFFFFF, NULL, 0)
                           DIM hr AS HRESULT, i AS LONG
                           DIM wszPath AS WSTRING * MAX_PATH
                           FOR i = 0 TO uNumFiles - 1
                              wszPath = ""
                              ' // Get the path of the file
                              DragQueryFile(hDrop, i, @wszPath, MAX_PATH)
                              ' // Add it to the listbox
                              ListBox_AddString(hListbox, @wszPath)
                           NEXT
                           ' // Unlock the global memry handle
                           GlobalUnlock(stg.hGlobal)
                           ' // Release the STGMEDIUM structure
                           ReleaseStgMedium(@stg)
                           ' // Set the focus in the Items tab
                           DIM hTab AS HWND = GetDlgItem(hwnd, IDC_TAB)
                           TabCtrl_SetCurFocus(hTab, 1)
                           ' // Set the focus in the first item of the listbox
                           ListBox_SetCursel(hListBox, 0)
                        END IF
                        ' // Release the IDataObject interface
                        pDataObject->lpVtbl->Release(pDataObject)
                     END IF
                  END IF
                  ' // Release the IShellView interface
                  IF psv THEN psv->lpVtbl->Release(psv)
                  EXIT FUNCTION
               END IF
         END SELECT

      CASE WM_GETMINMAXINFO
         ' Set the pointer to the address of the MINMAXINFO structure
         DIM ptmmi AS MINMAXINFO PTR = CAST(MINMAXINFO PTR, lParam)
         ' Set the minimum and maximum sizes that can be produced by dragging the borders of the window
         DIM pWindow AS CWindow PTR = AfxCWindowPtr(hwnd)
         IF pWindow THEN
            ptmmi->ptMinTrackSize.x = 460 * pWindow->rxRatio
            ptmmi->ptMinTrackSize.y = 320 * pWindow->ryRatio
         END IF
         EXIT FUNCTION

      CASE WM_SIZE
         DIM pWindow AS CWindow PTR = AfxCWindowPtr(hwnd)
         DIM hTab AS HWND = GetDlgItem(hwnd, IDC_TAB)
         ' / Move the buttons
         IF pWindow THEN pWindow->MoveWindow GetDlgItem(hwnd, IDC_SELECTION), pWindow->ClientWidth - 172, pWindow->ClientHeight - 28, 75, 23, CTRUE
         IF pWindow THEN pWindow->MoveWindow GetDlgItem(hwnd, IDCANCEL), pWindow->ClientWidth - 86, pWindow->ClientHeight - 28, 75, 23, CTRUE
         ' // Resize the tab control
         IF pWindow THEN pWindow->MoveWindow(hTab, 10, 10, pWindow->ClientWidth - 20, pWindow->ClientHeight - 42, CTRUE)
         ' // Resize the tab pages
         AfxResizeTabPages hTab
         EXIT FUNCTION

      CASE WM_NOTIFY
         DIM nPage AS DWORD              ' // Page number
         DIM pTabPage AS CTabPage PTR    ' // Tab page object reference
         DIM tci AS TCITEMW              ' // TCITEMW structure
         DIM ptnmhdr AS NMHDR PTR   ' // Information about a notification message
         ptnmhdr = CAST(NMHDR PTR, lParam)
         SELECT CASE ptnmhdr->idFrom
            CASE IDC_TAB
               SELECT CASE ptnmhdr->code
                  CASE TCN_SELCHANGE
                     ' // Show the selected page
                     pTabPage = AfxCTabPagePtr(ptnmhdr->hwndFrom, -1)
                     IF pTabPage THEN ShowWindow pTabPage->hTabPage, SW_SHOW
                  CASE TCN_SELCHANGING
                     ' // Hide the current page
                     pTabPage = AfxCTabPagePtr(ptnmhdr->hwndFrom, -1)
                     IF pTabPage THEN ShowWindow pTabPage->hTabPage, SW_HIDE
               END SELECT
         END SELECT

    CASE WM_DESTROY
         ' // Destroy the tab pages
         AfxDestroyAllTabPages(GetDlgItem(hwnd, IDC_TAB))
         ' // Quit the application
         PostQuitMessage(0)
         EXIT FUNCTION

   END SELECT

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

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

' ========================================================================================
' Tab page 1 window procedure
' ========================================================================================
FUNCTION TabPage1_WndProc (BYVAL hwnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT

   STATIC peb AS IExplorerBrowser PTR

   SELECT CASE uMsg

      CASE WM_CREATE
         ' // Get a pointer to the TabPage class
         DIM pTabPage AS CTabPage PTR = AfxCTabPagePtr(GetParent(hwnd), 0)
         ' // Create an instance of IExplorerBrowser
         CoCreateInstance(@CLSID_ExplorerBrowser, NULL, CLSCTX_INPROC_SERVER, @IID_IExplorerBrowser, @peb)
         IF peb = NULL THEN EXIT FUNCTION
         peb->lpVtbl->SetOptions(peb, EBO_SHOWFRAMES)
         DIM fs AS FOLDERSETTINGS
         fs.ViewMode = FVM_DETAILS
         DIM rc AS RECT
         GetClientRect hwnd, @rc
         peb->lpVtbl->Initialize(peb, hwnd, @rc, @fs)
         ' // Navigate to the Profile folder
         DIM pidlBrowse AS LPITEMIDLIST
'         IF SUCCEEDED(SHGetFolderLocation(NULL, CSIDL_PROFILE, NULL, 0, @pidlBrowse)) THEN
'            peb->lpVtbl->BrowseToIDList(peb, pidlBrowse, 0)
'            ILFree(pidlBrowse)
'         END IF
         DIM wszPath AS WSTRING * MAX_PATH
         wszPath = "C:\Users"   ' --> change me
         IF SUCCEEDED(SHParseDisplayName(wszPath, NULL, @pidlBrowse, 0, NULL)) THEN
            peb->lpVtbl->BrowseToIDList(peb, pidlBrowse, 0)
            ILFree(pidlBrowse)
         END IF
         ' // Store the IExplorerBrowser pointer into the user data of the main window
         DIM pWindow AS CWindow PTR = AfxCWindowPtr(GetAncestor(hwnd, GA_ROOTOWNER))
         pWindow->UserData(AFX_EXPLORER_BROWSER_PTR) = cast(LONG_PTR, peb)
         EXIT FUNCTION

      CASE WM_COMMAND
         SELECT CASE LOWORD(wParam)
            CASE IDC_BTNSUBMIT
               IF HIWORD(wParam) = BN_CLICKED THEN
                  MessageBoxW(hWnd, "Submit", "Tab 1", MB_OK)
                  EXIT FUNCTION
               END IF
         END SELECT

      CASE WM_SIZE
         ' // Resize the Explorer control
         DIM rc AS RECT
         GetClientRect hwnd, @rc
         IF peb THEN peb->lpVtbl->SetRect(peb, NULL, rc)
         EXIT FUNCTION

      CASE WM_DESTROY
            ' // Destroy the browser and release the interface
         IF peb THEN
            peb->lpVtbl->Destroy(peb)
            peb->lpVtbl->Release(peb)
         END IF
         EXIT FUNCTION

   END SELECT

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

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

' ========================================================================================
' Tab page 2 window procedure
' ========================================================================================
FUNCTION TabPage2_WndProc (BYVAL hwnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT

   DIM hBrush AS HBRUSH, rc AS RECT, tlb AS LOGBRUSH

   SELECT CASE uMsg

      CASE WM_CREATE
         ' // Get a pointer to the TabPage class
         DIM pTabPage AS CTabPage PTR = AfxCTabPagePtr(GetParent(hwnd), 1)
         ' // Add a combobox to the second page
         DIM hListBox AS HWND = pTabPage->AddControl("ListBox", hwnd, IDC_LISTBOX, "", 20, 20, 485, 270)
         EXIT FUNCTION

   END SELECT

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

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


José Roca

Guess that they will use this control to make different dialogs. Now that VB6 and ActiveX controls are history, they are building COM controls that can be embedded directly into a window without having to use an OLE container. Only the WebBrowser control is still an ActiveX.

You know that I always have disliked these ActiveX controls made for VB6 and the need to use an OLE container and Automation. That Automation stuff was developed by the VB6 team and worked very well with VB6, but it is a nightmare to use with other languages that don't have full Automation support, with all these BSTRs, Variants, safe arrays, etc.

The new COM controls (the first one was the Ribbon control) are no longer ActiveX, they don't need an OLE container and don't use Automation, but low-level COM.

aloberr

you want to say that FreeBasic and the other compilers must be fastened with net technology? 

José Roca

#28
I don't have mentioned .NET for anything. Controls like the Ribbon or this Explorer aren't written with .NET, but using low-level .COM. I dislike .NET even more than ActiveX.

As you can see in the example, I'm embedding Explorer wihout having to use an OLE container and without having to use Automation or .NET.

Apparently, you and Marc want to write ActiveX controls, and I wonder why. It would be better to learn how to do it using low-level COM. I still prefer the classic way of registering a window class and use the control calling SendMessage or functions instead of COM interfaces, and using a callback instead of events.


aloberr

QuoteIt would be better to learn how to do it using low-level COM.
what is it low level COM?  an example ?