태터데스크 관리자

도움말
닫기
적용하기   첫페이지 만들기

태터데스크 메시지

저장하였습니다.

달력

6

« 2021/6 »

  •  
  •  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  •  
  •  
  •  

'C | C++ | VC++'에 해당되는 글 25

  1. 2021.01.16 [소스공개] RealTime Trace Logger (log writer)
  2. 2014.06.24 C++ 개발자
  3. 2011.10.06 MiniUtil Source Code
  4. 2011.04.01 [Tip] VS2008 MFC 프로젝트 afximpl.h 파일찾기 또는 컴파일 오류
  5. 2010.12.23 2분법을 이용한 이진탐색(Binary Search) 샘플코드
  6. 2010.12.14 [Tip] MemoryLeaks 메모리릭,메모리누수 실시간 디버깅하여 잡기
  7. 2010.11.22 [Tip]첫째 예외가 있습니다. first-chance exception RPC 서버를 사용할 수 없습니다
  8. 2010.09.29 [Tip] UAC 와 CreateProcess의 ERROR_ELEVATION_REQUIRED,SendMessage의 ERROR_ACCESS_DENIED
  9. 2010.09.24 [Tip]32bit 프로그램에서 64bit DLL DllRegisterServer 등록하기 (5)
  10. 2010.09.17 [Tip] 윈7에서 툴바 툴팁에 검은 잔상이 생길때
  11. 2010.09.16 [Programming Tip] 탐색기 열면서 파일 선택하기
  12. 2010.09.16 툴바에 텍스트 추가시 세로폭(높이) 가 커지는데 줄이는 방법 (2)
  13. 2010.09.15 Owner Draw Menu 에서 WM_MEASUREITEM의 itemWidth와 WM_DRAWITEM이 다른이유
  14. 2010.09.13 VC++ MyVector Simple Template Class
  15. 2010.09.11 VC++ 배포후 APPCRASH 런타임 오류 추적기
  16. 2010.09.10 VC++9.0 (MSVS2008) 에서 Afximpl.h <L_TYPE_raw> 오류
  17. 2010.08.31 Rebar Band가 우측으로 align 되는 현상
  18. 2010.07.27 투박한 윈도우즈7의 메뉴,툴바를 바꿔보자!
  19. 2010.07.12 에디트 컨트롤 비밀번호 속성시 툴팁 안나오게 하기
  20. 2010.07.09 Visual Leak Detector - vld의 Bug
  21. 2010.07.09 [두루에디트 제작기] 정규식(Regular Expression) 검색 구현
  22. 2010.07.09 [두루에디트 제작기] 쓰레드 검색처리시 입력장치공유
  23. 2010.07.09 [두루에디트 제작기] WS_VISIBLE 과 SetRedraw와의 관계
  24. 2010.07.09 [KFCWndLib 제작기] 스크롤 윈도우와 인쇄미리보기용 윈도우 클래스 추가
  25. 2010.07.08 메모리누수감지 라이브러리 [Visual C++]

풀소스 오픈합니다.

자체 파일I/O는 시간이 느려 공유메모리를 통한 외부 트레이스 로그 기록하는 툴입니다.

BatGoRang.h/BatGoRang.cpp를 임포트하여,

extern function을 사용하면 됩니다.

 

screenshot 

여러 프로그램에서 동시 사용가능 합니다.

거의 20년되가는 자작 프로그램 소스입니다.

gorang.7z
0.04MB

 

Posted by 3LegsCrow::하늘날다 두루물

댓글을 달아 주세요

2014. 6. 24. 12:57

C++ 개발자 C | C++ | VC++2014. 6. 24. 12:57

C++ 개발자

http://news.naver.com/main/read.nhn?mode=LSD&mid=shm&sid1=105&oid=030&aid=0002281874

 

Posted by 3LegsCrow::하늘날다 두루물

댓글을 달아 주세요

2011. 10. 6. 14:11

MiniUtil Source Code C | C++ | VC++2011. 10. 6. 14:11

Free! 소스 창고 대방출 사업..

/* 
	miniutil.h
	author: krkim
	mailto://yeamaec@hanafos.com (=> durumul@gmail.com)
	http://yeamaec.com (=> http://krkim.net)
	If you get this source code,use freely but leave this notice.
	1990-2007,Yeamaec Communication.Co,.Ltd.All right reserved.
*/

#ifndef _miniutil__h_
#define _miniutil__h_

#pragma once
void TRACELOG(LPSTR szFile,LPCSTR pszFormat,...);
void __stdcall TRACELOGFILE(LPSTR szFile,LPCSTR pszFormat,...);

int GetFtpFile(char* szLocalFileName, char* szFtpFileName, char* url, int port, char* username, char* password);
BOOL PutFtpFile(char* szLocalFileName, char* szFtpFileName, char* url, int port, char* username, char* password);
CHAR * gettokenstr(CHAR *line,CHAR *delimiter,int pos,CHAR *token,int *tokenlen,int *boperator);
int wildcmp(char *wild, char *string);
CHAR skipcomments(FILE *f);
void removecomment(LPSTR buff);
void removeblank(LPSTR buff,int where = 0);
void GetHomeDirectory(char *szHomeDirectory);
void __stdcall TRACELOG(LPCTSTR pszFormat,...);	
LPTSTR __stdcall allocbuff(LPTSTR str);
void __stdcall freebuff(LPTSTR *str);
void __stdcall reallocbuff(LPTSTR *dest,LPTSTR src);
void __stdcall commastr(TCHAR *figure, TCHAR *buffer, bool no_comma = false);
void __stdcall commastr(LONGLONG figure, TCHAR *buffer, bool no_comma = false);
void __stdcall filesizestr(LONGLONG figure,TCHAR *buffer);
int __stdcall HexStrtoDec(LPTSTR hexastring);
__int64 __stdcall getfilepointer(HANDLE hFile);
__int64 __stdcall setfilepointer(HANDLE hFile,ULONGLONG Distance,DWORD dwMoveMethod = FILE_BEGIN);
HANDLE __stdcall openfile(LPTSTR szFile,bool bWrite = false,DWORD dwAttr = FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_NORMAL);
HANDLE __stdcall createfile(LPTSTR szFile,DWORD dwAttr = FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_NORMAL);
BOOL closefile(HANDLE hFile);
BOOL __stdcall writefile(HANDLE hFile, LPVOID lpBuffer, LONG lCount,DWORD *dwWritten = NULL);
BOOL __stdcall readfile(HANDLE hFile,LPVOID lpBuffer,LONG lCount,DWORD *dwReaded =  NULL);
bool __stdcall getlastwfiletime(HANDLE hFile,FILETIME *lastwtime);
bool __stdcall checkfilewrite(LPTSTR szDir);
bool __stdcall isfileexists(LPTSTR szFile,WIN32_FIND_DATA * finddata = NULL);
bool __stdcall createfolder(LPTSTR szFolder);
bool ismbslead(LPCTSTR string, int ncol);
bool ismbstrail(LPCTSTR string,int ncol);
bool __stdcall getprefixbypath(LPTSTR path,LPTSTR prefix);
void __stdcall getuniquefilename(LPTSTR path,LPTSTR prefix,LPTSTR ext,LPTSTR filename);
float __stdcall stopwatch(bool end,LARGE_INTEGER *swStart);
void __stdcall fileAttr2Str(DWORD attr,LPSTR szattr);

#endif

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
/* 
	miniutil.h
	author: krkim
	mailto://durumul@gmail.com
	http://krkim.net
	If you get this source code,use freely but leave this notice.
	1990-2007,Yeamaec Communication.Co,.Ltd.All right reserved.
*/

#include "stdafx.h"
#include "miniutil.h"
#include <stdio.h>
#include <process.h>
#include <sys/stat.h>
#include <math.h>
#include <vector>
#include <stdexcept>

#include <wininet.h>

//#include <atlconv.h>
//#include <atlbase.h>
//#include <atlcom.h>
#include <process.h>
#include <sys/stat.h>

#pragma warning (push)
#pragma warning(disable : 4996)

//using namespace ATL;
using namespace std;

#pragma comment(lib,"comctl32.lib")
void __stdcall TRACELOG(LPCSTR pszFormat,...)
{
	va_list arglist;
	va_start(arglist,pszFormat);
	int nMin = _vscprintf( pszFormat, arglist );
	static const int nCount = 1024;
	CHAR szBuf[nCount] = {'\0',};

	//vsprintf_s(szBuf,nNeed,pszFormat,arglist);
	_vsnprintf_s(szBuf, nCount, nCount - 1, pszFormat, arglist);
	va_end(arglist);
	OutputDebugString((LPCTSTR)szBuf);
}

void __stdcall TRACELOGFILE(LPSTR szFile,LPCSTR pszFormat,...)
{
#if 0
	va_list arglist;
	va_start(arglist,pszFormat);
	int nMin = _vscprintf( pszFormat, arglist );
	static const int nCount = 1024;
	CHAR szBuf[nCount] = {'\0',};

	//vsprintf_s(szBuf,nNeed,pszFormat,arglist);
	_vsnprintf_s(szBuf, nCount, nCount - 1, pszFormat, arglist);
	va_end(arglist);
	OutputDebugString((LPCTSTR)szBuf);
	if(szFile !=NULL && szFile[0]){
		FILE *fp = fopen(szFile,"a+");
		if(fp){
			fputs(szBuf,fp);
			fclose(fp);
		}
	}
#else
	int nwritten = 0;
	va_list arglist;
	char szBuf[2048]={0,};
	int towritelen = 0;

	va_start(arglist,pszFormat);
	vsprintf(szBuf,pszFormat,arglist);
	va_end(arglist);

	OutputDebugString((LPCTSTR)szBuf);
	if(szFile !=NULL && szFile[0]){
		FILE *fp = fopen(szFile,"a+");
		if(!fp)
			fp = fopen(szFile,"w");
		if(fp){
			fputs(szBuf,fp);
			fclose(fp);
		}
	}
#endif
}

LPTSTR __stdcall allocbuff(LPTSTR str)
{
	LPTSTR buff;
	if(!str) return NULL;
	int len = (int) _tcslen(str) + 1;
	buff = new TCHAR[len];
	memset(buff,0,len);
	lstrcpy(buff,str);
	return buff;
}

void __stdcall freebuff(LPTSTR *str)
{
	if(*str){
		delete [] *str;
		*str = NULL;
	}
}

void __stdcall reallocbuff(LPTSTR *dest,LPTSTR src)
{
	LPTSTR buff;
	if(*dest) delete [] *dest;
	*dest = NULL;

	int len = (int) _tcslen(src) + 1;
	buff = new TCHAR[len];
	memset(buff,0,len);
	lstrcpy(buff,src);
	
	*dest = buff;
}

void __stdcall commastr(TCHAR *figure, TCHAR *buffer, bool no_comma)
{
	TCHAR numb[128];
	_tcsncpy(numb,figure,sizeof(numb)-1);
	int i,j;
	TCHAR temp[128] ={0,};
	TCHAR *p = temp;
	for(i = (int)_tcslen(numb) - 1,j = 0; i >= 0 ; i--){ 
		if(no_comma == false && j % 3 ==0 && j >= 3 && numb[i] != '.'){
			*p++ = ',';
			*p++ = numb[i];
		}
		else
			*p++ = numb[i];
		j = (numb[i] == '.') ? 0 : j + 1;
    }
	for(i = (int)_tcslen(temp) - 1; i >= 0 ; i--)
		*buffer++ = temp[i];
	*buffer = 0;
}

void __stdcall commastr(LONGLONG figure, TCHAR *buffer, bool no_comma)
{
	TCHAR numb[128];
	sprintf(numb,"%.f",(float)figure);//don't use wsprintf for floating point
	commastr((TCHAR *)numb,buffer,no_comma);
}

void __stdcall filesizestr(LONGLONG figure,TCHAR *buffer)
{
	TCHAR tempsize[128];
	TCHAR unitsize[128];
	float dwtempsize = (float)figure;
	int unit = 0;
	LONGLONG kb = (LONGLONG)(double)pow((double)2,(double)10);
	LONGLONG mb = (LONGLONG)(double)pow((double)2,(double)20);
	LONGLONG gb = (LONGLONG)(double)pow((double)2,(double)30);
	LONGLONG tb = (LONGLONG)(double)pow((double)2,(double)40);
	LONGLONG pb = (LONGLONG)(double)pow((double)2,(double)40);

	if(dwtempsize < kb){
		unit = 0;
		if(dwtempsize == 0.)
			sprintf(tempsize,"0");//BYTES => 1KB
		else
			sprintf(tempsize,"1");//BYTES => 1KB
	}
	else if(dwtempsize < mb * 1){// ~ 1MB
		unit = 0;
		sprintf(tempsize,"%.f",dwtempsize/kb);//BYTES => KB
		if(dwtempsize/kb >= 1000){ //1KB ~ 999KB
			goto nextmb;
		}
	}
	else if(dwtempsize < gb * 10){// ~ 10000MB (1mb - 9999mb)
nextmb:
		unit = 1;
		sprintf(tempsize,"%.f",dwtempsize/mb);//BYTES => MB
		if(dwtempsize/mb >= 10000){// over 10000MB
			goto nextgb;
		}
	}
	else if(dwtempsize < tb * 10){// ~ 10000MB (1mb - 9999mb)
nextgb:
		unit = 2;
		sprintf(tempsize,"%.f",dwtempsize/gb);//BYTES => GB
	}
	else if(dwtempsize < pb){
		unit = 3;
		sprintf(tempsize,"%.f",dwtempsize/tb);//BYTES => TB
	}

	TCHAR *p = _tcsrchr(tempsize,'.');
	if (p && *(p + 1) == '0') *p = '\0';
	if (p && *(p + 1) && *(p + 2) != '\0') *(p + 2) = '\0';

	commastr(tempsize,unitsize);
	TCHAR *units[ ] = {
		"KB","MB","GB","TB","PB","EB","ZB","YB"};

	if(unit >= 0 && unit <  sizeof(units) / sizeof(units[0]) )
		_tcscat(unitsize,units[unit]);
	_tcscpy(buffer,unitsize);
}

