2008年12月16日星期二

mysql 数据库备份


mysqldump -h db481.1und1.de -P 3306 -udbo263011116 -pxy.cTPv8 db263011116 --compact --tables sms_history -w"f_clientid = '1' AND DATE_FORMAT(senddate,'%m') = DATE_FORMAT(CURRENT_TIMESTAMP() - INTERVAL 1 MONTH ,'%m')" | gzip > _DB/Backup/TESTSEITE_12-2008.gz



"--compact" :Produce less verbose output. This option enables the --skip-add-drop-table, --skip-add-locks, --skip-comments, --skip-disable-keys, and --skip-set-charset options.

2008年12月5日星期五

PHP:取得变量名

源程序:

/* 取得变量的名字 */
function getVarName(&$src)
{
//存储当前变量值
$save = $src;
//存储所有变量值
$allvar = $GLOBALS;
//在函数中不要直拉遍历$GLOBALS,会出现堆栈问题
foreach($allvar as $k=>$v)
{
//变量值相同,可能不是相同变量,因多个变量的值可能相同
if ($src == $v)
{
//改变当前变量$src的值
$src = 'change';
//如果$GLOBALS[$k]也跟着改变,那就是同一个变量。
if ($src == $GLOBALS[$k])
{
echo "\$$k name is $k
";
}
}
}
//还原变量值
$src = $save;
}
$test = "helo";
$test2 = "helo";
getVarName($test);
?>

改进后:
function getVarName(&$src)
{

$save = $src;
$allvar = $GLOBALS;
foreach($allvar as $k=>$v)
{
if ($src == $v)
{
$src = 'change';
if ($src == $GLOBALS[$k] && $k != 'argc')
{
//echo "\$$k name is $k
";
$src = $save;
return $k;
}
}
}
$src = $save;
}

2008年11月4日星期二

javascript 打印print 窗口


var invoiceWindow=window.open('','','width=1,height=1,location=NO,locationbar=NO,menubar=YES,screenX=100,screenY=100');
invoiceWindow.document.write("hallo, this is new window");
invoiceWindow.document.close(); // --> Sehr wichtig
invoiceWindow.print();
invoiceWindow.close();

2008年9月23日星期二

Prototype JS Event.observe



Event.observe(window, 'load', function()
{
Event.observe( 'searchBt', 'click', function(e)
{
ajaxListReceiver('{$clientId}');
getWinnerCount(0);
Event.stop(e);
});
});




var phrase = "This is SPAARRTTAAAA!";

$('somelink').observe('click', sayIt.bindAsEventListener(this, phrase));

function sayIt(event, phrase) {
console.log(phrase);
}

phrase = "Red sauce on PAASTAAAA!";





var obj = { name: 'A nice demo' };

function handler(e) {
var tag = Event.element(e).tagName.toLowerCase();
var data = $A(arguments);
data.shift();
alert(this.name + '\nClick on a ' + tag + '\nOther args: ' + data.join(', '));
}

Event.observe(document.body, 'click', handler.bindAsEventListener(obj, 1, 2, 3));
// Now any click on the page displays obj.name, the lower-cased tag name
// of the clicked element, and "1, 2, 3".




/*
* add click event
*
*/

// Attaching events
for (var i = items.length; i--; ) {
Event.observe(items[i], 'click', e_onclick, false);
}
// Detaching events
for (var i = items.length; i--; ) {
Event.stopObserving(items[i], 'click', e_onclick, false);
}



/*
* add click event with "return false"
*
*/
in html file:

Event.observe(window, 'load', function() {
Event.observe('button2', 'click', onchecktime);
});

if js file:

var onchecktime = function(event){
var element = Event.element(event);

alert(Event.pointerX(event));
Event.stop(event); // avoid page reloading
};

2008年9月22日星期一

Prototype JS Event.observe

