SetWindowSubclass

Windows specific questions.
deltarho[1859]
Posts: 4308
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

SetWindowSubclass

Post by deltarho[1859] »

I am trying to get SetWindowSubclass to work but to no avail.

At the PowerBASIC archives there are very few posts using this API and all of them, including me, employ it within WM_INITDIALOG.

However, I am using José Roca's WinFBX where WM_INITDIALOG, being a dialog message, does not pass muster. Since I am extremely ignorant of SDK programming I dropped SetWindowSubclass into WM_CREATE instead. With dialog programming we show the dialog at the last minute so WM_INITDIALOG knows everything about the dialog. What I did not know was that when we create a window in SDK the WndProc kicks in immediately so WM_CREATE is totally ignorant of any controls we add after the window creation. So, WM_CREATE had no idea what I was talking about when I referred to any controls. I cannot use then SetWindowSubclass in WM_CREATE.

I decided to put SetWindowSubclass at the end of WinMain just before DoEvents. SetWindowSubclass is returning TRUE so it is installing correctly and I am getting a GetLastError of zero so all seems well.

I am geting into DragDropProc because I am getting "Yep, I am here" on the first pass. However, DrafDropProc is not getting any WM_DropFiles messages.

I have had a look in the FreeBASIC archives but cannot find anything to help me out; with most folk using it in WM_INITDIALOG.

I have not coded any buttons yet and clicking on them will simply acknowledge the click. At the bottom of DragDropProc are commented statements which have not been rewritten in FreeBASIC yet and have no bearing on the Drag&Drop functionality.

Can anyone help me on this? Once the Drag&Drop is working then I can steam ahead with the idea behind this little app.

There is no point in posting snippets so here is the 'full monty' so far. The code will compile and a window will appear.

Code: Select all

'#Console On
#Define UNICODE

#Define _WIN32_WINNT &h0602
#Include Once "Afx/CWindow.inc"
#Include Once "Afx/CFileSys.inc"
#Include Once "Windows.bi"

Using Afx

Const IDC_FRAME1   = 1001
Const IDC_Encrypt  = 1002
Const IDC_Decrypt  = 1003
Const IDC_TEXTBOX1 = 1005
Const IDC_Execute  = 1007

Dim Shared szFileName() As Zstring * Max_Path
Dim Shared sPassword As String

Type DragDropType
  Title As Zstring * 20
  hHandle As Dword
End Type

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( As HWND, As UINT, As WPARAM, As LPARAM ) As LRESULT
Declare Function DragDropProc( As hwnd, As Uint, As wparam, As lParam, As Uint_ptr, As Dword_Ptr ) As winbool            
Dim Shared As Long xWindow, yWindow
Dim Shared pFileSys As CFileSys

Function WinMain (Byval hInstance As HINSTANCE, _
  Byval hPrevInstance As HINSTANCE, _
  Byval szCmdLine As Zstring Ptr, _
  Byval nCmdShow As Long) As Long
  
  Dim As Long f
  
  ' // Set process DPI aware
  AfxSetProcessDPIAware
  
  Dim pWindow As CWindow
  pWindow.SetFont("Tahoma", 10, FW_NORMAL, , , , DEFAULT_CHARSET)
  pWindow.Create(NULL, "Encryption/Decryption", @WndProc, ,,,, WS_SYSMENU Or WS_CAPTION, WS_EX_TOPMOST)
  pWindow.SetClientSize(334, 220)
  
  ' Open at last position
  Dim hwnd As Hwnd = pWindow.hWindow
  If pFileSys.Fileexists("Position.dat") Then
    f = Freefile
    Open "Position.dat" For Binary As #f
    Get #f, , xWindow
    Get #f, , yWindow
    Close #f
    SetWindowPos( HWnd, HWND_NOTOPMOST, xWindow, yWindow, 0, 0, SWP_NOSIZE )
  Else
    pWindow.Center
  End If
  
  pWindow.AddControl("GroupBox", , IDC_FRAME1, "Drag && Drop Or Left Click To browse ", 24, 16, 286, 100)
  pWindow.AddControl("Button", , IDC_Encrypt, "Encrypt a file", 40, 40, 120, 60, , WS_Ex_AcceptFiles) 
  pWindow.AddControl("Button", , IDC_Decrypt, "Decrypt a file", 174, 40, 120, 60, , WS_Ex_AcceptFiles)
  pWindow.AddControl("Edit", , IDC_TEXTBOX1, "", 35, 128, 266, 23 )
  Edit_SetReadOnly( GetDlgItem( hwnd, IDC_TEXTBOX1 ), true )
  pWindow.AddControl("Button", , IDC_Execute, "Execute", 130, 166, 80, 40 )
  
  Dim DragDrop As DragDropType
  Dim ptrDragDrop As DragDropType Ptr = @DragDrop
  DragDrop.Title = "Drag And Drop"
  DragDrop.hHandle = Cast(Dword, hWnd )
  Dim lResult As Boolean
  lResult = SetWindowSubclass(GetDlgItem( Hwnd, IDC_Encrypt), Procptr(DragDropProc), 1, Cast( DWORD_PTR, ptrDragDrop ) )
  Print lresult, getlasterror
  lResult = SetWindowSubclass(GetDlgItem( hWnd, IDC_Decrypt), Procptr(DragDropProc), 2, Cast( DWORD_PTR, ptrDragDrop ) )
  Print lresult, getlasterror
  
  Function = pWindow.DoEvents(nCmdShow)
  
