Installing a driver programmatically using INF file c++ - c++

Could someone here please let me know how to install 3rd party device drivers
programmatically if all the required files i.e. inf file, .sys etc are provided. The
minimum operating system this solution SHOULD work on is Windows2000.
I tried copying the .inf file into the Win Folder\INF folder and the sys file
into the Win folder\system32\drivers but each time plug in the device, windows
pops up Found New Hardware user interface which is what i am trying to avoid.
Below is something i tried but the function returns error 87 (The parameter is incorrect).
HINF HInf;
UINT ErrorLine;
BOOL bRes = FALSE;
PBOOL FileWasInUse = FALSE;
LPCSTR szSourceFileName = _T("C:\\Drivers_HypercomP1320\\hypvcpusb.inf");
LPCSTR szInfFileName = _T("hypvcpusb.inf");
PVOID Context = NULL;
HInf = SetupOpenInfFile ( szSourceFileName, NULL, INF_STYLE_WIN4, &ErrorLine);
LPCSTR SourceFile = ("hypvcp.sys");
LPCSTR SourcePathRoot = _T("C:\\Drivers_HypercomP1320");
LPCSTR DestinationName = _T("C:\\WINDOWS\\system32\\drivers\\hypvcp.sys");
bRes = SetupInstallFileEx ( HInf, NULL, SourceFile, SourcePathRoot, DestinationName, SP_COPY_FORCE_IN_USE,
(PSP_FILE_CALLBACK)CopyMsgHandler, Context, FileWasInUse);
DWORD dwVal = GetLastError();
SetupCloseInfFile(HInf);
// Callback function
UINT CopyMsgHandler (UINT Context, UINT Notification,UINT_PTR Param1, UINT_PTR Param2)
{
UINT rtnValue = NO_ERROR;
return rtnValue;
}
Thanks.