CODE:
/*
*you'd want this line of code to run once the form exists in the DOM; but putting *inline scripts in the document is pretty obtrusive, so instead we'll go for a simple *approach that waits till the page is fully loaded:
*/
Event.observe(window, 'load', function() {
Event.observe('percent', 'change', selectProPercent);
}

in main.js:
var selectProPercent = function()
{
......
}

2008年9月19日星期五

mysql_real_escape_string(PHP) SQL中的特殊字符查询

Problem:

TABLE COL => "cb_spielhalle" with context "RT-Betzingen (Carl-Zeiss-Str.)|*|RT-Betzingen (Eisenbahnstr.)|*|Mössingen|*|Tübingen|*|Li.-Unterhausen"

sql有效查询 带"Mössingen"的数据:
SELECT * FROM jos_comprofiler WHERE cb_handy != '' AND (cb_spielhalle LIKE '%Mössingen%' ) AND ( cb_infoserhaltenper = 'SMS und E-Mail' OR cb_infoserhaltenper = 'nur SMS' ) AND cb_anrede LIKE '%Frau%'

PHP有效查询 带"Mössingen"的数据:
SELECT * FROM jos_comprofiler WHERE cb_handy != '' AND (cb_spielhalle LIKE '%Mössingen%' ) AND ( cb_infoserhaltenper = 'SMS und E-Mail' OR cb_infoserhaltenper = 'nur SMS' ) AND cb_anrede LIKE '%Frau%'

其中 AND (cb_spielhalle LIKE '%Mössingen%' ) 使用了mysql_real_escape_string();
$q .= $dataDbtablecol2." LIKE '%".mysql_real_escape_string($spielhalle)."%' OR ";

2008年4月11日星期五

_variant_t 到 CString 转换

数据类型转换函数

CString CZjyDlg::VariantToString(VARIANT var)
{
CString strValue;
_variant_t var_t;
_bstr_t bstr_t;
time_t cur_time;
CTime time_value;
COleCurrency var_currency;
switch(var.vt)
{
case VT_EMPTY:
case VT_NULL:strValue=_T("");break;
case VT_UI1:strValue.Format("%d",var.bVal);break;
case VT_I2:strValue.Format("%d",var.iVal);break;
case VT_I4:strValue.Format("%d",var.lVal);break;
case VT_R4:strValue.Format("%f",var.fltVal);break;
case VT_R8:strValue.Format("%f",var.dblVal);break;
case VT_CY:
var_currency=var;
strValue=var_currency.Format(0);
break;
case VT_BSTR:
var_t =var;
bstr_t=var_t;
strValue.Format("%s",(const char *)bstr_t);
break;
case VT_DATE:
cur_time=var.date;
time_value=cur_time;
strValue.Format("%A,%B,%d,%Y");
break;
case VT_BOOL:strValue.Format("%d",var.boolVal);break;
default:strValue=_T("");break;

}
return strValue;

}

2008年4月10日星期四

使用Adox取得MS Access 的table信息

1. import msadox.dll
#import "C:\Programme\Gemeinsame Dateien\System\ado\msadox.dll"

Problem:
Kompilierung läuft...
ADOBase.cpp
d:\project\dbinfo2\debug\msadox.tli(246) : error C2511: 'long __thiscall ADOX::Columns::Append(const class _variant_t &,enum ADOX::DataTypeEnum,long)' : Überladene Member-Funktion nicht in '' gefunden
d:\project\dbinfo2\debug\msadox.tli(346) : error C2556: 'enum ADOX::DataTypeEnum __thiscall ADOX::_Column::GetType(void)' : Überladene Funktion unterscheidet sich nur hinsichtlich des Rückgabetyps von 'enum DataTypeEnum __thiscall ADOX::_Column::Get
Type(void)'
d:\project\dbinfo2\debug\msadox.tlh(444) : Siehe Deklaration von 'GetType'
d:\project\dbinfo2\debug\msadox.tli(346) : error C2371: 'GetType' : Neudefinition; unterschiedliche Basistypen
d:\project\dbinfo2\debug\msadox.tlh(444) : Siehe Deklaration von 'GetType'
d:\project\dbinfo2\debug\msadox.tli(348) : error C2664: 'get_Type' : Konvertierung des Parameters 1 von 'enum ADOX::DataTypeEnum *' in 'enum DataTypeEnum *' nicht moeglich
Die Typen, auf die verwiesen wird, sind nicht verwandt; die Konvertierung erfordert einen reinterpret_cast-Operator oder eine Typumwandlung im C- oder Funktionsformat
d:\project\dbinfo2\debug\msadox.tli(353) : error C2511: 'void __thiscall ADOX::_Column::PutType(enum ADOX::DataTypeEnum)' : Überladene Member-Funktion nicht in '' gefunden
Fehler beim Ausführen von cl.exe.

ADOBase.obj - 5 Fehler, 0 Warnung(en)


问题原因:
与Dao冲突定义了同名的"DataTypeEnum" and "EOF"


解决方案:
#import "C:\Programme\Gemeinsame Dateien\System\ado\msadox.dll" rename("EOF", "adoXEOF") rename("DataTypeEnum","adoXDataTypeEnum")


2. use _CatalogPtr 取得Table Information
in ADOBase.h:
#import "C:\Programme\Gemeinsame Dateien\System\ado\msadox.dll" rename("EOF", "adoXEOF") rename("DataTypeEnum","adoXDataTypeEnum")
using namespace ADOX;
ADOX::_CatalogPtr m_pCatalog;
BOOL existTable(CString sTable);


in ADOBase.cpp:
BOOL ADOBase::existTable(CString sTable)
{

try
{
m_pCatalog.CreateInstance(__uuidof(Catalog));
m_pCatalog->PutActiveConnection(_variant_t((IDispatch *) m_pConnectionSpecial));

TablesPtr m_pTables = m_pCatalog->GetTables();

_Table* m_pTable = NULL;
//m_pTables = cat->Tables->Item[sTable];

if (m_pTables->get_Item(_variant_t(sTable), &m_pTable) == S_OK)
{
return true;

}
else
return false;

}
catch (_com_error &e)
{
m_nLastError=ADOLE_OPEN_FAILED;
HandleErrorAB(e, "existTable (DB", sTable);
PROTOCOL_ENTRY(0,0,"END (_com_error) ADOBase::existTable")
return false;

}
catch(...)
{
m_nLastError=ADOLE_OPEN_FAIL_UNHANDLED;
m_sLastError = "**** Unhandled exception! **** in Open";
HandleErrorAB();
PROTOCOL_ENTRY(0,0,"END (...error) ADOBase::existTable")
return false;

}


}

2008年3月20日星期四

C++ Linux 中mencpy(),get(),strcpy(),strcmp()....的函数原型

1 /*
2 * linux/lib/string.c
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 */
6
7 /*
8 * stupid library routines.. The optimized versions should generally be found
9 * as inline code in
10 *
11 * These are buggy as well..
12 */
13
14 #include
15
16 char * ___strtok = NULL;
17
18 char * strcpy(char * dest,const char *src)
19 {
20 char *tmp = dest;
21
22 while ((*dest++ = *src++) != '\0')
23 /* nothing */;
24 return tmp;
25 }
26
27 char * strncpy(char * dest,const char *src,size_t count)
28 {
29 char *tmp = dest;
30
31 while (count-- && (*dest++ = *src++) != '\0')
32 /* nothing */;
33
34 return tmp;
35 }
36
37 char * strcat(char * dest, const char * src)
38 {
39 char *tmp = dest;
40
41 while (*dest)
42 dest++;
43 while ((*dest++ = *src++) != '\0')
44 ;
45
46 return tmp;
47 }
48
49 char * strncat(char *dest, const char *src, size_t count)
50 {
51 char *tmp = dest;
52
53 if (count) {
54 while (*dest)
55 dest++;
56 while ((*dest++ = *src++)) {
57 if (--count == 0)
58 break;
59 }
60 }
61
62 return tmp;
63 }
64
65 int strcmp(const char * cs,const char * ct)
66 {
67 register signed char __res;
68
69 while (1) {
70 if ((__res = *cs - *ct++) != 0 || !*cs++)
71 break;
72 }
73
74 return __res;
75 }
76
77 int strncmp(const char * cs,const char * ct,size_t count)
78 {
79 register signed char __res = 0;
80
81 while (count) {
82 if ((__res = *cs - *ct++) != 0 || !*cs++)
83 break;
84 count--;
85 }
86
87 return __res;
88 }
89
90 char * strchr(const char * s,char c)
91 {
92 for(; *s != c; ++s)
93 if (*s == '\0')
94 return NULL;
95 return (char *) s;
96 }
97
98 size_t strlen(const char * s)
99 {
100 const char *sc;
101
102 for (sc = s; *sc != '\0'; ++sc)
103 /* nothing */;
104 return sc - s;
105 }
106
107 size_t strnlen(const char * s, size_t count)
108 {
109 const char *sc;
110
111 for (sc = s; *sc != '\0' && count--; ++sc)
112 /* nothing */;
113 return sc - s;
114 }
115
116 size_t strspn(const char *s, const char *accept)
117 {
118 const char *p;
119 const char *a;
120 size_t count = 0;
121
122 for (p = s; *p != '\0'; ++p) {
123 for (a = accept; *a != '\0'; ++a) {
124 if (*p == *a)
125 break;
126 }
127 if (*a == '\0')
128 return count;
129 ++count;
130 }
131
132 return count;
133 }
134
135 char * strpbrk(const char * cs,const char * ct)
136 {
137 const char *sc1,*sc2;
138
139 for( sc1 = cs; *sc1 != '\0'; ++sc1) {
140 for( sc2 = ct; *sc2 != '\0'; ++sc2) {
141 if (*sc1 == *sc2)
142 return (char *) sc1;
143 }
144 }
145 return NULL;
146 }
147
148 char * strtok(char * s,const char * ct)
149 {
150 char *sbegin, *send;
151
152 sbegin = s ? s : ___strtok;
153 if (!sbegin) {
154 return NULL;
155 }
156 sbegin += strspn(sbegin,ct);
157 if (*sbegin == '\0') {
158 ___strtok = NULL;
159 return( NULL );
160 }
161 send = strpbrk( sbegin, ct);
162 if (send && *send != '\0')
163 *send++ = '\0';
164 ___strtok = send;
165 return (sbegin);
166 }
167
168 void * memset(void * s,char c,size_t count)
169 {
170 char *xs = (char *) s;
171
172 while (count--)
173 *xs++ = c;
174
175 return s;
176 }
177
178 char * bcopy(const char * src, char * dest, int count)
179 {
180 char *tmp = dest;
181
182 while (count--)
183 *tmp++ = *src++;
184
185 return dest;
186 }
187
188 void * memcpy(void * dest,const void *src,size_t count)
189 {
190 char *tmp = (char *) dest, *s = (char *) src;
191
192 while (count--)
193 *tmp++ = *s++;
194
195 return dest;
196 }
197
198 void * memmove(void * dest,const void *src,size_t count)
199 {
200 char *tmp, *s;
201
202 if (dest <= src) {
203 tmp = (char *) dest;
204 s = (char *) src;
205 while (count--)
206 *tmp++ = *s++;
207 }
208 else {
209 tmp = (char *) dest + count;
210 s = (char *) src + count;
211 while (count--)
212 *--tmp = *--s;
213 }
214
215 return dest;
216 }
217
218 int memcmp(const void * cs,const void * ct,size_t count)
219 {
220 const unsigned char *su1, *su2;
221 signed char res = 0;
222
223 for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
224 if ((res = *su1 - *su2) != 0)
225 break;
226 return res;
227 }
228
229 /*
230 * find the first occurrence of byte 'c', or 1 past the area if none
231 */
232 void * memscan(void * addr, unsigned char c, size_t size)
233 {
234 unsigned char * p = (unsigned char *) addr;
235
236 while (size) {
237 if (*p == c)
238 return (void *) p;
239 p++;
240 size--;
241 }
242 return (void *) p;
243 }

20.03.2008 Aufgabe: Exclusiv Connection Access DB with Ado

1. Korrektur von Access Dantenbank verbindung mit Ado.Um Exception von DB_Close() zu überwinden,vor "if ( m_pADOpaelogbuch->bConnectionIsOpen() )" addiere "if (m_pADOpaelogbuch != NULL)", erst prüft mal die Abwesenheit der Pointobjekte "m_pADOpaelogbuch":

if (m_pADOpaelogbuch != NULL)
{

if ( m_pADOpaelogbuch->bConnectionIsOpen() )
{

if( m_pADOpaelogbuch->CloseRecordsetAdoDB() ||
m_pADOpaelogbuch->CloseConnections() )
{

delete m_pADOpaelogbuch;
m_pADOpaelogbuch = NULL;
error = NOT_ERROR;

}
else
{
error = ADO_DISCONNECT_ERROR;

}

}else
{
AddStringError((LPCTSTR)(CString("connect from paelogbuch to ") + plc.tgDB + CString(" has not been opend.")) );
error = ADO_CONNECT_ERROR;
}

}


2. Bei DB_Open():

if (!( m_pADOpaelogbuch = new ADOpaelogbuch((LPCTSTR)plc.tgDB) ))
{

error = ADO_CONNECT_ERROR;

}

ist "if (!( m_pADOpaelogbuch = new ADOpaelogbuch((LPCTSTR)plc.tgDB) ))" ungültig, weil "ADOpaelogbuch(tgDB)" kein returned Value.
Codes:

//////////////////////////////////////////////////////////////////////
// *
// * Editor: zengzn@gmail.com 20.03.2008
// * after testing is known, that "CAdoExternDB *m_pExternDB;"
// * makes m_pExternDB not NULL, exceptions will only been thrown by
// * "m_pExternDB->bConnectionIsOpen()" if "new CAdoExternDB((LPCTSTR)sDB,nMode)"
// * tries to connect a unexsiting file.
// * It does not matter if the exlusive connection fails
// * or opens a wrong file(.txt or others), no exception throws out.
// *
//////////////////////////////////////////////////////////////////////
if (plc.existFile(sDB))
{

m_pExternDB = new CAdoExternDB( (LPCTSTR)sDB, nMode );
if (m_pExternDB != NULL)
{

if (m_pExternDB->bConnectionIsOpen() )

error = NOT_ERROR;

else

error = ADO_CONNECT_ERROR;


}
else

error = ADO_CONNECT_ERROR;


}
else
{

error = OPEN_FILE_FAILED;

}

3. Exclusive connection to Access DB with Ado:
in ADOBase.cpp:

OpenAdoDB(AdoNs::_ConnectionPtr& pConnDB, const char* sDatabasePath, AdoNs::ConnectModeEnum nMode)
...
pConnDB->Mode = nMode;

nMode can be:

msado15.tlh
enum ConnectModeEnum
{

adModeUnknown = 0,
adModeRead = 1,
adModeWrite = 2,
adModeReadWrite = 3,
adModeShareDenyRead = 4,
adModeShareDenyWrite = 8,
adModeShareExclusive = 12,
adModeShareDenyNone = 16,
adModeRecursive = 4194304

};


4. Versuche die Möglichkeit die DB Einspielung mit ADO-Exclusive Connection,wenn andere Client verbindung nach DB-Server hat, warte mal kurz(1 min ? ) und versucht nochmal, sonst "adModeUnknown" und alert den Benutzer ob weiter geht.

2008年3月19日星期三

Fehler Meldung bei unpack.exe (1)




Vermutliche Fehlerpunte:
Bei remote access von ferner Client kann diese Fehler erscheinen. Weil die Pfad"C:\Dokumente und Einstellung\LocalService\Desktop" enthält kein Benutzer, welche Benutzer-name kann auf remote computer eingelogen? anonymouse? Guest? oder "LocalService"?


Mögliche Lösung:

in Public.cpp add:

CPublic::CPublic()
{

...
CPublic::sSicherungDir = ( ( CPublic::sSicherungDir == _T("") || !existsDir(CPublic::sSicherungDir) ) ? _T("C:\\") : CPublic::sSicherungDir );

}


in CUnpackView.cpp CALLBACK CUnpackView::BrowseCallbackProc() ändert:

////////////////////////////////////////////////////////
//'d:\\' can not be recognised by SHGetPathFromIDList()
// must be changed into 'd:\'
////////////////////////////////////////////////////////
dir.Replace("\\\\","\\");
...
switch(uMsg)
{
case BFFM_INITIALIZED: //initial
hasInitial =true;
::SendMessage(hwnd,BFFM_SETSELECTION,TRUE,(LPARAM)(LPCTSTR)dir ); //"d:\\datenversicherung"
//AfxMessageBox("BFFM_INITIALIZED");

break;

case BFFM_SELCHANGED: //path changed
{
/////////////////////////////////////////////////////
// * modified by zengzn@gmail.com on 14.03.08
// * to avoid SHGetPathFromIDList()twice running
// * before "case BFFM_INITIALIZED" has been done
/////////////////////////////////////////////////////
if (hasInitial)
{
char curr[MAX_PATH];

SHGetPathFromIDList((LPCITEMIDLIST)lParam,curr);

//CString s;
//s.Format("BFFM_SELCHANGED, curr: %s",curr);
//AfxMessageBox(s);

if(curr[strlen(curr)-1]==92)
sprintf(curr,"%s",curr);
else
sprintf(curr,"%s\\",curr);

::SendMessage(hwnd,BFFM_SETSTATUSTEXT,0,(LPARAM)curr);

}

}
break;



2008年3月13日星期四

VC++: Accelerator 快捷键

In datei Project.rc:
Mansche wenn Projekte Verzeichniss direkt kopiert aus war, könnte diese Accelerator disable sein. Die lösung ist so wie ""C",ID_EDIT_COPY,..." auszukommentieren.

/////////////////////////////////////////////////////////////////////////////
//
// Accelerator
//

IDR_MAINFRAME ACCELERATORS PRELOAD MOVEABLE PURE
BEGIN
"N", ID_FILE_NEW, VIRTKEY,CONTROL
"O", ID_FILE_OPEN, VIRTKEY,CONTROL
"S", ID_FILE_SAVE, VIRTKEY,CONTROL
"P", ID_FILE_PRINT, VIRTKEY,CONTROL
"Z", ID_EDIT_UNDO, VIRTKEY,CONTROL
"X", ID_EDIT_CUT, VIRTKEY,CONTROL
"C", ID_EDIT_COPY, VIRTKEY,CONTROL
"V", ID_EDIT_PASTE, VIRTKEY,CONTROL
VK_BACK, ID_EDIT_UNDO, VIRTKEY,ALT
VK_DELETE, ID_EDIT_CUT, VIRTKEY,SHIFT
VK_INSERT, ID_EDIT_COPY, VIRTKEY,CONTROL
VK_INSERT, ID_EDIT_PASTE, VIRTKEY,SHIFT
VK_F6, ID_NEXT_PANE, VIRTKEY
VK_F6, ID_PREV_PANE, VIRTKEY,SHIFT
END

2008年3月7日星期五

软件2.0概念图

使用静态变量提高performance

In Project Unpack, die "CPublic plc" will be called for many times, each calling will run "CPublic::CPublic()" once. It takes a lot of rumtime to intial again and again those variables in "CPublic::CPublic()".

The solusion is: define these varables as static, so once "CPublic::CPublic()" be call, these variables will be valued. Next time will not be valued again.

codes:

public.h

static CString sInstallDir;
static CString sApoWorkDir;
static CString sSicherungDir;
static CString sVersionA3000;

static int nDBError;
static int nADOError;
static int nVersionA3000;


public.cpp

CString CPublic::sInstallDir =_T("");
CString CPublic::sApoWorkDir =_T("");
CString CPublic::sSicherungDir =_T("");
CString CPublic::sVersionA3000 =_T("");
int CPublic::nDBError = NOT_ERROR;
int CPublic::nADOError = NOT_ERROR;
int CPublic::nVersionA3000 = NOT_ERROR;
//********************************************************************************************
CPublic::CPublic()
{
//AfxMessageBox("call public!");

sDBError = _T("");
sADOError = _T("");
//nDBError = NOT_ERROR; //otherweise the valud is default with 1598884628
//nADOError = NOT_ERROR;
sSicherungDBError = _T("");
nSicherungDBError = NOT_ERROR;
nA3queryErrorLevel = 0;
sDaSiLaufwerk =_T("");
sPaeDatDir =_T("");

bReclaimDirProtect = false;

///////////////////////////////////////////////////////////////
//
// * to avoid reloading of some functions in CPublic::CPublic()
// * by checking the value of these static variable
//
///////////////////////////////////////////////////////////////
if (CPublic::sInstallDir.IsEmpty())
CPublic::sInstallDir = (LPCTSTR)m_reg.GetRegInstallDir(); //A3000 install dir C:\\A3000

sRezepturDir = "C:\\Rezeptur"; //valude in CUnpackView::OnCheckRezeptur()

sSourceDB = (LPCTSTR)((CPublic::sInstallDir) + CString("\\Database\\Apollo.mdb"));

//static
//---- * open apllo.mdb to get the parameter : sichrungdir
if (CPublic::sVersionA3000.IsEmpty())
{
CPublic::nDBError = openDB(); //sourceDB! get the version info
//get version info from apollo.mdb table version
CPublic::nVersionA3000 = m_versionA3000.m_versionsnummer;
CPublic::sVersionA3000.Format("%d", CPublic::nVersionA3000);
//CString s;
//s.Format("%d",m_version.m_versionsnummer);
//AfxMessageBox(s);
closeDB();
}
//---- *

//static
//---- *
if (CPublic::sSicherungDir.IsEmpty())
{
CPublic::nADOError = ADO_openDB();
//Get sicherungDir from regedit else apollo.mdb
CPublic::sSicherungDir = m_reg.GetRegDasiPath();
CPublic::sSicherungDir = ( ( CPublic::sSicherungDir == _T("") || !existsDir(CPublic::sSicherungDir) ) ? sDaSiLaufwerk : CPublic::sSicherungDir );
}

//static
//sApoWorkDir not allowed be null or folder not exists
if (CPublic::sApoWorkDir.IsEmpty())
{
CPublic::sApoWorkDir = ( sPaeDatDir == _T("") ? _T("C:\\Apo_Work") : sPaeDatDir );
mdDirectory(CPublic::sApoWorkDir);
}
//---- *




//AfxMessageBox(sApoWorkDir);
if(!CPublic::sInstallDir.IsEmpty())
{
sReportUrl = (LPCTSTR) ((CPublic::sInstallDir) + CString("\\Sicherungsentpacken_report.txt"));
sA3query = (LPCTSTR) ((CPublic::sInstallDir) + CString("\\a3query"));
sA3info = (LPCTSTR) ((CPublic::sInstallDir) + CString("\\A3info"));
sTool = (LPCTSTR) ((CPublic::sInstallDir) + CString("\\tool"));
sA3Task = (LPCTSTR) ((CPublic::sInstallDir) + CString("\\A3Task"));
sA3000bat = (LPCTSTR) ((CPublic::sInstallDir) + CString("\\a3000.bat"));
sJournalBat = (LPCTSTR) ((CPublic::sInstallDir) + CString("\\Journal.bat"));
sJDcomInfo = (LPCTSTR) ((CPublic::sInstallDir) + CString("\\jdcom_information"));
sJDcomApo = (LPCTSTR) ((CPublic::sInstallDir) + CString("\\jdcom_apotheke"));
//sTgDB = (LPCTSTR) (InstallDir + CString("\\Database\\Apollo.mdb"));
//ATISERV = (LPCTSTR) (InstallDir + CString("\\ATIServ"));
//ALifeService = (LPCTSTR) (InstallDir + CString("\\ALifeService"));
}


sA3000BatProtocolFile = "C:\\_A3000_BAT_PROTOKOLL.txt";
sJournalBatProtocolFile = "C:\\_JOURNAL_BAT_journal_PROTOKOLL.txt";


}


in other classes
will be call as "CPublic::sInstallDir" but not "plc.sInstallDir"

在MFC下定义全局变量和全局函数

用MFC制作的工程由很多文件构成,它不能象一般C++程序那样随意在类外定义全局变量,在这里要想定义能被工程内多个文件共享的全局变量和函数必须用一些特殊方法才行。实际上有多种方法可以实现,这里只介绍两种方法。

  一、在应用程序类中定义

  用MFC生成的工程中都有一个名为CxxxApp的类,它派生于CWinApp类。这个类主要进行程序的初始化,生成文档、视图对象等工作。我们可以把需要全局访问的变量和函数定义为这个类的成员变量和成员函数,就可以实现全局访问了。

  从严格意义上讲,这种变量和函数并不是全局的,因为它仍然只是类中的成员,只是由于我们很容易获得CxxxApp类的指针,所以我们可以在文档、视 图、对话框以及各种自定义类中访问到它们,达到与全局变量类似的效果。访问时用函数“AfxGetApp()”获得CxxxApp类的指针,用 “AfxGetApp()->成员”访问变量或函数。

  例:

  Test.h:(应用程序类头文件)

class CTestApp : public CWinApp
{
 public:
  int x; //全局变量
  int f(int y); //全局函数
  …………
};

  Test.cpp:(应用程序类程序文件)

int CTestApp::f(int y) //全局函数定义
{
 y++;
 return y;
}

  定义在CTestApp类中的变量和函数可以在其它类中被访问。比如在视图的某函数中要访问变量x和函数f():

void CTestView::xyz()
{
 CTestApp *app = (CTestApp *)AfxGetApp(); //生成指向应用程序类的指针
 app->x = 0; //访问变量x
 int z = app->f(1); //访问函数f()
 …………
}

  这样,变量x和函数f()可以视作为全局的。

  用这种方法实现的全局变量和全局函数虽比较简单,但也有缺点,一是访问不太方便,每次都需要获取应用程序类的指针;再就是把一些与应用程序类本身无关的变量和函数放在里面,使这个类看上去怪怪的,破坏了类的封装。

  二、用静态变量和静态函数实现

  很喜欢API函数的那种调用方法,不论在哪个类中只要用“::API函数”就可以调用了。合理利用静态类型(static)可以实现与此相似的全局变量和全局函数。

  静态变量和静态函数有如下性质:

  若在一个类中用关键字static声明数据成员,则这个数据成员就只存在一个拷贝,无论该类创建了多少个实例,它始终只存在一个,即使该类的实例一个也没创建,它也存在。

  若在一个类中用关键字static声明函数,该函数可以用“类名::函数名”方式访问,无需引用该类的实例,甚至这个类的实例可以不存在。

  利用这个性质实现的全局变量和函数使用起来很方便。

  值得注意的是,全局变量和全局函数最好集中封装,不要在文档、视图等类内部定义,这样用起来才有全局的感觉。

  例:

  1、添加一个没有基类的新类,设类名起为CPublic,姑且称之为公用类

  单击“Insert”菜单下的“New Class”命令,选择“Class type”为“Generic Class”,在“Name”栏中填入类名“CPublic”,单击“OK”,则新类建立完毕。

  2、包含公用类的头文件,使各个类都能访问它

  CPublic的头文件应包含在应用程序类的头文件中,这样在其它类中引用CPublic类时就不需要再包含了。

  Test.h:(应用程序类头文件)

#include "Public.h" //包含公用类头文件

class CTestApp : public CWinApp
{
…………
};

  3、在公用类中定义全局变量和全局函数,均使用static修饰,静态变量还必须在类外定义和初始化

  Public.h:(公用类头文件)

class CPublic
{
public:
CPublic();
virtual ~CPublic();

public:
static int x; //全局变量
static int time; //全局变量
static int f(int y); //全局函数
…………
}

  在公用类中对静态变量进行初始化和定义函数体:

  Public.cpp:(公用类程序文件)

int CPublic::x = 0; //初始化全局变量
int CPublic::time; //定义全局变量

CPublic::CPublic()
{

}

CPublic::~CPublic()
{

}

int CPublic::f(int y) //全局函数,这里不要再加static
{
y++;
return y;
}

  4、全局量的使用

  使用变量:CPublic::变量名

  使用函数:CPublic::函数()

  如在视图的某函数中访问变量x和函数f():

void CTestView::xyz()
{
CPublic::x = 0; //访问变量x
CPublic::time = CPublic::f(1); //访问函数f()
…………
}

  在其它类中访问x、time和f()的方法与此相同。

  5、几点注意:

  ① 由于静态量可独立于类存在,不需要生成CPublic类的实例。

  ② 静态数据成员的定义和初始化必须在类外进行,如例中x的初始化;变量time虽然没有初始化,但也必须在类外进行定义。由于没有生成CPublic类的实例,所以它的构造函数和析构函数都不会被执行,在里面做什么工作都没有什么意义。

  ③ 如果静态函数需要访问CPublic类内的变量,这些变量也必须为静态的。因为非静态量在不生成实例时都不会存在。 如:

class CPublic
{
public:
int x; //内部变量
static int f(int y) //全局函数
{
x++;
return x;
};
…………
};

  这里x虽为类内成员,但如果不生成CPublic类的实例,就会出现函数f()存在,而变量x不存在的问题。

  总之,用没有实例的类管理全局量是一个不错的选择,它具有集中管理,使用方便的好处。当然,除非特别必要,全局量还是少用为好,一个好的编程者决不会随意滥用全局量的,一个封装做得不好的程序,在修改维护时会让你吃足苦头。

2008年2月29日星期五

几个常用网络测试命令

Ping

  Ping是测试网络联接状况以及信息包发送和接收状况非常有用的工具,是网络测试最

  常用的命令。Ping向目标主机(地址)发送一个回送请求数据包,要求目标主机收到请求后给予答复,从而判断网络的响应时间和本机是否与目标主机(地址)联通。

  如果执行Ping不成功,则可以预测故障出现在以下几个方面:网线故障,网络适配器配置不正确,IP地址不正确。如果执行Ping成功而网络仍无法使用,那么问题很可能出在网络系统的软件配置方面,Ping成功只能保证本机与目标主机间存在一条连通的物理路径。

  命令格式:

  ping IP地址或主机名 [-t] [-a] [-n count] [-l size]

  参数含义:

  -t不停地向目标主机发送数据;

  -a 以IP地址格式来显示目标主机的网络地址 ;

  -n count 指定要Ping多少次,具体次数由count来指定 ;

  -l size 指定发送到目标主机的数据包的大小。

   例如当您的机器不能访问Internet,首先您想确认是否是本地局域网的故障。假定局域网的代理服务器IP地址为202.168.0.1,您可以使用 Ping避免202.168.0.1命令查看本机是否和代理服务器联通。又如,测试本机的网卡是否正确安装的常用命令是ping 127.0.0.1。

  Tracert

  Tracert命令用来显示数据包到达目标主机所经过的路径,并显示到达每个节点的时间。命令功能同Ping类似,但它所获得的信息要比Ping命令详细得多,它把数据包所走的全部路径、节点的IP以及花费的时间都显示出来。该命令比较适用于大型网络。

  命令格式:

  tracert IP地址或主机名 [-d][-h maximumhops][-j host_list] [-w timeout]

  参数含义:

  -d 不解析目标主机的名字;

  -h maximum_hops 指定搜索到目标地址的最大跳跃数;

  -j host_list 按照主机列表中的地址释放源路由;

  -w timeout 指定超时时间间隔,程序默认的时间单位是毫秒。

  例如大家想要了解自己的计算机与目标主机www.cce.com.cn之间详细的传输路径信息,可以在MS-DOS方式输入tracertwww.cce.com.cn。

  如果我们在Tracert命令后面加上一些参数,还可以检测到其他更详细的信息,例如使用参数-d,可以指定程序在跟踪主机的路径信息时,同时也解析目标主机的域名。

  Netstat

  Netstat命令可以帮助网络管理员了解网络的整体使用情况。它可以显示当前正在活动的网络连接的详细信息,例如显示网络连接、路由表和网络接口信息,可以统计目前总共有哪些网络连接正在运行。

  利用命令参数,命令可以显示所有协议的使用状态,这些协议包括TCP协议、UDP协议以及IP协议等,另外还可以选择特定的协议并查看其具体信息,还能显示所有主机的端口号以及当前主机的详细路由信息。

  命令格式:

  netstat [-r] [-s] [-n] [-a]

  参数含义:

  -r 显示本机路由表的内容;

  -s 显示每个协议的使用状态(包括TCP协议、UDP协议、IP协议);

  -n 以数字表格形式显示地址和端口;

  -a 显示所有主机的端口号。

  Winipcfg

  Winipcfg命令以窗口的形式显示IP协议的具体配置信息,命令可以显示网络适配器的物理地址、主机的IP地址、子网掩码以及默认网关等,还可以查看主机名、DNS服务器、节点类型等相关信息。其中网络适配器的物理地址在检测网络错误时非常有用。

  命令格式:

  winipcfg [/?] [/all]

  参数含义:

  /all 显示所有的有关IP地址的配置信息;

  /batch [file] 将命令结果写入指定文件;

  /renew_ all 重试所有网络适配器;

  /release_all 释放所有网络适配器;

  /renew N 复位网络适配器 N;

  /release N 释放网络适配器 N。

  在Microsoft的Windows 95及其以后的操作系统中,都可以运行以上命令。

2008年2月27日星期三

Boost regex Regular Express

[[:digit:]] 数字
[[:word:]] 字符加底划线

[:a-zA-Z:] 自定义字符集

\\\\ 一条\

Symbol Meaning
c Match the literal character c once, unless it is one of the special characters.
^ Match the beginning of a line.
. Match any character that isn't a newline.
$ Match the end of a line.
| Logical OR between expressions.
() Group subexpressions.
[] Define a character class.
* Match the preceding expression zero or more times.
+ Match the preceding expression one ore more times.
? Match the preceding expression zero or one time.
{n} Match the preceding expression n times.
{n,} Match the preceding expression at least n times.
{n, m} Match the preceding expression at least n times and at most m times.
d Match a digit.
D Match a character that is not a digit.
w Match an alpha character, including the underscore.
W Match a character that is not an alpha character.
s Match a whitespace character (any of t, n, r, or f).
S Match a non-whitespace character.
t Tab.
n Newline.
r Carriage return.
f Form feed.
m Escape m, where m is one of the metacharacters described above: ^, ., $, |, (), [], *, +, ?, , or /.

重要参考:
http://blog.chinaunix.net/u2/62093/showart_484483.html

2008年2月26日星期二

Boost regex backslash 问题

regex eps_change_blash("\"); //throw exception causes of a "bad_pattern".The problem is that
//have to escape the backslash once because of how C literals are interpreted
//and again because of how characters in regular expressions are interpreted.

Lösung:
regex eps_change_blash("\\");
or:
boost::regex expression("\", boost::regbase::literal);






Beispiel: use sourceDB(c:\backup\dbinfo.mdb) to repalce c:/apo_work/dbinfo.mdb
comes the problem "c:backupdbinfo.mdb"
Lösung: \\\\ for just once \

CString CDBinfoListCt::replaceSourceDB(CString s)
{
regex eps_sql_sourceDB("^.*\'c:\/apo_work\/dbinfo\.mdb\'$");
regex eps_sql_change_sourceDB("(c:/apo_work/dbinfo\.mdb)");
regex eps_change_blash("\\\\"); // \\\\ backslash for c, for boost... god!!!

cmatch what; // a array to store the matching string

std::string stdReplace;
CString sTmp;
CString sTmpDB;


if(regex_match(s, what, eps_sql_sourceDB))
{


stdReplace = (LPCTSTR)sourceDB;
stdReplace = boost::regex_replace(stdReplace,eps_change_blash,"\\\\\\\\");
sTmpDB.Format("%s",stdReplace.c_str());

sTmp.Format("%s",what[0]);
stdReplace = (LPCTSTR)sTmp;
stdReplace = boost::regex_replace(stdReplace,eps_sql_change_sourceDB,(LPCTSTR)sTmpDB);

sTmp.Format("%s",stdReplace.c_str());
return sTmp;

}
else
{
return s;

}


}

2008年2月7日星期四

std::string,char,Cstring

CString <--> std::string

CString sString
std::string stdString;

//
stdString = (LPCTSTR)sString;
//
sString = stdString.c_str();
sString = stdString.data();

//string 转换为 char 型
char* str = strdup ( stdString.c_str() );
cout << str << endl;

char 转换为 string 型
char* str = "char 转换为 string 型";
stdString = str;

2008年2月5日星期二

VC++ 日期格式

函数strftime()的操作有些类似于sprintf():识别以百分号(%)开始的格式命令集合,格式化输出结果放在一个字符串中。格式化命令说明串strDest中各种日期和时间信息的确切表示方法。格式串中的其他字符原样放进串中。格式命令列在下面,它们是区分大小写的。

%a 星期几的简写
%A 星期几的全称
%b 月分的简写
%B 月份的全称
%c 标准的日期的时间串
%C 年份的后两位数字
%d 十进制表示的每月的第几天
%D 月/天/年
%e 在两字符域中,十进制表示的每月的第几天
%F 年-月-日
%g 年份的后两位数字,使用基于周的年
%G 年分,使用基于周的年
%h 简写的月份名
%H 24小时制的小时
%I 12小时制的小时
%j 十进制表示的每年的第几天
%m 十进制表示的月份
%M 十时制表示的分钟数
%n 新行符
%p 本地的AM或PM的等价显示
%r 12小时的时间
%R 显示小时和分钟:hh:mm
%S 十进制的秒数
%t 水平制表符
%T 显示时分秒:hh:mm:ss
%u 每周的第几天,星期一为第一天 (值从0到6,星期一为0)
%U 第年的第几周,把星期日做为第一天(值从0到53)
%V 每年的第几周,使用基于周的年
%w 十进制表示的星期几(值从0到6,星期天为0)
%W 每年的第几周,把星期一做为第一天(值从0到53)
%x 标准的日期串
%X 标准的时间串
%y 不带世纪的十进制年份(值从0到99)
%Y 带世纪部分的十进制年份
%z,%Z 时区名称,如果不能得到时区名称则返回空字符。
%% 百分号

DAO问题: Unrecognized database format

If you are linking with the MFC DLL, you can specify that you want MFC to use DAO 3.6 by inserting the following line of code before you open an Access 2000 database:

AfxGetModuleState()->m_dwVersion = 0x0601;


Insert this line in the CYourApp::Initinstance() function of your program.

If you are building with the static MFC libraries, following are the steps to get static builds of MFC to use DAO 3.6:
1. Modify the Daocore.cpp file in the MFC SRC directory. You will receive the following comment:

// Determine whether to use DAO 3.6, 3.5, or 3.0
// Use DAO 3.0 if DLL build and not built with MFC 4.21 or later
// Use DAO 3.6 if MFC 6.01 or later
// otherwise, DAO 3.5



Add the following lines:

#undef _MFC_VER
#define _MFC_VER 0x0601



2. Rebuild the library for the variant you need. For example, to build the static MFC library, debug version, non-Unicode, with no browser files use the following command at the command prompt in the MFC\SRC folder:

nmake DEBUG=1


for release:
nmake DEBUG=0


for unicode builds:
nmake DEBUG=1 UNICODE=1
nmake DEBUG=0 UNICODE=1

加入boost/regex.hpp库后静态编译通不过的问题--LNK2005 产生原因及解决方法

许多Visual C++的使用者都碰到过LNK2005:symbol already defined和LNK1169:one or more multiply defined symbols found这样的链接错误,而且通常是在使用第三方库时遇到的。对于这个问题,有的朋友可能不知其然,而有的朋友可能知其然却不知其所以然,那么本文就试图为大家彻底解开关于它的种种疑惑。

大家都知道,从C/C++源程序到可执行文件要经历两个阶段:(1)编译器将源文件编译成汇编代码,然后由汇编器(assembler)翻译成机器指令 (再加上其它相关信息)后输出到一个个目标文件(object file,VC的编译器编译出的目标文件默认的后缀名是.obj)中;(2)链接器(linker)将一个个的目标文件(或许还会有若干程序库)链接在一起生成一个完整的可执行文件。

编译器编译源文件时会把源文件的全局符号(global symbol)分成强(strong)和弱(weak)两类传给汇编器,而随后汇编器则将强弱信息编码并保存在目标文件的符号表中。那么何谓强弱呢?编译器认为函数与初始化了的全局变量都是强符号,而未初始化的全局变量则成了弱符号。比如有这么个源文件:

extern int errorno;
int buf[2] = {1,2};
int *p;

int main()
{
return 0;
}


其中main、buf是强符号,p是弱符号,而errorno则非强非弱,因为它只是个外部变量的使用声明。

有了强弱符号的概念,我们就可以看看链接器是如何处理与选择被多次定义过的全局符号:

规则1: 不允许强符号被多次定义(即不同的目标文件中不能有同名的强符号);


规则2: 如果一个符号在某个目标文件中是强符号,在其它文件中都是弱符号,那么选择强符号;


规则3: 如果一个符号在所有目标文件中都是弱符号,那么选择其中任意一个;


由上可知多个目标文件不能重复定义同名的函数与初始化了的全局变量,否则必然导致LNK2005和LNK1169两种链接错误。可是,有的时候我们并没有在自己的程序中发现这样的重定义现象,却也遇到了此种链接错误,这又是何解?嗯,问题稍微有点儿复杂,容我慢慢道来。

众所周知,ANSI C/C++ 定义了相当多的标准函数,而它们又分布在许多不同的目标文件中,如果直接以目标文件的形式提供给程序员使用的话,就需要他们确切地知道哪个函数存在于哪个目标文件中,并且在链接时显式地指定目标文件名才能成功地生成可执行文件,显然这是一个巨大的负担。所以C语言提供了一种将多个目标文件打包成一个文件的机制,这就是静态程序库(static library)。开发者在链接时只需指定程序库的文件名,链接器就会自动到程序库中寻找那些应用程序确实用到的目标模块,并把(且只把)它们从库中拷贝出来参与构建可执行文件。几乎所有的C/C++开发系统都会把标准函数打包成标准库提供给开发者使用(有不这么做的吗?)。

程序库为开发者带来了方便,但同时也是某些混乱的根源。我们来看看链接器是如何解析(resolve)对程序库的引用的。

在符号解析(symbol resolution)阶段,链接器按照所有目标文件和库文件出现在命令行中的顺序从左至右依次扫描它们,在此期间它要维护若干个集合:(1)集合E是将被合并到一起组成可执行文件的所有目标文件集合;(2)集合U是未解析符号(unresolved symbols,比如已经被引用但是还未被定义的符号)的集合;(3)集合D是所有之前已被加入到E的目标文件定义的符号集合。一开始,E、U、D都是空的。

(1): 对命令行中的每一个输入文件f,链接器确定它是目标文件还是库文件,如果它是目标文件,就把f加入到E,并把f中未解析的符号和已定义的符号分别加入到U、D集合中,然后处理下一个输入文件。

(2): 如果f是一个库文件,链接器会尝试把U中的所有未解析符号与f中各目标模块定义的符号进行匹配。如果某个目标模块m定义了一个U中的未解析符号,那么就把 m加入到E中,并把m中未解析的符号和已定义的符号分别加入到U、D集合中。不断地对f中的所有目标模块重复这个过程直至到达一个不动点(fixed point),此时U和D不再变化。而那些未加入到E中的f里的目标模块就被简单地丢弃,链接器继续处理下一输入文件。

(3): 如果处理过程中往D加入一个已存在的符号,或者当扫描完所有输入文件时U非空,链接器报错并停止动作。否则,它把E中的所有目标文件合并在一起生成可执行文件。


VC带的编译器名字叫cl.exe,它有这么几个与标准程序库有关的选项: /ML、/MLd、/MT、/MTd、/MD、/MDd。这些选项告诉编译器应用程序想使用什么版本的C标准程序库。/ML(缺省选项)对应单线程静态版的标准程序库(libc.lib);/MT对应多线程静态版标准库(libcmt.lib),此时编译器会自动定义_MT宏;/MD对应多线程DLL版 (导入库msvcrt.lib,DLL是msvcrt.dll),编译器自动定义_MT和_DLL两个宏。后面加d的选项都会让编译器自动多定义一个 _DEBUG宏,表示要使用对应标准库的调试版,因此/MLd对应调试版单线程静态标准库(libcd.lib),/MTd对应调试版多线程静态标准库 (libcmtd.lib),/MDd对应调试版多线程DLL标准库(导入库msvcrtd.lib,DLL是msvcrtd.dll)。虽然我们的确在编译时明白无误地告诉了编译器应用程序希望使用什么版本的标准库,可是当编译器干完了活,轮到链接器开工时它又如何得知一个个目标文件到底在思念谁?为了传递相思,我们的编译器就干了点秘密的勾当。在cl编译出的目标文件中会有一个专门的区域(关心这个区域到底在文件中什么地方的朋友可以参考COFF和 PE文件格式)存放一些指导链接器如何工作的信息,其中有一种就叫缺省库(default library),这些信息指定了一个或多个库文件名,告诉链接器在扫描的时候也把它们加入到输入文件列表中(当然顺序位于在命令行中被指定的输入文件之后)。说到这里,我们先来做个小实验。写个顶顶简单的程序,然后保存为main.c :

/* main.c */
int main() { return 0; }


用下面这个命令编译main.c(什么?你从不用命令行来编译程序?这个......) :

cl /c main.c


/c是告诉cl只编译源文件,不用链接。因为/ML是缺省选项,所以上述命令也相当于: cl /c /ML main.c 。如果没什么问题的话(要出了问题才是活见鬼!当然除非你的环境变量没有设置好,这时你应该去VC的bin目录下找到vcvars32.bat文件然后运行它。),当前目录下会出现一个main.obj文件,这就是我们可爱的目标文件。随便用一个文本编辑器打开它(是的,文本编辑器,大胆地去做别害怕),搜索"defaultlib"字符串,通常你就会看到这样的东西: "-defaultlib:LIBC -defaultlib:OLDNAMES"。啊哈,没错,这就
是保存在目标文件中的缺省库信息。我们的目标文件显然指定了两个缺省库,一个是单线程静态版标准库libc.lib(这与/ML选项相符),另外一个是oldnames.lib(它是为了兼容微软以前的C/C++开发系统)。

VC的链接器是link.exe,因为main.obj保存了缺省库信息,所以可以用

link main.obj libc.lib


或者

link main.obj


来生成可执行文件main.exe,这两个命令是等价的。但是如果你用

link main.obj libcd.lib


的话,链接器会给出一个警告: "warning LNK4098: defaultlib "LIBC" conflicts with use of other libs; use /NODEFAULTLIB:library",因为你显式指定的标准库版本与目标文件的缺省值不一致。通常来说,应该保证链接器合并的所有目标文件指定的缺省标准库版本一致,否则编译器一定会给出上面的警告,而LNK2005和LNK1169链接错误则有时会出现有时不会。那么这个有时到底是什么时候?呵呵,别着急,下面的一切正是为喜欢追根究底的你准备的。

建一个源文件,就叫mylib.c,内容如下:

/* mylib.c */
#i nclude

void foo()
{
printf("%s","I am from mylib!\n");
}




cl /c /MLd mylib.c


命令编译,注意/MLd选项是指定libcd.lib为默认标准库。lib.exe是VC自带的用于将目标文件打包成程序库的命令,所以我们可以用

lib /OUT:my.lib mylib.obj


将mylib.obj打包成库,输出的库文件名是my.lib。接下来把main.c改成:

/* main.c */
void foo();

int main()
{
foo();
return 0;
}




cl /c main.c


编译,然后用

link main.obj my.lib


进行链接。这个命令能够成功地生成main.exe而不会产生LNK2005和LNK1169 链接错误,你仅仅是得到了一条警告信息:"warning LNK4098: defaultlib "LIBCD" conflicts with use of other libs; use /NODEFAULTLIB:library"。我们根据前文所述的扫描规则来分析一下链接器此时做了些啥。

一开始E、U、D都是空集,链接器首先扫描到main.obj,把它加入E集合,同时把未解析的foo加入U,把main加入D,而且因为 main.obj的默认标准库是libc.lib,所以它被加入到当前输入文件列表的末尾。接着扫描my.lib,因为这是个库,所以会拿当前U中的所有符号(当然现在就一个foo)与my.lib中的所有目标模块(当然也只有一个mylib.obj)依次匹配,看是否有模块定义了U中的符号。结果 mylib.obj确实定义了foo,于是它被加入到E,foo从U转移到D,mylib.obj引用的printf加入到U,同样地, mylib.obj指定的默认标准库是libcd.lib,它也被加到当前输入文件列表的末尾(在libc.lib的后面)。不断地在my.lib库的各模块上进行迭代以匹配U中的符号,直到U、D都不再变化。很明显,现在就已经到达了这么一个不动点,所以接着扫描下一个输入文件,就是libc.lib。链接器发现libc.lib里的printf.obj里定义有printf,于是printf从U移到D,而printf.obj被加入到E,它定义的所有符号加入到D,它里头的未解析符号加入到U。链接器还会把每个程序都要用到的一些初始化操作所在的目标模块(比如crt0.obj等)及它们所引用的模块(比如malloc.obj、free.obj等)自动加入到E中,并更新U和D以反应这个变化。事实上,标准库各目标模块里的未解析符号都可以在库内其它模块中找到定义,因此当链接器处理完libc.lib时,U一定是空的。最后处理libcd.lib,因为此时U已经为空,所以链接器会抛弃它里面的所有目标模块从而结束扫描,然后合并E中的目标模块并输出可执行文件。

上文描述了虽然各目标模块指定了不同版本的缺省标准库但仍然链接成功的例子,接下来你将目睹因为这种不严谨而导致的悲惨失败。

修改mylib.c成这个样子:

#include

void foo()
{
// just a test , don"t care memory leak
_malloc_dbg( 1, _NORMAL_BLOCK, __FILE__, __LINE__ );
}

其中_malloc_dbg不是ANSI C的标准库函数,它是VC标准库提供的malloc的调试版,与相关函数配套能帮助开发者抓各种内存错误。使用它一定要定义_DEBUG宏,否则预处理器会把它自动转为malloc。继续用

cl /c /MLd mylib.c
lib /OUT:my.lib mylib.obj


编译打包。当再次用

link main.obj my.lib


进行链接时,我们看到了什么?天哪,一堆的LNK2005加上个贵为"fatal error"的LNK1169垫底,当然还少不了那个LNK4098。链接器是不是疯了?不,你冤枉可怜的链接器了,我拍胸脯保证它可是一直在尽心尽责地照章办事。

一开始E、U、D为空,链接器扫描main.obj,把它加入E,把foo加入U,把main加入D,把libc.lib加入到当前输入文件列表的末尾。接着扫描my.lib,foo从U转移到D,_malloc_dbg加入到U,libcd.lib加到当前输入文件列表的尾部。然后扫描 libc.lib,这时会发现libc.lib里任何一个目标模块都没有定义_malloc_dbg(它只在调试版的标准库中存在),所以不会有任何一个模块因为_malloc_dbg而加入E,但是每个程序都要用到的初始化模块(如crt0.obj等)及它们所引用的模块(比如malloc.obj、 free.obj等)还是会自动加入到E中,同时U和D被更新以反应这个变化。当链接器处理完libc.lib时,U只剩_malloc_dbg这一个符号。最后处理libcd.lib,发现dbgheap.obj定义了_malloc_dbg,于是dbgheap.obj加入到E,它里头的未解析符号加入U,它定义的所有其它符号也加入D,这时灾难便来了。之前malloc等符号已经在D中(随着libc.lib里的malloc.obj加入E而加入的),而dbgheap.obj又定义了包括malloc在内的许多同名符号,这引发了重定义冲突,链接器只好中断工作并报告错误。

现在我们该知道,链接器完全没有责任,责任在我们自己的身上。是我们粗心地把缺省标准库版本不一致的目标文件(main.obj)与程序库 (my.lib)链接起来,导致了大灾难。解决办法很简单,要么用/MLd选项来重编译main.c;要么用/ML选项重编译mylib.c。

在上述例子中,我们拥有库my.lib的源代码(mylib.c),所以可以用不同的选项重新编译这些源代码并再次打包。可如果使用的是第三方的库,它并没有提供源代码,那么我们就只有改变自己程序的编译选项来适应这些库了。但是如何知道库中目标模块指定的默认库呢?其实VC提供的一个小工具便可以完成任务,这就是dumpbin.exe。运行下面这个命令

dumpbin /DIRECTIVES my.lib


然后在输出中找那些"Linker Directives"引导的信息,你一定会发现每一处这样的信息都会包含若干个类似"-defaultlib:XXXX"这样的字符串,其中XXXX便代表目标模块指定的缺省库名。

知道了第三方库指定的默认标准库,再用合适的选项编译我们的应用程序,就可以避免LNK2005和LNK1169 链接错误。喜欢IDE的朋友,你一样可以到 "Project属性" -> "C/C++" -> "代码生成(code generation)" -> "运行时库(run-time library)" 项下设置应用程序的默认标准库版本,这与命令行选项的效果是一样的。

终极解决办法:

在 Project/Setting/Link/General中的 Project Options: 加入 /FORCE:MULTIPLE即可。


来源:LNK2005 产生原因及解决方法-相当详细!(转载)

2008年2月1日星期五

VC++,指针对象与对象

void f(){
Person p;
p.age = 27;
p.name = "Winnetou";

Person *p_p = &p; // pointer to a Person
p_p->age = 32; // overwrites Winnetou's age
p_p->name = "Old Shatterhand";
// equivalently:
(*p_p).age = 32;
(*p_p).name = "Old Shatterhand";

}

指针的销毁:


(1)指针变量没有被初始化。任何指针变量刚被创建时不会自动成为NULL指针,它的缺省值是随机的,它会乱指一气。所以,指针变量在创建的同时应当被初始化,要么将指针设置为NULL,要么让它指向合法的内存。例如

char *p = NULL;
char *str = (char *) malloc(100);



(2)指针p被free或者delete之后,没有置为NULL,让人误以为p是个合法的指针。参见7.5节。

(3)指针操作超越了变量的作用范围。这种情况让人防不胜防,示例程序如下:
class A
{
public:
void Func(void){ cout << “Func of class A” << endl; }

};
void Test(void)
{
A *p;
{
A a;
p = &a; // 注意 a 的生命期

}
p->Func(); // p是“野指针”

}



函数Test在执行语句p->Func()时,对象a已经消失,而p是指向a的,所以p就成了“野指针”。但奇怪的是我运行这个程序时居然没有出错,这可能与编译器有关。

2008年1月31日星期四

Clistctrl自动下滚

pList.EnsureVisible(nRow,true);

2008年1月30日星期三

VC++ 改变Dialog窗口大小及定位,SetWindowPos()

1.引用库函数 #include "easysize.h",见:
codeproject::Easysize

2.函数SetWindowPos
原型为BOOL SetWindowPos(const CWnd * pWndInsertAfter,int x,int y,int cx,int cy,UINT nFlags);
pWndInsertAfter为指向标识窗口类型的CWnd对象的指针。
x,y为窗口左上角的坐标。
cx,cy为窗口的宽与高。
nFlags确定窗口的大小及位置。当为SWP_NOSIZE时,忽略cx,cy。当为SWP_NOMOVE时,忽略x,y。


3.代码:
BEGIN_EASYSIZE_MAP(CUnpackConfirm)
EASYSIZE(IDOK,ES_KEEPSIZE,ES_KEEPSIZE,ES_BORDER,ES_BORDER,0)
EASYSIZE(IDCANCEL,ES_KEEPSIZE,ES_KEEPSIZE,ES_BORDER,ES_BORDER,0)
EASYSIZE(IDC_STATIC_TEXT,IDC_STATIC_TITLE,ES_BORDER,ES_BORDER,ES_BORDER,0)

END_EASYSIZE_MAP

BOOL CUnpackConfirm::OnInitDialog()
{

CDialog::OnInitDialog();


// * set for easysize.h *
INIT_EASYSIZE;

if(!t_ColorStatic) //
t_ColorStatic.SubclassDlgItem(IDC_STATIC_TITLE,this);


if(!s_ColorStatic) //
s_ColorStatic.SubclassDlgItem(IDC_STATIC_TEXT,this);


intialTitleFont();
intialTextFont();

t_ColorStatic.SetWindowText("Sollen jetzt folgende Daten zurückgespielt werden?");

//--get CView pointer
CMDIFrameWnd *pFrame = (CMDIFrameWnd*)AfxGetApp()->m_pMainWnd;
CMDIChildWnd *pChild = (CMDIChildWnd *) pFrame->GetActiveFrame();
CUnpackView *pView = (CUnpackView *) pChild->GetActiveView();
//--

CString text (_T(""));

lHigh = 200;

switch (pView->nGroupFocus)
{
case GROUP_UNPACK:
if (pView->m_pageUnpack.m_pUnpackListCtrl.isApolloChecked)
{
text += "- Apollo.mdb.gz\n";
addHigh(); //lHigh += 10;

......

setText(text);

UpdateData(false);
Invalidate();

//MFC: CWnd::SetWindowPos
CRect Rect1;
pFrame->GetWindowRect(&Rect1); //get size and position of mainframe

//CRect Rect2;
//GetDlgItem(IDC_STATIC_TEXT)->GetWindowRect(&Rect2); // ???????
//Rect2.bottom = lHigh + Rect2.bottom;


long x, y;
x = Rect1.left + (Rect1.Width() - 420)/2;
y = Rect1.top + (Rect1.Height() - lHigh)/2;

CUnpackConfirm::SetWindowPos(NULL,
x , //left
y, //top
420, //width
lHigh, // hight.
SWP_SHOWWINDOW);


UPDATE_EASYSIZE;

UpdateData();
Invalidate();

return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE

}

CString 剖析

CString类功能强大,比STL的string类有过之无不及.新手使用CString时,都会被它强大
的功能所吸引.然而由于对它内部机制的不了解,新手在将CString向C的字符数组转换时
容易出现很多问题.因为CString已经重载了LPCTSTR运算符,所以CString类向const
char *转换时没有什么麻烦,如下所示:

char a[100];
CString str("aaaaaa");
strncpy(a,(LPCTSTR)str,sizeof(a));

或者如下:
strncpy(a,str,sizeof(a));
以上两种用法都是正确地.因为strncpy的第二个参数类型为const char *.所以编译器
会自动将CString类转换成const char *.很多人对LPCTSTR是什么东西迷惑不解,让我们
来看看:
1.LP表示长指针,在win16下有长指针(LP)和短指针(P)的区别,而在win32下是没有区别
的,都是32位.所以这里的LP和P是等价的.
2.C表示const
3.T是什么东西呢,我们知道TCHAR在采用UNICODE方式编译时是wchar_t,在普通时编译成char
那么就可以看出LPCTSTR(PCTSTR)在UINCODE时是const wchar_t *,PCWSTR,LPCWSTR,在
多字节字符模式时是const char *,PCSTR,LPCSTR.
接下来我们看在非UNICODE情况下,怎样将CString转换成char *,很多初学者都为了方便
采用如下方法:
(char *)(LPCSTR)str.这样对吗?我们首先来看一个例子:
CString str("aa");
strcpy((char *)(LPCTSTR)str,"aaaaaaaa");
cout<<(LPCTSTR)str<<endl;

在Debug下运行出现了异常,我们都知道CString类内部有自己的字符指针,指向一个已分
配的字符缓冲区.如果往里面写的字符数超出了缓冲区范围,当然会出现异常.但这个程
序在Release版本下不会出现问题.原来对CString类已经进行了优化.当需要分配的内存
小于64字节时,直接分配64字节的内存,以此类推,一般CString类字符缓冲区的大小为
64,128,256,512...这样是为了减少内存分配的次数,提高速度.
那有人就说我往里面写的字符数不超过它原来的字符数,不就不会出错了,比如
CString str("aaaaaaa");
strcpy((char *)(LPCTSTR)str,"aa");
cout<<(LPCTSTR)str<<endl;

这样看起来是没什么问题.我们再来看下面这个例子:
CString str("aaaaaaa");
strcpy((char *)(LPCTSTR)str,"aa");
cout<<(LPCTSTR)str<<endl;
cout<<str.GetLength()<<endl;

我们看到str的长度没有随之改变,继续为7而不是2.还有更严重的问题:
CString str("aaaaaaa");
CString str1 = str;
strcpy((char *)(LPCTSTR)str,"aa");
cout<<(LPCTSTR)str<<endl;
cout<<(LPCTSTR)str1<<endl;

按说我们只改变了str,str1应该没有改变呀,可是事实时他们都变成了"aa".难道str和
str1里面的字符指针指向的缓冲区是一个.我们在Effective C++里面得知,如果你的类
内部有包含指针,请为你的类写一个拷贝构造函数和赋值运算符.不要让两个对象内部的
指针指向同一区域,而应该重新分配内存.难道是微软犯了错?
原来这里还有一个"写时复制"和"引用计数"的概念.CString类的用途很广,这样有可能
在系统内部产生大量的CString临时对象.这时为了优化效率,就采用在系统软件内部广
泛使用的"写时复制"概念.即当从一个CString产生另一个CString并不复制它的字符缓
冲区内容,而只是将字符缓冲区的"引用计数"加1.当需要改写字符缓冲区内的内容时,才
分配内存,并复制内容.以后我会给出一个"写时复制"和"引用计数"的例子
我们回到主题上来,当我们需要将CString转换成char *时,我们应该怎么做呢?其时只是
麻烦一点,如下所示:
CString str("aaaaaaa");
strcpy(str.GetBuffer(10),"aa");
str.ReleaseBuffer();

当我们需要字符数组时调用GetBuffer(int n),其中n为我们需要的字符数组的长度.使
用完成后一定要马上调用ReleaseBuffer();
还有很重要的一点就是,在能使用const char *的地方,就不要使用char *

2008年1月29日星期二

VC++ 删除整个文件夹

int CPublic::removeDir(CString lpszPath)
{
lpszPath += '\0';

SHFILEOPSTRUCT FileOp;
FileOp.fFlags = FOF_NOCONFIRMATION;
FileOp.hNameMappings = NULL;
FileOp.hwnd = NULL;
FileOp.lpszProgressTitle = NULL;
FileOp.pFrom = lpszPath;
FileOp.pTo = NULL;
FileOp.wFunc = FO_DELETE;

if ( SHFileOperation( &FileOp ) == 0 )
return NOT_ERROR;
else
return DEL_TREE_ERROR;
}


意见:
CString strWorkAreaPath;
char path[MAX_PATH];
strcpy(path,"E:\\文件夹\\aa.txt");
SetCurrentDirectory(_T("C:\\"));
strWorkAreaPath = path;

strWorkAreaPath += '\0';
SHFILEOPSTRUCT fileop;
fileop.fFlags = FOF_ALLOWUNDO ;
fileop.hwnd = NULL;
fileop.pFrom = strWorkAreaPath;
fileop.pTo = NULL;
fileop.wFunc = FO_DELETE;
fileop.fAnyOperationsAborted = TRUE;
fileop.hNameMappings = NULL;
fileop.lpszProgressTitle = _T("正在删除文件");
// fileop.fFlags &= ~FOF_ALLOWUNDO;
SHFileOperation(&fileop);

这样才叫删除文件,你的代码是删除文件夹

注意:
关键在于,lpszPath 如 "d:\\aaaa\\TFG\0" 必须有个"\0",但是用 lpszPath = lpszPath + "\0"的办法加不上。

2008年1月28日星期一

VC++, CString to CTime, CTime to CString

CString to CTime:
//"20071221_094910_IF.A3P.gz"
sYear = sName.Mid(0,4);
sMonth = sName.Mid(4,2);
sDay = sName.Mid(6,2);
sHour = sName.Mid(9,2);
sMin = sName.Mid(11,2);
sSec = sName.Mid(13,2);

nYear = atoi((LPCTSTR)sYear);
nMonth = atoi((LPCTSTR)sMonth);
nDay = atoi((LPCTSTR)sDay);
nHour = atoi((LPCTSTR)sHour);
nMin = atoi((LPCTSTR)sMin);
nSec = atoi((LPCTSTR)sSec);

CTime *dynamicTime;
dynamicTime = new CTime(nYear,nMonth,nDay,nHour,nMin,nSec,0);
DateTime = *dynamicTime;
delete dynamicTime;

CTime to CString:
CString s = m_timeFrom.Format( "%Y-%m-%d %H:%M:%S" );

VC++ boost: regex应用

下载boost_1_34_1.zip,解压
安装:
  1、打开vs2005在菜单tools中选择Visual Studio 2005 Command Prompt,打开已配置好环境的命令行。
  2、进入目录boost_1_34_1\libs\regex\build,
  编译文件:nmake -f vc8.mak
  安装(将编译好的文件复制到vs2005的特定目录下):nmake -f vc8.mak install
  删除临时文件:nmake -f vc8.mak clean
  3、Tools->Options->Projects and Solutions->VC++ Directories->Include files添加boost_1_34_1路径

  初次使用提示找不到libboost_regex-vc80-mt-gd-1_34_1.lib文件,到网上搜了下解决方法为:将 libboost_regex-vc80-mt-gd-1_34.lib改名libboost_regex-vc80-mt-gd-1_34_1.lib 放到vs或工程目录下。
4.
#include <boost/regex.hpp>
using namespace boost;
...
regex expression("^([0-9]{8})_([0-9]{6})_([[:word:]]+)\.([[:word:]]+)\.gz$");
cmatch what; // a array to store the matching string
if(regex_match(sName, what, expression
{
...

2008年1月25日星期五

_access 可判断文件夹是否存在及访问权限

////////////////////////////////////////////////////////////////////
//
// * only check if the directory exists,
// * can not comfirm if a dir accessable
//
////////////////////////////////////////////////////////////////////
DWORD dwAttr = GetFileAttributes(sDir);
if(dwAttr == 0xFFFFFFFF) //Directory doesn't exists
return false;

return true;


//////////////////////////////////////////////
// * 最终解决方法:
//////////////////////////////////////////////
#include "stdafx.h"
#include "io.h"


BOOL existDir(sDir )
{
/* Check for exist */
if( (_access( sDir , 0 )) != -1 ) //"C:\\windows"
{
return true;

}
else
{
return false;

}

}

2008年1月22日星期二

VC++ 从数据文件一次读一行

[问题提出]
一数据文件一行一条记录,我用file.readstring()一次读一行,并对读取的数据做一些处理;
请问:while(文件还没到结尾)
{
file.readstring();
...

}
??文件还没到结尾如何判断?
如果,到了指定位置不读了,过一会儿再读又如何做?
[解决方法]
while()中不用另加判断条件了,因为CStdioFile::ReadString()本身就是判断标志,若没有了(文件到头)返回NULL,因此:while(file.ReadString(s)){}就可.
[程序实现]
假设你已有了名为ts.txt的文件在你的工程目录下:
{
CStdioFile file;
CString sss;
char ccc[100];
DWORD o=0;
int ol=0;
file.Open("ts.txt",CFile::modeRead);
while(file.ReadString(sss))
{
ol++;
if(ol>1)//读两次就不读了.
break;

}
o=file.GetPosition();//记录上次的结果(读到哪了)
.................
file.Seek(o,0);//接着上回读
while(file.ReadString(sss))
{
strcpy(ccc,sss);
AfxMessageBox(ccc);
}

}

我的代码:
int CDBinfoListCt::checkReport(CString sReportFile)
{
CStdioFile file;
CString str;
CString sDollar("$$$");
CString sProtocolOK("OK!");
try
{
if (file.Open(sReportFile,CFile::modeRead|CFile::shareDenyNone))
{
while(file.ReadString(str))
{
if(str.Find(sDollar) != -1 && str.Find(sProtocolOK) != -1)
{ //AfxMessageBox("no error for a3000.bat: "+ str);
return NOT_ERROR;
}
}
}
else
{
return OPEN_FILE_FAILED;
}
}
catch(CFileException *e)
{
CString str;
str.Format("reason:%d",e->m_cause);
AfxMessageBox((LPCTSTR)str); //error C2660: 'MessageBoxA' : Funktion akzeptiert keine 1 Parameter
file.Abort();
e->Delete();
}
return REPORT_ERROR;
}

VC++得到当前系统时间日期 GetSystemTime()

一、使用MFC可以用以下代码得到:
CTime time = CTime::GetCurrentTime(); ///构造CTime对象
int m_nYear = time.GetYear(); ///年
int m_nMonth = time.GetMonth(); ///月
int m_nDay = time.GetDay(); ///日
int m_nHour = time.GetHour(); ///小时
int m_nMinute = time.GetMinute(); ///分钟
int m_nSecond = time.GetSecond(); ///秒


我们还可以用CTime::Format函数将CTime对象转换为字符串对象
例如:
CString m_strTime = time.Format("%Y-%m-%d %H:%M:%S");


运行结果:m_strTime为 2001-8-1 12:11:05

二、使用GetSystemTime()这个API函数得到系统时间

SYSTEMTIME ti;
GetSystemTime(&ti);
////我们可以通过读取SYSTEMTIME结构体成员直接得到时间
typedef struct _SYSTEMTIME {
WORD wYear;
WORD wMonth;
WORD wDayOfWeek;
WORD wDay;
WORD wHour;
WORD wMinute;
WORD wSecond;
WORD wMilliseconds;

} SYSTEMTIME, *PSYSTEMTIME;


例如:ti.wMilliseconds;可以得到毫秒时间

2008年1月17日星期四

CTabCtrl控件

VC中的CTabCtrl用法与VB、Delphi的选项卡控件有很大的不同,每个属性页是用一个“窗体”(对话框)来实现,于是要为每个属性页对话框建类,还要关联、初始化……实在麻烦得多。但是CTabCtrl可重用性比ActiveX的选项卡控件好,因为一个属性页可以被多个不同的选项卡对话框调用,就像MFC中很多属性选项卡有“General”这一选项页,可以被多个控件的属性页调用,作为“通用”的,有符合现代软件工程可重用性要求。
下面发一个最简单的代码,使用CTabCtrl控件实现属性页功能,要源码的请登陆www.maoyeah.com,技术文章专栏找。
1、建立一个基于对话框的应用程序;
2、画CTabCtrl控件,类向导中关联变量名为m_tab,新建三个对话框属性设为Child,None,用ClassWizard生成新的类,基类为Cdialog,分别为Cpage0,Cpage1,Cpage2,ID号分别为 IDD_DIALOG0,IDD_DIALOG1,IDD_DIALOG2。在主对话框中加入三个变量,Cpage0 page0; Cpage1 page1;Cpage2 page2。别忘了在主对话框的头文件中要加入#include "Page0.h", #include "Page1.h",#include "Page2.h"
3、在主对话框的OnInitDialog()内初始化 :
// TODO: Add extra initialization here

//初始化m_tab控件
m_tab.InsertItem(0," 呵呵,茂叶工作室 ");
m_tab.InsertItem(1," 嘻嘻 ");
m_tab.InsertItem(2," 哈哈,www.maoyeah.com ");

//建立属性页各页
page0.Create(IDD_DIALOG0,GetDlgItem(IDC_TAB1));
page1.Create(IDD_DIALOG1,GetDlgItem(IDC_TAB1));
page2.Create(IDD_DIALOG2,GetDlgItem(IDC_TAB1));
//设置页面的位置在m_tab控件范围内
CRect rect;
m_tab.GetClientRect(&rect);
rect.top+=20;
rect.bottom-=4;
rect.left+=4;
rect.right-=4;
page0.MoveWindow(&rect);
page1.MoveWindow(&rect);
page2.MoveWindow(&rect);
page1.ShowWindow(TRUE);
m_tab.SetCurSel(1);

4、m_tab控件属性页选择时显示各页:
void CMy3Dlg::OnSelchangeTab1(NMHDR* pNMHDR, LRESULT* pResult)
{
// TODO: Add your control notification handler code here
int CurSel;
CurSel=m_tab.GetCurSel();
switch(CurSel)
{
case 0:
page0.ShowWindow(TRUE);
page1.ShowWindow(FALSE);
page2.ShowWindow(FALSE);

break;
case 1:
page0.ShowWindow(FALSE);
page1.ShowWindow(TRUE);
page2.ShowWindow(FALSE);

break;
case 2:
page0.ShowWindow(FALSE);
page1.ShowWindow(FALSE);
page2.ShowWindow(TRUE);

break;
default: ;

}

*pResult = 0;

}


错误:Dialog 必须选IDD_OLE_PROPAGE_xxx, 否则插入的控件不响应鼠标事件.

2008年1月14日星期一

Corrupt apollo.mdb bings unpack.exe "Failed to create empty document. "

CDaoDatabase::Open()本身是void,当遇到.mdb结构性破坏时,无法返回错误报告。
解决方案:利用抛出异常返回结果
BOOL CPublic::openDB()
{
......
//----build connection to source Datenbase by CDaoDatabase.
// *here must check the sourceDB is the right .mdb file and kann be found
// it can be the wrong .mdb file , "test.mdb"
try
{
CDaoWorkspace daoWorkspace;
//CDaoWorkspace::CompactDatabase( _T( "C:\\DB1.MDB" ),_T( "C:\\DB2.MDB" ) );
//CDaoWorkspace::RepairDatabase( (LPCTSTR)sourceDB );
daoWorkspace.Open( (LPCTSTR)sourceDB );
if (!daoWorkspace.IsOpen())
return false;
else
daoWorkspace.Close();

}
catch( CDaoException* e )
{
//AfxMessageBox( e->m_pErrorInfo->m_strDescription );
e->Delete();
return false; //利用CDaoWorkspace::Open可避免.lpb文件的产生,造成死锁

}
//----build connection to source Datenbase by CDaoDatabase.
// *here must check the sourceDB is the right .mdb file and kann be found
// it can be the wrong .mdb file , "test.mdb"

try
{
m_DaoDatabase.Open((LPCTSTR)sourceDB,FALSE,FALSE,_T(""));

}
catch(CDaoException* e)
{
e->Delete();
return false; //important, if .mdb corrupt ist.

}
//
......
return true;

}

2008年1月11日星期五

SetFileAttributes,更改文件写保护属性

//get rid of writeprotect featcher of sourcefile.
SetFileAttributes((LPCTSTR)sourceDB,FILE_ATTRIBUTE_NORMAL);
//

2008年1月9日星期三

常用的字符串处理函数

字符串标准函数的原型在头文件string.h中。

1.输入字符串──gets()函数

(1)调用方式:gets(字符数组)

(2)函数功能:从标准输入设备(stdin)──键盘上,读取1个字符串(可以包含空格),并将其存储到字符数组中去



(3)使用说明


1)gets()读取的字符串,其长度没有限制,编程者要保证字符数组有足够大的空间,存放输入的字符串。

2)该函数输入的字符串中允许包含空格,而scanf()函数不允许。


2.输出字符串──puts()函数

(1)调用方式:puts(字符数组)

(2)函数功能:把字符数组中所存放的字符串,输出到标准输出设备中去,并用‘\n’取代字符串的结束标志‘\0’

。所以用puts()函数输出字符串时,不要求另加换行符。

( 3)使用说明

1)字符串中允许包含转义字符,输出时产生一个控制操作。

2)该函数一次只能输出一个字符串,而printf()函数也能用来输出字符串,且一次能输出多个。


3.字符串比较──strcmp()函数

(1)调用方式:strcmp(字符串1 ,字符串2)

其中“字符串”可以是串常量,也可以是1维字符数组。

(2)函数功能:比较两个字符串的大小。

如果:字符串1=字符串2,函数返回值等于0;

字符串1字符串2,函数返回值正整数。

(3)使用说明

1)如果一个字符串是另一个字符串从头开始的子串,则母串为大。

2)不能使用关系运算符“==”来比较两个字符串,只能用strcmp() 函数来处理。

[案例6.7] gets函数和strcmp函数的应用。

/*案例代码文件名:AL6_7.C*/

/*功能:简单密码检测程序*/

#include "stdio.h"

main()

{char pass_str[80]; /*定义字符数组passstr*/

int I=0;

/*检验密码*/

while(1)

{clrscr();

printf("请输入密码\n");

gets(pass_str); /*输入密码*/

if(strcmp(pass_str,“password”)!=0) /*口令错*/

printf("口令错误,按任意键继续");

else

break; /*输入正确的密码,中止循环*/

getch();

I++;

if(I==3) exit(0); /*输入三次错误的密码,退出程序*/

}

/*输入正确密码所进入的程序段*/

}



4.拷贝字符串──strcpy()函数

(1)调用方式:strcpy(字符数组, 字符串)

其中“字符串”可以是串常量,也可以是字符数组。

(2)函数功能:将“字符串”完整地复制到“字符数组”中,字符数组中原有内容被覆盖。

(3)使用说明


1)字符数组必须定义得足够大,以便容纳复制过来的字符串。复制时,连同结束标志'\0'一起复制。

2)不能用赋值运算符“=”将一个字符串直接赋值给一个字符数组,只能用strcpy()函数来处理。


5.连接字符串──strcat()函数

(1)调用方式:strcat(字符数组, 字符串)

(2)函数功能:把“字符串”连接到“字符数组”中的字符串尾端,并存储于“字符数组”中。“字符数组”中原来

的结束标志,被“字符串”的第一个字符覆盖,而“字符串”在操作中未被修改。

(3)使用说明

1)由于没有边界检查,编程者要注意保证“字符数组”定义得足够大,以便容纳连接后的目标字符串;否则,会因