int __stdcall HexStrtoDec(LPTSTR hexastring)
{
	int ret=0, i =0;
	int p = 1;
	TCHAR hexstr[80];
	int len;
	LPTSTR buff = &hexstr[0];
	lstrcpy(buff,hexastring);
	len = (int)_tcslen(hexstr);

	while(1){
		if(hexstr[i] >= 'A' && hexstr[i] <= 'F')
			hexstr[i] = hexstr[i] -'A' + 0x0A;

		else if(hexstr[i] >= 'a' && hexstr[i] <= 'f')
			hexstr[i] = hexstr[i] -'a' + 0x0A;

		else
			hexstr[i] = hexstr[i] - '0';

		i++;
		if(i>=len) break;
	}
	for(i=len-1;i>=0;i--)
	{
		ret += hexstr[i]*p;
		p = p*16;
	}
	return ret;
}

////////////////////////////////////////////////////////////////////////////////////////////
// Raw File I/O Function
HANDLE __stdcall openfile(LPTSTR szFile,bool bWrite,DWORD dwAttr)
{
	HANDLE hFile;
	WIN32_FIND_DATA find32;
	//DWORD dwAttrDefault = FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_NORMAL;

	if(bWrite && isfileexists(szFile,&find32)){
		DWORD dwfattr = find32.dwFileAttributes;
		if((dwfattr & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_READONLY))){
			dwfattr &= ~(FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_READONLY);
			SetFileAttributes(szFile,dwfattr);
			DeleteFile(szFile);
		}
	}
	hFile = (bWrite) ?	CreateFile(szFile,GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ,NULL,CREATE_ALWAYS,dwAttr,NULL) :
						CreateFile(szFile,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,dwAttr,NULL);
	return hFile;
}

HANDLE __stdcall createfile(LPTSTR szFile,DWORD dwAttr)
{
	return openfile(szFile,true,dwAttr);
}

BOOL closefile(HANDLE hFile)
{
	return CloseHandle(hFile);
}

BOOL __stdcall writefile(HANDLE hFile, LPVOID lpBuffer, LONG lCount,DWORD *dwWritten)
{
	static const int maxsize = 32768 -1;
	ULONG  lOffset;
	DWORD wsize,written,twrite = 0L;
	LPTSTR lpPos;
	if(dwWritten) *dwWritten = 0L;

	for(lOffset = 0L; lCount > 0L; lOffset += wsize){
		wsize = (lCount <= maxsize) ? lCount : maxsize;
		lCount -= wsize;
		lpPos = (LPTSTR) lpBuffer + lOffset;
		::WriteFile(hFile,lpPos,wsize,&written,NULL);
		twrite += written;
		if(wsize != written)
			return twrite;
	}
	if(dwWritten) *dwWritten = twrite;
	return (twrite > 0);
}

BOOL __stdcall readfile(HANDLE hFile,LPVOID lpBuffer,LONG lCount,DWORD *dwReaded)
{
	static const int maxsize = 32768 -1;
	ULONG  lOffset;
	DWORD rsize,readed,tread = 0L;
	LPTSTR lpPos;
	if(dwReaded) *dwReaded = 0L;

	for(lOffset = 0L; lCount > 0L; lOffset += rsize){
		rsize = (lCount <= maxsize) ? lCount : maxsize;
		lCount -= rsize;
		lpPos = (LPTSTR) lpBuffer + lOffset;
		::ReadFile(hFile,lpPos,rsize,&readed,NULL);
		tread += readed;
		if(rsize != readed)
			return tread;
	}
	if(dwReaded) *dwReaded = tread;
	return (tread > 0);
}

__int64 __stdcall getfilepointer(HANDLE hFile)
{
	//get file pointer
	//return SetFilePointer(hFile,0,lpDistanceToMoveHigh,FILE_CURRENT);
	ULONGLONG dwStart = 0;
	LARGE_INTEGER liPos;
	liPos.QuadPart = 0;
	liPos.LowPart = ::SetFilePointer(hFile, liPos.LowPart, &liPos.HighPart ,FILE_CURRENT);
	return liPos.QuadPart;
}

__int64 __stdcall setfilepointer(HANDLE hFile,ULONGLONG Distance,DWORD dwMoveMethod)
{
	//set pointer to beginning of Catalog Data
	LARGE_INTEGER liOff;
	liOff.QuadPart = Distance;
	liOff.LowPart = ::SetFilePointer(hFile, liOff.LowPart, &liOff.HighPart,dwMoveMethod);
	return liOff.QuadPart;
}

bool __stdcall getlastwfiletime(HANDLE hFile,FILETIME *lastwtime)
{
	BOOL b;
	FILETIME CreationTime,LastAccessTime;
	b = ::GetFileTime((HANDLE)hFile, &CreationTime, &LastAccessTime, lastwtime);
	return ((b)? true : false);
}

bool __stdcall checkfilewrite(LPTSTR szDir)
{
	HANDLE hFile;
	TCHAR szTestFile[MAX_PATH];

    GetTempFileName(szDir,(LPCTSTR)"_tc",0,szTestFile);//thumbnail cache(TNC)

	if((hFile = createfile(szTestFile)) == INVALID_HANDLE_VALUE){
		DWORD dwerr = GetLastError();
		if(dwerr == ERROR_ACCESS_DENIED){
			//TRACE("err = %d(%x)\n",dwerr,dwerr);
		}
		return false;
	}
	else{
		closefile(hFile);
		DeleteFile(szTestFile);
	}
	return true;
}

bool __stdcall isfileexists(LPTSTR szFile,WIN32_FIND_DATA * finddata)
{
	BOOL bFind = FALSE;
	HANDLE flag32;
	WIN32_FIND_DATA read32={0,};//32bit porting routine..
	TCHAR szPath[MAX_PATH];
	_tcscpy(szPath,szFile);
	int len = (int)_tcslen(szPath);
	if(len > 0 && szPath[ len - 1] == _T('\\')) //bugfix : last '\\' exist, folder is unreconized even if it exists.
		szPath[len - 1] = NULL;                   // 2005 11 yeamaec

	if((flag32 = FindFirstFile(szPath,&read32)) == INVALID_HANDLE_VALUE)
		return false;
	if(finddata) *finddata = read32;
	FindClose(flag32);
	return true;
}

//2more sub-path included full path create directory
bool __stdcall createfolder(LPTSTR szFolder)
{
	TCHAR szSub[MAX_PATH+2]={0,};
	int flag,len,i;
	flag = CreateDirectory(szFolder,NULL);
	if(flag) return true;
	//c:\111\222\333
	len = (int)_tcslen(szFolder);
	if(len < 2) return false;

	for(i = 0;i < len; i++){
		szSub[i] = szFolder[i];
    if(szSub[i] == _T('\\')){ // c:\ or \\(windows network path)
			if( i >= 2){
				szSub[i+1] = NULL;
				CreateDirectory(szSub,NULL);
			}
		}
	}
	flag = CreateDirectory(szSub,NULL);
	return isfileexists(szSub);
}

bool ismbslead(LPCTSTR string, int ncol)//copy from my another project 'miedit'
{
#ifdef _UNICODE
	LPCTSTR current = string + ncol;
	return false;
#else // _UNICODE
	const unsigned char *current = (const unsigned char *)string + ncol;
	if(_ismbslead ((const unsigned char *)string, current) < 0)
		return true;
	return false;
#endif // _UNICODE
}

bool ismbstrail (LPCTSTR string, int ncol)
{
#ifdef _UNICODE
	LPCTSTR current = string + ncol;
	return false;
#else // _UNICODE
	const unsigned char *current = (const unsigned char *)string + ncol;
	if(_ismbstrail ((const unsigned char *)string, current) < 0)
		return true;
	return false;
#endif // _UNICODE
}

//디렉토리 경로에서 \\ 구분자다음의 첫문자만을 구해온다.
bool __stdcall getprefixbypath(LPTSTR path,LPTSTR prefix)
{
	TCHAR *p = path,*q = prefix,ch;
	while ((ch = *p) != NULL){
		if(p == path)
			*prefix++ = *p++;
		else if(ch == '\\'){
			ch = *++p;
			*prefix++ = ch;
			if(ch == NULL) break;
			if(ismbslead(path,(int)(p - path))){
				ch = *++p;
				*prefix++ = ch;
			}
			p++;
		}
		else
			p++;
	}
	*prefix = NULL;
	return (q != prefix);
}

void __stdcall getuniquefilename(LPTSTR path,LPTSTR prefix,LPTSTR ext,LPTSTR filename)//ext = with .
{
	SYSTEMTIME systime;
	int len = (int) _tcslen(path);
	if(len > 0 && path[len - 1] == _T('\\'))
		path[len - 1] = NULL;
	do{
		GetLocalTime(&systime);
		int x = systime.wHour+systime.wMinute+systime.wMilliseconds*systime.wSecond;
		wsprintf(filename,_T("%s\\%s%04x%s"),path,prefix,x,ext);
	}while(isfileexists(filename));
}

float __stdcall stopwatch(bool end,LARGE_INTEGER *swStart)
{
	static LARGE_INTEGER swFreq;
	if (swFreq.LowPart==0 && swFreq.HighPart==0) 	
		QueryPerformanceFrequency(&swFreq);

	if (end == false){
		QueryPerformanceCounter(swStart);
		return 0.;
	}
	else {
		float etime; //elapsed time
		LARGE_INTEGER swStop;
		QueryPerformanceCounter(&swStop);
		if (swFreq.LowPart==0 && swFreq.HighPart==0) etime = -1;
		else {
			etime = (float)(swStop.LowPart - swStart->LowPart);
			if (etime < 0) etime += 2^32;
			etime /= (swFreq.LowPart+swFreq.HighPart * 2^32);
		}
		return etime;
	}
}

void __stdcall fileAttr2Str(DWORD attr,LPSTR szattr)
{
  if(attr & FILE_ATTRIBUTE_ARCHIVE)
    *szattr++ = _T('A');
  if(attr & FILE_ATTRIBUTE_DIRECTORY)
    *szattr++ = _T('D');
  if(attr & FILE_ATTRIBUTE_HIDDEN)
    *szattr++ = _T('H');
  if(attr & FILE_ATTRIBUTE_READONLY)
    *szattr++ = _T('R');
  if(attr & FILE_ATTRIBUTE_SYSTEM)
    *szattr++ = _T('S');
  *szattr = NULL;
}

//주의 : VB와 같은 EXE 모듈에서 호출시 클래스 생성 이전또는 호출자의 FORM 로드전 또는
//       여러번 호출시에 HMODULE 의 값이 호출자인 EXE 가 되거나 DLL이 되거나 변경된다.
//       따라서 EXE 측의 폼이나 다이얼로그 가 최초 생성된 완료 이후에서 한번 호출하면
//       DLL의 Home 디렉토리가 얻어진다.(이후에 계속 호출하면 순간 exe의 home 경로로 
//       가져오게 되기도 한다.VB IDE 에서는 VB6.EXE 경로로 가져오므로 INI등의 경로가 
//       달라지므로 주의 하라.

void GetHomeDirectory(char *szHomeDirectory)
{
	char szHome[_MAX_PATH]={0,};
	char sFilename0[_MAX_PATH]={0,};
	char sFilename[_MAX_PATH]={0,};
	char *lp =NULL;
	int len=0;
	HMODULE hModule;

	hModule = AfxGetInstanceHandle();//GetModuleHandle(NULL); => EXE's PATH
	GetModuleFileName(hModule, sFilename, _MAX_PATH);//>> DLL FILE PATH
	//CString msg,a;
	//msg = sFilename0;
	//msg += "\r\n";
	//msg += sFilename;
	//a.Format("\r\nhModule = %x hModule2 = %x",hModule,hModule2);
	//msg += a;
	//AfxMessageBox(msg);
	len= strlen(sFilename);
	memcpy(szHome,sFilename,len);
	
	lp=strrchr(szHome,'\\');
	if(lp!=NULL)
		*lp = NULL;

	len=strlen(szHome);
	if(szHome[len-1]!='\\')
	{
		szHome[len] ='\\';
		szHome[len+1] = NULL;
	}
	len=strlen(szHome);
	memcpy(szHomeDirectory,szHome,len);
	szHomeDirectory[len] = NULL;
}

// 0 for all side, -1 for beginning only, 1 for end only
void removeblank(LPSTR buff,int where)
{
	int len;
	CHAR *p,*q;
	CHAR *tmpbuff;
	len = (int)_tcslen(buff);
	tmpbuff = (CHAR *)LocalAlloc (LPTR,len+1);
	_tcscpy(tmpbuff,buff);

	p = tmpbuff;
	if(where == 0 || where == -1){
		while(*p && (*p == _T(' ')||*p == _T('\t')||*p == _T('\r')||*p == _T('\n')||*p == _T('\b')))
			++p;
	}

	if(where == 0 || where == 1){
		len = (int)_tcslen(p);
		q = p + max(0,len-1);
		while(q >= p && (*q == _T(' ')||*q == _T('\t')||*q == _T('\r')||*q == _T('\n')||*q == _T('\b')))
			*q-- = _T('\0');
	}
	_tcscpy(buff,p);
	LocalFree(tmpbuff);
}

CHAR skipcomments(FILE *f)
{
	CHAR c;
	while (c = fgetc(f)) {
		while (c == '\n' || c == '\r') {
			c = fgetc(f); // Skip empty lines
		}
		if (c == '#' || c == ';') {
			while (c = fgetc(f)) {
				if (c == '\n') break;
			}
		}
		else break;
	}
	return c;
}

void removecomment(LPSTR buff)
{
	int len;
	CHAR *pbgnstr,*nextch;
	len = (int)_tcslen(buff);
	if(len > 0)
	{
		buff[len] = NULL;
		pbgnstr = _tcsrchr(buff,_T('#')); /*뒤에 # 주석이 붙은경우 주석제외*/
		if(pbgnstr != NULL){
			if(pbgnstr == buff){
				*pbgnstr = NULL;
			}
			else{
				nextch = pbgnstr - 1;
				while(nextch > buff && (*nextch == ' ' || *nextch == '\t')) nextch --;
				if(*nextch == '\'' || *nextch == '\"')//ignore char wrapped inside string data
					return;
				*pbgnstr = NULL;
			}
		}
	}
}


