Manually implement c string function with security enhancements - c++

I'm trying to write a replacement for the _tcstok_s function that doesn't skip initial delimiters. (_tcstok_s is a variant of the strtok function that uses TCHARs and includes security enhancements documented at https://msdn.microsoft.com/en-us/library/8ef0s5kh.aspx). I'm doing this due to the annoying behavior of strtok that skips consecutive delimiters. I got the idea from
c++ strtok skips second token or consecutive delimiter.
The thing I don't understand is how to implement the security enhancements that make _tcstok_s better than _tcstok. How to I make sure my re-implementation is as secure as _tcstok_s?
Although my code is C++, I am using C-style strings because I am implementing an MSI DLL.
This is what I have so far, but I don't know how to add the _s security enhancements.
TCHAR *GetNextToken(TCHAR *strToken, const TCHAR *szDelimit, TCHAR **pszContext)
{
if (strToken == NULL)
{
if ((pszContext == NULL) || (*pszContext == NULL))
return NULL;
TCHAR *pToken = _tcspbrk(*pszContext, szDelimit);
TCHAR *szResult = *pszContext;
if (!pToken)
{
*pszContext = NULL;
}
else
{
*pToken++ = _T('\0');
*pszContext = pToken;
}
return szResult;
}
else
{
TCHAR *pToken = _tcspbrk(strToken, szDelimit);
if (!pToken)
{
*pszContext = NULL;
}
else
{
*pToken++ = _T('\0');
*pszContext = pToken;
}
return strToken;
}
}

Related

Get string of temp file and add custom folder

I'm new to C++ and I have been thinking how to get string of the user's temp folder on Windows and append to it a custom folder name.
e.g "\Users\user\AppData\Local\Temp\NameOfCustomFolder"
I've tried this:
std::string szOutput{};
TCHAR path_buf[MAX_PATH];
DWORD ret_val = GetTempPath(MAX_PATH, path_buf);
if (ret_val > MAX_PATH || (ret_val == 0))
{
std::cout << "GetTempPath failed";
}
else
{
szOutput = path_buf, "NameOfCustomFolder\\file.exe"
}
return szOutput;
This does not perform the string concatenation you want
szOutput = path_buf, "NameOfCustomFolder\\file.exe";
Rather do
szOutput = std::string{path_buf} + "NameOfCustomFolder\\file.exe";
If you can use C++17, I would suggest std::filesystem::path::append
It will take care of the path separators, and will make it easy to go cross-platform.

How to set HTML Unicode text to clipboard in VC++?

I am a newbie to C++. I want to get the content of the clipboard, which might contain Unicode chars, append a div tag with some content formatted in HTML and set that back to clipboard.
I have achieved successfully in getting the content and appending it. But could not set it back to the clipboard as an HTML text. I have achieved setting as simple text. Here is my code:
#include <shlwapi.h>
#include <iostream>
#include <conio.h>
#include <stdio.h>
using namespace std;
wstring getClipboard(){
if (OpenClipboard(NULL)){
HANDLE clip = GetClipboardData(CF_UNICODETEXT);
WCHAR * c;
c = (WCHAR *)clip;
CloseClipboard();
return (WCHAR *)clip;
}
return L"";
}
bool setClipboard(wstring textToclipboard)
{
if (OpenClipboard(NULL)){
EmptyClipboard();
HGLOBAL hClipboardData;
size_t size = (textToclipboard.length()+1) * sizeof(WCHAR);
hClipboardData = GlobalAlloc(NULL, size);
WCHAR* pchData = (WCHAR*)GlobalLock(hClipboardData);
memcpy(pchData, textToclipboard.c_str(), size);
SetClipboardData(CF_UNICODETEXT, hClipboardData);
GlobalUnlock(hClipboardData);
CloseClipboard();
return true;
}
return false;
}
int main (int argc, char * argv[])
{
wstring s = getClipboard();
s += std::wstring(L"some extra text <b>hello</b>");
setClipboard(s);
getch();
return 0;
}
I did try using the code described here and read the doc here. But I couldn't make it work. What I tried could be way off track or completely wrong.
Update: The code below is what I tried after the modifications suggested by Cody Gray to the original code presented here:
bool CopyHTML2(WCHAR *html ){
wchar_t *buf = new wchar_t [400 + wcslen(html)];
if(!buf) return false;
static int cfid = 0;
if(!cfid) cfid = RegisterClipboardFormat("HTML Format");
// Create a template string for the HTML header...
wcscpy(buf,
L"Version:0.9\r\n"
L"StartHTML:00000000\r\n"
L"EndHTML:00000000\r\n"
L"StartFragment:00000000\r\n"
L"EndFragment:00000000\r\n"
L"<html><body>\r\n"
L"<!--StartFragment -->\r\n");
// Append the HTML...
wcscat(buf, html);
wcscat(buf, L"\r\n");
// Finish up the HTML format...
wcscat(buf,
L"<!--EndFragment-->\r\n"
L"</body>\r\n"
L"</html>");
wchar_t *ptr = wcsstr(buf, L"StartHTML");
wsprintfW(ptr+10, L"%08u", wcsstr(buf, L"<html>") - buf);
*(ptr+10+8) = L'\r';
ptr = wcsstr(buf, L"EndHTML");
wsprintfW(ptr+8, L"%08u", wcslen(buf));
*(ptr+8+8) = '\r';
ptr = wcsstr(buf, L"StartFragment");
wsprintfW(ptr+14, L"%08u", wcsstr(buf, L"<!--StartFrag") - buf);
*(ptr+14+8) = '\r';
ptr = wcsstr(buf, L"EndFragment");
wsprintfW(ptr+12, L"%08u", wcsstr(buf, L"<!--EndFrag") - buf);
*(ptr+12+8) = '\r';
// Open the clipboard...
if(OpenClipboard(0)) {
EmptyClipboard();
HGLOBAL hText = GlobalAlloc(GMEM_MOVEABLE |GMEM_DDESHARE, wcslen(buf)+4);
wchar_t *ptr = (wchar_t *)GlobalLock(hText);
wcscpy(ptr, buf);
GlobalUnlock(hText);
SetClipboardData(cfid, hText);
CloseClipboard();
GlobalFree(hText);
}
// Clean up...
delete [] buf;
return true;
}
This code compiles successfully, But I get the following error at SetClipboardData : HEAP[Project1.exe]: Heap block at 007A8530 modified at 007A860A past requested size of d2
Project1.exe has triggered a breakpoint.
Please guide me on how to proceed. I am using Visual Studio Express 2012 on Windows 8. Thanks.
You're mismatching ANSI (narrow) and Unicode (wide) strings.
Unlike the wcscpy function, the w in the wsprintf function doesn't stand for "wide", it stands for "Windows". It is part of the Win32 API, rather than the C runtime library. All of the Win32 API functions that work with strings have two versions, one suffixed with an A that deals with ANSI strings and another suffixed with a W that deals with wide strings. The headers hide all of this from you with macros. I explain all of this in more detail here—recommended reading.
Anyway, the simple fix here is to explicitly call the wide variant of that function, since you're correctly using wide strings everywhere else. Make all the calls to wsprintf look like this:
wchar_t *ptr = wcsstr(buf, L"StartHTML");
wsprintfW(ptr+10, L"%08u", wcsstr(buf, L"<html>") - buf);
*(ptr+10+8) = L'\r';
Alternatively, you could use the swprintf function provided by the C runtime library instead of the Win32 version. This one works just like the wcsstr and wcscpy functions you're using elsewhere. The w in the name means "wide". The documentation for this series of functions is here.
Note also that when you use character or string literals, they also need to be wide characters. You accomplish that by prepending them with an L. You do that some places, but miss doing it others. Make sure that you do it consistently.
The compiler should warn you about all this, though. You just need to make sure you turn your warning level up and don't ignore any of the warnings. Also make sure that both the UNICODE and _UNICODE preprocessor symbols are defined globally for your project. That will ensure that you are always calling the Unicode/wide versions of functions. Although that should be the default for all new projects.
This is the function I came up with the help of Jochen Arndt at codeproject.com. Hope this helps somebody. Here is a complete working code, if you are interested in checking this out.
It still has one problem. That is when pasted to onenote alone, it pastes gibberish after a anchor tag. It does not happen with Word, PowerPoint or Excel. And it does not have this problem for normal English language texts. If you have a solution for this, please do let me know. The problem seems to be with OneNote. Not with the code.
bool setClipboard(LPCWSTR lpszWide){
int nUtf8Size = ::WideCharToMultiByte(CP_UTF8, 0, lpszWide, -1, NULL, 0, NULL, NULL);
if (nUtf8Size < 1) return false;
const int nDescLen = 105;
HGLOBAL hGlobal = ::GlobalAlloc(GMEM_MOVEABLE, nDescLen + nUtf8Size);
if (NULL != hGlobal)
{
bool bErr = false;
LPSTR lpszBuf = static_cast<LPSTR>(::GlobalLock(hGlobal));
LPSTR lpszUtf8 = lpszBuf + nDescLen;
if (::WideCharToMultiByte(CP_UTF8, 0, lpszWide, -1, lpszUtf8, nUtf8Size, NULL, NULL) <= 0)
{
bErr = true;
}
else
{
LPCSTR lpszStartFrag = strstr(lpszUtf8, "<!--StartFragment-->");
LPCSTR lpszEndFrag = strstr(lpszUtf8, "<!--EndFragment-->");
lpszStartFrag += strlen("<!--StartFragment-->") + 2;
int i = _snprintf(
lpszBuf, nDescLen,
"Version:1.0\r\nStartHTML:%010d\r\nEndHTML:%010d\r\nStartFragment:%010d\r\nEndFragment:%010d\r\n",
nDescLen,
nDescLen + nUtf8Size - 1, // offset to next char behind string
nDescLen + static_cast<int>(lpszStartFrag - lpszUtf8),
nDescLen + static_cast<int>(lpszEndFrag - lpszUtf8));
}
::GlobalUnlock(hGlobal);
if (bErr)
{
::GlobalFree(hGlobal);
hGlobal = NULL;
}
// Get clipboard id for HTML format...
static int cfid = 0;
cfid = RegisterClipboardFormat("HTML Format");
// Open the clipboard...
if(OpenClipboard(0)) {
EmptyClipboard();
HGLOBAL hText = GlobalAlloc(GMEM_MOVEABLE |GMEM_DDESHARE, strlen(lpszBuf)+4);
char *ptr = (char *)GlobalLock(hText);
strcpy(ptr, lpszBuf);
GlobalUnlock(hText);
::SetClipboardData(cfid, hText);
CloseClipboard();
GlobalFree(hText);
}
}
return NULL != hGlobal;
}
Your problem comes from the use of wchar_t instead of char in the cited example which makes you wrong on the offset computations.
I would however recommend you avoiding the use of wchar_t for transfering UNICODE text to the clipboard. Indeed, UTF-8 char could coded with a sequence of bytes comprised between 1 and 4 bytes, while wchar_t on Windows is a fixed 2 bytes type.
As explained in the Microsoft doc refered in your email, the content of the clipboard shall be UNICODE, which happens to be the same as ASCII for the characters contained in the header of the clipboard memory.
To transfert UNICODE in the clipboard, you can do it using the standard char C++ functions to prepare the content sent to clipboard (std::string for eg.)
While the cited example works, please find here another code sample using C++ framework that can actually copy UTF-8 chars to the clipboard in HTML format:
void copyHTMLtoClipboard(const std::string& html) {
std::string contextStart("Version:0.9\r\nStartHTML:0000000000\r\nEndHTML:0000000000\r\nStartFragment:0000000000\r\nEndFragment:0000000000\r\n<html><body>\r\n<!--StartFragment -->\r\n");
std::string contextEnd("\r\n<!--EndFragment -->\r\n</body></html>");
std::stringstream aux;
aux << contextStart << html << contextEnd;
std::string res = aux.str();
size_t htmlStart = 105 * sizeof(char);
size_t fragmentStart = 119 * sizeof(char);
size_t htmlEnd = res.size() * sizeof(char);
size_t fragmentEnd = htmlEnd - 35 * sizeof(char);
aux.fill('0');
aux.width(10);
aux.seekp(23);
aux << htmlStart;
aux.seekp(43);
aux.fill('0');
aux.width(10);
aux << htmlEnd;
aux.seekp(69);
aux.fill('0');
aux.width(10);
aux << fragmentStart;
aux.seekp(93);
aux.fill('0');
aux.width(10);
aux << fragmentEnd;
res = aux.str();
HGLOBAL hdst = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, htmlEnd + sizeof(char));
LPSTR dst = (LPSTR)GlobalLock(hdst);
memcpy(dst, res.c_str(), htmlEnd);
dst[htmlEnd] = 0;
GlobalUnlock(hdst);
OpenClipboard(NULL);
EmptyClipboard();
SetClipboardData(RegisterClipboardFormat(L"HTML Format"), hdst);
CloseClipboard();
GlobalFree(hdst);
}
Note that this code was compiled defining the macros _UNICODE and UNICODE.

