I want to get the pixels of every physical screen individually, but MSDN says GetDC needs a window to know which screen to get the handle of. Is there any way of telling it which handle to use without using a window or mouse?
So I can call EnumDisplayDevices and as suggested loop through to find how many monitors are attached and the information of each: Problem is I am using the code provided by Microsoft:
http://msdn.microsoft.com/en-us/library/windows/desktop/dd144942(v=vs.85).aspx
Using this code it has errors on the EnumDisplayDevices call "Too many arguments in function call"
BOOL GetDisplayMonitorInfo(int nDeviceIndex, LPSTR lpszMonitorInfo)
{
FARPROC EnumDisplayDevices;
HINSTANCE hInstUser32;
DISPLAY_DEVICE DispDev;
char szSaveDeviceName[33];
BOOL bRet = TRUE;
HRESULT hr;
hInstUser32 = LoadLibrary("c:\\windows\User32.DLL");
if (!hInstUser32) return FALSE;
EnumDisplayDevices = (FARPROC)GetProcAddress(hInstUser32, "EnumDisplayDevicesA");
if (!EnumDisplayDevices) {
FreeLibrary(hInstUser32);
return FALSE;
}
ZeroMemory(&DispDev, sizeof(DispDev));
DispDev.cb = sizeof(DispDev);
if (EnumDisplayDevices(NULL, nDeviceIndex, &DispDev, 0))
{
hr = StringCchCopy(szSaveDeviceName, 33, DispDev.DeviceName);
if (FAILED(hr))
{
}
EnumDisplayDevices(szSaveDeviceName, 0, &DispDev, 0);
hr = StringCchCopy(lpszMonitorInfo, 129, DispDev.DeviceString);
if (FAILED(hr))
{
// TODO: write error handler
}
}
else {
bRet = FALSE;
}
FreeLibrary(hInstUser32);
return bRet;
}
This was handled in KB117428 because of C to C++ code porting (i.e. that code was originally written in C).
The proposed solution is to properly handle the typedefs
typedef BOOL (WINAPI *EDDType)(LPCSTR,DWORD,PDISPLAY_DEVICEA,DWORD);
BOOL GetDisplayMonitorInfo(int nDeviceIndex, LPSTR lpszMonitorInfo)
{
EDDType EnumDisplayDevices;
HINSTANCE hInstUser32;
DISPLAY_DEVICE DispDev;
char szSaveDeviceName[33];
BOOL bRet = TRUE;
HRESULT hr;
hInstUser32 = LoadLibrary("c:\\windows\\User32.DLL"); // You forgot the double backslash
if (!hInstUser32) return FALSE;
EnumDisplayDevices = (EDDType)GetProcAddress(hInstUser32, "EnumDisplayDevicesA");
Related
I am trying to implement a wrapper function for EnumWindows API function to be included in my wrapper dll, so it can be used with many scripting languages.
First of all, I had to test it using VBScript. I implemented a wrapper function and a callback function for EnumWindows with the help of my useful researches, but it is not working as I want.
Here is the code I currently have:
Wrapper functions for EnumWindows and EnumWindowsProc callback:
BOOL CALLBACK EnumWindowsProc(__in HWND hWnd, __in LPARAM lParam) {
LPENUMWINDOWSPARAMS pewParams;
VARIANT vhWnd, vResult; HRESULT HR = S_OK;
VariantInit(&vhWnd);
VariantInit(&vResult);
vhWnd.vt = VT_I4;
vhWnd.lVal = (LONG)(LONG_PTR)hWnd;
pewParams = reinterpret_cast<LPENUMWINDOWSPARAMS>(lParam);
// ^ PASSING MY PARAMETERS THROUGH LPARAM
CComVariant varArgs[2] = { &vResult, &vhWnd };
DISPPARAMS Parameters = { &varArgs[0], NULL, 2, 0 };
pewParams->DISPATCH->Invoke(0, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &Parameters, &vResult, NULL, NULL);
// ^ I SUSPECT SOMETHING IS WRONG WITH THIS INVOKE METHOD. BUT IT RETURNS S_OK.
if (vResult.vt != VT_BOOL) { HR = DISP_E_TYPEMISMATCH; }
pewParams->CallbackResult.vt = VT_ERROR;
pewParams->CallbackResult.scode = HR;
if (HR == S_OK)
return (vResult.boolVal == VARIANT_TRUE ? TRUE : FALSE);
else
return FALSE;
}
STDMETHODIMP CWinAPI::WinAPI_EnumWindows(VARIANT EnumFunc, int lParam, int *Result) {
ENUMWINDOWSPARAMS ewParams; HRESULT HR = S_OK;
switch (EnumFunc.vt)
{
case VT_DISPATCH:
ewParams.DISPATCH = EnumFunc.pdispVal;
break;
case VT_VARIANT | VT_BYREF:
if (EnumFunc.pvarVal->vt == VT_DISPATCH) { ewParams.DISPATCH = EnumFunc.pvarVal->pdispVal; }
break;
default: return DISP_E_TYPEMISMATCH;
}
ewParams.lParam = reinterpret_cast<LPVARIANT>(&lParam);
*Result = (int)EnumWindows(EnumWindowsProc, reinterpret_cast<LPARAM>(&ewParams));
HR = ewParams.CallbackResult.scode;
return HR;
}
ENUMWINDOWSPARAMS structure:
typedef struct tagENUMWINDOWSPARAMS {
LPDISPATCH DISPATCH;
LPVARIANT lParam;
VARIANT CallbackResult;
} ENUMWINDOWSPARAMS, *PENUMWINDOWSPARAMS, *LPENUMWINDOWSPARAMS;
Here is the testing VBScript I am currently using:
Dim WINAPI: Set WINAPI = WScript.CreateObject("WinAPIWrapperLib.WINAPI")
Function EnumWindowsProc(HWND, lParam)
WScript.Echo "Handle to the window: 0x" + CStr(UCase(Hex(HWND)))
EnumWindowsProc = True
End Function
Dim Result: Result = WINAPI.WinAPI_EnumWindows(GetRef("EnumWindowsProc"), 0)
WScript.Echo "EnumWindows returned " + CStr(Result)
One thing works, EnumWindows is returning True.
But, instead what I expect, I am not getting handles of windows echoed.
And when I call GetLastError, it returns ERROR_SUCCESS.
Thanks in advance for your kind help.
I fixed the problem, nothing special done, it's only a small change:
Changed varArgs's type from CComVariant to VARIANT like this:
VARIANT varArgs[2] = { vResult, vhWnd };
Changed DISPPARAMS as below:
DISPPARAMS Parameters = {};
Parameters.cArgs = 2;
Parameters.rgvarg = varArgs;
Invoke method is still the same:
pewParams->DISPATCH->Invoke(0, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &Parameters, &vResult, NULL, NULL);
Any good suggestions are further appreciated.
I would need to get all elements of webpage displayed in IE from a c++ program.
I tried to see with spy++ but there's only the IEFrame.
So I'm thinking about using the developement tool (F12 in IE), I heard there's a way to automat it, a good idea ?
Thanks
You can get an IHtmlDocument2 reference from an IE's window handle, even out-of-process. This is documented here https://support.microsoft.com/en-us/help/249232/how-to-get-ihtmldocument2-from-a-hwnd, but not really supported by Microsoft.
However it looks like it still works today, I've tested it with a Windows 10 box, and IE is now a frozen app, so not going to change any time soon.
Once you have the proper HWND for Internet Explorer, than you can get the DOM with a code like this. Make sure IE and your program run at the same security level
The DOM is the same as when you're coding IE inprocess (host, activex, etc.), however for security reasons, some things may not work :
void DoSomeDomOperations(HWND hwnd)
{
UINT msg = RegisterWindowMessage(L"WM_HTML_GETOBJECT");
LRESULT result = 0;
SendMessageTimeout(hwnd, msg, NULL, NULL, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR)&result);
if (!result)
return;
// get main document object
IHTMLDocument2 *doc = NULL;
ObjectFromLresult(result, IID_IHTMLDocument2, NULL, (void**)&doc);
if (!doc)
return;
// get document's url
BSTR url = NULL;
doc->get_URL(&url);
wprintf(L"url:%s\n", url);
SysFreeString(url);
// get body element
IHTMLElement *element = NULL;
doc->get_body(&element);
if (element)
{
BSTR text = NULL;
element->get_innerText(&text);
wprintf(L"text:%s\n", text);
SysFreeString(text);
element->Release();
}
// etc.
// etc.
doc->Release();
}
And here is a full sample console app that scans all current IE processes running:
BOOL CALLBACK GetIEServerWindowProc(HWND hwnd, LPARAM lParam)
{
// enumerate all child windows to find IE's COM server
wchar_t className[100];
GetClassName(hwnd, className, 100);
if (!wcscmp(className, L"Internet Explorer_Server"))
{
*((HWND*)lParam) = hwnd;
return FALSE;
}
return TRUE;
}
HWND GetIEServerWindow(HWND hwnd)
{
HWND serverHwnd = NULL;
EnumChildWindows(hwnd, GetIEServerWindowProc, (LPARAM)&serverHwnd);
return serverHwnd;
}
struct IEServer
{
DWORD processId;
HWND serverHwnd;
};
BOOL CALLBACK GetIEProcessServerWindowProc(HWND hwnd, LPARAM lParam)
{
DWORD processId = ((IEServer*)lParam)->processId;
DWORD pid;
GetWindowThreadProcessId(hwnd, &pid);
if (pid == processId)
{
HWND serverHwnd = GetIEServerWindow(hwnd);
if (serverHwnd)
{
((IEServer*)lParam)->serverHwnd = serverHwnd;
return FALSE;
}
}
return TRUE;
}
HWND GetIEProcessServerWindow(DWORD processId)
{
IEServer ie = { processId, NULL };
EnumWindows(GetIEProcessServerWindowProc, (LPARAM)&ie);
return ie.serverHwnd;
}
void EnumerateIEProcesses()
{
HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (h == INVALID_HANDLE_VALUE)
return;
PROCESSENTRY32 process;
process.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(h, &process))
{
do
{
// we only consider IE processes
if (!wcscmp(process.szExeFile, L"iexplore.exe"))
{
HWND serverHwnd = GetIEProcessServerWindow(process.th32ProcessID);
if (serverHwnd)
{
DoSomeDomOperations(serverHwnd);
}
}
} while (Process32Next(h, &process));
}
CloseHandle(h);
}
int main()
{
CoInitialize(NULL);
EnumerateIEProcesses();
CoUninitialize();
return 0;
}
I'm working on a C/S application, Server in C++ and Client in C#, I need to send some information about current running processes and related icon.
I get icon file thanks to EnumWindows with this code inside the callback...
// Get the window icon
HICON hIcon = (HICON)(::SendMessageW(hWnd, WM_GETICON, ICON_SMALL, 0));
if (hIcon == 0) {
// Alternative method. Get from the window class
hIcon = reinterpret_cast<HICON>(::GetClassLongPtrW(hWnd, GCLP_HICONSM));
}
// Alternative: get the first icon from the main module
if (hIcon == 0) {
hIcon = ::LoadIcon(GetModuleHandleW(0), MAKEINTRESOURCE(0));
}
// Alternative method. Use OS default icon
if (hIcon == 0) {
hIcon = ::LoadIcon(0, IDI_APPLICATION);
}
OK, now I have the Icon and I can "print" it (simply for check) with DrawIcon().
My question is: How to get bytes starting from this?
I need a buffer to send this data to my Client and CONVERT the same data to display icon in a list (icon + process_name). So, I need to get bytes of this icon/hIcon (or bitmap/hBitmap, etc.)
(Of course I need help for server side.)
I think is good to copy the icon in a temp buffer to get bytes but nothing works.
Any help would be appreciated.
EDIT:
#DavidHeffernan thank you for reply. I found this: Converting-DDB-to-DIB through StackOverflow's past questions (sorry if is bad to post external links).
Now, with GetDIBits() I have in the fifth param the LPVOID lpvBits , that is "A pointer to a buffer to receive the bitmap data msdn - GetDIBits()"
Now, How Should I send from lpvBits? What's about Bitmap Size?
I've found something on MSDN and StackOverflow and it helped me: link;
#include "stdafx.h"
#include <windows.h>
#include <olectl.h>
#pragma comment(lib, "oleaut32.lib")
HRESULT SaveIcon(HICON hIcon, const wchar_t* path) {
// Create the IPicture intrface
PICTDESC desc = { sizeof(PICTDESC) };
desc.picType = PICTYPE_ICON;
desc.icon.hicon = hIcon;
IPicture* pPicture = 0;
HRESULT hr = OleCreatePictureIndirect(&desc, IID_IPicture, FALSE, (void**)&pPicture);
if (FAILED(hr)) return hr;
// Create a stream and save the image
IStream* pStream = 0;
CreateStreamOnHGlobal(0, TRUE, &pStream);
LONG cbSize = 0;
hr = pPicture->SaveAsFile(pStream, TRUE, &cbSize);
// Write the stream content to the file
if (!FAILED(hr)) {
HGLOBAL hBuf = 0;
GetHGlobalFromStream(pStream, &hBuf);
void* buffer = GlobalLock(hBuf);
HANDLE hFile = CreateFile(path, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
if (!hFile) hr = HRESULT_FROM_WIN32(GetLastError());
else {
DWORD written = 0;
WriteFile(hFile, buffer, cbSize, &written, 0);
CloseHandle(hFile);
}
GlobalUnlock(buffer);
}
// Cleanup
pStream->Release();
pPicture->Release();
return hr;
}
int _tmain(int argc, _TCHAR* argv[])
{
HICON hIcon = (HICON)LoadImage(0, L"c:\\windows\\system32\\perfcentercpl.ico", IMAGE_ICON, 32, 32, LR_LOADFROMFILE);
if (!hIcon) return GetLastError();
HRESULT hr = SaveIcon(hIcon, L"c:\\temp\\test.ico");
return hr;
}
Thanks to SaveIcon() I can save it and after, when needed, I can open it as binary file and send it via socket.
When error occurs in the program, on the screen we can see something like this:
Is there anyway to determine this situation using c++ winapi? I have aldready tried to use this code to find out if the main thread of the procces is suspend. But it doesn't.
I also tried to send timeot messages(code below) but result is always true, even if error window have appeared.
typedef struct tagENUMINFO
{
// In Parameters
DWORD PId;
// Out Parameters
HWND hWnd;
HWND hEmptyWnd;
HWND hInvisibleWnd;
HWND hEmptyInvisibleWnd;
} ENUMINFO, *PENUMINFO;
BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam)
{
DWORD pid = 0;
PENUMINFO pInfo = (PENUMINFO)lParam;
TCHAR szTitle[_MAX_PATH+1];
// sanity checks
if (pInfo == NULL)
// stop the enumeration if invalid parameter is given
return(FALSE);
// get the processid for this window
if (!::GetWindowThreadProcessId(hWnd, &pid))
// this should never occur :-)
return(TRUE);
// compare the process ID with the one given as search parameter
if (pInfo->PId == pid)
{
// look for the visibility first
if (::IsWindowVisible(hWnd))
{
// look for the title next
if (::GetWindowText(hWnd, szTitle, _MAX_PATH) != 0)
{
pInfo->hWnd = hWnd;
// we have found the right window
return(FALSE);
}
else
pInfo->hEmptyWnd = hWnd;
}
else
{
// look for the title next
if (::GetWindowText(hWnd, szTitle, _MAX_PATH) != 0)
{
pInfo->hInvisibleWnd = hWnd;
}
else
pInfo->hEmptyInvisibleWnd = hWnd;
}
}
// continue the enumeration
return(TRUE);
}
HWND GetMainWindow(DWORD PId)
{
ENUMINFO EnumInfo;
// set the search parameters
EnumInfo.PId = PId;
// set the return parameters to default values
EnumInfo.hWnd = NULL;
EnumInfo.hEmptyWnd = NULL;
EnumInfo.hInvisibleWnd = NULL;
EnumInfo.hEmptyInvisibleWnd = NULL;
// do the search among the top level windows
::EnumWindows((WNDENUMPROC)EnumWindowsProc, (LPARAM)&EnumInfo);
// return the one found if any
if (EnumInfo.hWnd != NULL)
return(EnumInfo.hWnd);
else if (EnumInfo.hEmptyWnd != NULL)
return(EnumInfo.hEmptyWnd);
else if (EnumInfo.hInvisibleWnd != NULL)
return(EnumInfo.hInvisibleWnd);
else
return(EnumInfo.hEmptyInvisibleWnd);
}
DWORD GetProcessByExeName(char *ExeName)
{
DWORD Pid;
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(PROCESSENTRY32);
HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPALL, NULL);
if (hProcessSnap == INVALID_HANDLE_VALUE)
{
return false;
}
if (Process32First(hProcessSnap, &pe32))
{
do
{
if (strcmpi(pe32.szExeFile, ExeName) == 0)
{
CloseHandle(hProcessSnap);
return pe32.th32ProcessID;
}
} while (Process32Next(hProcessSnap, &pe32));
}
CloseHandle(hProcessSnap);
return 0;
}
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE prev, LPSTR cmdline, int show)
{
HWND Hwnd;
LRESULT res;
DWORD PID;
PID=GetProcessByExeName("procces.exe");
Hwnd=GetMainWindow(PID);
res = SendMessageTimeout(Hwnd, WM_NULL, NULL, NULL, SMTO_ABORTIFHUNG, 3000,NULL);
//res == 1 always
}
Yes there is a way, all crash interceptors work this way, like the firefox crash reporter.
On windows you can use structured exception handling:
reference:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms680657(v=vs.85).aspx
and howto:
http://www.codeproject.com/Articles/207464/Exception-Handling-in-Visual-Cplusplus
extract:
LONG WINAPI MyUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionPtrs)
{
// Do something, for example generate error report
//..
// Execute default exception handler next
return EXCEPTION_EXECUTE_HANDLER;
}
void main()
{
SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
// .. some unsafe code here
}
I found another solution. This error message has it's own procces WerFault.exe, we can simply destroy it with TerminateProcess() and the hang procces will be destroyed too. And then it is quite simple to notice that the required process does not exist.
I am using Viveks capture filter with vlc (http://tmhare.mvps.org/downloads/vcam.zip) to emulate a capture source. When the filter is open and I close vlc I get a crash. The stack trace indicates that 2 COM objects still exist (Im guessing the filter and pin) which should be released before a CoUninitialize call. My problem is I am not sure where to release the filter and pin COM objects, I have a destructor for the fitler and pin but they are never called when vlc closes. Someone who had a similar problem (Unreleased DirectShow CSource filter makes program crash at process shutdown).
This is the important registering part of the dll.
STDAPI RegisterFilters( BOOL bRegister )
{
HRESULT hr = NOERROR;
WCHAR achFileName[MAX_PATH];
char achTemp[MAX_PATH];
ASSERT(g_hInst != 0);
if( 0 == GetModuleFileNameA(g_hInst, achTemp, sizeof(achTemp)))
return AmHresultFromWin32(GetLastError());
MultiByteToWideChar(CP_ACP, 0L, achTemp, lstrlenA(achTemp) + 1,
achFileName, NUMELMS(achFileName));
hr = CoInitialize(0);
if(bRegister)
{
hr = AMovieSetupRegisterServer(CLSID_VirtualCam, L"Virtual Cam", achFileName, L"Both", L"InprocServer32");
}
if( SUCCEEDED(hr) )
{
IFilterMapper2 *fm = 0;
hr = CreateComObject( CLSID_FilterMapper2, IID_IFilterMapper2, fm );
if( SUCCEEDED(hr) )
{
if(bRegister)
{
IMoniker *pMoniker = 0;
REGFILTER2 rf2;
rf2.dwVersion = 1;
rf2.dwMerit = MERIT_DO_NOT_USE;
rf2.cPins = 1;
rf2.rgPins = &AMSPinVCam;
hr = fm->RegisterFilter(CLSID_VirtualCam, L"Virtual Cam", &pMoniker, &CLSID_VideoInputDeviceCategory, NULL, &rf2);
}
else
{
hr = fm->UnregisterFilter(&CLSID_VideoInputDeviceCategory, 0, CLSID_VirtualCam);
}
}
// release interface
//
if(fm)
fm->Release();
}
if( SUCCEEDED(hr) && !bRegister )
hr = AMovieSetupUnregisterServer( CLSID_VirtualCam );
CoFreeUnusedLibraries();
CoUninitialize();
return hr;
}
STDAPI DllRegisterServer()
{
return RegisterFilters(TRUE);
}
STDAPI DllUnregisterServer()
{
return RegisterFilters(FALSE);
}
extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
{
return DllEntryPoint((HINSTANCE)(hModule), dwReason, lpReserved);
}
The important filter part
CVCamStream::CVCamStream(HRESULT *phr, CVCam *pParent, LPCWSTR pPinName) :
CSourceStream(NAME("Virtual Cam"),phr, pParent, pPinName), m_pParent(pParent)
{
// Set the default media type as 320x240x24#15
GetMediaType(4, &m_mt);
}
CVCamStream::~CVCamStream()
{
m_pParent->Release();
}
Leaked COM references are a sort of hard to nail down. Assuming that COM client - in your case VLC - is doing everything right (which might be not the case, but it's okay to start with this assumption), the problem is on your code. It is typically one of the two:
You are dealing with raw pointers and there is somewhere no matching Release for AddRef done earlier
There are circular references and object keep each other alive
As you already see you have two objects floating around, a good strategy would be to identify what classes are they exactly, and trace reference counter changes to see where is the lost IUnknown::Release.