WinFBX - emulate a button click

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

WinFBX - emulate a button click

Post by deltarho[1859] »

@Josep Roca

Hi José

It is pulling my hair out time again.Image

I have a button which I may or may not click. However, I want an application to emulate my clicking on the button on opening. I really fancied my chances with 'SendMessage( pWindow.ControlHandle(IDC_Apply), BM_CLICK, 0, 0 )' but I don't know where to put it. Life was so easy with PB's DDT and WM_INITDIALOG. I know that putting it in WM_CREATE won't work - I had that problem sometime ago, if you remember. I tried putting it just before 'Function = pWindow.DoEvents(nCmdShow)'. I didn't expect that to work and it didn't - I am now grasping at straws.

The problem is with WinFBE. My application is telling me the state of checkboxes, three state checkboxes and radio buttons but WinFBE's WinFBE.ini does not reflect that so I have to click on the Apply button to force the issue and why I want the application to force the issue for me. WritePrivateProfileString is working fine, by checking WinFBe.ini, but when I close WinFBE WinFBE.ini it is not what I was just looking at. I may be wrong but I think when I use WritePrivateProfileString that is changing what is in the filecache and not what is on the drive.

Anyway, if I can emulate clicking on the Apply button on opening all should be OK.
Josep Roca
Posts: 564
Joined: Sep 27, 2016 18:20
Location: Valencia, Spain

Re: WinFBX - emulate a button click

Post by Josep Roca »

Instead of SendMessage, use PostMessage

Code: Select all

PostMessage( pWindow.ControlHandle(IDC_Apply), BM_CLICK, 0, 0 )
deltarho[1859]
Posts: 4313
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: WinFBX - emulate a button click

Post by deltarho[1859] »

<Ha,ha>

Your original code did not work unless I included AfxMsg "clicked" in my code. So, I replaced the message with a Sleep 200, 1 but that didn't work. I removed AfxMsg "clicked" from your code and that failed.

Ok, I will try the PostMessage above now.
Last edited by deltarho[1859] on Feb 22, 2020 10:27, edited 1 time in total.
deltarho[1859]
Posts: 4313
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: WinFBX - emulate a button click

Post by deltarho[1859] »

Nope that failed unless this, ie AfxMsg

Code: Select all

IF GET_WM_COMMAND_CMD(wParam, lParam) = BN_CLICKED THEN
  AfxMsg "clicked"
I remember a very long time ago someone at PowerBASIC had an issue unless they 'fired' a message box but I cannot remember anything else.

Of course, instead of "clicked" I could have "WinFBE.ini has been updated" but someone will undoubtedly remark something like "What are you telling me for?"
Josep Roca
Posts: 564
Joined: Sep 27, 2016 18:20
Location: Valencia, Spain

Re: WinFBX - emulate a button click

Post by Josep Roca »

Int this example, AfxMsg "Clicked" is only used to let you know that the message has been fired and processed. Remove it and put the code you wish.

Code: Select all

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

#define MyButton 1001

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)

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

' ========================================================================================
' 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)
   pWindow.Create(NULL, "CWindow with a button", @WndProc)
   ' // Sizes it by setting the wanted width and height of its client area
   pWindow.SetClientSize(500, 320)
   ' // Centers the window
   pWindow.Center

   ' // Adds a button
   DIM hButton AS HANDLE = pWindow.AddControl("Button", , MyButton, "&Close", 350, 250, 75, 23)
   PostMessageW hButton, BM_CLICK, 0, 0

   ' // Displays the window and dispatches the Windows messages
   FUNCTION = pWindow.DoEvents(nCmdShow)

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 GET_WM_COMMAND_ID(wParam, lParam)
            CASE MyButton
               IF GET_WM_COMMAND_CMD(wParam, lParam) = BN_CLICKED THEN
                  AfxMsg "Clicked"
               END IF
         END SELECT

    	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
' ========================================================================================
deltarho[1859]
Posts: 4313
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: WinFBX - emulate a button click

Post by deltarho[1859] »

I don't know what you have done because that is what I have now

Code: Select all

Select Case uMsg
 
  Case WM_COMMAND
      
    SELECT CASE GET_WM_COMMAND_ID(wParam, lParam)
      
      CASE IDC_Apply
        IF GET_WM_COMMAND_CMD(wParam, lParam) = BN_CLICKED THEN
          AfxMsg "clicked"