End Function

Function WndProc(Byval hwnd As HWND, Byval uMsg As UINT, Byval wParam As WPARAM, Byval lParam As LPARAM) As LRESULT
  Dim lResult As Boolean
  
	Select Case uMsg
  
  Case WM_COMMAND
    ' Process control notifications
    Select Case GET_WM_COMMAND_ID(wParam, lParam)
    Case IDC_Encrypt
      If GET_WM_COMMAND_CMD(wParam, lParam) = BN_CLICKED Then
        MessageBox hWnd, "IDC_Encrypt", "Test",MB_TASKMODAL
      End If
      
    Case IDC_Decrypt
      If GET_WM_COMMAND_CMD(wParam, lParam) = BN_CLICKED Then
        MessageBox hWnd, "IDC_Decrypt", "Test",MB_TASKMODAL
      End If
      
    Case IDC_Execute
      If GET_WM_COMMAND_CMD(wParam, lParam) = BN_CLICKED Then
        MessageBox hWnd, "IDC_Execute", "Test",MB_TASKMODAL
      End If
      
    End Select
    
  Case WM_DESTROY
    ' // Ends the application by sending a WM_QUIT message
    lResult = RemoveWindowSubclass(GetDlgItem( hWnd, IDC_Encrypt ), Procptr(DragDropProc), 1)
    lResult = RemoveWindowSubclass(GetDlgItem( HWnd, IDC_Decrypt ), Procptr(DragDropProc), 2)
    PostQuitMessage(0)
    Exit Function
    
  Case WM_SYSCOMMAND
    If Loword(wParam) = SC_CLOSE Then ' Close message
      Dim As Long x, y, f
      Dim rc As RECT
      GetWindowRect( hWnd, @rc )
      ' If Window has moved Then save current position
      If xWindow <> rc.Left Orelse yWindow <> rc.top Then
        f = Freefile
        Open "Position.dat" For Binary Access Write As #f
        Put #f, , rc.Left
        Put #f, , rc.top
        Close #f
      End If
    End If
    
  End Select
  
  ' // Default processing of Windows messages
  Function = DefWindowProcW(hWnd, uMsg, wParam, lParam)
  
End Function

Function DragDropProc( hWnd As hwnd, wMsg As Uint, wParam As wparam, _
  lParam As lParam, uIDSubclass As Uint_ptr, RefData As Dword_Ptr ) As WINBOOL
  
  Static As Boolean FirstPass = True
  Static As Dword hDlg
  Static As String MsgTitle
  Dim As Dword dwRes
  Dim As Zstring * MAX_PATH szFName
  
  If FirstPass Then
    Print "Yep, I am here"
    hDlg = Cast(DragDropType Ptr, RefData)->hHandle
    MsgTitle = Cast(DragDropType Ptr, RefData)->Title
    FirstPass = False
  End If
  
  Select Case wMsg
  
  Case WM_DropFiles
    Print "... And I am here As well"
    dwRes = DragQueryFile( Cast( hDrop, wParam ), -1, Byval Null, 0 ) ' Get number Of dropped files
    If dwRes Then
      If dwRes > 1 Then
        MessageBox Cast( hWnd, hDlg ), "Only one file may be dropped.", _
        MsgTitle, MB_IconError Or MB_TaskModal Or MB_Topmost
        DragFinish Cast( hDrop, wParam )
        Exit Function
      End If
    Else
      DragFinish Cast( hDrop, wParam )
      Exit Function
    End If
    
    dwRes = DragQueryFile( Cast( hDrop, wParam ), 0, szFName, Max_Path )
    If dwRes Then
      szFName  = Left$( szFName, dwRes )
      If ( GetFileAttributes( szFName ) And FileAttribute_Directory ) <> 0 Then
        MessageBox Cast( hWnd, hDlg ), "Only a file may be dropped, Not folders.", _
        MsgTitle, MB_IconError Or MB_TaskModal Or MB_Topmost
        DragFinish Cast( hDrop, wParam )
        Exit Function
      End If
    Else
      DragFinish Cast( hDrop, wParam )
      Exit Function
    End If
    
    '      szFileName(spID) = szFName
    
    '      If spID = 1 Then
    '        GetSHA512Password
    '        Control Disable hDlg, KeyFileButton
    '        Control Enable hDlg, EnableKeyFile
    '        Control Set Text hDlg, KeyFileText, PathName$( Namex, szFilename(1) )
    '      Else
    '        Control Disable hDlg, TargetFileButton
    '        Control Enable hDlg, EnableTargetFile
    '        Control Set Text hDlg, TargetFileText, szFileName(2)
    '      End If
    
    '      If szFileName(1) <> "" And szFileName(2) <> "" Then
    '        Control Enable hDlg, ExecuteButton
    '      End If
    
    DragFinish Cast( hDrop, wParam )
    
  End Select
  
  Function = DefSubclassProc( hwnd, wMsg, wParam, lParam )
  
  End Function