int wildcmp(char *wild, char *string)
{
	char *cp, *mp;


	while ((*string) && (*wild != '*')) {


		if ((*wild != *string) && (*wild != '?')) {
			return 0;
		}
		wild++;
		string++;
	}


	while (*string) {


		if (*wild == '*') {


			if (!*++wild) {
				return 1;
			}
			mp = wild;
			cp = string+1;


		} else if ((*wild == *string) || (*wild == '?')) {
			wild++;
			string++;


		} else {
			wild = mp;
			string = cp++;
		}
	}


	while (*wild == '*') {
		wild++;
	}
	return !*wild;
}

/*
바로 이전 또는 이후의 토큰을 구한다.
리턴값은 line 버퍼내의 토큰시작 포인터이다.토큰이름은 tokenname에 반환된다.
line = 수식 pos = line내 기준위치 forward = 0 (왼쪽으로),1(오른쪽으로) 나머지는 반환값
*/
CHAR * gettokenstr(CHAR *line,CHAR *delimiter,int pos,CHAR *token,int *tokenlen,int *boperator)
{
	char *start,*last;	
	CHAR *p = line + pos;
	int bop,bop2;	
	*boperator = 1;
	*tokenlen = 0;

	if(!p || p < line  || *line == NULL) return NULL;

	while(*p && (*p == ' ' || *p == '\t')) p++;
	start = last = p;	
	*boperator = bop = (strchr(delimiter,*p) != NULL);

//	if(*p =='\"'){
//		start = p++;
//
//		while(*p && (*p != '\"')) p++;
//		last = p;
//		*tokenlen = (int)(last - start) + 1 - 2;
//		_tcsncpy(token,start+1,*tokenlen);
//		*(token + *tokenlen) = NULL;
//		return last + 1;
//	} 

	if(bop)
		p++;
	else
		while(*p /*&& (*p != ' ' && *p != '\t')*/ && (bop == (bop2 = (strchr(delimiter,*p) != NULL)))) p++;

	last = p - 1;
	*tokenlen = (int)(last - start) + 1;
	_tcsncpy(token,start,*tokenlen);
	*(token + *tokenlen) = NULL;
	return last + 1;
}

BOOL PutFtpFile(char* szLocalFileName, char* szFtpFileName, char* url, int port, char* username, char* password)
{
	HINTERNET hINet = NULL;
	HINTERNET hConnection = NULL;
    BOOL res = FALSE;
	CHAR szAgent[80] = "MyFtpFile";
	int i;
	for (i=0; i<3 && !hINet; i++)
		hINet = InternetOpen(szAgent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0 );
	
	if (!hINet) 
	{
		return FALSE;
	}

	for (i=0; i<3 && !hConnection; i++)
		hConnection = InternetConnect(hINet, url, port, username, password, INTERNET_SERVICE_FTP, 0, 0);
	
	if (!hConnection) 
	{
		InternetCloseHandle(hINet);	
		return FALSE;
	}
	//char buff[300];
	//wsprintf(buff,"file : %s,%s",szLocalFileName,szFtpFileName);
	//MessageBox(NULL,buff,"ftp",MB_OK);

	for (i=0; i<3 && !res; i++)
		res = ::FtpPutFile( hConnection, szLocalFileName, szFtpFileName, FTP_TRANSFER_TYPE_BINARY,0 );

	if(!res){
		CHAR szBuf[380]; 
		DWORD dw = GetLastError(); 
		wsprintf(szBuf, "failed: GetLastError returned %u,locfile = %s\r\n", dw,szLocalFileName); 
		//WriteLog(szBuf); 
	}
	InternetCloseHandle(hConnection);
	InternetCloseHandle(hINet);

	return res;/* TRUE = success */
}

int GetFtpFile(char* szLocalFileName, char* szFtpFileName, char* url, int port, char* username, char* password)
{
	HINTERNET hINet = NULL;
	HINTERNET hConnection = NULL;
    BOOL res = FALSE;
	CHAR szAgent[80] = "MyFtpFile";
	int i;
	int rc = 0;
	for (i=0; i<3 && !hINet; i++)
		hINet = InternetOpen(szAgent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0 );
	
	if (!hINet) 
	{
		return 1;
	}

	for (i=0; i<3 && !hConnection; i++)
		hConnection = InternetConnect(hINet, url, port, username, password, INTERNET_SERVICE_FTP, 0, 0);
	
	if (!hConnection) 
	{
		InternetCloseHandle(hINet);	
		return 2;
	}
	//char buff[300];
	//wsprintf(buff,"file : %s,%s",szLocalFileName,szFtpFileName);
	//MessageBox(NULL,buff,"ftp",MB_OK);
	BOOL failExists = FALSE;
	DWORD dwAttrs = FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_NORMAL;
	//DWORD_PTR dwContext = 0L;
	DWORD dwContext = 0L;
	CHAR szFile[MAX_PATH]={0,};
	strcpy(szFile,szLocalFileName);
	for (i=0; i<3 && !res; i++){
		res = ::FtpGetFile( hConnection,szFtpFileName, szFile,failExists,dwAttrs, FTP_TRANSFER_TYPE_BINARY,dwContext);
		if(res == FALSE){
			Sleep(500);
			DWORD dw = ::GetLastError();
			if(dw == ERROR_SHARING_VIOLATION){//The process cannot access the file because it is being used by another process.
				strcpy(szFile,szLocalFileName);
				wsprintf(szFile,"%s.%03d",szLocalFileName,i);
			}
		}
	}
	strcpy(szLocalFileName,szFile);
	if(!res){
		CHAR szBuf[380]; 
		DWORD dw = ::GetLastError(); 
		DWORD dwError;
		wsprintf(szBuf, "failed: GetLastError returned %u,locfile = %s\r\n", dw,szLocalFileName); 
		TRACE(szBuf);
		CHAR szBuffer[1024];
		DWORD BuffLen = sizeof(szBuffer)- 1;
		InternetGetLastResponseInfo(&dwError,szBuffer,&BuffLen);
		TRACE("%s\n",szBuffer);
		rc = dw;
		//WriteLog(szBuf); 
	}
	InternetCloseHandle(hConnection);
	InternetCloseHandle(hINet);

	return rc;/* TRUE = success */
}

#pragma warning (pop)
TAG miniutil
Posted by 3LegsCrow::하늘날다 두루물

댓글을 달아 주세요


#include <afximpl.h> 가 경로에 없거나 컴파일시 오류 해결법(이전 버전 포팅시 주로 발생)

$(VCInstallDir)atlmfc\src\mfc 를 Include Path에 추가

그래도 에러나면

프로젝트파일의 StdAfx.h 열어서 WIN_VER를 맞춰준다.

#define WINVER 0x0501

TAG afximpl.h
Posted by 3LegsCrow::하늘날다 두루물

댓글을 달아 주세요


이미 순차정렬된 레코드 배열에서 특정값을 찾기위한 탐색알고리즘으로는 여러가지가 있는데 그중 중간값으로 2분하여 탐색하는 이진탐색은 비교적 적은 코드로 단순한 for 문으로 하는 순차탐색 보다 탁월한 O(log2N)의 탐색시간을 자랑한다.
특히,배열이나 레코드 등 내부에서 관리하는 리스트가 대용량일때 빛을 발한다.

 // binarysearch.cpp : O(log2N)의 탐색 평균속도를 내는 2진탐색 샘플
// http://krkim.net

#include "stdafx.h"
#include "windows.h"

struct MYDATA{
 int pos;
 int style;
};

int binarysearch(int *arraylist,int arraysize,int findvalue);
int binarysearchprev(MYDATA *arraylist,int arraysize,int findvalue,int findstyle);

int _tmain(int argc, _TCHAR* argv[])
{
 int arraylist[]={10,12,13,15,18,27,39,100,101,113,215,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
 int arraylist2[]={-1,-1,-1};

 MYDATA mylist[] = { {10,1},{15,1},{17,1},{110,1},{120,2},{129,1},{2100,1},{-1,1},{-1,1},{-1,1}};

 //binarysearch(arraylist,ARRAYSIZE(arraylist),15);
 binarysearchprev(mylist,ARRAYSIZE(mylist),2000,2);
 return 0;
}

int binarysearch(int *arraylist,int arraysize,int findvalue)
{
 int lo = 0;
 int hi = arraysize - 1;
 int cp;
 int loop = 0;
 int dummyvalue = -1;
// while(hi > 0 && arraylist[hi] == -1) hi--;

 for(;;){
  loop++;
  cp = (lo + hi) / 2;
  
  if(findvalue == arraylist[cp]){
   break;
  }
  if(lo >= hi)
   break;

  if(arraylist[cp] == dummyvalue)//뒷부분이 dummy로 채워져 있음
   hi = cp - 1;
  else if(findvalue > arraylist[cp]){
   lo = cp + 1;
   //같은값이 없으면 항상 크거나 작은 값 둘중 어느하나가 불규칙하게 탐색된다.
   //이유는,배열의 데이타 갯수 여부의 홀짝에 따라 중간값이 달라지기 때문이다.
   //따라서,같은값이 없을때 작은값을 구하기 위해 비교한다.
   //같은값만 찾으려면 아래는 필요없음.또는 데이타의 끝에 dummy 값을 만나도 멈춤
   //같은값이 없으면 작은값중 최대값으로 찾고 뒷부분의 더미바이트를 만나면 멈춘다.
   if(findvalue < arraylist[lo] || arraylist[lo] == dummyvalue){
    break;
   }
  }
  else
   hi = cp - 1;
 }
 char msg[300];
 sprintf(msg,"loop[%d] findvalue = %d => array[%d] = %d\r\n",loop,findvalue,cp,arraylist[cp]);
 OutputDebugStr(msg);

 return 0;
}


//findvalue보다 pos가 작거나같고 style이 findstyle 과 다른 항목 찾기
int binarysearchprev(MYDATA *arraylist,int arraysize,int findvalue,int findstyle)
{
 int lo = 0;
 int hi = arraysize - 1;
 int cp;
 int loop = 0;
 int dummyvalue = -1;
 // while(hi > 0 && arraylist[hi] == -1) hi--;

 for(;;){
  loop++;
  cp = (lo + hi) / 2;
  if(findvalue == arraylist[cp].pos)
   break;
  if(lo >= hi)
   break;
  if(arraylist[cp].pos == dummyvalue)//뒷부분이 dummy로 채워져 있음
   hi = cp - 1;
  else if(findvalue > arraylist[cp].pos){
   lo = cp + 1;
   if(findvalue < arraylist[lo].pos || arraylist[lo].pos == dummyvalue){
    break;
   }
  }
  else
   hi = cp - 1;
 }
 int loop2 = 0;
 int findpos = -1;
 for(int pos = cp; findpos == -1 && pos >= 0 ; pos--){
  loop2++;
  if(arraylist[pos].pos <= findvalue && arraylist[pos].style != findstyle)
   findpos = pos;
 }
 char msg[300];
 if(findpos != -1){
  cp = findpos;
  sprintf(msg,"loop[%d] loop2[%d] findvalue = (%d,%d) => array[%d] = (%d,%d)\r\n",
   loop,loop2,findvalue,findstyle,cp,arraylist[cp].pos,arraylist[cp].style);
  OutputDebugStr(msg);
 }
 else{
  sprintf(msg,"loop[%d] loop2[%d] findvalue = (%d,%d) => not found in this list\r\n",
   loop,loop2,findvalue,findstyle);
  OutputDebugStr(msg);
 }

 return 0;
}


Posted by 3LegsCrow::하늘날다 두루물

댓글을 달아 주세요

[팁하나]
디버그 모드에서 응용프로그램이 끝나면서 쏟아지는 Detected Memory Leaks! 가 많다면,분명 간과할 일이 아니다. 왜냐하면, 단 몇 바이트가 세더라도 365일 풀 가동되는 서비스나 기업 및 상업용 프로그램의 경우는 제품과 개발자,나아가 회사에 너무나도 치명적일 수 있기 때문이다.
단순 무식하게 하면 지정된 때에 재시작 하도록 하면 되겠지만... 기본적인 메모리누수를 잡지 않으면,언젠가 기억도 가물한 업체나 바이어에게서 연락이 올지도 모를 일이다.

이와 비슷한 도구로 Vld를 비롯하여 본 내용과 유사한 다른 글들이 인터넷에 다수 존재하지만,따라해도 마치 퍼오고 확인은 안한 글들처럼 실행도 안되고 불확실 하다. 또 Vld같은 경우는 디버그 툴이면서도 버그를 내장한 것을 직접 경험한 바 있는데,의외로,핵심적인 것만 추려서 여기에 간단한 방법을 소개한다.

시작!

프로그램 시작 지점에서,
 _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF);
 //_CrtSetReportMode(_CRT_ERROR,_CRTDBG_MODE_DEBUG);
 //AfxEnableMemoryTracking(allocMemDF|checkAlwaysMemDF);
 //_CrtSetBreakAlloc(5551);

를 선언한 후,

조사식창에 _crtBreakAlloc 를 입력한 후 값에 출력창에 나타나는 메모리릭 디버깅 정보에서
{} 블럭 사이의 메모리 할당번호를 입력한후 F5누르면 해당 번째 메모리가 할당되는 지점에서 Break가 걸린다.만약 _crtBreakAlloc 값이 제대로 활성화가 안되면 자신이 사용하는 각 버전에 맞는 msvcrxxd.DLL 로 (예: {,,msvcr90d.dll}_crtBreakAlloc) 로 추가한 다음(사실 특히 이부분에 대해 대부분 모를 것이다,이글을 쓰는 핵심 포인트는 바로 이것이라 해도 과언이 아니다) app의 소멸자에서 _CrtDumpMemoryLeaks();를 추가하면 메모리릭 발생시 뜨는 Detect Memory Leaks! 의 {} 번호를 값에 입력한다.
실행 처음시, 브레이크 포인트 걸면 해당 번호에 메모리 할당될때 break 걸린다.
또는,위 주석 내용중 _CrtSetBreakAlloc(5551); 처럼 직접 메모리 할당하는 순번을 직접 적어줘도 된다.