and if I remove AfxMsg "clicked" it fails.

In WinMain I have

Code: Select all

If IsTrue(Norm) Then
  pWindow.AddControl("Button", , IDC_Apply, "Apply", 41, nTop+30, 50, 22, dwStyle)
  PostMessage( pWindow.ControlHandle(IDC_Apply), BM_CLICK, 0, 0 )
else
  pWindow.AddControl("Button", , IDC_Apply, "Apply", 59, nTop+30, 70, 25, dwStyle)
  PostMessage( pWindow.ControlHandle(IDC_Apply), BM_CLICK, 0, 0 )
End If
The first part is for normal text and the second part is for larger text.
deltarho[1859]
Posts: 4313
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: WinFBX - emulate a button click

Post by deltarho[1859] »

It is worth mentioning that when your code says "clicked" that is all that it is doing. In my case if I see "clicked" then my form and WimFBE.ini are in agreement. If I remove AfxMsg "clicked" then my form and WinFBE.ini are not in agreement. I wish I could remember the issue years ago at PB. A member was pushing 'stuff' out via a message box to make sure all was well. When he was happy, he cancelled the message box and all was not well any more.
Josep Roca
Posts: 564
Joined: Sep 27, 2016 18:20
Location: Valencia, Spain

Re: WinFBX - emulate a button click

Post by Josep Roca »

> It is worth mentioning that when your code says "clicked" that is all that it is doing.

Indeed. I have no idea of what you want to do when the button is clicked.

I have removed AfxMsg and added code to write and read to an .ini file.

Code: Select all

      CASE WM_COMMAND
         SELECT CASE GET_WM_COMMAND_ID(wParam, lParam)
            CASE IDC_Apply
               IF GET_WM_COMMAND_CMD(wParam, lParam) = BN_CLICKED THEN
                  DIM cIni AS CInifile = "Test.ini"
                  cIni.WriteValue("Test", "Name", "deltarho[1859]")
                  DIM wsz AS WSTRING * 260
                  wsz = cIni.GetString("Test", "Name")
                  print wsz
               END IF
         END SELECT
Full example:

Code: Select all

'#CONSOLE ON
#define UNICODE
#INCLUDE ONCE "Afx/CWindow.inc"
#INCLUDE ONCE "Afx/CIniFile.inc"
USING Afx

#define IDC_Apply 1001

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)

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

' ========================================================================================
' 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)
   pWindow.Create(NULL, "CWindow with a button", @WndProc)
   ' // Sizes it by setting the wanted width and height of its client area
   pWindow.SetClientSize(500, 320)
   ' // Centers the window
   pWindow.Center

   ' // Adds a button
   DIM hButton AS HANDLE = pWindow.AddControl("Button", , IDC_Apply, "&Apply", 350, 250, 75, 23)
   PostMessageW hButton, BM_CLICK, 0, 0

   ' // Displays the window and dispatches the Windows messages
   FUNCTION = pWindow.DoEvents(nCmdShow)

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 GET_WM_COMMAND_ID(wParam, lParam)
            CASE IDC_Apply
               IF GET_WM_COMMAND_CMD(wParam, lParam) = BN_CLICKED THEN
                  DIM cIni AS CInifile = "Test.ini"
                  cIni.WriteValue("Test", "Name", "deltarho[1859]")
                  DIM wsz AS WSTRING * 260
                  wsz = cIni.GetString("Test", "Name")
                  print wsz
               END IF
         END SELECT

    	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
' ========================================================================================
Instead of WSTRING, you can also also use CWSTR:

Code: Select all

      CASE WM_COMMAND
         SELECT CASE GET_WM_COMMAND_ID(wParam, lParam)
            CASE IDC_Apply
               IF GET_WM_COMMAND_CMD(wParam, lParam) = BN_CLICKED THEN
                  DIM cIni AS CInifile = "Test.ini"
                  cIni.WriteValue("Test", "Name", "deltarho[1859]")
                  DIM cws AS CWSTR
                  cws = cIni.GetString("Test", "Name")
                  print cws
               END IF
         END SELECT
or STRING if you don't care about unicode:

Code: Select all

      CASE WM_COMMAND
         SELECT CASE GET_WM_COMMAND_ID(wParam, lParam)
            CASE IDC_Apply
               IF GET_WM_COMMAND_CMD(wParam, lParam) = BN_CLICKED THEN
                  DIM cIni AS CInifile = "Test.ini"
                  cIni.WriteValue("Test", "Name", "deltarho[1859]")
                  DIM s AS STRING
                  s = cIni.GetString("Test", "Name")
                  print s
               END IF
         END SELECT
deltarho[1859]
Posts: 4313
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: WinFBX - emulate a button click

Post by deltarho[1859] »

@Josep Roca

I am going out shortly so will have a look at your last post when I get back.

The problem that I am having is with WinFBE. Paul altered the way WinFBE worked when I was developing the paths/switches tools otherwise we had to run them before opening WinFBE; they did not work within WinFBE.

I am getting a similar problem on closing WinFBE. The paths tool has been working OK but I have noticed that if I changed the compiler path within WinFBE and then closed everything down the change was not honoured.

I then tried an experiment: I removed AfxMsg "clicked" from the switches code and removed the message posting, changed the switches and changed the compiler paths. I then compiled a code snippet and closed everything down. Next time I opened WinFBE it remembered everything that I had done.

We can change switches and paths within WinFBE, and they will be used at the next compilation. I have checked this by viewing the output window.

However, we should not make any changes to switches or paths or both without a compilation otherwise they will not be remembered.

I will remember that but getting users to remember that is another thing. I need to give some thought on that.
PaulSquires
Posts: 1002
Joined: Jul 14, 2005 23:41

Re: WinFBX - emulate a button click

Post by PaulSquires »

The change I made to WinFBE was to reload the ini file prior to a compile in order to take any changes into account that that your tool has written. If your tool makes changes but does not initiate a compile, then your version of the ini will get overwritten by WinFBE's internal version when WinFBE shuts down. I wonder if there is a better way for WinFBE to deal with your ini changes? Maybe I could poll the timestamp of the ini file and if it changes then reload it into WinFBE? That approach would not entail having to wait for a compile to be initiated.
deltarho[1859]
Posts: 4313
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: WinFBX - emulate a button click

Post by deltarho[1859] »

Hi Paul

Some young road-runner could make a change and be out of WinFBE mid poll, and we would miss it unless we have a small polling interval and that could be expensive.

Perhaps my tools could post a message via HWND_BROADCAST on a change that would be received by WinFBE - or something like that.
deltarho[1859]
Posts: 4313
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: WinFBX - emulate a button click

Post by deltarho[1859] »

Meanwhile on clicking the Apply button in SCS a message pops up saying: "Make sure you do a compilation before closing WinFBE." I could do the same for SCP.

Not exactly Image
deltarho[1859]
Posts: 4313
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: WinFBX - emulate a button click

Post by deltarho[1859] »

@PaulSquires

This is so simple there must be something wrong with it. Being a advocate of José's WinFBX you probably have this in WndProc.

Code: Select all

CASE WM_DESTROY
' // Ends the application by sending a WM_QUIT messaage
  PostQuitMessage(0)
  EXIT FUNCTION
Just before PostQuitMessage you could reload the inifile in any event, that is whether I have made any changes or not, and then continue to quit. My WinFBE.ini is just over 8KiB so WinFBE is not going to nod off during that workload.

The question is what is wrong with that to shoot it down?
PaulSquires
Posts: 1002
Joined: Jul 14, 2005 23:41

Re: WinFBX - emulate a button click

Post by PaulSquires »

That looks like it should work. However, prior to reading your post I coded up a solution that polls the LastWriteTime of the config file and reloads it should that value has changed. This also allows me to remove the specific pre-compile reloading of the config file and makes for a better general purpose use case in the event that somebody else codes a User Tool that manipulates the WinFBE config file.

I will have this change in the forthcoming 2.0.6 update (I'm working on uploading that tonight).
deltarho[1859]
Posts: 4313
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: WinFBX - emulate a button click

Post by deltarho[1859] »

This also allows me to remove the specific pre-compile reloading of the config file
There's a turn up.
in the event that somebody else codes a User Tool that manipulates the WinFBE config file.
I haven't left much wiggle room. Image
I will have this change in the forthcoming 2.0.6 update
Magic!

I have just posted two new versions of SCP and SCS. I have a lot of work to do now by removing the message: "Make sure you do a compilation before closing WinFBE." from both. I must remember to have a lie down between each task. Image
Post Reply