长度不够而产生问题。

2)连接前两个字符串都有结束标志'\0',连接后“字符数组”中存储的字符串的结束标志'\0'被舍弃,只在目标串


的最后保留一个'\0'。


6.求字符串长度──strlen()函数(len是length的缩写)

(1)调用方式:strlen(字符串)

(2)函数功能:求字符串(常量或字符数组)的实际长度(不包含结束标志)。


7.将字符串中大写字母转换成小写──strlwr()函数

(1)调用方式:strlwr(字符串)

(2)函数功能:将字符串中的大写字母转换成小写,其它字符(包括小写字母和非字母字符)不转换。


8.将字符串中小写字母转换成大写──strupr()函数

(1)调用方式:strupr(字符串)

(2)函数功能:将字符串中小写字母转换成大写,其它字符(包括大写字母和非字母字符)不转换。


C语言是通过函数来实现模块化程序设计的。所以较大的C语言应用程序,往往是由多个函数组成的,每个函数分别对应

各自的功能模块。

2008年1月8日星期二

几个关于zlib的小程序

#include
#include "/zlib/include/zlib.h"

// Demonstration of zlib utility functions

unsigned long file_size(char *filename)
{
FILE *pFile = fopen(filename, "rb");
fseek (pFile, 0, SEEK_END);
unsigned long size = ftell(pFile);
fclose (pFile);
return size;

}