Josep Roca
Posts: 564
Joined: Sep 27, 2016 18:20
Location: Valencia, Spain

Re: SetWindowSubclass

Post by Josep Roca »

1. Add the GroupBox after the buttons. For some reason, the group box is disabling drag and drop in the buttons if you put it before them.

2. Use HWND instead of DWORD as the type hHandle. This way, it will work with both 32 and 64 bit. BTW hDlg = Cast(DragDropType Ptr, RefData)->hHandle is unneeded. You can get the handle at any time using GetParent(hwnd), without having to pass it as a member of an structure in RefData. Use RefData if you need to pass further information, but to just pass the main window handle it is worthless.

3. Please add BYVAL or BYREF before the parameters or people that compiles with the -w pedantic option will get so many errors that won't care to test your code.

3. When using Unicode, forget ZString and use WString.

4. Optional: Take a look at my template Button Subclass (SetWindowSubclass). It uses a more elegant way to subclassing.

Code: Select all

'#Console On
#Define UNICODE

#Define _WIN32_WINNT &h0602
#Include Once "Afx/CWindow.inc"
#Include Once "Afx/CFileSys.inc"

Using Afx

Const IDC_FRAME1   = 1001
Const IDC_Encrypt  = 1002
Const IDC_Decrypt  = 1003
Const IDC_TEXTBOX1 = 1005
Const IDC_Execute  = 1007

Dim Shared szFileName() As Zstring * Max_Path
Dim Shared sPassword As String

Type DragDropType
  Title As Zstring * 20
  hHandle As HWND
End Type

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 As HWND, BYVAL As UINT, BYVAL As WPARAM, BYVAL As LPARAM ) As LRESULT
Declare Function DragDropProc( BYVAL hWnd As hwnd, BYVAL wMsg As Uint, BYVAL wParam As wparam, _
  BYVAL lParam As lParam, BYVAL uIDSubclass As Uint_ptr, BYVAL RefData As Dword_Ptr ) As LRESULT
Dim Shared As Long xWindow, yWindow
Dim Shared pFileSys As CFileSys

Function WinMain (Byval hInstance As HINSTANCE, _
  Byval hPrevInstance As HINSTANCE, _
  Byval szCmdLine As Zstring Ptr, _
  Byval nCmdShow As Long) As Long
 
  Dim As Long f
 
  ' // Set process DPI aware
  AfxSetProcessDPIAware
 
  Dim pWindow As CWindow
  pWindow.SetFont("Tahoma", 10, FW_NORMAL, , , , DEFAULT_CHARSET)
  pWindow.Create(NULL, "Encryption/Decryption", @WndProc, ,,,, WS_SYSMENU Or WS_CAPTION, WS_EX_TOPMOST)
  pWindow.SetClientSize(334, 220)
 
  ' Open at last position
  Dim hwnd As Hwnd = pWindow.hWindow
  If pFileSys.Fileexists("Position.dat") Then
    f = Freefile
    Open "Position.dat" For Binary As #f
    Get #f, , xWindow
    Get #f, , yWindow
    Close #f
    SetWindowPos( HWnd, HWND_NOTOPMOST, xWindow, yWindow, 0, 0, SWP_NOSIZE )
  Else
    pWindow.Center
  End If
 
  pWindow.AddControl("Button", , IDC_Encrypt, "Encrypt a file", 40, 40, 120, 60, , WS_Ex_AcceptFiles)
  pWindow.AddControl("Button", , IDC_Decrypt, "Decrypt a file", 174, 40, 120, 60, , WS_Ex_AcceptFiles)
  pWindow.AddControl("GroupBox", , IDC_FRAME1, "Drag && Drop Or Left Click To browse ", 24, 16, 286, 100)

  pWindow.AddControl("Edit", , IDC_TEXTBOX1, "", 35, 128, 266, 23 )
  Edit_SetReadOnly( GetDlgItem( hwnd, IDC_TEXTBOX1 ), true )
  pWindow.AddControl("Button", , IDC_Execute, "Execute", 130, 166, 80, 40 )
 
  Dim DragDrop As DragDropType
  Dim ptrDragDrop As DragDropType Ptr = @DragDrop
  DragDrop.Title = "Drag And Drop"
  DragDrop.hHandle = hwnd    ' Cast(Dword, hWnd )
  Dim lResult As Boolean
  lResult = SetWindowSubclass(GetDlgItem( Hwnd, IDC_Encrypt), Procptr(DragDropProc), 1, Cast( DWORD_PTR, ptrDragDrop ) )
  Print lresult, getlasterror
  lResult = SetWindowSubclass(GetDlgItem( hWnd, IDC_Decrypt), Procptr(DragDropProc), 2, Cast( DWORD_PTR, ptrDragDrop ) )
  Print lresult, getlasterror
 
  Function = pWindow.DoEvents(nCmdShow)
 
