I am using Visual Studio 2019. Appearance of Form in Designer looks older than in running application.
Is it intended to be so, and is it possible to change the look in the Designer?
You cannot change it. It's a Windows feature(bug), not a VS or .NET feature(bug).
The form which is hosted in designer is not a top-level form and as a result the top-level Window theme will not apply on it. It may be a bug in Windows or it may be by design, but it doesn't have anything to do with Visual Studio, Windows Forms .NET or your theme settings.
For example even if you use SetParent and set a notepad window as child of another notepad window you see similar behavior in rendering the titlebar. Here in this example, VS has nothing to do with rendering notepad titlebar, it's solely OS:
Above example has been created by the following code:
[DllImport("user32.dll")]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter,
int X, int Y, int cx, int cy, int uFlags);
[DllImport("user32.dll")]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter,
string lpszClass, string lpszWindow);
private void button1_Click(object sender, EventArgs e)
{
var parent = Process.Start("notepad.exe");
parent.WaitForInputIdle();
var edit = FindWindowEx(parent.MainWindowHandle, IntPtr.Zero, "Edit", null);
SetWindowPos(edit, IntPtr.Zero, 0, 0, 0, 0, 0x0080);
var child = Process.Start("notepad.exe");
child.WaitForInputIdle();
SetParent(child.MainWindowHandle, parent.MainWindowHandle);
SetWindowPos(child.MainWindowHandle, IntPtr.Zero, 30, 30, 300, 200, 0x0000);
}
I suggest you use Ui components such as GunaUI or DevComponent. then your Form will look better.
I don't know if you meant this by saying"Appearance of Form in Designer looks older than in running application"
but it's better to use components.
As part of extending the functionality of a dialog in an old Windows WinAPI GUI application written in C, I was faced with once more adding multiple check boxes for each line of a six line data entry dialog. I just could not bear the hassle of repetitive resource file and source code file changes and decided to borrow a UI design approach from Java UIs of building up a UI from panes.
The Visual Studio tools, at least Visual Studio 2005, seem to discourage this approach and in this case I hand edited the resource file. Perhaps the resource editing tools of Visual Studio 2017 are more flexible.
My question is what is an alternative to this approach that would seem to be as easy to do and would better fit with the Visual Studio philosophy.
I am also wondering about the downside of this approach.
This approach seems unusual for a Visual Studio C WinAPI GUI application which troubles me. I can't claim to be especially innovative so I wonder what I am missing as the approach seems to work well at least when doing hand edits of the resource file.
I am considering doing another iteration in which I move the list of controls for each line that is repeated into the modeless dialog box template as well and just having the original dialog be a stack of 6 static windows, one for each line.
Benefits of this approach was fewer defines and being able to reuse defines. It was also easier to insert the new functionality into the existing dialog behavior source code though that was mostly because these were just simple auto check boxes.
The one issue I see is using the Visual Studio tools after doing this change. However this particular application's resource file doesn't work well with the Visual Studio resource editing tools anyway.
This approach has already had a payback when I needed to add some additional checkboxes to the modeless dialog template. The resource file changes I had to do to was to add the additional checkboxes to the new dialog template and adjust the original dialog size, the modeless dialog size, and the sizes of the static windows to make everything visible.
The Implementation
The alternative I have implemented is to:
create a dialog template with the set of checkboxes
modify the dialog template style of the modeless dialog to WS_CHILD
create a static window on each of the six lines of the original dialog for the new dialog template
place an instance of the modeless dialog box into the static window on each line
The new version of the dialog looks like
When the original dialog is displayed, the handler for the init dialog message creates a set of six modeless dialogs, one for each of the newly added static windows with the parent window for the dialogs being the static window. This places the modeless dialog into the static window and when the static window moves so does the modeless dialog.
All six of the modeless dialogs use the same dialog message handler. The message handler doesn't handle any messages itself.
The modeless dialog template is:
IDD_A170_DAYS DIALOG DISCARDABLE 0, 0, 240, 20
STYLE WS_CHILD | WS_VISIBLE
FONT 8, "MS Sans Serif"
BEGIN
CONTROL "Ovr",IDD_A170_STR1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,1,25,10
CONTROL "AND",IDD_A170_STR2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,35,1,40,10
CONTROL "S",IDD_A170_CAPTION1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,75,1,20,10
CONTROL "M",IDD_A170_CAPTION2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,100,1,20,10
CONTROL "T",IDD_A170_CAPTION3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,125,1,20,10
CONTROL "W",IDD_A170_CAPTION4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,1,20,10
CONTROL "T",IDD_A170_CAPTION5,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,175,1,20,10
CONTROL "F",IDD_A170_CAPTION6,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,195,1,20,10
CONTROL "S",IDD_A170_CAPTION7,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,220,1,20,10
END
and the main dialog with the static windows is:
IDD_A170 DIALOG DISCARDABLE 2, 17, 530, 190
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "Set Sales Code Restriction Table of PLU (AC 170)"
FONT 8, "MS Sans Serif"
BEGIN
LTEXT "Address (PLU Sales Code)",IDD_A170_CAPTION1,14,10,64,20
LTEXT "Date",IDD_A170_CAPTION2,86,14,28,12
LTEXT "Day of week",IDD_A170_CAPTION3,115,10,33,21
LTEXT "Start hour",IDD_A170_CAPTION4,153,10,20,18
LTEXT "Minute",IDD_A170_CAPTION5,182,14,26,12
LTEXT "End hour",IDD_A170_CAPTION6,217,10,20,18
LTEXT "Minute",IDD_A170_CAPTION7,245,14,26,12
LTEXT "Override/Type",IDC_STATIC,290,14,50,12
LTEXT "Days To Restrict",IDC_STATIC,390,14,100,12
LTEXT "",IDD_A170_STR1,8,34,74,12 // first control on line 1
EDITTEXT IDD_A170_DATE1,87,33,18,12,ES_AUTOHSCROLL
SCROLLBAR IDD_A170_DATESPIN1,104,33,8,12,SBS_VERT
EDITTEXT IDD_A170_WEEK1,119,33,18,12,ES_AUTOHSCROLL
SCROLLBAR IDD_A170_WEEKSPIN1,136,33,8,12,SBS_VERT
EDITTEXT IDD_A170_SHOUR1,151,33,18,12,ES_AUTOHSCROLL
SCROLLBAR IDD_A170_SHOURSPIN1,168,33,8,12,SBS_VERT
EDITTEXT IDD_A170_SMINUTE1,183,33,18,12,ES_AUTOHSCROLL
SCROLLBAR IDD_A170_SMINUTESPIN1,200,33,8,12,SBS_VERT
EDITTEXT IDD_A170_EHOUR1,214,33,18,12,ES_AUTOHSCROLL
SCROLLBAR IDD_A170_EHOURSPIN1,231,33,8,12,SBS_VERT
EDITTEXT IDD_A170_EMINUTE1,246,33,18,12,ES_AUTOHSCROLL
SCROLLBAR IDD_A170_EMINUTESPIN1,263,33,8,12,SBS_VERT
LTEXT "D1",IDD_A170_DAYS_1,281,33,240,20 // static window to contain the modeless dialog box from the template IDD_A170_DAYS above
// .. repeated sequence for 5 more lines
CONTROL "MDC 298 - Sales Restriction Type is AND",IDD_A170_MDC_PLU5_ADR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,9,140,170,9
LTEXT "[Address : 1 - 6, Date : 0 - 31",IDD_A170_CAPTION8,9,154,99,9
LTEXT "Day of week : 0 - 7 (1 - Sunday, 7 - Saturday)]",IDD_A170_CAPTION9,110,154,167,9
LTEXT "[Hour : 0 - 24, Minute : 0 - 59 (For 0:00, enter 24:00)]",IDD_A170_CAPTION10,9,168,167,9
PUSHBUTTON "&Ok",IDOK,285,154,48,20
PUSHBUTTON "&Cancel",IDCANCEL,345,154,48,20
END
You may notice that I just reused some of the defines in the new modeless dialog box that were already being used in the original dialog box. I was able to do so because control identifiers are specific to the dialog box itself. So using the same define in different dialog boxes does not cause a problem since the use of GetDlgItem() to obtain the window handle of a control within a dialog box requires the window handle of a specific dialog instance.
I then created a set of helper functions that handle an instance of the modeless dialog.
static struct {
int iId;
HWND hWnd;
} A170DlgTabs[10] = { {0, 0} };
// modeless dialog box message handler which has nothing to do but the
// WinAPI requires it.
BOOL WINAPI A170DlgChildProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
return FALSE;
}
void A170ModeLessChildDialogClear ()
{
memset (A170DlgTabs, 0, sizeof(A170DlgTabs));
}
HWND A170ModeLessChildDialog (HWND hParentWnd, int nCmdShow, int iId)
{
int i;
HWND hWnd = DialogCreation(hResourceDll/*hActInst*/, //RPH 4-23-03 Multilingual
MAKEINTRESOURCEW(IDD_A170_DAYS),
hParentWnd,
A170DlgChildProc);
hWnd && ShowWindow (hWnd, nCmdShow);
for (i = 0; i < sizeof(A170DlgTabs)/sizeof(A170DlgTabs[0]); i++) {
if (A170DlgTabs[i].hWnd == 0) {
A170DlgTabs[i].iId = iId;
A170DlgTabs[i].hWnd = hWnd;
break;
}
}
return hWnd;
}
HWND A170ModeLessChildDialogFind (int iId)
{
int i;
HWND hWnd = NULL;
for (i = 0; i < sizeof(A170DlgTabs)/sizeof(A170DlgTabs[0]); i++) {
if (A170DlgTabs[i].iId == iId) {
hWnd = A170DlgTabs[i].hWnd;
break;
}
}
return hWnd;
}
USHORT A170ModeLessChildDialogSettings (int iId)
{
int i;
USHORT iBits = 0, kBits = 1;
HWND hWnd = A170ModeLessChildDialogFind (iId);
// least significant byte contains the bit mask for the days of the week.
// the next higher byte contains the indicators for the override type or
// whether MDC 298 is to be overriden or not.
for (i = IDD_A170_CAPTION1; i <= IDD_A170_CAPTION7; i++, (kBits <<= 1)) {
iBits |= IsDlgButtonChecked (hWnd, i) ? kBits : 0;
}
iBits |= iBits ? RESTRICT_WEEK_DAYS_ON : 0;
iBits |= IsDlgButtonChecked(hWnd, IDD_A170_STR1) ? KBITS_RESTRICT_OVERRIDE_ANDOR : 0;
iBits |= IsDlgButtonChecked(hWnd, IDD_A170_STR2) ? KBITS_RESTRICT_OVERRIDE_AND : 0;
return iBits;
}
USHORT A170ModeLessChildDialogSettingsSetMask (int iId, USHORT usMask)
{
int i;
USHORT k = 1;
HWND hWnd = A170ModeLessChildDialogFind (iId);
CheckDlgButton(hWnd, IDD_A170_STR1, (usMask & KBITS_RESTRICT_OVERRIDE_ANDOR) ? TRUE : FALSE);
CheckDlgButton(hWnd, IDD_A170_STR2, (usMask & KBITS_RESTRICT_OVERRIDE_AND) ? TRUE : FALSE);
for (i = IDD_A170_CAPTION1; i <= IDD_A170_CAPTION7; i++, (k <<= 1)) {
CheckDlgButton(hWnd, i, (usMask & k) ? TRUE : FALSE);
}
return usMask;
}
Using Visual Studio 2017 Community Edition made taking this approach to creating components from dialog templates which are then used to build a GUI easier.
I did this rough, proof of concept exercise using the About dialog that is automatically generated by the creation of a new Windows Desktop Application project since it was handy.
This was a simple component being expressed in a dialog template and that simplicity may make this proof of concept misleading.
I started with an initial Windows Desktop Application skeleton created as a new project. I then made the following modifications to the About dialog that is automatically generated with a New project. I was able to use the IDE and Resource Editor without doing any hand editing of the resource file.
The steps were as follows:
use the Resource Editor to modify the existing About dialog and create a new modeless dialog
add a new class to manage the new modeless dialog
modify the About dialog message handler to use the new class
Modifications to the dialog resources using the Resource Editor was fairly straightforward:
modify the automatically generated About dialog by making it larger and adding two static text windows in a column
specify actual control identifiers for each static text box added to the About dialog so that they could be referenced with GetDlgItem(), an important step as the IDE does not assign usable control identifiers by default to static windows
created a new dialog template using the Resource Editor after switching to Resource View
modified a couple of Appearance attributes in the Properties list of the dialog box to change the dialog to a modeless dialog with no border
added the checkboxes to the new dialog using the Resource Editor and removed the default buttons
The source code changes were also fairly straightforward as this is a simple control.
The new About dialog box looks like this. I added two static windows to the About dialog after making it larger. Each of the static windows has its own instance of the new dialog template based control. Notice that the size of the dialog template is larger than the size of the static windows which results in clipping of the dialog template to the display area of the static window.
The Details of What Was Done
Create and Modify the Dialog Styles
Using Resource View I added a new dialog. I clicked on the new dialog to bring it up in the Resource Editor. Then I modified the initial modal dialog template by changing the border attribute and the style attribute along with removing the default buttons the IDE added when it first created the dialog template, I turned the dialog template into a modeless dialog suitable for putting into a static window container.
Create the Code for the Behavior
I then created a class, CDialogChild to manage this new modeless dialog with the following source:
#pragma once
#include "resource.h"
class CDialogChild
{
private:
// static shared by all instances of this class
static LRESULT CALLBACK WndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
enum {DIALOG_ID = IDD_DIALOG1};
static const UINT idCheckBox[3]; // identifiers for the controls of the modeless dialog.
// management data for each modeless dialog instance created.
HINSTANCE m_hinst; // handle to the instance resources
HWND m_hWnd; // handle to the modeless dialog window
HWND m_hParent; // handle to the parent of the modeless dialog, usually static window
// operational data displayed and captured by this modeless dialog
// this is the data for the various controls we have in the dialog template.
bool bCheckBox[3] = { false, false, false };
public:
CDialogChild();
~CDialogChild();
bool GetCheck(int iIndex); // for reading checkbox value
void GetCheckFinal(void); // for capturing final checkbox states
bool SetCheck(int iIndex, bool bValue); // for writing checkbox value
void SetCheckInitial(void); // for setting the initial checkbox states.
HWND Create(HWND hParent, HINSTANCE hinst);
};
with an implementation of:
#include "stdafx.h"
#include "CDialogChild.h"
const UINT CDialogChild::idCheckBox[3] = { IDC_CHECK1, IDC_CHECK2, IDC_CHECK3 };
CDialogChild::CDialogChild()
{
}
CDialogChild::~CDialogChild()
{
}
HWND CDialogChild::Create(HWND hParent, HINSTANCE hinst)
{
// called to create the modeless dialog using the dialog resource in the
// specified resource file instance. the hParent is the container we are
// going to put this modeless dialogbox into.
m_hinst = hinst;
m_hParent = hParent;
m_hWnd = CreateDialog(hinst, MAKEINTRESOURCE(DIALOG_ID), hParent, (DLGPROC)CDialogChild::WndProc);
ShowWindow(m_hWnd, SW_SHOW);
return m_hWnd;
}
bool CDialogChild::GetCheck(int iIndex)
{
if (iIndex > 0 && iIndex < sizeof(bCheckBox) / sizeof(bCheckBox[0])) {
iIndex = 0;
}
bCheckBox [iIndex] = IsDlgButtonChecked(m_hWnd, idCheckBox[iIndex]);
return bCheckBox [iIndex];
}
bool CDialogChild::SetCheck(int iIndex, bool bValue)
{
if (iIndex > 0 && iIndex < sizeof(bCheckBox) / sizeof(bCheckBox[0])) {
iIndex = 0;
}
CheckDlgButton (m_hWnd, idCheckBox[iIndex], bValue);
bCheckBox[iIndex] = bValue;
return bCheckBox [iIndex];
}
void CDialogChild::GetCheckFinal(void)
{
for (int iIndex = 0; iIndex < sizeof(bCheckBox) / sizeof(bCheckBox[0]); iIndex++) {
bCheckBox[iIndex] = IsDlgButtonChecked(m_hWnd, idCheckBox[iIndex]);
}
}
void CDialogChild::SetCheckInitial(void)
{
for (int iIndex = 0; iIndex < sizeof(bCheckBox) / sizeof(bCheckBox[0]); iIndex++) {
CheckDlgButton(m_hWnd, idCheckBox[iIndex], bCheckBox[iIndex]);
}
}
// CDialogChild class Windows message procedure to handle any messages sent
// to a modeless dialog window. This simple example there is not much to do.
LRESULT CALLBACK CDialogChild::WndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
return (INT_PTR)FALSE;
}
Use the New Control in a Dialog
Finally I modified the About dialog to use the new dialog template based control. The first thing was to add the static windows to the About dialog template to provide containers for the new control which provided the placement for where I wanted the control instances to be.
Next I added the handling source code to use the new dialog template based control in the modified About dialog.
// other source code from the Windows Desktop Application main window handler
// is above this. We are only modifying the About dialog code which is at the
// bottom of the source file.
#include "CDialogChild.h"
CDialogChild myAbout1;
CDialogChild myAbout2;
// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
myAbout1.Create(GetDlgItem(hDlg, IDC_STATIC4), hInst);
myAbout1.SetCheckInitial();
myAbout2.Create(GetDlgItem(hDlg, IDC_STATIC5), hInst);
myAbout2.SetCheckInitial();
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
if (LOWORD(wParam) == IDOK) {
myAbout1.GetCheckFinal();
myAbout2.GetCheckFinal();
}
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
Some context:
I have an application that opens the first webcam device on Windows 10 64bit (whatever index 0 is during enumeration of devices) and does some processing on the frames. The application's source code is not accessible.
Question:
I need to make this application to work with two webcams at the same time. I thought maybe there is a way to do the following:
hide webcam 2
run application (picks up webcam 1)
hide webcam 1, unhide webcam 2
run application (picks up webcam 2)
Is there a way to do this without interrupting camera's operation? Note that both applications are running at the same time so hard-disabling a camera is not an option. Calling either a Win32 api or doing this in PowerShell is acceptable.
Thanks!
Thanks to comments on my original question, I managed to solve my problem by hooking into CM_Get_Device_Interface_List_ExW Win32 API call.
I had to verify what API is being called, so I used and API tracer tool (API monitor v2 64bit). Debugger should work too but for some reason my VS debugger did not show me any symbols (possibly missing pdbs).
The original process I tried to hook into is written in C# so I hooked into the call via an injected C# DLL containing EasyHook. Here is my code snippet (actual injection code left out):
using System;
using System.Runtime.InteropServices;
using EasyHook;
public class HookDevices : IEntryPoint
{
LocalHook FunctionLocalHook;
// construct this to hook into calls
HookDevices()
{
try
{
FunctionLocalHook = LocalHook.Create(
LocalHook.GetProcAddress("CfgMgr32.dll", "CM_Get_Device_Interface_List_ExW"),
new FunctionHookDelegate(CM_Get_Device_Interface_List_Ex_Hooked),
this);
FunctionLocalHook.ThreadACL.SetExclusiveACL(new Int32[] { 0 });
}
catch (Exception ExtInfo)
{
Debug.LogException(ExtInfo);
return;
}
}
[UnmanagedFunctionPointer(CallingConvention.StdCall,
CharSet = CharSet.Unicode,
SetLastError = true)]
delegate uint FunctionHookDelegate(
ref Guid interfaceClassGuid,
string deviceID,
IntPtr buffer,
uint bufferLength,
uint flags,
IntPtr hMachine);
[DllImport("CfgMgr32.dll",
CharSet = CharSet.Unicode,
SetLastError = true,
CallingConvention = CallingConvention.StdCall)]
static extern uint CM_Get_Device_Interface_List_ExW(
ref Guid interfaceClassGuid,
string deviceID,
IntPtr buffer,
uint bufferLength,
uint flags,
IntPtr hMachine);
// this is where we are intercepting all API accesses!
static uint CM_Get_Device_Interface_List_Ex_Hooked(
ref Guid interfaceClassGuid,
string deviceID,
IntPtr buffer,
uint bufferLength,
uint flags,
IntPtr hMachine)
{
// pass-through original API
uint ret = CM_Get_Device_Interface_List_ExW(
ref interfaceClassGuid,
deviceID,
buffer,
bufferLength,
flags,
hMachine);
// do custom logic here and re-arrange "buffer"
return ret;
}
}