|
They should be exactly the same... it's possible that there's an old bug in that Windows version, but I'm not sure. There's nothing wrong with setting the parent to NULL, but you should really be using the real parent for more predictable behavior.
|
|
|
|
|
I don't get it. It works fine in debug mode, but in release mode, this buffer I create doesn't seem to exist, and returns just nothing. At first I thought it was my wcsncpy_s, in which on ERROR_SUCCESS, I create the buffer, and copy the rgValue to szReturnValue instead of the wchar single copy for loop, but then I changed it to copy 1 wchar at a time and it does the same thing.
So in my message pump, I grab the data from the registry
case IDM_FILE_RECENTPROJECT_FILE1:
{
CA_Registry caReg;
WCHAR *szProject_Path = NULL;
DWORD dwProjectPath = 0;
caReg._read_Registry_ProjectMRUList_Value( L"File1", dwProjectPath );
szProject_Path = new WCHAR[ dwProjectPath + 1 ];
szProject_Path = caReg._read_Registry_ProjectMRUList_Value( L"File1", dwProjectPath );
_project_Open( szProject_Path );
delete [] szProject_Path;
}
break;
And in the registry function, szReturnValue is there, but I can't check the value using the Add Watch or the mouse over, when running in release. All the other values show and I can check the values.
WCHAR *szReturnValue = NULL;
WCHAR *regPath = L"SOFTWARE\\redCopper\\Internet Commerce Engine 5\\ProjectMRUList\\";
HKEY keyHandle;
WCHAR rgValue[MAX_PATH];
DWORD dwValue = sizeof(rgValue);
DWORD dwType = REG_SZ;
DWORD regStatus = REG_DWORD;
if(RegOpenKeyEx(HKEY_CURRENT_USER, regPath, 0, KEY_QUERY_VALUE, &keyHandle) == ERROR_SUCCESS) {
regStatus = RegQueryValueEx( keyHandle, pzValue, NULL, &dwType, (LPBYTE)&rgValue, &dwValue );
RegCloseKey(keyHandle);
switch ( regStatus ) {
case ERROR_SUCCESS:
{
if (( dwOut > 0 ) && ( dwOut < 4096 )) {
szReturnValue = new WCHAR[ dwOut+1 ];
for ( DWORD dwI = 0; dwI <= dwOut; ++dwI ) {
szReturnValue[ dwI ] = rgValue[ dwI ];
}
szReturnValue[ dwOut ] = L'\0';
}
else {
szReturnValue = L'\0';
dwOut = wcslen( rgValue );
}
}
break;
|
|
|
|
|
I'm a bit confused on the Debug/Release part of the question. The way I'm reading it, you have built a Release build but are running in the VS debugger, and that is when you "can't check the value...." Is that the case or did I assume too much?
In the message pump code, how is dwProjectPath getting a value? It's init to 0 then passed into the _read_Reg... function. Is it being passed by reference and getting a value there? Otherwise it's still zero when allocating szProject_Path.
In the second code block, how is dwOut evaluated? In code not shown here I'm guessing since I don't see it's declaration. Are you sure that you're executing the between 0 and 4096 section?
I know you're the one asking the question, so I should be answering instead of asking, but....
BDF
I often make very large prints from unexposed film, and every one of them turns out to be a picture of myself as I once dreamed I would be.
-- BillWoodruff
|
|
|
|
|
In the program code, I make a DWORD and set it to 0. Then I run the registry function, and if 0 is passed in, I get the wcslen of the value and set the passed in value of 0 to the measured length. Then I create a new WCHAR of the measured length, and run the registry function again with the DWORD passed in, and if the value is between 0 and 4096, I return the registry value.
I apologize for you have to ask more questions to get a better understanding of what I did.
As far as the degug / release goes, I know that you can't debug when running in the release mode, but I found it confusing that certain values show, and some don't.
With that said, I am now flashing back to the first time I checked the compile versions, and that I had to fix over a hundred programming mistakes that I made, in which I'm doing right now.
|
|
|
|
|
jkirkerx wrote: but I can't check the value using the Add Watch or the mouse over, when running in release.
That statement is... really lame... I guess most of the software engineers today would be without a job without intellisense and mouse-over debug variables.
Some thoughts:
1.) Try using the OutputDebugString function[^] to print some formatted text to your debugger. You can use this in your Release versions to print local debug variables.
2.) You should consider refactoring your code so that it avoids those new[] and delete[] operators and just pass the address of a WCHAR array. You could easily have the RegQueryValueEx function write directly into a WCHAR buffer.
Best Wishes,
-David Delaune
|
|
|
|
|
I'm flashing back now remembering that in Flash AS3,.Net and javascript, I had to print out the value somewhere, in order to find strange errors on the production servers. The same apply here in this case.
I do my best to not use the new and delete, but I don't have the years of experience or the college knowledge to find substitutes.
I freaked out, because I wanted to make this month the deadline to release this program on the customers that use my web applications, and see if it's truly a step in the right direction.
Thanks Randor
|
|
|
|
|
Randor wrote: That statement is... really lame... I guess most of the software engineers today would be without a job without intellisense and mouse-over debug variables.
I get it now Randor. I feel stupid, because I had to learn the same lesson in vb.
I ran the compiled debug version of the program, and used the jit debugger, and the call stack to back trace my errors. I fixed the threads, and used HeapFree to clear the memory that I used HeapAlloc for.
So now all the strange behavior is gone, and the program runs great, nice and smooth as well.
On the plus side, none of the code I wrote in the last 45 days had any errors.
Now I really need to learn your thought 1 and 2, and do away with new and delete. When you say avoid, you mean never use it unless you absolutely have to?
|
|
|
|
|
jkirkerx wrote: Now I really need to learn your thought 1 and 2, and do away with new and delete. When you say avoid, you mean never use it unless you absolutely have to?
Yes, I would recommend avoiding the new and delete operators unless you really need to use them. Especially in your case... where you could have simply passed a static buffer of MAX_PATH length. If you look closely at the code you showed in your original post... the function is using a static buffer of MAX_PATH length... and copying it into a buffer that you allocated with the new operator from the calling function. I was just pointing out that this is inefficient.
Best Wishes,
-David Delaune
|
|
|
|
|
Randor wrote: the function is using a static buffer of MAX_PATH length... and copying it into a buffer that you allocated with the new operator from the calling function.
I thought that was OK to do, because I did the copy 1 wchar at a time to fill the buffer to the precise length.
for ( DWORD dwI = 0; dwI <= dwOut; ++dwI ) {
szReturnValue[ dwI ] = rgValue[ dwI ];
}
szReturnValue[ dwOut ] = L'\0';
|
|
|
|
|
jkirkerx wrote: I thought that was OK to do
I am not sure that you understand my recommendation. There is nothing wrong with your logic. It will work just fine.
What I am trying to say is that you are essentially copying the data twice. You could have RegQueryValueEx write directly into a buffer passed by the calling function rather than reading it into a local buffer allocated on the stack and then copying it into a buffer allocated on the heap.
It is just a simple matter of being more efficient.
Look on the bright side... at least we are down to complaining about optimizations! A year ago you could barely invoke a MessageBox.
Your doing great and seem to be a very fast learner.
Best Wishes,
-David Delaune
|
|
|
|
|
Well Thanks Randor!
Actually it was October 15, 2011, around 7 months ago that I wrote my first line of c++ code
I changed the registry code to use the LPDWORD like Richard Suggested, See new post above or below.
Do I need to delete [] the pzProjectFolderPath, since I didn't use the new WCHAR[ ] word?. I was thinking, why should I make a new buffer since I already made the buffer in the registry function, and I just need to point to it in the main function.
Based on your thoughts, I want to take one more day and optimized some more, to lessen the chance of an embarrassing moment in the future.
CA_Registry caReg;
WCHAR *pzProjectFolderPath = NULL;
DWORD dwProjectFolderPath = 0;
caReg._read_Registry_ProjectMRUList_Value( L"File1", &dwProjectFolderPath );
if ( dwProjectFolderPath > 0 ) {
pzProjectFolderPath = caReg._read_Registry_ProjectMRUList_Value( L"File1", &dwProjectFolderPath );
_project_Open( pzProjectFolderPath );
}
|
|
|
|
|
DWORD dwProjectPath = 0;
caReg._read_Registry_ProjectMRUList_Value( L"File1", dwProjectPath );
szProject_Path = new WCHAR[ dwProjectPath + 1 ];
This will allocate you a buffer of 1 character. You cannot pass a variable into a function and expect it to have a new value on return. You can only get a value in there by sending its address, something like:
DWORD dwProjectPath = 0;
caReg._read_Registry_ProjectMRUList_Value( L"File1", &dwProjectPath );
szProject_Path = new WCHAR[ dwProjectPath + 1 ];
_read_Registry_ProjectMRUList_Value(PCWSTR pszFilename, PDWORD pdwSize)
{
DWORD size = ...
*pdwSize = size;
}
Binding 100,000 items to a list box can be just silly regardless of what pattern you are following. Jeremy Likness
|
|
|
|
|
Oh,
I didn't know that.
I'm gonna lookup PDWORD for to learn more about it.
I'll be back.
|
|
|
|
|
Microsoft defined types that begin with P or LP are pointers to the type. This article[^] by Ajay Vijayvargiya[^] gives some useful background information about it.
Binding 100,000 items to a list box can be just silly regardless of what pattern you are following. Jeremy Likness
|
|
|
|
|
So I changed my code here just for experimenting and used LPDWORD, might use PDWORD
CA_Registry caReg;
WCHAR *pzProjectFolderPath = NULL;
DWORD dwProjectFolderPath = 0;
caReg._read_Registry_ProjectMRUList_Value( L"File1", &dwProjectFolderPath );
if ( dwProjectFolderPath > 0 ) {
pzProjectFolderPath = caReg._read_Registry_ProjectMRUList_Value( L"File1", &dwProjectFolderPath );
_project_Open( pzProjectFolderPath );
}
Do I need to delete pzProjectFolderPath above?, or is it just a pointer to rgValue in the registry function?
WCHAR* CA_Registry::_read_Registry_ProjectMRUList_Value( WCHAR *pzValue, LPDWORD dwOut )
{
WCHAR *szReturnValue = NULL;
WCHAR *regPath = L"SOFTWARE\\redCopper\\Internet Commerce Engine 5\\ProjectMRUList\\";
HKEY keyHandle;
TCHAR rgValue[ MAX_PATH ];
DWORD dwValue = sizeof(rgValue);
DWORD dwType = REG_SZ;
DWORD regStatus = REG_DWORD;
if(RegOpenKeyEx(HKEY_CURRENT_USER, regPath, 0, KEY_QUERY_VALUE, &keyHandle) == ERROR_SUCCESS) {
regStatus = RegQueryValueEx( keyHandle, pzValue, NULL, &dwType, (LPBYTE)rgValue, &dwValue );
RegCloseKey(keyHandle);
switch ( regStatus ) {
case ERROR_SUCCESS:
{
if (( *dwOut > 0 ) && ( *dwOut < 4096 )) {
szReturnValue = new WCHAR[ *dwOut + 2 ];
for ( DWORD dwI = 0; dwI <= *dwOut; ++dwI ) {
szReturnValue[ dwI ] = rgValue[ dwI ];
}
szReturnValue[ *dwOut ] = L'\0';
DWORD dwErrorCode = GetLastError();
}
else {
*dwOut = wcslen( rgValue );
}
}
break;
case ERROR_FILE_NOT_FOUND:
*dwOut = 0;
break;
case ERROR_MORE_DATA:
*dwOut = 0;
break;
default:
*dwOut = 0;
}
}
else {
*dwOut = 0;
}
return szReturnValue;
}
|
|
|
|
|
jkirkerx wrote: used LPDWORD , might use PDWORD
They evaluate to exactly the same thing, the prefix L is there for historical reasons.
You could improve this by only calling your function once and not bothering about the size parameter, since that is only used within the _read_Registry_ProjectMRUList_Value() function. Just send the key name to the function and let it return a pointer to the value buffer that it allocates with new . The caller can then release that when it's finished with a call to delete[] .
Binding 100,000 items to a list box can be just silly regardless of what pattern you are following. Jeremy Likness
|
|
|
|
|
I'll try that
Thanks Richard
|
|
|
|
|
Hi,
I am somewhat of MFC C++ newbie
I have a uestion regarding virtual/overridable function
In My Case I dealing with the CASyncSocket Class
there are a number of overrideables in this class onSend OnReceive etc....
The examples of these function on the MSDN WebSite
in each these of examples the orignal functions is the last line of code
e.g
CAsyncSocket :: OnSend(nErrorCode);
CAsyncSocket::OnReceive(nErrorCode);
|
|
|
|
|
Usually when you override a virtual function, you still want to execute whatever code is within the base class, that's why you call that method either at the beginning or at the end of your own method. The placement (beginning or end) depends on the specific function, in some instances you want the base code to executed first and sometimes you want it to be executed last.
|
|
|
|
|
In addition to what Albert said, language-wise you are "overriding" a virtual function. In the language, that means you are replacing the functionality provided by the base class with your own implementation. In many examples in courses this is what they show, overriding.
In this instance, and in many such classes in the Microsoft Framework, you are, in reality, "extending" the functionality provided by the base class. So, the base class is giving you the opportunity to do *more stuff* than it would do but it still wants to do it's own stuff too. Hence you need to call the base class explicitly to let it do it's stuff. And, as Albert said, whether you call it first or last depends on the functionality you are extending so the documentation / example should help.
For example, every MFC dialog can have an function that handles the event of "InitDialog", the OnInitDialog() function. Since you want to allow the base CDialog class to do its initialization first, the very first thing you should do in your "OnInitDialog()" is to call CDialog::OnInitDialog().
That is the difference between the language defining "Virtual Functions" and an implementaion of a feature (Asynchronous Sockets) using virtual functions to obtain the desired effect.
|
|
|
|
|
Chuck O'Toole wrote: In this instance, and in many such classes in the Microsoft Framework, you are, in reality, "extending" the functionality provided by the base class.
Well put...
|
|
|
|
|
How to enumerate printers connected to the network in metro apps
|
|
|
|
|
You could start by posting your question in the metro forum.
Binding 100,000 items to a list box can be just silly regardless of what pattern you are following. Jeremy Likness
|
|
|
|
|
|
I assume it is done the same way that any other Windows software does.
Start with EnumPrinters[^] and continue.
Watched code never compiles.
|
|
|
|
|