End Function

Function WndProc(Byval hwnd As HWND, Byval uMsg As UINT, Byval wParam As WPARAM, Byval lParam As LPARAM) As LRESULT
  Dim lResult As Boolean
 
   Select Case uMsg
 
  Case WM_COMMAND
    ' Process control notifications
    Select Case GET_WM_COMMAND_ID(wParam, lParam)
    Case IDC_Encrypt
      If GET_WM_COMMAND_CMD(wParam, lParam) = BN_CLICKED Then
        MessageBox hWnd, "IDC_Encrypt", "Test",MB_TASKMODAL
      End If
     
    Case IDC_Decrypt
      If GET_WM_COMMAND_CMD(wParam, lParam) = BN_CLICKED Then
        MessageBox hWnd, "IDC_Decrypt", "Test",MB_TASKMODAL
      End If
     
    Case IDC_Execute
      If GET_WM_COMMAND_CMD(wParam, lParam) = BN_CLICKED Then
        MessageBox hWnd, "IDC_Execute", "Test",MB_TASKMODAL
      End If
     
    End Select
   
  Case WM_DESTROY
    ' // Ends the application by sending a WM_QUIT message
    lResult = RemoveWindowSubclass(GetDlgItem( hWnd, IDC_Encrypt ), Procptr(DragDropProc), 1)
    lResult = RemoveWindowSubclass(GetDlgItem( HWnd, IDC_Decrypt ), Procptr(DragDropProc), 2)
    PostQuitMessage(0)
    Exit Function
   
  Case WM_SYSCOMMAND
    If Loword(wParam) = SC_CLOSE Then ' Close message
      Dim As Long x, y, f
      Dim rc As RECT
      GetWindowRect( hWnd, @rc )
      ' If Window has moved Then save current position
      If xWindow <> rc.Left Orelse yWindow <> rc.top Then
        f = Freefile
        Open "Position.dat" For Binary Access Write As #f
        Put #f, , rc.Left
        Put #f, , rc.top
        Close #f
      End If
    End If
   
  End Select
 
  ' // Default processing of Windows messages
  Function = DefWindowProcW(hWnd, uMsg, wParam, lParam)
 
End Function

Function DragDropProc( BYVAL hWnd As hwnd, BYVAL wMsg As Uint, BYVAL wParam As wparam, _
  BYVAL lParam As lParam, BYVAL uIDSubclass As Uint_ptr, BYVAL RefData As Dword_Ptr ) As LRESULT
  
  Static As Boolean FirstPass = True
  Static As HWND hDlg
  Static As String MsgTitle
  Dim As Dword dwRes
  Dim As Wstring * MAX_PATH szFName
  
  If FirstPass Then
    Print "Yep, I am here"
    hDlg = Cast(DragDropType Ptr, RefData)->hHandle
    MsgTitle = Cast(DragDropType Ptr, RefData)->Title
    FirstPass = False
  End If
  
  Select Case wMsg
  
  Case WM_DropFiles
    Print "... And I am here As well"
    dwRes = DragQueryFile( Cast( hDrop, wParam ), -1, Byval Null, 0 ) ' Get number Of dropped files
    If dwRes Then
      If dwRes > 1 Then
        MessageBox Cast( hWnd, hDlg ), "Only one file may be dropped.", _
        MsgTitle, MB_IconError Or MB_TaskModal Or MB_Topmost
        DragFinish Cast( hDrop, wParam )
        Exit Function
      End If
    Else
      DragFinish Cast( hDrop, wParam )
      Exit Function
    End If
    
    dwRes = DragQueryFile( Cast( hDrop, wParam ), 0, szFName, Max_Path )
    AfxMsg szFName
    If dwRes Then
      szFName  = Left( szFName, dwRes )
      If ( GetFileAttributes( szFName ) And FileAttribute_Directory ) <> 0 Then
        MessageBox Cast( hWnd, hDlg ), "Only a file may be dropped, Not folders.", _
        MsgTitle, MB_IconError Or MB_TaskModal Or MB_Topmost
        DragFinish Cast( hDrop, wParam )
        Exit Function
      End If
    Else
      DragFinish Cast( hDrop, wParam )
      Exit Function
    End If
    
    '      szFileName(spID) = szFName
    
    '      If spID = 1 Then
    '        GetSHA512Password
    '        Control Disable hDlg, KeyFileButton
    '        Control Enable hDlg, EnableKeyFile
    '        Control Set Text hDlg, KeyFileText, PathName$( Namex, szFilename(1) )
    '      Else
    '        Control Disable hDlg, TargetFileButton
    '        Control Enable hDlg, EnableTargetFile
    '        Control Set Text hDlg, TargetFileText, szFileName(2)
    '      End If
    
    '      If szFileName(1) <> "" And szFileName(2) <> "" Then
    '        Control Enable hDlg, ExecuteButton
    '      End If
    
    DragFinish Cast( hDrop, wParam )
    
  End Select
  
  Function = DefSubclassProc( hwnd, wMsg, wParam, lParam )
  
  End Function
   
  
