Hi Mike,
If you look what happens earlier, displaydeviceA.devicename% points to a memory buffer, where the system call returns a string. Dredging my memory, and without checking the manual, such strings are usually nul-terminated, so you can use the indirection operator $$ to tell BB4W that that is what it will find there.
Hope that makes some sort of sense - if not, I'll need to revisit it, and it is quite possible it will turn out that my code is junk.... I just did what looked sensible (to me) based on the original code...
Best wishes,
D
Screen dimensions
-
- Posts: 78
- Joined: Sat 23 Jun 2018, 15:51
Re: Screen dimensions
I am not surprised that Mike was confused. KenDown's program has quite a few problems and DDRM's modification did give a result but largely by luck I think.
It works, kind of, because the memory allocated in the DIM statements maybe contiguous but that isn't guaranteed. [EDIT. Successive DIM allocations don't produce contiguous blocks so far as I can tell, but that memory isn't actually used either.] The only way to guarantee a contiguous block is to allocate it as such, i.e. DIM cb% 423 and note that allocates 424 locations.
Then as in the old days before structures you would call SYS"EnumDisplayDevicesA",0,i%,cb%,1TOsuccess% in the original program.
Then PRINT $$(cb%+4) gives you the device name string. It is just one integer in from the start of the API structure that used cb%'s memory.
What you can't do is a hybrid and confuse the method using structures in the API call with allocation of blocks of memory. A re-read of the manual section about structures might be helpful.
Note that DDRM's PRINT $$^displaydeviceA.devicestring% doesn't produce the device string but the devicename with the first four characters missing because that is pointing to the wrong place in the memory block due to the variables in the displaydeviceA structure being integer not the expected sizes.
So I would encourage KenDown to copy my earlier example as it aligns with what you read in MSDN and uses the structure rather than the slightly obscure indirection method that we used to have to use. And the hybrid method is only going to give you pain.
On the question of the indirection, remember that $$ is an indirection operator that expects the address of the string. In KenDown's program you have an integer variable in the structure that is overwritten by a string, so it is the address of the variable that needs to be passed, which is where the string starts not its integer value which is junk in this case.
Z
It works, kind of, because the memory allocated in the DIM statements maybe contiguous but that isn't guaranteed. [EDIT. Successive DIM allocations don't produce contiguous blocks so far as I can tell, but that memory isn't actually used either.] The only way to guarantee a contiguous block is to allocate it as such, i.e. DIM cb% 423 and note that allocates 424 locations.
Then as in the old days before structures you would call SYS"EnumDisplayDevicesA",0,i%,cb%,1TOsuccess% in the original program.
Then PRINT $$(cb%+4) gives you the device name string. It is just one integer in from the start of the API structure that used cb%'s memory.
Code: Select all
size%=4+32+128+4+128+128
DIM cb% 423
!cb%=size%
FORi%=0TO2
SYS"EnumDisplayDevicesA",0,i%,cb%,1TOsuccess%
PRINTsuccess%
PRINT $$(cb%+4)
PRINT $$(cb%+36)
PRINT cb%!164
NEXT
END
Note that DDRM's PRINT $$^displaydeviceA.devicestring% doesn't produce the device string but the devicename with the first four characters missing because that is pointing to the wrong place in the memory block due to the variables in the displaydeviceA structure being integer not the expected sizes.
So I would encourage KenDown to copy my earlier example as it aligns with what you read in MSDN and uses the structure rather than the slightly obscure indirection method that we used to have to use. And the hybrid method is only going to give you pain.
On the question of the indirection, remember that $$ is an indirection operator that expects the address of the string. In KenDown's program you have an integer variable in the structure that is overwritten by a string, so it is the address of the variable that needs to be passed, which is where the string starts not its integer value which is junk in this case.
Z
Last edited by Zaphod on Sat 09 Feb 2019, 13:52, edited 1 time in total.
Re: Screen dimensions
Thanks, Zaphod.
That's what happens when you have a quick hack at something during your lunchbreak without thinking it through...
D
That's what happens when you have a quick hack at something during your lunchbreak without thinking it through...
D
-
- Posts: 78
- Joined: Sat 23 Jun 2018, 15:51
Re: Screen dimensions
DDRM we have all done that!
So I finally managed to solve this, I think. Well I can certainly find the screen size and I think that this gives a solution to the wider requirements.
You use the Multiwin library and define a new window to be in the space where you know the second monitor to be.
To do that properly you would have to determine the size of the primary monitor and the virtual screen size to determine whether the secondary was the left or right of the primary.
FN_createwin gives a handle to that window.
Then we can use SYS"MonitorFromWindow" to get the handle to the monitor.
Then using SYS"GetMonitorInfoA " using the monitor handle you can get the size of the monitor and the work area.
The code below or something like it should work. It needs the ON ERROR etc. added to close properly.
Z
So I finally managed to solve this, I think. Well I can certainly find the screen size and I think that this gives a solution to the wider requirements.
You use the Multiwin library and define a new window to be in the space where you know the second monitor to be.
To do that properly you would have to determine the size of the primary monitor and the virtual screen size to determine whether the secondary was the left or right of the primary.
FN_createwin gives a handle to that window.
Then we can use SYS"MonitorFromWindow" to get the handle to the monitor.
Then using SYS"GetMonitorInfoA " using the monitor handle you can get the size of the monitor and the work area.
The code below or something like it should work. It needs the ON ERROR etc. added to close properly.
Code: Select all
SM_CXVIRTUALSCREEN = 78
SM_CYVIRTUALSCREEN = 79
SM_CXSCREEN = 0
SM_CYSCREEN = 1
SM_XVIRTUALSCREEN = 76
INSTALL @lib$+"WINLIB5A"
INSTALL @lib$+"MULTIWIN"
PROC_multiwin(1)
REM Find position of secondary.
REM Use SYS "GetSystemMetrics" to find all we can about the system
SYS "GetSystemMetrics", SM_CXSCREEN TO xscreen%
SYS "GetSystemMetrics", SM_CYSCREEN TO yscreen%
SYS "GetSystemMetrics", SM_XVIRTUALSCREEN TO xposn%
SYS "GetSystemMetrics", SM_CXVIRTUALSCREEN TO vxscreen%
SYS "GetSystemMetrics", SM_CYVIRTUALSCREEN TO vyscreen%
REM If xposn%=0 then the secondary is on the right, if it is negative it is on the left.
REM On a two monitor system we can imply the width of the secondary as the difference
REM between the primary and virtual screen width.
REM From here on I assume only the monitor on the right case.
REM Now set up a test window to get the handle of the second monitor.
REM We could change the s% parameter (8th) to not include WS_VISIBLE.
hwin%=FN_createwin(1, "test", xscreen%+1, 0, 300, 100, 0, &96C00000 , 0)
SYS "MonitorFromWindow", hwin%,0 TO hmon%
REM now get all the information for this monitor.
DIM mi{s%, rm{l%,t%,r%,b%}, rw{l%,t%,r%,b%}, flag%}
mi.s%=DIM(mi{})
SYS "GetMonitorInfoA", hmon%, mi{} TO R%
PROC_closewin(1)
REM Now draw the right size. Select mi.rw if you want the taskbar to show.
hmon%=FN_createwin(1, "Second", xscreen%, 0, mi.rm.r%-mi.rm.l% ,mi.rm.b%-mi.rm.t%, 0, &96C00000 , 0)
PROC_selectwin(1)
PRINT "Home and dry on the second monitor"
PRINT STR$(mi.rm.r%-mi.rm.l%)+" by "+STR$(mi.rm.b%-mi.rm.t%)
PRINT "You can put dialogs over here if you make hwin% the owner"
PROC_selectwin(0)
PRINT "Back on the primary monitor"
PRINT STR$(xscreen%)+" by "+STR$(yscreen%)
PRINT "By default dialogs and menus will appear on this monitor."
REPEAT
WAIT 100
UNTIL FALSE
PROC_closewin(1)
END
- hellomike
- Posts: 192
- Joined: Sat 09 Jun 2018, 09:47
- Location: Amsterdam
Re: Screen dimensions
Yes, the old-days notation PRINT $$(cb%+4), I grasp.
The string data that "EnumDisplayDevicesA" returns lay within the 424 bytes of the structure. Its no use the put pointers in the structure beforehand to instruct the "EnumDisplayDevicesA" function as to where to store its string data. So I'm very surprised the code kinda worked.
These discussions are always useful to understand / get confirmation on how to setup stuff in order to interact and interpret SYS calls to Windows OS functionality.
Regards,
Mike
The string data that "EnumDisplayDevicesA" returns lay within the 424 bytes of the structure. Its no use the put pointers in the structure beforehand to instruct the "EnumDisplayDevicesA" function as to where to store its string data. So I'm very surprised the code kinda worked.
These discussions are always useful to understand / get confirmation on how to setup stuff in order to interact and interpret SYS calls to Windows OS functionality.
Regards,
Mike
-
- Posts: 78
- Joined: Sat 23 Jun 2018, 15:51
Re: Screen dimensions
Mike wrote:
I agree that such discussions make you question what you know or think you know, and in this case made me look at Multiwin for the first time ever.
Z
Yes. I take your point, it overruns the structure and luckily there is nothing there that it runs into. I'll also add that those DIM allocations are irrelevant as that is not the space that is being written into as I first implied. Delete them all and it still runs the same.So I'm very surprised the code kinda worked.
I agree that such discussions make you question what you know or think you know, and in this case made me look at Multiwin for the first time ever.
Z