How to Obtain the MSI 'UILevel' Property From a C++ Custom Action

I am trying to get at the 'UILevel' MSI property from within a C++ custom action in order to determine whether or not the user is running in 'no UI mode', but am not having much luck. The function I am calling is passed the MSIHANDLE from a function which I export in my DLL (which may be either a 'deferred' or 'firstsequence' action). What I'm seeing is that MsiGetPropertyW is always returning ERROR_MORE_DATA and the trueLength field is always 0. Here is my code:
bool runningInNoUIMode(MSIHANDLE hInstall)
{
unsigned long nBufLen = 64UL;
WCHAR *wszValue = new WCHAR[nBufLen];
DWORD trueLength = 0UL;
UINT result = ::MsiGetPropertyW(hInstall, L"UILevel", L"", &trueLength); // Get the size of the property value first to see if there is enough storage allocated.
if (ERROR_MORE_DATA == result || nBufLen <= trueLength)
{
if (NULL != wszValue)
{
delete [] wszValue;
}
// Allocate more memory for the property adding one for the null terminator.
nBufLen = trueLength + 1;
wszValue = new WCHAR[nBufLen];
}
if (NULL == wszValue)
{
WcaLog(LOGMSG_STANDARD, "Unable to determine the user interface level the MSI is being run with because we were unable to allocate storage for accessing the 'UILevel' property.");
return false;
}
memset(wszValue, L'\0', nBufLen * sizeof(WCHAR));
result = ::MsiGetPropertyW(hInstall, L"UILevel", wszValue, &trueLength);
if (ERROR_SUCCESS != result)
{
WcaLog(LOGMSG_STANDARD, "Unable to determine the user interface level the MSI is being run with, error code = '%lu'.", result);
delete [] wszValue;
return false;
}
if (0 == wcscmp(L"2", wszValue)) // INSTALLUILEVEL_NONE == 2
{
delete [] wszValue;
return true;
}
delete [] wszValue;
return false;
}
I believe I can work around this for now by passing the 'UILevel' property through WiX and checking for it that way in the C++, but I am curious what the problem here is as well.
I'm using Visual Studio/Visual C++ 2010 on Windows 7 with WiX 3.5.2519.
Thanks for any assistance you can provide!
Another way of making this simpler is to use the MsiEvaluateCondition function.
BOOL bUI = MsiEvaluateCondition(L"UILevel<3");
in C# using Microsoft.Deployment.WindowsIntaller (DTF) it's:
var uiLevel = session["UILevel"];
In C++ there's a sample at MsiGetProperty function:
UINT __stdcall MyCustomAction(MSIHANDLE hInstall)
{
TCHAR* szValueBuf = NULL;
DWORD cchValueBuf = 0;
UINT uiStat = MsiGetProperty(hInstall, TEXT("MyProperty"), TEXT(""), &cchValueBuf);
//cchValueBuf now contains the size of the property's string, without null termination
if (ERROR_MORE_DATA == uiStat)
{
++cchValueBuf; // add 1 for null termination
szValueBuf = new TCHAR[cchValueBuf];
if (szValueBuf)
{
uiStat = MsiGetProperty(hInstall, TEXT("MyProperty"), szValueBuf, &cchValueBuf);
}
}
if (ERROR_SUCCESS != uiStat)
{
if (szValueBuf != NULL)
delete[] szValueBuf;
return ERROR_INSTALL_FAILURE;
}
// custom action uses MyProperty
// ...
delete[] szValueBuf;
return ERROR_SUCCESS;
}
Thanks to #DanielGehriger, we figured out that the problem isn't with the code, but with the scheduling for the custom action. The UILevel MSI property is simply not available when running a deferred custom action (I found that the code worked correctly for a custom action scheduled for firstsequence). I have worked around this limitation by explicitly passing it on custom action data using WiX:
<CustomAction Id="CustomAction.SetProperty" Property="CustomActionCall"
Value="UILEVEL=[UILevel];" />
and then checking for this in the C++ with WcaIsPropertySet and WcaGetProperty. Note that the character case of the property name between square brackets matters here.