int decompress_one_file(char *infilename, char *outfilename)
{
gzFile infile = gzopen(infilename, "rb");
FILE *outfile = fopen(outfilename, "wb");
if (!infile || !outfile) return -1;

char buffer[128];
int num_read = 0;
while ((num_read = gzread(infile, buffer, sizeof(buffer))) > 0)
{
fwrite(buffer, 1, num_read, outfile);

}

gzclose(infile);
fclose(outfile);

}

int compress_one_file(char *infilename, char *outfilename)
{
FILE *infile = fopen(infilename, "rb");
gzFile outfile = gzopen(outfilename, "wb");
if (!infile || !outfile) return -1;

char inbuffer[128];
int num_read = 0;
unsigned long total_read = 0, total_wrote = 0;
while ((num_read = fread(inbuffer, 1, sizeof(inbuffer), infile)) > 0)
{
total_read += num_read;
gzwrite(outfile, inbuffer, num_read);

}
fclose(infile);
gzclose(outfile);

printf("Read %ld bytes, Wrote %ld bytes,
Compression factor %4.2f%%\n",
total_read, file_size(outfilename),
(1.0-file_size(outfilename)*1.0/total_read)*100.0);

}


int main(int argc, char **argv)
{
compress_one_file(argv[1],argv[2]);
decompress_one_file(argv[2],argv[3]);

}

