Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using SetParent to make an Access Form escape from Access

I have been trying to get a Microsoft Access for to 'escape' from the main Access window so that I can hide the Access window and just show the form on the desktop so that it can be placed alongside other applications easily.

At first I found some code samples that use Access' own Form.PopUp property but this cannot be set at runtime, only when in design view. Although this seems to achieve what I'm trying to do, there are two drawbacks:

  1. Switching between design view and normal view requires 'closing' the window in between - I'd rather keep it open to preserve the current state especially as it's used for creating new records which are necessarily unsaved.

  2. I want to open other forms from the main one which also doesn't seem to work well with this approach unless they too are set as 'pop-up'. But this is a hassle as these would also need to be put into design view, etc and I'm not sure if it would be easy to switch between the two pop-up windows.

I then found an API function called SetParent that seemed to do what I need. I used the following commands (VBA syntax):

SetParent ShowForm.hWnd
ShowWindow hWndAccessApp, SW_HIDE
ShowWindow ShowForm.hWnd, SW_SHOWNORMAL

But I ran into two problems (probably related:

  1. The window seemed to be rather unresponsive (I couldn't type into it, for example and clicking the buttons didn't seem to work either).

  2. When I did ALT+TAB, I got a BSOD:

    BugCheck 1000008E, {c0000005, 9e3573f5, 88d9da10, 0}
    Probably caused by : win32k.sys ( win32k!xxxNextWindow+3a6 )
    at win32k!EngLineTo+1a641
    

Is there any other way to do this so that I can have a form without the access window that is able to call and display other access forms outside of the main access window?

I have noticed in the SetParent API Documentation that there are a couple of other things that need to be done - changing the UI state and changing the window style but I can't find the right methods to do them. Would doing this fix the BSOD and non-responsiveness problem?

Thanks for any ideas!

like image 575
ec2011 Avatar asked Nov 12 '22 04:11

ec2011


1 Answers

The core problem of the question can be solved with the following code. – However, there are some limitations (see below).

I would suggest you paste this code into a new VBA module, but you can put it inside a form’s module as well.

Private Const GWL_STYLE As Long = -16

Private Const WS_CHILD As Long = &H40000000
Private Const WS_POPUP As Long = &H80000000

Private Const SW_HIDE As Long = 0
Private Const SW_SHOW As Long = 5
Private Const SW_MINIMIZE As Long = 6

Private Declare PtrSafe Function SetParent Lib "User32.dll" (ByVal hWndChild As LongPtr, ByVal hWndNewParent As LongPtr) As LongPtr
Private Declare PtrSafe Function SetWindowLong Lib "User32.dll" Alias "SetWindowLongA" (ByVal hWnd As LongPtr, ByVal nIndex As Long, ByVal dwNewLong As LongPtr) As LongPtr
Private Declare PtrSafe Function GetWindowLong Lib "User32.dll" Alias "GetWindowLongA" (ByVal hWnd As LongPtr, ByVal nIndex As Long) As LongPtr
Private Declare PtrSafe Function ShowWindow Lib "User32.dll" (ByVal hWnd As LongPtr, ByVal nCmdShow As Long) As Boolean

Public Sub MakePopupWindow(ByVal hWnd As LongPtr)

    Dim windowStyle As LongPtr

    Call SetParent(hWnd, 0)

    windowStyle = GetWindowLong(hWnd, GWL_STYLE)
    windowStyle = windowStyle Xor WS_CHILD
    windowStyle = windowStyle Or WS_POPUP

    Call SetWindowLong(hWnd, GWL_STYLE, windowStyle)

    Call ShowWindow(Application.hWndAccessApp, SW_HIDE)
    Call ShowWindow(hWnd, SW_SHOW)

End Sub

This code will transform any Access form to a PopUp-like form that can be moved outside of the Access main window. It will set the parent window of the form to the desktop window and will remove the WS_CHILD window style and add the WS_POPUP style instead.

The code can be invoked any time and does not require any specific design time settings. To invoke the code on any form just call the MakePopupWindow method and pass the hWnd of the target form to it.

The current implementation has some limitations:

1.) The Document Window Option of the current database has to be set to Overlapping Windows. I guess it should be possible to make this work with Tabbed Documents as well, but that requires additional changes to the window styles of the target window.

2.) The transformation of the forms is one-way. I wasn’t able to find a way to reintegrate the forms back into the Access main window. Just reversing the code, did not work.

like image 158
PhilS Avatar answered Nov 15 '22 07:11

PhilS