Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Creating and setting registry key value

138 views
Skip to first unread message

Peter

unread,
May 25, 2004, 3:38:47 PM5/25/04
to
Hi,

I want to associate my mfc program with an icon yet I am having trouble
editing the registry to do it. I tried using:

EnableShellOpen();
RegisterShellFileTypes();

in the InitInstance function but it caused an error. I did not create this
program with a wizard so the above raises an error for some reason, that's
why I want to edit the registry directly. The code I have so far does not
work for Entry 2, I cannot get the full path for the application into the
registry or any data at all - I would also like to get the executable's
name but I do not know how to get it.

Entry 1's code is ok and I have included it for completeness. Is this code
correct for setting icon information in the registry?

I have placed this code in my main frame's OnCreate event.

//Entry 1
//HKEY_CLASSES_ROOT\.my
//(standard) "myfile"

//set up file types manually
HKEY hKey;
RegCreateKeyEx(HKEY_CLASSES_ROOT, TEXT(".xyz"), 0,
NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
NULL, &hKey, NULL);

TCHAR lpStr[100];
lstrcpy(lpStr, TEXT("H.Prog"));
RegSetValueEx(hKey, "", 0, REG_SZ,
(unsigned char *) lpStr, (unsigned long) sizeof(lpStr));

RegCloseKey(hKey);

//Entry 2
//HKEY_CLASSES_ROOT\myfile
//HKEY_CLASSES_ROOT\myfile\DefaultIcon
//(standard) "c:\path\app.exe,<index>"

HKEY hKey2;
RegCreateKeyEx(HKEY_CLASSES_ROOT, TEXT("H.Prog\\DefaultIcon"), 0,
NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
NULL, &hKey2, NULL);

string pathstr = AppPath(); //how do you get the name of the exe too?
pathstr += ",";
pathstr += "1";
int bytecount = lstrlen(pathstr.c_str());

//not working, no data in reg
long code = RegSetValueEx(hKey2, "", 0, REG_SZ,
reinterpret_cast<const unsigned char*>(pathstr.c_str()), bytecount);

RegCloseKey(hKey2);

ASSERT(code == ERROR_SUCCESS);


Thanks.
Peter.

Vikas Mishra

unread,
May 26, 2004, 3:41:05 AM5/26/04
to

Hi,

You can use GetModuleFilename function to get full application path.

CWinApp::RegisterShellFileTypes function will work, if you have used CDocTemplate and AddDocTemplate to create
you application.

You can refer MSDN.

void RegisterShellFileTypes( BOOL bCompat = FALSE );

Parameters

bCompat

TRUE adds registration entries for shell commands Print and Print To, allowing a user to print files directly from the shell, or by dragging the file to a printer object. It also adds a DefaultIcon key. By default, this parameter is FALSE for backward compatibility.

Remarks

Call this member function to register all of your application’s document types with the Windows File Manager. This allows the user to open a data file created by your application by double-clicking it from within File Manager. Call RegisterShellFileTypes after you call AddDocTemplate for each of the document templates in your application. Also call the EnableShellOpen member function when you call RegisterShellFileTypes.

RegisterShellFileTypes iterates through the list of CDocTemplate objects that the application maintains and, for each document template, adds entries to the registration database that Windows maintains for file associations. File Manager uses these entries to open a data file when the user double-clicks it. This eliminates the need to ship a .REG file with your application.

If the registration database already associates a given filename extension with another file type, no new association is created. See the CDocTemplate class for the format of strings necessary to register this information.


Regards,
Vikas Mishra

----- Peter wrote: -----

Joseph M. Newcomer

unread,
May 26, 2004, 10:51:15 AM5/26/04
to
If you don't create a program with a wizard, you are saying "I LOVE being miserable, and
hitting obscure bugs I don't understand, and generally I LOVE wasting time trying to find
out what I screwed up".

Bottom line: I won't help debug code that is not written by a wizard. I suggest you start
using the tools, and stop playing macho programmer. There is no reason to not use the
tools. And, in spite of the childish myths out there, it is the POOREST way to learn how
to use MFC, because it requires that you concentrate on irrelevant details before you are
ready for them, instead of concentrating on more important issues such as how to use MFC
properly.

But since the numerous errors in this code are unrelated to use or non-use of the wizard,
I'll suggest how to rewrite it so it is correct.

There are significant poor style usages in the code below. For example, why are you
creating a TCHAR of a fixed size, then COPYING a literal string to it, and WHY are you
using "sizeof", which is insane? You could have used a pointer if a literal string were
involved, so why do the copy?

LPCTSTR str = _T("H.prog");

would have made more sense. Copying to fixed-size buffers is poor style, and should only
be done under very restricted conditions, and this is not one of them.

Alternatively, you could have done