zlib dll包的使用

将zlib.h,zconf.h,zlib.lib三个文件拷到当前project的目录下,在stdafx.h中加入:
#define ZLIB_DLL
#include "zlib.h"//zconf.h

编译后,在c:\windows\system32中会自动生成一个zlib.dll文件。

注意:zlib version ist 1.1.3

zlib(integrity check)解压文件完整性检查 方案一:(未决)

压缩包文件: apollo.mdb.gz
解压文件: apollo.mdb
目的: 测试解压后的文件是否完整

方案一:
将apollo.mdb压入一个临时.gz文件apollo_tmp.mdb.gz,通过gzread()将apollo.mdb.gz与apollo.mdb进行比较。

代码:
BOOL CPublic::checkZippedFile(LPCTSTR sNameZipped, CString sNameExpand)
{
CString tempFile(ApoWorkDir + "\\apollo_tmp.mdb.gz");
gzFile pFileZipped;
gzFile pFileExpand;
HANDLE hFile;
//LPOFSTRUCT lpReOpenBuff;
int nReadedZipped;
int nReadedExpand;

//voidp pBufZipped;
//voidp pBufExpand;
char pBufZipped[1024];
char pBufExpand[1024];
CString strZip;
CString strExp;
//DWORD nDone;
//BOOL bSuccess;
CString sTmp;

//----compress the to be checked datei


if (!tempFile.IsEmpty())
{
DeleteFile(tempFile);
hFile = CreateFile(tempFile, GENERIC_WRITE, FILE_SHARE_WRITE|FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
// FH 10.12.2004
if (hFile == INVALID_HANDLE_VALUE)
hFile = NULL;
//
if (hFile == NULL)
{
AfxMessageBox("Create ExpandFile "+ tempFile + " failed");
sNameExpand.Empty();
}
}
//fclose(hFile);
//hFile = NULL;

FILE *infile = fopen(sNameExpand, "rb");
gzFile outfile = gzopen(tempFile, "wb");

if (!infile || !outfile)
{
AfxMessageBox("open failed");
return false;
}
char inbuffer[1024];
int num_read = 0;
unsigned long total_read = 0, total_wrote = 0;
while ((num_read = fread(inbuffer, 1, sizeof(inbuffer), infile)) > 0) {
total_read += num_read;
gzwrite(outfile, inbuffer, num_read);
}

fclose(infile);
gzclose(outfile);
AfxMessageBox("Create ExpandFile" + tempFile);
//----

/*
* gzopen returns NULL if the file could not be opened or if there was
* insufficient memory to allocate the (de)compression state; errno
* can be checked to distinguish the two cases (if errno is zero, the
* zlib error is Z_MEM_ERROR).
*/
pFileZipped = gzopen(sNameZipped, "rb");
pFileExpand = gzopen(tempFile, "rb");

CString s;
s.Format("%d", pFileExpand);
AfxMessageBox(s);
if (pFileZipped && pFileExpand)
{
AfxMessageBox("begin to check integrity");

int nLoops = 0;

//---- read from source file
/*
* gzread returns the number of uncompressed bytes actually read (0 for
* end of file, -1 for error).
*/
nReadedZipped = gzread(pFileZipped, pBufZipped, sizeof(pBufZipped)); //how large is BUFFER_SIZE:10MB
nReadedExpand = gzread(pFileExpand, pBufExpand, sizeof(pBufExpand));


if (nReadedZipped != -1)
{
while (nReadedZipped != 0)
{
//if ((nLoops % 20) == 0)
// pDLT->pParent->PostMessage(pDLT->nMsgWatchdog, ++nWatchdog, 0);

//if (!sNameExpand.IsEmpty())
// WriteFile(hFile, pBuf, nReaded, &nDone, NULL);


if (nReadedZipped != -1 && nReadedZipped != 0)
{
strZip.Format("%s", pBufZipped);
strExp.Format("%s", pBufExpand);
if (strZip != strExp )
return false;

}

AfxMessageBox(strZip + "\n" + strExp);
//go on reading
nReadedZipped = gzread(pFileZipped, pBufZipped, sizeof(pBufZipped));
nReadedExpand = gzread(pFileExpand, pBufExpand, sizeof(pBufExpand));
if (nReadedZipped == -1 || nReadedZipped == 0)
return false;
AfxMessageBox("break5");
}
}
//----

// if (hFile)
// CloseHandle(hFile);
gzclose(pFileZipped);
gzclose(pFileExpand);
/* if ((nReaded == -1) || (gzclose(pFileZipped) != Z_OK))
{
bSuccess = FALSE;
sTmp.Format("zipped File %s is corrupt", sNameZipped);
// PROTOCOL_ENTRY(0,0,sTmp)

//if (!DeleteFile(sNameZipped))
//PROTOCOL_ENTRY(0,0,"Delete CompressedFile failed")

if ( !sNameExpand.IsEmpty() )
{
if ( !DeleteFile(sNameExpand) )
PROTOCOL_ENTRY(0,0,"Delete ExpandFile failed");
}
return false;
}*/
}
if (!tempFile.IsEmpty())
{
DeleteFile(tempFile);
}
return true;
}

2008年1月4日星期五

Problem:header datei CUnpackView.h nicht gefunden vc++

Kommisch sache, in MFC-Klass-assistent enthählt die Class CUpackView nicht , zwar Dialog Komponenten verbindet sich mit CView nicht mehr. mit Rarf viel mal versucht, die Datei steht ewig in Project aber nicht gehört zu MFC-Klass-assistent. leztmal wurde lösung gefunden, blöd aber wirksam:
Schneide die Datei UnpackView.h und UnpackView.cpp aus project, erzeuge eine neue Class CUnpackView durch MFC-Klass-assistent, dann kopieren Sourcekordierung aus altere UnpackView ins neu Datei. erledigt!!!

2008年1月3日星期四

SHBrowseForFolder设置初始目录中CALLBACK函数的使用

目的:
通过BROWSEINFO,SHBrowseForFolder打开Directory对话框,并且通过int CALLBACK BrowseCallbackProc()设置初始目录.

(源代码)打开目录选择对话框:
void CUnpackView::OnButtonPath(CDataExchange* pDX)
{
// TODO: Add your control notification handler code here
char dispname[MAX_PATH];
char copytopath[MAX_PATH];


BROWSEINFO bi;
ITEMIDLIST *pidl;

bi.hwndOwner = 0;
bi.pidlRoot = 0; //set the default browser path
bi.pszDisplayName = dispname;
bi.lpszTitle = "Verzeichniss auswählen";
bi.ulFlags = BIF_STATUSTEXT;//BIF_RETURNONLYFSDIRS;
bi.lpfn = BrowseCallbackProc; //调用回调函数
bi.lParam = 0;
bi.iImage = 0;



if ((pidl = SHBrowseForFolder(&bi))!=NULL) //
{
memset(copytopath, 0, MAX_PATH);
SHGetPathFromIDList(pidl, copytopath);//copytopath
//
sourceDir = (CString) copytopath;


}
//OnInitialUpdate();
UpdateData(false);
Invalidate();

if ( plc.checkFolder((LPCTSTR)sourceDir) )
{
openedSourceDir = (LPCTSTR)sourceDir;

//--get the LastWriteTime of folder/files
WIN32_FIND_DATA ffd ;
HANDLE hFind = FindFirstFile(openedSourceDir,&ffd);
SYSTEMTIME stUTC, stLocal;
FileTimeToSystemTime(&(ffd.ftLastWriteTime), &stUTC);
SystemTimeToTzSpecificLocalTime(NULL, &stUTC, &stLocal);
myTime.Format("%d. %d %d, %d:%d", stLocal.wDay,stLocal.wMonth,stLocal.wYear,stLocal.wHour,stLocal.wMinute);
//--
d_ColorStatic.SetWindowText((LPCTSTR)myTime);


GetDlgItem(IDC_BUTTON_ROLLBACK)->EnableWindow(true);
GetDlgItem(IDC_BUTTON_REPORT)->EnableWindow(true);
GetDlgItem(IDC_STATIC_STATUSTITLE)->EnableWindow(false);

}
else
{
GetDlgItem(IDC_BUTTON_ROLLBACK)->EnableWindow(false);
GetDlgItem(IDC_BUTTON_REPORT)->EnableWindow(false);
GetDlgItem(IDC_STATIC_STATUSTITLE)->EnableWindow(false);
AfxMessageBox("Die angegebene Verzeichniss ist nicht richtig, bitte versuchen Sie nochmal.");

}

}


(源代码)CALLBACK函数:
在.h中:

CString sicherungDir;
static int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData);



