DevX Home    Today's Headlines   Articles Archive   Tip Bank   Forums   

Results 1 to 13 of 13

Thread: Modal forms

  1. #1
    Chris Brown Guest

    Modal forms


    Does anyone know of a way of detecting if a form is modal and, if so, making
    it modeless?? Assume the form is being opened using the .SHOW method along
    with the vbModal constant.

    If the modal form CAN be switched off, can it then be switched back on again???
    What API's (if any) are involved in this?? I can't seem to see anywhere the
    processes windows goes through to create Modal forms.

    Many thanks in advance....

  2. #2
    Matthew Curland Guest

    Re: Modal forms

    This is a dead-end pursuit. A form is made modal by pushing a new message
    loop. Essentially, the message loop of your background forms gets very few
    messages (painting messages would be the most important ones that are let
    through). What you're asking is to break out of the message loop that showed
    the form while it is still showing. Not happening. You need to find a
    different approach to your problem. You might start by stating what that
    problem is instead of stating a proposed solution. -Matt

    "Chris Brown" <christopherbrown@halifax.co.uk> wrote in message
    news:3b4aff6c$1@news.devx.com...
    >
    > Does anyone know of a way of detecting if a form is modal and, if so,

    making
    > it modeless?? Assume the form is being opened using the .SHOW method along
    > with the vbModal constant.
    >
    > If the modal form CAN be switched off, can it then be switched back on

    again???
    > What API's (if any) are involved in this?? I can't seem to see anywhere

    the
    > processes windows goes through to create Modal forms.
    >
    > Many thanks in advance....




  3. #3
    Matthew Curland Guest

    Re: Modal forms

    This is a dead-end pursuit. A form is made modal by pushing a new message
    loop. Essentially, the message loop of your background forms gets very few
    messages (painting messages would be the most important ones that are let
    through). What you're asking is to break out of the message loop that showed
    the form while it is still showing. Not happening. You need to find a
    different approach to your problem. You might start by stating what that
    problem is instead of stating a proposed solution. -Matt

    "Chris Brown" <christopherbrown@halifax.co.uk> wrote in message
    news:3b4aff6c$1@news.devx.com...
    >
    > Does anyone know of a way of detecting if a form is modal and, if so,

    making
    > it modeless?? Assume the form is being opened using the .SHOW method along
    > with the vbModal constant.
    >
    > If the modal form CAN be switched off, can it then be switched back on

    again???
    > What API's (if any) are involved in this?? I can't seem to see anywhere

    the
    > processes windows goes through to create Modal forms.
    >
    > Many thanks in advance....




  4. #4
    Chris Brown Guest

    Re: Modal forms


    Thanks for that Matt - I guess I knew in advance that it was unlikely - just
    needed a guru to tell me I suppose!!!

    I was originally trying to show a VB form on top of all other forms - I'm
    actually creating a new 'combo box' ACTIVEX control that uses a list box
    with the TABSTOPS style set so that we can have multiple columns. I was displaying
    the form and using SETPARENT function to move the list box from the ACTIVEX
    control onto the form (this was to get around problems of the control being
    bound by a container control like a frame and only displaying half of the
    list box if the frame was small - using the form allowed the list box to
    appear 'outside' the frame!)

    This worked fine on forms shown normally but became a problem when showing
    on top of a modal form. I've now started down a new route of using CREATEWINDOW
    to create a new window/form instead of using an internal VB form and I'm
    gonna see how that goes!!!

    Many thanks again for your input.

    "Matthew Curland" <mattcur@microsoft.com> wrote:
    >This is a dead-end pursuit. A form is made modal by pushing a new message
    >loop. Essentially, the message loop of your background forms gets very few
    >messages (painting messages would be the most important ones that are let
    >through). What you're asking is to break out of the message loop that showed
    >the form while it is still showing. Not happening. You need to find a
    >different approach to your problem. You might start by stating what that
    >problem is instead of stating a proposed solution. -Matt
    >
    >"Chris Brown" <christopherbrown@halifax.co.uk> wrote in message
    >news:3b4aff6c$1@news.devx.com...
    >>
    >> Does anyone know of a way of detecting if a form is modal and, if so,

    >making
    >> it modeless?? Assume the form is being opened using the .SHOW method along
    >> with the vbModal constant.
    >>
    >> If the modal form CAN be switched off, can it then be switched back on

    >again???
    >> What API's (if any) are involved in this?? I can't seem to see anywhere

    >the
    >> processes windows goes through to create Modal forms.
    >>
    >> Many thanks in advance....

    >
    >



  5. #5
    Chris Brown Guest

    Re: Modal forms


    Thanks for that Matt - I guess I knew in advance that it was unlikely - just
    needed a guru to tell me I suppose!!!

    I was originally trying to show a VB form on top of all other forms - I'm
    actually creating a new 'combo box' ACTIVEX control that uses a list box
    with the TABSTOPS style set so that we can have multiple columns. I was displaying
    the form and using SETPARENT function to move the list box from the ACTIVEX
    control onto the form (this was to get around problems of the control being
    bound by a container control like a frame and only displaying half of the
    list box if the frame was small - using the form allowed the list box to
    appear 'outside' the frame!)

    This worked fine on forms shown normally but became a problem when showing
    on top of a modal form. I've now started down a new route of using CREATEWINDOW
    to create a new window/form instead of using an internal VB form and I'm
    gonna see how that goes!!!

    Many thanks again for your input.

    "Matthew Curland" <mattcur@microsoft.com> wrote:
    >This is a dead-end pursuit. A form is made modal by pushing a new message
    >loop. Essentially, the message loop of your background forms gets very few
    >messages (painting messages would be the most important ones that are let
    >through). What you're asking is to break out of the message loop that showed
    >the form while it is still showing. Not happening. You need to find a
    >different approach to your problem. You might start by stating what that
    >problem is instead of stating a proposed solution. -Matt
    >
    >"Chris Brown" <christopherbrown@halifax.co.uk> wrote in message
    >news:3b4aff6c$1@news.devx.com...
    >>
    >> Does anyone know of a way of detecting if a form is modal and, if so,

    >making
    >> it modeless?? Assume the form is being opened using the .SHOW method along
    >> with the vbModal constant.
    >>
    >> If the modal form CAN be switched off, can it then be switched back on

    >again???
    >> What API's (if any) are involved in this?? I can't seem to see anywhere

    >the
    >> processes windows goes through to create Modal forms.
    >>
    >> Many thanks in advance....

    >
    >



  6. #6
    Matthew Curland Guest

    Re: Modal forms

    You're probably best off starting with a normal combobox. The window-on-top
    functionality sounds like the hardest part of what you're trying to do, and
    this is already built into the combo.

    There are two approaches here:
    1) Use CreateWindowEx. I'd strongly recommend that you start with the
    CreateWindowEx code in my book to do this. Otherwise, you'll have lots of
    problems with accelerators that will take a very long time to clear up. The
    main point of doing this is to enable you to set the combobox style to
    CBS_OWNERDRAWFIXED. This will then let you draw your own text. You might
    want to start the drawing code with the SubClass\DrawItem stuff in the book.

    2) Use a CBTHook and either Load on a control array or Controls.Add to
    change the style of a VB combobox behind VB's back, then put a subclass in
    place for WM_DRAWITEM on the parent. There are a few things to note when
    doing this. First, VB doesn't know you made this change, so the VB control
    properties will not necessarily reflect what you did to the underlying
    control. For example, you can change a listbox to MultiSelect using this
    technique, but you have to use the API instead of Selected to read the
    selection. Second, changing the style bits in the CREATESTRUCTA you receive
    during the HCBT_CREATEWND hook notification is not sufficient to change the
    style bits in the window, you need to change these explicitly with
    SetWindowLong GWL_STYLE.

    2 is probably the easiest approach. All you'll have to do is handle the
    WM_DRAWITEM messages and VB will take care of the rest. I have a very raw
    sample lying around that does this. There isn't much code to do this, I'll
    paste in a sample below (runs on a form with a single command button. all
    but Command1_Click goes in a .bas module). Note that this is pretty old
    code. The memory access stuff is a lot cleaner with the ArrayOwner construct
    described in my book. -Matt

    Option Explicit
    Private Sub Command1_Click()
    Dim LB As ListBox
    Dim hHook As Long
    hHook = SetWindowsHookEx(WH_CBT, AddressOf CBTProc, 0, App.ThreadID)
    Set LB = Controls.Add("VB.ListBox", "ListBox1")
    UnhookWindowsHookEx hHook
    LB.Visible = True
    'MultiSelect and Sorted properties don't reflect true state, but
    'control acts properly.
    Debug.Print LB.hWnd, Hex$(GetWindowLong(LB.hWnd, GWL_STYLE)),
    LB.MultiSelect, LB.Sorted
    LB.AddItem "Second"
    LB.AddItem "First"
    End Sub

    Option Explicit

    Public Declare Function SetWindowsHookEx Lib "user32" Alias
    "SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, ByVal hMod As
    Long, ByVal dwThreadID As Long) As Long
    Public Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As
    Long) As Long
    Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA"
    (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
    Public Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA"
    (ByVal hWnd As Long, ByVal nIndex As Long) As Long

    Public Const WH_CBT As Long = 5
    Public Const HCBT_CREATEWND As Long = 3
    Public Const GWL_STYLE As Long = -16
    Public Type CBT_CREATEWNDA
    lpcs As Long
    hwndInsertAfter As Long
    End Type
    Public Type CREATESTRUCTA
    lpCreateParams As Long
    hInstance As Long
    hMenu As Long
    hwndParent As Long
    cy As Long
    cx As Long
    y As Long
    x As Long
    Style As Long
    lpszName As Long
    lpszClass As Long
    dwExStyle As Long
    End Type

    Public Type SafeArray1D
    cDims As Integer
    fFeatures As Integer
    cbElements As Long
    cLocks As Long
    pvData As Long
    cElements As Long
    lLbound As Long
    End Type

    'VarPtrArray gets a pointer to the SAFEARRAY pointer
    Public Declare Function VarPtrArray Lib "msvbvm60.dll" Alias "VarPtr" (Ptr()
    As Any) As Long
    Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDest As
    Any, pSrc As Any, ByVal ByteLen As Long)
    Public Declare Sub ZeroMemory Lib "kernel32" Alias "RtlZeroMemory" (pDest As
    Any, ByVal ByteLen As Long)

    Public Sub ShareMemoryViaArray(ByVal ArrayPtr As Long, ByVal MemPtr As Long,
    SA1D As SafeArray1D, Optional ByVal ElemByteLen As Long)
    With SA1D
    'This is optional because this is a 1 element array,
    'so cbElements is not needed to walk the array. If Erase
    'is called on an array with .cbElements = 0, VB will still
    'free all pointer types, but non-pointer types will not get
    'zeroed out. Note that the compiler calculates the length
    'of a structure at compile time, so LenB(MyStruct(0)) is
    'valid regardless of whether or not MyStruct is actually allocated.
    .cbElements = ElemByteLen
    .cDims = 1
    '2 = FADF_STATIC. This means that if the
    'array goes out of scope, then the pointed
    'to memory will be cleaned, but no attempt
    'will be made to free the array pointer
    'or descriptor.
    .fFeatures = 2
    .pvData = MemPtr
    .cElements = 1
    End With
    CopyMemory ByVal ArrayPtr, VarPtr(SA1D), 4
    End Sub

    Function CBTProc(ByVal lMsg As Long, ByVal wParam As Long, ByVal lParam As
    Long) As Long
    Dim saCreateWnd As SafeArray1D
    Dim psaCreateWnd() As CBT_CREATEWNDA
    Dim saCreateStruct As SafeArray1D
    Dim psaCreateStruct() As CREATESTRUCTA
    If lMsg = HCBT_CREATEWND Then
    ShareMemoryViaArray VarPtrArray(psaCreateWnd), lParam, saCreateWnd
    ShareMemoryViaArray VarPtrArray(psaCreateStruct),
    psaCreateWnd(0).lpcs, saCreateStruct
    'Changing the style in the CreateStruct is insufficient.
    SetWindowLong is required.
    'Note that the changes don't automatically show up in the pointed to
    structures.
    'Make the LB multiselect and sorted. This is LBS_SORT Or
    LBS_MULTIPLESEL
    SetWindowLong wParam, GWL_STYLE, psaCreateStruct(0).Style Or &HA
    ZeroMemory ByVal VarPtrArray(psaCreateStruct), 4
    ZeroMemory ByVal VarPtrArray(psaCreateWnd), 4
    End If
    End Function


    "Chris Brown" <christopherbrown@halifax.co.uk> wrote in message
    news:3b4bfa54$1@news.devx.com...
    >
    > Thanks for that Matt - I guess I knew in advance that it was unlikely -

    just
    > needed a guru to tell me I suppose!!!
    >
    > I was originally trying to show a VB form on top of all other forms - I'm
    > actually creating a new 'combo box' ACTIVEX control that uses a list box
    > with the TABSTOPS style set so that we can have multiple columns. I was

    displaying
    > the form and using SETPARENT function to move the list box from the

    ACTIVEX
    > control onto the form (this was to get around problems of the control

    being
    > bound by a container control like a frame and only displaying half of the
    > list box if the frame was small - using the form allowed the list box to
    > appear 'outside' the frame!)
    >
    > This worked fine on forms shown normally but became a problem when showing
    > on top of a modal form. I've now started down a new route of using

    CREATEWINDOW
    > to create a new window/form instead of using an internal VB form and I'm
    > gonna see how that goes!!!
    >
    > Many thanks again for your input.
    >
    > "Matthew Curland" <mattcur@microsoft.com> wrote:
    > >This is a dead-end pursuit. A form is made modal by pushing a new message
    > >loop. Essentially, the message loop of your background forms gets very

    few
    > >messages (painting messages would be the most important ones that are let
    > >through). What you're asking is to break out of the message loop that

    showed
    > >the form while it is still showing. Not happening. You need to find a
    > >different approach to your problem. You might start by stating what that
    > >problem is instead of stating a proposed solution. -Matt
    > >
    > >"Chris Brown" <christopherbrown@halifax.co.uk> wrote in message
    > >news:3b4aff6c$1@news.devx.com...
    > >>
    > >> Does anyone know of a way of detecting if a form is modal and, if so,

    > >making
    > >> it modeless?? Assume the form is being opened using the .SHOW method

    along
    > >> with the vbModal constant.
    > >>
    > >> If the modal form CAN be switched off, can it then be switched back on

    > >again???
    > >> What API's (if any) are involved in this?? I can't seem to see anywhere

    > >the
    > >> processes windows goes through to create Modal forms.
    > >>
    > >> Many thanks in advance....

    > >
    > >

    >




  7. #7
    Matthew Curland Guest

    Re: Modal forms

    You're probably best off starting with a normal combobox. The window-on-top
    functionality sounds like the hardest part of what you're trying to do, and
    this is already built into the combo.

    There are two approaches here:
    1) Use CreateWindowEx. I'd strongly recommend that you start with the
    CreateWindowEx code in my book to do this. Otherwise, you'll have lots of
    problems with accelerators that will take a very long time to clear up. The
    main point of doing this is to enable you to set the combobox style to
    CBS_OWNERDRAWFIXED. This will then let you draw your own text. You might
    want to start the drawing code with the SubClass\DrawItem stuff in the book.

    2) Use a CBTHook and either Load on a control array or Controls.Add to
    change the style of a VB combobox behind VB's back, then put a subclass in
    place for WM_DRAWITEM on the parent. There are a few things to note when
    doing this. First, VB doesn't know you made this change, so the VB control
    properties will not necessarily reflect what you did to the underlying
    control. For example, you can change a listbox to MultiSelect using this
    technique, but you have to use the API instead of Selected to read the
    selection. Second, changing the style bits in the CREATESTRUCTA you receive
    during the HCBT_CREATEWND hook notification is not sufficient to change the
    style bits in the window, you need to change these explicitly with
    SetWindowLong GWL_STYLE.

    2 is probably the easiest approach. All you'll have to do is handle the
    WM_DRAWITEM messages and VB will take care of the rest. I have a very raw
    sample lying around that does this. There isn't much code to do this, I'll
    paste in a sample below (runs on a form with a single command button. all
    but Command1_Click goes in a .bas module). Note that this is pretty old
    code. The memory access stuff is a lot cleaner with the ArrayOwner construct
    described in my book. -Matt

    Option Explicit
    Private Sub Command1_Click()
    Dim LB As ListBox
    Dim hHook As Long
    hHook = SetWindowsHookEx(WH_CBT, AddressOf CBTProc, 0, App.ThreadID)
    Set LB = Controls.Add("VB.ListBox", "ListBox1")
    UnhookWindowsHookEx hHook
    LB.Visible = True
    'MultiSelect and Sorted properties don't reflect true state, but
    'control acts properly.
    Debug.Print LB.hWnd, Hex$(GetWindowLong(LB.hWnd, GWL_STYLE)),
    LB.MultiSelect, LB.Sorted
    LB.AddItem "Second"
    LB.AddItem "First"
    End Sub

    Option Explicit

    Public Declare Function SetWindowsHookEx Lib "user32" Alias
    "SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, ByVal hMod As
    Long, ByVal dwThreadID As Long) As Long
    Public Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As
    Long) As Long
    Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA"
    (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
    Public Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA"
    (ByVal hWnd As Long, ByVal nIndex As Long) As Long

    Public Const WH_CBT As Long = 5
    Public Const HCBT_CREATEWND As Long = 3
    Public Const GWL_STYLE As Long = -16
    Public Type CBT_CREATEWNDA
    lpcs As Long
    hwndInsertAfter As Long
    End Type
    Public Type CREATESTRUCTA
    lpCreateParams As Long
    hInstance As Long
    hMenu As Long
    hwndParent As Long
    cy As Long
    cx As Long
    y As Long
    x As Long
    Style As Long
    lpszName As Long
    lpszClass As Long
    dwExStyle As Long
    End Type

    Public Type SafeArray1D
    cDims As Integer
    fFeatures As Integer
    cbElements As Long
    cLocks As Long
    pvData As Long
    cElements As Long
    lLbound As Long
    End Type

    'VarPtrArray gets a pointer to the SAFEARRAY pointer
    Public Declare Function VarPtrArray Lib "msvbvm60.dll" Alias "VarPtr" (Ptr()
    As Any) As Long
    Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDest As
    Any, pSrc As Any, ByVal ByteLen As Long)
    Public Declare Sub ZeroMemory Lib "kernel32" Alias "RtlZeroMemory" (pDest As
    Any, ByVal ByteLen As Long)

    Public Sub ShareMemoryViaArray(ByVal ArrayPtr As Long, ByVal MemPtr As Long,
    SA1D As SafeArray1D, Optional ByVal ElemByteLen As Long)
    With SA1D
    'This is optional because this is a 1 element array,
    'so cbElements is not needed to walk the array. If Erase
    'is called on an array with .cbElements = 0, VB will still
    'free all pointer types, but non-pointer types will not get
    'zeroed out. Note that the compiler calculates the length
    'of a structure at compile time, so LenB(MyStruct(0)) is
    'valid regardless of whether or not MyStruct is actually allocated.
    .cbElements = ElemByteLen
    .cDims = 1
    '2 = FADF_STATIC. This means that if the
    'array goes out of scope, then the pointed
    'to memory will be cleaned, but no attempt
    'will be made to free the array pointer
    'or descriptor.
    .fFeatures = 2
    .pvData = MemPtr
    .cElements = 1
    End With
    CopyMemory ByVal ArrayPtr, VarPtr(SA1D), 4
    End Sub

    Function CBTProc(ByVal lMsg As Long, ByVal wParam As Long, ByVal lParam As
    Long) As Long
    Dim saCreateWnd As SafeArray1D
    Dim psaCreateWnd() As CBT_CREATEWNDA
    Dim saCreateStruct As SafeArray1D
    Dim psaCreateStruct() As CREATESTRUCTA
    If lMsg = HCBT_CREATEWND Then
    ShareMemoryViaArray VarPtrArray(psaCreateWnd), lParam, saCreateWnd
    ShareMemoryViaArray VarPtrArray(psaCreateStruct),
    psaCreateWnd(0).lpcs, saCreateStruct
    'Changing the style in the CreateStruct is insufficient.
    SetWindowLong is required.
    'Note that the changes don't automatically show up in the pointed to
    structures.
    'Make the LB multiselect and sorted. This is LBS_SORT Or
    LBS_MULTIPLESEL
    SetWindowLong wParam, GWL_STYLE, psaCreateStruct(0).Style Or &HA
    ZeroMemory ByVal VarPtrArray(psaCreateStruct), 4
    ZeroMemory ByVal VarPtrArray(psaCreateWnd), 4
    End If
    End Function


    "Chris Brown" <christopherbrown@halifax.co.uk> wrote in message
    news:3b4bfa54$1@news.devx.com...
    >
    > Thanks for that Matt - I guess I knew in advance that it was unlikely -

    just
    > needed a guru to tell me I suppose!!!
    >
    > I was originally trying to show a VB form on top of all other forms - I'm
    > actually creating a new 'combo box' ACTIVEX control that uses a list box
    > with the TABSTOPS style set so that we can have multiple columns. I was

    displaying
    > the form and using SETPARENT function to move the list box from the

    ACTIVEX
    > control onto the form (this was to get around problems of the control

    being
    > bound by a container control like a frame and only displaying half of the
    > list box if the frame was small - using the form allowed the list box to
    > appear 'outside' the frame!)
    >
    > This worked fine on forms shown normally but became a problem when showing
    > on top of a modal form. I've now started down a new route of using

    CREATEWINDOW
    > to create a new window/form instead of using an internal VB form and I'm
    > gonna see how that goes!!!
    >
    > Many thanks again for your input.
    >
    > "Matthew Curland" <mattcur@microsoft.com> wrote:
    > >This is a dead-end pursuit. A form is made modal by pushing a new message
    > >loop. Essentially, the message loop of your background forms gets very

    few
    > >messages (painting messages would be the most important ones that are let
    > >through). What you're asking is to break out of the message loop that

    showed
    > >the form while it is still showing. Not happening. You need to find a
    > >different approach to your problem. You might start by stating what that
    > >problem is instead of stating a proposed solution. -Matt
    > >
    > >"Chris Brown" <christopherbrown@halifax.co.uk> wrote in message
    > >news:3b4aff6c$1@news.devx.com...
    > >>
    > >> Does anyone know of a way of detecting if a form is modal and, if so,

    > >making
    > >> it modeless?? Assume the form is being opened using the .SHOW method

    along
    > >> with the vbModal constant.
    > >>
    > >> If the modal form CAN be switched off, can it then be switched back on

    > >again???
    > >> What API's (if any) are involved in this?? I can't seem to see anywhere

    > >the
    > >> processes windows goes through to create Modal forms.
    > >>
    > >> Many thanks in advance....

    > >
    > >

    >




  8. #8
    Rob Teixeira Guest

    Re: Modal forms


    I don't know if there's a problem with this, but couldn't you simply use SetParent
    on the usercontrol, and set it's parent to the Desktop hwnd in order to make
    it "float"?

    -Rob

    "Matthew Curland" <mattcur@microsoft.com> wrote:
    >You're probably best off starting with a normal combobox. The window-on-top
    >functionality sounds like the hardest part of what you're trying to do,

    and
    >this is already built into the combo.
    >
    >There are two approaches here:
    >1) Use CreateWindowEx. I'd strongly recommend that you start with the
    >CreateWindowEx code in my book to do this. Otherwise, you'll have lots of
    >problems with accelerators that will take a very long time to clear up.

    The
    >main point of doing this is to enable you to set the combobox style to
    >CBS_OWNERDRAWFIXED. This will then let you draw your own text. You might
    >want to start the drawing code with the SubClass\DrawItem stuff in the book.
    >
    >2) Use a CBTHook and either Load on a control array or Controls.Add to
    >change the style of a VB combobox behind VB's back, then put a subclass

    in
    >place for WM_DRAWITEM on the parent. There are a few things to note when
    >doing this. First, VB doesn't know you made this change, so the VB control
    >properties will not necessarily reflect what you did to the underlying
    >control. For example, you can change a listbox to MultiSelect using this
    >technique, but you have to use the API instead of Selected to read the
    >selection. Second, changing the style bits in the CREATESTRUCTA you receive
    >during the HCBT_CREATEWND hook notification is not sufficient to change

    the
    >style bits in the window, you need to change these explicitly with
    >SetWindowLong GWL_STYLE.
    >
    >2 is probably the easiest approach. All you'll have to do is handle the
    >WM_DRAWITEM messages and VB will take care of the rest. I have a very raw
    >sample lying around that does this. There isn't much code to do this, I'll
    >paste in a sample below (runs on a form with a single command button. all
    >but Command1_Click goes in a .bas module). Note that this is pretty old
    >code. The memory access stuff is a lot cleaner with the ArrayOwner construct
    >described in my book. -Matt
    >
    >Option Explicit
    >Private Sub Command1_Click()
    >Dim LB As ListBox
    >Dim hHook As Long
    > hHook = SetWindowsHookEx(WH_CBT, AddressOf CBTProc, 0, App.ThreadID)
    > Set LB = Controls.Add("VB.ListBox", "ListBox1")
    > UnhookWindowsHookEx hHook
    > LB.Visible = True
    > 'MultiSelect and Sorted properties don't reflect true state, but
    > 'control acts properly.
    > Debug.Print LB.hWnd, Hex$(GetWindowLong(LB.hWnd, GWL_STYLE)),
    >LB.MultiSelect, LB.Sorted
    > LB.AddItem "Second"
    > LB.AddItem "First"
    >End Sub
    >
    >Option Explicit
    >
    >Public Declare Function SetWindowsHookEx Lib "user32" Alias
    >"SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, ByVal hMod

    As
    >Long, ByVal dwThreadID As Long) As Long
    >Public Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As
    >Long) As Long
    >Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA"
    >(ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
    >Public Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA"
    >(ByVal hWnd As Long, ByVal nIndex As Long) As Long
    >
    >Public Const WH_CBT As Long = 5
    >Public Const HCBT_CREATEWND As Long = 3
    >Public Const GWL_STYLE As Long = -16
    >Public Type CBT_CREATEWNDA
    > lpcs As Long
    > hwndInsertAfter As Long
    >End Type
    >Public Type CREATESTRUCTA
    > lpCreateParams As Long
    > hInstance As Long
    > hMenu As Long
    > hwndParent As Long
    > cy As Long
    > cx As Long
    > y As Long
    > x As Long
    > Style As Long
    > lpszName As Long
    > lpszClass As Long
    > dwExStyle As Long
    >End Type
    >
    >Public Type SafeArray1D
    > cDims As Integer
    > fFeatures As Integer
    > cbElements As Long
    > cLocks As Long
    > pvData As Long
    > cElements As Long
    > lLbound As Long
    >End Type
    >
    >'VarPtrArray gets a pointer to the SAFEARRAY pointer
    >Public Declare Function VarPtrArray Lib "msvbvm60.dll" Alias "VarPtr" (Ptr()
    >As Any) As Long
    >Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDest

    As
    >Any, pSrc As Any, ByVal ByteLen As Long)
    >Public Declare Sub ZeroMemory Lib "kernel32" Alias "RtlZeroMemory" (pDest

    As
    >Any, ByVal ByteLen As Long)
    >
    >Public Sub ShareMemoryViaArray(ByVal ArrayPtr As Long, ByVal MemPtr As Long,
    >SA1D As SafeArray1D, Optional ByVal ElemByteLen As Long)
    > With SA1D
    > 'This is optional because this is a 1 element array,
    > 'so cbElements is not needed to walk the array. If Erase
    > 'is called on an array with .cbElements = 0, VB will still
    > 'free all pointer types, but non-pointer types will not get
    > 'zeroed out. Note that the compiler calculates the length
    > 'of a structure at compile time, so LenB(MyStruct(0)) is
    > 'valid regardless of whether or not MyStruct is actually allocated.
    > .cbElements = ElemByteLen
    > .cDims = 1
    > '2 = FADF_STATIC. This means that if the
    > 'array goes out of scope, then the pointed
    > 'to memory will be cleaned, but no attempt
    > 'will be made to free the array pointer
    > 'or descriptor.
    > .fFeatures = 2
    > .pvData = MemPtr
    > .cElements = 1
    > End With
    > CopyMemory ByVal ArrayPtr, VarPtr(SA1D), 4
    >End Sub
    >
    >Function CBTProc(ByVal lMsg As Long, ByVal wParam As Long, ByVal lParam

    As
    >Long) As Long
    >Dim saCreateWnd As SafeArray1D
    >Dim psaCreateWnd() As CBT_CREATEWNDA
    >Dim saCreateStruct As SafeArray1D
    >Dim psaCreateStruct() As CREATESTRUCTA
    > If lMsg = HCBT_CREATEWND Then
    > ShareMemoryViaArray VarPtrArray(psaCreateWnd), lParam, saCreateWnd
    > ShareMemoryViaArray VarPtrArray(psaCreateStruct),
    >psaCreateWnd(0).lpcs, saCreateStruct
    > 'Changing the style in the CreateStruct is insufficient.
    >SetWindowLong is required.
    > 'Note that the changes don't automatically show up in the pointed

    to
    >structures.
    > 'Make the LB multiselect and sorted. This is LBS_SORT Or
    >LBS_MULTIPLESEL
    > SetWindowLong wParam, GWL_STYLE, psaCreateStruct(0).Style Or &HA
    > ZeroMemory ByVal VarPtrArray(psaCreateStruct), 4
    > ZeroMemory ByVal VarPtrArray(psaCreateWnd), 4
    > End If
    >End Function
    >
    >
    >"Chris Brown" <christopherbrown@halifax.co.uk> wrote in message
    >news:3b4bfa54$1@news.devx.com...
    >>
    >> Thanks for that Matt - I guess I knew in advance that it was unlikely

    -
    >just
    >> needed a guru to tell me I suppose!!!
    >>
    >> I was originally trying to show a VB form on top of all other forms -

    I'm
    >> actually creating a new 'combo box' ACTIVEX control that uses a list box
    >> with the TABSTOPS style set so that we can have multiple columns. I was

    >displaying
    >> the form and using SETPARENT function to move the list box from the

    >ACTIVEX
    >> control onto the form (this was to get around problems of the control

    >being
    >> bound by a container control like a frame and only displaying half of

    the
    >> list box if the frame was small - using the form allowed the list box

    to
    >> appear 'outside' the frame!)
    >>
    >> This worked fine on forms shown normally but became a problem when showing
    >> on top of a modal form. I've now started down a new route of using

    >CREATEWINDOW
    >> to create a new window/form instead of using an internal VB form and I'm
    >> gonna see how that goes!!!
    >>
    >> Many thanks again for your input.
    >>
    >> "Matthew Curland" <mattcur@microsoft.com> wrote:
    >> >This is a dead-end pursuit. A form is made modal by pushing a new message
    >> >loop. Essentially, the message loop of your background forms gets very

    >few
    >> >messages (painting messages would be the most important ones that are

    let
    >> >through). What you're asking is to break out of the message loop that

    >showed
    >> >the form while it is still showing. Not happening. You need to find a
    >> >different approach to your problem. You might start by stating what that
    >> >problem is instead of stating a proposed solution. -Matt
    >> >
    >> >"Chris Brown" <christopherbrown@halifax.co.uk> wrote in message
    >> >news:3b4aff6c$1@news.devx.com...
    >> >>
    >> >> Does anyone know of a way of detecting if a form is modal and, if so,
    >> >making
    >> >> it modeless?? Assume the form is being opened using the .SHOW method

    >along
    >> >> with the vbModal constant.
    >> >>
    >> >> If the modal form CAN be switched off, can it then be switched back

    on
    >> >again???
    >> >> What API's (if any) are involved in this?? I can't seem to see anywhere
    >> >the
    >> >> processes windows goes through to create Modal forms.
    >> >>
    >> >> Many thanks in advance....
    >> >
    >> >

    >>

    >
    >



  9. #9
    Rob Teixeira Guest

    Re: Modal forms


    I don't know if there's a problem with this, but couldn't you simply use SetParent
    on the usercontrol, and set it's parent to the Desktop hwnd in order to make
    it "float"?

    -Rob

    "Matthew Curland" <mattcur@microsoft.com> wrote:
    >You're probably best off starting with a normal combobox. The window-on-top
    >functionality sounds like the hardest part of what you're trying to do,

    and
    >this is already built into the combo.
    >
    >There are two approaches here:
    >1) Use CreateWindowEx. I'd strongly recommend that you start with the
    >CreateWindowEx code in my book to do this. Otherwise, you'll have lots of
    >problems with accelerators that will take a very long time to clear up.

    The
    >main point of doing this is to enable you to set the combobox style to
    >CBS_OWNERDRAWFIXED. This will then let you draw your own text. You might
    >want to start the drawing code with the SubClass\DrawItem stuff in the book.
    >
    >2) Use a CBTHook and either Load on a control array or Controls.Add to
    >change the style of a VB combobox behind VB's back, then put a subclass

    in
    >place for WM_DRAWITEM on the parent. There are a few things to note when
    >doing this. First, VB doesn't know you made this change, so the VB control
    >properties will not necessarily reflect what you did to the underlying
    >control. For example, you can change a listbox to MultiSelect using this
    >technique, but you have to use the API instead of Selected to read the
    >selection. Second, changing the style bits in the CREATESTRUCTA you receive
    >during the HCBT_CREATEWND hook notification is not sufficient to change

    the
    >style bits in the window, you need to change these explicitly with
    >SetWindowLong GWL_STYLE.
    >
    >2 is probably the easiest approach. All you'll have to do is handle the
    >WM_DRAWITEM messages and VB will take care of the rest. I have a very raw
    >sample lying around that does this. There isn't much code to do this, I'll
    >paste in a sample below (runs on a form with a single command button. all
    >but Command1_Click goes in a .bas module). Note that this is pretty old
    >code. The memory access stuff is a lot cleaner with the ArrayOwner construct
    >described in my book. -Matt
    >
    >Option Explicit
    >Private Sub Command1_Click()
    >Dim LB As ListBox
    >Dim hHook As Long
    > hHook = SetWindowsHookEx(WH_CBT, AddressOf CBTProc, 0, App.ThreadID)
    > Set LB = Controls.Add("VB.ListBox", "ListBox1")
    > UnhookWindowsHookEx hHook
    > LB.Visible = True
    > 'MultiSelect and Sorted properties don't reflect true state, but
    > 'control acts properly.
    > Debug.Print LB.hWnd, Hex$(GetWindowLong(LB.hWnd, GWL_STYLE)),
    >LB.MultiSelect, LB.Sorted
    > LB.AddItem "Second"
    > LB.AddItem "First"
    >End Sub
    >
    >Option Explicit
    >
    >Public Declare Function SetWindowsHookEx Lib "user32" Alias
    >"SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, ByVal hMod

    As
    >Long, ByVal dwThreadID As Long) As Long
    >Public Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As
    >Long) As Long
    >Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA"
    >(ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
    >Public Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA"
    >(ByVal hWnd As Long, ByVal nIndex As Long) As Long
    >
    >Public Const WH_CBT As Long = 5
    >Public Const HCBT_CREATEWND As Long = 3
    >Public Const GWL_STYLE As Long = -16
    >Public Type CBT_CREATEWNDA
    > lpcs As Long
    > hwndInsertAfter As Long
    >End Type
    >Public Type CREATESTRUCTA
    > lpCreateParams As Long
    > hInstance As Long
    > hMenu As Long
    > hwndParent As Long
    > cy As Long
    > cx As Long
    > y As Long
    > x As Long
    > Style As Long
    > lpszName As Long
    > lpszClass As Long
    > dwExStyle As Long
    >End Type
    >
    >Public Type SafeArray1D
    > cDims As Integer
    > fFeatures As Integer
    > cbElements As Long
    > cLocks As Long
    > pvData As Long
    > cElements As Long
    > lLbound As Long
    >End Type
    >
    >'VarPtrArray gets a pointer to the SAFEARRAY pointer
    >Public Declare Function VarPtrArray Lib "msvbvm60.dll" Alias "VarPtr" (Ptr()
    >As Any) As Long
    >Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDest

    As
    >Any, pSrc As Any, ByVal ByteLen As Long)
    >Public Declare Sub ZeroMemory Lib "kernel32" Alias "RtlZeroMemory" (pDest

    As
    >Any, ByVal ByteLen As Long)
    >
    >Public Sub ShareMemoryViaArray(ByVal ArrayPtr As Long, ByVal MemPtr As Long,
    >SA1D As SafeArray1D, Optional ByVal ElemByteLen As Long)
    > With SA1D
    > 'This is optional because this is a 1 element array,
    > 'so cbElements is not needed to walk the array. If Erase
    > 'is called on an array with .cbElements = 0, VB will still
    > 'free all pointer types, but non-pointer types will not get
    > 'zeroed out. Note that the compiler calculates the length
    > 'of a structure at compile time, so LenB(MyStruct(0)) is
    > 'valid regardless of whether or not MyStruct is actually allocated.
    > .cbElements = ElemByteLen
    > .cDims = 1
    > '2 = FADF_STATIC. This means that if the
    > 'array goes out of scope, then the pointed
    > 'to memory will be cleaned, but no attempt
    > 'will be made to free the array pointer
    > 'or descriptor.
    > .fFeatures = 2
    > .pvData = MemPtr
    > .cElements = 1
    > End With
    > CopyMemory ByVal ArrayPtr, VarPtr(SA1D), 4
    >End Sub
    >
    >Function CBTProc(ByVal lMsg As Long, ByVal wParam As Long, ByVal lParam

    As
    >Long) As Long
    >Dim saCreateWnd As SafeArray1D
    >Dim psaCreateWnd() As CBT_CREATEWNDA
    >Dim saCreateStruct As SafeArray1D
    >Dim psaCreateStruct() As CREATESTRUCTA
    > If lMsg = HCBT_CREATEWND Then
    > ShareMemoryViaArray VarPtrArray(psaCreateWnd), lParam, saCreateWnd
    > ShareMemoryViaArray VarPtrArray(psaCreateStruct),
    >psaCreateWnd(0).lpcs, saCreateStruct
    > 'Changing the style in the CreateStruct is insufficient.
    >SetWindowLong is required.
    > 'Note that the changes don't automatically show up in the pointed

    to
    >structures.
    > 'Make the LB multiselect and sorted. This is LBS_SORT Or
    >LBS_MULTIPLESEL
    > SetWindowLong wParam, GWL_STYLE, psaCreateStruct(0).Style Or &HA
    > ZeroMemory ByVal VarPtrArray(psaCreateStruct), 4
    > ZeroMemory ByVal VarPtrArray(psaCreateWnd), 4
    > End If
    >End Function
    >
    >
    >"Chris Brown" <christopherbrown@halifax.co.uk> wrote in message
    >news:3b4bfa54$1@news.devx.com...
    >>
    >> Thanks for that Matt - I guess I knew in advance that it was unlikely

    -
    >just
    >> needed a guru to tell me I suppose!!!
    >>
    >> I was originally trying to show a VB form on top of all other forms -

    I'm
    >> actually creating a new 'combo box' ACTIVEX control that uses a list box
    >> with the TABSTOPS style set so that we can have multiple columns. I was

    >displaying
    >> the form and using SETPARENT function to move the list box from the

    >ACTIVEX
    >> control onto the form (this was to get around problems of the control

    >being
    >> bound by a container control like a frame and only displaying half of

    the
    >> list box if the frame was small - using the form allowed the list box

    to
    >> appear 'outside' the frame!)
    >>
    >> This worked fine on forms shown normally but became a problem when showing
    >> on top of a modal form. I've now started down a new route of using

    >CREATEWINDOW
    >> to create a new window/form instead of using an internal VB form and I'm
    >> gonna see how that goes!!!
    >>
    >> Many thanks again for your input.
    >>
    >> "Matthew Curland" <mattcur@microsoft.com> wrote:
    >> >This is a dead-end pursuit. A form is made modal by pushing a new message
    >> >loop. Essentially, the message loop of your background forms gets very

    >few
    >> >messages (painting messages would be the most important ones that are

    let
    >> >through). What you're asking is to break out of the message loop that

    >showed
    >> >the form while it is still showing. Not happening. You need to find a
    >> >different approach to your problem. You might start by stating what that
    >> >problem is instead of stating a proposed solution. -Matt
    >> >
    >> >"Chris Brown" <christopherbrown@halifax.co.uk> wrote in message
    >> >news:3b4aff6c$1@news.devx.com...
    >> >>
    >> >> Does anyone know of a way of detecting if a form is modal and, if so,
    >> >making
    >> >> it modeless?? Assume the form is being opened using the .SHOW method

    >along
    >> >> with the vbModal constant.
    >> >>
    >> >> If the modal form CAN be switched off, can it then be switched back

    on
    >> >again???
    >> >> What API's (if any) are involved in this?? I can't seem to see anywhere
    >> >the
    >> >> processes windows goes through to create Modal forms.
    >> >>
    >> >> Many thanks in advance....
    >> >
    >> >

    >>

    >
    >



  10. #10
    Chris Brown Guest

    Re: Modal forms


    Thanks Rob. Matt, do you have any thoughts on this?? WOuld it work?? Would
    there be a lot of problems with re-positioning the control when moving from
    one parent to another??

    Your thoughts would be appreciated...

    Thanks - Chris

    "Rob Teixeira" <RobTeixeira@@msn.com> wrote:
    >
    >I don't know if there's a problem with this, but couldn't you simply use

    SetParent
    >on the usercontrol, and set it's parent to the Desktop hwnd in order to

    make
    >it "float"?
    >
    >-Rob
    >
    >"Matthew Curland" <mattcur@microsoft.com> wrote:
    >>You're probably best off starting with a normal combobox. The window-on-top
    >>functionality sounds like the hardest part of what you're trying to do,

    >and
    >>this is already built into the combo.
    >>
    >>There are two approaches here:
    >>1) Use CreateWindowEx. I'd strongly recommend that you start with the
    >>CreateWindowEx code in my book to do this. Otherwise, you'll have lots

    of
    >>problems with accelerators that will take a very long time to clear up.

    >The
    >>main point of doing this is to enable you to set the combobox style to
    >>CBS_OWNERDRAWFIXED. This will then let you draw your own text. You might
    >>want to start the drawing code with the SubClass\DrawItem stuff in the

    book.
    >>
    >>2) Use a CBTHook and either Load on a control array or Controls.Add to
    >>change the style of a VB combobox behind VB's back, then put a subclass

    >in
    >>place for WM_DRAWITEM on the parent. There are a few things to note when
    >>doing this. First, VB doesn't know you made this change, so the VB control
    >>properties will not necessarily reflect what you did to the underlying
    >>control. For example, you can change a listbox to MultiSelect using this
    >>technique, but you have to use the API instead of Selected to read the
    >>selection. Second, changing the style bits in the CREATESTRUCTA you receive
    >>during the HCBT_CREATEWND hook notification is not sufficient to change

    >the
    >>style bits in the window, you need to change these explicitly with
    >>SetWindowLong GWL_STYLE.
    >>
    >>2 is probably the easiest approach. All you'll have to do is handle the
    >>WM_DRAWITEM messages and VB will take care of the rest. I have a very raw
    >>sample lying around that does this. There isn't much code to do this, I'll
    >>paste in a sample below (runs on a form with a single command button. all
    >>but Command1_Click goes in a .bas module). Note that this is pretty old
    >>code. The memory access stuff is a lot cleaner with the ArrayOwner construct
    >>described in my book. -Matt
    >>
    >>Option Explicit
    >>Private Sub Command1_Click()
    >>Dim LB As ListBox
    >>Dim hHook As Long
    >> hHook = SetWindowsHookEx(WH_CBT, AddressOf CBTProc, 0, App.ThreadID)
    >> Set LB = Controls.Add("VB.ListBox", "ListBox1")
    >> UnhookWindowsHookEx hHook
    >> LB.Visible = True
    >> 'MultiSelect and Sorted properties don't reflect true state, but
    >> 'control acts properly.
    >> Debug.Print LB.hWnd, Hex$(GetWindowLong(LB.hWnd, GWL_STYLE)),
    >>LB.MultiSelect, LB.Sorted
    >> LB.AddItem "Second"
    >> LB.AddItem "First"
    >>End Sub
    >>
    >>Option Explicit
    >>
    >>Public Declare Function SetWindowsHookEx Lib "user32" Alias
    >>"SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, ByVal hMod

    >As
    >>Long, ByVal dwThreadID As Long) As Long
    >>Public Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As
    >>Long) As Long
    >>Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA"
    >>(ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As

    Long
    >>Public Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA"
    >>(ByVal hWnd As Long, ByVal nIndex As Long) As Long
    >>
    >>Public Const WH_CBT As Long = 5
    >>Public Const HCBT_CREATEWND As Long = 3
    >>Public Const GWL_STYLE As Long = -16
    >>Public Type CBT_CREATEWNDA
    >> lpcs As Long
    >> hwndInsertAfter As Long
    >>End Type
    >>Public Type CREATESTRUCTA
    >> lpCreateParams As Long
    >> hInstance As Long
    >> hMenu As Long
    >> hwndParent As Long
    >> cy As Long
    >> cx As Long
    >> y As Long
    >> x As Long
    >> Style As Long
    >> lpszName As Long
    >> lpszClass As Long
    >> dwExStyle As Long
    >>End Type
    >>
    >>Public Type SafeArray1D
    >> cDims As Integer
    >> fFeatures As Integer
    >> cbElements As Long
    >> cLocks As Long
    >> pvData As Long
    >> cElements As Long
    >> lLbound As Long
    >>End Type
    >>
    >>'VarPtrArray gets a pointer to the SAFEARRAY pointer
    >>Public Declare Function VarPtrArray Lib "msvbvm60.dll" Alias "VarPtr" (Ptr()
    >>As Any) As Long
    >>Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDest

    >As
    >>Any, pSrc As Any, ByVal ByteLen As Long)
    >>Public Declare Sub ZeroMemory Lib "kernel32" Alias "RtlZeroMemory" (pDest

    >As
    >>Any, ByVal ByteLen As Long)
    >>
    >>Public Sub ShareMemoryViaArray(ByVal ArrayPtr As Long, ByVal MemPtr As

    Long,
    >>SA1D As SafeArray1D, Optional ByVal ElemByteLen As Long)
    >> With SA1D
    >> 'This is optional because this is a 1 element array,
    >> 'so cbElements is not needed to walk the array. If Erase
    >> 'is called on an array with .cbElements = 0, VB will still
    >> 'free all pointer types, but non-pointer types will not get
    >> 'zeroed out. Note that the compiler calculates the length
    >> 'of a structure at compile time, so LenB(MyStruct(0)) is
    >> 'valid regardless of whether or not MyStruct is actually allocated.
    >> .cbElements = ElemByteLen
    >> .cDims = 1
    >> '2 = FADF_STATIC. This means that if the
    >> 'array goes out of scope, then the pointed
    >> 'to memory will be cleaned, but no attempt
    >> 'will be made to free the array pointer
    >> 'or descriptor.
    >> .fFeatures = 2
    >> .pvData = MemPtr
    >> .cElements = 1
    >> End With
    >> CopyMemory ByVal ArrayPtr, VarPtr(SA1D), 4
    >>End Sub
    >>
    >>Function CBTProc(ByVal lMsg As Long, ByVal wParam As Long, ByVal lParam

    >As
    >>Long) As Long
    >>Dim saCreateWnd As SafeArray1D
    >>Dim psaCreateWnd() As CBT_CREATEWNDA
    >>Dim saCreateStruct As SafeArray1D
    >>Dim psaCreateStruct() As CREATESTRUCTA
    >> If lMsg = HCBT_CREATEWND Then
    >> ShareMemoryViaArray VarPtrArray(psaCreateWnd), lParam, saCreateWnd
    >> ShareMemoryViaArray VarPtrArray(psaCreateStruct),
    >>psaCreateWnd(0).lpcs, saCreateStruct
    >> 'Changing the style in the CreateStruct is insufficient.
    >>SetWindowLong is required.
    >> 'Note that the changes don't automatically show up in the pointed

    >to
    >>structures.
    >> 'Make the LB multiselect and sorted. This is LBS_SORT Or
    >>LBS_MULTIPLESEL
    >> SetWindowLong wParam, GWL_STYLE, psaCreateStruct(0).Style Or &HA
    >> ZeroMemory ByVal VarPtrArray(psaCreateStruct), 4
    >> ZeroMemory ByVal VarPtrArray(psaCreateWnd), 4
    >> End If
    >>End Function
    >>
    >>
    >>"Chris Brown" <christopherbrown@halifax.co.uk> wrote in message
    >>news:3b4bfa54$1@news.devx.com...
    >>>
    >>> Thanks for that Matt - I guess I knew in advance that it was unlikely

    >-
    >>just
    >>> needed a guru to tell me I suppose!!!
    >>>
    >>> I was originally trying to show a VB form on top of all other forms -

    >I'm
    >>> actually creating a new 'combo box' ACTIVEX control that uses a list

    box
    >>> with the TABSTOPS style set so that we can have multiple columns. I was

    >>displaying
    >>> the form and using SETPARENT function to move the list box from the

    >>ACTIVEX
    >>> control onto the form (this was to get around problems of the control

    >>being
    >>> bound by a container control like a frame and only displaying half of

    >the
    >>> list box if the frame was small - using the form allowed the list box

    >to
    >>> appear 'outside' the frame!)
    >>>
    >>> This worked fine on forms shown normally but became a problem when showing
    >>> on top of a modal form. I've now started down a new route of using

    >>CREATEWINDOW
    >>> to create a new window/form instead of using an internal VB form and

    I'm
    >>> gonna see how that goes!!!
    >>>
    >>> Many thanks again for your input.
    >>>
    >>> "Matthew Curland" <mattcur@microsoft.com> wrote:
    >>> >This is a dead-end pursuit. A form is made modal by pushing a new message
    >>> >loop. Essentially, the message loop of your background forms gets very

    >>few
    >>> >messages (painting messages would be the most important ones that are

    >let
    >>> >through). What you're asking is to break out of the message loop that

    >>showed
    >>> >the form while it is still showing. Not happening. You need to find

    a
    >>> >different approach to your problem. You might start by stating what

    that
    >>> >problem is instead of stating a proposed solution. -Matt
    >>> >
    >>> >"Chris Brown" <christopherbrown@halifax.co.uk> wrote in message
    >>> >news:3b4aff6c$1@news.devx.com...
    >>> >>
    >>> >> Does anyone know of a way of detecting if a form is modal and, if

    so,
    >>> >making
    >>> >> it modeless?? Assume the form is being opened using the .SHOW method

    >>along
    >>> >> with the vbModal constant.
    >>> >>
    >>> >> If the modal form CAN be switched off, can it then be switched back

    >on
    >>> >again???
    >>> >> What API's (if any) are involved in this?? I can't seem to see anywhere
    >>> >the
    >>> >> processes windows goes through to create Modal forms.
    >>> >>
    >>> >> Many thanks in advance....
    >>> >
    >>> >
    >>>

    >>
    >>

    >



  11. #11
    Chris Brown Guest

    Re: Modal forms


    Thanks Rob. Matt, do you have any thoughts on this?? WOuld it work?? Would
    there be a lot of problems with re-positioning the control when moving from
    one parent to another??

    Your thoughts would be appreciated...

    Thanks - Chris

    "Rob Teixeira" <RobTeixeira@@msn.com> wrote:
    >
    >I don't know if there's a problem with this, but couldn't you simply use

    SetParent
    >on the usercontrol, and set it's parent to the Desktop hwnd in order to

    make
    >it "float"?
    >
    >-Rob
    >
    >"Matthew Curland" <mattcur@microsoft.com> wrote:
    >>You're probably best off starting with a normal combobox. The window-on-top
    >>functionality sounds like the hardest part of what you're trying to do,

    >and
    >>this is already built into the combo.
    >>
    >>There are two approaches here:
    >>1) Use CreateWindowEx. I'd strongly recommend that you start with the
    >>CreateWindowEx code in my book to do this. Otherwise, you'll have lots

    of
    >>problems with accelerators that will take a very long time to clear up.

    >The
    >>main point of doing this is to enable you to set the combobox style to
    >>CBS_OWNERDRAWFIXED. This will then let you draw your own text. You might
    >>want to start the drawing code with the SubClass\DrawItem stuff in the

    book.
    >>
    >>2) Use a CBTHook and either Load on a control array or Controls.Add to
    >>change the style of a VB combobox behind VB's back, then put a subclass

    >in
    >>place for WM_DRAWITEM on the parent. There are a few things to note when
    >>doing this. First, VB doesn't know you made this change, so the VB control
    >>properties will not necessarily reflect what you did to the underlying
    >>control. For example, you can change a listbox to MultiSelect using this
    >>technique, but you have to use the API instead of Selected to read the
    >>selection. Second, changing the style bits in the CREATESTRUCTA you receive
    >>during the HCBT_CREATEWND hook notification is not sufficient to change

    >the
    >>style bits in the window, you need to change these explicitly with
    >>SetWindowLong GWL_STYLE.
    >>
    >>2 is probably the easiest approach. All you'll have to do is handle the
    >>WM_DRAWITEM messages and VB will take care of the rest. I have a very raw
    >>sample lying around that does this. There isn't much code to do this, I'll
    >>paste in a sample below (runs on a form with a single command button. all
    >>but Command1_Click goes in a .bas module). Note that this is pretty old
    >>code. The memory access stuff is a lot cleaner with the ArrayOwner construct
    >>described in my book. -Matt
    >>
    >>Option Explicit
    >>Private Sub Command1_Click()
    >>Dim LB As ListBox
    >>Dim hHook As Long
    >> hHook = SetWindowsHookEx(WH_CBT, AddressOf CBTProc, 0, App.ThreadID)
    >> Set LB = Controls.Add("VB.ListBox", "ListBox1")
    >> UnhookWindowsHookEx hHook
    >> LB.Visible = True
    >> 'MultiSelect and Sorted properties don't reflect true state, but
    >> 'control acts properly.
    >> Debug.Print LB.hWnd, Hex$(GetWindowLong(LB.hWnd, GWL_STYLE)),
    >>LB.MultiSelect, LB.Sorted
    >> LB.AddItem "Second"
    >> LB.AddItem "First"
    >>End Sub
    >>
    >>Option Explicit
    >>
    >>Public Declare Function SetWindowsHookEx Lib "user32" Alias
    >>"SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, ByVal hMod

    >As
    >>Long, ByVal dwThreadID As Long) As Long
    >>Public Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As
    >>Long) As Long
    >>Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA"
    >>(ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As

    Long
    >>Public Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA"
    >>(ByVal hWnd As Long, ByVal nIndex As Long) As Long
    >>
    >>Public Const WH_CBT As Long = 5
    >>Public Const HCBT_CREATEWND As Long = 3
    >>Public Const GWL_STYLE As Long = -16
    >>Public Type CBT_CREATEWNDA
    >> lpcs As Long
    >> hwndInsertAfter As Long
    >>End Type
    >>Public Type CREATESTRUCTA
    >> lpCreateParams As Long
    >> hInstance As Long
    >> hMenu As Long
    >> hwndParent As Long
    >> cy As Long
    >> cx As Long
    >> y As Long
    >> x As Long
    >> Style As Long
    >> lpszName As Long
    >> lpszClass As Long
    >> dwExStyle As Long
    >>End Type
    >>
    >>Public Type SafeArray1D
    >> cDims As Integer
    >> fFeatures As Integer
    >> cbElements As Long
    >> cLocks As Long
    >> pvData As Long
    >> cElements As Long
    >> lLbound As Long
    >>End Type
    >>
    >>'VarPtrArray gets a pointer to the SAFEARRAY pointer
    >>Public Declare Function VarPtrArray Lib "msvbvm60.dll" Alias "VarPtr" (Ptr()
    >>As Any) As Long
    >>Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDest

    >As
    >>Any, pSrc As Any, ByVal ByteLen As Long)
    >>Public Declare Sub ZeroMemory Lib "kernel32" Alias "RtlZeroMemory" (pDest

    >As
    >>Any, ByVal ByteLen As Long)
    >>
    >>Public Sub ShareMemoryViaArray(ByVal ArrayPtr As Long, ByVal MemPtr As

    Long,
    >>SA1D As SafeArray1D, Optional ByVal ElemByteLen As Long)
    >> With SA1D
    >> 'This is optional because this is a 1 element array,
    >> 'so cbElements is not needed to walk the array. If Erase
    >> 'is called on an array with .cbElements = 0, VB will still
    >> 'free all pointer types, but non-pointer types will not get
    >> 'zeroed out. Note that the compiler calculates the length
    >> 'of a structure at compile time, so LenB(MyStruct(0)) is
    >> 'valid regardless of whether or not MyStruct is actually allocated.
    >> .cbElements = ElemByteLen
    >> .cDims = 1
    >> '2 = FADF_STATIC. This means that if the
    >> 'array goes out of scope, then the pointed
    >> 'to memory will be cleaned, but no attempt
    >> 'will be made to free the array pointer
    >> 'or descriptor.
    >> .fFeatures = 2
    >> .pvData = MemPtr
    >> .cElements = 1
    >> End With
    >> CopyMemory ByVal ArrayPtr, VarPtr(SA1D), 4
    >>End Sub
    >>
    >>Function CBTProc(ByVal lMsg As Long, ByVal wParam As Long, ByVal lParam

    >As
    >>Long) As Long
    >>Dim saCreateWnd As SafeArray1D
    >>Dim psaCreateWnd() As CBT_CREATEWNDA
    >>Dim saCreateStruct As SafeArray1D
    >>Dim psaCreateStruct() As CREATESTRUCTA
    >> If lMsg = HCBT_CREATEWND Then
    >> ShareMemoryViaArray VarPtrArray(psaCreateWnd), lParam, saCreateWnd
    >> ShareMemoryViaArray VarPtrArray(psaCreateStruct),
    >>psaCreateWnd(0).lpcs, saCreateStruct
    >> 'Changing the style in the CreateStruct is insufficient.
    >>SetWindowLong is required.
    >> 'Note that the changes don't automatically show up in the pointed

    >to
    >>structures.
    >> 'Make the LB multiselect and sorted. This is LBS_SORT Or
    >>LBS_MULTIPLESEL
    >> SetWindowLong wParam, GWL_STYLE, psaCreateStruct(0).Style Or &HA
    >> ZeroMemory ByVal VarPtrArray(psaCreateStruct), 4
    >> ZeroMemory ByVal VarPtrArray(psaCreateWnd), 4
    >> End If
    >>End Function
    >>
    >>
    >>"Chris Brown" <christopherbrown@halifax.co.uk> wrote in message
    >>news:3b4bfa54$1@news.devx.com...
    >>>
    >>> Thanks for that Matt - I guess I knew in advance that it was unlikely

    >-
    >>just
    >>> needed a guru to tell me I suppose!!!
    >>>
    >>> I was originally trying to show a VB form on top of all other forms -

    >I'm
    >>> actually creating a new 'combo box' ACTIVEX control that uses a list

    box
    >>> with the TABSTOPS style set so that we can have multiple columns. I was

    >>displaying
    >>> the form and using SETPARENT function to move the list box from the

    >>ACTIVEX
    >>> control onto the form (this was to get around problems of the control

    >>being
    >>> bound by a container control like a frame and only displaying half of

    >the
    >>> list box if the frame was small - using the form allowed the list box

    >to
    >>> appear 'outside' the frame!)
    >>>
    >>> This worked fine on forms shown normally but became a problem when showing
    >>> on top of a modal form. I've now started down a new route of using

    >>CREATEWINDOW
    >>> to create a new window/form instead of using an internal VB form and

    I'm
    >>> gonna see how that goes!!!
    >>>
    >>> Many thanks again for your input.
    >>>
    >>> "Matthew Curland" <mattcur@microsoft.com> wrote:
    >>> >This is a dead-end pursuit. A form is made modal by pushing a new message
    >>> >loop. Essentially, the message loop of your background forms gets very

    >>few
    >>> >messages (painting messages would be the most important ones that are

    >let
    >>> >through). What you're asking is to break out of the message loop that

    >>showed
    >>> >the form while it is still showing. Not happening. You need to find

    a
    >>> >different approach to your problem. You might start by stating what

    that
    >>> >problem is instead of stating a proposed solution. -Matt
    >>> >
    >>> >"Chris Brown" <christopherbrown@halifax.co.uk> wrote in message
    >>> >news:3b4aff6c$1@news.devx.com...
    >>> >>
    >>> >> Does anyone know of a way of detecting if a form is modal and, if

    so,
    >>> >making
    >>> >> it modeless?? Assume the form is being opened using the .SHOW method

    >>along
    >>> >> with the vbModal constant.
    >>> >>
    >>> >> If the modal form CAN be switched off, can it then be switched back

    >on
    >>> >again???
    >>> >> What API's (if any) are involved in this?? I can't seem to see anywhere
    >>> >the
    >>> >> processes windows goes through to create Modal forms.
    >>> >>
    >>> >> Many thanks in advance....
    >>> >
    >>> >
    >>>

    >>
    >>

    >



  12. #12
    Bill Slater Guest

    Re: Modal forms

    Try this URL:

    http://www.mvps.org/vbnet/code/subcl...tabbedlist.htm


    Chris Brown wrote:

    > Thanks Rob. Matt, do you have any thoughts on this?? WOuld it work?? Would
    > there be a lot of problems with re-positioning the control when moving from
    > one parent to another??
    >
    > Your thoughts would be appreciated...
    >
    > Thanks - Chris
    >
    > "Rob Teixeira" <RobTeixeira@@msn.com> wrote:
    > >
    > >I don't know if there's a problem with this, but couldn't you simply use

    > SetParent
    > >on the usercontrol, and set it's parent to the Desktop hwnd in order to

    > make
    > >it "float"?
    > >
    > >-Rob
    > >
    > >"Matthew Curland" <mattcur@microsoft.com> wrote:
    > >>You're probably best off starting with a normal combobox. The window-on-top
    > >>functionality sounds like the hardest part of what you're trying to do,

    > >and
    > >>this is already built into the combo.
    > >>
    > >>There are two approaches here:
    > >>1) Use CreateWindowEx. I'd strongly recommend that you start with the
    > >>CreateWindowEx code in my book to do this. Otherwise, you'll have lots

    > of
    > >>problems with accelerators that will take a very long time to clear up.

    > >The
    > >>main point of doing this is to enable you to set the combobox style to
    > >>CBS_OWNERDRAWFIXED. This will then let you draw your own text. You might
    > >>want to start the drawing code with the SubClass\DrawItem stuff in the

    > book.
    > >>
    > >>2) Use a CBTHook and either Load on a control array or Controls.Add to
    > >>change the style of a VB combobox behind VB's back, then put a subclass

    > >in
    > >>place for WM_DRAWITEM on the parent. There are a few things to note when
    > >>doing this. First, VB doesn't know you made this change, so the VB control
    > >>properties will not necessarily reflect what you did to the underlying
    > >>control. For example, you can change a listbox to MultiSelect using this
    > >>technique, but you have to use the API instead of Selected to read the
    > >>selection. Second, changing the style bits in the CREATESTRUCTA you receive
    > >>during the HCBT_CREATEWND hook notification is not sufficient to change

    > >the
    > >>style bits in the window, you need to change these explicitly with
    > >>SetWindowLong GWL_STYLE.
    > >>
    > >>2 is probably the easiest approach. All you'll have to do is handle the
    > >>WM_DRAWITEM messages and VB will take care of the rest. I have a very raw
    > >>sample lying around that does this. There isn't much code to do this, I'll
    > >>paste in a sample below (runs on a form with a single command button. all
    > >>but Command1_Click goes in a .bas module). Note that this is pretty old
    > >>code. The memory access stuff is a lot cleaner with the ArrayOwner construct
    > >>described in my book. -Matt
    > >>
    > >>Option Explicit
    > >>Private Sub Command1_Click()
    > >>Dim LB As ListBox
    > >>Dim hHook As Long
    > >> hHook = SetWindowsHookEx(WH_CBT, AddressOf CBTProc, 0, App.ThreadID)
    > >> Set LB = Controls.Add("VB.ListBox", "ListBox1")
    > >> UnhookWindowsHookEx hHook
    > >> LB.Visible = True
    > >> 'MultiSelect and Sorted properties don't reflect true state, but
    > >> 'control acts properly.
    > >> Debug.Print LB.hWnd, Hex$(GetWindowLong(LB.hWnd, GWL_STYLE)),
    > >>LB.MultiSelect, LB.Sorted
    > >> LB.AddItem "Second"
    > >> LB.AddItem "First"
    > >>End Sub
    > >>
    > >>Option Explicit
    > >>
    > >>Public Declare Function SetWindowsHookEx Lib "user32" Alias
    > >>"SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, ByVal hMod

    > >As
    > >>Long, ByVal dwThreadID As Long) As Long
    > >>Public Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As
    > >>Long) As Long
    > >>Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA"
    > >>(ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As

    > Long
    > >>Public Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA"
    > >>(ByVal hWnd As Long, ByVal nIndex As Long) As Long
    > >>
    > >>Public Const WH_CBT As Long = 5
    > >>Public Const HCBT_CREATEWND As Long = 3
    > >>Public Const GWL_STYLE As Long = -16
    > >>Public Type CBT_CREATEWNDA
    > >> lpcs As Long
    > >> hwndInsertAfter As Long
    > >>End Type
    > >>Public Type CREATESTRUCTA
    > >> lpCreateParams As Long
    > >> hInstance As Long
    > >> hMenu As Long
    > >> hwndParent As Long
    > >> cy As Long
    > >> cx As Long
    > >> y As Long
    > >> x As Long
    > >> Style As Long
    > >> lpszName As Long
    > >> lpszClass As Long
    > >> dwExStyle As Long
    > >>End Type
    > >>
    > >>Public Type SafeArray1D
    > >> cDims As Integer
    > >> fFeatures As Integer
    > >> cbElements As Long
    > >> cLocks As Long
    > >> pvData As Long
    > >> cElements As Long
    > >> lLbound As Long
    > >>End Type
    > >>
    > >>'VarPtrArray gets a pointer to the SAFEARRAY pointer
    > >>Public Declare Function VarPtrArray Lib "msvbvm60.dll" Alias "VarPtr" (Ptr()
    > >>As Any) As Long
    > >>Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDest

    > >As
    > >>Any, pSrc As Any, ByVal ByteLen As Long)
    > >>Public Declare Sub ZeroMemory Lib "kernel32" Alias "RtlZeroMemory" (pDest

    > >As
    > >>Any, ByVal ByteLen As Long)
    > >>
    > >>Public Sub ShareMemoryViaArray(ByVal ArrayPtr As Long, ByVal MemPtr As

    > Long,
    > >>SA1D As SafeArray1D, Optional ByVal ElemByteLen As Long)
    > >> With SA1D
    > >> 'This is optional because this is a 1 element array,
    > >> 'so cbElements is not needed to walk the array. If Erase
    > >> 'is called on an array with .cbElements = 0, VB will still
    > >> 'free all pointer types, but non-pointer types will not get
    > >> 'zeroed out. Note that the compiler calculates the length
    > >> 'of a structure at compile time, so LenB(MyStruct(0)) is
    > >> 'valid regardless of whether or not MyStruct is actually allocated.
    > >> .cbElements = ElemByteLen
    > >> .cDims = 1
    > >> '2 = FADF_STATIC. This means that if the
    > >> 'array goes out of scope, then the pointed
    > >> 'to memory will be cleaned, but no attempt
    > >> 'will be made to free the array pointer
    > >> 'or descriptor.
    > >> .fFeatures = 2
    > >> .pvData = MemPtr
    > >> .cElements = 1
    > >> End With
    > >> CopyMemory ByVal ArrayPtr, VarPtr(SA1D), 4
    > >>End Sub
    > >>
    > >>Function CBTProc(ByVal lMsg As Long, ByVal wParam As Long, ByVal lParam

    > >As
    > >>Long) As Long
    > >>Dim saCreateWnd As SafeArray1D
    > >>Dim psaCreateWnd() As CBT_CREATEWNDA
    > >>Dim saCreateStruct As SafeArray1D
    > >>Dim psaCreateStruct() As CREATESTRUCTA
    > >> If lMsg = HCBT_CREATEWND Then
    > >> ShareMemoryViaArray VarPtrArray(psaCreateWnd), lParam, saCreateWnd
    > >> ShareMemoryViaArray VarPtrArray(psaCreateStruct),
    > >>psaCreateWnd(0).lpcs, saCreateStruct
    > >> 'Changing the style in the CreateStruct is insufficient.
    > >>SetWindowLong is required.
    > >> 'Note that the changes don't automatically show up in the pointed

    > >to
    > >>structures.
    > >> 'Make the LB multiselect and sorted. This is LBS_SORT Or
    > >>LBS_MULTIPLESEL
    > >> SetWindowLong wParam, GWL_STYLE, psaCreateStruct(0).Style Or &HA
    > >> ZeroMemory ByVal VarPtrArray(psaCreateStruct), 4
    > >> ZeroMemory ByVal VarPtrArray(psaCreateWnd), 4
    > >> End If
    > >>End Function
    > >>
    > >>
    > >>"Chris Brown" <christopherbrown@halifax.co.uk> wrote in message
    > >>news:3b4bfa54$1@news.devx.com...
    > >>>
    > >>> Thanks for that Matt - I guess I knew in advance that it was unlikely

    > >-
    > >>just
    > >>> needed a guru to tell me I suppose!!!
    > >>>
    > >>> I was originally trying to show a VB form on top of all other forms -

    > >I'm
    > >>> actually creating a new 'combo box' ACTIVEX control that uses a list

    > box
    > >>> with the TABSTOPS style set so that we can have multiple columns. I was
    > >>displaying
    > >>> the form and using SETPARENT function to move the list box from the
    > >>ACTIVEX
    > >>> control onto the form (this was to get around problems of the control
    > >>being
    > >>> bound by a container control like a frame and only displaying half of

    > >the
    > >>> list box if the frame was small - using the form allowed the list box

    > >to
    > >>> appear 'outside' the frame!)
    > >>>
    > >>> This worked fine on forms shown normally but became a problem when showing
    > >>> on top of a modal form. I've now started down a new route of using
    > >>CREATEWINDOW
    > >>> to create a new window/form instead of using an internal VB form and

    > I'm
    > >>> gonna see how that goes!!!
    > >>>
    > >>> Many thanks again for your input.
    > >>>
    > >>> "Matthew Curland" <mattcur@microsoft.com> wrote:
    > >>> >This is a dead-end pursuit. A form is made modal by pushing a new message
    > >>> >loop. Essentially, the message loop of your background forms gets very
    > >>few
    > >>> >messages (painting messages would be the most important ones that are

    > >let
    > >>> >through). What you're asking is to break out of the message loop that
    > >>showed
    > >>> >the form while it is still showing. Not happening. You need to find

    > a
    > >>> >different approach to your problem. You might start by stating what

    > that
    > >>> >problem is instead of stating a proposed solution. -Matt
    > >>> >
    > >>> >"Chris Brown" <christopherbrown@halifax.co.uk> wrote in message
    > >>> >news:3b4aff6c$1@news.devx.com...
    > >>> >>
    > >>> >> Does anyone know of a way of detecting if a form is modal and, if

    > so,
    > >>> >making
    > >>> >> it modeless?? Assume the form is being opened using the .SHOW method
    > >>along
    > >>> >> with the vbModal constant.
    > >>> >>
    > >>> >> If the modal form CAN be switched off, can it then be switched back

    > >on
    > >>> >again???
    > >>> >> What API's (if any) are involved in this?? I can't seem to see anywhere
    > >>> >the
    > >>> >> processes windows goes through to create Modal forms.
    > >>> >>
    > >>> >> Many thanks in advance....
    > >>> >
    > >>> >
    > >>>
    > >>
    > >>

    > >



  13. #13
    Bill Slater Guest

    Re: Modal forms

    Try this URL:

    http://www.mvps.org/vbnet/code/subcl...tabbedlist.htm


    Chris Brown wrote:

    > Thanks Rob. Matt, do you have any thoughts on this?? WOuld it work?? Would
    > there be a lot of problems with re-positioning the control when moving from
    > one parent to another??
    >
    > Your thoughts would be appreciated...
    >
    > Thanks - Chris
    >
    > "Rob Teixeira" <RobTeixeira@@msn.com> wrote:
    > >
    > >I don't know if there's a problem with this, but couldn't you simply use

    > SetParent
    > >on the usercontrol, and set it's parent to the Desktop hwnd in order to

    > make
    > >it "float"?
    > >
    > >-Rob
    > >
    > >"Matthew Curland" <mattcur@microsoft.com> wrote:
    > >>You're probably best off starting with a normal combobox. The window-on-top
    > >>functionality sounds like the hardest part of what you're trying to do,

    > >and
    > >>this is already built into the combo.
    > >>
    > >>There are two approaches here:
    > >>1) Use CreateWindowEx. I'd strongly recommend that you start with the
    > >>CreateWindowEx code in my book to do this. Otherwise, you'll have lots

    > of
    > >>problems with accelerators that will take a very long time to clear up.

    > >The
    > >>main point of doing this is to enable you to set the combobox style to
    > >>CBS_OWNERDRAWFIXED. This will then let you draw your own text. You might
    > >>want to start the drawing code with the SubClass\DrawItem stuff in the

    > book.
    > >>
    > >>2) Use a CBTHook and either Load on a control array or Controls.Add to
    > >>change the style of a VB combobox behind VB's back, then put a subclass

    > >in
    > >>place for WM_DRAWITEM on the parent. There are a few things to note when
    > >>doing this. First, VB doesn't know you made this change, so the VB control
    > >>properties will not necessarily reflect what you did to the underlying
    > >>control. For example, you can change a listbox to MultiSelect using this
    > >>technique, but you have to use the API instead of Selected to read the
    > >>selection. Second, changing the style bits in the CREATESTRUCTA you receive
    > >>during the HCBT_CREATEWND hook notification is not sufficient to change

    > >the
    > >>style bits in the window, you need to change these explicitly with
    > >>SetWindowLong GWL_STYLE.
    > >>
    > >>2 is probably the easiest approach. All you'll have to do is handle the
    > >>WM_DRAWITEM messages and VB will take care of the rest. I have a very raw
    > >>sample lying around that does this. There isn't much code to do this, I'll
    > >>paste in a sample below (runs on a form with a single command button. all
    > >>but Command1_Click goes in a .bas module). Note that this is pretty old
    > >>code. The memory access stuff is a lot cleaner with the ArrayOwner construct
    > >>described in my book. -Matt
    > >>
    > >>Option Explicit
    > >>Private Sub Command1_Click()
    > >>Dim LB As ListBox
    > >>Dim hHook As Long
    > >> hHook = SetWindowsHookEx(WH_CBT, AddressOf CBTProc, 0, App.ThreadID)
    > >> Set LB = Controls.Add("VB.ListBox", "ListBox1")
    > >> UnhookWindowsHookEx hHook
    > >> LB.Visible = True
    > >> 'MultiSelect and Sorted properties don't reflect true state, but
    > >> 'control acts properly.
    > >> Debug.Print LB.hWnd, Hex$(GetWindowLong(LB.hWnd, GWL_STYLE)),
    > >>LB.MultiSelect, LB.Sorted
    > >> LB.AddItem "Second"
    > >> LB.AddItem "First"
    > >>End Sub
    > >>
    > >>Option Explicit
    > >>
    > >>Public Declare Function SetWindowsHookEx Lib "user32" Alias
    > >>"SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, ByVal hMod

    > >As
    > >>Long, ByVal dwThreadID As Long) As Long
    > >>Public Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As
    > >>Long) As Long
    > >>Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA"
    > >>(ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As

    > Long
    > >>Public Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA"
    > >>(ByVal hWnd As Long, ByVal nIndex As Long) As Long
    > >>
    > >>Public Const WH_CBT As Long = 5
    > >>Public Const HCBT_CREATEWND As Long = 3
    > >>Public Const GWL_STYLE As Long = -16
    > >>Public Type CBT_CREATEWNDA
    > >> lpcs As Long
    > >> hwndInsertAfter As Long
    > >>End Type
    > >>Public Type CREATESTRUCTA
    > >> lpCreateParams As Long
    > >> hInstance As Long
    > >> hMenu As Long
    > >> hwndParent As Long
    > >> cy As Long
    > >> cx As Long
    > >> y As Long
    > >> x As Long
    > >> Style As Long
    > >> lpszName As Long
    > >> lpszClass As Long
    > >> dwExStyle As Long
    > >>End Type
    > >>
    > >>Public Type SafeArray1D
    > >> cDims As Integer
    > >> fFeatures As Integer
    > >> cbElements As Long
    > >> cLocks As Long
    > >> pvData As Long
    > >> cElements As Long
    > >> lLbound As Long
    > >>End Type
    > >>
    > >>'VarPtrArray gets a pointer to the SAFEARRAY pointer
    > >>Public Declare Function VarPtrArray Lib "msvbvm60.dll" Alias "VarPtr" (Ptr()
    > >>As Any) As Long
    > >>Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDest

    > >As
    > >>Any, pSrc As Any, ByVal ByteLen As Long)
    > >>Public Declare Sub ZeroMemory Lib "kernel32" Alias "RtlZeroMemory" (pDest

    > >As
    > >>Any, ByVal ByteLen As Long)
    > >>
    > >>Public Sub ShareMemoryViaArray(ByVal ArrayPtr As Long, ByVal MemPtr As

    > Long,
    > >>SA1D As SafeArray1D, Optional ByVal ElemByteLen As Long)
    > >> With SA1D
    > >> 'This is optional because this is a 1 element array,
    > >> 'so cbElements is not needed to walk the array. If Erase
    > >> 'is called on an array with .cbElements = 0, VB will still
    > >> 'free all pointer types, but non-pointer types will not get
    > >> 'zeroed out. Note that the compiler calculates the length
    > >> 'of a structure at compile time, so LenB(MyStruct(0)) is
    > >> 'valid regardless of whether or not MyStruct is actually allocated.
    > >> .cbElements = ElemByteLen
    > >> .cDims = 1
    > >> '2 = FADF_STATIC. This means that if the
    > >> 'array goes out of scope, then the pointed
    > >> 'to memory will be cleaned, but no attempt
    > >> 'will be made to free the array pointer
    > >> 'or descriptor.
    > >> .fFeatures = 2
    > >> .pvData = MemPtr
    > >> .cElements = 1
    > >> End With
    > >> CopyMemory ByVal ArrayPtr, VarPtr(SA1D), 4
    > >>End Sub
    > >>
    > >>Function CBTProc(ByVal lMsg As Long, ByVal wParam As Long, ByVal lParam

    > >As
    > >>Long) As Long
    > >>Dim saCreateWnd As SafeArray1D
    > >>Dim psaCreateWnd() As CBT_CREATEWNDA
    > >>Dim saCreateStruct As SafeArray1D
    > >>Dim psaCreateStruct() As CREATESTRUCTA
    > >> If lMsg = HCBT_CREATEWND Then
    > >> ShareMemoryViaArray VarPtrArray(psaCreateWnd), lParam, saCreateWnd
    > >> ShareMemoryViaArray VarPtrArray(psaCreateStruct),
    > >>psaCreateWnd(0).lpcs, saCreateStruct
    > >> 'Changing the style in the CreateStruct is insufficient.
    > >>SetWindowLong is required.
    > >> 'Note that the changes don't automatically show up in the pointed

    > >to
    > >>structures.
    > >> 'Make the LB multiselect and sorted. This is LBS_SORT Or
    > >>LBS_MULTIPLESEL
    > >> SetWindowLong wParam, GWL_STYLE, psaCreateStruct(0).Style Or &HA
    > >> ZeroMemory ByVal VarPtrArray(psaCreateStruct), 4
    > >> ZeroMemory ByVal VarPtrArray(psaCreateWnd), 4
    > >> End If
    > >>End Function
    > >>
    > >>
    > >>"Chris Brown" <christopherbrown@halifax.co.uk> wrote in message
    > >>news:3b4bfa54$1@news.devx.com...
    > >>>
    > >>> Thanks for that Matt - I guess I knew in advance that it was unlikely

    > >-
    > >>just
    > >>> needed a guru to tell me I suppose!!!
    > >>>
    > >>> I was originally trying to show a VB form on top of all other forms -

    > >I'm
    > >>> actually creating a new 'combo box' ACTIVEX control that uses a list

    > box
    > >>> with the TABSTOPS style set so that we can have multiple columns. I was
    > >>displaying
    > >>> the form and using SETPARENT function to move the list box from the
    > >>ACTIVEX
    > >>> control onto the form (this was to get around problems of the control
    > >>being
    > >>> bound by a container control like a frame and only displaying half of

    > >the
    > >>> list box if the frame was small - using the form allowed the list box

    > >to
    > >>> appear 'outside' the frame!)
    > >>>
    > >>> This worked fine on forms shown normally but became a problem when showing
    > >>> on top of a modal form. I've now started down a new route of using
    > >>CREATEWINDOW
    > >>> to create a new window/form instead of using an internal VB form and

    > I'm
    > >>> gonna see how that goes!!!
    > >>>
    > >>> Many thanks again for your input.
    > >>>
    > >>> "Matthew Curland" <mattcur@microsoft.com> wrote:
    > >>> >This is a dead-end pursuit. A form is made modal by pushing a new message
    > >>> >loop. Essentially, the message loop of your background forms gets very
    > >>few
    > >>> >messages (painting messages would be the most important ones that are

    > >let
    > >>> >through). What you're asking is to break out of the message loop that
    > >>showed
    > >>> >the form while it is still showing. Not happening. You need to find

    > a
    > >>> >different approach to your problem. You might start by stating what

    > that
    > >>> >problem is instead of stating a proposed solution. -Matt
    > >>> >
    > >>> >"Chris Brown" <christopherbrown@halifax.co.uk> wrote in message
    > >>> >news:3b4aff6c$1@news.devx.com...
    > >>> >>
    > >>> >> Does anyone know of a way of detecting if a form is modal and, if

    > so,
    > >>> >making
    > >>> >> it modeless?? Assume the form is being opened using the .SHOW method
    > >>along
    > >>> >> with the vbModal constant.
    > >>> >>
    > >>> >> If the modal form CAN be switched off, can it then be switched back

    > >on
    > >>> >again???
    > >>> >> What API's (if any) are involved in this?? I can't seem to see anywhere
    > >>> >the
    > >>> >> processes windows goes through to create Modal forms.
    > >>> >>
    > >>> >> Many thanks in advance....
    > >>> >
    > >>> >
    > >>>
    > >>
    > >>

    > >



Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
HTML5 Development Center
 
 
FAQ
Latest Articles
Java
.NET
XML
Database
Enterprise
Questions? Contact us.
C++
Web Development
Wireless
Latest Tips
Open Source


   Development Centers

   -- Android Development Center
   -- Cloud Development Project Center
   -- HTML5 Development Center
   -- Windows Mobile Development Center