The original post is on MSDN develop forums, cause the post there sometimes get lost, and the coding style is totally crash by HTML. So, I made one copy here for backup and clear the coding style for easy read.
Below link it the original post:
This post share source code of two functions: BackupMain() and RestoreMain() to backup and restore cemail.vol, The idea is very simple.
When doing backup, the method create a cemail_backup.vol (CEDB, too), enumerate all database and records from ceminl.vol and make a backup copy to cemail_backup.vol.
When doing restore, the method clear all records in cemail.vol, and then do the same thing as backup, just different direction.
Here is the BackupMail() function, used to backup cemail.vol:
BOOL BackupMail()
{
CEGUID ceguidCemail;
CEGUID ceguidBackUp;
CREATE_INVALIDGUID(&ceguidCemail);
CREATE_INVALIDGUID(&ceguidBackUp);
if (!CeMountDBVol(&ceguidCemail, L"cemail.vol", OPEN_EXISTING))
{
return FALSE;
}
if (!CeMountDBVol( &ceguidBackUp, L"\\cemail_backup.vol", CREATE_ALWAYS))
{
return FALSE;
}
HANDLE hDatabaseEnumHandle = INVALID_HANDLE_VALUE;
if ((hDatabaseEnumHandle = CeFindFirstDatabaseEx(&ceguidCemail, 0)) == INVALID_HANDLE_VALUE)
{
return FALSE;
}
CEOID ceoidFind = 0;
while (ceoidFind = CeFindNextDatabaseEx(hDatabaseEnumHandle, NULL))
{
HANDLE hDBOpened = INVALID_HANDLE_VALUE;
hDBOpened = CeOpenDatabaseEx(
&ceguidCemail,
&ceoidFind,
NULL,
NULL,
CEDB_AUTOINCREMENT,
NULL);
if (hDBOpened == INVALID_HANDLE_VALUE)
{
DWORD error = GetLastError();
return FALSE;
}
BY_HANDLE_DB_INFORMATION hDBOpenedInfo;
hDBOpenedInfo.wVersion = 1;
if (!CeGetDBInformationByHandle(hDBOpened, &hDBOpenedInfo))
{
DWORD dwError = GetLastError();
return FALSE;
}
CEOIDINFOEX cdDb;
CEOID ceoidFindRecorde = NULL;
CeOidGetInfoEx2(&ceguidCemail,ceoidFindRecorde, &cdDb);
CEOID ceoidDBaseCopy = 0;
if (!(ceoidDBaseCopy = CeCreateDatabaseEx2(&ceguidBackUp, &hDBOpenedInfo.infDatabase)))
{
DWORD dwErro = GetLastError();
return FALSE;
}
HANDLE hDBaseCopyHandle = INVALID_HANDLE_VALUE;
hDBaseCopyHandle = CeOpenDatabaseEx(\
&ceguidBackUp,
&ceoidDBaseCopy,
hDBOpenedInfo.infDatabase.szDbaseName,
0,
CEDB_AUTOINCREMENT,
NULL);
if (hDBaseCopyHandle == INVALID_HANDLE_VALUE)
{
return FALSE;
}
hDBOpenedInfo.wVersion = 1;
if (!CeGetDBInformationByHandle(hDBaseCopyHandle, &hDBOpenedInfo))
{
DWORD dwError = GetLastError();
return FALSE;
}
DWORD dwCpt = 0;
CEOID ceoidFindRecord = 0;
WORD dwPropId = 0;
CEPROPVAL* Buffer = NULL;
DWORD dwSizeOfBuffer = 0;
HANDLE hHeap = GetProcessHeap();
if (hHeap == NULL)
return FALSE;
while (ceoidFindRecord = CeReadRecordPropsEx(
hDBOpened,
CEDB_ALLOWREALLOC,
&dwPropId,NULL,
(LPBYTE*)&Buffer,
&dwSizeOfBuffer,
hHeap))
{
dwCpt++;
}
if (GetLastError() != ERROR_NO_MORE_ITEMS)
return false;
free(Buffer);
Buffer = NULL;
CeSeekDatabaseEx(hDBOpened, CEDB_SEEK_BEGINNING, 0, 0, NULL);
ceoidFindRecord = 0;
DWORD dwNumberOfRecordFound = 0;
while (dwNumberOfRecordFound++ < dwCpt)
{
ceoidFindRecord = CeReadRecordPropsEx(
hDBOpened,
CEDB_ALLOWREALLOC,
&dwPropId,
NULL,
(LPBYTE*)&Buffer,
&dwSizeOfBuffer,
hHeap);
if (!ceoidFindRecord)
{
DWORD dwError = GetLastError();
return FALSE;
}
CEOID ceoidRecordAdd;
ceoidRecordAdd = CeWriteRecordProps(
hDBaseCopyHandle,
0,
dwPropId,
Buffer);
if (!ceoidRecordAdd)
{
DWORD dwError = GetLastError();
return FALSE;
}
free(Buffer);
Buffer = NULL;
}
CloseHandle(hDBaseCopyHandle);
hDBaseCopyHandle = NULL;
}
if (!CeFlushDBVol(&ceguidCemail))
return FALSE;
if (!CeFlushDBVol(&ceguidBackUp))
return FALSE;
if (!CeUnmountDBVol(&ceguidCemail))
return FALSE;
if (!CeUnmountDBVol(&ceguidBackUp))
return FALSE;
return TRUE;
}
And this is the RestoreMail() function, user to restore cemail.vol:
BOOL RestoreMail()
{
CEGUID ceguidCemail;
CEGUID ceguidBackUp;
CREATE_INVALIDGUID(&ceguidCemail);
CREATE_INVALIDGUID(&ceguidBackUp);
if (!CeMountDBVol(&ceguidCemail, L"cemail.vol", OPEN_EXISTING))
{
return FALSE;
}
if (!CeMountDBVol(&ceguidBackUp, L"cemail_backup.vol", OPEN_EXISTING))
{
return FALSE;
}
HANDLE hDatabaseEnumHandle = INVALID_HANDLE_VALUE;
if ((hDatabaseEnumHandle = CeFindFirstDatabaseEx(&ceguidBackUp, 0)) == INVALID_HANDLE_VALUE)
{
return FALSE;
}
CEOID ceoidFind = 0;
// Delete old value
HANDLE hRemoveHandle = INVALID_HANDLE_VALUE;
CEOID oldid = 0;
if ((hRemoveHandle = CeFindFirstDatabaseEx(&ceguidCemail, 0)) == INVALID_HANDLE_VALUE)
{
return FALSE;
}
while (oldid = CeFindNextDatabaseEx(hRemoveHandle, NULL))
{
HANDLE oldHandle = INVALID_HANDLE_VALUE;
oldHandle = CeOpenDatabaseEx(
&ceguidCemail,
&oldid,
NULL,
NULL,
CEDB_AUTOINCREMENT,
NULL);
if (oldHandle == INVALID_HANDLE_VALUE)
return FALSE;
BY_HANDLE_DB_INFORMATION hDBOldOpenedInfo;
hDBOldOpenedInfo.wVersion = 1;
if (!CeGetDBInformationByHandle(oldHandle, &hDBOldOpenedInfo))
return FALSE;
DWORD dwOldCpt = 0;
CEOID ceoOldidFindRecord = 0;
WORD dwOldPropId = 0;
CEPROPVAL* oldBuffer = NULL;
DWORD dwOldSizeOfBuffer = 0;
HANDLE hOldHeap = GetProcessHeap();
if (hOldHeap == NULL)
return FALSE;
while (ceoOldidFindRecord = CeReadRecordPropsEx(
oldHandle,
CEDB_ALLOWREALLOC,
&dwOldPropId,
NULL,
(LPBYTE*)&oldBuffer,
&dwOldSizeOfBuffer,
hOldHeap))
{
dwOldCpt++;
}
if (GetLastError() != ERROR_NO_MORE_ITEMS)
return false;
free(oldBuffer);
oldBuffer = NULL;
CeSeekDatabaseEx(oldHandle, CEDB_SEEK_BEGINNING, 0, 0, NULL);
ceoOldidFindRecord = 0;
DWORD dwOldNumberOfRecordFound = 0;
while (dwOldNumberOfRecordFound++ < dwOldCpt)
{
ceoOldidFindRecord = CeReadRecordPropsEx(
oldHandle,
CEDB_ALLOWREALLOC,
&dwOldPropId,
NULL,
(LPBYTE*)&oldBuffer,
&dwOldSizeOfBuffer,
hOldHeap);
CeDeleteRecord(oldHandle,ceoOldidFindRecord);
}
CloseHandle(oldHandle);
oldHandle = NULL;
}
CloseHandle(hRemoveHandle);
hRemoveHandle = NULL;
while (ceoidFind = CeFindNextDatabaseEx(hDatabaseEnumHandle, NULL))
{
HANDLE hDBOpened = INVALID_HANDLE_VALUE;
hDBOpened = CeOpenDatabaseEx(
&ceguidBackUp,
&ceoidFind,
NULL,
NULL,
CEDB_AUTOINCREMENT,
NULL);
if (hDBOpened == INVALID_HANDLE_VALUE)
{
DWORD error = GetLastError();
return FALSE;
}
BY_HANDLE_DB_INFORMATION hDBOpenedInfo;
hDBOpenedInfo.wVersion = 1;
if (!CeGetDBInformationByHandle(hDBOpened, &hDBOpenedInfo))
{
return FALSE;
}
CEOID ceoidDBaseOriginal = 0;
HANDLE hDBaseOriginalHandle = INVALID_HANDLE_VALUE;
hDBaseOriginalHandle = CeOpenDatabaseEx2(
&ceguidCemail,
&ceoidDBaseOriginal,
hDBOpenedInfo.infDatabase.szDbaseName,
NULL,
CEDB_AUTOINCREMENT,
NULL);
if (hDBaseOriginalHandle == INVALID_HANDLE_VALUE)
{
if (GetLastError() == ERROR_FILE_NOT_FOUND)
{
CEOID ceoidDBaseCopy = 0;
// Trap error only if not a duplicate/existing db name
if(!(ceoidDBaseCopy = CeCreateDatabaseEx2(&ceguidCemail,
&hDBOpenedInfo.infDatabase)))
{
DWORD dwError = GetLastError();
return FALSE;
}
}
else
{
return FALSE;
}
}
ceoidDBaseOriginal = 0;
hDBaseOriginalHandle = INVALID_HANDLE_VALUE;
hDBaseOriginalHandle = CeOpenDatabaseEx2(
&ceguidCemail,
&ceoidDBaseOriginal,
hDBOpenedInfo.infDatabase.szDbaseName,
NULL,
CEDB_AUTOINCREMENT,
NULL);
if (hDBaseOriginalHandle == INVALID_HANDLE_VALUE)
{
return FALSE;
}
WORD dwPropId = 0;
CEPROPVAL* Buffer = NULL;
DWORD dwSizeOfBuffer = 0;
HANDLE hHeap = GetProcessHeap();
if (hHeap == NULL)
return FALSE;
BOOL bDBIsEmpty = FALSE;
CEOID ceoidFindRecord = 0;
while (!bDBIsEmpty)
{
ceoidFindRecord = CeReadRecordPropsEx(
hDBOpened,
CEDB_ALLOWREALLOC,
&dwPropId,
NULL,
(LPBYTE*)&Buffer,
&dwSizeOfBuffer,
hHeap);
if (!ceoidFindRecord)
{
if (GetLastError() != ERROR_NO_MORE_ITEMS)
return FALSE;
else
bDBIsEmpty = TRUE;
}
else
{
CEPROPVAL* temp;
temp = (CEPROPVAL*)malloc(dwSizeOfBuffer);
memcpy(temp, Buffer, dwSizeOfBuffer);
CEOID ceoidRecordAdd = 0;
ceoidRecordAdd = CeWriteRecordProps(
hDBaseOriginalHandle,
0,
dwPropId,
Buffer);
if (!ceoidRecordAdd)
return FALSE;
free(temp);
temp = NULL;
free(Buffer);
Buffer = NULL;
}
}
}
if (!CeFlushDBVol(&ceguidCemail)) return FALSE;
if (!CeFlushDBVol(&ceguidBackUp)) return FALSE;
if (!CeUnmountDBVol(&ceguidCemail)) return FALSE;
if (!CeUnmountDBVol(&ceguidBackUp)) return FALSE;
return TRUE;
}
I never tested it yet, and not really study the code carefully. But logically it should work fine. Actually, I still image that I can stop the application & service locked cemial.vol, and then I can just do a easy file copy…
沒有留言:
張貼留言