|
OK, Let me give that a whirl. I added the error code, and it was 87, I will look that up.
|
|
|
|
|
How did you verify it?
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]
|
|
|
|
|
There is no error 87 on the progress thread.
I used SetLastError for 0, then asked for the error again after Creating the thread.
The progress thread runs, just can't send a SetWindowText or SendMessage out of it.
I'll see if there is an error.
|
|
|
|
|
I pulled the guts out the Progress bar function, and pasted it in after CreateProcess, and before WaitForSingleObject, So the progress bar function ends, the window is painted and updated, and when the CreateProcess is done, it picks up where it left off.
|
|
|
|
|
Ok guys, I am totally puzzled with this one. I have been reading and reading and experimenting and I finally had to post.
Basically, whenever I call the FileCopy function below and I supply cSource with "C:\\Users\\UserTest\\Desktop\\File1.txt" and cDest with "C:\\Users\\UserTest\\Desktop\\File2.txt", instead of creating File2.txt ASCII file, the function generates an empty folder instead and names it File2.txt and the return value is 2. However, if I hard code the shFileOps.pFrom and shFileOps.pTo with the above paths the function works fine and the return value is 0! It even works when I have no '\0' chars with that one. What is wrong with my code???
I have the following code:
int FileCopy(LPSTR cSource, LPSTR cDest)
{
cSource = Tools::NullifyString(cSource, true);
cDest = Tools::NullifyString(cDest, true);
LPCWSTR lpwstrSource = Convert::CharArrayToWideCharArray(cSource, false);
LPCWSTR lpwstrDest = Convert::CharArrayToWideCharArray(cDest, false);
SHFILEOPSTRUCT shFileOps;
ZeroMemory(&shFileOps, sizeof(shFileOps));
shFileOps.wFunc = FO_COPY;
shFileOps.pFrom = lpwstrSource;
shFileOps.pTo = lpwstrDest;
shFileOps.fFlags = FOF_FILESONLY | FOF_NOCONFIRMATION | FOF_SILENT;
shFileOps.fFlags |= FOF_ALLOWUNDO;
return SHFileOperation(&shFileOps);
}
char *NullifyString(const char *cSource, bool DoubleNull = false)
{
char *cNew = NULL;
int SourceLength = strlen(cSource);
if (DoubleNull)
cNew = new char[SourceLength + 2];
else
cNew = new char[SourceLength + 1];
for (int i = 0; i < SourceLength; i++)
cNew[i] = cSource[i];
cNew[strlen(cSource)] = '\0';
if (DoubleNull)
cNew[strlen(cSource) + 1] = '\0';
return cNew;
}
wchar_t *CharArrayToWideCharArray(const char *cSource, bool Nullify = true)
{
wchar_t *wcDest = NULL;
if (Nullify) wcDest = new wchar_t[strlen(cSource) + 1];
else wcDest = new wchar_t[strlen(cSource)];
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, cSource, strlen(cSource), wcDest, wcslen(wcDest));
if (Nullify) wcDest[strlen(cSource)] = NULL;
return wcDest;
}
I checked the values in the converted vars returned by NullifyString and CharArrayToWideCharArray and I get everything as expected. I am using Visual C++ 2010 Express (and for some reason it forces me nearly everything to convert into wchar_t * for some reason when it is supposed to be a normal LPSTR according to MSDN docs)
modified 25-Jan-12 7:13am.
|
|
|
|
|
1. You are adding additional NULL chars to your char source strings, but the converted wide char strings have no NULL terminators (passing false as second parameter to CharArrayToWideCharArray ). So these are not strings, but arrays without NULL terminators. Therefore, wcslen can't be used with these strings.
2. You are passing wcslen(wcDest) to MultiByteToWideChar , but wcDest has just been allocated and is not initialized!
So remove the Nullify parameter and always create a null terminated string:
wchar_t *CharArrayToWideCharArray(const char *cSource)
{
size_t nSize = strlen(cSource) + 1;
wchar_t *wcDest = new wchar_t[nSize];
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, cSource, nSize, wcDest, nSize);
return wcDest;
}
|
|
|
|
|
I can't answer your main question, but I can see that your Nullify function is a buffer overrun just waiting to happen.
The purpose of the function is, apparently, to nullify a string that does not end with a null, however, you're using the strlen function to determine the length of the string!!!
strlen relies on there being a null in order to know when to stop counting, so if there is no null, then you've got an access violation.
Pass an additional length parameter into the Nullify function so that it knows objectively the size of the string.
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
Well, I have managed to resolve the issue. I had errors even in the second version of the Nullify function. (P.S I changed the project type to Multi-byte char set and I am no longer forced to use wide chars).
Working version of the code is shown below:
int FileCopy(LPSTR cSource, LPSTR cDest)
{
cSource = Nullify::NullifyString(cSource, true);
cDest = Nullify::NullifyString(cDest);
int NullCount = Tools::CountCharType('\0',cSource, strlen(cSource) + 2);
Messages::ShowMessage(NullCount);
SHFILEOPSTRUCT shFileOps;
ZeroMemory(&shFileOps, sizeof(shFileOps));
shFileOps.wFunc = FO_COPY;
shFileOps.pFrom = cSource;
shFileOps.pTo = cDest;
shFileOps.fFlags = FOF_FILESONLY | FOF_NOCONFIRMATION | FOF_SILENT;
shFileOps.fFlags |= FOF_ALLOWUNDO;
return SHFileOperation(&shFileOps);
}
char *NullifyString(const char *cSource, bool DoubleNull = false)
{
std::string strValue = cSource;
char *cNullTerminated;
if (DoubleNull)
cNullTerminated = new char [strValue.size() + 2];
else
cNullTerminated = new char [strValue.size() + 1];
strcpy (cNullTerminated, strValue.c_str());
if (DoubleNull)
cNullTerminated[strlen(cNullTerminated) + 1] = '\0';
return cNullTerminated;
}
Here is a wide char version of the Nullify function
wchar_t *NullifyWideString(const wchar_t *wcSource, bool DoubleNull = false)
{
std::wstring strValue = wcSource;
wchar_t *wcNullTerminated;
if (DoubleNull)
wcNullTerminated = new wchar_t [strValue.size() + 2];
else
wcNullTerminated = new wchar_t [strValue.size() + 1];
wcscpy (wcNullTerminated, strValue.c_str());
if (DoubleNull)
wcNullTerminated[wcslen(wcNullTerminated) + 1] = '\0';
return wcNullTerminated;
}
I don't remember having these issues with C++ Builder but that's probably because 1. It fixes my errors and I don't even know about it, 2. VC++ is more restrictive, 3. There are errors I just haven't noticed it. Thanks Jochen and Richard for your assistance. P.S. I am now making sure there is always a "\0" at the end of any char array.
modified 26-Jan-12 2:38am.
|
|
|
|
|
It's fine that you resolved the issues. But there are still two errors:
1. shFileOps.pTo must be also double-null terminated.
2. You are allocating memory for cSource and cDest which is never freed resulting in memory leaks.
To solve these you may change your code:
cDest = Nullify::NullifyString(cDest, true);
int nRet = SHFileOperation(&shFileOps);
delete [] cDest;
delete [] cSrc;
return nRet;
|
|
|
|
|
Ouch that memory leak. Thanks, both errors have been fixed and I confirm the function still works.
I think I'd be forgiven as I spent a considerable amount of time trying to fix something so simple but I am glad I did as I learned quite a bit about VC++ and MS's data types. What I like about VC++ is when you highlight over a data type identifier for example LPCSTR it tells you what it is for example typedef const char * so if one is not sure you just hover over it! It makes things so much easier!
|
|
|
|
|
bcb_guy wrote: std::wstring strValue = wcSource;
This statement still might not behave as you'd expect. If wcSource does not have a \0 character at the end, or it has one further on in memory, strValue will be incorrect. You really need to tell NullifyWideString() how long the source string is.
"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
"Show me a community that obeys the Ten Commandments and I'll show you a less crowded prison system." - Anonymous
|
|
|
|
|
Does anyone know how to be able to list down all the working local drives ( like drive C, D, removable disks and so on..) through combo box? And with that, I could be able to scan that specific drive and retrieve all the deleted files in it. I mean, to recover those files that have been deleted through formatting or by pressing shift+delete.
Just the functions that would be needed to do all of these stuffs would be enough though. By the way,
I know it would be hard if I would be using high-level language like Java and C# to do that, so visual c++ is the one I've been working on.
That's it! I hope to get positive response from you guys. Any suggestions would be highly appreciated. Thank you!
|
|
|
|
|
Kev Karl wrote: Does anyone know how to be able to list down all the working local drives (like drive C, D, removable disks and so on..) through combo box?
Have you looked into the CB_DIR message (with wParam set to DDL_DRIVES )? You could also call GetLogicalDriveStrings() and fill the combobox yourself.
"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
"Show me a community that obeys the Ten Commandments and I'll show you a less crowded prison system." - Anonymous
|
|
|
|
|
Hello Friends
I created an application that parsed XML File By using MSXML, DOM Pointers and then saved each of XML Data into C++ objects.
Now,mine XML file size is increasing and this way of parsing is costly in terms of performance,speed and memory.
I come to know about some of XML Data Binding Schemas on Internet suxh as CodaLogic LMX,XBinder that converts XML data into C++ objects directly without any headache of Binding between Data.
So,My Question is that I want to know which is the best XML Data Binidng Method[not from that I mention but if some different] in terms of performance and should be Robust.
Thanks In Advance.
Regards
Yogesh
|
|
|
|
|
|
How is sure way to find if an internet connection is still avaiable ?
I find something here :
Check for an active Internet connection[^], but I don't want to install an SDK only to check a simple connection ...
|
|
|
|
|
|
Hi All,
I declared a variable
int x = 0; in Main.cpp
In the remaining .cpp files I am using
extern int x;
Now I want to change the contents of x to any other value in only Main.cpp
but not in the other .cpp files
How to do this?
|
|
|
|
|
When changing a global variable, all modules accessing it, will get the changed value. This is by design. To have a variable for Main.cpp only, you have to add another one.
A note: You are asking for C, but using C++ file extensions.
|
|
|
|
|
Hi,
Iam asking in C only not cpp.
|
|
|
|
|
Then you should rename your files to use .c extensions. If you use a compiler that supports C and C++, it will use C++ when detecting a .cpp extension and C compilation is not specified explicitely.
But the answer about the global variable is still the same.
|
|
|
|
|
Sakhalean wrote: How to do this?
You cant, period. You only have one variable called x. Chanhe its value and it changes, regrdless of where it is used.
==============================
Nothing to say.
|
|
|
|
|
Your question shows that you don't understand scope.
When you declare a variable using extern , it has global scope. Global scope means that all parts of your application will access the same variable when using that name, and there's only one variable and one value.
When you declare a variable in your .c file, but not elsewhere, this variable has local scope. Local scope means you can use it in this compilation unit only, and only from the point where you declare it, not before. It also means that when you use the same name in another .c file you get a compiler error, because the variable is not known there. You can declare another variable by the same name in another .c file. If you do that, that variable will be independent of the first one - you will have two different variables storing two different values.
If you want a variable that does not affect other parts of your application when you change it, you need a local variable
On a sidenote, it is a good practice to avoid variables with global scope. Prefer local variables over global ones wherever you can. Instead of using global variables, pass every value that a function requires as a fucntion argument, even if the only thing the function does with it is pass it on to another function.
|
|
|
|
|
Well, to be precise, declaring it outside of any code gives the variable global scope, using 'extern' just allows that symbol to be imported into the other source code file at compile time.
Stefan_Lang wrote: On a sidenote
Verging on dogma. A solution demands certain things, and with C, you use alot of globals. OK, you can get into a mess, and if that is the case the coder whould wonder about his ability, rather than what features of the language to use.
==============================
Nothing to say.
|
|
|
|
|
1. Yes and no. Syntacticaly you are correct. At least if you only have one .c file. But if you have more than one .c file, each file defines a local scope within the program. It's a wider scope than a function block or struct, but not as wide as a variable declared with 'extern' in a header.
2. Maybe. I am aware that many C program(mer)s like to use a lot of globals, and some mechanisms that make it easier to avoid globals in C++ are not available in C. Still, the problems caused by too many global variables is exactly the same in C as it is in C++. It's just that the effort to avoid them is on a different scale.
I've also noticed that long-time C programmers turning to C++ have a nasty habit to keep using lots of globals if there's no one around to keep them in check ('them' referring to both the globals and the programmers). Therefore I like to give out this advice to C and C++ programmers alike.
|
|
|
|
|