단,코드생성 옵션값 중 런타임라이브러리를 MT가 아닌 - 다중쓰레드 디버그 DLL /MDd 선택해야 한다.

출처:본인(http://krkim.net/128)




Posted by 3LegsCrow::하늘날다 두루물

댓글을 달아 주세요

Remote Procedure Call 관련하여 호출한적도 없는 Network 함수 임에도 이런 경우가 발생한다.
0x7c81eb33에 첫째 예외가 있습니다. 0x000006BA: RPC 서버를 사용할 수 없습니다

이 Exception Error 는 비록 내가 직접 Remote 접근을 위한 Network 함수를 호출하지 않았다해도
원격 디버거가 비활성되고 탐색창 Shell (네트워크가 보이는)이나 INET 함수가 시스템 내부적으로 호출되면 발생하는 것으로 보인다.

이 부분에 대해 디버그창 TRACE 문구가 뜰때 어디서 호출되는지 확인하는 법

디버그메뉴 > 예외 > 추가 를 눌러
새형식: WIN32 Exception
이름:아무거나
번호: 위의 경우 000006BA
입력하여 추가하면 해당 Exception이 발생하면
디버그 출력창에는 DuruEdit.exe의 0x76fab727에 첫째 예외가 있습니다. 0x000006BA: aa 라고 뜨면서
Break Proint가 걸려 해당 시점에서 중단된다.


일단,INET 함수나 Shell 또는 이를 포괄하는 Network 관련 함수를 직접 호출하지 않고 또는 호출했다하더라도 버그 없는 온전한 코드라면,이 문제는 무시해도 무관 합니다.
혹시라도 빠트린 내용이 있을지 모르니 더 자세한 건 first-chance exception 으로 구글링 해보면 됩니다^^.
출처: http://krkim.net/89
TAG rpc
Posted by 3LegsCrow::하늘날다 두루물

댓글을 달아 주세요

UAC(사용자 계정 컨트롤) 와 CreateProcess의  ERROR_ELEVATION_REQUIRED,SendMessage의 ERROR_ACCESS_DENIED

UAC(사용자 계정 컨트롤) 보안기능은 사용자에겐 불편함이,또 개발자에게는 참으로 골치덩이이자,손볼게 많은 것임에 틀림없다.
더군다나 PC업계 MS-Windows 에서는 (이제야) 32비트와 64비트의 과도기에 접어들면서 WOW에 따른 접근제한등과 맞물려서 개발자가 신경써야 할 부분이 늘어나게 되어 더욱 혼잡하게 된 상황인듯하다.

UAC는 VC++ 2005,2008 이상 빌드시 메니페스트에 쉽게 FIX가능한데, 여기서 asInvoker 로 하자니,프로그램 파일폴더쓰기 금지,HKEY_LOCAL_MACHINE 레지스트리 쓰기금지,파일 쓰기 금지 등 관리자 권한과 관련된 어떠한 접근도 불가능하다. 그렇다면 manifest에 관리자 권한 상승이 필요한(requireAdministrator) 으로 빌드하면 이런 문제는 쉽게 해결이 된다.
하지만 이것도 마냥 편할수 가 없는 문제가 발생한다.
일례로 탐색기의 Shell Extension에서 해당 프로그램에 File Path를 넘겨 해당 작업을 수행하고자 할 경우,
100% 실패할 것이다.(물론,사용자가 UAC 기능 끄기를 하지 않는한)

그렇다고 이렇게 UAC 실행 수준 권한 요구 를 리소스에 FIX 하면, 이 권한중에(정확하게는 highestAvailable 포함 3개) 무언가 하나를 선택해서 고정시켜야 하기 때문에,응용프로그램 생산자 입장에서는 왠지 매끄럽지가 못하다.
이것은 프로그램이 우선 현재 실행중인 일반적인 사용자 권한 (asInvoker)로 프로그램을 빌드하고 프로그램내에서 권리자 권한이 요구되는 레지스트리 쓰기,파일 쓰기등이 시점에서 COM Moniker 나 별도의 Service로 EXE를 따로 만들어 올려놓고,프로그램에서 유동적으로 필요할 때만,관리자 권한을 획득하고 반환하면 된다는 등의 우회방법이 공공연 하게 돌고 있다.

어쨋튼 이제서야 보안에 눈뜬 MS측에서 새롭게 내놓은 이 보안정책이 예전엔 EXE 하나가 모두 해결할 일을 MS에서는 불편하더라도 대세니 각 DLL이나 COM,별도의 EXE 서비스등으로 쪼개서 개발하고 관리하라는 식의 지침(?)을 내리는 것 같은 느낌이다.

각설하고,그렇다면 실제 UAC 관련하여 CreateProcess 와 SendMessage등의 처리시 어떻게 되는 건지 테스트 결과를 보도록 하자.이걸 실제로 확인해 보려면 테스트 프로그램을 만들어 보아야 한다.
먼저 호출되는 대상 EXE는 requireAdministrator 로 빌드 되었다.
결론부터 말하자면, UAC로 인해 내권한 보다 더 높은 관리자 권한 상승이 필요한(requireAdministrator) EXE 실행시 나 메모리 공유 관련등의 접근은 원칙적으로 100% 실패한다.(어차피 나혼자 쓰는 PC용 OS인데 이렇게 복잡할 필요있나라고 할수 있지만,단순한 1 User 용 이었던 MS의 Windows 였지만 이제는 완벽하게 Single User 를 탈피하고  Home PC 급으로 안정화된지 수년, Multi User 를 지향하는 Windows 로서 이런 보안을 강화하는 메카니즘상으로 보면 당연한 결과일 것이다.)

위 CreateProcess는 관리자권한이 요구되는 레벨의 EXE를 일반사용자 권한으로 실행된 EXE에서 호출시,
ERROR_ELEVATION_REQUIRED에러가 발생한다. 이 해결법은,ShellExecute나 ShellExecuteEx 함수로 해결할 수 있다.

일반적으로는 SendMessage는 무결성 수준(Integrity Level)이 낮은 프로세스에서 높은 프로세스로의 SendMessage는 UAC가 WIM(Windows Integrity Mechanism)를 이용해 차단해 버리기 때문에 메세지 전달자체가 안되고 ERROR_ACCESS_DENIED 에러가 발생한다.
이를 위한 해결 방법은 IPC의 다른 방법은 얼마든지 있다.실제로 UAC는 레지스트리,특정폴더 쓰기작업등의 물리적인 접근제한 이외에도 WIM을 사용하여 무결성 수준이 다른 process간에도 Message를 보내지 못하도록 차단하는 것이다.
(Shared Memory나 단순한 인스턴스 형태의 1대1 공유시 파일 매핑이 자주 쓰이지만 UAC Elevation 에 관련된 메시징은 아래 링크를 참고하거나 더 검색해보시길.. 대략 보면 권한높은쪽에서 ChangeWindowMessageFilter() 호출하면 된다고 하는듯....)

The Windows Vista and Windows Server 2008 Developer Story: Windows Vista Application Development Requirements for User Account Control (UAC)

사용자 삽입 이미지


http://msdn.microsoft.com/en-us/library/aa905330.aspx


http://msdn.microsoft.com/library/en-us/IETechCol/dnwebgen/ProtectedMode.asp?frame=true

http://msdn.microsoft.com/en-us/library/Aa480152
http://msdn.microsoft.com/en-us/library/Aa480152#appcomp_topic21


Low Rights 의 대표적인 보호모드 Explorer 가 접근할 수 있는 영역에 대한 문서
Understanding and Working in Protected Mode Internet Explorer
http://msdn.microsoft.com/en-us/library/Bb250462
현재 사용자 권한으로 실행중인 탐색기에서 Shell Extension DLL 을 작성하고 관리자 권한 EXE 에 대해 CreateProcess , SendMessage 등은 이처럼 오류가 날것 이니 참조 하십시오.
(DLL의 manifest에 아무리 권한 수준을 준다고 해도 소유자인 EXE의 권한으로 로드되어 실행되므로 무용지물임)

호출하고자 하는 본체 EXE를 asInvoker로 작성하고 레지스트리 HKEY_LOCAL_MACHINE등에 쓰기 접근하지 말거나,프로그램 파일폴더등에 접근을 하지 못하게 하면 호출은 성공합니다만 ..

파일쓰기,프로그램 폴더 접근,레지스트리 쓰기등의 나머지 로직은 애초에 관리자권한으로 빌드하거나,
앞서 말한 다른 두가지 방법을 찾아봐도 될것이다.

아래는 kxLibrary(자작,구 KFC 윈도우즈 SDK 플랫폼 개발 라이브러리 클래스-KFC1.0이름으로 풀소스 공개) 로 작성된 테스트 소스이다.

 
/* 
  $Id: DECmd.cpp 3 2009-12-20 19:12:53Z krkim $ $Revision: 3 $
  $HeadURL: https://krkim-laptop/svn/KFC/trunk/Demo/Dialog/DECmd.cpp $
 */

#include "stdafx.h"
#include "DlgCmd.h"

#include "resource.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
//
#include "KFCApp.h"
#include "kxRegUtil.h"
#include <tchar.h>

#define WOW64API __fastcall
#define GetProc(m, n) ((PVOID)GetProcAddress(GetModuleHandleA(m), n))
#ifndef _WIN64
//#define GetProc(m, n) ((PVOID)GetProcAddress(GetModuleHandleA(m), n))
#endif
class CApp : public KFCApp  
{
public:
 virtual BOOL InitInstance();
 virtual BOOL ExitInstance();
 CApp();
 virtual ~CApp();
};
/*for dll
KFC_DLL_ENTRYPOINT(CApp)
*/

/*for exe*/

KFC_ENTRYPOINT(CApp)

//int APIENTRY WinMain(HINSTANCE hInstance,
//                     HINSTANCE hPrevInstance,
//                     LPSTR     lpCmdLine,
//                     int       nCmdShow)
//{
// int a = 0;
// //CExampleDlg *demodlg = new CExampleDlg(IDD_MAIN,0);
// MSG msg;
// //ghWnd = CreateDialogParam(hInstance,MAKEINTRESOURCE
(IDD_MAKESFX_DIALOG),NULL,(DLGPROC)MainDlgProc,(LPARAM)0);
// //ShowWindow(ghWnd,SW_SHOW);
// // Main message loop:
// while (GetMessage(&msg, NULL, 0, 0)){
//  TranslateMessage(&msg);
//  DispatchMessage(&msg);
// }
//
// return 0;
//}

void __stdcall TRACELOG(LPCTSTR pszFormat,...)
{
 va_list arglist;
 va_start(arglist,pszFormat);
 //int nMin = _vscprintf((LPCSTR)pszFormat, arglist );
 static const int nCount = 1024;
 TCHAR szBuf[nCount] = {'\0',};

 //vsprintf_s(szBuf,nNeed,pszFormat,arglist);
 //_vsnprintf_s((LPSTR)szBuf, nCount, nCount - 1, 
(LPCSTR)pszFormat, arglist);
 vsnprintf((LPSTR)szBuf, nCount, (LPCSTR)pszFormat, arglist);
 va_end(arglist);
 FILE *fp = fopen("c:\\DEShellx.log","a");
 OutputDebugString((LPCTSTR)szBuf);
 if(fp){
  fprintf(fp,szBuf);
  MessageBox(0,szBuf,"msg",MB_OK);
  fclose(fp);
 }
 else{
  CHAR mess[80];
  DWORD dwerr = GetLastError();
  wsprintf(mess,"error=%d\r\n",dwerr);
  MessageBox(0,szBuf,mess,MB_OK);
 }
}

CApp::CApp()
{

}

CApp::~CApp()
{

}

BOOL WOW64API Wow64CheckProcess( )
{
 typedef BOOL (WINAPI *PFNISWOW64PROCESS)( HANDLE
 hProcess, PBOOL Wow64Process );

 PFNISWOW64PROCESS pfnIsWow64Process =(PFNISWOW64PROCESS)
  GetProc("KERNEL32.dll", "IsWow64Process");
 //fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(
 // GetModuleHandle(TEXT("kernel32")),"IsWow64Process");

 BOOL bIsWow64;

 if (pfnIsWow64Process && pfnIsWow64Process(
GetCurrentProcess(), &bIsWow64))
  return(bIsWow64);

 return(FALSE);
}