#define HPROG _T("H.prog")

and done
RegSetValueEx(hkey, _T(""), 0, REG_SZ, (LPCBYTE)HPROG, lstrlen(HPROG)*sizeof(TCHAR));

and avoided any assignment entirely! But if you need a variable, CString is a better
choice than TCHAR or std::string for this purpose:

CString str(_T("H.prog"));
RegSetValueEx(hkey, _T(""), 0, REG_SZ, (LPCBYTE)(LPCTSTR)str, (DWORD)str.GetLength()*
sizeof(TCHAR));

works well, has the advantage that the second parameter is Unicode-aware (Why you would
use TEXT (a synonym for _T) for one string but not for another escapes me), there is no
need for a fixed-size buffer; why, when the last parameter is specified as DWORD would you
cast it as "unsigned long" escapes me [what makes you think DWORD is "unsigned long"? And
why do you think, if this is correct, that it is the right way to write the code?]? Note
that sizeof() is a compile-time operator that gives you the total size of the buffer in
bytes, and not the length of the string in it. This will cause your program to write more
bytes than are present, including whatever garbage is on the stack. In your second
example, using string, you also neglect to convert from string length to byte length
(Unicode bytes are twice the character count).
joe

****
TCHAR path[MAX_PATH]; // one of the few places you would allocate a fixed buffer
GetModuleFileName(NULL, path, MAX_PATH); // not sure about parameter order, check
CString pathstr = path;
****
>pathstr += ",";
****
_T(",")
****
>pathstr += "1";
****
_T("1")
****
>int bytecount = lstrlen(pathstr.c_str());
****
you forgot "*sizeof(TCHAR)" in the computation of the byte count. If you use CString, and
TEXT or _T, you need to account for Unicode issues everywhere. I don't know if 'string' is
Unicode-aware or not, but if it isn't, it would be an exceedingly poor choice of type. If
it is, you need to account for the byte conversion.

Also, why did you use std::string here and a fixed buffer in the other case, and why not
use CString? It would have been easier; you don't need the c_str() operator at all, you
could have written
(LPCBYTE)(LPCTSTR)pathstr
for the pointer to the string.
****


>
>//not working, no data in reg
>long code = RegSetValueEx(hKey2, "", 0, REG_SZ,
> reinterpret_cast<const unsigned char*>(pathstr.c_str()), bytecount);

*****
Why something long and clumsy like
reinterpret_cast<const unsigned char *>
when it would make more sense to write
reinterpret_cast(LPCBYTE)
or the even shorter
(LPCBYTE)
do you have religious opposition to using the Windows types, or do you just like to write
error-prone code? Those types are defined for a reason, and it is poor style to ignore
them.
****


>
>RegCloseKey(hKey2);
>
>ASSERT(code == ERROR_SUCCESS);
>
>
>Thanks.
>Peter.

Joseph M. Newcomer [MVP]
email: newc...@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm

Peter

unread,
May 26, 2004, 7:00:44 PM5/26/04
to
On Wed, 26 May 2004 10:51:15 -0400, Joseph M. Newcomer wrote:

> If you don't create a program with a wizard, you are saying "I LOVE being miserable, and
> hitting obscure bugs I don't understand, and generally I LOVE wasting time trying to find
> out what I screwed up".

No, if you can deflate your ego for a moment it suggests I am a beginner at
mfc and took my lead from the only book I could afford in order to learn it
- the cheap one written by deitel and deitel. Secondly, the book was
psychologically appealing because of my previous experience learning Java
and me being used to/preferring to create Java user interfaces in code. As
I have now discovered the mfc is not nearly so user friendly as the JDK. I
will know this for my next project, but it is far too late to change this
one - sorry for offending you...

>
> Bottom line: I won't help debug code that is not written by a wizard. I suggest you start
> using the tools, and stop playing macho programmer. There is no reason to not use the
> tools. And, in spite of the childish myths out there, it is the POOREST way to learn how
> to use MFC, because it requires that you concentrate on irrelevant details before you are
> ready for them, instead of concentrating on more important issues such as how to use MFC
> properly.

I agree, good point, but this is the first time I ever used mfc as I said,
we all make mistakes.

>
> But since the numerous errors in this code are unrelated to use or non-use of the wizard,
> I'll suggest how to rewrite it so it is correct.
>
> There are significant poor style usages in the code below. For example, why are you
> creating a TCHAR of a fixed size, then COPYING a literal string to it, and WHY are you
> using "sizeof", which is insane? You could have used a pointer if a literal string were
> involved, so why do the copy?

It wasn't me who did it, but someone who posted to another forum explaining
with code how to access the registry. I whipped it off and modified it to
try and make it work. I do not even know what _T("H.prog") means exactly.
Is it a macro? I do not understand macros because I have never needed to.