Last edited by Josep Roca on Mar 27, 2018 12:55, edited 1 time in total.
Josep Roca
Posts: 564
Joined: Sep 27, 2016 18:20
Location: Valencia, Spain

Re: SetWindowSubclass

Post by Josep Roca »

BTW if you're using the CFileSys class just to check if a file exists, you can use the function AfxFileExists instead, i.e. If AfxFileExists("Position.dat") Then

and for GetFileAttributes you can use the constant FILE_ATTRIBUTE_DIRECTORY, ie. If ( GetFileAttributes( szFName ) And FILE_ATTRIBUTE_DIRECTORY ) <> 0 Then
deltarho[1859]
Posts: 4308
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: SetWindowSubclass

Post by deltarho[1859] »

Wow, thanks José.

1. I had WinMain printing all sorts of stuff and DragDropProc printing all sorts of stuff and everything was telling me that I should not be having an issue. It did not occur to me to put the GroupBox after the two WS_Ex_AcceptFiles buttons. So, it appears that I wasn't making as much of a mess as I thought I was - in so far as the Drag&Drop bit.

2. I have 'dumped' the udt. I have put the MessageBox title into a static in DragDropProc. hDlg = GetParent(hWnd) - nice one!

3. (first one) Didn't know that. Will do that and bear in mind in future.

3. (second one). Yes, ZString did screw up DragQueryFile. Since all my GUI stuff will be courtesy of WinFBX then it is goodbye ZString. <Ha, ha>

4. I checked the templates. I must clean my glasses more often. <smile> I will check that out after I have had a celebratory cup of tea and raise my cup to you.

Next Post:

AfxFileExists: Will do.
FILE_ATTRIBUTE_DIRECTORY: Will do

Thanks again. That was a big stumbling block. I was going nowhere fast without the Drag&Drop working.
deltarho[1859]
Posts: 4308
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: SetWindowSubclass

Post by deltarho[1859] »

Just for the record I have just added 'Edit_SetText( GetDlgItem( hDlg, IDC_TEXTBOX1 ), pFileSys.GetFileName( szFName ) )' before DragFinish so that the read only edit control gets populated with the selected file to confirm that the selected file is the one I meant to select before going ahead with Execute. Violins at the ready, pause: I cannot trust my eyes or my mouse hand as once I did. Oh, dear. <smile>
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: SetWindowSubclass

Post by dodicat »

What are these files
#Include Once "Afx/CWindow.inc"
#Include Once "Afx/CFileSys.inc"

Are they available on the forum.
(I have searched but not found)

I fished around the forum for some ideas on drag and drop.
This is the hotchpotch I put together.

Code: Select all

 

#include once "windows.bi"
#include once "win/shellapi.bi"  'for drag and drop
#include "win/commctrl.bi"
#include "file.bi"               'for loadfile

Declare Function Blueframe Lib "UxTheme.dll" Alias "SetWindowTheme"(As Any Ptr,As zstring Ptr,As zstring Ptr) As Long
Declare Function main As Long
Declare Function loadFile(As String) As String
declare function checkstring(as string) as long

End main


Dim Shared As String  s 
Dim Shared show As Hwnd

Function WndProc ( Byval hWnd As HWND, _
    Byval wMsg As UINT, _
    Byval wParam As WPARAM, _
    Byval lParam As LPARAM ) As LRESULT
    Function = 0

    Select Case wMsg 

    Case WM_CREATE  
        Exit Function
        
    Case WM_DROPFILES
        Dim hDrop As HANDLE
        Dim drag_file As zstring * (MAX_PATH+1)  '261
        Dim count As Integer
        Dim i As Integer
        hDrop = Cast( HANDLE, wParam )
        count = DragQueryFile(hDrop,&HFFFFFFFF,drag_file, MAX_PATH )'see msdn
        For i = 0 To count - 1 
        DragQueryFile( hDrop, i, drag_file, MAX_PATH )
        Next i
        if loadfile(drag_file)="---ERROR---" then
            dim as string message
            if err=1 then message="FOLDER ERROR"
            if err=2 then message="NON TEXT FILE ERROR"
        messagebox(0,"cannot load "+drag_file,message,0)
        err=0
        exit function
    end if
    
        s+=loadfile( drag_file )  'accumulate dropped files
        
        setWindowText(show,s)
        DragFinish( hDrop )
        Exit Function
        
    Case WM_PAINT
        Dim As PAINTSTRUCT ps
            BeginPaint(hwnd, @ps)
            FillRect(ps.hdc, @ps.rcPaint, CreateSolidBrush(BGR(225,225,255)))
            EndPaint(hWnd, @ps)
       
        Exit Function 
        
    Case WM_KEYDOWN
        If Lobyte(wParam) = 27  Then s="": setWindowText(show,"")'clear the box
        
    Case WM_DESTROY
        PostQuitMessage( 0 )
        Exit Function
    End Select
    
    Function = DefWindowProc( hWnd, wMsg, wParam, lParam )    
    