在.cpp中:
int CALLBACK CUnpackView::BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
{
//CALLBACKSTRUCT * cs = (CALLBACKSTRUCT*) lpData;

CString dir(_T(""));
BOOL hasInitial = false;
// * Statische Member-Funktionen haben keinen this-Zeiger: *
// * this does not work, because the pUnpack is a new obj,
// * pUnpack->openedSourceDir is the new one

//---- use the View pointobject
CMDIFrameWnd *pFrame = (CMDIFrameWnd*)AfxGetApp()->m_pMainWnd;
CMDIChildWnd *pChild = (CMDIChildWnd *) pFrame->GetActiveFrame();
CUnpackView *pView = (CUnpackView *) pChild->GetActiveView();
//--

if ( pView->openedSourceDir != "")
dir = pView->openedSourceDir; // the default stays at the opened folder failed!because pView is a new pObject

else
dir = CPublic::sSicherungDir; //if first time to open the folder dialog


/////////////////////////////////////////////////
//'d:\\' can not be recognised by SHGetPathFromIDList()
// must be changed into 'd:\'
/////////////////////////////////////////////////
dir.Replace("\\\\","\\");

switch(uMsg)
{
case BFFM_INITIALIZED: //initial
hasInitial =true;
::SendMessage(hwnd,BFFM_SETSELECTION,TRUE,(LPARAM)(LPCTSTR)dir ); //"d:\\datenversicherung"
//AfxMessageBox("BFFM_INITIALIZED");

break;

case BFFM_SELCHANGED: //path changed
{
/////////////////////////////////////////////
// to avoid SHGetPathFromIDList()twice running
// before "case BFFM_INITIALIZED" has been done
////////////////////////////////////////////
if (hasInitial)
{
char curr[MAX_PATH];

SHGetPathFromIDList((LPCITEMIDLIST)lParam,curr);

CString s;
s.Format("BFFM_SELCHANGED, curr: %s",curr);
AfxMessageBox(s);

if(curr[strlen(curr)-1]==92)
sprintf(curr,"%s",curr);
else
sprintf(curr,"%s\\",curr);

::SendMessage(hwnd,BFFM_SETSTATUSTEXT,0,(LPARAM)curr);

}

}
break;

}
return 0;

}


