Related
I am using DirectSound to capture the sound of my desktop, using the tutorial from MSDN https://msdn.microsoft.com/en-us/library/windows/desktop/ee416968(v=vs.85).aspx
The problem is that when I start to capture, my WAV file gets to hundreds of MB and even GB, in a few seconds.When I play the WAV file, 5 seconds of audio capture become 30 minutes, and the same frame of sound is duplicated like 1000 times.I have noticed that WAIT_OBJECT_0 + 1 and 2 are never fired.Thanks in advance.
bool captureSound = false;
wav_header wavFile; // the wav file
UINT totalData = 0;
LPDIRECTSOUNDCAPTURE8 capturer = NULL;
GUID guid = DSDEVID_DefaultCapture;
HRESULT err;
DSCBUFFERDESC dscbd;
LPDIRECTSOUNDCAPTUREBUFFER8 pDSCB8;
DWORD g_dwNextCaptureOffset = 0;
DWORD g_dwCaptureBufferSize = 0;
DWORD g_dwNotifySize = 0;
#define cEvents 3
WAVEFORMATEX wfx;
HANDLE rghEvent[cEvents] = {0,0,0};
DSBPOSITIONNOTIFY rgdsbpn[cEvents];
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
MSG msg;
HACCEL hAccelTable;
BOOL bDone;
// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_WIN32PROJECT2, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WIN32PROJECT2));
bDone = FALSE;
// Main message loop:
while( !bDone ) {
dwResult = MsgWaitForMultipleObjects( 3, rghEvent,
FALSE, INFINITE, QS_ALLEVENTS );
switch( dwResult ) {
case WAIT_OBJECT_0 + 0:
if(FAILED(RecordCapturedData())) MessageBox(NULL,TEXT("Error!"), TEXT("Error"), MB_OK);
break;
case WAIT_OBJECT_0 + 1:
if(FAILED(RecordCapturedData())) MessageBox(NULL,TEXT("Error!"), TEXT("Error"), MB_OK);
break;
case WAIT_OBJECT_0 + 2:
if(FAILED(RecordCapturedData())) MessageBox(NULL,TEXT("Error!"), TEXT("Error"), MB_OK);
break;
case WAIT_OBJECT_0 + 3:
//MessageBox(NULL,TEXT("wait3"), TEXT("Error"), MB_OK);
// Windows messages are available
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if( msg.message == WM_QUIT )
bDone = TRUE;
}
break;
}
}
//CloseHandle(rghEvent);
return (int) msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_CAPTURESOUND:
captureSound = true;
if (FAILED(createWav(&wavFile)))
{
closeWav(wavFile.pFile);
MessageBox(NULL,TEXT("Error creating the sound file!"), TEXT("Error"), MB_OK);
}
// add the WAV header
for(int i = 0; i < 4; i++) {
fputc(wavFile.riff_header[i], wavFile.pFile);
}
fwrite((char*)&wavFile.wav_size,sizeof(int),1,wavFile.pFile);
for(int i = 0; i < 4; i++) {
fputc(wavFile.wave_header[i], wavFile.pFile);
}
for(int i = 0; i < 4; i++) {
fputc(wavFile.fmt_header[i], wavFile.pFile);
}
fwrite((const char*)&wavFile.fmt_chunk_size,4,1,wavFile.pFile);
fwrite((const char*)&wavFile.audio_format,2,1,wavFile.pFile);
fwrite((const char*)&wavFile.num_channels,2,1,wavFile.pFile);
fwrite((const char*)&wavFile.sample_rate,4,1,wavFile.pFile);
fwrite((const char*)&wavFile.byte_rate,4,1,wavFile.pFile);
fwrite((const char*)&wavFile.sample_alignment,2,1,wavFile.pFile);
fwrite((const char*)&wavFile.bit_depth,2,1,wavFile.pFile);
for(int i = 0; i < 4; i++) {
fputc(wavFile.data_header[i], wavFile.pFile);
}
fwrite((const char*)&wavFile.data_bytes,4,1,wavFile.pFile);
/* Use DirectSoundCaptureCreate8() to create and initialize an object and get the pointer (pDSC8) to IDirectSoundCapture8 */
if(FAILED(DirectSoundCaptureCreate8(&guid, &capturer, NULL))) {
ErrorExit(TEXT("DirectSoundCaptureCreate8"));
}
/* Use the method CreateCaptureBuffer() of IDirectSoundCapture8(pDSC8->CreateSoundBuffer()) to create
and initialize an object and get the pointer (pDSCB) to IDirectSoundCaptureBuffer. */
if(FAILED(CreateCaptureBuffer(capturer,&pDSCB8))) {
ErrorExit(TEXT("CreateCaptureBuffer"));
}
/* Use the method QueryInterface of IDirectSoundCaptureBuffer8(pDSCB8->QueryInterface()) to get a pointer(lpDsNotify) to the interface IDirectSoundNotify8. */
if(FAILED(SetCaptureNotifications(pDSCB8))) {
ErrorExit(TEXT("SetCaptureNotifications"));
}
/* Start capturing */
if(FAILED(pDSCB8->Start( DSCBSTART_LOOPING ) ) )
ErrorExit(TEXT("Start"));
else MessageBox(NULL,TEXT("Started capturing!"), TEXT("Good"), MB_OK);
break;
case IDM_OPRESTE:
captureSound = false;
// Stop the buffer, and read any data that was not
// caught by a notification
if( FAILED(pDSCB8->Stop() ) )
ErrorExit(TEXT("Stop"));
if(FAILED(RecordCapturedData())) MessageBox(NULL,TEXT("ERROR "), TEXT("Error"), MB_OK);
/* Update the fields in the WAV header and close the file */
fseek (wavFile.pFile, 4 , SEEK_SET );
wavFile.wav_size += totalData;
fwrite((char*)&wavFile.wav_size,sizeof(int),1,wavFile.pFile);
wavFile.data_bytes += totalData;
fseek (wavFile.pFile, 40 , SEEK_SET );
fwrite((char*)&wavFile.data_bytes,sizeof(int),1,wavFile.pFile);
closeWav(wavFile.pFile);
break;
case IDM_EXIT:
DestroyWindow(hWnd); // POSTS THE MESSAGE WM_DESTROY TO DESTROY THE CREATED WINDOW.
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_CREATE:
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
HRESULT CreateCaptureBuffer(LPDIRECTSOUNDCAPTURE8 pDSC,
LPDIRECTSOUNDCAPTUREBUFFER8* ppDSCB8)
{
HRESULT hr;
DSCBUFFERDESC dscbd;
LPDIRECTSOUNDCAPTUREBUFFER pDSCB;
// Set up WAVEFORMATEX for 44.1 kHz 16-bit stereo.
WAVEFORMATEX wfx =
{WAVE_FORMAT_PCM, wavFile.num_channels, wavFile.sample_rate, wavFile.byte_rate, wavFile.sample_alignment, wavFile.bit_depth, 0};
// wFormatTag, nChannels, nSamplesPerSec, mAvgBytesPerSec,
// nBlockAlign, wBitsPerSample, cbSize
if ((NULL == pDSC) || (NULL == ppDSCB8)) return E_INVALIDARG;
dscbd.dwSize = sizeof(DSCBUFFERDESC);
dscbd.dwFlags = 0;
dscbd.dwBufferBytes = wfx.nAvgBytesPerSec;
dscbd.dwReserved = 0;
dscbd.lpwfxFormat = &wfx;
dscbd.dwFXCount = 0;
dscbd.lpDSCFXDesc = NULL;
g_dwNotifySize = MAX( 1024, wavFile.byte_rate / 8 );
g_dwNotifySize -= g_dwNotifySize % wavFile.sample_alignment;
g_dwCaptureBufferSize = g_dwNotifySize * 3;
if (SUCCEEDED(hr = pDSC->CreateCaptureBuffer(&dscbd, &pDSCB, NULL)))
{
/* Use the method QueryInterface of IDirectSoundCaptureBuffer(pDSCB->QueryInterface()) to get a
pointer(pDSCB8) to the interface IDirectSoundCaptureBuffer8 */
hr = pDSCB->QueryInterface(IID_IDirectSoundCaptureBuffer8, (LPVOID*)ppDSCB8);
pDSCB->Release();
}
return hr;
}
HRESULT SetCaptureNotifications(LPDIRECTSOUNDCAPTUREBUFFER8 pDSCB)
{
LPDIRECTSOUNDNOTIFY8 pDSNotify;
HRESULT hr;
if (NULL == pDSCB) return E_INVALIDARG;
if (FAILED(hr = pDSCB->QueryInterface(IID_IDirectSoundNotify, (LPVOID*)&pDSNotify)))
{
return hr;
}
if (FAILED(hr = pDSCB->GetFormat(&wfx, sizeof(WAVEFORMATEX), NULL)))
{
return hr;
}
// Create events.
for (int i = 0; i < cEvents; ++i)
{
rghEvent[i] = CreateEvent(NULL, TRUE, FALSE, NULL);
if (NULL == rghEvent[i])
{
hr = GetLastError();
return hr;
}
}
// Describe notifications.
rgdsbpn[0].dwOffset = (wfx.nAvgBytesPerSec/2) -1;
rgdsbpn[0].hEventNotify = rghEvent[0];
rgdsbpn[1].dwOffset = wfx.nAvgBytesPerSec - 1;
rgdsbpn[1].hEventNotify = rghEvent[1];
rgdsbpn[2].dwOffset = DSBPN_OFFSETSTOP;
rgdsbpn[2].hEventNotify = rghEvent[2];
/* Use the SetNotificationPositions() of IDirectSoundNotify8(lpDsNotify->SetNotificationPositions())
to set the notification buffer positions */
hr = pDSNotify->SetNotificationPositions(cEvents, rgdsbpn);
pDSNotify->Release();
return hr;
}
HRESULT RecordCapturedData()
{
HRESULT hr;
VOID* pbCaptureData = NULL;
DWORD dwCaptureLength;
VOID* pbCaptureData2 = NULL;
DWORD dwCaptureLength2;
VOID* pbPlayData = NULL;
UINT dwDataWrote;
DWORD dwReadPos;
LONG lLockSize;
if (NULL == pDSCB8)
MessageBox(NULL,TEXT("Empty buffer!"), TEXT("Error"), MB_OK);
if (NULL == wavFile.pFile)
MessageBox(NULL,TEXT("Empty .wav file!"), TEXT("Error"), MB_OK);
if (FAILED (hr = pDSCB8->GetCurrentPosition(
NULL, &dwReadPos)))
MessageBox(NULL,TEXT("Failed to get current position!"), TEXT("Error"), MB_OK);
// Lock everything between the private cursor
// and the read cursor, allowing for wraparound.
lLockSize = dwReadPos - g_dwNextCaptureOffset;
if( lLockSize < 0 ) lLockSize += g_dwCaptureBufferSize;
// Block align lock size so that we are always write on a boundary
//lLockSize -= (lLockSize % g_dwNotifySize);
if( lLockSize == 0 ) return S_FALSE;
if (FAILED(hr = pDSCB8->Lock(
g_dwNextCaptureOffset, lLockSize,
&pbCaptureData, &dwCaptureLength,
&pbCaptureData2, &dwCaptureLength2, 0L)))
MessageBox(NULL,TEXT("Lock failed!"), TEXT("Error"), MB_OK);
// Write the data. This is done in two steps
// to account for wraparound.
if (FAILED( addData(&wavFile, (BYTE*)pbCaptureData, dwCaptureLength, &dwDataWrote)))
MessageBox(NULL,TEXT("Error writting to the file!"), TEXT("Error"), MB_OK);
if (pbCaptureData2 != NULL)
{
if (FAILED( addData(&wavFile, (BYTE*)pbCaptureData2, dwCaptureLength2, &dwDataWrote)))
MessageBox(NULL,TEXT("Error writting to the file 2!"), TEXT("Error"), MB_OK);
}
// Unlock the capture buffer.
pDSCB8->Unlock( pbCaptureData, dwCaptureLength,
pbCaptureData2, dwCaptureLength2 );
// Move the capture offset forward.
g_dwNextCaptureOffset += dwCaptureLength;
g_dwNextCaptureOffset %= g_dwCaptureBufferSize;
g_dwNextCaptureOffset += dwCaptureLength2;
g_dwNextCaptureOffset %= g_dwCaptureBufferSize;
totalData += (dwCaptureLength + dwCaptureLength2);
return S_OK;
}
Wav writer utility
#include "stdafx.h"
#include "Wav.h"
HRESULT createWav(wav_header* pWav) {
pWav->pFile = fopen("sound.wav","w");
if(pWav->pFile == NULL) {
return 0;
}
strcpy(pWav->riff_header, "RIFF");
strcpy(pWav->wave_header, "WAVE");
strcpy(pWav->fmt_header, "fmt ");
pWav->fmt_chunk_size = 16;
pWav->audio_format = 1;
pWav->num_channels = 2;
pWav->sample_rate = 44100; // 44.1 KHz - CD-quality audio
pWav->bit_depth = 16; // Bits per Sample – The number of bits available for one sample.
pWav->sample_alignment = pWav->num_channels * (pWav->bit_depth)/8; // This is the number of bytes in a frame
pWav->byte_rate = pWav->sample_rate * pWav->sample_alignment; // number of bytes per second captured
strcpy(pWav->data_header, "data");
pWav->data_bytes = 0; // n * frames , n = 0 empty data default, to be updated each time new data is added
pWav->wav_size = 36 + pWav->data_bytes; // to be updated each time new data is added
return S_OK;
}
HRESULT closeWav(FILE * pFile) {
fclose(pFile);
return S_OK;
}
HRESULT addData(wav_header* pWav, VOID* data,UINT dataLength, UINT* dataWrote) {
// set the positon back at the end of the file
fseek (pWav->pFile, 0 , SEEK_END );
*dataWrote = fwrite((const char*)data,sizeof(byte),(size_t)dataLength, pWav->pFile);
return S_OK;
}
edit: how can i get windows title using processname? for example get current title of chrome.exe
You can get title of specific windows using it's process ID.
If you know the name of executed file(ex: Chrome.exe), you can get Handle with FindWindowEX() or get PID "Chrome.exe" with CreateToolHelp32Snapshot.
Then use EnumWindows to get HWND using HANDLE.
struct param_enum
{
unsigned long ulPID;
HWND hWnd_out;
};
HWND find_specific_window(unsigned long process_id)
{
param_enum param_data;
param_data.ulPID = process_id;
param_data.hWnd_out = 0;
EnumWindows(enum_windows_callback, (LPARAM)¶m_data);
get_window_title(process_id, param_data.hWnd_out);
return param_data.hWnd_out;
}
BOOL CALLBACK enum_windows_callback(HWND handle, LPARAM lParam)
{
param_enum& param_data = *(param_enum*)lParam;
unsigned long process_id = 0;
GetWindowThreadProcessId(handle, &process_id);
if (param_data.ulPID != process_id)
{
return TRUE;
}
param_data.hWnd_out = handle;
return FALSE;
}
---------------------------Get Handle---------------------------
HANDLE GetHandleFromProcessPath(TCHAR* szExeName, DWORD& dwPID)
{
HANDLE hExeName = INVALID_HANDLE_VALUE;
HANDLE hSnap = INVALID_HANDLE_VALUE;
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(PROCESSENTRY32);
hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (INVALID_HANDLE_VALUE != hSnap)
{
if (Process32First(hSnap, &pe32))
{
do
{
//!!! Attention pe32.szExeFile always return exe file name. not window title.
if (NULL != _tcsstr(pe32.szExeFile, szExeName))
{
hExeName = OpenProcess(PROCESS_ALL_ACCESS, TRUE, pe32.th32ProcessID);
dwPID = pe32.th32ProcessID;
break;
}
} while (Process32Next(hSnap, &pe32));
}
}
return hExeName;
}
Completing the answer of "G.Alexander" and and the comment of Skewjo
the get_window_title code is incomplete. So, worked for me, by removing it and calling find_specific_window like below:
wchar_t* caption = new wchar_t[MAX_PATH*2];
HWND h = find_specific_window(processID);
GetWindowTextW(h, caption, MAX_PATH*2);
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;
}
Anyone know why returns 183 in call EnumDesktopWindows
This process is an service running in System LocalService
I'm trying to put the window in the top, because the process starts minimized.
Thank for Help
My Code:
BOOL CALLBACK EnumWindowsProc( HWND hwnd, LPARAM lParam )
{
DWORD dwPID;
GetWindowThreadProcessId( hwnd, &dwPID );
if( dwPID == lParam ) {
SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE );
SwitchToThisWindow(hwnd, true);
SetFocus( hwnd );
return FALSE;
}
return TRUE;
}
BOOL CALLBACK EnumDesktopProc(LPTSTR lpszDesktop, LPARAM lParam) {
HDESK hDesk = OpenDesktop(lpszDesktop, NULL, FALSE, GENERIC_ALL);
if(hDesk != NULL) {
if(!EnumDesktopWindows(hDesk,&EnumWindowsProc, lParam)) {
//This call returns (183) Cannot create a file when that file already exists
}
CloseDesktop(hDesk);
}
return TRUE;
}
BOOL CALLBACK EnumWindowStationProc(LPTSTR lpszWindowStation, LPARAM lParam)
{
HWINSTA hWinStat = OpenWindowStation(lpszWindowStation,FALSE,WINSTA_ENUMDESKTOPS|WINSTA_ENUMERATE);
if(hWinStat) {
SetProcessWindowStation(hWinStat);
EnumDesktops(hWinStat,&EnumDesktopProc,lParam);
CloseWindowStation(hWinStat);
}
return TRUE;
}
bool Utils::execIntoDifferentSession(const std::wstring &aPath, const std::wstring &aParams, const std::wstring &aMode)
{
PROCESS_INFORMATION pi;
STARTUPINFO si;
BOOL bResult = FALSE;
DWORD dwSessionId,winlogonPid;
HANDLE hUserToken,hUserTokenDup,hPToken,hProcess;
DWORD dwCreationFlags;
// Log the client on to the local computer.
dwSessionId = WTSGetActiveConsoleSessionId();
//////////////////////////////////////////
// Find the winlogon process
////////////////////////////////////////
PROCESSENTRY32 procEntry;
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnap == INVALID_HANDLE_VALUE)
return false;
procEntry.dwSize = sizeof(PROCESSENTRY32);
if (!Process32First(hSnap, &procEntry))
return false;
do {
if (_wcsicmp(procEntry.szExeFile, L"winlogon.exe") == 0) {
// We found a winlogon process...make sure it's running in the console session
DWORD winlogonSessId = 0;
if (ProcessIdToSessionId(procEntry.th32ProcessID, &winlogonSessId) && winlogonSessId == dwSessionId) {
winlogonPid = procEntry.th32ProcessID;
break;
}
}
} while (Process32Next(hSnap, &procEntry));
WTSQueryUserToken(dwSessionId,&hUserToken);
dwCreationFlags = NORMAL_PRIORITY_CLASS|CREATE_NEW_CONSOLE;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb= sizeof(STARTUPINFO);
si.lpDesktop = L"winsta0\\default";
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOWNORMAL|SW_RESTORE;
ZeroMemory(&pi, sizeof(pi));
TOKEN_PRIVILEGES tp;
LUID luid;
hProcess = OpenProcess(MAXIMUM_ALLOWED,FALSE,winlogonPid);
if(!::OpenProcessToken(hProcess,TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY
|TOKEN_DUPLICATE|TOKEN_ASSIGN_PRIMARY|TOKEN_ADJUST_SESSIONID
|TOKEN_READ|TOKEN_WRITE,&hPToken))
{
return false;
}
if (!LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&luid))
return false;
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
DuplicateTokenEx(hPToken,MAXIMUM_ALLOWED,NULL,SecurityIdentification,TokenPrimary,&hUserTokenDup);
//Adjust Token privilege
SetTokenInformation(hUserTokenDup,TokenSessionId,(void*)dwSessionId,sizeof(DWORD));
if (!AdjustTokenPrivileges(hUserTokenDup,FALSE,&tp,sizeof(TOKEN_PRIVILEGES),(PTOKEN_PRIVILEGES)NULL,NULL))
return false;
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
return false;
LPVOID pEnv = NULL;
if(CreateEnvironmentBlock(&pEnv,hUserTokenDup,TRUE))
dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
else
pEnv = NULL;
// Launch the process in the client's logon session.
std::wstring params = aParams;
std::wstring path = aPath;
if(aMode == L"select") {
TCHAR infoBuffer[MAX_PATH];
GetSystemWindowsDirectory(infoBuffer, MAX_PATH);
std::wstring windowsDir(infoBuffer);
path = windowsDir+L"\\explorer.exe";
params = L" /n, /select,"+replaceString(aPath, L"\\\\", L"\\");
}
bResult = CreateProcessAsUser(
hUserTokenDup, // client's access token
path.c_str(), // file to execute
params.length() > 0 ? stringToLPWSTR(wideToUtf8(params)) : NULL, // command line
NULL, // pointer to process SECURITY_ATTRIBUTES
NULL, // pointer to thread SECURITY_ATTRIBUTES
FALSE, // handles are not inheritable
dwCreationFlags, // creation flags
pEnv, // pointer to new environment block
NULL, // name of current directory
&si, // pointer to STARTUPINFO structure
&pi // receives information about new process
);
EnumWindowStations(&EnumWindowStationProc, (LPARAM)(pi.dwProcessId));
// End impersonation of client.
//GetLastError Shud be 0
int rv = GetLastError();
//Perform All the Close Handles task
CloseHandle(hProcess);
CloseHandle(hUserToken);
CloseHandle(hUserTokenDup);
CloseHandle(hPToken);
return !rv;
}
Error 183 is ERROR_ALREADY_EXISTS. EnumDesktopWindows() does not set that error, so it must be a carry-over from an earlier API call. If you read the documentation says this:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms682615.aspx
You must ensure that the callback function sets SetLastError if it fails.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms682614.aspx
If the callback function fails, the return value is zero. The callback function can call SetLastError to set an error code for the caller to retrieve by calling GetLastError.
So try something more like this:
struct WndInfo
{
DWORD dwProcessID;
HWND hWnd;
};
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
WndInfo *pInfo = (WndInfo*) lParam;
DWORD dwPID;
GetWindowThreadProcessId(hwnd, &dwPID);
if (dwPID == pInfo->dwProcessID)
{
pInfo->hWnd = hwnd;
SetLastError(0);
return FALSE;
}
return TRUE;
}
BOOL CALLBACK EnumDesktopProc(LPTSTR lpszDesktop, LPARAM lParam)
{
HDESK hDesk = OpenDesktop(lpszDesktop, NULL, FALSE, GENERIC_ALL);
if (hDesk != NULL)
{
if (!EnumDesktopWindows(hDesk, &EnumWindowsProc, lParam))
{
if (GetLastError() != 0)
{
// handle error as needed...
}
}
CloseDesktop(hDesk);
WndInfo *pInfo = (WndInfo*) lParam;
if (pInfo->hWnd != NULL)
{
SetLastError(0);
return FALSE;
}
}
return TRUE;
}
BOOL CALLBACK EnumWindowStationProc(LPTSTR lpszWindowStation, LPARAM lParam)
{
HWINSTA hWinStat = OpenWindowStation(lpszWindowStation, FALSE, WINSTA_ENUMDESKTOPS|WINSTA_ENUMERATE);
if (hWinStat != NULL)
{
SetProcessWindowStation(hWinStat);
if (!EnumDesktops(hWinStat, &EnumDesktopProc, lParam))
{
if (GetLastError() != 0)
{
// handle error as needed...
}
}
CloseWindowStation(hWinStat);
WndInfo *pInfo = (WndInfo*) lParam;
if (pInfo->hWnd != NULL)
{
SetLastError(0);
return FALSE;
}
}
return TRUE;
}
HWND findWindowForProcess(DWORD PID)
{
WndInfo info;
info.dwProcessID = PID;
info.hWnd = NULL;
if (!EnumWindowStations(&EnumWindowStationProc, (LPARAM)&info))
{
if (GetLastError() != 0)
{
// handle error as needed...
}
}
return info.hWnd;
}
bool Utils::execIntoDifferentSession(const std::wstring &aPath, const std::wstring &aParams, const std::wstring &aMode)
{
...
bResult = CreateProcessAsUser(...);
if (bResult)
{
HWND hWnd = findWindowForProcess(pi.dwProcessId);
if (hWnd != NULL)
{
SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
SwitchToThisWindow(hWnd, TRUE);
SetFocus(hWnd);
}
}
...
}
With that said, since all you are really trying to do is execute a new process in a specific user session, you don't need to bother with all that enumeration logic. You don't need to find the WinLogon process at all, you already have the user's token from WTSQueryUserToken() so just duplicate+adjust that token as needed. And you are not doing anything useful in your window enumeration that the new process would not already do by default when it is started, so just get rid of that logic, too.
And then finally fix your error handling (or lack of) so you can close any handles that are open and not leak them.
I'm writing an Excel Addin. One of a UDF in the addin is to set value to a selected cell by using Excel Automation in C++. In my code, I have no problem to get range, read value from selected cell, but when I try to set value to cell, if the value is a string, the code throw exception (0x80020005 Type mismatch), otherwise, it always throw exception with HResult 0x800A03EC. Below is a code snippet:
Any ideas?
void SetValue()
{
Excel::SheetsPtr pSheets = GetExcelApplicationObj()->GetWorksheets();
Excel::_WorksheetPtr pSheet = GetExcelApplicationObj()->GetActiveSheet();
_variant_t text = pSheet->Range["A2"]->Text; //Read value from selected cell works fine
pSheet->Range["C2"]->Value = "Hello"; // throw 0x80020005 Type mismatch
pSheet->Range["B2"]->Value = 5.0; //Set value throw Exception with HRESULT 0x800A03EC
}
Excel::_Application* GetExcelApplicationObj()
{
if (m_pApp == NULL)
{
std::vector<HWND>::iterator it;
std::vector<HWND> handles = getToplevelWindows();
for (it = handles.begin(); it != handles.end(); it++)
{
HWND hwndChild = NULL;
::EnumChildWindows( (*it), EnumChildProc, (LPARAM)&hwndChild);
if (hwndChild != NULL)
{
Excel::Window* pWindow = NULL;
HRESULT hr = ::AccessibleObjectFromWindow(hwndChild, OBJID_NATIVEOM, __uuidof(Excel::Window), (void**)&pWindow);
if (SUCCEEDED(hr))
{
if (pWindow != NULL)
{
m_pApp = pWindow->GetApplication();
pWindow->Release();
}
break;
}
}
}
}
return m_pApp;
}
std::vector<HWND> getToplevelWindows()
{
EnumWindowsCallbackArgs args( ::GetCurrentProcessId() );
if ( ::EnumWindows( &EnumWindowsCallback, (LPARAM) &args ) == FALSE ) {
return std::vector<HWND>();
}
return args.handles;
}
BOOL CALLBACK EnumWindowsCallback( HWND hnd, LPARAM lParam )
{
EnumWindowsCallbackArgs *args = (EnumWindowsCallbackArgs *)lParam;
DWORD windowPID;
(void)::GetWindowThreadProcessId( hnd, &windowPID );
if ( windowPID == args->pid ) {
args->handles.push_back( hnd );
}
return TRUE;
}
BOOL CALLBACK EnumChildProc(HWND hwndChild,LPARAM lParam)
{
CHAR className[128];
::GetClassName(hwndChild, className, 128);
if (strcmp(className, "EXCEL7") == 0)
{
HWND * phandle = (HWND*)lParam;
(*phandle) = hwndChild;
return FALSE;
}
return TRUE;
}
You have to wrap the string value into a variant.
Try this:
pSheet->Range["C2"]->Value = _variant_t(_bstr_t("Hello")).Detach();