|
I have a method that will take in a char data type if I build it with the methods shown below. If I manually put the template into the variable, it runs fine, but when I build it, it craps out (I never know what the name of the user is, so I have to build the template with just a name given).
char voice_template_g[26] = "" ;
void initiate_voice_rec(char* voice_template) {
strncpy ( voice_template_g, voice_template, sizeof( voice_template_g ) ) ;
}
void get_current_voice_template() {
char template_file_path[100] = "c:\\Dragon\\Speaker\\" ;
char default_template[100] = "c:\\Dragon\\Speaker\\IPART" ;
char temporary_file_path[100] = "";
strncat( temporary_file_path,
template_file_path,
sizeof( temporary_file_path ) ) ;
strncat( temporary_file_path,
voice_template_g,
sizeof( temporary_file_path ) ) ;
if( !_chdir( temporary_file_path ) )
{
strncpy( voice_template_g,
temporary_file_path,
sizeof(voice_template_g) ) ;
}
else
{
strncpy( voice_template_g,
default_template,
sizeof(voice_template_g) ) ;
}
}
now if a template is made (not the default) it crashes, but if I call:
strncpy( voice_template_g, "c:\\Dragon\\Speaker\\TERR2285", sizeof( voice_template_g ) ) ;
right at the end of get_current_voice_template(), it works fine.
is there a difference in the data used between:
strncpy( voice_template_g, temporary_file_path, sizeof(voice_template_g) ) ;
and
strncpy( voice_template_g, "c:\\Dragon\\Speaker\\TERR2285", sizeof( voice_template_g ) ) ;
They produce the same string, but they both don't work!
|
|
|
|
|
Hi,
it is not completely clear to me. Here are some ideas:
1.
as temporary_file_path is initially empty, the first strncat better be a strncpy.
2.
your overrun protection is not effective:
strncat( buffer, data, sizeof(buffer));
if buffer initially holds 10 chars, you will overrun it by 10 (assuming data is a long string).
you should either calculate how many buffer positions remain and use that as count, or use a safer version of strcat/strcpy.
3.
there is something quite illogical in using the same buffer (voice_template_g[26]) for input and output.
Assume it is almost full at input; your code creates a longer path (path+initial content of buffer). then
copies that back into the input buffer.
4.
And then there is the problem of string functions not ensuring there will be a terminating NULL. (When they reach the count limit before reaching the source's NULL, no NULL is copied nor appended).
5.
I can imagine situations where things run fine the first time around, and fail the second time around, maybe because voice_template_g now contains the earlier result.
6.
you should add log statements and/or use your debugger's facilities to inspect the data in the buffers.
|
|
|
|
|
pjdriverdude wrote: If I manually put the template into the variable...
Template? I see no templates or classes. Perhaps you've used the wrong word?
pjdriverdude wrote: ...but when I build it, it craps out...
With what error?
pjdriverdude wrote: They produce the same string...
How have you verified this?
"One man's wage rise is another man's price increase." - Harold Wilson
"Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons
"Man who follows car will be exhausted." - Confucius
|
|
|
|
|
1. I'm building the string to search for my template.
2. If I build the string by using "c:\\Dragon\\speaker\\TERR2285", it works fine. If I build the string with the strncat/strncpy, the function I insert my template string into give me an access violation error.
3. Yes, I've used strcmp to make sure the strings were the same. Is there a better way to do this?
|
|
|
|
|
pjdriverdude wrote: If I build the string with the strncat/strncpy, the function I insert my template string into give me an access violation error.
Which line is doing this?
pjdriverdude wrote: Is there a better way to do this?
Yes. Use the debugger to put a breakpoint on the strncpy() statement(s). Then you can see the values of voice_template_g , temporary_file_path , and default_template .
"One man's wage rise is another man's price increase." - Harold Wilson
"Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons
"Man who follows car will be exhausted." - Confucius
|
|
|
|
|
if( !_chdir( temporary_file_path ) )
{
strncpy( voice_template_g,
temporary_file_path,
sizeof(voice_template_g) ) ;
}
the strncpy here is where the template would be made so that it can be passed to a later function.
|
|
|
|
|
Ok, and?
"One man's wage rise is another man's price increase." - Harold Wilson
"Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons
"Man who follows car will be exhausted." - Confucius
|
|
|
|
|
hehe that's it, the later function that I speak of is a part of naunce's dragon naturally speaking API, so I didn't include it here, since it might just confuse anyone trying to help.
Basically,
strncpy( voice_template_g, "c:\\Dragon\\Speaker\\TERR2285", sizeof( voice_template_g ) ) ;
works, while
strncpy( voice_template_g, temporary_file_path, sizeof(voice_template_g) ) ;
doesn't. I don't see the difference in putting the actual user name in, as opposed to building it with my method listed in the code.
the dragon function looks like
m_dragon_engine->put_Speaker(speaker) ;
where speaker is the template variable I create.
|
|
|
|
|
pjdriverdude wrote: I don't see the difference in putting the actual user name in, as opposed to building it with my method listed in the code.
See my second response here.
"One man's wage rise is another man's price increase." - Harold Wilson
"Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons
"Man who follows car will be exhausted." - Confucius
|
|
|
|
|
How long is this string? "c:\\Dragon\\Speaker\\TERR2285"
It looks like 27 characters to me and you're copying it into a 26 character buffer. Try giving voice_template_g a decent size (e.g. 4096) and see if things start working a bit more to your liking. If it does then you can rein it back in again later.
All C programs spend an inordinate amount of effort widdling about with character arrays pretending to be string. You could simplify things a bit if you used a helper function to get rid of the endless sizeof operators and then you'd have a central place where you could check that you're not about to overrun a buffer or truncate a string.
Cheers,
Ash
|
|
|
|
|
The I was using an array of 100, but I got the same results..hehe I thought by making it the exact size, I might get rid of a \0 that might exist.
I've been throwing all kinds of things at this before I posted here, just haven't had time, yet, to test the suggestions. I'm definently going to tweak the size of those sizeof methods to see if that is causing the problem.
|
|
|
|
|
Rather than trying things at random, I suggest two things:
1.
yes you can start heuristically, i.e. guess at what the problem could be, investigate, try an alternative. But that will only solve the simple problems. if you can't find the overall solution, it could well be there is more than one problem; fixing the first may be unnoticeable as long as the others haven't been fixed. And that is exactly why debugging can be tiresome, and programming defensively pays off.
This also implies that "no, this change does not help" is irrelevant, the change may still be an essential part of the fix.
2.
but when heuristics fail, you need a systematic approach, which always start from the facts. Not the things you think hold true, as some of them obviously don't (otherwise your code would run fine). The only facts that count are those that you have observed by looking at intermediate values, either by printing them out (log statements) or by single-stepping and using debugger features.
The first anomaly you encounter must be remedied, it doesn't make much sense to ignore it and continue, it can only confuse you. So, take small steps, observe, and fix everything that is less than perfect.
BTW: with #2, your problem will be history in a couple of minutes. Add log statements (use hex, so you see all those pesky non-printable characters as well), and use the gray cells.
|
|
|
|
|
I see a number of conceptual mistakes here, and some of them might be part of the problem you perceive:
1. You are using statically defined buffers for storing a string of dynamic length. You cannot do that, since the behaviour of your function(s) will be undefined if for whatever reason the total string length exceeds the length of your buffer. Just using an arbitrary 'large' size is exactly the kind of thinking that caused the year 2000 bug histeria. The better solution is to calculate the size you need and dynamically allocate a buffer large enough for your purposes.
2. The third parameter of strncat is the maximum number of characters being appended. If you want to make sure that you don't write past the end of your buffer, you first need to calculate the length of the string currently stored within that buffer, using e. g. the strlen() function, and then calculate the difference.
However, that point is moot if you do what I stated in 1. since you will already know for sure that your buffer is sufficiently large - you made it so!
3. Beyond what I stated in 2., while you tried to avoid writing past the end of the buffer, you didn't care to check whether that actually causes a truncation of the concatenated string. Depending on what you want to do with that string, truncating it might render it unusable, and your function's behaviour becomes unpredictable.
4. Using strncat() or strncpy() instead of strcat and strcopy will truncate the terminating 0-character if the concatenated string is too long. As a result, your buffer will contain a string of undefined length, a length that will be equal or greater than your buffer size. Any followup calls to strncat() or strcat() will inevitably write past your reserved buffer. Not to mention that your buffer, when interpreted as a 0-terminated string, will be invalid for your purposes.
Summary:
(a) Do not use strncat() or strncpy! At all! The strings you are working with must not be truncated. A truncated directory name will cause errors as will truncated file names. There is no point at all in using functions that might truncate your strings without producing any indication that they did!
(b) Always use precise length for your string literals and string buffers! For string literals, just don't supply the length, define them like this instead:
char template_file_path[] = "c:\\Dragon\\Speaker\\" ;
And for dynamically sized buffers, calculate the exact length that you need:
char *temporary_file_path = new char[strlen(template_file_path)+strlen(voice_template_g)+1];
(and don't forget the delete [] temporary_file_path; later)
(or use malloc and free if you must)
(c) Use strcpy and strcat to make sure your path and filenames are not truncated, and your final string will be 0-terminated.
If you have a C++ compiler, it would of course be much easier to just use std:string instead of char* ...
|
|
|
|
|
I took your advice, and came up with this, and it works!
char* voice_template = new char [ strlen(user_voice_template_g) ] ;
char directory[] = "c:\\Dragon\\Speaker\\" ;
char* template_path = new char[ strlen( voice_template ) + strlen( directory ) + 1 ] ;
strcpy( voice_template, user_voice_template_g ) ;
strcpy( template_path, directory ) ;
strcat( template_path, voice_template ) ;
dragon_object = new Dragon_Base(dragon_voice_utility_g, template_path, NULL);
but something interesting came up in the process. I starting moving everything into my code and I put my _chdir function back in and I start getting errors again. It has everything to do with my _chdir function call. MSDN says that using _chdir changes the working directory, but I was thinking that it would stay in the C drive, so that didn't matter. So now, if I call _chdir, it craps out again. But hey, that's workable now. I got a good lesson on dynamic allocation of memory =) thanks!
char* voice_template = new char [ strlen(user_voice_template_g) ] ;
char directory[] = "c:\\Dragon\\Speaker\\" ;
char* template_path = new char[ strlen( voice_template ) + strlen( directory ) + 1 ] ;
strcpy( voice_template, user_voice_template_g ) ;
strcpy( template_path, directory ) ;
strcat( template_path, voice_template ) ;
if( !_chdir( template_path ) )
{
}
else
{
strcpy( template_path, "c:\\Dragon\\Speaker\\IPART" ) ;
}
dragon_object = new Dragon_Base(dragon_voice_utility_g, template_path, NULL);
|
|
|
|
|
Glad to be of help. There's still an error though: when you call strlen(somestring) what you get is not the actual size required to store a 0-terminated string, you only get the number of actual characters, or length of the string stored in this variable. It does not account for the terminating 0-byte. So when using strlen() for the purpose of allocating a sufficiently long block of memory, you always have to add 1! So instead of
pjdriverdude wrote:
char* voice_template = new char [ strlen(user_voice_template_g) ] ;
you should write
char* voice_template = new char [ strlen(user_voice_template_g) + 1 ] ;
You can also see this technique in the second example I gave: there I added the two strlen results and added another 1 on top of that.
That said, the missing byte might not cause any issues: using strcpy and strcat in place of strncpy and strncat makes sure the terminating 0 will be copied even if it's past the buffer. This can cause a lot of trouble if that memory location is being used for something else, but it is entirely possible for a single byte address to remain unused.
|
|
|
|
|
Hello,
Is MFC coding different for different versions of visual studio.
Pritha
modified on Monday, September 27, 2010 5:44 PM
|
|
|
|
|
Yes and no.
They occasionally change the argument/parameter order in a method (i.e. CRegKey changed between 6.0 and 2003) but for the most part, the overall approach tends to change little. Ivor Horton has hardly changed his "Beginning Visual C++" books over the years since the basics have not changed all that much.
However, I don't think I've ever been able to compile an MFC application with a newer version of Visual Studio without needing to change a few things such as the project VC++ Directories, minor shifts in the header files, etc...
ATL has changed a bit over the years and a few things have been left out in newer versions of Visual C++ so that tends to be the most painful part if you utilize any ATL.
|
|
|
|
|
|
Greetings!
I need to get the help button at the bottom left of the older version of the CPrintDialog class to point to something other than its default location.
Is there a way to do so?
I was able to hide the Help button with code resembling the following line:
dlg.m_pd.Flags -= PD_SHOWHELP;
Thank you for your help.
Regards,
Rajneesh
|
|
|
|
|
for that, you need to get get the control ID of the 'Help' button on PrintDialog. Using Spy++, i could find it as 0x40E. Don't know whether it is #defined anywhere
Try adding an MFC class (say CMyPrintDlg), derived from CPrintDialog, override its OnInitDialog().
BOOL CMyPrintDlg::OnInitDialog()
{
CPrintDialog::OnInitDialog();
CWnd *pBtnHelp = this->GetDlgItem(0x40E);
if(pBtnHelp)
{
CRect rc;
pBtnHelp->GetWindowRect(&rc);
ScreenToClient(&rc);
pBtnHelp->SetWindowPos(0, 0, rc.top, 0, 0, SWP_NOSIZE);
}
return TRUE;
}
and invoke it..
CMyPrintDlg dlg(FALSE, PD_PAGENUMS | PD_USEDEVMODECOPIES | PD_SHOWHELP);
dlg.m_pd.nMinPage = dlg.m_pd.nFromPage =1;
dlg.m_pd.nMaxPage = dlg.m_pd.nToPage = 10;
if (dlg.DoModal() == IDOK)
{
}
|
|
|
|
|
Hello Friends
How can I use Libtiff in my project.
I want to open a existing tiff image and recreate with layers while it is opened in application.and want to exchange layers with each other also.
Any Ideas?
Thanks In Advance.
Regards
Yogesh
|
|
|
|
|
There's a looooot of documentation at LibTIFF website.
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
[My articles]
|
|
|
|
|
Hi all,
I have made a sdi application, in that application i have made a splitter control. On Left and right side of splitter control i have placed a class derived from CFormView. On Left side of Splitter control on form view i have placed a Report style list control. All things are working fine bu my List control is not displaying vertical scrollbar but instead it is displaying a horizontal scrollbar.
What can i do?
Can anybody help me in this?
Thanks in advance
|
|
|
|
|
Are you resizing the list control properly? Make sure the control is not wider than your splitter pane. Also, you need to populate the list with enough items to make the scroll bar visible.
If the list should fill the entire area, you could use a CListView instead.
|
|
|
|
|
if the points specified above are alright, another reason for only the horizonatal scrollbar to get showed is, setting the LVS_ALIGNLEFT property to list control. Try changing it to LVS_ALIGN_TOP.
m_listControl.ModifyStyle(0, LVS_ALIGNTOP, 0);
|
|
|
|
|