End Function

Function main As Long
    Function=0
    Dim hInstance As HINSTANCE = GetModuleHandle( null )
    Dim wMsg As MSG
    Dim wcls As WNDCLASS     
    Dim hWnd As HWND
  
    With wcls
        .style         = CS_HREDRAW Or CS_VREDRAW Or CS_DROPSHADOW
        .lpfnWndProc   = @WndProc
        .cbClsExtra    = 0
        .cbWndExtra    = 0
        .hInstance     = hInstance
        .hIcon         = LoadIcon( NULL, IDI_APPLICATION )
        .hCursor       = LoadCursor( NULL, IDC_ARROW )
        .hbrBackground = GetStockObject( WHITE_BRUSH )
        .lpszMenuName  = NULL
        .lpszClassName = @"HelloWin"
    End With
    
    If( RegisterClass( @wcls ) = FALSE ) Then
        MessageBox( null, "Failed to register wcls", "Error", MB_ICONERROR )
        End 1
    End If
    
    hWnd = CreateWindowEx( WS_EX_ACCEPTFILES, _
    @"HelloWin", _
    "Drag a text file to box  -- Press <Esc> to refresh", _
    WS_OVERLAPPEDWINDOW, _
    0, _
    0, _
    800, _
    600, _
    NULL, _
    NULL, _
    hInstance, _
    NULL )
    show=CreateWindowEx(0,"EDIT","", ws_border Or WS_VISIBLE Or WS_CHILD Or WS_HSCROLL Or WS_VSCROLL Or ES_AUTOHSCROLL Or ES_AUTOVSCROLL Or ES_MULTILINE, 10, 10,770,540, hwnd, 0, 0, 0 )
    BlueFrame(hwnd,"","")
    ShowWindow( hWnd, SW_SHOW )
    UpdateWindow( hWnd )
    
    While( GetMessage( @wMsg, NULL, 0, 0 ) <> FALSE )    
        TranslateMessage( @wMsg )
        DispatchMessage( @wMsg )
    Wend
    
    End wMsg.wParam
End Function

Function loadfile(file As String) As String
	If Fileexists(file)=0 Then Print file;" not found":err=1:return "---ERROR---"
    Var  f=Freefile
    Open file For Binary Access Read As #f
    Dim As String text
    If Lof(f) > 0 Then
        text = String(Lof(f), 0)
        Get #f, , text
    End If
    Close #f
    if checkstring(text)=0 then err=2:return "---ERROR---"
    Return text
End Function

function checkstring(t as string) as long
    for n as long=0 to len(t)-1
        if t[n]>128 then return 0
    next
    return -1
    end function
        
 
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: SetWindowSubclass

Post by jj2007 »

Code: Select all

    show=CreateWindowEx(0,"EDIT","", ws_border Or WS_VISIBLE Or WS_CHILD Or WS_HSCROLL Or WS_VSCROLL Or ES_AUTOHSCROLL Or ES_AUTOVSCROLL Or ES_MULTILINE, 10, 10,770,540, hwnd, 0, 0, 0 )
    BlueFrame(hwnd,"","")
    ShowWindow( hWnd, SW_SHOW )
    UpdateWindow( hWnd )
   
    While( GetMessage( @wMsg, NULL, 0, 0 ) <> FALSE )   
While it is apparently possible to create controls before entering the message loop, it's not the standard way of doing this. Normally, you would use the WM_CREATE handler to do this:

Code: Select all

    Case WM_CREATE 
  show=CreateWindowEx(0,"EDIT","", ws_border Or WS_VISIBLE Or WS_CHILD Or WS_HSCROLL Or WS_VSCROLL Or ES_AUTOHSCROLL Or ES_AUTOVSCROLL Or ES_MULTILINE, 10, 10,770,540, hwnd, 0, 0, 0 )
  ' Exit Function not needed
With...

Code: Select all

    "Drag a text file to box  -- Press <Esc> to refresh", _
    WS_OVERLAPPEDWINDOW or WS_VISIBLE, _
... you can drop the ShowWindow and UpdateWindow lines. The WS_VISIBLE style takes care of showing the window.

