CreateService and quotes for lpBinaryPathName parameter - c++

I'm trying to install a kernel driver from an MFC application using CreateService function and I'm not sure that I fully understand how lpBinaryPathName parameter is supposed to be set up.
Quoting MSDN:
The fully qualified path to the service binary file. If the path
contains a space, it must be quoted so that it is correctly
interpreted. For example, "d:\my share\myservice.exe" should be
specified as "\"d:\my share\myservice.exe\"".
The path can also include arguments for an auto-start service. For
example, "d:\myshare\myservice.exe arg1 arg2". These arguments are
passed to the service entry point (typically the main function).
So I do this:
LPCTSTR pStrDriverFilePath; //Driver full path
LPCTSTR pStrDriverFileParams; //Parameters
hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
CString strDrvPath;
strDrvPath.Format(L"\"%s\"", pStrDriverFilePath);
if(pStrDriverFileParams &&
pStrDriverFileParams[0])
{
strDrvPath.AppendFormat(L" %s", pStrDriverFileParams);
}
CreateService(hSCManager, pStrDriverName, pStrDriverDispName,
SERVICE_START | DELETE | SERVICE_STOP | SERVICE_QUERY_STATUS,
dwDriverType, dwStartType, dwErrorCtrl,
strDrvPath,
NULL, NULL, NULL,
NULL, NULL);
But then when I try to start it:
StartService(hScDrvHandle, 0, NULL);
it fails with the error code 123, or ERROR_INVALID_NAME:
The filename, directory name, or volume label syntax is incorrect.
Edit: This is how it ends up looking in HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\ key:
It only works if I remove double quotes (but only w/o a parameter.)

Related

Why does JetAttachDatabase return error -550?

stack, I need help, JetAttachDatabase returning error -550. JET_paramRecovery is switched off. What should I do that it starts work?
I've already tried to restore instance, but I have no restore file... I don't know what should I do. Now I have code like that
sWebDataBase.err = JetGetDatabaseFileInfo(sWebDataBase.path,
&sWebDataBase.dbPageSize,
sizeof(sWebDataBase.dbPageSize),
JET_DbInfoPageSize);
ErrCheck(sWebDataBase.err, "JetSetSystemParameter, JetGetDatabaseFileInfo");
sWebDataBase.err = JetSetSystemParameter (&sWebDataBase.instance,
JET_sesidNil,
JET_paramDatabasePageSize,
sWebDataBase.dbPageSize,
NULL);
ErrCheck(sWebDataBase.err, "JetSetSystemParameter, JET_paramDatabasePageSize");
sWebDataBase.err = JetSetSystemParameterW(&sWebDataBase.instance,
JET_sesidNil,
JET_paramAlternateDatabaseRecoveryPath,
NULL,
L"C:\\Users\\Chrnykh\\AppData\\Local\\Microsoft\\Windows\\WebCache\\test1.dat");
ErrCheck(sWebDataBase.err, "JetSetSystemParameter, JET_paramAlternateDatabaseRecoveryPath");
sWebDataBase.err = JetSetSystemParameter (&sWebDataBase.instance,
JET_sesidNil,
JET_paramRecovery,
NULL,
(JET_PCWSTR)"On");
ErrCheck(sWebDataBase.err, "JetSetSystemParameter, JET_paramRecovery");
sWebDataBase.err = JetInit (&sWebDataBase.instance); //------------------------------------JetInit
ErrCheck(sWebDataBase.err, "JetInit");
sWebDataBase.err = JetBeginSession (sWebDataBase.instance,
&sWebDataBase.sesId,
NULL,
NULL);
ErrCheck(sWebDataBase.err, "JetBeginSession");
ErrCheck(sWebDataBase.err, "JetRestoreInstanceW");
sWebDataBase.err = JetAttachDatabase(sWebDataBase.sesId,
sWebDataBase.path,
JET_bitDbReadOnly);
ErrCheck(sWebDataBase.err, "JetAttachDatabaseW");
sWebDataBase.err = JetOpenDatabaseW(sWebDataBase.sesId,
sWebDataBase.path,
NULL,
&sWebDataBase.dbId,
JET_bitDbReadOnly);
ErrCheck(sWebDataBase.err, "JetOpenDatabaseW");
You shouldn't have to set JET_paramRecovery. It defaults to on. Try removing that. You also set it to "On" in the code, but your question says it was set off. It's also not a good idea to disable it, because if you modify the database and crash, then the entire database is unusable at that point. This is acceptable for a very small minority of people.
Instead of setting JET_paramAlternateDatabaseRecoveryPath, you should set the Logging path.
When you call JetInit, the database engine will examine the current log stream, and replay the operations if necessary. You'll need to set the logging directory, as well as the Checkpoint file location (confusingly called "System Path"). Then it should be able to replay the log files successfully. You may also need to set the "Log file base name", which defaults to "edb", but it can be set to any 3-character sequence.
You can also use the command-line utility esentutl.exe to replay the logs first. Use it by changing in to the directory of the log files, and running a command like esentutl.exe -r edb.
Does that make sense?

