Get dos_name of usb on inserting or removal - c++

I have designed a program to detect whenever a usb device is connected or removed. I want to know the either the dos path of the connected device or a Guid like this \\?\Volume{17ee3574-7082-4881-aeae-07893db4e957}\
But instead dbcc_name gives me \\?\STORAGE#Volume#_??_USBSTOR#Disk&Ven_JetFlash&Prod_Transcend_8GB&Rev_1100#546IYBDAPBE1075Q&0#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}#{53f5630d-b6bf-11d0-94f2-00a0c91efb8b}
Is there anyway to obtain the guid of the connected logical drive or its dos name. My code is:
#define CLS_NAME L"USB_LISTENER_CLASS"
#define HID_CLASSGUID {0x4d1e55b2, 0xf16f, 0x11cf,{ 0x88, 0xcb, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30}}
LRESULT message_handler(HWND__* hwnd, UINT uint, WPARAM wparam, LPARAM lparam)
{
switch (uint)
{
case WM_NCCREATE: // before window creation
return true;
break;
case WM_CREATE: // the actual creation of the window
{
// you can get your creation params here..like GUID..
LPCREATESTRUCT params = (LPCREATESTRUCT)lparam;
GUID InterfaceClassGuid = *((GUID*)params->lpCreateParams);
DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
ZeroMemory(&NotificationFilter, sizeof(NotificationFilter));
NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
NotificationFilter.dbcc_classguid = GUID_DEVINTERFACE_VOLUME;
HDEVNOTIFY dev_notify = RegisterDeviceNotification(hwnd, &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE);
if (dev_notify == NULL)
{
throw std::runtime_error("Could not register for device Notifications!");
}
}
break;
case WM_DEVICECHANGE:
{
PDEV_BROADCAST_HDR(lpdb) = (PDEV_BROADCAST_HDR)lparam;
PDEV_BROADCAST_DEVICEINTERFACE_W lpdbv = (PDEV_BROADCAST_DEVICEINTERFACE_W)lpdb;
switch (wparam)
{
case DBT_DEVICEARRIVAL: //A device or piece of media has been inserted and is now available.
std::cout << "Device Arrived" << std::endl;
std::cout << "GUID od inserted device: " << lpdbv->dbcc_name;
break;
case DBT_DEVICEREMOVECOMPLETE:
std::cout << "Device Removed" << std::endl;
break;
}
}
}
return 0L;
}
void UsbListener::RegisterListener()
{
HWND hWnd = NULL;
WNDCLASSEXW wx;
ZeroMemory(&wx, sizeof(wx));
wx.cbSize = sizeof(WNDCLASSEX);
wx.lpfnWndProc = reinterpret_cast<WNDPROC>(message_handler);
wx.hInstance = reinterpret_cast<HINSTANCE>(GetModuleHandle(0));
wx.style = CS_HREDRAW | CS_VREDRAW;
wx.hInstance = GetModuleHandle(0);
wx.hbrBackground = (HBRUSH)(COLOR_WINDOW);
wx.lpszClassName = CLS_NAME;
GUID guid = HID_CLASSGUID;
if (RegisterClassExW(&wx))
{
hWnd = CreateWindowW(
CLS_NAME, L"DeviceNotificationWindow", WS_ICONIC, 0, 0, CW_USEDEFAULT, 0, HWND_MESSAGE, NULL, GetModuleHandle(0), (void*)&guid
);
}
if (hWnd == NULL)
{
throw std::runtime_error("Could not create message window!");
}
std::cout <<std::endl<< "Listening..." << std::endl;
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
I want to know the Dos name of the exact drive that is inserted or removed so that UI can display. I am new to winapi so please bear with the code,

at the begin you need open Mount Manager and save it handle in class associated with your window, for not open/close it multiple time, bit only once
#include <mountmgr.h>
HANDLE hMountMgr = CreateFileW(MOUNTMGR_DOS_DEVICE_NAME, 0, 0, 0, OPEN_EXISTING, 0, 0);
for query dos like name (if it exist !) you need first get device name via IOCTL_MOUNTDEV_QUERY_DEVICE_NAME which need send to device, which interface name you have. so you need first open it.
then you can send IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH to Mount Manager and got what you want
volatile UCHAR guz;
ULONG GetDosVolumePath(HANDLE hMountMgr, PCWSTR InterfaceLink, PWSTR* ppszDosPath)
{
*ppszDosPath = 0;
HANDLE hFile = CreateFileW(InterfaceLink, 0, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);
if (hFile == INVALID_HANDLE_VALUE) return GetLastError();
union {
PVOID buf;
PMOUNTDEV_NAME pmdn;
};
ULONG dwError;
PVOID stack = alloca(guz);
ULONG cb = 0, rcb, InputBufferLength = sizeof(MOUNTDEV_NAME) + 0x40;
do
{
if (cb < InputBufferLength)
{
cb = RtlPointerToOffset(buf = alloca(InputBufferLength - cb), stack);
}
dwError = BOOL_TO_ERROR(DeviceIoControl(hFile, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, 0, 0, pmdn, cb, &rcb, 0));
InputBufferLength = FIELD_OFFSET(MOUNTDEV_NAME, Name) + pmdn->NameLength;
} while ( dwError == ERROR_MORE_DATA);
CloseHandle(hFile);
if (dwError == NOERROR)
{
union {
PVOID pv;
PMOUNTMGR_VOLUME_PATHS pmvp;
};
cb = 0, rcb = sizeof(MOUNTMGR_VOLUME_PATHS) + 8;
do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(pv = alloca(rcb - cb), pmdn);
}
dwError = BOOL_TO_ERROR(DeviceIoControl(hMountMgr,
IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH,
pmdn, InputBufferLength, pmvp, cb, &rcb, 0));
if (dwError == NOERROR)
{
*ppszDosPath = _wcsdup(pmvp->MultiSz);
}
rcb = FIELD_OFFSET(MOUNTMGR_VOLUME_PATHS, MultiSz) + pmvp->MultiSzLength;
} while (dwError == ERROR_MORE_DATA);
}
return dwError;
}