Complete code:

Code: Select all

 

#include once "windows.bi"
#include once "win/shellapi.bi"  'for drag and drop
#include "win/commctrl.bi"
#include "file.bi"               'for loadfile

Declare Function Blueframe Lib "UxTheme.dll" Alias "SetWindowTheme"(As Any Ptr,As zstring Ptr,As zstring Ptr) As Long
Declare Function main As Long
Declare Function loadFile(As String) As String
declare function checkstring(as string) as long

End main


Dim Shared As String  s
Dim Shared show As Hwnd

Function WndProc ( Byval hWnd As HWND, _
    Byval wMsg As UINT, _
    Byval wParam As WPARAM, _
    Byval lParam As LPARAM ) As LRESULT
    Function = 0

    Select Case wMsg

    Case WM_CREATE 
  show=CreateWindowEx(0,"EDIT","", ws_border Or WS_VISIBLE Or WS_CHILD Or WS_HSCROLL Or WS_VSCROLL Or ES_AUTOHSCROLL Or ES_AUTOVSCROLL Or ES_MULTILINE, 10, 10,770,540, hwnd, 0, 0, 0 )
  ' Exit Function not needed
       
    Case WM_DROPFILES
        Dim hDrop As HANDLE
        Dim drag_file As zstring * (MAX_PATH+1)  '261
        Dim count As Integer
        Dim i As Integer
        hDrop = Cast( HANDLE, wParam )
        count = DragQueryFile(hDrop,&HFFFFFFFF,drag_file, MAX_PATH )'see msdn
        For i = 0 To count - 1
        DragQueryFile( hDrop, i, drag_file, MAX_PATH )
        Next i
        if loadfile(drag_file)="---ERROR---" then
            dim as string message
            if err=1 then message="FOLDER ERROR"
            if err=2 then message="NON TEXT FILE ERROR"
        messagebox(0,"cannot load "+drag_file,message,0)
        err=0
        exit function
    end if
   
        s+=loadfile( drag_file )  'accumulate dropped files
       
        setWindowText(show,s)
        DragFinish( hDrop )
        Exit Function
       
    Case WM_PAINT
        Dim As PAINTSTRUCT ps
            BeginPaint(hwnd, @ps)
            FillRect(ps.hdc, @ps.rcPaint, CreateSolidBrush(BGR(225,225,255)))
            EndPaint(hWnd, @ps)
       
        Exit Function
       
    Case WM_KEYDOWN
        If Lobyte(wParam) = 27  Then s="": setWindowText(show,"")'clear the box
       
    Case WM_DESTROY
        PostQuitMessage( 0 )
        Exit Function
    End Select
   
    Function = DefWindowProc( hWnd, wMsg, wParam, lParam )   
   
End Function

Function main As Long
    Function=0
    Dim hInstance As HINSTANCE = GetModuleHandle( null )
    Dim wMsg As MSG
    Dim wcls As WNDCLASS     
    Dim hWnd As HWND
 
    With wcls
        .style         = CS_HREDRAW Or CS_VREDRAW Or CS_DROPSHADOW
        .lpfnWndProc   = @WndProc
        .cbClsExtra    = 0
        .cbWndExtra    = 0
        .hInstance     = hInstance
        .hIcon         = LoadIcon( NULL, IDI_APPLICATION )
        .hCursor       = LoadCursor( NULL, IDC_ARROW )
        .hbrBackground = GetStockObject( WHITE_BRUSH )
        .lpszMenuName  = NULL
        .lpszClassName = @"HelloWin"
    End With
   
    If( RegisterClass( @wcls ) = FALSE ) Then
        MessageBox( null, "Failed to register wcls", "Error", MB_ICONERROR )
        End 1
    End If
   
    hWnd = CreateWindowEx( WS_EX_ACCEPTFILES, _
    @"HelloWin", _
    "Drag a text file to box  -- Press <Esc> to refresh", _
    WS_OVERLAPPEDWINDOW or WS_VISIBLE, _
    0, _
    0, _
    800, _
    600, _
    NULL, _
    NULL, _
    hInstance, _
    NULL )


    BlueFrame(hwnd,"","")
'     ShowWindow( hWnd, SW_SHOW )
'     UpdateWindow( hWnd )
   
    While( GetMessage( @wMsg, NULL, 0, 0 ) <> FALSE )   
        TranslateMessage( @wMsg )
        DispatchMessage( @wMsg )
    Wend
   
    End wMsg.wParam
End Function

Function loadfile(file As String) As String
   If Fileexists(file)=0 Then Print file;" not found":err=1:return "---ERROR---"
    Var  f=Freefile
    Open file For Binary Access Read As #f
    Dim As String text
    If Lof(f) > 0 Then
        text = String(Lof(f), 0)
        Get #f, , text
    End If
    Close #f
    if checkstring(text)=0 then err=2:return "---ERROR---"
    Return text