How do I get username and appname for file path

How am I able to define a path like "C:/Users/<USER>/AppData/Local/<APPNAME>", for different username and app? How do I set this to automatically get the user and the appname? Thank you.
You can use SHGetKnownFolderPath to get the full path of App Local:
...
#include <KnownFolders.h>
#include <ShlObj.h>
...
SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_SIMPLE_IDLIST, NULL, &path); // NULL for current user
...
To get the Local AppData path for a given user, use SHGetFolderPath() specifying CSIDL_LOCAL_APPDATA, or SHGetKnownFolderPath() specifying FOLDERID_LocalAppData. Both take an optional user token for the desired user account to query. If you don't provide a token, the user associated with the calling thread is used.
To get the username:
char username[MAX_PATH];
DWORD size = MAX_PATH;
GetUserName(username,&size);
To get the appname(Executable File Name without ".exe"):
char appname[MAX_PATH];
char buffer[MAX_PATH];
GetModuleFileName(NULL, appname,MAX_PATH); //get the string: "PATH\\appname.exe"
char *szExe = NULL;
//Remove prefix
GetFullPathName(appname, MAX_PATH, buffer, &szExe);
//Remove suffix
strncpy_s(appname, szExe, strlen(szExe) - strlen(".exe"));

NSIS Plugin with bad string

I've tried to develop an NSIS Plugin in C++.
Here is my method to set informations from NSIS:
void __declspec(dllexport) SetCredentials(HWND hWndParent, int string_size, TCHAR *variables, stack_t **stacktop, extra_parameters *extra) {
EXDLL_INIT();
server = getuservariable(INST_0);
port = myatou(getuservariable(INST_1));
database = getuservariable(INST_2);
username = getuservariable(INST_3);
password = getuservariable(INST_4);
MessageBox(hWndParent, server, L"Info", MB_OK); // Here is the problem
setuservariable(INST_0, server);
}
Sample:
OutFile "Example.exe"
BrandingText " "
Section
MySQL::SetCredentials "localhost" 3306 "banananode" "root" ""
Pop $0
MessageBox MB_OK "Server: $0" ; Returns the server value...
SectionEnd
The Problem is, when i try to print out the server variable, chinese characters will be shown, not the correct text:
When i return the value with setuservariable(INST_0, server);, NSIS will be display it correctly:
Can you tell me, whats wrong?
I've tried to build the resulted .dll with pluginapi-x86-ansi.lib and pluginapi-x86-unicode.lib but the result is the same...
ANSI characters interpreted as Unicode (UTF-16LE) tends to look Chinese.
When you create a Unicode plug-in you need to:
Make sure UNICODE and _UNICODE is defined in your project/.C files.
Link with pluginapi-x86-unicode.lib
Add Unicode True to your .NSI
Place the plug-in in \NSIS\x86-unicode
In your case you most likely forgot about Unicode True. Returning the value works because you never actually changed the memory of server, it is still the same input string.

ShellExecute (and ShellExecuteEx) do nothing with my URL