BOOL CApp::InitInstance()
{
 LPTSTR strArg = GetCommandLine();
 HWND hBrood;
 ATOM hAtom;
 STARTUPINFO si={0,};
 PROCESS_INFORMATION pi={0,};
 TCHAR EXEPath[MAX_PATH];
 HANDLE hFile = INVALID_HANDLE_VALUE;
 TCHAR szProgram[MAX_PATH * 2 + 1]={0,};

 si.cb = sizeof(si);

 TRACELOG("IsWOW64Process: %d\r\n",Wow64CheckProcess());
 kxReg::LoadString(HKEY_CURRENT_USER,REG_DURUEDIT,
"InstallDir","",EXEPath,MAX_PATH);
 if(lstrlen(InstPath) <= 0)
  return FALSE;

 MessageBox(0,strArg,"test",MB_OK);
 BOOL error= 0;
 hBrood = FindWindow(DURUEDIT_CLASSNAME,NULL);
 // 실행중이지 않으면 직접 실행시킨다.
 int i = 1;
 LPTSTR lpFile = 0;
 TCHAR szTest[MAX_PATH]="c:\\vfo.log";
 if(__argc > 1){
  lpFile = __argv[1];
 }
 else
  lpFile = szTest;
 if(hBrood == NULL) {
  wsprintf(szProgram,"%s \"%s\"",EXEPath,lpFile);
  //관리자권한이 요구되는 레벨의 EXE를 일반사용자 권한으로
  //실행된 EXE에서 호출시,
  //ERROR_ELEVATION_REQUIRED에러가 발생한다.
  //따라서,같은 권한으로 실행된 EXE에서(탐색기포함) 호출해야 성공한다.
  //다른 방법은 ShellExecute나 ShellExecuteEx로 호출하여야 한다.
  //관리자 권한이 아니면 c:\Program Files 나 HKEY_
  //LOCAL_MACHINE 레지스트리,파일쓰기등
  //의 에러도 난다.
  if (CreateProcess(NULL,szProgram,NULL,NULL,
   FALSE,0,NULL,NULL,&si,&pi)) {
   WaitForInputIdle(pi.hProcess,5000);
   CloseHandle(pi.hProcess);
   CloseHandle(pi.hThread);
  }
  else{
   //UAC로 인해 내권한 보다 더 높은 관리자 권한 상승이
   //필요한(requireAdministrator) EXE 실행시 오류난다.
   //하지만,대상 EXE가 asInvoker 권한이면 성공한다.
   //다만,그 EXE에서 권한에 따른 제약이 따르게 된다.
   //(c:\Program Files 나 HKEY_LOCAL_MACHINE 레지스트리,파일쓰기)
   error= 1;
   DWORD dwError = GetLastError();
   if(dwError == ERROR_ELEVATION_REQUIRED){
   }
   TRACELOG("CreateProcess failed! dwError=[%d],
    szProgram=[%s]\r\n",dwError,szProgram);

  }
  // 실행중이면 파일을 열도록 한다.
 } else {
  //관리자권한이 요구되는 레벨의 EXE를 일반사용자 
  //권한으로 실행된 EXE에서 호출시,
  //ERROR_ACCESS_DENIED 에러가 발생한다.
  //권한이 같거나  SendMessage 메세지를 받는 대상
  //윈도우를 소유한 EXE가 높은 무결성 수준 권한으로
  //실행중 이여야 SendMessage가 성공한다.
  hAtom = GlobalAddAtom(lpFile);
  if(hAtom){
   UINT n = SendMessage(hBrood,WM_OPEN_ATOM,(WPARAM)hAtom,0);
   DWORD dwError = GetLastError();
  if(dwError == ERROR_ACCESS_DENIED){

   }
   TRACELOG("SendMessage n = %d(%x) dwError=[%d]\r\n",n,n,dwError);
   GlobalDeleteAtom(hAtom);
  }
  else{
   error= 1;
   DWORD dwError = GetLastError();
   if(dwError == ERROR_ACCESS_DENIED){

   }
   TRACELOG("GlobalAddAtom failed! dwError=[%d]\r\n",dwError);
  }
  SetForegroundWindow(hBrood);
  }
 if(error){
#if 0   //권한상승 효과주는 콜
  //ShellExecute 를 사용 하는 방법
  if(IsUserAnAdmin() == FALSE)
  //프로그램이 관리자 권한인지 알 수 있는 함수
  {
   //관리자 권한으로 실행 시킨다.
   SHELLEXECUTEINFO si;
   ZeroMemory(&si, sizeof(SHELLEXECUTEINFO));
   si.cbSize = sizeof(SHELLEXECUTEINFO);
   si.hwnd = NULL;
   si.fMask = SEE_MASK_FLAG_DDEWAIT | SEE_MASK_FLAG_NO_UI;
   si.lpVerb = _T("runas");
   si.lpFile = _T("프로그램명");
   si.lpParameters = _T("파라미터");
   si.nShow = SW_SHOWNORMAL;
   si.lpDirectory = NULL;
   ShellExecuteEx(&si);
   /*si.hProcess로 제어*/
  }
#endif
#if 0  //권한상승 효과주는 콜
  wsprintf(szProgram,"\"%s\"",lpFile);
  HINSTANCE hInstance = (HINSTANCE)
   ShellExecute(NULL,_T("open"),InstPath,szProgram,NULL,SW_SHOWNORMAL);
  if(hInstance <= (HINSTANCE)HINSTANCE_ERROR){
   TRACELOG("ShellExecute error!\r\n");
  }
#endif
 }

 return TRUE;
}

BOOL CApp::ExitInstance()
{
 return TRUE;
}

int __stdcall StartUp(int * mask)
{
 DlgCmd dlg(IDD_STARTUP,0);
 int f =  dlg.DoModal();
 *mask = dlg.m_mask;
 return f;
}

참고할 만한 함수:
ChangeWindowMessageFilterEx Function
Modifies the User Interface Privilege Isolation (UIPI) message filter for a specified window.

Syntax

BOOL WINAPI ChangeWindowMessageFilterEx(
  __in         HWND hWnd,
  __in         UINT message,
  __in         DWORD action,
  __inout_opt  PCHANGEFILTERSTRUCT pChangeFilterStruct
);

Parameters

hWnd [in]
HWND

A handle to the window whose UIPI message filter is to be modified.

message [in]
UINT

The message that the message filter allows through or blocks.

action [in]
DWORD

The action to be performed, and can take one of the following values:

Value Meaning
MSGFLT_ALLOW
1

Allows the message through the filter. This enables the message to be received by hWnd, regardless of the source of the message, even it comes from a lower privileged process.

MSGFLT_DISALLOW
2

Blocks the message to be delivered to hWnd if it comes from a lower privileged process, unless the message is allowed process-wide by using the ChangeWindowMessageFilter function or globally.

MSGFLT_RESET
0

Resets the window message filter for hWnd to the default. Any message allowed globally or process-wide will get through, but any message not included in those two categories, and which comes from a lower privileged process, will be blocked.


pChangeFilterStruct [in, out, optional]
PCHANGEFILTERSTRUCT

Optional pointer to a CHANGEFILTERSTRUCT structure.

Return Value

BOOL

If the function succeeds, it returns TRUE; otherwise, it returns FALSE. To get extended error information, call GetLastError.

Remarks

UIPI is a security feature that prevents messages from being received from a lower-integrity-level sender. You can use this function to allow specific messages to be delivered to a window even if the message originates from a process at a lower integrity level. Unlike the ChangeWindowMessageFilter function, which controls the process message filter, the ChangeWindowMessageFilterEx function controls the window message filter.

An application may use the ChangeWindowMessageFilter function to allow or block a message in a process-wide manner. If the message is allowed by either the process message filter or the window message filter, it will be delivered to the window.

Note that processes at or below SECURITY_MANDATORY_LOW_RID are not allowed to change the message filter. If those processes call this function, it will fail and generate the extended error code, ERROR_ACCESS_DENIED.

Certain messages whose value is smaller than WM_USER are required to be passed through the filter, regardless of the filter setting. There will be no effect when you attempt to use this function to allow or block such messages.

Examples

For an example, see MSDN Code Gallery.

Requirements

Minimum supported client

Windows 7

Minimum supported server

Windows Server 2008 R2

Header

Winuser.h (include Windows.h)

Library

User32.lib

DLL

User32.dll

See Also

Reference
ChangeWindowMessageFilter

Conceptual

Windows 

Send comments about this topic to Microsoft

Build date: 9/7/2010


출처: http://krkim.net/39

Posted by 3LegsCrow::하늘날다 두루물

댓글을 달아 주세요

오늘도 잠시 유용한 팁하나 올립니다.
윈7 32비트 응용프로그램에서 64비트 DLL 호출 및 등록은 죽었다 깨어나도 안된다.
그리고 윈도우 95부터 등장한 32비트에서 16비트 하위 호환실행을 지원하기 위한 WOW(Windows-On-Windows) 시스템에 의해 이제는 64비트 os하의 32bit 어플들이 지원되긴 하는데 이 32비트 응용프로그램들은 (윈도우즈 파일들)모두 SysWOW64 폴더로 리다이렉션 되기 때문에 System32 하의 64비트 프로그램들은 호출이 기본적으로 안되게 되어 있다. 아래 소스를 참조 바란다.

따라서, 직접 DLL을 로드하여 DllRegisterServer 를 호출하려면 호출자 EXE도 같은 64비트여야 한다.
여기서는 간략하게 32비트 EXE에서 64비트 DLL을 등록하는 방법을 설명한다.
탐색기 팝업메뉴를 제어하기 위한 Shell Extension DLL 은 64비트 OS에선 반드시 64비트로 또한 작성되어야 함.

BOOL DEApp::RegisterShellCommand(BOOL bRegist)
{
 TCHAR szOS[256];
 int whatbit;
 OSVERSIONINFOEX osvi;
 TCHAR szDLL[MAX_PATH];
 GetOSString(szOS,&osvi,&whatbit);
 GetHomeDirectory(szDLL);
 if(whatbit == 64)
  lstrcat(szDLL,"DEShl64.dll");
 else
  lstrcat(szDLL,"DEShl.DLL");
 
 int whatsize = sizeof(int);
 typedef BOOL (WINAPI *LPFN_Wow64Disable)(PVOID* OldValue);
 typedef BOOL (WINAPI *LPFN_Wow64Revert)(PVOID OldValue);
 PVOID OldValue;
 LPFN_Wow64Disable pWowDis = NULL;
 LPFN_Wow64Revert pWowRev = NULL;
 BOOL bRet = 0;
 BOOL fc=1;
 //i am 32bit app and os is 64bit,register 64bit dll and
 //redirect folder.krkim
 if(whatsize == 4 && whatbit == 64){
  pWowDis = (LPFN_Wow64Disable) GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
   "Wow64DisableWow64FsRedirection");
  pWowRev = (LPFN_Wow64Revert) GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
   "Wow64RevertWow64FsRedirection");
  if(pWowDis)
   bRet = pWowDis(&OldValue);
 
  TCHAR szEXE[MAX_PATH*2];
  if(bRegist){
   wsprintf(szEXE,"/s \"%s\"",szDLL);
   ShellExecute(NULL,_T("open"),"regsvr32",szEXE,NULL,SW_SHOWDEFAULT);
  }
  else{
   wsprintf(szEXE,"/u /s \"%s\"",szDLL);
   ShellExecute(NULL,_T("open"),"regsvr32",szEXE,NULL,SW_SHOWDEFAULT);
  }
  if(bRet && pWowRev)
   bRet = pWowRev(OldValue);
 }
 else if((whatbit / whatsize) == 8){ //same bit
 //don't call different bit between app and dll, 32<->64bit direct
  fc = RegisterDll(szDLL,bRegist);
 }
 return fc;

}


*추가:
if(whatsize == 4 && whatbit == 64) 로 WOW64에서 실행중인 32비트 어플인지를 체크하는 부분을
다음 함수로 대체해도 된다.

#define WOW64API __fastcall
#define GetProc(m, n) ((PVOID)GetProcAddress(GetModuleHandleA(m), n))

BOOL WOW64API Wow64CheckProcess( )
{
 typedef BOOL (WINAPI *PFNISWOW64PROCESS)( HANDLE hProcess, PBOOL Wow64Process );

 PFNISWOW64PROCESS pfnIsWow64Process =(PFNISWOW64PROCESS)
  GetProc("KERNEL32.dll", "IsWow64Process");
 //fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(
 // GetModuleHandle(TEXT("kernel32")),"IsWow64Process");

 BOOL bIsWow64;

 if (pfnIsWow64Process && pfnIsWow64Process(GetCurrentProcess(), &bIsWow64))
  return(bIsWow64);

 return(FALSE);
}

아니면 위 로직을 아예 DLL 자체의 DllRegisterServer( ) 와 DllUnregisterServer( )에 심어서
WOW64를 구분하여,리다이렉션을 해제하고 원복하도록 레지스트리에 등록하는
실제 코드의 앞뒤로 Wrapping 하여 호출하게 해놓고,외부에서는 그냥 이 함수들을 원래대로 호출하게 해도 되겠다.