End Function

function checkstring(t as string) as long
    for n as long=0 to len(t)-1
        if t[n]>128 then return 0
    next
    return -1
    end function
Josep Roca
Posts: 564
Joined: Sep 27, 2016 18:20
Location: Valencia, Spain

Re: SetWindowSubclass

Post by Josep Roca »

What are these files
#Include Once "Afx/CWindow.inc"
#Include Once "Afx/CFileSys.inc"

Are they available on the forum.
(I have searched but not found)
They are part of my Windows Framework (WinFBX)
http://www.planetsquires.com/protect/fo ... pic=4109.0
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: SetWindowSubclass

Post by dodicat »

Thanks jj2007
That does the job also.

Thanks josep Roca
I got hold of your library.
deltarho[1859]
Posts: 4308
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: SetWindowSubclass

Post by deltarho[1859] »

This is what the above code currently looks like.

Image

The two main buttons are sub-classed. We can either (eventually) left click on 'Encrypt a file' to be presented with an Open File Dialog and select a file for encryption or left click on 'Decrypt a file' to be presented with an Open File Dialog and select an .aes file. Another way is to either Drag & Drop a file onto 'Encrypt a file' or Drag & Drop a .aes file onto 'Decrypt a file'. The two main buttons are then dual purpose. Personally, I am not a fan of the Open File Dialog and prefer a Drag and Drop from my two pane Total Commander file manager.

Which ever method we use the selected filename will populate the read only edit control.

The 'real' idea is that we will not be asked for a password/passkey on either encryption or decryption. The code will generate a 256 bit random binary key and use that. So, how the blazes do I do that? Simple: I use RSA 3072. Our public key is on our hard drive and our private key will somewhere else; mine will be on a flash drive. Why bother? The passkey is only ever used once, one time pad, so is uncrackable and we don't need to keep a copy; in a password manager, for example. I have not seen anybody else use this method of 'home' encryption so perhaps it is a barmy idea. I tend to have more barmy ideas than good ones but I have this odd feeling that it may not be as barmy as it may first appear. I tend to have a lot of odd feelings and they are increasing with age and they are not as unpleasant as I thought they might be. I am now rambling but I have always done that. <smile>

Added: The encryption will generate a single file; the encrypted passkey will be embedded and never see the light of day in plaintext form during encryption or decryption.
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: SetWindowSubclass

Post by dodicat »

DeltaRho
Have you altered your win 10 default settings?
I don't get a blue frame or blue shaded buttons here.
The only colours I see are white (Frame and message boxes) and rgb(240,240,240) (main window and buttons )
St_W
Posts: 1626
Joined: Feb 11, 2009 14:24
Location: Austria
Contact:

Re: SetWindowSubclass

Post by St_W »

dodicat wrote:I don't get a blue frame or blue shaded buttons here.
The only colours I see are white (Frame and message boxes) and rgb(240,240,240) (main window and buttons )
Just FYI: there's a setting "Show the accent colour on the following surfaces: Title bars" to change that; see e.g. https://www.tenforums.com/tutorials/321 ... -10-a.html
deltarho[1859]
Posts: 4308
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: SetWindowSubclass

Post by deltarho[1859] »

@dodicat

I use Winaero Tweaker.

In particular, I have increased the size of the font used in message boxes and menus. With menus it is global so even the font size in web browser drop down menus has been increased.

You may have noticed that all of my GUI screenshots do not use the default system fonts - I almost invariably use Tahoma 10 and have my GUIRuler font set at Tahoma 10.
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: SetWindowSubclass

Post by dodicat »

Thank you St_W and deltarho[]
deltarho[1859]
Posts: 4308
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: SetWindowSubclass

Post by deltarho[1859] »

I have now got the opening post working as intended: Left click and drag and drop and all the necessary crypto stuff. Effectively, the project is finished so all that is needed now is for me to try and break it. I have a friend who will be testing it for me as well plus feedback on how easy it is to use, or not as the case may be. <smile>

However, in 64 bit I am getting four warnings, the following times two.

Code: Select all

Passing different pointer types, at parameter 2 of SETWINDOWSUBCLASS()
Passing different pointer types, at parameter 2 of REMOVEWINDOWSUBCLASS()
All are to do with ProcPtr.

Bearing in mind that we normally only have 2GB of memory to play with per process then a Long is sufficient to point to a procedure.

WinFBE will not let me proceed. FBEdit warns me but lets me Run anyway. poseidonFB doesn't even warn me and Runs.

I have checked the bi files for 32 bit and 64 bit and there does not seem to be a distinction so I not sure how the 64 bit compiler is deciding to warn me at all.

Of course, if we 'pushed' the 2GB limit to 3GB then we could get into trouble but that would be true for both 32 bit and 64 bit.

I am not overly concerned because there is no apparent performance benefit whatsoever in running in 64 bit and the application does not tick any 64 bit boxes.
Post Reply