c++ - Why does RegSetValueEx work even when I break the rule about accounting for NUL termination in the length? -


i've got simple program adds calc.exe startup:

#include <windows.h> #include <tchar.h>  int main(){     _tprintf(text("adding calc.exe software\\microsoft\\windows\\currentversion\\run...\n"));      hkey hregrunkey;     lpctstr lpkeyname = text("software\\microsoft\\windows\\currentversion\\run");     lpctstr lpkeyvalue = text("calculator");      lpctstr lpprogram = text("c:\\windows\\system32\\calc.exe");     dword cchprogram = _tcslen(lpprogram);      _tprintf(text("path: %s. \n"), lpprogram);     _tprintf(text("length: %d. \n"), cchprogram);      if(regopenkeyex( hkey_local_machine, lpkeyname, 0, key_set_value, &hregrunkey) == error_success){         if(regsetvalueex(hregrunkey, lpkeyvalue, 0, reg_sz, (const byte *)lpprogram, cchprogram * sizeof(tchar)) != error_success){             _tprintf(text("error: can't set key value.\n"));             exit(1);         }else{             _tprintf(text("key has been added sucessfully.\n"));         }     }      sleep(5000);     regclosekey(hregrunkey); } 

for me world of c/c++/win32api still full of misteries... have few questions.

1. when define string automatically null terminated?

lpctstr lpprogram = text("c:\\windows\\system32\\calc.exe"); 

or should done:

lpctstr lpprogram = text("c:\\windows\\system32\\calc.exe\0"); 

2. in code final argument regsetvalueex set correct value?

from msdn - regsetvalueex function page:

cbdata [in] size of information pointed lpdata parameter, in bytes. if data of type reg_sz, reg_expand_sz, or reg_multi_sz, cbdata must include size of terminating null character or characters.

cchprogram set 28 characters without null termination. on system(because of unicode think?) cchprogram * sizeof(tchar) = 56.

shouldn't set 58 add null termination?


when run program, above, without modifications , i'll check calculator value in registry via modify binary date get:

43 00 3a 00 5c 00 57 00 c.:.\.w. 49 00 4e 00 44 00 4f 00 i.n.d.o. 57 00 53 00 5c 00 73 00 w.s.\.s. 79 00 73 00 74 00 65 00 y.s.t.e. 6d 00 33 00 32 00 5c 00 m.3.2.\. 63 00 61 00 6c 00 63 00 c.a.l.c. 2e 00 65 00 78 00 65 00 ..e.x.e. 00 00                   .. 

its 58 bytes including null termination. i'am confuse:/

update

accounting null character adding 1 string length when calculating cbdata yields same result without adding it.

cchprogram * sizeof(tchar) produces same data entry (cchprogram + 1) * sizeof(tchar)

providing value smaller string length doesn't add null byte , copies given number of bytes.

27 * sizeof(tchar) cbdata produces:

43 00 3a 00 5c 00 57 00 c.:.\.w. 49 00 4e 00 44 00 4f 00 i.n.d.o. 57 00 53 00 5c 00 73 00 w.s.\.s. 79 00 73 00 74 00 65 00 y.s.t.e. 6d 00 33 00 32 00 5c 00 m.3.2.\. 63 00 61 00 6c 00 63 00 c.a.l.c. 2e 00 65 00 78 00       ..e.x. 

i on old xp, service pack god knows what, don't know how other version of windows handle it.

when define string automatically null terminated?

string literals null-terminated, yes. "hello" {'h', 'e', 'l', 'l', 'o', '\0'}.

in code final argument regsetvalueex set correct value?

you're right need null terminator. easier way sizeof(text("c:\\windows\\system32\\calc.exe")) if string literal short, since sizeof("hello") 6; includes null-terminator, in cases, you'll need variable , have add 1 length string character-counting functions, since don't include null-terminator.

ben voigt made excellent point below const tchar[] program = text("text"); can used same way literal in call (sizeof(program)), lot more maintainable when want change 1 less place in code, must actual project instead of small test, , can grow.

finally, there 2 things should out of head early:

  1. hungarian notation: don't it. it's outdated , rather pointless.

  2. tchar: use wide strings windows api functions can.

what you're doing absolutely right checking function calls errors. wouldn't believe how many problems asked can solved checking failure , using getlasterror when documentation says to.


since asked how you're supposed use c++ facilities, here's 1 way, couple changes make more sense using c++:

#include <windows.h>  int main(){     //r means raw string literal. note 1 backslash     std::cout << r"(adding calc.exe software\microsoft\windows\currentversion\run...)" << '\n';      const wchar[] keyname = lr"(software\microsoft\windows\currentversion\run)");      std::cout << "enter program name: ";     std::wstring keyvalue;             if (!std::getline(std::wcin, keyvalue)) {/*error*/}      std::cout << "enter full program path: ";     std::wstring program;     if (!std::getline(std::wcin, program)) {/*error*/}      std::wcout << "path: " << program << ".\n";     std::cout << "length: " << program.size() << ".\n";      hkey runkey;     if(regopenkeyexw(hkey_local_machine, keyname, 0, key_set_value, &runkey)) {/*error*/}      if(regsetvalueexw(runkey, keyvalue.c_str(), 0, reg_sz, reinterpret_cast<const byte *>(program.c_str()), (program.size() + 1) * 2)) {         std::cout << "error: can't set key value.\n";         return 1;     }      if (regclosekey(runkey)) {/*error*/}      std::cout << "key has been added successfully.\n";      std::cout << "press enter continue..."         std::cin.get(); } 

a better way using c++ idioms @ least have regkey raii class calls regclosekey in destructor , saves work. @ least, used this:

regkey key(hkey_local_machine, keyname, key_set_value); regsetvalueexw(key, ...); //could have implicit or explicit conversion, fill in ... //regclosekey called when key goes out of scope 

Comments

Popular posts from this blog

c# - DetailsView in ASP.Net - How to add another column on the side/add a control in each row? -

javascript - firefox memory leak -

Trying to import CSV file to a SQL Server database using asp.net and c# - can't find what I'm missing -