Xcvdata() for deleting port.
BOOL DeletePortCus( TCHAR* PortName )
{
HANDLE hPrinter;
PRINTER_DEFAULTS PrinterDefaults;
memset(&PrinterDefaults, 0, sizeof(PrinterDefaults));
PrinterDefaults.pDatatype = NULL;
PrinterDefaults.pDevMode = NULL;
PrinterDefaults.DesiredAccess = SERVER_ACCESS_ADMINISTER;
DWORD needed = 0;
DWORD rslt = 0;
//Port data
PORT_DATA_1 pOutputData ;
DWORD error = 0;
if (!OpenPrinter(L",XcvMonitor Standard TCP/IP Port", &hPrinter, &PrinterDefaults))
{
LPVOID lpMsgBuf;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, GetLastError(), NULL,(LPTSTR) &lpMsgBuf, 0, NULL );
_tprintf( TEXT("Error in OpenPrinter. Error msg : %s"),lpMsgBuf);
LocalFree( lpMsgBuf );
return FALSE;
}
DWORD xcvresult= 0;
if (
!XcvData(
hPrinter,
TEXT("DeletePort"),
(PBYTE)PortName,
(lstrlen(PortName) +1) * sizeof(TCHAR), //the 1 is for the trailing NULL
( byte * ) &pOutputData,
sizeof(PORT_DATA_1),
&needed,
&xcvresult)
)
{
LPVOID lpMsgBuf;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, GetLastError(), NULL,(LPTSTR) &lpMsgBuf, 0, NULL );
_tprintf( TEXT("Error in XcvData. Error msg : %s; XcvDataPort status val = %d"), lpMsgBuf, xcvresult);
LocalFree( lpMsgBuf );
return FALSE;
}
ClosePrinter(hPrinter);
return TRUE;
}
The highlight is both the functions (openprinter and xcvdata) succeed. But the port is not getting removed. I am completely at a loss here as I dont have any error to lookup.
Instead of ,XcvMonitor Standard TCP/IP Port I also tried with ,XcvPort <portname>. Still same.
As Samer suggested below, I tried with OpenPrinter2 with no cache option.
PS: I know there's this simple alternative DeletePort(), but it invokes a UI dialog box if it fails, so I don't want to use it.
It seems the issue might be related to specific version of OS which caches printer handles. To get around this you use an alternate call OpenPrinter2 with the PRINTER_OPTION_NO_CACHE. Below is the modified code with the flag set.
HANDLE hPrinter;
PRINTER_DEFAULTS PrinterDefaults;
memset(&PrinterDefaults, 0, sizeof(PrinterDefaults));
PrinterDefaults.pDatatype = NULL;
PrinterDefaults.pDevMode = NULL;
PrinterDefaults.DesiredAccess = SERVER_ACCESS_ADMINISTER;
PRINTER_OPTIONS PrinterOptions;
PrinterOptions.cbSize = sizeof(PrinterOptions);
PrinterOptions.dwFlags = PRINTER_OPTION_NO_CACHE;
DWORD needed = 0;
DWORD rslt = 0;
//Port data
PORT_DATA_1 pOutputData ;
DWORD error = 0;
if (!OpenPrinter2(L",XcvMonitor Standard TCP/IP Port", &hPrinter, &PrinterDefaults, &PrinterOptions))
{
LPVOID lpMsgBuf;
Related
Recently I came across a Windows API called GetAppContainerNamedObjectPath. But I have no idea on how I can use it.
I found a msdn page for this api (https://learn.microsoft.com/en-us/windows/win32/api/securityappcontainer/nf-securityappcontainer-getappcontainernamedobjectpath). But it does not have a right example and remarks, parameters are written poorly.
I am getting ERROR_INVALID_PARAMETER(87) error at the end, which tells me something's wrong with the parameters that I put. Here's what I've tried.
#define TokenIsAppContainer 29
#define TokenAppContainerSid 31
#define TokenAppContainerNumber 32
typedef struct _TOKEN_APPCONTAINER_INFORMATION {
PSID TokenAppContainer;
} TOKEN_APPCONTAINER_INFORMATION, *PTOKEN_APPCONTAINER_INFORMATION;
void GetAppContainerProcessInfo(CString & procName)
{
DWORD dwSize = 0;
DWORD dwResult;
HANDLE hToken;
PTOKEN_APPCONTAINER_INFORMATION pAppCoInfo;
WCHAR wcsDebug[1024] = {0,};
WCHAR * pwSID = NULL;
typedef BOOL (WINAPI *_LPGETAPPCONTAINERNAMEOBJECTPATH)(HANDLE, PSID, ULONG, LPWSTR, PULONG);
static _LPGETAPPCONTAINERNAMEOBJECTPATH lpGetAppContainerNamedObjectPath = NULL;
if (0 == lpGetAppContainerNamedObjectPath)
{
HMODULE hKernel32 = LoadLibraryExW(L"kernel32.dll", NULL, 0);
if (hKernel32)
{
lpGetAppContainerNamedObjectPath = reinterpret_cast<_LPGETAPPCONTAINERNAMEOBJECTPATH>(GetProcAddress(hKernel32, "GetAppContainerNamedObjectPath"));
}
}
if (lpGetAppContainerNamedObjectPath)
{
DWORD processId = (DWORD)_ttoi((LPCTSTR)procName);
//HANDLE hProcess = GetProcessHandleByProcessName(procName);
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processId);
if(!OpenProcessToken(hProcess, TOKEN_QUERY, &hToken))
{
dwResult = GetLastError();
swprintf_s( wcsDebug, _countof(wcsDebug), L"OpenProcessToken Error(%u) PID(%d)\n", dwResult, processId );
AfxMessageBox(wcsDebug);
return;
}
if (!GetTokenInformation(hToken, (TOKEN_INFORMATION_CLASS) TokenAppContainerSid, NULL, dwSize, &dwSize))
{
dwResult = GetLastError();
if( dwResult != ERROR_INSUFFICIENT_BUFFER )
{
swprintf_s( wcsDebug, _countof(wcsDebug), L"GetTokenInformation Error %u\n", dwResult );
AfxMessageBox(wcsDebug);
return;
}
}
pAppCoInfo = (PTOKEN_APPCONTAINER_INFORMATION) GlobalAlloc( GPTR, dwSize );
if (!GetTokenInformation(hToken, (TOKEN_INFORMATION_CLASS) TokenAppContainerSid, pAppCoInfo, dwSize, &dwSize))
{
dwResult = GetLastError();
swprintf_s( wcsDebug, _countof(wcsDebug), L"GetTokenInformation Error %u\n", dwResult );
AfxMessageBox(wcsDebug);
return;
}
WCHAR wcsNamedObjectPath[MAX_PATH];
ULONG ulRetlen = 0;
BOOL bRet = lpGetAppContainerNamedObjectPath(hToken, pAppCoInfo->TokenAppContainer, _countof(wcsNamedObjectPath), wcsNamedObjectPath, &ulRetlen );
if (bRet)
{
swprintf_s( wcsDebug, _countof(wcsDebug), L"GetAppContainerNamedObjectPath Path(%s)\n", wcsNamedObjectPath );
AfxMessageBox(wcsDebug);
}
else
{
dwResult = GetLastError();
swprintf_s( wcsDebug, _countof(wcsDebug), L"GetAppContainerNamedObjectPath Error %u\n", dwResult );
AfxMessageBox(wcsDebug);
}
if (pwSID)
LocalFree(pwSID);
CloseHandle(hToken)
CloseHandle(hProcess);
}
}
As a side-note, I have tried using wchar_t * and dynamically allocate the memory buffer by calling GetAppContainerNamedObjectPath twice. But still had no chance. Return length does not return a meaningful value.
if you call RtlGetLastNtStatus(); instead GetLastError(); after GetAppContainerNamedObjectPath you will got
STATUS_INVALID_PARAMETER_MIX - An invalid combination of parameters was specified.
this give you more info compare simply invalid parameter.
then look for function signature
BOOL
WINAPI
GetAppContainerNamedObjectPath(
_In_opt_ HANDLE Token,
_In_opt_ PSID AppContainerSid,
_In_ ULONG ObjectPathLength,
_Out_writes_opt_(ObjectPathLength) LPWSTR ObjectPath,
_Out_ PULONG ReturnLength
);
the Token and AppContainerSid declared with In_opt -- this mean that this parameters is optional, and you can pass 0 in place one of it. then ask your self - for what you query token for TokenAppContainerSid ? are system can not do this for you if you pass this token to api ? obvious can. so you not need do this yourself. really you need pass Token to api and in this case AppContainerSid must be 0. or you can pass AppContainerSid to api and in this case Token must be 0. when both AppContainerSid and Token not zero - you and got STATUS_INVALID_PARAMETER_MIX
also as side note - you not need open process with PROCESS_ALL_ACCESS if you need get it token. the PROCESS_QUERY_LIMITED_INFORMATION is enough
really api not do big magic. it return to you
AppContainerNamedObjects\<Sid>
path, where string form of app container sid.(some like S-1-15-2-...)
I am trying to do some stuff with the desktop listview. I can get the text of the item with LVM_GETITEM, but the iImage struct member is always zero, and so is the state. I'm running Win 7 64 and compiled for 64 with Dev C++(gcc). I also tried compiling it as 32bit and tested on XP with the same result...just text, image and state are assigned zero. I can also get the item count no problem with ListView_GetItemCount().
HWND progman = FindWindow("progman", NULL);
HWND shell = FindWindowEx(progman, NULL, "shelldll_defview", NULL);
HWND hwndListView = FindWindowEx(shell, NULL, "syslistview32", NULL);
int ct = ListView_GetItemCount(hwndListView);
const DWORD dwBufSize = 1024;
DWORD dwProcessID;
DWORD dwResult;
HANDLE hProcess;
BYTE *lpRemoteBuffer;
LVITEM lvItem = {0};
BYTE lpLocalBuffer[dwBufSize] = {0};
// Get the process id owning the window
::GetWindowThreadProcessId( hwndListView, &dwProcessID );
// Open the process wih all access (You may not have the rights to do this)
hProcess = ::OpenProcess( PROCESS_ALL_ACCESS, FALSE, dwProcessID );
// Allocate a buffer in the remote process
lpRemoteBuffer = (BYTE*)::VirtualAllocEx( hProcess, NULL, dwBufSize,
MEM_COMMIT, PAGE_READWRITE );
// Fill in the LVITEM struct, this is in your own process
// Set the pszText member to somewhere in the remote buffer,
// For the example I used the address imediately following the LVITEM stuct
lvItem.mask = LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM|LVIF_STATE;
lvItem.iItem = 0;
lvItem.iSubItem = 0;
lvItem.cchTextMax = MAX_PATH;
// Point to after LVITEM in the remote buffer
lvItem.pszText = (LPTSTR)(lpRemoteBuffer + sizeof( LVITEM ));
// Copy the local LVITEM to the remote buffer
::WriteProcessMemory( hProcess, (LPVOID)lpRemoteBuffer, &lvItem, sizeof(LVITEM), NULL );
// Send the message
::SendMessage( hwndListView, LVM_GETITEM, 0, (LPARAM)lpRemoteBuffer);
// Read the struct back from the remote process into local buffer
::ReadProcessMemory( hProcess, (LPVOID)lpRemoteBuffer, lpLocalBuffer, dwBufSize, NULL );
//Fix pszText to point to same offset in local buffer
lvItem.pszText = (LPTSTR)(lpLocalBuffer + sizeof( LVITEM ));
MessageBox(hwnd, lvItem.pszText, "", 0);
char txt[10];
ZeroMemory(txt, 10);
MessageBox(hwnd, itoa(lvItem.iImage, txt, 10), "", 0);
MessageBox(hwnd, itoa((int)lvItem.state, txt, 10), "", 0);
// Clean-up
::VirtualFreeEx( hProcess, (LPVOID)lpRemoteBuffer, 0, MEM_RELEASE );
::CloseHandle( hProcess );
You are allocating virtual memory for text. You must also allocate virtual memory for LVITEM. Then assign the text memory to lvItem.pszText, and then read both memory. It has to be compiled 64-bit for 64-bit systems. Add more error checks.
HANDLE hProcess = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ |
PROCESS_VM_WRITE | PROCESS_QUERY_INFORMATION, FALSE, dwProcessID);
const DWORD dwBufSize = 1024;
void* pbuf = VirtualAllocEx(hProcess, NULL, dwBufSize, MEM_COMMIT, PAGE_READWRITE);
void* pitem = VirtualAllocEx(hProcess, NULL, sizeof(LVITEM), MEM_COMMIT, PAGE_READWRITE);
LVITEM lvItem = { 0 };
lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE;
lvItem.iItem = 0;
lvItem.iSubItem = 0;
lvItem.cchTextMax = MAX_PATH;
lvItem.pszText = (char*)pbuf;
WriteProcessMemory(hProcess, pitem, &lvItem, sizeof(LVITEM), NULL);
if (SendMessage(hwndListView, LVM_GETITEM, 0, (LPARAM)(LVITEM*)(pitem)))
{
char buf[dwBufSize];
if (ReadProcessMemory(hProcess, pbuf, buf, dwBufSize, 0))
{
OutputDebugString(buf);
OutputDebugString(", ");
if (ReadProcessMemory(hProcess, pitem, &lvItem, sizeof(LVITEM), 0))
{
_itoa_s(lvItem.iImage, buf, 10);
OutputDebugString(buf);
OutputDebugString("\n");
}
}
}
VirtualFreeEx(hProcess, pitem, 0, MEM_RELEASE);
VirtualFreeEx(hProcess, pbuf, 0, MEM_RELEASE);
CloseHandle(hProcess);
I'm trying to adjust my monitor brightness programmatically. After little bit of research, I came up with this link, and wrote the following code (mostly copy paste from other links that one lead me).
#include "Windows.h"
#include "WinUser.h"
#include "PhysicalMonitorEnumerationAPI.h"
#include "HighLevelMonitorConfigurationAPI.h"
#include <strsafe.h>
void ShowError(LPTSTR lpszFunction);
int main()
{
HMONITOR hMonitor = NULL;
DWORD cPhysicalMonitors;
LPPHYSICAL_MONITOR pPhysicalMonitors = NULL;
HWND hWnd = GetDesktopWindow();
// Get the monitor handle.
hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTOPRIMARY);
// Get the number of physical monitors.
BOOL bSuccess = GetNumberOfPhysicalMonitorsFromHMONITOR(hMonitor, &cPhysicalMonitors);
if (bSuccess)
{
// Allocate the array of PHYSICAL_MONITOR structures.
pPhysicalMonitors = (LPPHYSICAL_MONITOR)malloc(cPhysicalMonitors* sizeof(PHYSICAL_MONITOR));
if (pPhysicalMonitors != NULL)
{
// Get the array.
bSuccess = GetPhysicalMonitorsFromHMONITOR( hMonitor, cPhysicalMonitors, pPhysicalMonitors);
// Get physical monitor handle.
HANDLE hPhysicalMonitor = pPhysicalMonitors[0].hPhysicalMonitor;
LPDWORD pdwMinimumBrightness = NULL;
LPDWORD pdwCurrentBrightness = NULL;
LPDWORD pdwMaximumBrightness = NULL;
bSuccess = GetMonitorBrightness(hPhysicalMonitor, pdwMinimumBrightness, pdwCurrentBrightness, pdwMaximumBrightness);
if (bSuccess == FALSE)
{
ShowError(TEXT("GetMonitorBrightness"));
}
// Close the monitor handles.
bSuccess = DestroyPhysicalMonitors(cPhysicalMonitors, pPhysicalMonitors);
// Free the array.
free(pPhysicalMonitors);
}
}
return 0;
}
void ShowError(LPTSTR lpszFunction)
{
// Retrieve the system error message for the last-error code
LPVOID lpMsgBuf;
LPVOID lpDisplayBuf;
DWORD dw = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0, NULL );
// Display the error message and exit the process
lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
(lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));
StringCchPrintf((LPTSTR)lpDisplayBuf,
LocalSize(lpDisplayBuf) / sizeof(TCHAR),
TEXT("%s failed with error %d: %s"),
lpszFunction, dw, lpMsgBuf);
MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);
LocalFree(lpMsgBuf);
LocalFree(lpDisplayBuf);
}
This code crashes when executing this line:
bSuccess = GetMonitorBrightness(hPhysicalMonitor, pdwMinimumBrightness, pdwCurrentBrightness, pdwMaximumBrightness);
According to documentation, that function might not be supported.
If this function is supported, the GetMonitorCapabilities function
returns the MC_CAPS_BRIGHTNESS flag.
So, in order to check that, I add the following block to my code, just before calling GetMonitorBrightness.
LPDWORD pdwMonitorCapabilities = NULL;
LPDWORD pdwSupportedColorTemperatures = NULL;
bSuccess = GetMonitorCapabilities(hPhysicalMonitor, pdwMonitorCapabilities, pdwSupportedColorTemperatures);
if (bSuccess == FALSE)
{
ShowError(TEXT("GetMonitorCapabilities"));
}
Unfortunately after I added that block, I received the following error:
Again, according to documentation, GetMonitorCapabilities function fails if the monitor does not support DDC/CI.
Then I checked if my monitor is supporting DDC/CI, and found out that it is. Moreover, when I manually disable DDC/CI support from monitor settings, previous error message switches to following one, so now I'm pretty sure my monitor has DDC/CI support.
I feel like I'm doing everything correct but apparently I'm not. In short, GetMonitorCapabilities function fails with an error message that I can't give any meaning, and GetMonitorBrightness function gets crashed.
Notes:
My monitor is Dell U2713H.
I'm on 64 bit Windows 7.
I'm using Microsoft Visual C++ Compiler 12.0 (x86)
Your calls to GetMonitorBrightness() and GetMonitorCapabilities() are wrong. You are passing NULL pointers, but they expect pointers to actual DWORD variables instead:
DWORD dwMinimumBrightness = 0;
DWORD dwCurrentBrightness = 0;
DWORD dwMaximumBrightness = 0;
bSuccess = GetMonitorBrightness(hPhysicalMonitor, &dwMinimumBrightness, &dwCurrentBrightness, &dwMaximumBrightness);
DWORD dwMonitorCapabilities = 0;
DWORD dwSupportedColorTemperatures = 0;
bSuccess = GetMonitorCapabilities(hPhysicalMonitor, &dwMonitorCapabilities, &dwSupportedColorTemperatures);
I'm trying to start an application and then monitor it until it closes. I'm using ShellExecuteEX and GetExitCodeProcess and having several problems.
The code below causes a segmentation fault when GetExitCodeProcess is Called. If I change shellInfo.fMask = NULL, it will not seg fault but I recieve an error saying Invalid Handle.
Notepad.exe does launch.
QString executeFile("notepad.exe");
// Conversion QString to LPCTSTR
wchar_t* tempEF = new wchar_t[executeFile.size()+1];
int tempEFTerminator = executeFile.toWCharArray(tempEF);
tempEF[tempEFTerminator] = 0;
LPDWORD exitCode = 0;
SHELLEXECUTEINFO shellInfo;
shellInfo.cbSize = sizeof(SHELLEXECUTEINFO);
shellInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
shellInfo.hwnd = NULL;
shellInfo.lpVerb = NULL;
shellInfo.lpFile = tempEF;
shellInfo.lpParameters = NULL;
shellInfo.lpDirectory = NULL;
shellInfo.nShow = SW_MAXIMIZE;
shellInfo.hInstApp = NULL;
if(ShellExecuteEx(&shellInfo))
{
if(!GetExitCodeProcess(shellInfo.hProcess, exitCode))
{
DWORD lastError = GetLastError();
LPTSTR lpMsgBuf;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS , NULL, lastError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL);
QString errorText = ("failed with error: " + QString::number(lastError) + QString::fromWCharArray(lpMsgBuf));
}
}
I think, the problem is in exitCode argument.
MSND specifies it as LPDWORD that is pointer for DWORD. You should pass valid pointer to the function, so it could dereference it to save exit code here:
DWORD exitCode;
//....
if(!GetExitCodeProcess(shellInfo.hProcess, &exitCode))
I found the below comment on Microsoft's documentation site:
Also, CreateProcessWithLogonW rejects STD handles (0/1/2) i.e. what GetStdHandle() returns by default, when using STARTF_USESTDHANDLES. It returns error 6, invalid handles, because 0/1/2 are not "real" handles. The only way we found to redirect the console input/output was to create custom handles (pipes) and use those instead (e.g. even just as dummy handles that you don't use). This is missing functionality from CreateProcessWithLogonW, because CreateProcess (and maybe CreateProcessAsUser, I didn't verify that) accepts STD handles.
This points to creating custom pipes.
I found this StackOverflow answer which points to using things such as "SafeFileHandle". This is apparently C++/CLI which I am not familiar with how to use. I am using Visual C++ and therefore "native" C++?
I am looking for a simple solution of how to fix this issue. I am a newbie in C++ and the CLI thing confused me because I simply don't know how to use it, or make Visual C++ compatible with it.
Given my normal C++ and my question, HOW EXACTLY would I create the custom pipe which will allow me to get the standard output?
Here is my code:
#include "stdafx.h"
void DisplayError(LPWSTR pszAPI)
{
LPVOID lpvMessageBuffer;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL, GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPWSTR)&lpvMessageBuffer, 0, NULL);
//
//... now display this string
//
wprintf(L"ERROR: API = %s.\n", pszAPI);
wprintf(L" error code = %d.\n", GetLastError());
wprintf(L" message = %s.\n", (LPWSTR)lpvMessageBuffer);
//
// Free the buffer allocated by the system
//
LocalFree(lpvMessageBuffer);
ExitProcess(GetLastError());
}
void _tmain(int argc, WCHAR *argv[])
{
STARTUPINFO si;
ZeroMemory( &si, sizeof(STARTUPINFO) );
si.cb = sizeof(STARTUPINFO);
HANDLE pipe1 = CreateNamedPipe(L"\\\\.\\pipe\\pipe1", PIPE_ACCESS_DUPLEX,
PIPE_WAIT, 1024, 1024, 1024, 60, NULL);
HANDLE pipe2 = CreateNamedPipe(L"\\\\.\\pipe\\pipe2", PIPE_ACCESS_DUPLEX,
PIPE_WAIT, 1024, 1024, 1024, 60, NULL);
si.dwFlags |= STARTF_USESHOWWINDOW;
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdOutput = pipe1;
si.hStdError = pipe2;
DWORD dwSize;
HANDLE hToken;
LPVOID lpvEnv;
PROCESS_INFORMATION pi = {0};
WCHAR szUserProfile[256] = L"";
si.cb = sizeof(STARTUPINFO);
if (argc != 4)
{
wprintf(L"Usage: %s [user#domain] [password] [cmd]", argv[0]);
wprintf(L"\n\n");
return;
}
//
// TO DO: change NULL to '.' to use local account database
//
if (!LogonUser(argv[1], NULL, argv[2], LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT, &hToken))
DisplayError(L"LogonUser");
if (!CreateEnvironmentBlock(&lpvEnv, hToken, TRUE))
DisplayError(L"CreateEnvironmentBlock");
dwSize = sizeof(szUserProfile)/sizeof(WCHAR);
if (!GetUserProfileDirectory(hToken, szUserProfile, &dwSize))
DisplayError(L"GetUserProfileDirectory");
//
// TO DO: change NULL to '.' to use local account database
//
if (!CreateProcessWithLogonW(argv[1], NULL, argv[2],
LOGON_WITH_PROFILE, NULL, argv[3],
CREATE_UNICODE_ENVIRONMENT, lpvEnv, szUserProfile,
&si, &pi))
DisplayError(L"CreateProcessWithLogonW");
if (!DestroyEnvironmentBlock(lpvEnv))
DisplayError(L"DestroyEnvironmentBlock");
CloseHandle(hToken);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
I tried this and I am getting no output on the console window. As I said, I checked the answer on StackOverflow and this whole C++/CLI thing confuses me. If someone knows a simple solution to redirecting the output using a custom pipe using Visual C++, let me know.
And if I did anything wrong above, let me know as well.
EDIT:
After following the suggestions given by Remy's answer. I came up with the following code, which yields an error code 3: The system cannot find the path specified.
#include "stdafx.h"
HANDLE g_hChildStd_IN_Rd = NULL;
HANDLE g_hChildStd_IN_Wr = NULL;
HANDLE g_hChildStd_OUT_Rd = NULL;
HANDLE g_hChildStd_OUT_Wr = NULL;
HANDLE g_hInputFile = NULL;
int BUFSIZE = 1064;
void CreateChildProcess(void);
void WriteToPipe(void);
void ReadFromPipe(void);
void ErrorExit(PTSTR);
void DisplayError(LPWSTR pszAPI)
{
LPVOID lpvMessageBuffer;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL, GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPWSTR)&lpvMessageBuffer, 0, NULL);
//
//... now display this string
//
wprintf(L"ERROR: API = %s.\n", pszAPI);
wprintf(L" error code = %d.\n", GetLastError());
wprintf(L" message = %s.\n", (LPWSTR)lpvMessageBuffer);
//
// Free the buffer allocated by the system
//
LocalFree(lpvMessageBuffer);
ExitProcess(GetLastError());
}
void _tmain(int argc, WCHAR *argv[])
{
SECURITY_ATTRIBUTES saAttr;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
if ( ! CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0) )
ErrorExit(TEXT("StdoutRd CreatePipe"));
if ( ! SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0) )
ErrorExit(TEXT("Stdout SetHandleInformation"));
if (! CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0))
ErrorExit(TEXT("Stdin CreatePipe"));
if ( ! SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0) )
ErrorExit(TEXT("Stdin SetHandleInformation"));
/////////////////////////////Start CreateChildProcess////////
STARTUPINFO si;
ZeroMemory( &si, sizeof(STARTUPINFO) );
si.cb = sizeof(STARTUPINFO);
si.dwFlags |= STARTF_USESHOWWINDOW;
si.dwFlags |= STARTF_USESTDHANDLES;
si.hStdError = g_hChildStd_OUT_Wr;
si.hStdOutput = g_hChildStd_OUT_Wr;
si.hStdInput = g_hChildStd_IN_Rd;
DWORD dwSize;
HANDLE hToken;
LPVOID lpvEnv;
PROCESS_INFORMATION pi = {0};
WCHAR szUserProfile[256] = L"";
si.cb = sizeof(STARTUPINFO);
if (argc != 4)
{
wprintf(L"Usage: %s [user#domain] [password] [cmd]", argv[0]);
wprintf(L"\n\n");
return;
}
//
// TO DO: change NULL to '.' to use local account database
//
if (!LogonUser(argv[1], NULL, argv[2], LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT, &hToken))
DisplayError(L"LogonUser");
if (!CreateEnvironmentBlock(&lpvEnv, hToken, TRUE))
DisplayError(L"CreateEnvironmentBlock");
dwSize = sizeof(szUserProfile)/sizeof(WCHAR);
if (!GetUserProfileDirectory(hToken, szUserProfile, &dwSize))
DisplayError(L"GetUserProfileDirectory");
//
// TO DO: change NULL to '.' to use local account database
//
if (!CreateProcessWithLogonW(argv[1], NULL, argv[2],
LOGON_WITH_PROFILE, NULL, argv[3],
CREATE_UNICODE_ENVIRONMENT, lpvEnv, szUserProfile,
&si, &pi))
DisplayError(L"CreateProcessWithLogonW");
if (!DestroyEnvironmentBlock(lpvEnv))
DisplayError(L"DestroyEnvironmentBlock");
CloseHandle(hToken);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
/////////////////////////////End CreateChildProcess///////////
if (argc == 1)
ErrorExit(TEXT("Please specify an input file.\n"));
g_hInputFile = CreateFile(
argv[3],
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_READONLY,
NULL);
if ( g_hInputFile == INVALID_HANDLE_VALUE )
ErrorExit(TEXT("CreateFile"));
WriteToPipe();
printf( "\n->Contents of %s written to child STDIN pipe.\n", argv[1]);
printf( "\n->Contents of child process STDOUT:\n\n", argv[1]);
ReadFromPipe();
}
void WriteToPipe(void)
// Read from a file and write its contents to the pipe for the child's STDIN.
// Stop when there is no more data.
{
DWORD dwRead, dwWritten;
CHAR chBuf[4096];
BOOL bSuccess = FALSE;
for (;;)
{
bSuccess = ReadFile(g_hInputFile, chBuf, BUFSIZE, &dwRead, NULL);
if ( ! bSuccess || dwRead == 0 ) break;
bSuccess = WriteFile(g_hChildStd_IN_Wr, chBuf, dwRead, &dwWritten, NULL);
if ( ! bSuccess ) break;
}
// Close the pipe handle so the child process stops reading.
if ( ! CloseHandle(g_hChildStd_IN_Wr) )
ErrorExit(TEXT("StdInWr CloseHandle"));
}
void ReadFromPipe(void)
// Read output from the child process's pipe for STDOUT
// and write to the parent process's pipe for STDOUT.
// Stop when there is no more data.
{
DWORD dwRead, dwWritten;
CHAR chBuf[4096];
BOOL bSuccess = FALSE;
HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
for (;;)
{
bSuccess = ReadFile( g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL);
if( ! bSuccess || dwRead == 0 ) break;
bSuccess = WriteFile(hParentStdOut, chBuf,
dwRead, &dwWritten, NULL);
if (! bSuccess ) break;
}
}
void ErrorExit(PTSTR lpszFunction)
// Format a readable error message, display a message box,
// and exit from the application.
{
LPVOID lpMsgBuf;
LPVOID lpDisplayBuf;
DWORD dw = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0, NULL );
lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
(lstrlen((LPCTSTR)lpMsgBuf)+lstrlen((LPCTSTR)lpszFunction)+40)*sizeof(TCHAR));
StringCchPrintf((LPTSTR)lpDisplayBuf,
LocalSize(lpDisplayBuf) / sizeof(TCHAR),
TEXT("%s failed with error %d: %s"),
lpszFunction, dw, lpMsgBuf);
MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);
LocalFree(lpMsgBuf);
LocalFree(lpDisplayBuf);
ExitProcess(1);
}
Use anonymous pipes via CreatePipe(), not named pipes via CreateNamedPipe(). See MSDN for an example:
Creating a Child Process with Redirected Input and Output