I'm creating a project with C++Builder XE7, in which a user can click on a button to open a web link, e.g. to open a support page, or to share his experience on a social media. For that, I use the ShellExecute() function, and it works well, except for one button.
When I click on this button, simply nothing happens. The ShellExecute() function returns without error (the returned value is 42), but my default browser does not open, and the web page isn't shown at all.
Here is my ShellExecute() implementation
const HINSTANCE result = ::ShellExecute(handle, "open", url.c_str(), NULL, NULL, SW_SHOWDEFAULT);
I also tried the ShellExecuteEx() function:
::SHELLEXECUTEINFO info;
std::memset(&info, 0, sizeof(info));
info.cbSize = sizeof(info);
info.hwnd = handle;
info.lpVerb = "open";
info.lpFile = url.c_str();
info.nShow = SW_SHOWDEFAULT;
if (!::ShellExecuteEx(&info))
The url parameter contains the website link I am trying to open. For security reasons, I cannot post it here as a sample, however I tested it in my browser (FireFox) and it works well. On the other hand, if I execute my code by just replacing the url content with Google's website, all works as expected.
The handle is just the Handle parameter of the parent frame.
I also tried to tweak the ShellExecute/Ex() parameters, like the hwnd and nShow fields, but no change.
Can anybody point me to what is wrong?
The url is formatted like this: http:// www.
mysite.xxx/selectPage.php?arg1=xxx&arg2=yyy&...&argX=a text containing
"quotes" and some %26amp%3b special chars!
In this example you have to URL-encode the double quotes and the spaces because these are not valid characters for the query part of an URL.
Fix it by replacing double quotes with %22 and spaces with %20. I suggest to use a function like UrlEscape() to properly encode the URL.
Although most browsers have an error tolerance for user input and will also accept an URL which does not have valid encoding, it's better to strictly follow the spec because you are not guaranteed that tolerance.
In addition, the double quotes will make problems when the URL is passed as a command-line argument to the command associated with the URL protocol. This is because double quotes are reserved characters for defining command-line parameters that contain spaces.
For instance, on my machine the http protocol is associated with the following command (see HKEY_CLASSES_ROOT\http\shell\open\command):
"C:\Program Files (x86)\Mozilla Firefox\firefox.exe" -osint -url "%1"
You can see that the double quotes are already used to enclose the last parameter, which obviously gets messed up if you have unencoded double quotes within the URL.
Example for correctly encoding an URL for use with ShellExecuteEx():
#include <windows.h>
#include <Shellapi.h>
int main()
{
::CoInitialize(nullptr);
SHELLEXECUTEINFOW info{ sizeof(info) };
info.fMask = SEE_MASK_NOASYNC; // because we exit process after ShellExecuteEx()
info.lpVerb = L"open";
info.lpFile = L"http://www.google.de/search?q=ShellExecuteEx%20URL%20%22double%20quotes%22";
info.nShow = SW_SHOWDEFAULT;
if( !::ShellExecuteExW( &info ) )
{
DWORD err = ::GetLastError();
printf("ShellExecuteEx failed with error %d\n", err );
}
::CoUninitialize();
}

how to initialize IMAPISession OpenMsgStore?

I am using MAPI for tracking the incoming messages. (using C++)
I have called MAPIInitialize and LAPILogonEx as follows:
HRESULT hr;
hr = MAPIInitialize(0);
IMAPISession *pSession;
hr = MAPILogonEx(0, NULL, NULL, 0, (LPMAPISESSION *)&pSession);
I want to register this for notifications as I want to track the incoming messages. So I tried to call the IMAPISession::OpenMsgStore before calling IMsgStore::Advise as follows:
IMsgStore *imsg = NULL;
hr = pSession->OpenMsgStore(NULL, NULL, 0, NULL, 0, &imsg);
But the above call does not work (It returns -2147221241). I am passing 0 to the Entry ID because I want to track messages in all the folders. Can someone please help me about where I am going wrong? Any help would be much appreciated. Thanks
The error is MAPI_E_INVALID_ENTRYID. You cannot pass NULL for the entry id.
You need to call IMAPIsession::GetMsgStoresTables, find the message store that you need, then pass its entry id to OpenMsgStore.