I want to create a COM control in Win32 by clsid: {3523C2FB-4031-44E4-9A3B-F1E94986EE7F} and then use the api QueryInterface to send commands to it. In MFC project this would be very simple in 4 lines of code:
m_wndMsTsc.CreateControl(L"{3523C2FB-4031-44E4-9A3B-F1E94986EE7F}", NULL, WS_VISIBLE, CRect(10, 10, 470, 280), this,0))
LPUNKNOWN lpUnk = m_wndMsTsc.GetControlUnknown();
lpUnk->QueryInterface(IID_IMsRdpClient5, (void**)&m_pMsTsc);
lpUnk->QueryInterface(IID_IMsRdpClientNonScriptable5, (void**)&pns);
In Win32 what i tried so far:
container = ::CreateWindow(L"EDIT",L"", WS_CHILD | WS_VISIBLE, 0, 0, rect.right, rect.bottom, mainWindow, 0, hInstance, 0);
IMsRdpClient5 *rdpClient = NULL;
// Then initialize com control
CoInitialize(0);
CoCreateInstance(CLSID_MsRdpClient5, 0, CLSCTX_ALL, IID_IMsRdpClient5, (void**)&rdpClient);
// Attach
AtlAxAttachControl(rdpClient, container, 0);
IUnknown *pUnk = NULL;
AtlAxGetControl(container, &pUnk);
pUnk->QueryInterface(IID_IMsRdpClient5, (void**)&rdpClient);
A very basic example how to create a control by clsid and attach it to IUnknown would be very helpful!
HRESULT hr = AtlAxWinInit();
HWND hWnd = CreateWindow(_T("AtlAxWin"), _T("{3523C2FB-4031-44E4-9A3B-F1E94986EE7F}"), WS_CHILD | WS_VISIBLE, 10, 10, 400, 300, hwnd, (HMENU)102, NULL, NULL);
IUnknown *unkn;
hr = AtlAxGetControl(hWnd, &unkn);
unkn->QueryInterface(IID_IMsRdpClient5, (void**)&rdpClient);
unkn->QueryInterface(IID_IMsRdpClientNonScriptable5, (void**)&rdpClientNonScriptable);\
This method works perfectly in Win32. Thanks everyone for ideas
Related
I'm coding my Win32 application with MFC shared DLL and I was trying to use ActiveX controls on it , is that possible? or I'm just wasting my time?
When creating a new MFC project, make sure you activate ActiveX support (example using VS2008):
Often you want to use an ActiveX control from within a dialog window. Right click on the dialog in the designer view and select 'Insert ActiveX control' and select the ActiveX you want:
If you want to freely embed an ActiveX control outside a dialog, there is an ATL wrapper for MFC. But it's a bit more tricky and would look like this:
#include "stdafx.h"
#include "atlbase.h"
#include "oleidl.h"
#include "comdef.h"
...
...
AtlAxWinInit();
pPluginWnd = new CAxWindow();
CRect r = GetParent()->GetClientRect();
if (!pPluginWnd->Create(GetParent()->m_hWnd, r, "ActiveX Plugin Window", WS_VISIBLE
| WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VSCROLL | WS_HSCROLL)))
{
AfxMessageBox("Couldn't create the ActiveX host window");
return;
}
LPUNKNOWN pUnk;
pPluginWnd->QueryControl(&pUnk);
IDispatch *spDispatch;
HRESULT hRes = pUnk->QueryInterface(__uuidof(spDispatch), (void **) &spDispatch);
if (hRes != S_OK)
{
AfxMessageBox("Couldn't query the ActiveX interface");
return;
}
// get a method called 'Init' in the ActiveX to pass a long integer parameter to it
long nMyValueToPass;
DISPID dispid;
OLECHAR FAR szMember[5];
MultiByteToWideChar(CP_ACP, 0, "Init", -1, szMember, 5);
OLECHAR FAR *pszMember = szMember;
DISPPARAMS dispparams = { NULL, NULL, 0, 0 };
VARIANT vRet;
COleVariant vParam(nMyValueToPass,VT_I4);
EXCEPINFO excepinfo;
UINT nArgErr;
dispparams.rgvarg = (LPVARIANT)vParam;
dispparams.cArgs = 1;
dispparams.cNamedArgs = 0;
hRes = spDispatch->GetIDsOfNames(IID_NULL, &pszMember, 1, LOCALE_SYSTEM_DEFAULT, &dispid);
if (hRes != S_OK)
{
AfxMessageBox("Init method couldn't be found in ActiveX control");
return;
}
// call the Init method
hRes = spDispatch->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT,
DISPATCH_METHOD, &dispparams, &vRet, &excepinfo, &nArgErr);
I'm coding a application like Notepad in Win32 c++. But when i change szClassName in createWindow(), the menu can't work although it still show it when I run
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // Store instance handle in our global variable
hMenu = LoadMenu(hInst, MAKEINTRESOURCE(IDC_NOTEPAD));
hWnd = CreateWindow(L"EDIT", szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, hMenu, hInstance, NULL);
//SetWindowLong(hWnd, GWL_WNDPROC, (LONG)WndProc);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
In CreateWindow(), the hMenu parameter is the control ID but not the menu handle.
I suggest creating the main window before adding a textbox:
WNDCLASSEX wc;
// ...
wc.lpszClassName="window class";
wc.lpszMenuName=hMenu;
// ...
RegisterWindowEx(&wc);
hWnd=CreateWindow("window class", ...);
// When processing WM_CREATE message in WndProc()
hEdit=CreateWindow("EDIT","your textbox", ... /* set hWndParent as hWnd */);
I think theForger's Win32 API Programming Tutorial is also a good place for you to start.
I have this program that is supposed to print a rectangle on the printer. It uses standard Win32 API calls.
HANDLE hdl;
DEVMODE* devmode;
OpenPrinter(L"HP Deskjet F4400 series", &hdl, NULL);
int size = DocumentProperties(NULL, hdl, L"HP Deskjet F4400 series", NULL, NULL, 0);
devmode = (DEVMODE*)malloc(size);
DocumentProperties(NULL, hdl, L"HP Deskjet F4400 series", devmode, NULL, DM_OUT_BUFFER);
HDC printerDC = CreateDC(L"WINSPOOL", devmode->dmDeviceName, NULL, devmode);
DOCINFO info;
memset(&info, 0, sizeof(info));
info.cbSize = sizeof(info);
StartDoc(printerDC, &info);
StartPage(printerDC);
Rectangle(printerDC, 100, 100, 200, 200);
EndPage(printerDC);
EndDoc(printerDC);
DeleteDC(printerDC);
All the API calls succeed, but no printing happens. What did I do wrong?
There's a couple of issues here:
You're not closing the printer with ClosePrinter
The parameters to OpenPrinter and CreateDC are incorrect - they need to be an actual printer name, not a printer class. (When I tried your code, the APIs failed.)
I tweaked the GDI print sample to print to the default printer, and it works; I modified your sample appropriately:
HANDLE hdl;
DEVMODE* devmode;
wchar_t szPrinter[MAX_PATH];
DWORD cchPrinter(ARRAYSIZE(szPrinter));
GetDefaultPrinter(szPrinter, &cchPrinter);
OpenPrinter(szPrinter, &hdl, NULL);
int size = DocumentProperties(NULL, hdl, szPrinter, NULL, NULL, 0);
devmode = (DEVMODE*)malloc(size);
DocumentProperties(NULL, hdl, szPrinter, devmode, NULL, DM_OUT_BUFFER);
HDC printerDC = CreateDC(L"WINSPOOL", szPrinter, NULL, devmode);
DOCINFO info;
memset(&info, 0, sizeof(info));
info.cbSize = sizeof(info);
StartDoc(printerDC, &info);
StartPage(printerDC);
Rectangle(printerDC, 100, 100, 200, 200);
EndPage(printerDC);
EndDoc(printerDC);
DeleteDC(printerDC);
ClosePrinter(hdl);
I am using the WinAPI to create a GUI utility. I have two Tabs and each tab has some buttons. I am creating the buttons with this function:
CreateWindowEx(NULL,"button", "Clear", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
150, 175, 100, 25, tab_window_2, (HMENU) CLEAR_DATA, instance_handle, NULL);
In the Windows proc function, I don't know how to detect when the above button is pressed. I also tried handling CLEAR_DATA in the WM_COMMAND switch construct, as follows.
switch ( message ) {
case WM_COMMAND:{
switch(LOWORD(wparam)) {
case CLEAR_DATA : break
}
}
How can I detect and handle those buttons being pressed?
I am creating the tab_window_2 tab as follows :
class frame_window {
private:
LPCSTR window_class_name;
HINSTANCE instance_handle;
HCURSOR cursor_arrow;
HWND window_handle;
HWND tab_handle;
HWND tab_window_1;
HWND tab_window_2;
HWND current_tab_window;
RECT client_rectangle;
public:
frame_window(LPCSTR window_class_identity) : window_class_name(window_class_identity) {
INITCOMMONCONTROLSEX common_controls;
common_controls.dwSize = sizeof(INITCOMMONCONTROLSEX);
common_controls.dwICC = ICC_BAR_CLASSES;
InitCommonControlsEx(&common_controls);
int screen_width = GetSystemMetrics(SM_CXFULLSCREEN);
int screen_height = GetSystemMetrics(SM_CYFULLSCREEN);
instance_handle = GetModuleHandle(NULL);
WNDCLASS window_class = { CS_OWNDC, main_window_proc, 0, 0,
instance_handle, NULL,
NULL, NULL, NULL,
window_class_name };
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Create a standard frame window
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
RegisterClass(&window_class);
window_handle = CreateWindowEx(WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE,
window_class_name,
"IR Remote and Barcode Demo",
WS_OVERLAPPEDWINDOW |
WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
100, 100, screen_width-1600,
screen_height-490, NULL, NULL,
instance_handle, NULL);
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Get the size of the client rectangle for the window we have just created
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
RECT client_rect;
GetClientRect(window_handle, &client_rect);
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Create the tab control window.
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
tab_handle = CreateWindowEx(NULL, WC_TABCONTROL, NULL,
WS_CHILD | WS_VISIBLE,
10, 10, client_rect.right-client_rect.left-20,
client_rect.bottom-client_rect.top-10,
window_handle, NULL,
instance_handle, NULL);
// Create three tabs.
TCITEM tab_info;
memset(&tab_info, 0, sizeof(tab_info));
tab_info.mask = TCIF_TEXT;
tab_info.pszText = "tab#1";
tab_info.cchTextMax = 5;
SendMessage(tab_handle, TCM_INSERTITEM, 0, (LPARAM)&tab_info);
tab_info.pszText = "tab#2";
SendMessage(tab_handle, TCM_INSERTITEM, 1, (LPARAM)&tab_info);
RECT tab_rectangle;
GetClientRect(tab_handle, &tab_rectangle);
SendMessage(tab_handle, TCM_ADJUSTRECT, FALSE, (LPARAM)&tab_rectangle);
// Create the tab view windows
tab_window_1 = CreateWindowEx(NULL, "STATIC", " ",
WS_CHILD | WS_VISIBLE|SS_OWNERDRAW,
tab_rectangle.left+10, tab_rectangle.top+10,
tab_rectangle.right-tab_rectangle.left,
tab_rectangle.bottom -tab_rectangle.top,
tab_handle, (HMENU)1,
instance_handle, NULL);
SetParent(tab_window_1, window_handle);
current_tab_window = tab_window_1;
tab_window_2 = CreateWindowEx(NULL, "STATIC", " ",
WS_CHILD|SS_OWNERDRAW,
tab_rectangle.left+10, tab_rectangle.top+10,
tab_rectangle.right-tab_rectangle.left,
tab_rectangle.bottom -tab_rectangle.top,
tab_handle, (HMENU)2,
instance_handle, NULL);
CreateWindowEx(NULL,"button", "Clear", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
150, 175, 100, 25, tab_window_2, (HMENU) CLEAR_DATA, instance_handle, NULL);
SetParent(tab_window_2, window_handle);
SetCursor(LoadCursor(NULL, IDC_ARROW));
SetWindowLongPtr(window_handle, GWL_USERDATA, (LONG)this);
ShowWindow(window_handle, SW_SHOW);
UpdateWindow(window_handle);
}
~frame_window() {
UnregisterClass(window_class_name, instance_handle);
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Windows main entry point
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
int WINAPI wWinMain(HINSTANCE instance_handle, HINSTANCE, LPWSTR, INT) {
frame_window main_window("my base window");
main_window.run();
return 0;
}
The WM_COMMAND for handling the events from a Push Button must be in the Window Procedure of it's parent. Your code show tab_window_2 as the parent for the CLEAR_DATA button.
Move the WM_COMMAND code in the right Window Proc (or Dialog Proc).
EDIT: I think you didn't understand how the Tab Control works.
If you want each Tab View to contain more than a dummy static control, you should use modeless and borderless DialogBox, children of the Tab Control, and show/hide them accordingly to the TCN_SELCHANGE notification.
If you don't realy need the Dialog Box functionalities, you could create regular child windows (with RegisterClass/CreateWindow) and then add your controls as child windows.
In either case, the show/hide code must react to TCN_SELCHANGE.
With regular child windows or with Dialog Box the net effect is the same: you will have a Window Procedure, or a Dialog Procadure, in which WM_COMMAND will deal with user actions.
Don't play with SetParent. But, if you absolutly want it, then use:
HWND hWndPushClear = CreateWindowEx(NULL,"button", "Clear", [...]
SetParent( hWndPushClear, window_handle );
You may have weird Paint/Focus problems, however.
EDIT: Unfortunately, it seems that there is no good Tab Control tutorial in line.
I recommend updating your actual source code. As a starting point, do the following:
Replace CreateWindowEx by CreateDialog for tab_window_1 end tab_window_2 (only one Dialog must be visible)
Suppress all SetParent calls
Your CreateWindowEx() and WM_COMMAND code are seems correct.
So,
Check return value of CreateWindowEx() whether is NULL. NULL means which is failed to create control.
Check HWND of parent is valid. In your code, it is tab_window_2.
Also, if you do not want to any WS_EX_XXX style, you can just use CreateWindow().
This code is just sample.
LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
switch(iMessage) {
case WM_CREATE:
CreateWindow("button","Clear",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
20,20,100,25,hWnd,(HMENU)0,g_hInst,NULL);
return 0;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case 0:
MessageBox(hWnd,"Clear Button Clicked","Button",MB_OK);
break;
}
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}
I have a dialog box on which controls are added with resource editor. But I am trying to create a toolbar on the fly in WM_INITGDIALOG message but the toolbar is not visible. Is there something else to do make it visible(I dont think so but...). If this is not possible how can add a toolbar in resource editor.
As you guessed I use VS 2008.
CreateButtons(HWND hwnd)
{
HIMAGELIST m_hTBImageList;
HIMAGELIST m_hTBHottrack;
HWND hwndSysButtonTB = CreateWindowEx(0,
TOOLBARCLASSNAME,
_T(""),
WS_CHILD | WS_VISIBLE | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | CCS_NORESIZE | CCS_NOPARENTALIGN,
toolbarRect.left, toolbarRect.top, toolbarRect.right-toolbarRect.left, toolbarRect.bottom-toolbarRect.top,
hwnd,
(HMENU)IDR_TOOLBAR,
(HINSTANCE)hAppInstance,
NULL);
m_hTBImageList = ImageList_LoadImage((HINSTANCE)hAppInstance,
MAKEINTRESOURCE(IDB_BITMAP_ICONS), toolbarButtonSize.cx, 1,
0, IMAGE_BITMAP, LR_CREATEDIBSECTION|LR_SHARED);
m_hTBHottrack = ImageList_LoadImage((HINSTANCE)hAppInstance,
MAKEINTRESOURCE(IDB_MOUSEOVER), toolbarButtonSize.cx, 1,
0, IMAGE_BITMAP, LR_CREATEDIBSECTION|LR_SHARED);
SendMessage(hwndSysButtonTB, (UINT) TB_SETIMAGELIST, 0, (LPARAM)m_hTBImageList);
SendMessage(hwndSysButtonTB, (UINT) TB_SETHOTIMAGELIST, 0, (LPARAM)m_hTBHottrack);
SendMessage(hwndSysButtonTB, (UINT) TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
// win2k: set color of hot tracking frame
COLORSCHEME scheme;
scheme.dwSize = sizeof(scheme);
scheme.clrBtnHighlight = RGB(175,175,175);
scheme.clrBtnShadow = RGB(175,175,175);
SendMessage(hwndSysButtonTB, (UINT) TB_SETCOLORSCHEME, 0, (LPARAM)&scheme);
TBBUTTON ButtonEnd = {0,ID_BUTTON_END,TBSTATE_ENABLED,TBSTYLE_BUTTON};
TBBUTTON ButtonRefresh = {1,ID_BUTTON_REFRESH,TBSTATE_ENABLED,TBSTYLE_BUTTON};
TBBUTTON ButtonOptions = {2,ID_BUTTON_PROPERTIES,TBSTATE_ENABLED,TBSTYLE_BUTTON};
SendMessage(hwndSysButtonTB, (UINT) TB_ADDBUTTONS, 1, (LPARAM)&ButtonEnd);
SendMessage(hwndSysButtonTB, (UINT) TB_ADDBUTTONS, 1, (LPARAM)&ButtonRefresh);
SendMessage(hwndSysButtonTB, (UINT) TB_ADDBUTTONS, 1, (LPARAM)&ButtonOptions);
}
You have to call
SendMessage(hwndSysButtonTB, TB_AUTOSIZE, 0, 0);
ShowWindow(hwndSysButtonTB , SW_SHOW);
at the end of your function.
And I think you should use an TBBUTTON array instead of three separate variables. Then you can add them all at once with
SendMessage(hwndSysButtonTB, (UINT) TB_ADDBUTTONS, 3, (LPARAM)&ButtonArray);