|
I understand that you want the parent and type to be template parameters.
So let me repeat my earlier code snippet -
template<class Parent, typename Type>
void AddMember(Type Parent::*Member)
{
return true;
}
Here Parent and Type are template parameters and the calling is also convenient - AddMember(&TestObject::i);
Here Parent will be deduced to TestObject and Type will be deduced to int .
And Member will point to i .
I think this is as convenient as it can get.
|
|
|
|
|
I'm having trouble either launching the 2 correctly, or getting them to run together, not sure which one.
I want to run a fake progress bar update, and run a program in cmd.exe together at the same time.
This current code runs the CreateProcess, and before I wait for the Process, I create a thread to run the progress program. The process runs, and then the progress program runs when the process is complete. I'm trying to run them simultaneously. I'm not waiting for the progress bar to finish, because it's decorative.
if (CreateProcess( lpFile_Create, szParameters_Create, NULL, NULL, FALSE, CREATE_NO_WINDOW, 0, szWindowsTempDir, &si, &pi) )
{
PIIS7_INSTALL_PROGRESSDATA pDataArray;
pDataArray = (PIIS7_INSTALL_PROGRESSDATA) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof(IIS7_INSTALL_PROGRESSDATA));
if( pDataArray == NULL )
{
ExitProcess(2);
}
else {
pDataArray->hStatusMessage = pzStatusMessage;
pDataArray->hProgressBar = pzProgressBar;
hProgressBar = CreateThread( NULL, 0, CA_IIS7_ProgressBar_Install, pDataArray, 0, dwProgressBarID );
}
WaitForSingleObject(pi.hProcess, INFINITE);
GetExitCodeProcess(pi.hProcess, (unsigned long *)&exitstatus);
CloseHandle(hProgressBar);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
if(pDataArray != NULL)
{
HeapFree(GetProcessHeap(), 0, pDataArray);
pDataArray = NULL;
}
|
|
|
|
|
Did you state what the problem is? My apologies if I missed it.
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
I can get the CreateProcess to go, or the CreateThread, but not both.
|
|
|
|
|
So when the process starts, and it gets to the CreateThread call, did you call GetLastError to see why CreateThread fails?
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
Could it be that since you're blocking the thread in the WaitForSingleObject function, that the program is unable to process the window messages necessary to update the progress bar?
And then when the main thread is released, all the messages are processed?
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
I think your right. But I'm not sure in how to proceed, I was thinking WaitForMultiple, but I thought it was only for threads with the same handle.
Would it be possible to offer a hint?
|
|
|
|
|
Just offhand, I would say try creating the secondary thread first, then launch the process from the secondary thread. That way the secondary thread can wait for the process to finish, and your main thread can update the progress bar.
Then the secondary thread can alert the main thread that the process is finished by posting a custom message to its main window.
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
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 ...
|
|
|
|
|
|