Yes. You start by calling
SC_HANDLE manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (manager)
{
wprintf(L"Opened SC Manager\n");
}
else
{
wprintf(L"Open SC Manager failed\n");
return;
}
Then having the .inf file stored in szInfFileName you call:
HInf = SetupOpenInfFile(szInfFileName.c_str(), NULL, INF_STYLE_WIN4, &ErrorLine);
Then you call
if (SetupInstallFileEx(HInf, NULL, SourceFile, SourcePathRoot, DestinationName, SP_COPY_NEWER_OR_SAME, NULL, Context, &FileWasInUse) == NULL)
SourceFile = the driver file name (ending with .sys)
SourcePathRoot = the location of the driver file (would be the path where your program runs from)
DestinationName = full path of the driver to be installed (for example:
c:\windows\system32\drivers\yourdriver.sys
Then there is the Registry. You need to add an entry for your driver under
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\
this entry (key) should have:
Driver name, display name, description, ErrorControl and Group.
Next step, you start the driver using:
SC_HANDLE service = CreateService(manager,
DRIVER_NAME,
DRIVER_NAME,
SERVICE_ALL_ACCESS,
SERVICE_KERNEL_DRIVER,
SERVICE_AUTO_START,
SERVICE_ERROR_NORMAL,
KeyName,
NULL, NULL, NULL, NULL, NULL);
When KeyName is the driver's path under System32 as appeared in the Registry entry. For example:
system32\drivers\yourdriver.sys
Last step:
BOOL result = StartService(service, 0, NULL);
and cleaning up
CloseServiceHandle(manager)

You can use InstallHinfSection.

It might be your use of
PBOOL FileWasInUse = FALSE;
. You should change it in
BOOL FileWasInUse = FALSE;
and use it in the function-call with &FileWasInUse (note the &-character).

Related

SHGetKnownFolderPath fails with E_ACCESSDENIED

I have a program that calls SHGetKnownFolderPath with FOLDERID_RoamingAppData.
If I start the program by double clicking it, it works ok.
If the program is started by a windows service (in the current user context), the function fails with error E_ACCESSDENIED (-2147024891).
This is what my code looks like:
Tstring EasyGetFolderPath(REFKNOWNFOLDERID folderid)
{
Tstring sPath = _T("");
PWSTR pszPath = NULL;
HRESULT hr = SHGetKnownFolderPath(folderid, 0, NULL, &pszPath);
if (hr == S_OK && pszPath)
{
sPath = WStringToTCHAR(pszPath);
CoTaskMemFree(pszPath);
return sPath;
}
else
{
throw HResultException(hr, _T("SHGetKnownFolderPath failed"));
}
}
Tstring EasyGetUsrAppDataPath()
{
return EasyGetFolderPath(FOLDERID_RoamingAppData);
}
static TCHAR* WStringToTCHAR(const std::wstring &s)
{
#ifdef UNICODE
TCHAR *sT = new TCHAR[s.length() + 1];
_tcscpy_s(sT, s.length() + 1, s.c_str());
return sT;
#else
std::string str = WStringToString(s);
TCHAR *sT = new TCHAR[str.length()+1];
_tcscpy_s(sT, str.length() + 1, str.c_str());
return sT;
#endif // UNICODE
}
static std::string WStringToString(const std::wstring& s, bool method = true)
{
std::string temp;
temp.assign(s.begin(), s.end());
return temp;
}
This is the code that starts the process in the current user context:
(I've removed the error handling in order to reduce verbosity)
void StartProcessInCurrentUserContext(const Tstring &sExeName, const Tstringarr &lstParams, const Tstring &sWorkingDir)
{
...
EnableDebugPrivilege();
errCode = GetProcessByName(_T("explorer.exe"), hProcess);
if (!OpenProcessToken(hProcess, TOKEN_ALL_ACCESS, &hToken))
{
...
}
if (hProcess)
CloseHandle(hProcess);
Tstring sCmdLine = ...;
...
// Create the child process.
bSuccess = CreateProcessAsUser(hToken, NULL,
(LPTSTR)sCmdLine.c_str(), // command line
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // handles are inherited
0, // creation flags
NULL, // use parent's environment
sWorkingDir.length() > 0 ? (LPCTSTR)sWorkingDir.c_str() : NULL,
&siStartInfo, // STARTUPINFO pointer
&piProcInfo); // receives PROCESS_INFORMATION
CloseHandle(hToken);
...
}
Does anyone know what the problem might be?
The documentation for SHGetKnownFolderPath says in the discussion of the hToken parameter:
In addition to passing the user's hToken, the registry hive of that specific user must be mounted.
The documentation for CreateProcessAsUser says
CreateProcessAsUser does not load the specified user's profile into the HKEY_USERS registry key.
These two paragraphs together explain why your code is not working. Fortunately, the next sentence in the documentation for CreateProcessAsUser explains what you need to do:
Therefore, to access the information in the HKEY_CURRENT_USER registry key, you must load the user's profile information into HKEY_USERS with the LoadUserProfile function before calling CreateProcessAsUser. Be sure to call UnloadUserProfile after the new process exits.

Get active processname in vc++

Am working on a background appliation in vc++
How can i get the Process Name of the current Application for example "Iexplore" for Using Internet Explorer, "Skype" for window with tile "Skype - username", "Explorer" for using windows explorer ?
i referred this link but am getting Null error : http://www.codeproject.com/Articles/14843/Finding-module-name-from-the-window-handle
This can be done using the following code:
bool GetActiveProcessName(TCHAR *buffer, DWORD cchLen)
{
HWND fg = GetForegroundWindow();
if (fg)
{
DWORD pid;
GetWindowThreadProcessId(fg, &pid);
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
if (hProcess)
{
BOOL ret = QueryFullProcessImageName(hProcess, 0, buffer, &cchLen);
//here you can trim process name if necessary
CloseHandle(hProcess);
return (ret != FALSE);
}
}
return false;
}
and then
TCHAR buffer[MAX_PATH];
if(GetActiveProcessName(buffer, MAX_PATH))
{
_tprintf(_T("Active process: %s\n"), buffer);
}
else
{
_tprintf(_T("Cannot obtain active process name.\n"));
}
Note though that QueryFullProcessImageName function is only available since Windows Vista, on earlier systems you could use GetProcessImageFileName (it is similar, but requires linkage with psapi.dll and returns device path instead of usual win32 path)
I used this code in my QT5/C++ project to get the currently active process name and window title successfully, based on some research (thanks #dsi). Just wanted to share the code so that someone else would benefit from it.
# Put this two declarations in the top of the CPP file
#include <windows.h>
#pragma comment(lib, "user32.lib")
And put the following into a method:
// get handle of currently active window
HWND hwnd = GetForegroundWindow();
if (hwnd) {
// Get active app name
DWORD maxPath = MAX_PATH;
wchar_t app_path[MAX_PATH];
DWORD pid;
GetWindowThreadProcessId(hwnd, &pid);
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
if (hProcess) {
QueryFullProcessImageName(hProcess, 0, app_path, &maxPath);
// here you can trim process name if necessary
CloseHandle(hProcess);
QString appPath = QString::fromWCharArray(app_path).trimmed();
QFileInfo appFileInfo(appPath);
windowInfo.appName = appFileInfo.fileName();
}
// Get active window title
wchar_t wnd_title[256];
GetWindowText(hwnd, wnd_title, sizeof(wnd_title));
windowInfo.windowTitle = QString::fromWCharArray(wnd_title);
}
This code may not be compiled directly, because windowInfo is a parameter in my program. Please feel free to let me know in case you encountered any issues when trying this code.

How can i get shortcut display name when mouse right-click in (c++/c#)

i'm buliding a dll about filecontextmenu , i need to get the execution path and shortcut displaynem when mouse right-click . now i can get the path ,but no idea how to get the displayname.
EX: IE Shortcut in desktop, i need the name "IE" which can edit by user , not "iexplore.exe".
here is a reference very similar , but i can't find out i should to do , when the shortcut in the desktop
if there any suggestion i will very appreciate , here is my code and thanks.
IFACEMETHODIMP FileContextMenuExt::Initialize(
LPCITEMIDLIST pidlFolder, LPDATAOBJECT pDataObj, HKEY hKeyProgID)
if (NULL == pDataObj)
return E_INVALIDARG;
HRESULT hr = E_FAIL;
FORMATETC fe = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
STGMEDIUM stm;
// The pDataObj pointer contains the objects being acted upon. In this
// example, we get an HDROP handle for enumerating the selected files and
// folders.
if (SUCCEEDED(pDataObj->GetData(&fe, &stm)))
{
// Get an HDROP handle.
HDROP hDrop = static_cast<HDROP>(GlobalLock(stm.hGlobal));
if (hDrop != NULL)
{
UINT nFiles = DragQueryFileW(hDrop, 0xFFFFFFFF, NULL, 0);
if (nFiles > 0)
{
vecSelectFiles.clear();
std::vector<std::wstring> vecTotalFiles;
vecTotalFiles.clear();
for(int i=0; i<(int)nFiles; ++i)
{
wchar_t wszThisFile[MAX_PATH];
memset(wszThisFile, 0, MAX_PATH*2);
// Here get excution path
if(DragQueryFileW(hDrop, i, wszThisFile, MAX_PATH) != 0)
{
vecTotalFiles.push_back(wszThisFile);
hr = S_OK;
}
}
}
GlobalUnlock(stm.hGlobal);
}
ReleaseStgMedium(&stm);
}
// If any value other than S_OK is returned from the method, the context
// menu item is not displayed.
return hr;
As mentioned in MSDN, "It is recommend that handlers use a Shell item array rather than clipboard formats like CF_HDROP and CFSTR_SHELLIDLIST (also known as HIDA) as it leads to simpler code and allows some performance improvements."
So, firstly call SHCreateShellItemArrayFromDataObject() on pDataObj and retrieve IShellItemArray interface. Enumerate it with IShellItemArray::Count() and IShellItemArray::GetItemAt().
Each IShellItem object has an excellent GetDisplayName() method!
You ever can specify display type:
SIGDN_NORMALDISPLAY = 0x00000000,
SIGDN_PARENTRELATIVEPARSING = 0x80018001,
SIGDN_PARENTRELATIVEFORADDRESSBAR = 0x8001c001,
SIGDN_DESKTOPABSOLUTEPARSING = 0x80028000,
SIGDN_PARENTRELATIVEEDITING = 0x80031001,
SIGDN_DESKTOPABSOLUTEEDITING = 0x8004c000,
SIGDN_FILESYSPATH = 0x80058000,
SIGDN_URL = 0x80068000,
Where you have SIGDN_FILESYSPATH and SIGDN_NORMALDISPLAY ids :-)

AddPrinterDriver fails with ERROR_ACCESS_DENIED

On a few computers a call to AddPrinterDriver fails with ERROR_ACCESS_DENIED. My program is ensured to run with administrator rights, and it copies the driver DLLs into C:\WINDOWS without any errors (access denied or other).
// structure for AddPrinterDriver
DRIVER_INFO_3 di3 = { 0 };
di3.cVersion = 3;
di3.pName = _T(MyAppPrinterName) _T(" Driver");
di3.pDefaultDataType = _T("");
// path to driver dll
FilePath file1(strDriverDirectory.c_str());
di3.pDriverPath = (LPTSTR) file1.Append(MyAppPrinterDriverDllFileName).ToString();
// path to driver ui dll
FilePath file2(strDriverDirectory.c_str());
di3.pConfigFile = (LPTSTR) file2.Append(MyAppPrinterUiDllFileName).ToString();
// path to license file
FilePath file3(strDriverDirectory.c_str());
di3.pDataFile = (LPTSTR) file3.Append(_T(MyAppPrinterName) _T(".dat")).ToString();
// add driver
bResult = AddPrinterDriver(NULL, 3, (LPBYTE) &di3);
StoreLastError(_T("AddPrinterDriver"));
if (!bResult)
return FALSE;
This is my DrvPrinterEvent function:
BOOL DrvPrinterEvent(
LPWSTR lpwstrPrinterName,
INT iEvent,
DWORD dwFlags,
LPARAM lParam
)
{
return TRUE;
}

Creating a MiniDump of a running process

Im trying to make a tool for my end users that can create a MiniDump of my application if it hangs (i.e. external to the app). Im using the same code as the internal MiniDumper but with the handle and processid of the app but i keep getting error code 0xD0000024 when calling MiniDumpWriteDump. Any ideas?
void produceDump( const char* exe )
{
DWORD processId = 0;
HANDLE process = findProcess(exe, processId);
if (!process || processId == 0)
{
printf("Unable to find exe %s to produce dump.\n", exe);
return;
}
LONG retval = EXCEPTION_CONTINUE_SEARCH;
HWND hParent = NULL; // find a better value for your app
// firstly see if dbghelp.dll is around and has the function we need
// look next to the EXE first, as the one in System32 might be old
// (e.g. Windows 2000)
HMODULE hDll = NULL;
char szDbgHelpPath[_MAX_PATH];
if (GetModuleFileName( NULL, szDbgHelpPath, _MAX_PATH ))
{
char *pSlash = _tcsrchr( szDbgHelpPath, '\\' );
if (pSlash)
{
_tcscpy( pSlash+1, "DBGHELP.DLL" );
hDll = ::LoadLibrary( szDbgHelpPath );
}
}
if (hDll==NULL)
{
// load any version we can
hDll = ::LoadLibrary( "DBGHELP.DLL" );
}
LPCTSTR szResult = NULL;
int err = 0;
if (hDll)
{
MINIDUMPWRITEDUMP pDump = (MINIDUMPWRITEDUMP)::GetProcAddress( hDll, "MiniDumpWriteDump" );
if (pDump)
{
char szDumpPath[_MAX_PATH];
char szScratch [_MAX_PATH];
time_t rawtime;
struct tm * timeinfo;
time ( &rawtime );
timeinfo = localtime ( &rawtime );
char comAppPath[MAX_PATH];
SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA , NULL, SHGFP_TYPE_CURRENT, comAppPath );
//COMMONAPP_PATH
_snprintf(szDumpPath, _MAX_PATH, "%s\\DN", comAppPath);
CreateDirectory(szDumpPath, NULL);
_snprintf(szDumpPath, _MAX_PATH, "%s\\DN\\D", comAppPath);
CreateDirectory(szDumpPath, NULL);
_snprintf(szDumpPath, _MAX_PATH, "%s\\DN\\D\\dumps", comAppPath);
CreateDirectory(szDumpPath, NULL);
char fileName[_MAX_PATH];
_snprintf(fileName, _MAX_PATH, "%s_Dump_%04d%02d%02d_%02d%02d%02d.dmp", exe, timeinfo->tm_year+1900, timeinfo->tm_mon, timeinfo->tm_mday, timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec );
_snprintf(szDumpPath, _MAX_PATH, "%s\\DN\\D\\dumps\\%s", comAppPath, fileName);
// create the file
HANDLE hFile = ::CreateFile( szDumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
if (hFile!=INVALID_HANDLE_VALUE)
{
MINIDUMP_CALLBACK_INFORMATION mci;
mci.CallbackRoutine = (MINIDUMP_CALLBACK_ROUTINE)MyMiniDumpCallback;
mci.CallbackParam = 0;
MINIDUMP_TYPE mdt = (MINIDUMP_TYPE)(MiniDumpWithPrivateReadWriteMemory |
MiniDumpWithDataSegs |
MiniDumpWithHandleData |
//MiniDumpWithFullMemoryInfo |
//MiniDumpWithThreadInfo |
MiniDumpWithProcessThreadData |
MiniDumpWithUnloadedModules );
// write the dump
BOOL bOK = pDump( process, processId, hFile, mdt, NULL, NULL, &mci );
DWORD lastErr = GetLastError();
if (bOK)
{
printf("Crash dump saved to: %s\n", szDumpPath);
return;
}
else
{
_snprintf( szScratch, _MAX_PATH, "Failed to save dump file to '%s' (error %u)", szDumpPath, lastErr);
szResult = szScratch;
err = ERR_CANTSAVEFILE;
}
::CloseHandle(hFile);
}
else
{
_snprintf( szScratch, _MAX_PATH, "Failed to create dump file '%s' (error %u)", szDumpPath, GetLastError());
szResult = szScratch;
err = ERR_CANTMAKEFILE;
}
}
else
{
szResult = "DBGHELP.DLL too old";
err = ERR_DBGHELP_TOOLD;
}
}
else
{
szResult = "DBGHELP.DLL not found";
err = ERR_DBGHELP_NOTFOUND;
}
printf("Could not produce a crash dump of %s.\n\n[error: %u %s].\n", exe, err, szResult);
return;
}
this code works 100% when its internal to the process (i.e. with SetUnhandledExceptionFilter)
Are you opening the process with the necessary access rights? MiniDumpWriteDump() needs the process handle to be opened using PROCESS_QUERY_INFORMATION and PROCESS_VM_READ access rights. When using GetCurrentProcess(), I think these are granted automatically, but when using OpenProcess() to open another process, you have to request these rights.
To do so, you might also have to enable SeDebugPrivilege, which would cause problems for users whose accounts don't have that privilege. But the documentation doesn't seem to be clear on whether SeDebugPrivilege is necessary for PROCESS_QUERY_INFORMATION and PROCESS_VM_READ rights specifically (as opposed to all process access rights), particularly when opening a process that is running as the same user account.
I see that you are explicitly casting MyMiniDumpCallback to be a PMINIDUMP_CALLBACK_INFORMATION type. That looks fishy, as if you had a compiler error that you were getting around because the types didn't match. That, and PMINIDUMP_CALLBACK_INFORMATION is a struct, not a function pointer.
The direct cast of function pointer to PMINIDUMP_CALLBACK_INFORMATION might be valid since the first parameter of that struct is the callback function. But again, it looks real fishy. Perhaps you misdeclared your callback function (like forgetting the CALLBACK/__stdcall modifier). Get your code to compile without casting those formal params first, then I'll be more inclined to help you.
Also, did you even check that your callback function is even getting called at all?