Related
I am trying to check the lenght of a string from my clipboard and also the first character of the string and if it returns true, I would like to set the clipboard to a different content. Here is my class;
#include <iostream>
#include <windows.h>
#include <cstring>
namespace Diall_ClipBoard_catch
{
class ClipBoard
{
private:
::HANDLE dHDat;
::std::string tmpstringsign;
bool isopen;
char* dHbuffer;
char* dHbuffertemp;
char* dNtoken;
public:
ClipBoard(void)
{
this->dHbuffer = const_cast <char*>("");
this->dHbuffertemp = const_cast <char*>("");
this->tmpstringsign = "dnb_4554_2102";
this->isopen = false;
};
~ClipBoard(void)
{
}
char* GetData(void)
{
this->Start();
if (this->isopen)
{
this->dHDat = ::GetClipboardData(CF_TEXT);
if (this->dHDat)
{
this->dHbuffer = (char*)::GlobalLock(this->dHDat);
if (::std::strcmp(this->dHbuffertemp, this->dHbuffer) != 0 && this->dHbuffer != "" && this->dHbuffer != NULL)
{
this->dHbuffertemp = this->dHbuffer;
//::std::cout << this->dHbuffer << "\n";
return this->dHbuffer;
}
::GlobalUnlock(this->dHDat);
}
CloseClipboard();
this->isopen = FALSE;
::Sleep(1000);
}
}
void SetData(void)
{
const char* data = this->dHbuffer;
const char* newstring = "Hello World";
const size_t len = strlen(newstring) + 1;
HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, len);
memcpy(GlobalLock(hMem), newstring, len);
GlobalUnlock(hMem);
if (!OpenClipboard(NULL))
{
return;
}
if (strlen(data) == 8)
{
if(data[0] == '1' || data[0] == '7')
{
EmptyClipboard();
SetClipboardData(CF_TEXT, hMem);
}
}
CloseClipboard();
this->isopen = TRUE;
}
private:
void Start(void)
{
if (!OpenClipboard(NULL))
{
return;
}
this->isopen = true;
}
};
}
And here is my main.cpp
#include "Clipboard.h"
int main()
{
::Diall_ClipBoard_catch::ClipBoard* clipboard = new Diall_ClipBoard_catch::ClipBoard();
int temp1 = 0, temp2 = 0;
EmptyClipboard();
while (1)
{
temp1 = GetClipboardSequenceNumber();
if (temp1!= temp2)
{
clipboard->SetData();
std::cout << clipboard->GetData() << std::endl;
}
temp2 = temp1;
}
return 0;
}
When I try to echo strlen(data), the value i get is 0 which should not be the case. But i get the first character of the string from data[0] but when I check it against my condition, it always returns false even though it should return as true.
PS. I am an absolute beginner in c++.
In
this->dHDat = ::GetClipboardData(CF_TEXT);
if (this->dHDat)
{
this->dHbuffer = (char*)::GlobalLock(this->dHDat);
if (::std::strcmp(this->dHbuffertemp, this->dHbuffer) != 0 && this->dHbuffer != "" && this->dHbuffer != NULL)
{
this->dHbuffertemp = this->dHbuffer;
//::std::cout << this->dHbuffer << "\n";
return this->dHbuffer;
you do not copy the data but save the (volatile) pointer to char *, you need to duplicate it, from GetClipboardData function documentation :
The application should copy the data immediately.
Why are you using array of char ? You are in C++, use std::string
[edit for your remark]
using std::string the first part of your code becomes (I do not see the usage of dNtoken so I let it unchanged) :
#include <iostream>
#include <windows.h>
#include <string>
namespace Diall_ClipBoard_catch
{
class ClipBoard
{
private:
::HANDLE dHDat;
::std::string tmpstringsign;
bool isopen;
std::string dHbuffer;
std::string dHbuffertemp;
char* dNtoken;
public:
ClipBoard(void)
{
tmpstringsign = "dnb_4554_2102";
isopen = false;
dNtoken = NULL; // better to not let it non initialized
};
~ClipBoard(void)
{
// if needed free(dNtoken)
}
std::string GetData(void)
{
this->Start();
if (this->isopen)
{
this->dHDat = ::GetClipboardData(CF_TEXT);
if (this->dHDat)
{
this->dHbuffer = (char*)::GlobalLock(this->dHDat);
if ((this->dHbuffertemp != this->dHbuffer) && !this->dHbuffer.empty())
{
this->dHbuffertemp = this->dHbuffer;
//::std::cout << this->dHbuffer << "\n";
return this->dHbuffer;
}
::GlobalUnlock(this->dHDat);
}
CloseClipboard();
this->isopen = FALSE;
::Sleep(1000);
}
}
void SetData(void)
{
std::string data = this->dHbuffer;
const char* newstring = "Hello World";
const size_t len = strlen(newstring) + 1;
HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, len);
memcpy(GlobalLock(hMem), newstring, len);
GlobalUnlock(hMem);
if (!OpenClipboard(NULL))
{
return;
}
if (data.length() == 8)
{
if(data[0] == '1' || data[0] == '7')
{
EmptyClipboard();
SetClipboardData(CF_TEXT, hMem);
}
}
CloseClipboard();
this->isopen = TRUE;
}
private:
void Start(void)
{
if (!OpenClipboard(NULL))
{
return;
}
this->isopen = true;
}
};
}
Additional note, you do not need to write this-> in all the code above
dHbuffer is initialized to point to ""
In SetData you assign data to the value of dhBuffer, which is pointing to ""
You then do strlen(data), aka strlen(""), which has a length of 0.
Everyone else's advice is pretty solid. It wasn't clear which you "were" when you had your issue, and you should likely be using std::string.
I am trying to get data from clipboard but it doesn't seem to be displaying any data when i copy to my clipboard
Here is my clipboard class
namespace Diall_ClipBoard_catch
{
class ClipBoard
{
private:
::HANDLE dHDat;
::std::string tmpstringsign;
bool isopen;
char * dHbuffer;
char * dHbuffertemp;
char * dNtoken;
public:
ClipBoard(void)
{
this->dHbuffer = "";
this->dHbuffertemp = "";
this->tmpstringsign = "dnb_4554_2102";
this->isopen = false;
};
~ClipBoard(void)
{
if(this-isopen)
{
::CloseClipboard();
this->isopen = false;
}
}
void GetData(void)
{
this->Start();
if(this->isopen)
{
this->dHDat = ::GetClipboardData(CF_TEXT);
if(this->dHDat)
{
this->dHbuffer = (char*)::GlobalLock(this->dHDat);
if(::std::strcmp(this->dHbuffertemp, this->dHbuffer)!=0 && this->dHbuffer != "" && this->dHbuffer != NULL)
{
this->dHbuffertemp = this->dHbuffer;
::std::cout << this->dHbuffer << "\n";
}
::GlobalUnlock(this->dHDat);
}
this->~ClipBoard();
::Sleep(1000);
}
}
private:
Start(void)
{
}
} ;
}
And here is my main.cpp
#include <iostream>
#include <windows.h>
#include <cstring>
#include "Clipboard.h"
int main()
{
::Diall_ClipBoard_catch::ClipBoard * clipboard = new Diall_ClipBoard_catch::ClipBoard();
while(1)
{
clipboard->GetData();
}
return 0;
}
Even though I do not get any error when i build and run on Codeblocks, I still don't get any data displayed to my console.
Even though I have played around with the compiler settings on codeblock, I still haven't been able to get it to work
The comments have given enough information to fix this problem.
In the Start() function, you need some API calls, such as OpenClipboard, SetClipboardData.
And you did not set isopen to true, so when debugging, you will find that the breakpoint cannot reach GetClipboardData ().
Add the following code to test:
Start(void)
{
const char* output = "Hello World";
const size_t len = strlen(output) + 1;
HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, len);
memcpy(GlobalLock(hMem), output, len);
GlobalUnlock(hMem);
if (!OpenClipboard(NULL))
{
return;
}
EmptyClipboard();
SetClipboardData(CF_TEXT, hMem);
this->isopen = TRUE;
}
Note: The above code uses SetClipboardData to copy the text to the clipboard, and then uses GetClipboardData to get the text.
You can also use the clipboard to copy text yourself. Run the code and check whether the return value of the GetClipboardSequenceNumber function has changed. If it changes, it means that the clipboard contents have changed or the clipboard has been emptied.
Code Sample:
#include <iostream>
#include <windows.h>
#include <cstring>
namespace Diall_ClipBoard_catch
{
class ClipBoard
{
private:
::HANDLE dHDat;
::std::string tmpstringsign;
bool isopen;
char* dHbuffer;
char* dHbuffertemp;
char* dNtoken;
public:
ClipBoard(void)
{
this->dHbuffer = const_cast <char*>("");
this->dHbuffertemp = const_cast <char*>("");
this->tmpstringsign = "dnb_4554_2102";
this->isopen = false;
};
~ClipBoard(void)
{
}
void GetData(void)
{
this->Start();
if (this->isopen)
{
this->dHDat = ::GetClipboardData(CF_TEXT);
if (this->dHDat)
{
this->dHbuffer = (char*)::GlobalLock(this->dHDat);
if (::std::strcmp(this->dHbuffertemp, this->dHbuffer) != 0 && this->dHbuffer != "" && this->dHbuffer != NULL)
{
this->dHbuffertemp = this->dHbuffer;
::std::cout << this->dHbuffer << "\n";
}
::GlobalUnlock(this->dHDat);
}
EmptyClipboard();
CloseClipboard();
this->isopen = FALSE;
::Sleep(1000);
}
}
private:
void Start(void)
{
if (!OpenClipboard(NULL))
{
return;
}
this->isopen = TRUE;
}
};
}
int main()
{
::Diall_ClipBoard_catch::ClipBoard* clipboard = new Diall_ClipBoard_catch::ClipBoard();
int temp1 = 0, temp2 = 0;
EmptyClipboard();
while (1)
{
temp1 = GetClipboardSequenceNumber();
if (temp1!= temp2)
{
clipboard->GetData();
}
temp2 = temp1;
}
return 0;
}
Debug:
I am writing a C++ console program using WinAPI. This program works with files and directories. The program is launched as follows:
app -R -1 "mask"
(for example, "D: \ Work \*").
-R is a recursive directory traversal, -1 - output of information about files (creation date, size, attributes).
Full program code:
LIBSPEC BOOL ConsolePrompt(LPCTSTR, LPTSTR, DWORD, BOOL);
LIBSPEC BOOL PrintStrings(HANDLE, ...);
LIBSPEC BOOL PrintMsg(HANDLE, LPCTSTR);
LIBSPEC VOID ReportError(LPCTSTR, DWORD, BOOL);
BOOL TraverseDirectory(LPCTSTR, DWORD, LPBOOL);
DWORD FileType(LPWIN32_FIND_DATA);
BOOL ProcessItem(LPWIN32_FIND_DATA, DWORD, LPBOOL);
DWORD Options(int argc, LPCTSTR argv[], LPCTSTR OptStr, ...) {
va_list pFlagList;
LPBOOL pFlag;
int iFlag = 0, iArg;
va_start(pFlagList, OptStr);
while ((pFlag = va_arg(pFlagList, LPBOOL)) != NULL && iFlag < (int)_tcslen(OptStr)) {
*pFlag = FALSE;
for (iArg = 1; !(*pFlag) && iArg < argc && argv[iArg][0] == '-'; iArg++)
*pFlag = memchr(argv[iArg], OptStr[iFlag], _tcslen(argv[iArg])) != NULL;
iFlag++;
}
va_end(pFlagList);
for (iArg = 1; iArg < argc && argv[iArg][0] == '-'; iArg++);
return iArg;
}
void pr_err(int code) {
setlocale(LC_ALL, "Russian");
if (code == 3) {
printf("Файл с указанным названием по указанному пути не найден.");
}
else if (code == 5) {
printf("Операция отклонена. Возможны следующие причины: \n");
printf("Копируемый файл защищен от копирования, скрыт или используется операционной системой.\n");
printf("В целевой директории стоит запрет на запись файлов.\n");
}
else if (code == 20) {
printf("Устройство не найдено.\n");
}
else if (code == 123) {
printf("Указано некорректное название для файла или директории. Возможно были использованы запрещенные символы.\n");
}
}
static void PrintAttributes(DWORD Attrs)
{
setlocale(LC_ALL, "Russian");
if (Attrs == INVALID_FILE_ATTRIBUTES)
{
printf(" Ошибка чтения атрибутов\n");
}
else
{
printf(" \nАтрибуты: ");
if (Attrs & FILE_ATTRIBUTE_ARCHIVE)
{
printf("A ");
}
if (Attrs & FILE_ATTRIBUTE_COMPRESSED)
{
printf("C ");
}
if (Attrs & FILE_ATTRIBUTE_DIRECTORY)
{
printf("D ");
}
if (Attrs & FILE_ATTRIBUTE_HIDDEN)
{
printf("H ");
}
if (Attrs & FILE_ATTRIBUTE_READONLY)
{
printf("R ");
}
printf("\n");
}
}
int _tmain(int argc, LPCTSTR argv[]) {
setlocale(LC_ALL, "Russian");
BOOL Flags[MAX_OPTIONS], ok = TRUE;
TCHAR PathName[buffsize + 1], CurrPath[buffsize + 1];
LPCTSTR pFileName;
int i, FileIndex;
FileIndex = Options(argc, argv, _T("R1"), &Flags[0], &Flags[1], &Flags[2], NULL);
GetCurrentDirectory(buffsize, CurrPath);
printf("argc = %d Index = %d\n", argc, FileIndex);
if (argc < FileIndex + 1) {
printf("Поиск в текущей директории:\n (%s)\n", CurrPath);
ok = TraverseDirectory(_T("*"), MAX_OPTIONS, Flags);
}
else {
for (i = FileIndex; i < argc; i++) {
pFileName = argv[i];
/* Нужно из pFileName вытащить сабстринг по разделителю *
FileAddress = ... // тут получение адреса
SetCurrentDirectory(FileAddress);
*/
printf("DIR: %s\n", pFileName);
if (!SetCurrentDirectory(pFileName)) {
printf("Ошибка установки директории %s как текущей...", pFileName);
return 1;
}
else {
ok = TraverseDirectory(pFileName, MAX_OPTIONS, Flags) && ok;
SetCurrentDirectory(CurrPath);
}
}
}
return ok ? 0 : 1;
}
static BOOL TraverseDirectory(LPCTSTR PathName, DWORD NumFlags, LPBOOL Flags) {
HANDLE SearchHandle;
WIN32_FIND_DATA FindData;
BOOL Recursive = Flags[0];
DWORD FType, iPass;
TCHAR CurrPath[buffsize + 1];
GetCurrentDirectory(buffsize, CurrPath);
for (iPass = 1; iPass <= 2; iPass++) {
SearchHandle = FindFirstFile(PathName, &FindData);
if (SearchHandle == INVALID_HANDLE_VALUE) {
pr_err(GetLastError());
return 1;
}
do {
FType = FileType(&FindData);
if (iPass == 1)
ProcessItem(&FindData, MAX_OPTIONS, Flags);
if (FType == TYPE_DIR && iPass == 2 && Recursive) {
_tprintf(_T("%s\\%s:\n"), CurrPath, FindData.cFileName);
if (!SetCurrentDirectory(FindData.cFileName))
{
printf("Ошибка установки %s как текущей директории...", FindData.cFileName);
}
else {
TraverseDirectory(_T("*"), NumFlags, Flags);
SetCurrentDirectory(_T(".."));
}
}
} while (FindNextFile(SearchHandle, &FindData));
FindClose(SearchHandle);
}
return TRUE;
}
static BOOL ProcessItem(LPWIN32_FIND_DATA pFileData, DWORD NumFlags, LPBOOL Flags)
{
const TCHAR FileTypeChar[] = { 'c', 'd' };
DWORD FType = FileType(pFileData);
BOOL Long = Flags[1];
SYSTEMTIME LastWrite;
if (FType != TYPE_FILE && FType != TYPE_DIR)
return FALSE;
_tprintf(_T("\n"));
if (Long) {
_tprintf(_T("%c"), FileTypeChar[FType - 1]);
_tprintf(_T("%10d"), pFileData->nFileSizeLow);
FileTimeToSystemTime(&(pFileData->ftLastWriteTime), &LastWrite);
_tprintf(_T(" %02d/%02d/%04d %02d:%02d:%02d "), LastWrite.wMonth, LastWrite.wDay,
LastWrite.wYear, LastWrite.wHour, LastWrite.wMinute, LastWrite.wSecond);
}
_tprintf(_T("%s"), pFileData->cFileName);
PrintAttributes(GetFileAttributesA(pFileData->cFileName));
return TRUE;
}
static DWORD FileType(LPWIN32_FIND_DATA pFileData) {
BOOL IsDir;
DWORD FType;
FType = TYPE_FILE;
IsDir = (pFileData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
if (IsDir)
if (lstrcmp(pFileData->cFileName, _T(".")) == 0 ||
lstrcmp(pFileData->cFileName, _T("..")) == 0)
FType = TYPE_DOT;
else
FType = TYPE_DIR;
return FType;
}
The problem is switching to the specified path does not work. How can I solve this problem?
Wildcard characters are not accepted in SetCurrentDirectory.
You should to specify a valid path, like "D:\\work\\".
Then, you should call GetFileAttributes to decide whether to add wildcards after the filename.
TCHAR file[MAX_PATH] = {0};
_stprintf(file, _T("%s\\*"), pFileName);
ok = TraverseDirectory(file, MAX_PATH, Flags) && ok;
I'm using "readline" library to create a console interface for my program. I'm able to autocomplete words using tab, but when I have words that share the same prefix like (car, card, carbon) it always chooses the shortest one. Here's my program (mostly taken from link):
#include <readline/readline.h>
#include <readline/history.h>
#include <stdlib.h>
#include <iostream>
const char *words[] = {"add", "remove", "rm", "update", "child", "children", "wife", "wifes"};
void *xmalloc (int size)
{
void *buf;
buf = malloc (size);
if (!buf)
{
fprintf (stderr, "Error: Out of memory. Exiting.\n");
exit (1);
}
return buf;
}
char *dupstr (const char *str)
{
char *temp;
temp = (char *) xmalloc (strlen (str) + 1);
strcpy (temp, str);
return (temp);
}
char *my_generator (const char *text, int state)
{
static int list_index, len;
const char *name;
if (!state)
{
list_index = 0;
len = strlen (text);
}
while (name = words[list_index])
{
list_index++;
if (strncmp (name, text, len) == 0) return dupstr (name);
}
// If no names matched, then return NULL.
return ((char *) NULL);
}
static char **my_completion (const char *text, int start, int end)
{
char **matches = (char **) NULL;
if (start == 0)
{
matches = rl_completion_matches ((char *) text, &my_generator);
}
else rl_bind_key ('\t', rl_abort);
return matches;
}
int main (int argc, char *argv[])
{
char *buf;
rl_attempted_completion_function = my_completion;
while ((buf = readline(">> ")) != NULL)
{
rl_bind_key ('\t', rl_complete);
if (strcmp (buf, "exit") == 0) break;
else if (buf[0] == '\0') continue;
else
{
std::cout << buf << std::endl;
add_history (buf);
}
}
free (buf);
return 0;
}
Is it possible to list all matches on double tab just like in ubuntu terminal?
I managed to get it to work by commenting out these two lines:
rl_bind_key ('\t', rl_complete);
and:
else rl_bind_key ('\t', rl_abort);
The default completion behaviour of readline works exactly like in ubuntu terminal, one tab to complete and two tabs to list possible completions. Not sure though what's the default completion function that's binded with the tab key, from the documentation i thought it was rl_possible_completions but it didn't give the same results.
Also i added the following line to my_completion function to prevent adding space at the end of the matched word:
rl_completion_append_character = '\0';
I removed dupstrfunction it and replaced it with the native strdup function instead (this has nothing to do with the auto complete problem, it's just to remove unnecessary code).
This is the final code:
#include <readline/readline.h>
#include <readline/history.h>
#include <stdlib.h>
#include <iostream>
const char *words[] = {"add", "remove", "rm", "update", "child", "children", "wife", "wives"};
// Generator function for word completion.
char *my_generator (const char *text, int state)
{
static int list_index, len;
const char *name;
if (!state)
{
list_index = 0;
len = strlen (text);
}
while (name = words[list_index])
{
list_index++;
if (strncmp (name, text, len) == 0) return strdup (name);
}
// If no names matched, then return NULL.
return ((char *) NULL);
}
// Custom completion function
static char **my_completion (const char *text, int start, int end)
{
// This prevents appending space to the end of the matching word
rl_completion_append_character = '\0';
char **matches = (char **) NULL;
if (start == 0)
{
matches = rl_completion_matches ((char *) text, &my_generator);
}
// else rl_bind_key ('\t', rl_abort);
return matches;
}
int main (int argc, char *argv[])
{
char *buf;
rl_attempted_completion_function = my_completion;
while ((buf = readline(">> ")) != NULL)
{
// rl_bind_key ('\t', rl_complete);
if (strcmp (buf, "exit") == 0) break;
else if (buf[0] == '\0')
{
free (buf);
continue;
}
else
{
std::cout << buf << std::endl;
add_history (buf);
}
free (buf);
buf = NULL;
}
if (buf != NULL) free (buf);
return 0;
}
The answer by razzak is almost correct, but this NULL must be added at the end of array of strings:
const char *words[] = {"add", "remove", "rm", "update", "child", "children", "wife", "wives", NULL};
Some changes for nonwarning compilation in my_generator() function:
while ((name = words[list_index++]))
{
if (strncmp (name, text, len) == 0) return strdup (name);
}
Should I create two CFile objects and copy one into the other character by character? Or is there something in the library that will do this for me?
I would just use the CopyFile Win32 API function, but the example code in the CFile::Open documentation shows how to copy files with CFile (using pretty much the method you suggest).
It depends on what you want to do. There are a number of ways to copy files:
CopyFile()
CopyFileEx()
SHFileOperation()
IFileOperation (replaces SHFileOperation() in Vista)
While I appreciate the previous answers, I have found that this FileOperations is a nice wrapper that mimics the way copy operations are performed in Windows Explorer, which also includes Copy, Move and Delete files and rename directories:
http://www.ucancode.net/Visual_C_Source_Code/Copy-Move-Delete-files-rename-directories-SHFileOperation-CFileFind-FindFirstFile-FindNextFile-mfc-example.htm
#include "stdafx.h"
#include "FileOperations.h"
//
// this code copy 'c:\source' directory and
// all it's subdirectories and files
// to the 'c:\dest' directory.
//
CFileOperation fo; // create object
fo.SetOverwriteMode(false); // reset OverwriteMode flag (optional)
if (!fo.Copy("c:\\source", "c:\\dest")) // do Copy
{
fo.ShowError(); // if copy fails show error message
}
//
// this code delete 'c:\source' directory and
// all it's subdirectories and files.
//
fo.Setucancode.netIfReadOnly(); // set ucancode.netIfReadonly flag (optional)
if (!fo.Delete("c:\\source")) // do Copy
{
fo.ShowError(); // if copy fails show error message
}
Here is the source code for completeness:
#include "resource.h"
#define PATH_ERROR -1
#define PATH_NOT_FOUND 0
#define PATH_IS_FILE 1
#define PATH_IS_FOLDER 2
class CFExeption
{
public:
CFExeption(DWORD dwErrCode);
CFExeption(CString sErrText);
CString GetErrorText() {return m_sError;}
DWORD GetErrorCode() {return m_dwError;}
private:
CString m_sError;
DWORD m_dwError;
};
//*****************************************************************************************************
class CFileOperation
{
public:
CFileOperation(); // constructor
bool Delete(CString sPathName); // delete file or folder
bool Copy(CString sSource, CString sDest); // copy file or folder
bool Replace(CString sSource, CString sDest); // move file or folder
bool Rename(CString sSource, CString sDest); // rename file or folder
CString GetErrorString() {return m_sError;} // return error description
DWORD GetErrorCode() {return m_dwError;} // return error code
void ShowError() // show error message
{MessageBox(NULL, m_sError, _T("Error"), MB_OK | MB_ICONERROR);}
void SetAskIfReadOnly(bool bAsk = true) // sets behavior with readonly files(folders)
{m_bAskIfReadOnly = bAsk;}
bool IsAskIfReadOnly() // return current behavior with readonly files(folders)
{return m_bAskIfReadOnly;}
bool CanDelete(CString sPathName); // check attributes
void SetOverwriteMode(bool bOverwrite = false) // sets overwrite mode on/off
{m_bOverwriteMode = bOverwrite;}
bool IsOverwriteMode() {return m_bOverwriteMode;} // return current overwrite mode
int CheckPath(CString sPath);
bool IsAborted() {return m_bAborted;}
protected:
void DoDelete(CString sPathName);
void DoCopy(CString sSource, CString sDest, bool bDelteAfterCopy = false);
void DoFileCopy(CString sSourceFile, CString sDestFile, bool bDelteAfterCopy = false);
void DoFolderCopy(CString sSourceFolder, CString sDestFolder, bool bDelteAfterCopy = false);
void DoRename(CString sSource, CString sDest);
bool IsFileExist(CString sPathName);
void PreparePath(CString &sPath);
void Initialize();
void CheckSelfRecursion(CString sSource, CString sDest);
bool CheckSelfCopy(CString sSource, CString sDest);
CString ChangeFileName(CString sFileName);
CString ParseFolderName(CString sPathName);
private:
CString m_sError;
DWORD m_dwError;
bool m_bAskIfReadOnly;
bool m_bOverwriteMode;
bool m_bAborted;
int m_iRecursionLimit;
};
//*****************************************************************************************************
C++ file:
#include "stdafx.h"
#include "resource.h"
#include "FileOperations.h"
//************************************************************************************************************
CFExeption::CFExeption(DWORD dwErrCode)
{
LPVOID lpMsgBuf;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, dwErrCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL);
m_sError = (LPTSTR)lpMsgBuf;
LocalFree(lpMsgBuf);
m_dwError = dwErrCode;
}
CFExeption::CFExeption(CString sErrText)
{
m_sError = sErrText;
m_dwError = 0;
}
//************************************************************************************************************
CFileOperation::CFileOperation()
{
Initialize();
}
void CFileOperation::Initialize()
{
m_sError = _T("No error");
m_dwError = 0;
m_bAskIfReadOnly = true;
m_bOverwriteMode = false;
m_bAborted = false;
m_iRecursionLimit = -1;
}
void CFileOperation::DoDelete(CString sPathName)
{
CFileFind ff;
CString sPath = sPathName;
if (CheckPath(sPath) == PATH_IS_FILE)
{
if (!CanDelete(sPath))
{
m_bAborted = true;
return;
}
if (!DeleteFile(sPath)) throw new CFExeption(GetLastError());
return;
}
PreparePath(sPath);
sPath += "*.*";
BOOL bRes = ff.FindFile(sPath);
while(bRes)
{
bRes = ff.FindNextFile();
if (ff.IsDots()) continue;
if (ff.IsDirectory())
{
sPath = ff.GetFilePath();
DoDelete(sPath);
}
else DoDelete(ff.GetFilePath());
}
ff.Close();
if (!RemoveDirectory(sPathName) && !m_bAborted) throw new CFExeption(GetLastError());
}
void CFileOperation::DoFolderCopy(CString sSourceFolder, CString sDestFolder, bool bDelteAfterCopy)
{
CFileFind ff;
CString sPathSource = sSourceFolder;
BOOL bRes = ff.FindFile(sPathSource);
while (bRes)
{
bRes = ff.FindNextFile();
if (ff.IsDots()) continue;
if (ff.IsDirectory()) // source is a folder
{
if (m_iRecursionLimit == 0) continue;
sPathSource = ff.GetFilePath() + CString("\\") + CString("*.*");
CString sPathDest = sDestFolder + ff.GetFileName() + CString("\\");
if (CheckPath(sPathDest) == PATH_NOT_FOUND)
{
if (!CreateDirectory(sPathDest, NULL))
{
ff.Close();
throw new CFExeption(GetLastError());
}
}
if (m_iRecursionLimit > 0) m_iRecursionLimit --;
DoFolderCopy(sPathSource, sPathDest, bDelteAfterCopy);
}
else // source is a file
{
CString sNewFileName = sDestFolder + ff.GetFileName();
DoFileCopy(ff.GetFilePath(), sNewFileName, bDelteAfterCopy);
}
}
ff.Close();
}
bool CFileOperation::Delete(CString sPathName)
{
try
{
DoDelete(sPathName);
}
catch(CFExeption* e)
{
m_sError = e->GetErrorText();
m_dwError = e->GetErrorCode();
delete e;
if (m_dwError == 0) return true;
return false;
}
return true;
}
bool CFileOperation::Rename(CString sSource, CString sDest)
{
try
{
DoRename(sSource, sDest);
}
catch(CFExeption* e)
{
m_sError = e->GetErrorText();
m_dwError = e->GetErrorCode();
delete e;
return false;
}
return true;
}
void CFileOperation::DoRename(CString sSource, CString sDest)
{
if (!MoveFile(sSource, sDest)) throw new CFExeption(GetLastError());
}
void CFileOperation::DoCopy(CString sSource, CString sDest, bool bDelteAfterCopy)
{
CheckSelfRecursion(sSource, sDest);
// source not found
if (CheckPath(sSource) == PATH_NOT_FOUND)
{
CString sError = sSource + CString(" not found");
throw new CFExeption(sError);
}
// dest not found
if (CheckPath(sDest) == PATH_NOT_FOUND)
{
CString sError = sDest + CString(" not found");
throw new CFExeption(sError);
}
// folder to file
if (CheckPath(sSource) == PATH_IS_FOLDER && CheckPath(sDest) == PATH_IS_FILE)
{
throw new CFExeption("Wrong operation");
}
// folder to folder
if (CheckPath(sSource) == PATH_IS_FOLDER && CheckPath(sDest) == PATH_IS_FOLDER)
{
CFileFind ff;
CString sError = sSource + CString(" not found");
PreparePath(sSource);
PreparePath(sDest);
sSource += "*.*";
if (!ff.FindFile(sSource))
{
ff.Close();
throw new CFExeption(sError);
}
if (!ff.FindNextFile())
{
ff.Close();
throw new CFExeption(sError);
}
CString sFolderName = ParseFolderName(sSource);
if (!sFolderName.IsEmpty()) // the source is not drive
{
sDest += sFolderName;
PreparePath(sDest);
if (!CreateDirectory(sDest, NULL))
{
DWORD dwErr = GetLastError();
if (dwErr != 183)
{
ff.Close();
throw new CFExeption(dwErr);
}
}
}
ff.Close();
DoFolderCopy(sSource, sDest, bDelteAfterCopy);
}
// file to file
if (CheckPath(sSource) == PATH_IS_FILE && CheckPath(sDest) == PATH_IS_FILE)
{
DoFileCopy(sSource, sDest);
}
// file to folder
if (CheckPath(sSource) == PATH_IS_FILE && CheckPath(sDest) == PATH_IS_FOLDER)
{
PreparePath(sDest);
char drive[MAX_PATH], dir[MAX_PATH], name[MAX_PATH], ext[MAX_PATH];
_splitpath(sSource, drive, dir, name, ext);
sDest = sDest + CString(name) + CString(ext);
DoFileCopy(sSource, sDest);
}
}
void CFileOperation::DoFileCopy(CString sSourceFile, CString sDestFile, bool bDelteAfterCopy)
{
BOOL bOvrwriteFails = FALSE;
if (!m_bOverwriteMode)
{
while (IsFileExist(sDestFile))
{
sDestFile = ChangeFileName(sDestFile);
}
bOvrwriteFails = TRUE;
}
if (!CopyFile(sSourceFile, sDestFile, bOvrwriteFails)) throw new CFExeption(GetLastError());
if (bDelteAfterCopy)
{
DoDelete(sSourceFile);
}
}
bool CFileOperation::Copy(CString sSource, CString sDest)
{
if (CheckSelfCopy(sSource, sDest)) return true;
bool bRes;
try
{
DoCopy(sSource, sDest);
bRes = true;
}
catch(CFExeption* e)
{
m_sError = e->GetErrorText();
m_dwError = e->GetErrorCode();
delete e;
if (m_dwError == 0) bRes = true;
bRes = false;
}
m_iRecursionLimit = -1;
return bRes;
}
bool CFileOperation::Replace(CString sSource, CString sDest)
{
if (CheckSelfCopy(sSource, sDest)) return true;
bool bRes;
try
{
bool b = m_bAskIfReadOnly;
m_bAskIfReadOnly = false;
DoCopy(sSource, sDest, true);
DoDelete(sSource);
m_bAskIfReadOnly = b;
bRes = true;
}
catch(CFExeption* e)
{
m_sError = e->GetErrorText();
m_dwError = e->GetErrorCode();
delete e;
if (m_dwError == 0) bRes = true;
bRes = false;
}
m_iRecursionLimit = -1;
return bRes;
}
CString CFileOperation::ChangeFileName(CString sFileName)
{
CString sName, sNewName, sResult;
char drive[MAX_PATH];
char dir [MAX_PATH];
char name [MAX_PATH];
char ext [MAX_PATH];
_splitpath((LPCTSTR)sFileName, drive, dir, name, ext);
sName = name;
int pos = sName.Find("Copy ");
if (pos == -1)
{
sNewName = CString("Copy of ") + sName + CString(ext);
}
else
{
int pos1 = sName.Find('(');
if (pos1 == -1)
{
sNewName = sName;
sNewName.Delete(0, 8);
sNewName = CString("Copy (1) of ") + sNewName + CString(ext);
}
else
{
CString sCount;
int pos2 = sName.Find(')');
if (pos2 == -1)
{
sNewName = CString("Copy of ") + sNewName + CString(ext);
}
else
{
sCount = sName.Mid(pos1 + 1, pos2 - pos1 - 1);
sName.Delete(0, pos2 + 5);
int iCount = atoi((LPCTSTR)sCount);
iCount ++;
sNewName.Format("%s%d%s%s%s", "Copy (", iCount, ") of ", (LPCTSTR)sName, ext);
}
}
}
sResult = CString(drive) + CString(dir) + sNewName;
return sResult;
}
bool CFileOperation::IsFileExist(CString sPathName)
{
HANDLE hFile;
hFile = CreateFile(sPathName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
if (hFile == INVALID_HANDLE_VALUE) return false;
CloseHandle(hFile);
return true;
}
int CFileOperation::CheckPath(CString sPath)
{
DWORD dwAttr = GetFileAttributes(sPath);
if (dwAttr == 0xffffffff)
{
if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
return PATH_NOT_FOUND;
return PATH_ERROR;
}
if (dwAttr & FILE_ATTRIBUTE_DIRECTORY) return PATH_IS_FOLDER;
return PATH_IS_FILE;
}
void CFileOperation::PreparePath(CString &sPath)
{
if(sPath.Right(1) != "\\") sPath += "\\";
}
bool CFileOperation::CanDelete(CString sPathName)
{
DWORD dwAttr = GetFileAttributes(sPathName);
if (dwAttr == -1) return false;
if (dwAttr & FILE_ATTRIBUTE_READONLY)
{
if (m_bAskIfReadOnly)
{
CString sTmp = sPathName;
int pos = sTmp.ReverseFind('\\');
if (pos != -1) sTmp.Delete(0, pos + 1);
CString sText = sTmp + CString(" is read olny. Do you want delete it?");
int iRes = MessageBox(NULL, sText, _T("Warning"), MB_YESNOCANCEL | MB_ICONQUESTION);
switch (iRes)
{
case IDYES:
{
if (!SetFileAttributes(sPathName, FILE_ATTRIBUTE_NORMAL)) return false;
return true;
}
case IDNO:
{
return false;
}
case IDCANCEL:
{
m_bAborted = true;
throw new CFExeption(0);
return false;
}
}
}
else
{
if (!SetFileAttributes(sPathName, FILE_ATTRIBUTE_NORMAL)) return false;
return true;
}
}
return true;
}
CString CFileOperation::ParseFolderName(CString sPathName)
{
CString sFolderName = sPathName;
int pos = sFolderName.ReverseFind('\\');
if (pos != -1) sFolderName.Delete(pos, sFolderName.GetLength() - pos);
pos = sFolderName.ReverseFind('\\');
if (pos != -1) sFolderName = sFolderName.Right(sFolderName.GetLength() - pos - 1);
else sFolderName.Empty();
return sFolderName;
}
void CFileOperation::CheckSelfRecursion(CString sSource, CString sDest)
{
if (sDest.Find(sSource) != -1)
{
int i = 0, count1 = 0, count2 = 0;
for(i = 0; i < sSource.GetLength(); i ++) if (sSource[i] == '\\') count1 ++;
for(i = 0; i < sDest.GetLength(); i ++) if (sDest[i] == '\\') count2 ++;
if (count2 >= count1) m_iRecursionLimit = count2 - count1;
}
}
bool CFileOperation::CheckSelfCopy(CString sSource, CString sDest)
{
bool bRes = false;
if (CheckPath(sSource) == PATH_IS_FOLDER)
{
CString sTmp = sSource;
int pos = sTmp.ReverseFind('\\');
if (pos != -1)
{
sTmp.Delete(pos, sTmp.GetLength() - pos);
if (sTmp.CompareNoCase(sDest) == 0) bRes = true;
}
}
return bRes;
}
The Copy option in your code requires the dest file or folder to first exist otherwise this
if (CheckPath(sDest) == PATH_NOT_FOUND)
will always cause an error.