In a certain sense, any time one registers a window class with RegisterClass() or RegisterClassEx(), one has created a custom Window Class the instantiation of which through a CreateWindow() or CreateWindowEx() call results in a custom window object in the case of a top level window, or a custom windows control in the case of an object with the WS_CHILD property/style.
That custom control example of mine you are speaking of is an adaptation of one I learned from Chris Boss who is also very knowledgable in this area. In that example the custom control consisted of only a simple colored window. The buttons to change the color were located in the parent window. When I created that tutorial/example I had thought of putting the three buttons within the control itself, but decided against that at the last moment, because that would have robbed me of the opportunity of showing function calls being made ‘into’ the control, as the button clicks would then have been picked up within the Window Procedure of the custom control in the dll rather than in the host or parent as is now the case. However, by doing that I lost the opportunity of showing how to make a ‘composite’ control, which is apparently what you want and seemingly have achieved on your own anyway.
In many cases when building custom window controls they are ‘Composite Controls’ and contain other simple Windows Controls such as buttons, edit controls, etc (or in your case, a Rich Edit Control). The way I create these is inside the WM_CREATE handler of the custom control. A few words about this may be in order.
I view the WM_CREATE message very much like an object constructor in OOP terminology. When Windows sends a WM_CREATE message to a Window Procedure, it has already set up everything or nearly everything it needs to maintain that window such as the allocation of memory, creation of handles, etc. So when you receive that WM_CREATE message, Windows is saying to you, “I’ve done everyting I need to create, service, and manage your window hWnd = xxxxxxxxx, so now its your turn to do what you need to do to customize its final creation. Do what you will!” So in the case of a composite custom control one would be making additional CreateWindow() calls inside the CreateWindow call the WM_CREATE message of which you are now coding! So you can end up with whole series of cascading and almost recursive CreateWindow calls inside other CreateWindow calls inside yet other CreateWindow calls as an object pulls itself together – pulling itself up by the bootstraps, so to speak. Because, don’t forget, when a WM_CREATE call occurs, and while inside a WM_CREATE handler, the CreateWindow() call that caused the WM_CREATE message has not as of yet returned.
As an exercise, it might be worthwhile to modify that custom control example of mine to locate the buttons within the custom control and think that whole process through.
When you first posted Frank, I wasn’t sure what you wanted. That’s why I mentioned another program I had that showed how to create a main form which then created multiple ‘sub-forms’. I use that architecture frequently in the work I do. Here is that example…
#Compile Exe
#Dim All
%UNICODE = 1
#If %Def(%UNICODE)
Macro ZStr = WStringz
Macro BStr = WString
%SIZEOF_CHAR = 2
#Else
Macro ZStr = Asciiz
Macro BStr = String
%SIZEOF_CHAR = 1
#EndIf
#Include "Win32api.inc"
%IDC_BUTTON_1 = 1501
%IDC_BUTTON_2 = 1502
%IDC_BUTTON_3 = 1503
Type WndEventArgs
hIns As Dword
hWnd As Dword
wParam As Dword
lParam As Dword
End Type
Function fnForm1(ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Local hParent As Dword
Select Case As Long wMsg
Case %WM_CREATE
Local pCreateStruct As CREATESTRUCT Ptr
pCreateStruct = lParam
hParent=@pCreateStruct.lpCreateParams
Call SetWindowLong(hWnd,0,hParent)
Call EnableWindow(hParent,%FALSE)
Function=0 : Exit Function
Case %WM_PAINT
Local ps As PAINTSTRUCT
Local hDC As Dword
hDC=BeginPaint(hWnd,ps)
TextOut(hDC,0,0,"This Form Disables The Main Program Window.",43)
TextOut(hDC,0,18,"Therefore It Can Be Considered As A Modal",41)
TextOut(hDC,0,36,"Window.",7)
Call EndPaint(hWnd,ps)
fnForm1 = 0 : Exit Function
Case %WM_DESTROY
hParent=GetWindowLong(hWnd,0)
Call EnableWindow(hParent,%TRUE)
Function=0 : Exit Function
End Select
fnForm1=DefWindowProc(hWnd, wMsg, wParam, lParam)
End Function
Function fnForm2(ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Local hParent As Dword
Select Case As Long wMsg
Case %WM_CREATE
Local pCreateStruct As CREATESTRUCT Ptr
pCreateStruct = lParam
hParent=@pCreateStruct.lpCreateParams
Call SetWindowLong(hWnd,0,hParent)
Call ShowWindow(hParent,%SW_HIDE)
Function=0 : Exit Function
Case %WM_PAINT
Local ps As PAINTSTRUCT
Local hDC As Dword
hDC=BeginPaint(hWnd,ps)
TextOut(hDC,0,0,"This Form Hides The Main Program Window. It",44)
TextOut(hDC,0,18,"Will Be Shown Again When You Dismiss This",41)
TextOut(hDC,0,36,"Window.",7)
Call EndPaint(hWnd,ps)
Function = 0 : Exit Function
Case %WM_DESTROY
hParent=GetWindowLong(hWnd,0)
Call ShowWindow(hParent,%SW_RESTORE)
Function=0 : Exit Function
End Select
fnForm2=DefWindowProc(hWnd, wMsg, wParam, lParam)
End Function
Function fnForm3(ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Select Case wMsg
Case %WM_PAINT
Local ps As PAINTSTRUCT
Local hDC As Dword
hDC=BeginPaint(hWnd,ps)
TextOut(hDC,0,0,"You can create as many Form3s As You Like.",42)
Call EndPaint(hWnd,ps)
fnForm3 = 0 : Exit Function
End Select
fnForm3=DefWindowProc(hWnd, wMsg, wParam, lParam)
End Function
Function fnMainWndProc_OnCreate(Wea As WndEventArgs) As Long
Local pCreateStruct As CREATESTRUCT Ptr
Local szClassName As ZStr*16
Local wc As WndClassEx
Local hCtl As Dword
pCreateStruct=wea.lParam
wea.hIns=@pCreateStruct.hInstance
hCtl=CreateWindow("button","Button 1",%WS_CHILD Or %WS_VISIBLE,50,25,125,25,wea.hWnd,%IDC_BUTTON_1,wea.hIns,ByVal 0)
hCtl=CreateWindow("button","Button 2",%WS_CHILD Or %WS_VISIBLE,50,60,125,25,wea.hWnd,%IDC_BUTTON_2,wea.hIns,ByVal 0)
hCtl=CreateWindow("button","Button 3",%WS_CHILD Or %WS_VISIBLE,50,95,125,25,wea.hWnd,%IDC_BUTTON_3,wea.hIns,ByVal 0)
'Form1 Window
szClassName="Form1" : wc.lpszClassName=VarPtr(szClassName) 'Form1
wc.lpfnWndProc=CodePtr(fnForm1) : wc.hbrBackground=GetStockObject(%WHITE_BRUSH)
wc.cbSize=SizeOf(wc) : wc.style=%CS_HREDRAW Or %CS_VREDRAW
wc.cbClsExtra=0 : wc.cbWndExtra=4
wc.hInstance=wea.hIns : wc.hIcon=LoadIcon(%NULL, ByVal %IDI_APPLICATION)
wc.hCursor=LoadCursor(%NULL, ByVal %IDC_ARROW) : wc.lpszMenuName=%NULL
Call RegisterClassEx(wc)
'Form2 Window
szClassName="Form2" : wc.lpszClassName=VarPtr(szClassName) 'Form2
wc.lpfnWndProc=CodePtr(fnForm2) : wc.hbrBackground=GetStockObject(%WHITE_BRUSH)
Call RegisterClassEx(wc)
'Form3 Window
szClassName="Form3" : wc.lpszClassName=VarPtr(szClassName) 'Form3
wc.lpfnWndProc=CodePtr(fnForm3) : wc.hbrBackground=GetStockObject(%WHITE_BRUSH)
Call RegisterClassEx(wc)
fnMainWndProc_OnCreate=0
End Function
Function fnMainWndProc_OnCommand(Wea As WndEventArgs) As Long
Local hForm As Dword
Select Case LoWrd(wea.wParam)
Case %IDC_BUTTON_1
hForm=CreateWindowEx(0,"Form1","Form1",%WS_OVERLAPPEDWINDOW,325,75,350,225,wea.hWnd,0,wea.hIns,Byval Wea.hWnd)
Call ShowWindow(hForm,%SW_SHOWNORMAL)
Call UpdateWindow(hForm)
Case %IDC_BUTTON_2
hForm=CreateWindowEx(0,"Form2","Form2",%WS_OVERLAPPEDWINDOW,350,250,350,125,wea.hWnd,0,wea.hIns,Byval Wea.hWnd)
Call ShowWindow(hForm,%SW_SHOWNORMAL)
Call UpdateWindow(hForm)
Case %IDC_BUTTON_3
hForm=CreateWindowEx(0,"Form3","Form3",%WS_OVERLAPPEDWINDOW,%CW_USEDEFAULT,%CW_USEDEFAULT,350,125,wea.hWnd,0,wea.hIns,Byval 0)
Call ShowWindow(hForm,%SW_SHOWNORMAL)
Call UpdateWindow(hForm)
End Select
fnMainWndProc_OnCommand=0
End Function
Function fnMainWndProc_OnClose(wea As WndEventArgs) As Long
PostQuitMessage 0
fnMainWndProc_OnClose=0
End Function
Function fnMainWndProc(ByVal hWnd As Long,ByVal wMsg As Long,ByVal wParam As Long,ByVal lParam As Long) Export As Long
Local wea As WndEventArgs
Select Case wMsg
Case %WM_CREATE
wea.hWnd=hWnd : wea.wParam=wParam : wea.lParam=lParam
fnMainWndProc=fnMainWndProc_OnCreate(wea)
Exit Function
Case %WM_COMMAND
wea.hWnd=hWnd : wea.wParam=wParam : wea.lParam=lParam
fnMainWndProc=fnMainWndProc_OnCommand(wea)
Exit Function
Case %WM_CLOSE
wea.hWnd=hWnd : wea.wParam=wParam : wea.lParam=lParam
fnMainWndProc=fnMainWndProc_OnClose(wea)
Exit Function
End Select
fnMainWndProc=DefWindowProc(hWnd, wMsg, wParam, lParam)
End Function
Function WinMain(ByVal hIns As Long, ByVal hPrev As Long, ByVal lpCL As Asciiz Ptr, ByVal Is As Long) As Long
Local szAppName As ZStr * 32
Local hMainWnd As Dword
Local wc As WndClassEx
Local Msg As tagMsg
szAppName="Multiple Windows" : wc.lpszClassName=VarPtr(szAppName)
wc.lpfnWndProc=CodePtr(fnMainWndProc) : wc.cbSize=SizeOf(wc)
wc.style=%CS_HREDRAW Or %CS_VREDRAW : wc.cbClsExtra=0
wc.cbWndExtra=0 : wc.hInstance=hIns
wc.hIcon=LoadIcon(%NULL, ByVal %IDI_APPLICATION) : wc.hCursor=LoadCursor(%NULL, ByVal %IDC_ARROW)
wc.hbrBackground=%COLOR_BTNSHADOW : wc.hIconSm=0
wc.lpszMenuName=%NULL
Call RegisterClassEx(wc)
hMainWnd=CreateWindowEx(0,szAppName,"Multiple Forms",%WS_OVERLAPPEDWINDOW,575,75,240,190,0,0,hIns,ByVal 0)
Call ShowWindow(hMainWnd,Is)
While GetMessage(Msg,%NULL,0,0)
TranslateMessage Msg
DispatchMessage Msg
Wend
Function=msg.wParam
End Function