0

I'd like to add controls to a property sheet without resource script, rather using pure code. The reason for this I'd like to create a property sheet(mimicking C#'s property grid), calling C routines/WINAPI, from another language, binary-compatible to C; but I'd like to define everything with code, without need of a resource script. Is this possible or the way to go is write my own property-sheet-like, with underlying CreateWindow*() calls? (different approaches to do this are welcome, I'm new to WINAPI) which I suppose property sheet use behind the scenes

Jack
  • 16,276
  • 55
  • 159
  • 284
  • You can generate a dialog template at runtime and set the `pResource` member to point to it. – Raymond Chen Jan 03 '21 at 04:16
  • I'll take a look at it, thanks. Out curiosity, do you know if the .NET WinForms framework use this approach to make some of its GUI controls, like Property Grid? – Jack Jan 03 '21 at 04:33
  • 1
    [You can look it up yourself](https://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/PropertyGrid.cs,a6e8a358837fd5d4). – Raymond Chen Jan 03 '21 at 05:10
  • @RaymondChen I'll try dig all that, thanks! – Jack Jan 10 '21 at 21:34

1 Answers1

0

Found the solution! I found this post from Raymond Chen where he shows how do that.

the main code goes like this:

BOOL FakeMessageBox(HWND hwnd, LPCWSTR pszMessage, LPCWSTR pszTitle)
{
 BOOL fSuccess = FALSE;
 HDC hdc = GetDC(NULL);
 if (hdc) {
  NONCLIENTMETRICSW ncm = { sizeof(ncm) };
  if (SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0)) {
   DialogTemplate tmp;

   // Write out the extended dialog template header
   tmp.Write<WORD>(1); // dialog version
   tmp.Write<WORD>(0xFFFF); // extended dialog template
   tmp.Write<DWORD>(0); // help ID
   tmp.Write<DWORD>(0); // extended style
   tmp.Write<DWORD>(WS_CAPTION | WS_SYSMENU | DS_SETFONT | DS_MODALFRAME);
   tmp.Write<WORD>(2); // number of controls
   tmp.Write<WORD>(32); // X
   tmp.Write<WORD>(32); // Y
   tmp.Write<WORD>(200); // width
   tmp.Write<WORD>(80); // height
   tmp.WriteString(L""); // no menu
   tmp.WriteString(L""); // default dialog class
   tmp.WriteString(pszTitle); // title

   // Next comes the font description.
   // See text for discussion of fancy formula.
   if (ncm.lfMessageFont.lfHeight < 0) {
     ncm.lfMessageFont.lfHeight = -MulDiv(ncm.lfMessageFont.lfHeight,
              72, GetDeviceCaps(hdc, LOGPIXELSY));
   }
   tmp.Write<WORD>((WORD)ncm.lfMessageFont.lfHeight); // point
   tmp.Write<WORD>((WORD)ncm.lfMessageFont.lfWeight); // weight
   tmp.Write<BYTE>(ncm.lfMessageFont.lfItalic); // Italic
   tmp.Write<BYTE>(ncm.lfMessageFont.lfCharSet); // CharSet
   tmp.WriteString(ncm.lfMessageFont.lfFaceName);

   // Then come the two controls.  First is the static text.
   tmp.AlignToDword();
   tmp.Write<DWORD>(0); // help id
   tmp.Write<DWORD>(0); // window extended style
   tmp.Write<DWORD>(WS_CHILD | WS_VISIBLE); // style
   tmp.Write<WORD>(7); // x
   tmp.Write<WORD>(7); // y
   tmp.Write<WORD>(200-14); // width
   tmp.Write<WORD>(80-7-14-7); // height
   tmp.Write<DWORD>(-1); // control ID
   tmp.Write<DWORD>(0x0082FFFF); // static
   tmp.WriteString(pszMessage); // text
   tmp.Write<WORD>(0); // no extra data

   // Second control is the OK button.
   tmp.AlignToDword();
   tmp.Write<DWORD>(0); // help id
   tmp.Write<DWORD>(0); // window extended style
   tmp.Write<DWORD>(WS_CHILD | WS_VISIBLE |
                    WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON); // style
   tmp.Write<WORD>(75); // x
   tmp.Write<WORD>(80-7-14); // y
   tmp.Write<WORD>(50); // width
   tmp.Write<WORD>(14); // height
   tmp.Write<DWORD>(IDCANCEL); // control ID
   tmp.Write<DWORD>(0x0080FFFF); // static
   tmp.WriteString(L"OK"); // text
   tmp.Write<WORD>(0); // no extra data

   // Template is ready - go display it.
   fSuccess = DialogBoxIndirect(g_hinst, tmp.Template(),
                                hwnd, DlgProc) >= 0;
  }
  ReleaseDC(NULL, hdc); // fixed 11 May
 }
 return fSuccess;
}
Jack
  • 16,276
  • 55
  • 159
  • 284