*RegisterDll는 단순히 해당경로의 dll을 LoadLibrary하여 DllRegisterServer 와 DllUnregisterServer를 호출하는 함수임.귀찮아서 나머지는 생략하고 올립니다.
출처: 나(
http://krkim.net)

Posted by 3LegsCrow::하늘날다 두루물

댓글을 달아 주세요

  1. 전도연이짱 2013.10.17 18:08  댓글주소  수정/삭제  댓글쓰기

    저도 컨텍스트 메뉴때문에 dll을 32bit,64bit 두개로 만들었는데
    실행파일이 32bit전용이라
    LoadLibrary하면 64bit용은 못불러서 골치 썩고있습니다 ㅠㅠ..
    그러던중 regsvr32를 ShellExecute()로 실행하면 되겠다 싶었는데 문제는
    LoadLibrary()할때 뱉어내는 에러들이 좀 부러워서 다른 방법이 없을까
    검색하던 도중 이사이트를 알게되었습니다( 구글에서 ShellExecute regsvr32 로 검색ㅎㅎ )

    글을 보다가 궁금한게 생겼는데요. ShellExecute로 regsvr32를 불러다 쓰는 소스 위에 kernel32에
    Wow64DisableWow64FsRedirection 이런 API는 왜 불러다 쓰는거고
    맨마지막에 DLL파일을 왜 LoadLibrary()해주는지 모르겠거든요
    RegisterDll()함수 호출하기전에 regsvr32로 이미 DllRegisterServer,DllUnregisterServer이런걸 하고있지않습니까?
    다시 RegisterDll()함수를 호출하는 목적이 뭔지 궁금합니다^^;그럼 좋은하루되세요

    • Favicon of http://durueduit.com BlogIcon DURUEDIT.COM 2013.10.21 00:04  댓글주소  수정/삭제

      님께서 작성한 32bit APP가 사용자 PC에서 설치될때는 사용자의 32bit,64bit OS를 모두 지원해야 합니다. 따라서,wow64 리다이렉션 기능이 지원되는지 여부를 체크하고 64비트인경우와 32비트인 일반적인경우(RegisterDLL() 부분) 에 대해 동시지원 하기 위한 코드입니다.

    • Favicon of http://durueduit.com BlogIcon DURUEDIT.COM 2013.10.21 00:07  댓글주소  수정/삭제

      즉,둘다 연속해서 호출하는게 아니고(if else죠)
      wow64는 32bit os에서는 없는 함수 입니다.(pWowRev = NULL)


  2. 전도연이짱 2013.10.23 13:11  댓글주소  수정/삭제  댓글쓰기

    안녕하세요 답변 감사드립니다. 제가 이해가 좀 덜되어 그런데
    주인장님 말씀은

    64bit운영체제일 경우 regsvr32로 dll을 등록/해제하고
    운영체제가 32bit일 경우 regsvr32로 dll을 등록/해제 하지 않고
    LoadLibrary()처리해주기 위해서 하신건지요?


    else if((whatbit / whatsize) == 8){ //same bit
    //don't call different bit between app and dll, 32<->64bit direct
    fc = RegisterDll(szDLL,bRegist);
    }

    여기서 궁금한게 RegisterDll()에서는 어떤 dll을 LoadLibrary()하신다는건지요?kernel32.dll인지 아니면 shell extension dll인지

  3. Favicon of http://durueduit.com BlogIcon DURUEDIT.COM 2013.10.25 01:09  댓글주소  수정/삭제  댓글쓰기

    자신의 shell extension dll 입니다.

How to Fix Toolbar Tooltip's black background at a moment

이 현상은 원래 HIDE 된 상태의 팝업 윈도우에 WS_EX_LAYERED 의 레이어 속성이 들어가고 반투명
윈도우를 만들고 %를 올려서 서서히 보이게 하기 위한 기능으로 자주 사용하는데,문제는
HIDE된 Window가 나타날때 바로 검은반전 색상으로 껌뻑거리게 되는 현상 때문이다.

바로 테마를 먹힌 툴팁도 그러한데, 이런 현상은 다음처럼 반투명 레이어가 기본으로 툴바에 적용되는
툴팁의 속성을 변경해줌으로써 해결한다.

아래의 코드는 kxLibrary 의 툴팁 클래스 소스중 해당 부분이다.

 /*
   very important! windows 7 and theme applied, the tooltip filled black background at a moment.
   toolbar's default tooltip 컨트롤이 검은배경에 껌뻑거림 현상이 발견됨 win7
   이것은 WS_EX_LAYERED 속성으로 SW_SHOW 시점에서 반투명과(WS_EX_LAYERED) 불투명(non WS_EX_LAYERED)
   속성 전환시 나타나는 현상이다. krkim in duruedit
  */
 m_wndToolBar.GetToolTips().TurnOffTransparentLayer();
 m_wndToolBar.GetToolTips().SetDelayTime(TTDT_AUTOMATIC,1000);

void kxToolTipCtrl::TurnOffTransparentLayer()
{
    if(IsWindow())
        ModifyStyleEx(WS_EX_TRANSPARENT|WS_EX_LAYERED,0);//black fill background tooltip appear
}

출처: 자작(http://krkim.net)

Posted by 3LegsCrow::하늘날다 두루물

댓글을 달아 주세요

How to open explorer Folder and select the file programmatically

짬나는 시간에 아주 단순하지만 아주 유용한 팁을 하나 소개하고자 한다.
자신의 응용 프로그램에서 마치 뮤토런트 같이 파일 위치 열기시 폴더만 딸랑 열게 아니라,
(해당 파일을 찾아 사용자가 일일이 스크롤 해야 하므로 번거롭다)
아예 파일까지 선택해주는 기능을 수행하려면 다음과 같이 하면 된다.

아마 보통 szOpenFile 가 있는 폴더를 열고자 할 경우, 패스에서 파일명 앞('\\') 까지 자른후,

ShellExecute(NULL,_T("open"),szOpenPath,"",NULL,SW_SHOWDEFAULT);
이런식으로 자주들 쓰고 있었을 것이다.

아래처럼 약간 수정하면, 탐색기로 해당 파일을 선택하면서 오픈할 수가 있다.

  TCHAR szSelFile[MAX_PATH+30];
  wsprintf(szSelFile,"/select, \"%s\"",szOpenFile);
  ShellExecute(NULL,_T("open"),"explorer.exe",szSelFile,NULL,SW_SHOWDEFAULT);

아참,주의 할것은 ,뒤에 공백이 있어야 한다는 거 잊지 마세요,,
^^

출처: http://krkim.net

Posted by 3LegsCrow::하늘날다 두루물

댓글을 달아 주세요

툴바에 텍스트 추가시 세로폭(높이) 가 커지는데 줄이는 방법
How to decrease ToolBar Height when added text and dropdown style

 SetToolbarText(IDM_FIND);
 SetToolbarText(IDM_REPLACE);

 dwButtonStyle = m_ToolBar.GetButtonStyle(m_ToolBar.CommandToIndex(IDM_FIND));
 dwButtonStyle |= (BTNS_DROPDOWN | BTNS_CHECK |BTNS_AUTOSIZE);//여기서 BTNS_AUTOSIZE로해야 버튼들의 폭이 일률적으로 같게 안들어난다.
 m_ToolBar.SetButtonStyle(m_ToolBar.CommandToIndex(IDM_FIND), dwButtonStyle);

 dwButtonStyle = m_ToolBar.GetButtonStyle(m_ToolBar.CommandToIndex(IDM_REPLACE));
 dwButtonStyle |= (BTNS_DROPDOWN | BTNS_CHECK |BTNS_AUTOSIZE);
 m_ToolBar.SetButtonStyle(m_ToolBar.CommandToIndex(IDM_REPLACE), dwButtonStyle);

위 처럼, 툴바에 텍스트 + 드롭다운 시 세로폭이 엄청 커지게 된다.
이를 줄이는 방법은,
 /*텍스트가 포함될 때 cy가 늘어나는데 사이즈를 줄이게 조절*/
 TBMETRICS tb;
 tb.cbSize = sizeof(TBMETRICS);
 tb.dwMask = 0xff;
 m_ToolBar.GetMetrics(&tb);
 tb.cyPad = 1;
 m_ToolBar.SetMetrics(&tb);

하여 padding 값을 줄이면 아이콘만 있을때 처럼 줄일수 있다.

출처:본인

Posted by 3LegsCrow::하늘날다 두루물

댓글을 달아 주세요

  1. highlander 2010.11.06 14:17  댓글주소  수정/삭제  댓글쓰기

    이런!!! 툴바 옵션 전체를 다 해 봤다우... 덕분에 해결했소. 외국사이트에도 이거 해결못해서 윈도우 포지션 바꾼다는 얘기가 수두룩하더이다. 거듭 감사하오.

윈도우즈 프로그래밍을 조금만 하다보면 컨트롤을 직접 만들거나 기존의 컨트롤을 Customizing 할 필요를 느낄 것이다.
여기서는 그 중에서도 커스텀 메뉴의 것에 대해 심심한 팁을 소개하고자 한다.

즉, WM_DRAWITEM이나 MFC의 OnDrawItem()에서의 처리를 말하는 것이다.

막상 이부분을 개발하다가 대부분의 사람들이 한가지 이해가 안가는 것이 있을 것이다.
그것은 아마도 아무리 MEASUREITEM에 값을 설정해도,실제로 DRAWITEM시의 사각 영역이 약 14 만큼 더 늘어나서 항상 들어온다 라는 사실..

과연 왜 그런가? 그 이유는 MS-윈도우즈가 내 윈도우의 프로시듀어가 메세지를 받도록 메세지큐에 전달하기 훨씬 이전에 이미 시스템 내부적으로 항상 CHECKBOX의 크기만큼 더해주기 때문에 그렇다.



It will be Increased to 14 pixel on DrawItem more than MeasureItem setting.

BOOL kxNSMenu::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{

  dc.DrawText(pItem->szMenuText, rci, DT_CALCRECT|DT_SINGLELINE|DT_LEFT|DT_VCENTER);
  lpMeasureItemStruct->itemHeight = rci.Height();
  lpMeasureItemStruct->itemWidth = rci.Width();

}

BOOL kxNSMenu::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
         lpDrawItemStruct->rcItem 's width more than 14 pixel...
}

why?

Windows will add the width of a menu checkmark,so you subtract more width as
 int cx = GetSystemMetrics(SM_CXMENUCHECK)-1;

따라서 결론은,아래 예시처럼 WM_MEASUREITEM 메세지에서 해당 부분의 소스를 이렇게 하면 된다.
CXMENUTEXTMARGIN 는 자신이 용도에 맞게 더해줄 Custom Margin 값이다.

BOOL kxNSMenu::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{

  dc.DrawText(pItem->szMenuText, rci, DT_CALCRECT|DT_SINGLELINE|DT_LEFT|DT_VCENTER);
  lpMeasureItemStruct->itemHeight = rci.Height();
  lpMeasureItemStruct->itemWidth = rci.Width();

  lpMeasureItemStruct->itemWidth -= cx;  
  lpMeasureItemStruct->itemWidth += CXMENUTEXTMARGIN; // your margin

}


이 걸 모르면, 이미 상업용으로 전락한지 꽤 되는 국내 오합지졸의 메카 데브피아 같은 인력 포탈 시장 바닥에 올라온 수준처럼 0으로 주었는데 왜 작은 사각박스가 계속 뜨냐는둥의 삽질 질/답 드립을 하게 된다.

만일 메뉴아이템 크기를 0 으로 원하면  lpMeasureItemStruct->itemWidth = 0 할 것이 아니라
lpMeasureItemStruct->itemWidth -= GetSystemMetrics(SM_CXMENUCHECK); 해야 된다는 것이다.

사실,이런 부분은 MS 제품군의 사용자(개발자)의 삽질이라는 표현보다는 파보면 파볼수록 이런식으로 엉성하게 밖에 만들지 못한 MS의 자체 제품군의 로직에서 조차 들쑥 날쑥한 비표준의 극치를 달리는 삽질이라고 해야 옳다.

현실의 굴레에 갇혀서 또 이런 것을 알면서도 어쩔수 없이 써야만 하는 뭇 개발자들의 심정은 어떠할까?
이글을 발견하지 않고도 이걸 이미 알고 있던 사람은 윈도우즈 메카니즘을 어느정도 꿰뚫고 이해한 중고렙이상의 경험치를 쌓은 개발자라 인정한다.
더 궁금하다면
kxLibrary 나 well-done coolmenu 소스를 보시라!

출처:http://krkim.net/34


Posted by 3LegsCrow::하늘날다 두루물

댓글을 달아 주세요

2010. 9. 13. 19:18

VC++ MyVector Simple Template Class C | C++ | VC++2010. 9. 13. 19:18

My Vector Simple Array Template Class (fake vector)
Posted by 3LegsCrow::하늘날다 두루물

댓글을 달아 주세요

두루에디트의 불법복제 방지 기능차원에서
PC고유 식별자로 HDD 시리얼 번호를 검사하는 로직에서 가상화 기반에서 오류가 발생했다.
코드를 안정화 하든가 다른 방안을 검토 해봐야 겠다.

딴건 다 무시하고,짱돌이 보내준 소중한 아래 정보(이벤트 로그 내용) 로 추적시작!
APPCRASH 는 메모리 폴트에서 야기된다.즉,잘못된 메모리 참조.

: 오류 모듈 이름: vfo.dll
: 예외 오프셋: 0000172b


1) 우선,해당 오프셋이라는 곳이 뭔 삽질내용이 들어가있는건지 확인하기 위해
VC++ 툴 dumpbin /disasm로 EXE로 어셈블리로 변환하여
C:\Program Files (x86)\DuruEdit>dumpbin /disasm vfo.dll /OUT:BB.TXT

하여 출력된 결과를 편집기로 불러오니 아래와 같음
10001725: 8B 01 mov eax,dword ptr [ecx]
10001727: 8B 4C 24 04 mov ecx,dword ptr [esp+4]
1000172B: 8B 04 88 mov eax,dword ptr [eax+ecx*4]
1000172E: 0F B7 00 movzx eax,word ptr [eax]
10001731: 84 C0 test al,al

여기서 로드될때마다 동적으로 물리는 메모리 BASE 주소인 세그먼트
앞 2바이트(100 0)를 제외한 실제 모듈내 오프셋인
오류 이벤트의 예외 오프셋: 0000172b 에 해당하는 줄을 찾아 내용 확인

2) 이제 vfo.dll 프로젝트를 열어 디버그정보 포함 릴리즈모드로 컴파일한 후
vfo1.dll로 리네임 후 덤프하여 열기
C:\Program Files (x86)\DuruEdit>dumpbin /disasm vfo1.dll /out:cc.txt

같은 코드부분을 찾기,메모리주소가 달라져서 쉽게 매칭이 안됨.
baseaddr 주소를 강제지정 하면 맞출수는 있지만, 귀칞고.. 무식하게 눈으로 찾기
DriveType@DiskInfo@@QAEPADI@Z: /
10001B01: 8B 01 mov eax,dword ptr [ecx]
10001B03: 8B 4C 24 04 mov ecx,dword ptr [esp+4]
10001B07: 8B 04 88 mov eax,dword ptr [eax+ecx*4]
10001B0A: 0F B7 00 movzx eax,word ptr [eax]

를 발견,
DiskInfo의 DriveType 이라는 함수에서 잘못된 메모리 (null pointer) eax+ecx*4
의 값을 참조하다가 죽어버림.


소스원형:
컴퓨터에 설치된 HDD갯수를 찾아 순서대로 정보를 얻어오는데,
하드정보를 구한후 채우는 벡터리스트 m_list 가 0 개여서 나타나는 문제네,.
으,, 왜 하드 감지에 실패...ㅜㅜ;; 터보메모리 끼면 0번째가 터보메모리가
먼저 잡혀서 hdd 는 1부터드만... 이건 가상화에서 실제 물리적 장치접근하다
가상화기반에서 작동중인 win7이 뭔가 물지적 장치의존적인 기능수행에 안정화 관련되서 뻑나네... 저번에 윈7 VM기능으로 윈XP 돌리니까, 윈XP에서 실행 프로그램 오류나고 안정적이지 못해서 걍 지웠던 케이스가 생각나네...

char* DiskInfo::DriveType (UINT drive)
{
if (m_list[drive][0] & 0x0080)
return "Removable";
else if (m_list[drive][0] & 0x0040)
return "Fixed";
else return "Unknown";
}

if (m_list.size() <= 0 || drive >= m_list.size())
return NULL;
로 임시로 처리할예정인데.

원래 이거 왜한거 냐면, 불법복제 방지 차원에서 복제해서 다른컴퓨터에서는
실행 안되게 할려고 하드 시리얼 조사해서 레지에 암호화 저장해서,
실제 하드의 일련번호를 조사해 같은지 검사하는 과정인데,,,,,