>
> LPCTSTR str = _T("H.prog");
>
> would have made more sense. Copying to fixed-size buffers is poor style, and should only
> be done under very restricted conditions, and this is not one of them.
>
> Alternatively, you could have done
>
> #define HPROG _T("H.prog")
>
> and done
> RegSetValueEx(hkey, _T(""), 0, REG_SZ, (LPCBYTE)HPROG, lstrlen(HPROG)*sizeof(TCHAR));

ok, but I thought using c-style casts in c++ was poor style. I understand
what was explained on here, but I've changed it all to c casts:
http://www.coding-zone.co.uk/cpp/articles/050101casting.shtml

>
> and avoided any assignment entirely! But if you need a variable, CString is a better
> choice than TCHAR or std::string for this purpose:
>
> CString str(_T("H.prog"));
> RegSetValueEx(hkey, _T(""), 0, REG_SZ, (LPCBYTE)(LPCTSTR)str, (DWORD)str.GetLength()*
> sizeof(TCHAR));

Thanks for the tip, but now I have a problem. How do you convert an stl
string to a CString? Only thing I seem to be able to do is rebuild the
string char by char using CString +=

>
> works well, has the advantage that the second parameter is Unicode-aware (Why you would
> use TEXT (a synonym for _T) for one string but not for another escapes me), there is no
> need for a fixed-size buffer; why, when the last parameter is specified as DWORD would you
> cast it as "unsigned long" escapes me [what makes you think DWORD is "unsigned long"?

I'd have to ask the person who wrote it, but I should have checked the
docs.

>And
> why do you think, if this is correct, that it is the right way to write the code?]? Note
> that sizeof() is a compile-time operator that gives you the total size of the buffer in
> bytes, and not the length of the string in it. This will cause your program to write more
> bytes than are present, including whatever garbage is on the stack. In your second
> example, using string, you also neglect to convert from string length to byte length
> (Unicode bytes are twice the character count).
> joe

I got the code working before seeing this but I am taking your points on
board, as I don't want it to crash out later. What i ended up with did not
get garbage though.

I will place the updated code at the end of this and you can flame me
again, as I do not want errors, I am glad for any comments.

That would not compile had to change to this

(CONST BYTE *) (LPCTSTR)pathstr

>>
>>//not working, no data in reg
>>long code = RegSetValueEx(hKey2, "", 0, REG_SZ,
>> reinterpret_cast<const unsigned char*>(pathstr.c_str()), bytecount);
> *****
> Why something long and clumsy like
> reinterpret_cast<const unsigned char *>
> when it would make more sense to write
> reinterpret_cast(LPCBYTE)
> or the even shorter
> (LPCBYTE)
> do you have religious opposition to using the Windows types, or do you just like to write
> error-prone code? Those types are defined for a reason, and it is poor style to ignore
> them.
> ****

No, just following some advice about casts, see above. Why the hostility?

You go on about style without giving a reason why. You might well be
right, but you never told me why. Style can be as subjective as to where
to place the curly braces...

HKEY hKey;
RegCreateKeyEx(HKEY_CLASSES_ROOT, TEXT(".xyz"), 0,
NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
NULL, &hKey, NULL);

CString str = _T("H.Prog");
RegSetValueEx(hKey, _T(""), 0, REG_SZ, (CONST BYTE *) (LPCTSTR) str,
(DWORD) (str.GetLength() + 1) * sizeof(TCHAR));

RegCloseKey(hKey);

HKEY hKey2;
long code = RegCreateKeyEx(HKEY_CLASSES_ROOT,
_T("H.Prog\\DefaultIcon"), 0,


NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey2, NULL);

string pathstr = FullAppPath();
CString cstr;
for(int i = 0; i < pathstr.length(); i++)
cstr += pathstr[i];
cstr += _T(",1");
int bytecount = (cstr.GetLength() + 1) * sizeof(TCHAR);
code = RegSetValueEx(hKey2, _T(""), 0, REG_SZ,
(CONST BYTE *) (LPCTSTR) cstr, (DWORD) bytecount);

RegCloseKey(hKey2);

HKEY hKey3;
RegCreateKeyEx(HKEY_CLASSES_ROOT,
TEXT("H.Prog\\shell\\open\\command"), 0,
NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
NULL, &hKey3, NULL);

pathstr = FullAppPath();
pathstr += " %1";
cstr = "";
for(i = 0; i < pathstr.length(); i++)
cstr += pathstr[i];
bytecount = (cstr.GetLength() + 1) * sizeof(TCHAR);
RegSetValueEx(hKey3, _T(""), 0, REG_SZ, (CONST BYTE *) (LPCTSTR) cstr,
(DWORD) bytecount);

RegCloseKey(hKey3);

0 new messages