source: dev/trunk/abdev/BasicCompiler_Common/Compile.cpp@ 262

Last change on this file since 262 was 261, checked in by dai_9181, 17 years ago
File size: 16.7 KB
RevLine 
[206]1#include "stdafx.h"
2
[182]3#include <jenga/include/smoothie/Smoothie.h>
4#include <jenga/include/smoothie/LexicalAnalysis.h>
5#include <jenga/include/smoothie/SmoothieException.h>
6
[248]7#include <LexicalScope.h>
[182]8#include <CodeGenerator.h>
[193]9#include <Compiler.h>
[195]10#include <NamespaceSupporter.h>
[182]11
[4]12#include "../BasicCompiler_Common/common.h"
13
14#ifdef _AMD64_
15#include "../BasicCompiler64/opcode.h"
16#else
[5]17#include "../BasicCompiler32/opcode.h"
[4]18#endif
19
[182]20#include <Exception.h>
21
[4]22//グローバル変数初期バッファ
23BYTE *initGlobalBuf;
24
25//With情報
26WITHINFO WithInfo;
27
28
[89]29
[16]30///////////////////////////////////////////////////
[17]31// トークンを取得
32///////////////////////////////////////////////////
33void GetIdentifierToken( char *token, const char *source, int &pos ){
34 for( int i=0; ; i++, pos++ ){
35 if( ! IsVariableChar( source[pos] ) ){
36 token[i] = 0;
37 break;
38 }
39 token[i] = source[pos];
40 }
41}
42
43
44///////////////////////////////////////////////////
[16]45// 対になっているステートメントを飛び越す
46// ※グローバル領域用
47///////////////////////////////////////////////////
48int JumpStatement(const char *source, int &pos){
49 if( source[pos] != 1 ) return 0;
50
51 if( ! IsCommandDelimitation( source[pos - 1] ) ){
52 //直前がコマンド区切りではない場合
53 return 0;
54 }
55
56 char cStatement = source[pos + 1];
57
58 char cEnd = GetEndXXXCommand( cStatement );
59 if( cEnd == 0 ) return 0;
60
61 pos += 2;
62 while( ! ( source[pos] == 1 && source[pos + 1] == cEnd ) ){
63
64 if( source[pos] == '\0' ){
65 char temporary[64];
66 GetDefaultNameFromES( cStatement, temporary );
67 SetError( 22, temporary, pos );
68 return -1;
69 }
70
71 pos++;
72 }
73 if( ! ( source[pos] == '\0' || source[pos + 2] == '\0' ) ){
74 pos += 2;
75 }
76
77 return 1;
78}
79
80
[4]81void NextLine(void){
82 extern HANDLE hHeap;
83 extern int MaxLineInfoNum;
84 extern LINEINFO *pLineInfo;
85 if(MaxLineInfoNum){
[253]86 extern int obp;
[4]87 if(pLineInfo[MaxLineInfoNum-1].TopObp==obp){
88 pLineInfo[MaxLineInfoNum-1].TopCp=cp;
89 return;
90 }
91 }
92 pLineInfo=(LINEINFO *)HeapReAlloc(hHeap,0,pLineInfo,(MaxLineInfoNum+1)*sizeof(LINEINFO));
93 pLineInfo[MaxLineInfoNum].TopCp=cp;
[253]94 extern int obp;
[4]95 pLineInfo[MaxLineInfoNum].TopObp=obp;
96
97 extern BOOL bDebugSupportProc;
98 extern BOOL bSystemProc;
99 pLineInfo[MaxLineInfoNum].dwCodeType=0;
100 if(bDebugSupportProc)
101 pLineInfo[MaxLineInfoNum].dwCodeType|=CODETYPE_DEBUGPROC;
102 if(bSystemProc)
103 pLineInfo[MaxLineInfoNum].dwCodeType|=CODETYPE_SYSTEMPROC;
104
105 MaxLineInfoNum++;
106}
107
108void ChangeOpcode(char *Command){
109 extern HANDLE hHeap;
110
[206]111 if(Command[0]=='\0')
112 {
113 return;
114 }
115
116 trace_for_sourcecodestep( FormatEscapeSequenceStringToDefaultString(Command) );
117
[4]118 if(Command[0]=='*'&&IsVariableTopChar(Command[1])){
119 //Goto先ラベル
[253]120 extern int obp;
[261]121 compiler.codeGenerator.gotoLabels.push_back( GotoLabel( Command + 1, obp ) );
[4]122
123 //書き込みスケジュール
[253]124 GotoLabelSchedules::iterator it = compiler.codeGenerator.gotoLabelSchedules.begin();
[246]125 while( it != compiler.codeGenerator.gotoLabelSchedules.end() )
126 {
[253]127 if( (*it)->GetName() == Command+1 )
[246]128 {
[253]129 compiler.codeGenerator.opfix_JmpPertialSchedule( (*it) );
[246]130
[4]131 //詰める
[246]132 it = compiler.codeGenerator.gotoLabelSchedules.erase( it );
[4]133 }
[246]134 else
135 {
136 it++;
137 }
[4]138 }
139 return;
140 }
141 if(Command[0]==1){
142 switch(Command[1]){
143 case ESC_CONST:
[7]144 OpcodeDim(Command+2, DIMFLAG_CONST);
145 break;
146
[4]147 case ESC_TYPEDEF:
[113]148 if( UserProc::IsLocalAreaCompiling() ){
149 // ローカル領域をコンパイルしているとき
150 SetError(65,"TypeDef",cp );
151 }
152
[78]153 //既に収集済み
[4]154 break;
155
156 case ESC_STATIC:
157 OpcodeDim(Command+2,DIMFLAG_STATIC);
158 break;
159
160 case ESC_IF:
161 OpcodeIf(Command+2);
162 break;
163 case ESC_EXITWHILE:
[182]164 {
[248]165 LexicalScope *pScope = compiler.codeGenerator.lexicalScopes.SearchScope( LexicalScope::SCOPE_TYPE_WHILE );
[182]166 if( !pScope ){
167 SetError(12,"Exit While",cp);
168 return;
169 }
170 pScope->Break();
171 }
[4]172 break;
173 case ESC_EXITFOR:
[182]174 {
[248]175 LexicalScope *pScope = compiler.codeGenerator.lexicalScopes.SearchScope( LexicalScope::SCOPE_TYPE_FOR );
[182]176 if( !pScope ){
177 SetError(12,"Exit For",cp);
178 return;
179 }
180 pScope->Break();
181 }
[4]182 break;
183 case ESC_EXITDO:
[182]184 {
[248]185 LexicalScope *pScope = compiler.codeGenerator.lexicalScopes.SearchScope( LexicalScope::SCOPE_TYPE_DO );
[182]186 if( !pScope ){
187 SetError(12,"Exit Do",cp);
188 return;
189 }
190 pScope->Break();
191 }
[4]192 break;
193 case ESC_CONTINUE:
194 OpcodeContinue();
195 break;
196
197 case ESC_EXITSUB:
198 case ESC_EXITFUNCTION:
199 case ESC_EXITMACRO:
200 OpcodeExitSub();
201 break;
202
203 case ESC_SELECTCASE:
204 OpcodeSelect(Command+2);
205 break;
206 case ESC_CASE:
207 case ESC_CASEELSE:
208 OpcodeCase(Command+2);
209 break;
210
211 case ESC_WITH:
212 extern WITHINFO WithInfo;
213
214 WithInfo.ppName=(char **)HeapReAlloc(hHeap,0,WithInfo.ppName,(WithInfo.num+1)*sizeof(char **));
215 WithInfo.ppName[WithInfo.num]=(char *)HeapAlloc(hHeap,0,lstrlen(Command+2)+1);
216 lstrcpy(WithInfo.ppName[WithInfo.num],Command+2);
217
218 WithInfo.pWithCp=(int *)HeapReAlloc(hHeap,0,WithInfo.pWithCp,(WithInfo.num+1)*sizeof(int));
219 WithInfo.pWithCp[WithInfo.num]=cp;
220
221 WithInfo.num++;
222 break;
223 case ESC_ENDWITH:
224 if(WithInfo.num<=0){
225 SetError(12,"End With",cp);
226 return;
227 }
228 WithInfo.num--;
229 HeapDefaultFree(WithInfo.ppName[WithInfo.num]);
230 break;
231 case ESC_DECLARE:
[113]232 if( UserProc::IsLocalAreaCompiling() ){
233 // ローカル領域をコンパイルしているとき
234 SetError(65,"Declare",cp );
235 }
[4]236 break;
[26]237
[99]238 case ESC_NAMESPACE:
[199]239 compiler.GetNamespaceSupporter().GetLivingNamespaceScopes().push_back( Command + 2 );
[103]240 break;
[99]241 case ESC_ENDNAMESPACE:
[199]242 if( compiler.GetNamespaceSupporter().GetLivingNamespaceScopes().size() <= 0 ){
[103]243 SetError(12,"End Namespace",cp);
244 }
[199]245 compiler.GetNamespaceSupporter().GetLivingNamespaceScopes().pop_back();
[99]246 break;
[107]247 case ESC_IMPORTS:
[199]248 compiler.GetNamespaceSupporter().ImportsNamespace( Command + 2 );
[107]249 break;
250 case ESC_CLEARNAMESPACEIMPORTED:
[199]251 compiler.GetNamespaceSupporter().GetImportedNamespaces().clear();
[107]252 break;
[99]253
[26]254 //Tryによる例外処理
255 case ESC_TRY:
256 Exception::TryCommand();
257 break;
258 case ESC_CATCH:
259 Exception::CatchCommand();
260 break;
261 case ESC_FINALLY:
262 Exception::FinallyCommand();
263 break;
264 case ESC_ENDTRY:
265 Exception::EndTryCommand();
266 break;
267 case ESC_THROW:
268 Exception::ThrowCommand( Command + 2 );
269 break;
270
[4]271 default:
272 char temporary[64];
273 GetDefaultNameFromES(Command[1],temporary);
274 SetError(30,temporary,cp);
275 break;
276 }
277 return;
278 }
279 switch(MAKEWORD(Command[1],Command[0])){
280 case COM_DIM:
281 OpcodeDim(Command+2,0);
282 break;
283 case COM_DELETE:
[64]284 OpcodeDelete(Command+2, false);
[4]285 break;
[64]286 case COM_SWEEPINGDELETE:
287 OpcodeDelete(Command+2, true);
288 break;
[4]289
290 case COM_GOTO:
291 OpcodeGoto(Command+2);
292 break;
293 case COM_WHILE:
294 OpcodeWhile(Command+2);
295 break;
296 case COM_FOR:
297 OpcodeFor(Command+2);
298 break;
299 case COM_DO:
300 OpcodeDo(Command+2);
301 break;
302
303 case COM_GOSUB:
304 OpcodeGosub(Command+2);
305 break;
306 case COM_RETURN:
307 OpcodeReturn(Command+2);
308 break;
309
310 case COM_SETDOUBLE:
311 OpcodeSetPtrData(Command+2,DEF_DOUBLE);
312 break;
313 case COM_SETSINGLE:
314 OpcodeSetPtrData(Command+2,DEF_SINGLE);
315 break;
316 case COM_SETQWORD:
317 OpcodeSetPtrData(Command+2,DEF_QWORD);
318 break;
319 case COM_SETDWORD:
320 OpcodeSetPtrData(Command+2,DEF_DWORD);
321 break;
322 case COM_SETWORD:
323 OpcodeSetPtrData(Command+2,DEF_WORD);
324 break;
325 case COM_SETBYTE:
326 OpcodeSetPtrData(Command+2,DEF_BYTE);
327 break;
328
329 case COM_DEBUG:
330 extern BOOL bDebugCompile;
331 //int 3
[253]332 if(bDebugCompile)
333 {
334 breakpoint;
335 }
[4]336#if defined(_DEBUG)
[253]337 else
338 {
339 breakpoint;
340 }
[4]341#endif
342 break;
343
344 case COM_LET:
345 OpcodeCalc(Command+2);
346 break;
347 default:
348 OpcodeOthers(Command);
349 break;
350 }
351}
352
353void GetGlobalDataForDll(void){
354 extern char *basbuf;
355 extern HANDLE hHeap;
356 int i2,BufferSize;
357 char *Command;
358 DWORD dwRetCode;
359
360 dwRetCode=0;
361 BufferSize=128;
362 Command=(char *)HeapAlloc(hHeap,0,BufferSize);
363 for(cp++,i2=0;;cp++,i2++){
364 if(i2>=BufferSize){
365 //バッファ領域が足りなくなった場合はバッファを増量する
366 BufferSize+=128;
367 Command=(char *)HeapReAlloc(hHeap,0,Command,BufferSize);
368 }
369 if(basbuf[cp]=='\"'){
370 Command[i2]=basbuf[cp];
371 for(cp++,i2++;;cp++,i2++){
372 if(i2>=BufferSize){
373 //バッファ領域が足りなくなった場合はバッファを増量する
374 BufferSize+=128;
375 Command=(char *)HeapReAlloc(hHeap,0,Command,BufferSize);
376 }
377 Command[i2]=basbuf[cp];
378 if(basbuf[cp]=='\"') break;
379 }
380 continue;
381 }
382 if(IsCommandDelimitation(basbuf[cp])){
383 Command[i2]=0;
384
385 if(Command[0]==1&&Command[1]==ESC_SUB){
386 i2=cp;
387 while(!(basbuf[cp]==1&&basbuf[cp+1]==ESC_ENDSUB)){
388 if(basbuf[cp]=='\0'){
389 SetError(22,"Sub",i2);
390 break;
391 }
392 cp++;
393 }
394 if(basbuf[cp+2]=='\0'||basbuf[cp]=='\0') break;
395 cp+=2;
396 i2=-1;
397 continue;
398 }
399 if(Command[0]==1&&Command[1]==ESC_FUNCTION){
400 i2=cp;
401 while(!(basbuf[cp]==1&&basbuf[cp+1]==ESC_ENDFUNCTION)){
402 if(basbuf[cp]=='\0'){
403 SetError(22,"Function",i2);
404 break;
405 }
406 cp++;
407 }
408 if(basbuf[cp+2]=='\0'||basbuf[cp]=='\0') break;
409 cp+=2;
410 i2=-1;
411 continue;
412 }
413 if(Command[0]==1&&Command[1]==ESC_MACRO){
414 i2=cp;
415 while(!(basbuf[cp]==1&&basbuf[cp+1]==ESC_ENDMACRO)){
416 if(basbuf[cp]=='\0'){
417 SetError(22,"Macro",i2);
418 break;
419 }
420 cp++;
421 }
422 if(basbuf[cp+2]=='\0'||basbuf[cp]=='\0') break;
423 cp+=2;
424 i2=-1;
425 continue;
426 }
427 if(Command[0]==1&&Command[1]==ESC_TYPE){
428 i2=cp;
429 while(!(basbuf[cp]==1&&basbuf[cp+1]==ESC_ENDTYPE)){
430 if(basbuf[cp]=='\0'){
431 SetError(22,"Type",i2);
432 break;
433 }
434 cp++;
435 }
436 if(basbuf[cp+2]=='\0'||basbuf[cp]=='\0') break;
437 cp+=2;
438 i2=-1;
439 continue;
440 }
441 if(Command[0]==1&&Command[1]==ESC_CLASS){
442 i2=cp;
443 while(!(basbuf[cp]==1&&basbuf[cp+1]==ESC_ENDCLASS)){
444 if(basbuf[cp]=='\0'){
445 SetError(22,"Class",i2);
446 break;
447 }
448 cp++;
449 }
450 if(basbuf[cp+2]=='\0'||basbuf[cp]=='\0') break;
451 cp+=2;
452 i2=-1;
453 continue;
454 }
455 if(Command[0]==1&&Command[1]==ESC_INTERFACE){
456 i2=cp;
457 while(!(basbuf[cp]==1&&basbuf[cp+1]==ESC_ENDINTERFACE)){
458 if(basbuf[cp]=='\0'){
459 SetError(22,"Interface",i2);
460 break;
461 }
462 cp++;
463 }
464 if(basbuf[cp+2]=='\0'||basbuf[cp]=='\0') break;
465 cp+=2;
466 i2=-1;
467 continue;
468 }
469
470 //DLLのグローバルデータに必要なコマンドだけ
471 if(MAKEWORD(Command[1],Command[0])==COM_DIM)
472 OpcodeDim(Command+2,0);
473
[89]474 // ネイティブコードバッファの再確保
475 ReallocNativeCodeBuffer();
[4]476
477 if(basbuf[cp]=='\0') break;
478 i2=-1;
479 continue;
480 }
481 Command[i2]=basbuf[cp];
482 }
483 HeapDefaultFree(Command);
484}
485DWORD CompileBuffer(char Return_Sequence,WORD Return_Command){
486 extern char *basbuf;
487 extern HANDLE hHeap;
488 int i,i2,i3,i4,BufferSize,ScopeStart;
489 char *Command,temporary[VN_SIZE],*temp2,temp3[32];
490 DWORD dwRetCode;
491
492 ScopeStart=cp;
493
494 dwRetCode=0;
495 BufferSize=128;
496 Command=(char *)HeapAlloc(hHeap,0,BufferSize);
[15]497
[4]498 for(cp++,i2=0;;cp++,i2++){
499 if(i2>=BufferSize){
500 //バッファ領域が足りなくなった場合はバッファを増量する
501 BufferSize+=128;
502 Command=(char *)HeapReAlloc(hHeap,0,Command,BufferSize);
503 }
504 if(basbuf[cp]=='\"'){
505 Command[i2]=basbuf[cp];
506 for(cp++,i2++;;cp++,i2++){
507 if(i2>=BufferSize){
508 //バッファ領域が足りなくなった場合はバッファを増量する
509 BufferSize+=128;
510 Command=(char *)HeapReAlloc(hHeap,0,Command,BufferSize);
511 }
512 Command[i2]=basbuf[cp];
513 if(basbuf[cp]=='\"') break;
514 }
515 continue;
516 }
517 if(IsCommandDelimitation(basbuf[cp])){
518 Command[i2]=0;
519
520 if(Command[0]==1&&Command[1]==ESC_LINENUM){
521 for(i=2,i2=0;;i++,i2++){
522 if(Command[i]==','){
523 temporary[i2]=0;
524 break;
525 }
526 temporary[i2]=Command[i];
527 }
528 i3=atoi(temporary);
529 i4=i+1;
530
531 //Goto先ラベル
[253]532 extern int obp;
[261]533 compiler.codeGenerator.gotoLabels.push_back( GotoLabel( (long)i3, obp ) );
[4]534
535 //書き込みスケジュール
[253]536 GotoLabelSchedules::iterator it = compiler.codeGenerator.gotoLabelSchedules.begin();
[246]537 while( it != compiler.codeGenerator.gotoLabelSchedules.end() )
538 {
[253]539 if( (*it)->GetName().size() == 0 && (*it)->GetLineNum() == i3 )
[246]540 {
[253]541 compiler.codeGenerator.opfix_JmpPertialSchedule( (*it) );
542
[4]543 //詰める
[246]544 it = compiler.codeGenerator.gotoLabelSchedules.erase( it );
[4]545 }
[246]546 else
547 {
548 it++;
549 }
[4]550 }
551
552 temp2=(char *)HeapAlloc(hHeap,0,lstrlen(Command+i4)+1);
553 lstrcpy(temp2,Command+i4);
554 lstrcpy(Command,temp2);
555 HeapDefaultFree(temp2);
556 }
557
558 if(Command[0]==1&&
559 (((Command[1]==ESC_VIRTUAL||Command[1]==ESC_OVERRIDE)&&Command[2]==1&&(Command[3]==ESC_SUB||Command[3]==ESC_FUNCTION))||
560 Command[1]==ESC_SUB||
561 Command[1]==ESC_FUNCTION||
562 Command[1]==ESC_MACRO||
563 Command[1]==ESC_TYPE||
564 Command[1]==ESC_CLASS||
565 Command[1]==ESC_INTERFACE||
566 Command[1]==ESC_ENUM||
567 (Command[1]==ESC_CONST&&Command[2]==1&&Command[3]==ESC_ENUM)
568 )
569 ){
570 if(Command[1]==ESC_VIRTUAL||Command[1]==ESC_OVERRIDE||Command[1]==ESC_CONST){
571 GetDefaultNameFromES(Command[3],temporary);
572 }
573 else{
574 GetDefaultNameFromES(Command[1],temporary);
575 }
576 if(Return_Sequence){
577 SetError(12,temporary,cp);
578 break;
579 }
580
581 if(Command[1]==ESC_CONST) i3=GetEndXXXCommand(Command[3]);
582 else i3=GetEndXXXCommand(Command[1]);
583 for(i2=cp;;cp++){
584 if(basbuf[cp]==1){
585 if(basbuf[cp+1]==i3) break;
586 if(Command[1]==ESC_CLASS||Command[1]==ESC_INTERFACE){
587 //クラス、インターフェイスではSub、Functionの定義を可能にしておく
588 if(basbuf[cp+1]==ESC_MACRO||
589 basbuf[cp+1]==ESC_TYPE||
590 basbuf[cp+1]==ESC_CLASS||
591 basbuf[cp+1]==ESC_INTERFACE||
592 basbuf[cp+1]==ESC_ENUM){
593 GetDefaultNameFromES(basbuf[cp+1],temp3);
594 SetError(12,temp3,cp);
595 }
596 }
597 else{
598 if(basbuf[cp-1]!='*'&&(
599 basbuf[cp+1]==ESC_VIRTUAL||
600 basbuf[cp+1]==ESC_OVERRIDE||
601 basbuf[cp+1]==ESC_SUB||
602 basbuf[cp+1]==ESC_FUNCTION||
603 basbuf[cp+1]==ESC_MACRO||
604 basbuf[cp+1]==ESC_TYPE||
605 basbuf[cp+1]==ESC_CLASS||
606 basbuf[cp+1]==ESC_INTERFACE||
607 basbuf[cp+1]==ESC_ENUM)){
608 GetDefaultNameFromES(basbuf[cp+1],temp3);
609 SetError(12,temp3,cp);
610 }
611 }
612 }
613 if(basbuf[cp]=='\0'){
614 //error
615 //既にエラー発行済みのため、何もせずに抜ける
616 break;
617 }
618 }
619 if(basbuf[cp+2]=='\0'||basbuf[cp]=='\0') break;
620 cp+=2;
621 i2=-1;
622 continue;
623 }
624
625 if(Command[0]==0x10||Command[0]==0x11){
626 //Wend、Next、Loopなど
627 if(Return_Command==MAKEWORD(Command[1],Command[0])){
628 if(Return_Command==COM_NEXT){
629 //Nextの場合は、パラメータ(省略化)の整合性を判断する必要がある(OpcodeFor関数を参照)
630 extern char szNextVariable[VN_SIZE];
631 if(Command[2]) lstrcpy(szNextVariable,Command+2);
632 else szNextVariable[0]=0;
633 }
634 break;
635 }
636 }
637
638 NextLine();
639
640 if(Command[0]==1){
641 if(Return_Sequence==ESC_ENDIF&&Command[1]==ESC_ELSE){
642 dwRetCode=ESC_ELSE;
643 break;
644 }
645
646 if(Command[1]==Return_Sequence){
647 dwRetCode=Command[1];
648 break;
649 }
650 }
651
[182]652 try
653 {
654 ChangeOpcode(Command);
655 }
656 catch( const SmoothieException &smoothieException )
657 {
658 SetError(
659 smoothieException.GetErrorCode(),
660 smoothieException.GetKeyword(),
661 smoothieException.GetNowLine()
662 );
663 }
[4]664
[232]665
[4]666 epi_check();
667
[232]668
[4]669 //コンパイルを中断するとき
670 extern BOOL bStopCompile;
671 if(bStopCompile) return 0;
672
[182]673 ReallocNativeCodeBuffer();
[4]674
675 if(basbuf[cp]=='\0'){
676 switch(Return_Command){
677 case COM_WEND:
678 SetError(4,"\"While\" - \"Wend\" ",ScopeStart);
679 break;
680 case COM_NEXT:
681 SetError(4,"\"For\" - \"Next\" ",ScopeStart);
682 break;
683 case COM_LOOP:
684 SetError(4,"\"Do\" - \"Loop\" ",ScopeStart);
685 break;
686 }
687 switch(Return_Sequence){
688 case ESC_ENDSUB:
689 SetError(4,"\"Sub\" - \"End Sub\" ",ScopeStart);
690 break;
691 case ESC_ENDFUNCTION:
692 SetError(4,"\"Function\" - \"End Function\" ",ScopeStart);
693 break;
694 case ESC_ENDMACRO:
695 SetError(4,"\"Macro\" - \"End Macro\" ",ScopeStart);
696 break;
697 case ESC_ENDIF:
698 SetError(22,"If",ScopeStart);
699 break;
700 }
701 break;
702 }
703 i2=-1;
704 continue;
705 }
706 Command[i2]=basbuf[cp];
707 }
708 HeapDefaultFree(Command);
709
710 return dwRetCode;
711}
Note: See TracBrowser for help on using the repository browser.