이렇게 오류가 나서 시렬을 못구해오면,,이건 어케 해야남..ㅋ쿠ㅜ;;;
다른방법을 찾아야나.... 뭔가 좋은 아이디어없냐??



--- 디스크 정보 얻는 부분 이거 일반적인 방법인데,,,---
#include "StdAfx.h"
//for native code only uncomment the next line and use UnmanagedCode.h and UnmanagedCode.cpp
//as source files in your project, for managed C++ leave it as is
#define NATIVE_CODE
#include "DiskInfo.h"
#ifndef NATIVE_CODE
using namespace System::Runtime::InteropServices;
#endif

char DiskInfo::HardDriveSerialNumber [1024];

DiskInfo* DiskInfo::m_instance = NULL;

BOOL DiskInfo::AddIfNew(USHORT *pIdSector)
{
BOOL bAdd = TRUE;
for(int i =0; i< m_list.size();i++)
{
if(memcmp(pIdSector,m_list[i],256 * sizeof(WORD)) == 0)
{
bAdd = false;
break;
}
}
if(bAdd)
{
WORD* diskdata = new WORD[256];
::memcpy(diskdata,pIdSector,256*sizeof(WORD));
m_list.push_back(diskdata);
}
return bAdd;
}

int DiskInfo::ReadPhysicalDriveInNTUsingSmart (void)
{
int done = FALSE;
int drive = 0;
DWORD dwError = 0;

for (drive = 0; drive < MAX_IDE_DRIVES; drive++)
{
HANDLE hPhysicalDriveIOCTL = 0;

// Try to get a handle to PhysicalDrive IOCTL, report failure
// and exit if can't.

TCHAR driveName [256];
wsprintf (driveName, "\\\\.\\PhysicalDrive%d", drive);

// Windows NT, Windows 2000, Windows Server 2003, Vista
hPhysicalDriveIOCTL = CreateFile(driveName,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);

if(hPhysicalDriveIOCTL != INVALID_HANDLE_VALUE)
{
GETVERSIONINPARAMS GetVersionParams;
DWORD cbBytesReturned = 0;

// Get the version, etc of PhysicalDrive IOCTL
memset ((void*) & GetVersionParams, 0, sizeof(GetVersionParams));

if ( DeviceIoControl (hPhysicalDriveIOCTL, SMART_GET_VERSION,
NULL,
0,
&GetVersionParams, sizeof (GETVERSIONINPARAMS),
&cbBytesReturned, NULL) )
{
// Allocate the command buffer
ULONG CommandSize = sizeof(SENDCMDINPARAMS) + IDENTIFY_BUFFER_SIZE;
PSENDCMDINPARAMS Command = (PSENDCMDINPARAMS) malloc (CommandSize);
// Retrieve the IDENTIFY data
// Prepare the command
#define ID_CMD 0xEC // Returns ID sector for ATA
Command -> irDriveRegs.bCommandReg = ID_CMD;
DWORD BytesReturned = 0;
if ( DeviceIoControl (hPhysicalDriveIOCTL,
SMART_RCV_DRIVE_DATA, Command, sizeof(SENDCMDINPARAMS),
Command, CommandSize,
&BytesReturned, NULL) )

{
// Print the IDENTIFY data
USHORT *pIdSector = (USHORT *)
(PIDENTIFY_DATA) ((PSENDCMDOUTPARAMS) Command) -> bBuffer;
AddIfNew(pIdSector);
done = TRUE;
}
free (Command);
}
else{
dwError = GetLastError();
}
// Done
CloseHandle (hPhysicalDriveIOCTL);
}
}

return done;
}