Related

Shell Execute From Explorer

Trying to follow this sample:
https://devblogs.microsoft.com/oldnewthing/20040520-00/?p=39243
void ShellExecuteFromExplorer(PCWSTR pszFile, PCWSTR pszParameters = nullptr, PCWSTR pszDirectory = nullptr, PCWSTR pszOperation = nullptr, int nShowCmd = SW_SHOWNORMAL)
{
CComPtr<IShellFolderViewDual> spFolderView;
GetDesktopAutomationObject(IID_PPV_ARGS(&spFolderView));
CComPtr<IDispatch> spdispShell;
spFolderView->get_Application(&spdispShell);
CComQIPtr<IShellDispatch2>(spdispShell)
->ShellExecute(CComBSTR(pszFile),
CComVariant(pszParameters ? pszParameters : L""),
CComVariant(pszDirectory ? pszDirectory : L""),
CComVariant(pszOperation ? pszOperation : L""),
CComVariant(nShowCmd));
}
In this case, how do i retrieve the pid from the process being launch from the ShellExecute?
not need use this way for create unelevated process. for instance we can use shell process (explorer) as parent for new process with help PROC_THREAD_ATTRIBUTE_PARENT_PROCESS. example of code
ULONG ExecFromShell(_In_opt_ PCWSTR lpApplicationName,
_Inout_opt_ PWSTR lpCommandLine)
{
if (HWND hwnd = GetShellWindow())
{
ULONG dwProcessId, dwThreadId;
if (dwThreadId = GetWindowThreadProcessId(hwnd, &dwProcessId))
{
if (HANDLE hProcess = OpenProcess(PROCESS_CREATE_PROCESS|READ_CONTROL,
FALSE, dwProcessId))
{
PROCESS_INFORMATION pi;
STARTUPINFOEXW si { sizeof(si)};
SIZE_T s = 0;
ULONG dwError;
__0:
switch (dwError = InitializeProcThreadAttributeList(
si.lpAttributeList, 1, 0, &s) ? NOERROR : GetLastError())
{
case ERROR_INSUFFICIENT_BUFFER:
if (!si.lpAttributeList)
{
si.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)alloca(s);
goto __0;
}
break;
case NOERROR:
if (UpdateProcThreadAttribute(si.lpAttributeList, 0,
PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,
&hProcess, sizeof(hProcess), 0, 0))
{
ULONG cb = 0;
SECURITY_ATTRIBUTES sa = { sizeof(sa) };
__1:
switch (GetKernelObjectSecurity(hProcess,
DACL_SECURITY_INFORMATION|LABEL_SECURITY_INFORMATION,
sa.lpSecurityDescriptor, cb, &cb) ? NOERROR : GetLastError())
{
case ERROR_INSUFFICIENT_BUFFER:
if (!sa.lpSecurityDescriptor)
{
sa.lpSecurityDescriptor = alloca(cb);
goto __1;
}
break;
case NOERROR:
if (CreateProcessW(lpApplicationName, lpCommandLine, &sa, &sa,
FALSE, EXTENDED_STARTUPINFO_PRESENT, 0, 0, &si.StartupInfo, &pi))
{
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
}
else
{
dwError = GetLastError();
}
break;
}
}
else
{
dwError = GetLastError();
}
DeleteProcThreadAttributeList(si.lpAttributeList);
break;
}
CloseHandle(hProcess);
return dwError;
}
return GetLastError();
}
}
return ERROR_NOT_FOUND;
}
In this case, how do i retrieve the pid from the process being launch from the ShellExecute?
You can't. just like ::ShellExecute(), IShellDispatch2::ShellExecute() simply does not provide any information about the new process.