注意:
在对CALLBACK函数的使用中,必须是类的静态成员函数。
否则,用MS编译器,会得到这个编译错误:
error C2664: 'Bubblesort' : cannot convert parameter 4 from 'int (__stdcall CCallbackTester::*)(const unsigned char *,const unsigned char *)' to 'int (__stdcall *)(const unsigned char *,const unsigned char *)' There is no context in which this conversion is possible


参考:
Visual C++中回调函数使用的变身大法
回调函数指南(Callback Functions Tutorial)
How to Implement Callbacks in C and C++

VC++获取文件修改时间

WIN32_FIND_DATA结构

  关于文件的全部属性信息,总计有以下以下9 种:文件的标题名、文件的属性(只读、存档,隐藏等)、文件的创建时间、文件的最后访问时间、文件的最后修改时间、文件大小的高位双字、文件大小的低位双字、保留、保留。在这里只有文件标题名和文件的长度可以通过CFile类比较方便的获得,而对于其他几种属性的获取和设置就无能为力了。

  在用findfirst()和findnext()函数去查找磁盘文件时经常使用的一个数据结构WIN32_FIND_DATA的成员变量里包含了以上所有的文件属性,因此可以通过这个结构作为获取和更改文件属性的手段。该结构的内容如下:
typedef struct _WIN32_FIND_DATA {
  DWORD dwFileAttributes; //文件属性
  FILETIME ftCreationTime; // 文件创建时间
  FILETIME ftLastAccessTime; // 文件最后一次访问时间
  FILETIME ftLastWriteTime; // 文件最后一次修改时间
  DWORD nFileSizeHigh; // 文件长度高32位
  DWORD nFileSizeLow; // 文件长度低32位
  DWORD dwReserved0; // 系统保留
  DWORD dwReserved1; // 系统保留
  TCHAR cFileName[ MAX_PATH ]; // 长文件名
  TCHAR cAlternateFileName[ 14 ]; // 8.3格式文件名
} WIN32_FIND_DATA, *PWIN32_FIND_DATA;

可以通过FindFirstFile()函数根据当前的文件存放路径查找该文件来把待操作文件的相关属性读取到WIN32_FIND_DATA结构中去:
WIN32_FIND_DATA ffd ;
HANDLE hFind = FindFirstFile("c:\\test.dat",&ffd);

在使用这个结构时不能手工修改这个结构中的任何数据,结构对于开发人员来说只能作为一个只读数据,其所有的成员变量都会由系统完成填写。

实例
//--get the LastWriteTime of folder/files
WIN32_FIND_DATA ffd ;
HANDLE hFind = FindFirstFile(openedSourceDir,&ffd);
SYSTEMTIME stUTC, stLocal;
FileTimeToSystemTime(&(ffd.ftLastWriteTime), &stUTC);
SystemTimeToTzSpecificLocalTime(NULL, &stUTC, &stLocal);
myTime.Format("%d. %d %d, %d:%d", stLocal.wDay,stLocal.wMonth,stLocal.wYear,stLocal.wHour,stLocal.wMinute);
//--
d_ColorStatic.SetWindowText((LPCTSTR)myTime);

2008年1月2日星期三

修改MFC标题栏上的图标

HICON m_hIcon;


在MainFrm的OnCreate()里
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon

博客归档