string parser text adventure

Hello! I am currently working on a text adventure in C++ and could use some help.
What I'm trying to do is let the user input a command like the following:
'go kitchen'
'open door with key'
and make the game react accordingly.
Our teacher gave us the following code (which I have modified) and I'm having difficulty understanding what exactly it is doing and how I can use it to make the game. I modified it so that the user can input strings and it does tokenize the string wonderfully into a verb, object, preposition and object2.
But what I need to do then is somehow compare the input to a list of available commands. This is what I'm having trouble accomplishing at the moment. I am new to programming and need to do this as a homework assignment for my studies. Any help would be much appreciated.
struct command {
char* verb;
char* object;
char* preposition;
char* object2;
};
bool getTokens(char * acInput,
const char token_delimiter,
command * pTargetCommand)
{
char * pCurToken;
pCurToken = strtok (acInput, &token_delimiter);
if (pCurToken == NULL) {
printf("Error: Found no verb");
getchar();
return 1;
}
pTargetCommand->verb = pCurToken;
pCurToken = strtok (NULL, &token_delimiter);
if (pCurToken == NULL) {
printf("Error: Found no object");
getchar();
return 1;
}
pTargetCommand->object = pCurToken;
pCurToken = strtok (NULL, &token_delimiter);
if (pCurToken != NULL) {
pTargetCommand->preposition = pCurToken;
pCurToken = strtok (NULL, &token_delimiter);
if (pCurToken == NULL) {
printf("Error: Found no second object for preposition");
getchar();
return 1;
}
pTargetCommand->object2 = pCurToken;
}
pCurToken = strtok (NULL, &token_delimiter);
if (pCurToken != NULL) {
printf("Error: too many tokens.");
getchar();
return 1;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
char acInput[256];
cin.getline (acInput,256);
command myCommand = { NULL };
int RoomChoice = 0;
printf ("Splitting string \"%s\" into tokens:\n", acInput);
getTokens(acInput, *TOKEN_DELIMITER, &myCommand);
printf ("Verb: %s\n", myCommand.verb);
printf ("object: %s\n", myCommand.object);
printf ("preposition: %s\n", myCommand.preposition);
printf ("object2: %s\n", myCommand.object2);
getchar();
return 0;
}
Without giving too much of your homework assignment away, you'll need to somehow read the list of all available actions into a structure, then compare against that structure.
As a hint, depending on the pattern, that might be a switch() {} statement or a collection like an array.
Consider
switch (myCommand.verb)
Case "go":
In a real-world application, you'd spin up a factory of command objects, then invoke one of those. Here, however, I would suggesting thinking through your control statements.
You cannot do a switch with strings (as you already noted, switch only work with constant numbers)
To do compare strings you can use strcmp, strncmp, or better yet, use String.compare. You should be able to find enough information about them with a Google search.

c++ loop through registry recursively is slow

Have an annoying problem with my code, probably I am doing something wrong because my Python
implementation is much faster!
C++ implementation problems:
Iterating over "HKEY_CLASSES_ROOT" takes a lot of ram, I assume it's because c++ implementation uses lots of variables. Fixed
It's also slow, much slower than python implantation of the code Fixed
The code even slower when trying to iterate over HKEY_CLASSES_ROOT Fixed
New Questions:
Thanks to Nam Nguyen i understood what causing the leaks in my code, and directly effecting execution time, the code below is the fixed one. how come c++ implementation runs as fast as my python implementation?
C++ implementation:
#include <iostream>
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <string>
using namespace std;
#define MAX_KEY_LENGTH 255
int RecurseOpenRegEx(HKEY hkey, string subKey = "",string search = "nothing", DWORD sum = 0)
{
TCHAR csubKey[MAX_KEY_LENGTH];
DWORD nSubKeys = 0;
DWORD pathLength = MAX_PATH;
TCHAR storeKeyName[MAX_KEY_LENGTH];
DWORD keyLength;
HKEY hKey = hkey; //somehow i need to reassign HKEY, otherwise it won't pass it with the function, this is bigger than me tough...
const char * ccsearch = search.c_str();
const char * ccsubKey;
if (subKey != "")
{
ccsubKey = subKey.c_str();
copy(subKey.begin(), subKey.end(),csubKey); //convert string to TCHAR
}
if (RegOpenKeyEx(hkey, ccsubKey, 0, KEY_READ, &hkey) == ERROR_SUCCESS)
{
if (RegQueryInfoKey(hkey, csubKey, &pathLength, NULL,&nSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
{
sum += nSubKeys;
for (DWORD subKeyIndex = 0; subKeyIndex < nSubKeys; subKeyIndex++)
{
keyLength = MAX_KEY_LENGTH;
if (RegEnumKeyEx(hkey, subKeyIndex, storeKeyName, &keyLength, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
{
string sKeyName = storeKeyName; //Convert TCHAR to string explicitly
if (subKey != "")
{
sKeyName = subKey + "\\" + sKeyName;
}
sum += RecurseOpenRegEx(hKey, sKeyName);
}
}
}
}
RegCloseKey(hkey); //Now closing the right key
return sum;
}
int main()
{
cout << "sum of all keys: " << RecurseOpenRegEx(HKEY_LOCAL_MACHINE);
return 0;
}
Python implementation:
import winreg
def recurseRegistrySearch(key, keySearch = "",subkey = "", subkeypath = "", x = 0):
key = winreg.OpenKey(key, subkey, 0)
y = winreg.QueryInfoKey(key)[0]
x += y
for items in range(x):
try:
subkey = winreg.EnumKey(key, items)
if ((keySearch.lower() in subkey.lower()) and (keySearch != "")):
print(subkeypath + "\\" + subkey)
x += recurseRegistrySearch(key, keySearch, subkey, subkeypath = subkeypath + "\\" + subkey)
except WindowsError:
pass
return x
print("sum of all keys: {0}".format(recurseRegistrySearch(winreg.HKEY_CLASSES_ROOT)))
There is leak of resource in your code. You open hkey but you close hKey (note the difference in case of k and K).
On a side note, you store the opened registry key into hkey itself. And it happens that hkey is the passed in parameter, shared among all calls to RecurseOpenRegEx. That is why "somehow i need to reassign HKEY".
Basically, what I can advise you now is immediately clean up your code. Bugs like these are hard to spot when your code is a too difficult to read. Once done, I believe you will find it easier to debug/trace.
Probably it's your heavy use of string variables ,which involves a lot of dynamic memory allocations.
Try accepting parameters as LPCTSTR .assign string variables inside the function with those LPCTSTRs and pass parameters with str.c_str().