DirectSound captures gigabytes of frames instead of megabytes

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;
}

Windows Raw Input works only if initialised late

I am creating a DLL which gets called from a Windows application. It calls my function which then spawns a thread running PttThread shown below. I then register a message only window to handle raw input events. None of the calls return any errors but I do not get raw input events. However, if I add a delay after creating the window but before registering the raw input it suddenly works.
Since Windows does not tell me anything is wrong, how can I change my code so initialisation works properly?
DWORD WINAPI PttThread(LPVOID lpParameter) {
if (!hInstance) {
hInstance = GetModuleHandle(NULL);
}
//Create message only window
WNDCLASSEX wx = {};
wx.cbSize = sizeof(WNDCLASSEX);
wx.lpfnWndProc = messageProc;
wx.hInstance = hInstance;
wx.lpszClassName = class_name;
if (!RegisterClassEx(&wx)) {
printf("could not register window class: ");
printLastError();
}
windowHandle = CreateWindowEx(0, class_name, L"R4nd0m_dummy_name", 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
if (!windowHandle) {
printf("Could not create window\n");
printLastError();
}
printf("hinstance %u\nhwnd %u\n", hInstance, windowHandle);
// HERE
Sleep(1000); //Then raw input works
// Setup raw input
RAWINPUTDEVICE rid[1];
rid[0].usUsagePage = 0x01;
rid[0].usUsage = 0x06;
rid[0].dwFlags = RIDEV_NOLEGACY | RIDEV_INPUTSINK;
rid[0].hwndTarget = windowHandle;
if (RegisterRawInputDevices(rid, 1, sizeof(rid[0])) == FALSE) {
printf("!!! Could not setup keyboard input\n");
printLastError();
}
printf("Finish setup of PTT\n");
// Raw input does NOT work if Sleep(1000) is move to here
MSG msg;
BOOL bRet;
while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)
{
printf("Message received\n"); //Does not print if early registration of raw input.
if (msg.message == MSG_SHUTDOWN) {
break;
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
threadShutdown();
return 0;
}

EnumDesktopWindows Error: (183) Cannot create a file when that file already exists

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.

Shell Execute bring Window to front

I'm using this function to call an executable from my MSI. However the window for the executable hides behind my MSI window. Is there any way to bring it to the front?
I have tried minimizing all the windows just before the call to ShellExecute but that still does not bring the executable window to the front.
extern "C" UINT __stdcall InstallDrivers(MSIHANDLE hInstall)
{
HRESULT hr = S_OK;
UINT er = ERROR_SUCCESS;
HANDLE hFile = INVALID_HANDLE_VALUE;
BYTE* pbData = NULL;
DWORD cbData = 0;
char pwzFilename[MAX_PATH], szDriverType[MAX_PATH], pwzSentinelFilename[MAX_PATH], szIsInstalled[MAX_PATH];
LPWSTR szValueBuf = NULL, szIsHaspInstalled = NULL, szIsSentinelInstalled = NULL;
hr = WcaInitialize(hInstall, "InstallDrivers");
ExitOnFailure(hr, "Failed to initialize");
WcaLog(LOGMSG_STANDARD, "Initialized.");
WcaLog(LOGMSG_STANDARD, "%s", szValueBuf);
CreateDirectory("C:\\Temp", NULL);
strcpy_s(pwzFilename, "C:\\Temp\\HASPUserSetup.exe");
hr = ExtractBinary(L"Hasp", &pbData, &cbData);
ExitOnFailure(hr, "failed to extract binary data");
if ((hFile = CreateFile(pwzFilename, GENERIC_WRITE,FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE)
{
PMSIHANDLE hRecord = MsiCreateRecord(0);
MsiRecordSetString(hRecord, 0, TEXT("Could not create new temporary file"));
MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_ERROR + MB_OK), hRecord);
return ERROR_INSTALL_USEREXIT;
}
DWORD cbWritten = 0;
if ( !WriteFile(hFile, pbData, cbData, &cbWritten, NULL) )
{
PMSIHANDLE hRecord = MsiCreateRecord(0);
MsiRecordSetString(hRecord, 0, TEXT("Could not write to file"));
MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_ERROR + MB_OK), hRecord);
return ERROR_INSTALL_USEREXIT;
}
CloseHandle(hFile);
strcpy_s(pwzSentinelFilename, "C:\\Temp\\sentinel_setup.exe");
hr = ExtractBinary(L"Sentinel", &pbData, &cbData);
ExitOnFailure(hr, "failed to extract binary data");
if ((hFile = CreateFile(pwzSentinelFilename, GENERIC_WRITE,FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE)
{
PMSIHANDLE hRecord = MsiCreateRecord(0);
MsiRecordSetString(hRecord, 0, TEXT("Could not create new temporary file"));
MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_ERROR + MB_OK), hRecord);
return ERROR_INSTALL_USEREXIT;
}
if ( !WriteFile(hFile, pbData, cbData, &cbWritten, NULL) )
{
PMSIHANDLE hRecord = MsiCreateRecord(0);
MsiRecordSetString(hRecord, 0, TEXT("Could not write to file"));
MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_ERROR + MB_OK), hRecord);
return ERROR_INSTALL_USEREXIT;
}
CloseHandle(hFile);
hr = WcaGetProperty(L"DRIVER", &szValueBuf);
ExitOnFailure(hr, "failed to get driver info");
wcstombs(szDriverType, szValueBuf, 260);
if (strcmp(szDriverType, "Hasp") == 0)
{
hr = WcaGetProperty(L"SENTINELINSTALLED", &szIsSentinelInstalled);
ExitOnFailure(hr, "failed to get driver info");
wcstombs(szIsInstalled, szValueBuf, 260);
if (strcmp(szIsInstalled, "Sentinel Protection Installer 7.6.5") == 0)
{
ShellExecute(NULL, "open", pwzSentinelFilename, NULL, NULL, SW_SHOWNORMAL);
}
ShellExecute(NULL, "open", pwzFilename, NULL, NULL, SW_SHOWNORMAL);
}else
{
hr = WcaGetProperty(L"HASPINSTALLED", &szIsHaspInstalled);
ExitOnFailure(hr, "failed to get driver info");
wcstombs(szIsInstalled, szIsHaspInstalled, 260);
if (strcmp(szIsInstalled, "Sentinel Runtime") == 0)
{
ShellExecute(NULL, "open", pwzFilename, NULL, NULL, SW_SHOWNORMAL);
}
ShellExecute(NULL, "open", pwzSentinelFilename, NULL, NULL, SW_SHOWNORMAL);
}
LExit:
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
return WcaFinalize(er);
}
Updated Code:
extern "C" UINT __stdcall InstallDrivers(MSIHANDLE hInstall)
{
HRESULT hr = S_OK;
UINT er = ERROR_SUCCESS;
HANDLE hFile = INVALID_HANDLE_VALUE;
BYTE* pbData = NULL;
DWORD cbData = 0;
char pwzFilename[MAX_PATH], szDriverType[MAX_PATH], pwzSentinelFilename[MAX_PATH], szIsInstalled[MAX_PATH];
LPWSTR szValueBuf = NULL, szIsHaspInstalled = NULL, szIsSentinelInstalled = NULL;
SHELLEXECUTEINFO ShExecInfo;
ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
ShExecInfo.fMask = NULL;
ShExecInfo.hwnd = NULL;
ShExecInfo.lpVerb = NULL;
ShExecInfo.lpParameters = NULL;
ShExecInfo.lpDirectory = NULL;
ShExecInfo.nShow = SW_SHOWNORMAL;
ShExecInfo.hInstApp = NULL;
hr = WcaInitialize(hInstall, "InstallDrivers");
ExitOnFailure(hr, "Failed to initialize");
WcaLog(LOGMSG_STANDARD, "Initialized.");
WcaLog(LOGMSG_STANDARD, "%s", szValueBuf);
CreateDirectory("C:\\Temp", NULL);
strcpy_s(pwzFilename, "C:\\Temp\\HASPUserSetup.exe");
hr = ExtractBinary(L"Hasp", &pbData, &cbData);
ExitOnFailure(hr, "failed to extract binary data");
if ((hFile = CreateFile(pwzFilename, GENERIC_WRITE,FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE)
{
PMSIHANDLE hRecord = MsiCreateRecord(0);
MsiRecordSetString(hRecord, 0, TEXT("Could not create new temporary file"));
MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_ERROR + MB_OK), hRecord);
return ERROR_INSTALL_USEREXIT;
}
DWORD cbWritten = 0;
if ( !WriteFile(hFile, pbData, cbData, &cbWritten, NULL) )
{
PMSIHANDLE hRecord = MsiCreateRecord(0);
MsiRecordSetString(hRecord, 0, TEXT("Could not write to file"));
MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_ERROR + MB_OK), hRecord);
return ERROR_INSTALL_USEREXIT;
}
CloseHandle(hFile);
strcpy_s(pwzSentinelFilename, "C:\\Temp\\sentinel_setup.exe");
hr = ExtractBinary(L"Sentinel", &pbData, &cbData);
ExitOnFailure(hr, "failed to extract binary data");
if ((hFile = CreateFile(pwzSentinelFilename, GENERIC_WRITE,FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE)
{
PMSIHANDLE hRecord = MsiCreateRecord(0);
MsiRecordSetString(hRecord, 0, TEXT("Could not create new temporary file"));
MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_ERROR + MB_OK), hRecord);
return ERROR_INSTALL_USEREXIT;
}
if ( !WriteFile(hFile, pbData, cbData, &cbWritten, NULL) )
{
PMSIHANDLE hRecord = MsiCreateRecord(0);
MsiRecordSetString(hRecord, 0, TEXT("Could not write to file"));
MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_ERROR + MB_OK), hRecord);
return ERROR_INSTALL_USEREXIT;
}
CloseHandle(hFile);
hr = WcaGetProperty(L"DRIVER", &szValueBuf);
ExitOnFailure(hr, "failed to get driver info");
wcstombs(szDriverType, szValueBuf, 260);
if (strcmp(szDriverType, "Hasp") == 0)
{
hr = WcaGetProperty(L"SENTINELINSTALLED", &szIsSentinelInstalled);
ExitOnFailure(hr, "failed to get driver info");
wcstombs(szIsInstalled, szValueBuf, 260);
if (strcmp(szIsInstalled, "Sentinel Protection Installer 7.6.5") == 0)
{
AllowSetForegroundWindow(ASFW_ANY);
ShExecInfo.lpFile = pwzSentinelFilename;
ShellExecuteEx(&ShExecInfo);
/*ShellExecute(NULL, "open", pwzSentinelFilename, NULL, NULL, SW_SHOWNORMAL);*/
}
AllowSetForegroundWindow(ASFW_ANY);
ShExecInfo.lpFile = pwzFilename;
ShellExecuteEx(&ShExecInfo);
/*ShellExecute(NULL, "open", pwzFilename, NULL, NULL, SW_SHOWNORMAL);*/
}else
{
hr = WcaGetProperty(L"HASPINSTALLED", &szIsHaspInstalled);
ExitOnFailure(hr, "failed to get driver info");
wcstombs(szIsInstalled, szIsHaspInstalled, 260);
if (strcmp(szIsInstalled, "Sentinel Runtime") == 0)
{
AllowSetForegroundWindow(ASFW_ANY);
/*ShellExecute(NULL, "open", pwzFilename, NULL, NULL, SW_SHOWNORMAL);*/
ShExecInfo.lpFile = pwzFilename;
ShellExecuteEx(&ShExecInfo);
}
AllowSetForegroundWindow(ASFW_ANY);
ShExecInfo.lpFile = pwzSentinelFilename;
ShellExecuteEx(&ShExecInfo);
/* ShellExecute(NULL, "open", pwzSentinelFilename, NULL, NULL, SW_SHOWNORMAL);*/
}
LExit:
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
return WcaFinalize(er);
}
Windows doesn't permit processes to snatch the foreground window unless the user starts them. This is to avoid things like persuading the user to type their bank details into the wrong window. However the current foreground process can pass permission to another process to do this. See AllowSetForegroundWindow for the details. To do this you have to provide the process id for the process that will become foreground and ShellExecute doesn't provide that. However, if you switch to using ShellExecuteEx you can get this from the hProcess member on the SHELLEXECUTEINFO structure.
You can then call SetForegroundWindow in your new process and it will be permitted. Otherwise it just starts flashing on the taskbar.
EDIT
If your initial application is the foreground application and you start a subprocess from that then the subprocess should automatically become foreground as described in the documentation for these functions.
Below is an example of how we can choose to enable and set another application to become the foreground window. In this case it just creates a text file and calls ShellExecuteEx with the open verb. We have to wait for the child process to get going and to have its window prepared and then we can locate the window from the process ID and give it permissions and set its window to be foreground. In this case the launched notepad (or whatever is your "open" verb for .txt files) will be foreground anyway. If you separately run a notepad process and substiture in the process ID for that process where we normally put in the child process ID then we can make another process become foreground -- one that is not part of our process tree. This can be compiled using Visual C++ with cl -nologo -W3 -O2 -MD fg_test.cpp to produce an fg_test.exe.
#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <shellapi.h>
#pragma comment(lib, "shell32")
#pragma comment(lib, "user32")
static void PrintError(LPCTSTR szPrefix, DWORD dwError);
static BOOL CALLBACK OnGetWindowByProcess(HWND hwnd, LPARAM lParam);
typedef struct {
DWORD pid;
HWND hwnd;
} WINDOWPROCESSINFO;
int _tmain(int argc, TCHAR *argv[])
{
SHELLEXECUTEINFO sxi = {0};
sxi.cbSize = sizeof(sxi);
sxi.nShow = SW_SHOWNORMAL;
FILE *fp = NULL;
_tfopen_s(&fp, _T("junk.txt"), _T("wt"));
_fputts(_T("Example text file\n"), fp);
fclose(fp);
sxi.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NOASYNC | SEE_MASK_WAITFORINPUTIDLE;
sxi.lpVerb = _T("open");
sxi.lpFile = _T("junk.txt");
if (!ShellExecuteEx(&sxi))
PrintError(_T("ShellExecuteEx"), GetLastError());
else
{
WINDOWPROCESSINFO info;
info.pid = GetProcessId(sxi.hProcess); // SPECIFY PID
info.hwnd = 0;
AllowSetForegroundWindow(info.pid);
EnumWindows(OnGetWindowByProcess, (LPARAM)&info);
if (info.hwnd != 0)
{
SetForegroundWindow(info.hwnd);
SetActiveWindow(info.hwnd);
}
CloseHandle(sxi.hProcess);
}
return 0;
}
static BOOL CALLBACK OnGetWindowByProcess(HWND hwnd, LPARAM lParam)
{
WINDOWPROCESSINFO *infoPtr = (WINDOWPROCESSINFO *)lParam;
DWORD check = 0;
BOOL br = TRUE;
GetWindowThreadProcessId(hwnd, &check);
_tprintf(_T("%x %x %x\n"), hwnd, check, infoPtr->pid);
if (check == infoPtr->pid)
{
_tprintf(_T("found window %x for process id %x\n"), hwnd, check);
infoPtr->hwnd = hwnd;
br = FALSE;
}
return br;
}
static void
PrintError(LPCTSTR szPrefix, DWORD dwError)
{
LPTSTR lpsz = NULL;
DWORD cch = 0;
cch = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, dwError, LANG_NEUTRAL, (LPTSTR)&lpsz, 0, NULL);
if (cch < 1) {
cch = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_STRING
| FORMAT_MESSAGE_ARGUMENT_ARRAY,
_T("Code 0x%1!08x!"),
0, LANG_NEUTRAL, (LPTSTR)&lpsz, 0,
(va_list*)&dwError);
}
_ftprintf(stderr, _T("%s: %s"), szPrefix, lpsz);
LocalFree((HLOCAL)lpsz);
}