int DiskInfo::ReadPhysicalDriveInNTWithAdminRights (void)
{
int done = FALSE;
int drive = 0;
BYTE IdOutCmd [sizeof (SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1];
for (drive = 0; drive < MAX_IDE_DRIVES; drive++)
{
HANDLE hPhysicalDriveIOCTL = 0;

// Try to get a handle to PhysicalDrive IOCTL, report failure
// and exit if can't.
TCHAR driveName [256];

wsprintf (driveName, "\\\\.\\PhysicalDrive%d", drive);

// Windows NT, Windows 2000, must have admin rights
hPhysicalDriveIOCTL = CreateFile (driveName,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, 0, NULL);

if (hPhysicalDriveIOCTL != INVALID_HANDLE_VALUE)
{
GETVERSIONOUTPARAMS VersionParams;
DWORD cbBytesReturned = 0;

// Get the version, etc of PhysicalDrive IOCTL
memset ((void*) &VersionParams, 0, sizeof(VersionParams));

if ( DeviceIoControl (hPhysicalDriveIOCTL, DFP_GET_VERSION,
NULL,
0,
&VersionParams,
sizeof(VersionParams),
&cbBytesReturned, NULL) )
{


// If there is a IDE device at number "i" issue commands
// to the device
if (VersionParams.bIDEDeviceMap > 0)
{
BYTE bIDCmd = 0; // IDE or ATAPI IDENTIFY cmd
SENDCMDINPARAMS scip;

// Now, get the ID sector for all IDE devices in the system.
// If the device is ATAPI use the IDE_ATAPI_IDENTIFY command,
// otherwise use the IDE_ATA_IDENTIFY command
bIDCmd = (VersionParams.bIDEDeviceMap >> drive & 0x10) ? \
IDE_ATAPI_IDENTIFY : IDE_ATA_IDENTIFY;

memset (&scip, 0, sizeof(scip));
memset (IdOutCmd, 0, sizeof(IdOutCmd));

if ( DoIDENTIFY (hPhysicalDriveIOCTL,
&scip,
(PSENDCMDOUTPARAMS)&IdOutCmd,
(BYTE) bIDCmd,
(BYTE) drive,
&cbBytesReturned))
{
USHORT *pIdSector = (USHORT *)((PSENDCMDOUTPARAMS) IdOutCmd) -> bBuffer;
AddIfNew(pIdSector);
done = TRUE;
}
}
}

CloseHandle (hPhysicalDriveIOCTL);
}
}

return done;
}


// Required to ensure correct PhysicalDrive IOCTL structure setup
#pragma pack(4)


//
// IOCTL_STORAGE_QUERY_PROPERTY
//
// Input Buffer:
// a STORAGE_PROPERTY_QUERY structure which describes what type of query
// is being done, what property is being queried for, and any additional
// parameters which a particular property query requires.
//
// Output Buffer:
// Contains a buffer to place the results of the query into. Since all
// property descriptors can be cast into a STORAGE_DESCRIPTOR_HEADER,
// the IOCTL can be called once with a small buffer then again using
// a buffer as large as the header reports is necessary.
//


//
// Types of queries
//
//
//typedef enum _STORAGE_QUERY_TYPE {
// PropertyStandardQuery = 0, // Retrieves the descriptor
// PropertyExistsQuery, // Used to test whether the descriptor is supported
// PropertyMaskQuery, // Used to retrieve a mask of writeable fields in the descriptor
// PropertyQueryMaxDefined // use to validate the value
//} STORAGE_QUERY_TYPE, *PSTORAGE_QUERY_TYPE;

//
// define some initial property id's
//
//
//typedef enum _STORAGE_PROPERTY_ID {
// StorageDeviceProperty = 0,
// StorageAdapterProperty
//} STORAGE_PROPERTY_ID, *PSTORAGE_PROPERTY_ID;
//
////
//// Query structure - additional parameters for specific queries can follow
//// the header
////
//
//typedef struct _STORAGE_PROPERTY_QUERY {
//
// //
// // ID of the property being retrieved
// //
//
// STORAGE_PROPERTY_ID PropertyId;
//
// //
// // Flags indicating the type of query being performed
// //
//
// STORAGE_QUERY_TYPE QueryType;
//
// //
// // Space for additional parameters if necessary
// //
//
// UCHAR AdditionalParameters[1];
//
//} STORAGE_PROPERTY_QUERY, *PSTORAGE_PROPERTY_QUERY;
//
//
//#define IOCTL_STORAGE_QUERY_PROPERTY CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS)
//
//
////
//// Device property descriptor - this is really just a rehash of the inquiry
//// data retrieved from a scsi device
////
//// This may only be retrieved from a target device. Sending this to the bus
//// will result in an error
////
//
//typedef struct _STORAGE_DEVICE_DESCRIPTOR {
//
// //
// // Sizeof(STORAGE_DEVICE_DESCRIPTOR)
// //
//
// ULONG Version;
//
// //
// // Total size of the descriptor, including the space for additional
// // data and id strings
// //
//
// ULONG Size;
//
// //
// // The SCSI-2 device type
// //
//
// UCHAR DeviceType;
//
// //
// // The SCSI-2 device type modifier (if any) - this may be zero
// //
//
// UCHAR DeviceTypeModifier;
//
// //
// // Flag indicating whether the device's media (if any) is removable. This
// // field should be ignored for media-less devices
// //
//
// BOOLEAN RemovableMedia;
//
// //
// // Flag indicating whether the device can support mulitple outstanding
// // commands. The actual synchronization in this case is the responsibility
// // of the port driver.
// //
//
// BOOLEAN CommandQueueing;
//
// //
// // Byte offset to the zero-terminated ascii string containing the device's
// // vendor id string. For devices with no such ID this will be zero
// //
//
// ULONG VendorIdOffset;
//
// //
// // Byte offset to the zero-terminated ascii string containing the device's
// // product id string. For devices with no such ID this will be zero
// //
//
// ULONG ProductIdOffset;
//
// //
// // Byte offset to the zero-terminated ascii string containing the device's
// // product revision string. For devices with no such string this will be
// // zero
// //
//
// ULONG ProductRevisionOffset;
//
// //
// // Byte offset to the zero-terminated ascii string containing the device's
// // serial number. For devices with no serial number this will be zero
// //
//
// ULONG SerialNumberOffset;
//
// //
// // Contains the bus type (as defined above) of the device. It should be
// // used to interpret the raw device properties at the end of this structure
// // (if any)
// //
//
// STORAGE_BUS_TYPE BusType;
//
// //
// // The number of bytes of bus-specific data which have been appended to
// // this descriptor
// //
//
// ULONG RawPropertiesLength;
//
// //
// // Place holder for the first byte of the bus specific property data
// //
//
// UCHAR RawDeviceProperties[1];
//
//} STORAGE_DEVICE_DESCRIPTOR, *PSTORAGE_DEVICE_DESCRIPTOR;


// function to decode the serial numbers of IDE hard drives
// using the IOCTL_STORAGE_QUERY_PROPERTY command
char * DiskInfo::flipAndCodeBytes (char * str)
{
static char flipped [1000];
int num = strlen (str);
strcpy (flipped, "");
for (int i = 0; i < num; i += 4)
{
for (int j = 1; j >= 0; j--)
{
int sum = 0;
for (int k = 0; k < 2; k++)
{
sum *= 16;
switch (str [i + j * 2 + k])
{
case '0': sum += 0; break;
case '1': sum += 1; break;
case '2': sum += 2; break;
case '3': sum += 3; break;
case '4': sum += 4; break;
case '5': sum += 5; break;
case '6': sum += 6; break;
case '7': sum += 7; break;
case '8': sum += 8; break;
case '9': sum += 9; break;
case 'a': sum += 10; break;
case 'b': sum += 11; break;
case 'c': sum += 12; break;
case 'd': sum += 13; break;
case 'e': sum += 14; break;
case 'f': sum += 15; break;
}
}
if (sum > 0)
{
char sub [2];
sub [0] = (char) sum;
sub [1] = 0;
strcat (flipped, sub);
}
}
}

return flipped;
}


typedef struct _MEDIA_SERAL_NUMBER_DATA {
ULONG SerialNumberLength;
ULONG Result;
ULONG Reserved[2];
UCHAR SerialNumberData[1];
} MEDIA_SERIAL_NUMBER_DATA, *PMEDIA_SERIAL_NUMBER_DATA;


int DiskInfo::ReadPhysicalDriveInNTWithZeroRights (void)
{
int done = FALSE;
int drive = 0;

for (drive = 0; drive < MAX_IDE_DRIVES; drive++)
{
HANDLE hPhysicalDriveIOCTL = 0;

// Try to get a handle to PhysicalDrive IOCTL, report failure
// and exit if can't.
TCHAR driveName [256];

wsprintf (driveName, "\\\\.\\PhysicalDrive%d", drive);

// Windows NT, Windows 2000, Windows XP - admin rights not required
hPhysicalDriveIOCTL = CreateFile (driveName, 0,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, 0, NULL);


if (hPhysicalDriveIOCTL != INVALID_HANDLE_VALUE)
{
STORAGE_PROPERTY_QUERY query;
DWORD cbBytesReturned = 0;
char buffer [10000];

memset ((void *) & query, 0, sizeof (query));
query.PropertyId = StorageDeviceProperty;
query.QueryType = PropertyStandardQuery;

char serialNumber [1000];

memset (buffer, 0, sizeof (buffer));

if ( DeviceIoControl (hPhysicalDriveIOCTL, IOCTL_STORAGE_QUERY_PROPERTY,
& query,
sizeof (query),
& buffer,
sizeof (buffer),
& cbBytesReturned, NULL) )
{
STORAGE_DEVICE_DESCRIPTOR * descrip = (STORAGE_DEVICE_DESCRIPTOR *) & buffer;
strcpy (serialNumber,
flipAndCodeBytes ( & buffer [descrip -> SerialNumberOffset]));
}
else
{
DWORD err = GetLastError ();

}

memset (buffer, 0, sizeof (buffer));

if ( DeviceIoControl (hPhysicalDriveIOCTL, IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER,
NULL,
0,
& buffer,
sizeof (buffer),
& cbBytesReturned, NULL) )
{
MEDIA_SERIAL_NUMBER_DATA * mediaSerialNumber =
(MEDIA_SERIAL_NUMBER_DATA *) & buffer;
strcpy (serialNumber, (char *) mediaSerialNumber -> SerialNumberData);

}
else
{
DWORD err = GetLastError ();
}

CloseHandle (hPhysicalDriveIOCTL);
}
}

return done;
}


// DoIDENTIFY
// FUNCTION: Send an IDENTIFY command to the drive
// bDriveNum = 0-3
// bIDCmd = IDE_ATA_IDENTIFY or IDE_ATAPI_IDENTIFY
BOOL DiskInfo::DoIDENTIFY (HANDLE hPhysicalDriveIOCTL, PSENDCMDINPARAMS pSCIP,
PSENDCMDOUTPARAMS pSCOP, BYTE bIDCmd, BYTE bDriveNum,
PDWORD lpcbBytesReturned)
{
// Set up data structures for IDENTIFY command.
pSCIP -> cBufferSize = IDENTIFY_BUFFER_SIZE;
pSCIP -> irDriveRegs.bFeaturesReg = 0;
pSCIP -> irDriveRegs.bSectorCountReg = 1;
pSCIP -> irDriveRegs.bSectorNumberReg = 1;
pSCIP -> irDriveRegs.bCylLowReg = 0;
pSCIP -> irDriveRegs.bCylHighReg = 0;

// Compute the drive number.
pSCIP -> irDriveRegs.bDriveHeadReg = 0xA0 | ((bDriveNum & 1) << 4);

// The command can either be IDE identify or ATAPI identify.
pSCIP -> irDriveRegs.bCommandReg = bIDCmd;
pSCIP -> bDriveNumber = bDriveNum;
pSCIP -> cBufferSize = IDENTIFY_BUFFER_SIZE;

return ( DeviceIoControl (hPhysicalDriveIOCTL, DFP_RECEIVE_DRIVE_DATA,
(LPVOID) pSCIP,
sizeof(SENDCMDINPARAMS) - 1,
(LPVOID) pSCOP,
sizeof(SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1,
lpcbBytesReturned, NULL) );
}


// ---------------------------------------------------

// (* Output Bbuffer for the VxD (rt_IdeDinfo record) *)
typedef struct _rt_IdeDInfo_
{
BYTE IDEExists[4];
BYTE DiskExists[8];
WORD DisksRawInfo[8*256];
} rt_IdeDInfo, *pt_IdeDInfo;


// (* IdeDinfo "data fields" *)
typedef struct _rt_DiskInfo_
{
BOOL DiskExists;
BOOL ATAdevice;
BOOL RemovableDevice;
WORD TotLogCyl;
WORD TotLogHeads;
WORD TotLogSPT;
char SerialNumber[20];
char FirmwareRevision[8];
char ModelNumber[40];
WORD CurLogCyl;
WORD CurLogHeads;
WORD CurLogSPT;
} rt_DiskInfo;


#define m_cVxDFunctionIdesDInfo 1


// ---------------------------------------------------


int DiskInfo::ReadDrivePortsInWin9X (void)
{
int done = FALSE;

HANDLE VxDHandle = 0;
pt_IdeDInfo pOutBufVxD = 0;
DWORD lpBytesReturned = 0;

// set the thread priority high so that we get exclusive access to the disk
BOOL status =
// SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
SetPriorityClass (GetCurrentProcess (), REALTIME_PRIORITY_CLASS);
// SetPriorityClass (GetCurrentProcess (), HIGH_PRIORITY_CLASS);

// 1. Make an output buffer for the VxD
rt_IdeDInfo info;
pOutBufVxD = &info;

// *****************
// KLUDGE WARNING!!!
// HAVE to zero out the buffer space for the IDE information!
// If this is NOT done then garbage could be in the memory
// locations indicating if a disk exists or not.
ZeroMemory (&info, sizeof(info));

// 1. Try to load the VxD
// must use the short file name path to open a VXD file
//char StartupDirectory [2048];
//char shortFileNamePath [2048];
//char *p = NULL;
//char vxd [2048];
// get the directory that the exe was started from
//GetModuleFileName (hInst, (LPSTR) StartupDirectory, sizeof (StartupDirectory));
// cut the exe name from string
//p = &(StartupDirectory [strlen (StartupDirectory) - 1]);
//while (p >= StartupDirectory && *p && '\\' != *p) p--;
//*p = '\0';
//GetShortPathName (StartupDirectory, shortFileNamePath, 2048);
//sprintf (vxd, "\\\\.\\%s\\IDE21201.VXD", shortFileNamePath);
//VxDHandle = CreateFile (vxd, 0, 0, 0,
// 0, FILE_FLAG_DELETE_ON_CLOSE, 0);
VxDHandle = CreateFile ("\\\\.\\IDE21201.VXD", 0, 0, 0,
0, FILE_FLAG_DELETE_ON_CLOSE, 0);

if (VxDHandle != INVALID_HANDLE_VALUE)
{
// 2. Run VxD function
DeviceIoControl (VxDHandle, m_cVxDFunctionIdesDInfo,
0, 0, pOutBufVxD, sizeof(pt_IdeDInfo), &lpBytesReturned, 0);

// 3. Unload VxD
CloseHandle (VxDHandle);
}
else
//::MessageBox (NULL, L"ERROR: Could not open IDE21201.VXD file",
// TITLE, MB_ICONSTOP);
return FALSE;


// 4. Translate and store data
unsigned long int i = 0;
for (i=0; i<8; i++)
{
if((pOutBufVxD->DiskExists[i]) && (pOutBufVxD->IDEExists[i/2]))
{

WORD* diskdata = new WORD[256];
for (int j = 0; j < 256; j++)
diskdata [j] = pOutBufVxD -> DisksRawInfo [i * 256 + j];

// process the information for this buffer
BOOL bAdd = TRUE;
for(int j =0; j< m_list.size();j++)
{
if(memcmp(diskdata,m_list[j],256 * sizeof(WORD)) == 0)
{
bAdd = false;
break;
}
}
if(bAdd)
m_list.push_back(diskdata);
else
delete diskdata;
done = TRUE;
}
}

// reset the thread priority back to normal
SetPriorityClass (GetCurrentProcess (), NORMAL_PRIORITY_CLASS);

return done;
}


#define SENDIDLENGTH sizeof (SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE


int DiskInfo::ReadIdeDriveAsScsiDriveInNT (void)
{
int done = FALSE;
int controller = 0;

for (controller = 0; controller < 16; controller++)
{
HANDLE hScsiDriveIOCTL = 0;
TCHAR driveName [256];

// Try to get a handle to PhysicalDrive IOCTL, report failure
// and exit if can't.
wsprintf (driveName, "\\\\.\\Scsi%d:", controller);

// Windows NT, Windows 2000, any rights should do
hScsiDriveIOCTL = CreateFile (driveName,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, 0, NULL);


if (hScsiDriveIOCTL != INVALID_HANDLE_VALUE)
{
int drive = 0;

for (drive = 0; drive < 2; drive++)
{
char buffer [sizeof (SRB_IO_CONTROL) + SENDIDLENGTH];
SRB_IO_CONTROL *p = (SRB_IO_CONTROL *) buffer;
SENDCMDINPARAMS *pin =
(SENDCMDINPARAMS *) (buffer + sizeof (SRB_IO_CONTROL));
DWORD dummy;

memset (buffer, 0, sizeof (buffer));
p -> HeaderLength = sizeof (SRB_IO_CONTROL);
p -> Timeout = 10000;
p -> Length = SENDIDLENGTH;
p -> ControlCode = IOCTL_SCSI_MINIPORT_IDENTIFY;
strncpy ((char *) p -> Signature, "SCSIDISK", 8);

pin -> irDriveRegs.bCommandReg = IDE_ATA_IDENTIFY;
pin -> bDriveNumber = drive;
// //For IDE: 0=master;1=slave; actual ID for SCSI

if (DeviceIoControl (hScsiDriveIOCTL, IOCTL_SCSI_MINIPORT,
buffer,
sizeof (SRB_IO_CONTROL) +
sizeof (SENDCMDINPARAMS) - 1,
buffer,
sizeof (SRB_IO_CONTROL) + SENDIDLENGTH,
&dummy, NULL))
{
SENDCMDOUTPARAMS *pOut =
(SENDCMDOUTPARAMS *) (buffer + sizeof (SRB_IO_CONTROL));
IDSECTOR *pId = (IDSECTOR *) (pOut -> bBuffer);
if (pId -> sModelNumber [0])
{
USHORT *pIdSector = (USHORT *) pId;
AddIfNew(pIdSector);
done = TRUE;
}
}
}
CloseHandle (hScsiDriveIOCTL);
}
}

return done;
}

#ifndef NATIVE_CODE
String^ DiskInfo::GetModelNumber(UINT drive)
{
String^ ms = GetString (m_list[drive], 27, 46);
return ms->Trim();
}
String^ DiskInfo::GetSerialNumber(UINT drive)
{
String^ ms = GetString (m_list[drive], 10, 19);
return ms->Trim();
}

String^ DiskInfo::GetRevisionNumber(UINT drive)
{
String^ ms = GetString (m_list[drive], 23, 26);
return ms->Trim();
}

String^ DiskInfo::GetDriveType (UINT drive)
{
if (m_list[drive][0] & 0x0080)
return "Removable";
else if (m_list[drive][0] & 0x0040)
return "Fixed";
else return "Unknown";
}

String^ DiskInfo::GetString (WORD* pdiskdata, int firstIndex, int lastIndex)
{
int index = 0;
int position = 0;
//if(lastIndex < firstIndex)
// return (String^)NULL;
// each integer has two characters stored in it backwards
char* string = new char[2*(lastIndex- firstIndex +1)];
for (index = firstIndex; index <= lastIndex; index++)
{
// get high byte for 1st character
string [position] = (char) (pdiskdata [index] / 256);
position++;

// get low byte for 2nd character
string [position] = (char) (pdiskdata [index] % 256);
position++;
}

String^ ms = Marshal::PtrToStringAnsi((IntPtr)string,2*(lastIndex- firstIndex +1));
delete string;
return ms;
}
#else

char* DiskInfo::ModelNumber (UINT drive)
{
return ConvertToString(m_list[drive], 27, 46);
}

char* DiskInfo::SerialNumber (UINT drive)
{
return ConvertToString(m_list[drive], 10, 19);
}



char* DiskInfo::RevisionNumber (UINT drive)
{
return ConvertToString(m_list[drive], 23, 26);
}

char* DiskInfo::DriveType (UINT drive)
{
if (m_list[drive][0] & 0x0080)
return "Removable";
else if (m_list[drive][0] & 0x0040)
return "Fixed";
else return "Unknown";
}



char * DiskInfo::ConvertToString (WORD diskdata [256], int firstIndex, int lastIndex)
{
static char string [1024];
int index = 0;
int position = 0;

// each integer has two characters stored in it backwards
for (index = firstIndex; index <= lastIndex; index++)
{
// get high byte for 1st character
string [position] = (char) (diskdata [index] / 256);
position++;

// get low byte for 2nd character
string [position] = (char) (diskdata [index] % 256);
position++;
}

// end the string
string [position] = '\0';

// cut off the trailing blanks
for (index = position - 1; index > 0 && ' ' == string [index]; index--)
string [index] = '\0';

return string;
}
#endif

unsigned __int64 DiskInfo::DriveSize (UINT drive)
{
unsigned __int64 bytes = 0,sectors =0;
if (m_list[drive] [83] & 0x400)
sectors = m_list[drive][103] * 65536I64 * 65536I64 * 65536I64 +
m_list[drive][102] * 65536I64 * 65536I64 +
m_list[drive][101] * 65536I64 +
m_list[drive][100];
else
sectors = m_list[drive][61] * 65536 + m_list[drive][60];
// there are 512 bytes in a sector
bytes = sectors * 512;
return bytes;
}

DiskInfo::DiskInfo(void)
{
//m_DriveCount = 0;
}

DiskInfo::~DiskInfo(void)
{
for(int i = 0; i< m_list.size(); i++)
delete m_list[i];
m_list.clear();
}

BOOL GetDriveGeometry(DISK_GEOMETRY *pdg)
{
HANDLE hDevice; // handle to the drive to be examined
BOOL bResult; // results flag
DWORD junk; // discard results

hDevice = CreateFile(TEXT("\\\\.\\PhysicalDrive0"), // drive
0, // no access to the drive
FILE_SHARE_READ | // share mode
FILE_SHARE_WRITE,
NULL, // default security attributes
OPEN_EXISTING, // disposition
0, // file attributes
NULL); // do not copy file attributes

if (hDevice == INVALID_HANDLE_VALUE) // cannot open the drive
{
return (FALSE);
}
GETVERSIONINPARAMS GetVersionParams;
DWORD cbBytesReturned = 0;

bResult = DeviceIoControl(hDevice, // device to be queried
IOCTL_DISK_GET_DRIVE_GEOMETRY, // operation to perform
NULL, 0, // no input buffer
pdg, sizeof(*pdg), // output buffer
&junk, // # bytes returned
(LPOVERLAPPED) NULL); // synchronous I/O

CloseHandle(hDevice);
return (bResult);
}

int testmain()
{
DISK_GEOMETRY pdg; // disk drive geometry structure
BOOL bResult; // generic results flag
ULONGLONG DiskSize; // size of the drive, in bytes

bResult = GetDriveGeometry(&pdg);

if (bResult)
{
printf("Cylinders = %I64d\n", pdg.Cylinders);
printf("Tracks/cylinder = %ld\n", (ULONG) pdg.TracksPerCylinder);
printf("Sectors/track = %ld\n", (ULONG) pdg.SectorsPerTrack);
printf("Bytes/sector = %ld\n", (ULONG) pdg.BytesPerSector);

DiskSize = pdg.Cylinders.QuadPart * (ULONG)pdg.TracksPerCylinder *
(ULONG)pdg.SectorsPerTrack * (ULONG)pdg.BytesPerSector;
printf("Disk size = %I64d (Bytes) = %I64d (Gb)\n", DiskSize,
DiskSize / (1024 * 1024 * 1024));
}
else
{
printf ("GetDriveGeometry failed. Error %ld.\n", GetLastError ());
}

return ((int)bResult);
}

long DiskInfo::LoadDiskInfo()
{
int done = FALSE;
__int64 id = 0;
OSVERSIONINFO version;
memset (&version, 0, sizeof (version));
version.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
GetVersionEx (&version);
for(int i = 0; i< m_list.size(); i++)
delete m_list[i];
m_list.clear();
#ifd