Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
i have some c++ project after a release of support c++20, i want to upgrade my makefile std support 17 to 20 after that point my compiler (gcc10.2) give me a error like this ;
Error
In file included from /usr/local/lib/gcc10/include/c++/bits/node_handle.h:39,
from /usr/local/lib/gcc10/include/c++/bits/stl_tree.h:72,
from /usr/local/lib/gcc10/include/c++/map:60,
from AsyncSQL.h:10,
from AsyncSQL.cpp:4:
/usr/local/lib/gcc10/include/c++/optional: In function 'constexpr std::strong_ordering std::operator<=>(const std::optional<_Tp>&, std::nullopt_t)':
/usr/local/lib/gcc10/include/c++/optional:1052:24: error: invalid operands of types 'bool' and 'int' to binary 'operator<=>'
1052 | { return bool(__x) <=> false; }
| ~~~~~~~~~ ^~~
| |
| bool
gmake[2]: *** [Makefile:23: AsyncSQL.o] Error 1
This is my AsyncSQL.cpp ;
#include <sys/time.h>
#include <cstdlib>
#include <cstring>
#include "AsyncSQL.h"
#define MUTEX_LOCK(mtx) pthread_mutex_lock(mtx)
#define MUTEX_UNLOCK(mtx) pthread_mutex_unlock(mtx)
CAsyncSQL::CAsyncSQL(): m_stHost (""), m_stUser (""), m_stPassword (""), m_stDB (""), m_stLocale (""), m_iMsgCount (0), m_iPort (0), m_bEnd (false), m_hThread (0), m_mtxQuery (NULL), m_mtxResult (NULL), m_iQueryFinished (0), m_ulThreadID (0), m_bConnected (false), m_iCopiedQuery (0)
{
memset (&m_hDB, 0, sizeof (m_hDB));
m_aiPipe[0] = 0;
m_aiPipe[1] = 0;
}
CAsyncSQL::~CAsyncSQL()
{
Quit();
Destroy();
}
void CAsyncSQL::Destroy()
{
if (m_hDB.host)
{
sys_log (0, "AsyncSQL: closing mysql connection.");
mysql_close (&m_hDB);
m_hDB.host = NULL;
}
if (m_mtxQuery)
{
pthread_mutex_destroy (m_mtxQuery);
delete m_mtxQuery;
m_mtxQuery = NULL;
}
if (m_mtxResult)
{
pthread_mutex_destroy (m_mtxResult);
delete m_mtxResult;
m_mtxQuery = NULL;
}
}
void* AsyncSQLThread (void* arg)
{
CAsyncSQL* pSQL = ((CAsyncSQL*) arg);
if (!pSQL->Connect())
{
return NULL;
}
pSQL->ChildLoop();
return NULL;
}
bool CAsyncSQL::QueryLocaleSet()
{
if (0 == m_stLocale.length())
{
sys_err ("m_stLocale == 0");
return true;
}
if (mysql_set_character_set (&m_hDB, m_stLocale.c_str()))
{
sys_err ("cannot set locale %s by 'mysql_set_character_set', errno %u %s", m_stLocale.c_str(), mysql_errno (&m_hDB) , mysql_error (&m_hDB));
return false;
}
sys_log (0, "\t--mysql_set_character_set(%s)", m_stLocale.c_str());
return true;
}
bool CAsyncSQL::Connect()
{
if (0 == mysql_init (&m_hDB))
{
fprintf (stderr, "mysql_init failed\n");
return false;
}
if (!m_stLocale.empty())
{
if (mysql_options (&m_hDB, MYSQL_SET_CHARSET_NAME, m_stLocale.c_str()) != 0)
{
fprintf (stderr, "mysql_option failed : MYSQL_SET_CHARSET_NAME %s ", mysql_error(&m_hDB));
}
}
if (!mysql_real_connect (&m_hDB, m_stHost.c_str(), m_stUser.c_str(), m_stPassword.c_str(), m_stDB.c_str(), m_iPort, NULL, CLIENT_MULTI_STATEMENTS))
{
fprintf (stderr, "mysql_real_connect: %s\n", mysql_error(&m_hDB));
return false;
}
my_bool reconnect = true;
if (0 != mysql_options (&m_hDB, MYSQL_OPT_RECONNECT, &reconnect))
{
fprintf (stderr, "mysql_option: %s\n", mysql_error(&m_hDB));
}
m_ulThreadID = mysql_thread_id (&m_hDB);
m_bConnected = true;
return true;
}
bool CAsyncSQL::Setup (CAsyncSQL* sql, bool bNoThread)
{
return Setup (sql->m_stHost.c_str(), sql->m_stUser.c_str(), sql->m_stPassword.c_str(), sql->m_stDB.c_str(), sql->m_stLocale.c_str(), bNoThread, sql->m_iPort);
}
bool CAsyncSQL::Setup (const char* c_pszHost, const char* c_pszUser, const char* c_pszPassword, const char* c_pszDB, const char* c_pszLocale, bool bNoThread, int iPort)
{
m_stHost = c_pszHost;
m_stUser = c_pszUser;
m_stPassword = c_pszPassword;
m_stDB = c_pszDB;
m_iPort = iPort;
if (c_pszLocale)
{
m_stLocale = c_pszLocale;
sys_log (0, "AsyncSQL: locale %s", m_stLocale.c_str());
}
if (!bNoThread)
{
m_mtxQuery = new pthread_mutex_t;
m_mtxResult = new pthread_mutex_t;
if (0 != pthread_mutex_init (m_mtxQuery, NULL))
{
perror ("pthread_mutex_init");
exit (0);
}
if (0 != pthread_mutex_init (m_mtxResult, NULL))
{
perror ("pthread_mutex_init");
exit (0);
}
pthread_create (&m_hThread, NULL, AsyncSQLThread, this);
return true;
}
else
{
return Connect();
}
}
void CAsyncSQL::Quit()
{
m_bEnd = true;
m_sem.Release();
if (m_hThread)
{
pthread_join (m_hThread, NULL);
m_hThread = NULL;
}
}
SQLMsg* CAsyncSQL::DirectQuery (const char* c_pszQuery)
{
if (m_ulThreadID != mysql_thread_id (&m_hDB))
{
sys_log (0, "MySQL connection was reconnected. querying locale set");
while (!QueryLocaleSet());
m_ulThreadID = mysql_thread_id (&m_hDB);
}
SQLMsg* p = new SQLMsg;
p->m_pkSQL = &m_hDB;
p->iID = ++m_iMsgCount;
p->stQuery = c_pszQuery;
if (mysql_real_query (&m_hDB, p->stQuery.c_str(), p->stQuery.length()))
{
char buf[1024];
snprintf (buf, sizeof(buf), "AsyncSQL::DirectQuery : mysql_query error: %s\nquery: %s", mysql_error (&m_hDB), p->stQuery.c_str());
sys_err (buf);
p->uiSQLErrno = mysql_errno (&m_hDB);
}
p->Store();
return p;
}
void CAsyncSQL::AsyncQuery (const char* c_pszQuery)
{
auto p = new SQLMsg;
p->m_pkSQL = &m_hDB;
p->iID = ++m_iMsgCount;
p->stQuery = c_pszQuery;
PushQuery (p);
}
void CAsyncSQL::ReturnQuery (const char* c_pszQuery, void* pvUserData)
{
auto p = new SQLMsg;
p->m_pkSQL = &m_hDB;
p->iID = ++m_iMsgCount;
p->stQuery = c_pszQuery;
p->bReturn = true;
p->pvUserData = pvUserData;
PushQuery (p);
}
void CAsyncSQL::PushResult (SQLMsg* p)
{
MUTEX_LOCK (m_mtxResult);
m_queue_result.push (p);
MUTEX_UNLOCK (m_mtxResult);
}
bool CAsyncSQL::PopResult(SQLMsg** pp)
{
MUTEX_LOCK (m_mtxResult);
if (m_queue_result.empty())
{
MUTEX_UNLOCK (m_mtxResult);
return false;
}
*pp = m_queue_result.front();
m_queue_result.pop();
MUTEX_UNLOCK (m_mtxResult);
return true;
}
void CAsyncSQL::PushQuery (SQLMsg* p)
{
MUTEX_LOCK (m_mtxQuery);
m_queue_query.push (p);
m_sem.Release();
MUTEX_UNLOCK (m_mtxQuery);
}
bool CAsyncSQL::PeekQuery (SQLMsg** pp)
{
MUTEX_LOCK (m_mtxQuery);
if (m_queue_query.empty())
{
MUTEX_UNLOCK (m_mtxQuery);
return false;
}
*pp = m_queue_query.front();
MUTEX_UNLOCK (m_mtxQuery);
return true;
}
bool CAsyncSQL::PopQuery (int iID)
{
MUTEX_LOCK (m_mtxQuery);
if (m_queue_query.empty())
{
MUTEX_UNLOCK (m_mtxQuery);
return false;
}
m_queue_query.pop();
MUTEX_UNLOCK (m_mtxQuery);
return true;
}
bool CAsyncSQL::PeekQueryFromCopyQueue (SQLMsg** pp)
{
if (m_queue_query_copy.empty())
{
return false;
}
*pp = m_queue_query_copy.front();
return true;
}
int CAsyncSQL::CopyQuery()
{
MUTEX_LOCK (m_mtxQuery);
if (m_queue_query.empty())
{
MUTEX_UNLOCK (m_mtxQuery);
return -1;
}
while (!m_queue_query.empty())
{
SQLMsg* p = m_queue_query.front();
m_queue_query_copy.push (p);
m_queue_query.pop();
}
int count = m_queue_query_copy.size();
MUTEX_UNLOCK (m_mtxQuery);
return count;
}
bool CAsyncSQL::PopQueryFromCopyQueue()
{
if (m_queue_query_copy.empty())
{
return false;
}
m_queue_query_copy.pop();
return true;
}
int CAsyncSQL::GetCopiedQueryCount()
{
return m_iCopiedQuery;
}
void CAsyncSQL::ResetCopiedQueryCount()
{
m_iCopiedQuery = 0;
}
void CAsyncSQL::AddCopiedQueryCount (int iCopiedQuery)
{
m_iCopiedQuery += iCopiedQuery;
}
DWORD CAsyncSQL::CountQuery()
{
return m_queue_query.size();
}
DWORD CAsyncSQL::CountResult()
{
return m_queue_result.size();
}
void __timediff (struct timeval* a, struct timeval* b, struct timeval* rslt)
{
if (a->tv_sec < b->tv_sec)
{
rslt->tv_sec = rslt->tv_usec = 0;
}
else if (a->tv_sec == b->tv_sec)
{
if (a->tv_usec < b->tv_usec)
{
rslt->tv_sec = rslt->tv_usec = 0;
}
else
{
rslt->tv_sec = 0;
rslt->tv_usec = a->tv_usec - b->tv_usec;
}
}
else
{
rslt->tv_sec = a->tv_sec - b->tv_sec;
if (a->tv_usec < b->tv_usec)
{
rslt->tv_usec = a->tv_usec + 1000000 - b->tv_usec;
rslt->tv_sec--;
}
else
{
rslt->tv_usec = a->tv_usec - b->tv_usec;
}
}
}
class cProfiler
{
public:
cProfiler()
{
m_nInterval = 0 ;
memset (&prev, 0, sizeof (prev));
memset (&now, 0, sizeof (now));
memset (&interval, 0, sizeof (interval));
Start();
}
cProfiler (int nInterval = 100000)
{
m_nInterval = nInterval;
memset (&prev, 0, sizeof (prev));
memset (&now, 0, sizeof (now));
memset (&interval, 0, sizeof (interval));
Start();
}
void Start()
{
gettimeofday (&prev , (struct timezone*) 0);
}
void Stop()
{
gettimeofday (&now, (struct timezone*) 0);
__timediff (&now, &prev, &interval);
}
bool IsOk()
{
if (interval.tv_sec > (m_nInterval / 1000000))
{
return false;
}
if (interval.tv_usec > m_nInterval)
{
return false;
}
return true;
}
struct timeval* GetResult()
{
return &interval;
}
long GetResultSec()
{
return interval.tv_sec;
}
long GetResultUSec()
{
return interval.tv_usec;
}
private:
int m_nInterval;
struct timeval prev;
struct timeval now;
struct timeval interval;
};
void CAsyncSQL::ChildLoop()
{
cProfiler profiler(500000);
while (!m_bEnd)
{
m_sem.Wait();
int count = CopyQuery();
if (count <= 0)
{
continue;
}
AddCopiedQueryCount (count);
SQLMsg* p;
while (count--)
{
profiler.Start();
if (!PeekQueryFromCopyQueue (&p))
{
continue;
}
if (m_ulThreadID != mysql_thread_id (&m_hDB))
{
sys_log (0, "MySQL connection was reconnected. querying locale set");
while (!QueryLocaleSet());
m_ulThreadID = mysql_thread_id (&m_hDB);
}
if (mysql_real_query (&m_hDB, p->stQuery.c_str(), p->stQuery.length()))
{
p->uiSQLErrno = mysql_errno (&m_hDB);
sys_err ("AsyncSQL: query failed: %s (query: %s errno: %d)", mysql_error (&m_hDB), p->stQuery.c_str(), p->uiSQLErrno);
switch (p->uiSQLErrno)
{
case CR_SOCKET_CREATE_ERROR:
case CR_CONNECTION_ERROR:
case CR_IPSOCK_ERROR:
case CR_UNKNOWN_HOST:
case CR_SERVER_GONE_ERROR:
case CR_CONN_HOST_ERROR:
case ER_NOT_KEYFILE:
case ER_CRASHED_ON_USAGE:
case ER_CANT_OPEN_FILE:
case ER_HOST_NOT_PRIVILEGED:
case ER_HOST_IS_BLOCKED:
case ER_PASSWORD_NOT_ALLOWED:
case ER_PASSWORD_NO_MATCH:
case ER_CANT_CREATE_THREAD:
case ER_INVALID_USE_OF_NULL:
m_sem.Release();
sys_err ("AsyncSQL: retrying");
continue;
}
}
profiler.Stop();
if (!profiler.IsOk())
{
sys_log (0, "[QUERY : LONG INTERVAL(OverSec %ld.%ld)] : %s", profiler.GetResultSec(), profiler.GetResultUSec(), p->stQuery.c_str());
}
PopQueryFromCopyQueue();
if (p->bReturn)
{
p->Store();
PushResult (p);
}
else
{
delete p;
}
++m_iQueryFinished;
}
}
SQLMsg* p;
while (PeekQuery (&p))
{
if (m_ulThreadID != mysql_thread_id (&m_hDB))
{
sys_log (0, "MySQL connection was reconnected. querying locale set");
while (!QueryLocaleSet());
m_ulThreadID = mysql_thread_id (&m_hDB);
}
if (mysql_real_query (&m_hDB, p->stQuery.c_str(), p->stQuery.length()))
{
p->uiSQLErrno = mysql_errno (&m_hDB);
sys_err ("AsyncSQL::ChildLoop : mysql_query error: %s:\nquery: %s", mysql_error (&m_hDB), p->stQuery.c_str());
switch (p->uiSQLErrno)
{
case CR_SOCKET_CREATE_ERROR:
case CR_CONNECTION_ERROR:
case CR_IPSOCK_ERROR:
case CR_UNKNOWN_HOST:
case CR_SERVER_GONE_ERROR:
case CR_CONN_HOST_ERROR:
case ER_NOT_KEYFILE:
case ER_CRASHED_ON_USAGE:
case ER_CANT_OPEN_FILE:
case ER_HOST_NOT_PRIVILEGED:
case ER_HOST_IS_BLOCKED:
case ER_PASSWORD_NOT_ALLOWED:
case ER_PASSWORD_NO_MATCH:
case ER_CANT_CREATE_THREAD:
case ER_INVALID_USE_OF_NULL:
continue;
}
}
sys_log (0, "QUERY_FLUSH: %s", p->stQuery.c_str());
PopQuery (p->iID);
if (p->bReturn)
{
p->Store();
PushResult (p);
}
else
{
delete p;
}
++m_iQueryFinished;
}
}
int CAsyncSQL::CountQueryFinished()
{
return m_iQueryFinished;
}
void CAsyncSQL::ResetQueryFinished()
{
m_iQueryFinished = 0;
}
MYSQL* CAsyncSQL::GetSQLHandle()
{
return &m_hDB;
}
size_t CAsyncSQL::EscapeString (char* dst, size_t dstSize, const char* src, size_t srcSize)
{
if (0 == srcSize)
{
memset (dst, 0, dstSize);
return 0;
}
if (0 == dstSize)
{
return 0;
}
if (dstSize < srcSize * 2 + 1)
{
char tmp[256];
size_t tmpLen = sizeof (tmp) > srcSize ? srcSize : sizeof (tmp);
strlcpy (tmp, src, tmpLen);
sys_err ("FATAL ERROR!! not enough buffer size (dstSize %u srcSize %u src%s: %s)", dstSize, srcSize, tmpLen != srcSize ? "(trimmed to 255 characters)" : "", tmp);
dst[0] = '\0';
return 0;
}
return mysql_real_escape_string (GetSQLHandle(), dst, src, srcSize);
}
void CAsyncSQL2::SetLocale (const std::string & stLocale)
{
m_stLocale = stLocale;
QueryLocaleSet();
}
This is my AsyncSQL.h
#ifndef __INC_METIN_II_ASYNCSQL_H__
#define __INC_METIN_II_ASYNCSQL_H__
#include "../../libthecore/src/stdafx.h"
#include "../../libthecore/src/log.h"
#include "../../Ayarlar.h"
#include <string>
#include <queue>
#include <vector>
#include <map>
#include <mysql/server/mysql.h>
#include <mysql/server/errmsg.h>
#include <mysql/server/mysqld_error.h>
#include "Semaphore.h"
typedef struct _SQLResult
{
_SQLResult(): pSQLResult (NULL), uiNumRows (0), uiAffectedRows (0), uiInsertID (0) {}
~_SQLResult()
{
if (pSQLResult)
{
mysql_free_result (pSQLResult);
pSQLResult = NULL;
}
}
MYSQL_RES* pSQLResult;
uint32_t uiNumRows;
uint32_t uiAffectedRows;
uint32_t uiInsertID;
} SQLResult;
typedef struct _SQLMsg
{
_SQLMsg() : m_pkSQL (NULL), iID (0), uiResultPos (0), pvUserData (NULL), bReturn (false), uiSQLErrno (0) {}
~_SQLMsg()
{
auto first = vec_pkResult.begin();
auto past = vec_pkResult.end();
while (first != past)
{
delete * (first++);
}
vec_pkResult.clear();
}
void Store()
{
do
{
SQLResult* pRes = new SQLResult;
pRes->pSQLResult = mysql_store_result (m_pkSQL);
pRes->uiInsertID = mysql_insert_id (m_pkSQL);
pRes->uiAffectedRows = mysql_affected_rows (m_pkSQL);
if (pRes->pSQLResult)
{
pRes->uiNumRows = mysql_num_rows (pRes->pSQLResult);
}
else
{
pRes->uiNumRows = 0;
}
vec_pkResult.push_back (pRes);
}
while (!mysql_next_result (m_pkSQL));
}
SQLResult* Get()
{
if (uiResultPos >= vec_pkResult.size())
{
return NULL;
}
return vec_pkResult[uiResultPos];
}
bool Next()
{
if (uiResultPos + 1 >= vec_pkResult.size())
{
return false;
}
++uiResultPos;
return true;
}
MYSQL* m_pkSQL;
int iID;
std::string stQuery;
std::vector<SQLResult *> vec_pkResult;
unsigned int uiResultPos;
void* pvUserData;
bool bReturn;
unsigned int uiSQLErrno;
} SQLMsg;
class CAsyncSQL
{
public:
CAsyncSQL();
virtual ~CAsyncSQL();
void Quit();
bool Setup (const char* c_pszHost, const char* c_pszUser, const char* c_pszPassword, const char* c_pszDB, const char* c_pszLocale, bool bNoThread = false, int iPort = 0);
bool Setup (CAsyncSQL* sql, bool bNoThread = false);
bool Connect();
bool IsConnected()
{
return m_bConnected;
}
bool QueryLocaleSet();
void AsyncQuery (const char* c_pszQuery);
void ReturnQuery (const char* c_pszQuery, void* pvUserData);
SQLMsg* DirectQuery (const char* c_pszQuery);
DWORD CountQuery();
DWORD CountResult();
void PushResult (SQLMsg* p);
bool PopResult (SQLMsg** pp);
void ChildLoop();
MYSQL* GetSQLHandle();
int CountQueryFinished();
void ResetQueryFinished();
size_t EscapeString (char* dst, size_t dstSize, const char* src, size_t srcSize);
protected:
void Destroy();
void PushQuery (SQLMsg* p);
bool PeekQuery (SQLMsg** pp);
bool PopQuery (int iID);
bool PeekQueryFromCopyQueue (SQLMsg** pp );
INT CopyQuery();
bool PopQueryFromCopyQueue();
public:
int GetCopiedQueryCount();
void ResetCopiedQueryCount();
void AddCopiedQueryCount (int iCopiedQuery);
protected:
MYSQL m_hDB;
std::string m_stHost;
std::string m_stUser;
std::string m_stPassword;
std::string m_stDB;
std::string m_stLocale;
int m_iMsgCount;
int m_aiPipe[2];
int m_iPort;
std::queue<SQLMsg*> m_queue_query;
std::queue<SQLMsg*> m_queue_query_copy;
std::queue<SQLMsg*> m_queue_result;
volatile bool m_bEnd;
pthread_t m_hThread;
pthread_mutex_t* m_mtxQuery;
pthread_mutex_t* m_mtxResult;
CSemaphore m_sem;
int m_iQueryFinished;
unsigned long m_ulThreadID;
bool m_bConnected;
int m_iCopiedQuery;
};
class CAsyncSQL2 : public CAsyncSQL
{
public:
void SetLocale (const std::string & stLocale);
};
#endif
And this is the function the reason of the error ;
optional:1052 ;
#ifdef __cpp_lib_three_way_comparison
template<typename _Tp>
constexpr strong_ordering
operator<=>(const optional<_Tp>& __x, nullopt_t) noexcept
{ return bool(__x) <=> false; }
#else
After a see a document the microsoft release i'm gonna try <= > false; like this and take a error again..
Best Regards.
I ve no idea why it looks is getting bool(__x) <=> false as an bool and int comparison.
I would think you got some strange macro in your files included before to include the header that is going to break the standard code.
I would suggest you try to move above the standard headers and below them your 'user defined' headers.
#include <string>
#include <queue>
#include <vector>
#include <map>
#include <mysql/server/mysql.h>
#include <mysql/server/errmsg.h>
#include <mysql/server/mysqld_error.h>
#include "../../libthecore/src/stdafx.h"
#include "../../libthecore/src/log.h"
#include "../../Ayarlar.h"
#include "Semaphore.h"
EDIT:
i ve found the cause of the problem.
a macro defined in "libthrecore/stdafx.h" (i own the files that is using the author, they are public).
#ifndef false
#define false 0
#define true (!false)
#endif
it is causing false to be read as a int and is causing the spaceship operator to fails with the error shown by the author. Move up the standard headers or remove the macro to solve the error.
I'm trying to compare the first character of a string to see if it matches and if it does, I want to set the clipboard data. The string comes from the getclipboard function and set to const char* data and I have tried to set it to std::string but I get a different error from that.
Here is my Clipboard.cpp
#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;
}
I tried changing
data[0] = "1"
to
strcmp(data[0], 1) == 0
But I get a the same error.
The other problem I have is that the program only runs once in the sense that only the content of the clipboard is displayed and when I copy a different text, it doesn't get displayed.
TL;DR: Change
if(data[0] == "1" || data[0] == "7")
to
if(data[0] == '1' || data[0] == '7')
data is a char*, so dereferencing it with data[0] will give you a char. "1" is a string (char*) of length 1, which will result in an invalid comparison of char to char* (see the error).
What you probably want is the character '1'. We denote character literals in C++ with a single quote.
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'm making a game in C++, but I've been running into an issue I just can't figure out when it comes to the sound. I'm using SDL_Mixer, with Mix_Music for the music and Mix_Chunk for the sound effects, but for some reason when I try to load a sound effect file using MIX_LoadWAV it returns NULL.
The thing is, when I load the same file using MIX_LoadMUS (loading as music instead of sound effect), it loads fine.
I can't find any differences that would explain the issue; the only difference is Mix_LoadWAV instead of Mix_LoadMUS, but why? Mix_LoadMUS doesn't work for Mix_Chunk, or else I'd just use that, but ...
Here, I'll show you the code for the sound manager I use. MusicClip being a Mix_Music and SoundClip being a Mix_Chunk.
#include "stdafx.h"
#include "SoundManager.h"
#include "MusicClip.h"
#include "SoundClip.h"
SoundManager::SoundManager()
{
}
SoundManager::~SoundManager()
{
Shutdown();
}
bool SoundManager::Initialize()
{
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0)
{
printf("SDL could not initialize! SDL Error: %s\n", SDL_GetError());
}
if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048) < 0)
{
printf(" SDL_mixer :: Msx_OpenAudio %s\n", Mix_GetError());
return false;
}
return true;
}
void SoundManager::Shutdown()
{
for (unsigned int i = 0; i < m_axSoundClips.size(); i++)
{
delete m_axSoundClips[i];
m_axSoundClips[i] = nullptr;
}
m_axSoundClips.clear();
for (unsigned int i = 0; i < m_axMusicClips.size(); i++)
{
delete m_axMusicClips[i];
m_axMusicClips[i] = nullptr;
}
m_axMusicClips.clear();
{
std::map<std::string, Mix_Chunk*>::iterator it = m_axSounds.begin();
while (it != m_axSounds.end())
{
Mix_FreeChunk(it->second);
it->second = nullptr;
it++;
}
m_axSounds.clear();
}
{
std::map<std::string, Mix_Music*>::iterator it = m_axMusic.begin();
while (it != m_axMusic.end())
{
Mix_FreeMusic(it->second);
it->second = nullptr;
it++;
}
m_axMusic.clear();
}
Mix_CloseAudio();
}
MusicClip *SoundManager::CreateMusicClip(std::string p_sFilename)
{
MusicClip *Ret = nullptr;
std::map<std::string, Mix_Music*>::iterator it = m_axMusic.find(p_sFilename);
if (it == m_axMusic.end())
{
Mix_Music* Music = Mix_LoadMUS(p_sFilename.c_str());
if (Music == NULL) {
printf("Error; music will not play\n");
printf(p_sFilename.c_str());
printf("\n");
printf(Mix_GetError());
}
std::pair<std::string, Mix_Music*> Pair;
Pair = std::make_pair(p_sFilename, Music);
Ret = new MusicClip(Music);
}
else
Ret = new MusicClip(it->second);
m_axMusicClips.push_back(Ret);
return Ret;
}
SoundClip *SoundManager::CreateSoundClip(std::string p_sFilename)
{
SoundClip *Ret = nullptr;
std::map<std::string, Mix_Chunk*>::iterator it = m_axSounds.find(p_sFilename);
if (it == m_axSounds.end())
{
Mix_Chunk* Sound = Mix_LoadWAV(p_sFilename.c_str());
if (Sound == NULL) {
printf("\nError; sound will not play\n");
printf(p_sFilename.c_str());
printf("\n");
printf(Mix_GetError());
}
std::pair<std::string, Mix_Chunk*> Pair;
Pair = std::make_pair(p_sFilename, Sound);
Ret = new SoundClip(Sound);
}
else
Ret = new SoundClip(it->second);
m_axSoundClips.push_back(Ret);
return Ret;
}
Here's the code for MusicClip and SoundClip; They seem identical aside from me adding PlayOnce and fadeout to MusicClip.
#include "stdafx.h"
#include "SoundClip.h"
SoundClip::SoundClip()
{
m_pxClip = nullptr;
m_iChannel = -1;
}
SoundClip::~SoundClip()
{
m_pxClip = nullptr;
}
SoundClip::SoundClip(Mix_Chunk* p_pxClip)
{
m_pxClip = p_pxClip;
m_iChannel = -1;
}
void SoundClip::Play()
{
m_iChannel = Mix_PlayChannel(-1, m_pxClip, 0);
}
void SoundClip::Stop()
{
if (m_iChannel == -1)
return;
Mix_HaltChannel(m_iChannel);
m_iChannel = -1;
}
void SoundClip::Volume(int p_iVolume)
{
if (m_iChannel == -1)
return;
Mix_Volume(m_iChannel, p_iVolume);
}
void SoundClip::Pause()
{
if (m_iChannel == -1)
return;
if (Mix_Paused(m_iChannel))
{
Mix_Resume(m_iChannel);
}
else
{
Mix_Pause(m_iChannel);
}
}
-
// MusicClip.cpp
#include "stdafx.h"
#include "MusicClip.h"
MusicClip::MusicClip()
{
m_xClip = nullptr;
m_iChannel = -1;
}
MusicClip::~MusicClip()
{
m_xClip = nullptr;
m_iChannel = -1;
}
MusicClip::MusicClip(Mix_Music* p_xClip)
{
m_xClip = p_xClip;
m_iChannel = -1;
}
void MusicClip::Play()
{
m_iChannel = Mix_PlayMusic(m_xClip, -1);
}
void MusicClip::PlayOnce()
{
m_iChannel = Mix_PlayMusic(m_xClip, 1);
}
void MusicClip::Pause()
{
if (m_iChannel == -1)
return;
if ( Mix_PausedMusic() )
Mix_ResumeMusic();
else
Mix_Pause(m_iChannel);
}
void MusicClip::Volume(int p_iVolume)
{
Mix_VolumeMusic(p_iVolume);
oldVolume = p_iVolume;
}
void MusicClip::FadeOut()
{
if (oldVolume>0)
oldVolume--;
Mix_VolumeMusic(oldVolume);
}
void MusicClip::Stop()
{
if (m_iChannel == -1)
return;
Mix_HaltChannel(m_iChannel);
m_iChannel = -1;
}
And this is the code I use to call on the functions. (The soundManager was initialized earlier in the program to start up the BGM.) So this, using the Mix_Chunk* SFX2, won't work:
void GameState::playSFX(std::string FX)
{
SFX2 = soundManager.CreateSoundClip("../assets/sfx/sfx-bleep.wav");
SFX2->Volume(60);
SFX2->Play();
}
But for some reason, if I change SFX2 to a Mix_Music*, this DOES work.
void GameState::playSFX(std::string FX)
{
SFX2 = soundManager.CreateMusicClip("../assets/sfx/sfx-bleep.wav");
SFX2->Volume(60);
SFX2->Play();
}
What do I do? Mix_GetError() doesn't return anything either... If I write the path wrong it returns "couldn't open file", so clearly it can find/open the file, it just... won't? I can't just use Mix_Music for my sound effects either, because if I do they cancel out the music.
By the way, I don't know if it's related, but Mix_LoadMUS won't load non-wav files even though it's supposed to support .ogg and .mp3 too?
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.