태터데스크 관리자

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

태터데스크 메시지

저장하였습니다.

'ⓘ Programming'에 해당되는 글 45건

  1. 2014.04.02 [VBscript] 네트워크 정보 수집
  2. 2013.07.15 [AES암호화/복호화] python에서 암호화, php에서 복호화
  3. 2013.07.11 [Python] Httplib post/get 전송
  4. 2013.07.09 [VBscript] windows update
  5. 2013.07.09 [Python] 설치하지 않은 Windows 업데이트 정보 출력
  6. 2013.03.26 [VBScript] 바이너리 파일 다운로드 받기
  7. 2012.11.05 [Batch] 배치파일 만들기
  8. 2012.01.27 [Oracle] DBMS_CRYPTO
  9. 2011.07.26 [perl] URL, BASE64 Encode/Decode
  10. 2011.04.15 [Perl] MCPAN으로 모듈설치하기
  11. 2011.02.11 sikuli(시쿠리)를 아시나요?
  12. 2010.09.01 [mysql] 명령 모음
  13. 2009.10.09 CString Method(메쏘드)
  14. 2009.10.04 CString 변환하기 - To integer, TCHAR, const char* 변환 등등
  15. 2009.09.17 VC 디버그 옵션
  16. 2008.06.17 [본문스크랩] 최대공약수 프로그램
  17. 2008.05.15 Undelete a file in NTFS (1)
  18. 2008.05.13 [본문스크랩] API FAQ
  19. 2008.05.13 [본문스크랩] API FAQ
  20. 2008.05.13 [본문스크랩] [자바스크립트] Base64 인코딩/디코딩
  21. 2008.01.10 [perl] 프로세스 상태관리 프로그램
  22. 2007.12.27 [java] db 연결테스트
  23. 2007.12.26 On lisp 편하게 보기
  24. 2007.12.26 lisp가 대체 무엇인고~
  25. 2007.12.08 [perl] 고급스러운 펄 프로그래밍 기법
  26. 2007.12.07 [링크스크랩] tail log 브라우저로 보기
  27. 2007.12.07 [링크스크랩] tail log 브라우저로 보기
  28. 2007.12.07 perl을 이용한 하위 파일에 대한 일괄작업
  29. 2007.12.06 할당과 InterlockedExchange 중 누가 더 빠를까?
  30. 2007.12.02 [vim] VIM & bash script 예제 (C source to html view)

[VBscript] 네트워크 정보 수집

ⓘ Programming 2014.04.02 17:18
On Error Resume Next
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colItems = objWMIService.ExecQuery("Select * from Win32_NetworkAdapterConfiguration",,48)
For Each objItem in colItems
    Wscript.Echo "ArpAlwaysSourceRoute: " & objItem.ArpAlwaysSourceRoute
    Wscript.Echo "ArpUseEtherSNAP: " & objItem.ArpUseEtherSNAP
    Wscript.Echo "Caption: " & objItem.Caption
    Wscript.Echo "DatabasePath: " & objItem.DatabasePath
    Wscript.Echo "DeadGWDetectEnabled: " & objItem.DeadGWDetectEnabled
    Wscript.Echo "DefaultIPGateway: " & objItem.DefaultIPGateway
    Wscript.Echo "DefaultTOS: " & objItem.DefaultTOS
    Wscript.Echo "DefaultTTL: " & objItem.DefaultTTL
    Wscript.Echo "Description: " & objItem.Description
    Wscript.Echo "DHCPEnabled: " & objItem.DHCPEnabled
    Wscript.Echo "DHCPLeaseExpires: " & objItem.DHCPLeaseExpires
    Wscript.Echo "DHCPLeaseObtained: " & objItem.DHCPLeaseObtained
    Wscript.Echo "DHCPServer: " & objItem.DHCPServer
    Wscript.Echo "DNSDomain: " & objItem.DNSDomain
    Wscript.Echo "DNSDomainSuffixSearchOrder: " & objItem.DNSDomainSuffixSearchOrder
    Wscript.Echo "DNSEnabledForWINSResolution: " & objItem.DNSEnabledForWINSResolution
    Wscript.Echo "DNSHostName: " & objItem.DNSHostName
    Wscript.Echo "DNSServerSearchOrder: " & objItem.DNSServerSearchOrder
    Wscript.Echo "DomainDNSRegistrationEnabled: " & objItem.DomainDNSRegistrationEnabled
    Wscript.Echo "ForwardBufferMemory: " & objItem.ForwardBufferMemory
    Wscript.Echo "FullDNSRegistrationEnabled: " & objItem.FullDNSRegistrationEnabled
    Wscript.Echo "GatewayCostMetric: " & objItem.GatewayCostMetric
    Wscript.Echo "IGMPLevel: " & objItem.IGMPLevel
    Wscript.Echo "Index: " & objItem.Index
    Wscript.Echo "IPAddress: " & objItem.IPAddress
    Wscript.Echo "IPConnectionMetric: " & objItem.IPConnectionMetric
    Wscript.Echo "IPEnabled: " & objItem.IPEnabled
    Wscript.Echo "IPFilterSecurityEnabled: " & objItem.IPFilterSecurityEnabled
    Wscript.Echo "IPPortSecurityEnabled: " & objItem.IPPortSecurityEnabled
    Wscript.Echo "IPSecPermitIPProtocols: " & objItem.IPSecPermitIPProtocols
    Wscript.Echo "IPSecPermitTCPPorts: " & objItem.IPSecPermitTCPPorts
    Wscript.Echo "IPSecPermitUDPPorts: " & objItem.IPSecPermitUDPPorts
    Wscript.Echo "IPSubnet: " & objItem.IPSubnet
    Wscript.Echo "IPUseZeroBroadcast: " & objItem.IPUseZeroBroadcast
    Wscript.Echo "IPXAddress: " & objItem.IPXAddress
    Wscript.Echo "IPXEnabled: " & objItem.IPXEnabled
    Wscript.Echo "IPXFrameType: " & objItem.IPXFrameType
    Wscript.Echo "IPXMediaType: " & objItem.IPXMediaType
    Wscript.Echo "IPXNetworkNumber: " & objItem.IPXNetworkNumber
    Wscript.Echo "IPXVirtualNetNumber: " & objItem.IPXVirtualNetNumber
    Wscript.Echo "KeepAliveInterval: " & objItem.KeepAliveInterval
    Wscript.Echo "KeepAliveTime: " & objItem.KeepAliveTime
    Wscript.Echo "MACAddress: " & objItem.MACAddress
    Wscript.Echo "MTU: " & objItem.MTU
    Wscript.Echo "NumForwardPackets: " & objItem.NumForwardPackets
    Wscript.Echo "PMTUBHDetectEnabled: " & objItem.PMTUBHDetectEnabled
    Wscript.Echo "PMTUDiscoveryEnabled: " & objItem.PMTUDiscoveryEnabled
    Wscript.Echo "ServiceName: " & objItem.ServiceName
    Wscript.Echo "SettingID: " & objItem.SettingID
    Wscript.Echo "TcpipNetbiosOptions: " & objItem.TcpipNetbiosOptions
    Wscript.Echo "TcpMaxConnectRetransmissions: " & objItem.TcpMaxConnectRetransmissions
    Wscript.Echo "TcpMaxDataRetransmissions: " & objItem.TcpMaxDataRetransmissions
    Wscript.Echo "TcpNumConnections: " & objItem.TcpNumConnections
    Wscript.Echo "TcpUseRFC1122UrgentPointer: " & objItem.TcpUseRFC1122UrgentPointer
    Wscript.Echo "TcpWindowSize: " & objItem.TcpWindowSize
    Wscript.Echo "WINSEnableLMHostsLookup: " & objItem.WINSEnableLMHostsLookup
    Wscript.Echo "WINSHostLookupFile: " & objItem.WINSHostLookupFile
    Wscript.Echo "WINSPrimaryServer: " & objItem.WINSPrimaryServer
    Wscript.Echo "WINSScopeID: " & objItem.WINSScopeID
    Wscript.Echo "WINSSecondaryServer: " & objItem.WINSSecondaryServer
Next

 

Trackbacks 0 : Comments 0

Write a comment


[AES암호화/복호화] python에서 암호화, php에서 복호화

ⓘ Programming 2013.07.15 20:06

출처: http://stackoverflow.com/questions/13051293/encrypt-data-with-python-decrypt-in-php

 

 

[ python encrypt ]

from Crypto.Cipher import AES
import base64
import os
# the block size for the cipher object; must be 16, 24, or 32 for AES
BLOCK_SIZE = 32
BLOCK_SZ = 14

# the character used for padding--with a block cipher such as AES, the value
# you encrypt must be a multiple of BLOCK_SIZE in length.  This character is
# used to ensure that your value is always a multiple of BLOCK_SIZE
PADDING = '{'

# one-liner to sufficiently pad the text to be encrypted
pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * PADDING

# one-liners to encrypt/encode and decrypt/decode a string
# encrypt with AES, encode with base64
EncodeAES = lambda c, s: base64.b64encode(c.encrypt(pad(s)))
DecodeAES = lambda c, e: c.decrypt(base64.b64decode(e)).rstrip(PADDING)
secret = "332SECRETabc1234"
iv = "HELLOWORLD123456"
cipher=AES.new(key=secret,mode=AES.MODE_CBC,IV=iv)
my_text_to_encode = "password"
encoded = EncodeAES(cipher, my_text_to_encode)
print 'Encrypted string:', encoded

[ php decrypt (note the encoded text is just copy/pasted from python print above) ]

<?php
$enc = "x3OZjCAL944N/awRHSrmRBy9P4VLTptbkFdEl2Ao8gk=";
$secret = "332SECRETabc1234"; // same secret as python
$iv="HELLOWORLD123456";  // same iv as python
$padding = "{";  //same padding as python
function decrypt_data($data, $iv, $key) {
    $cypher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');

    if(is_null($iv)) {
        $ivlen = mcrypt_enc_get_iv_size($cypher);
        $iv = substr($data, 0, $ivlen);
        $data = substr($data, $ivlen);
    }

    // initialize encryption handle
    if (mcrypt_generic_init($cypher, $key, $iv) != -1) {
            // decrypt
            $decrypted = mdecrypt_generic($cypher, $data);

            // clean up
            mcrypt_generic_deinit($cypher);
            mcrypt_module_close($cypher);

            return $decrypted;
    }

    return false;
}



$res = decrypt_data(base64_decode($enc), $iv, $secret);
print rtrim($res,$padding);
?>
Trackbacks 0 : Comments 0

Write a comment


[Python] Httplib post/get 전송

ⓘ Programming 2013.07.11 18:24

 출처: http://www.gmazzola.com/notes/Python_Httplib.html

 

Python Httplib

HTTP GET:

Here is an example session that uses the "GET" method:

 

import httplib


conn = httplib.HTTPConnection("example.com")
conn.request("GET", "/index.php")
response = conn.getresponse()
data = response.read()
conn.close()

HTTP POST:

import httplib, urllib


params = {'first_param' : 1, 'second_param' : 2, 'third_param' : 3}
params = urllib.urlencode(params)
headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain"}

conn = httplib.HTTPConnection("google.com")
conn.request("POST", "/cgi-bin/query", params, headers)
response = conn.getresponse()
data = response.read()
conn.close()

 

HTTP Authentication:

import httplib, base64


username = "foo"
password = "pass"
auth = base64.encodestring("%s:%s" % (username, password))
headers = {"Authorization" : "Basic %s" % auth}

conn = httplib.HTTPConnection("example.com")
conn.request("GET", "/page.php", headers=headers)
response = conn.getresponse()
data = response.read()
conn.close()

 

 

 

 

Trackbacks 1 : Comments 0

Write a comment


[VBscript] windows update

ⓘ Programming 2013.07.09 15:54

WindowsUpdates_1.1.vbs

 

 

' Run Windows Updates
'vbscript

'# Windows Update agent MUST already be installed.
'# http://support.microsoft.com/kb/949104

'------------------------------------------------------------------------------
' *** Filename:  WindowsUpdates_1.1.vbs
' *** Version 1.0 (Microsoft)
' *** Version 1.1 Ammendments by D.Collins for Altiris distribution
'------------------------------------------------------------------------------

 

' ~~~
' ~~~ Force variables to be declared
' ~~~
Option Explicit

Dim I, I2, oSession, oSearcher, oSearchResult, oUpdate, oUpdatesToDownload, oUpdatesToInstall, oDownloader, oInstaller, oInstallationResult
Dim oFileSystem, oLog
dim oWinFolder
Dim blNoUpdates, qVal, oRunLog

blNoUpdates = False

' ~~~ '------------------------------------------------------------------------------
' ~~~ Create objects
' ~~~ '------------------------------------------------------------------------------
Set oSession       = CreateObject("Microsoft.Update.Session")
Set oSearcher      = oSession.CreateupdateSearcher()

Set oFileSystem = CreateObject("Scripting.FileSystemObject")
Set oWinFolder = oFileSystem.GetSpecialFolder (0)
Set oLog = oWinFolder.CreateTextFile("SCTWindowsUpdates.log", True)
Set oRunLog = oFileSystem.OpenTextFile("C:\Logs\WindowsUpdates-All.log", 8, True)

Public Function DoWindowsUpdates

On Error Resume Next

 ' ~~~ '------------------------------------------------------------------------------
 ' ~~~ Search for updates
 ' ~~~ '------------------------------------------------------------------------------
 oLog.WriteLine FormatDateTime (Now) & " Searching for updates..." & vbCRLF
 oLog.WriteLine FormatDateTime (Now) & " List of applicable items on the machine:"
 
 I2=0
 For I = 0 To oSearchResult.Updates.Count-1
     Set oUpdate = oSearchResult.Updates.Item(I)
  I2=I2+1
     oLog.WriteLine I + 1 & "> " & oUpdate.Title
     oRunLog.WriteLine Now() & " - " & I + 1 & " > " & oUpdate.Title
 Next
 
 If I2 = 0 Then
  oLog.WriteLine FormatDateTime (Now) & " There are no applicable updates."
                blNoUpdates = True

  Exit Function
 Else
  oRunLog.WriteLine Now() & " - Applicable updates: " & I2
 End If
 
 ' ~~~ '------------------------------------------------------------------------------
 ' ~~~ Create collection of upates to download
 ' ~~~ '------------------------------------------------------------------------------
 oLog.WriteLine vbCRLF & FormatDateTime (Now) & " Creating collection of updates to download:"
 Set oUpdatesToDownload = CreateObject("Microsoft.Update.UpdateColl")
 
 For I = 0 to oSearchResult.Updates.Count-1
     Set oUpdate = oSearchResult.Updates.Item(I)
     oLog.WriteLine I + 1 & "> adding: " & oUpdate.Title
  oUpdatesToDownload.Add(oUpdate)
 Next
 
 ' ~~~ '------------------------------------------------------------------------------
 ' ~~~ Download updates
 ' ~~~ '------------------------------------------------------------------------------
 oLog.WriteLine vbCRLF & FormatDateTime (Now) & " Downloading updates..."
 
 Set oDownloader = oSession.CreateUpdateDownloader()
 oDownloader.Updates = oUpdatesToDownload
 oDownloader.Download()
 
 ' ~~~ '------------------------------------------------------------------------------
 ' ~~~ Create a collection of downloaded updates to install
 ' ~~~ '------------------------------------------------------------------------------
 oLog.WriteLine  vbCRLF & FormatDateTime (Now) & " Creating collection of downloaded updates to install:"
 Set oUpdatesToInstall = CreateObject("Microsoft.Update.UpdateColl")
 
 For I = 0 To oSearchResult.Updates.Count-1
     Set oUpdate = oSearchResult.Updates.Item(I)
     oLog.WriteLine I + 1 & "> adding:  " & oUpdate.Title
     oUpdatesToInstall.Add(oUpdate) 
 Next
 
 ' ~~~ '------------------------------------------------------------------------------
 ' ~~~ Install updates
 ' ~~~ '------------------------------------------------------------------------------
 oLog.WriteLine FormatDateTime (Now) & " Installing updates..."
 Set oInstaller = oSession.CreateUpdateInstaller()
 oInstaller.Updates = oUpdatesToInstall
 oInstaller.ForceQuiet = true
 Set oInstallationResult = oInstaller.Install()
 
 ' ~~~ '------------------------------------------------------------------------------
 ' ~~~ Output results of install
 ' ~~~ '------------------------------------------------------------------------------
 oLog.WriteLine FormatDateTime (Now) & " Installation Result: " & oInstallationResult.ResultCode
 oLog.WriteLine FormatDateTime (Now) & " Reboot Required: " & oInstallationResult.RebootRequired & vbCRLF
 oLog.WriteLine FormatDateTime (Now) & " Listing of updates installed and individual installation results:"
 
 For I = 0 to oUpdatesToInstall.Count - 1
  oLog.WriteLine I + 1 & "> " & oUpdatesToInstall.Item(i).Title & ": " & oInstallationResult.GetUpdateResult(i).ResultCode
 Next
 
End Function

 

On Error Resume Next

oRunLog.WriteLine Now() & " - Start: Windows Updates All script starting."

oLog.WriteLine FormatDateTime (Now) & " Downloading and Installing All Available Software Updates"
Set oSearchResult  = oSearcher.Search("IsAssigned=1 and IsHidden=0 and IsInstalled=0 and Type='Software'")
Call DoWindowsUpdates
oLog.WriteLine vbCRLF & vbCRLF


oLog.WriteLine FormatDateTime (Now) & " Updates Complete"

oLog.Close


If blNoUpdates = True Then
    oRunLog.WriteLine Now() & " - No Updates Found."
    qVal = 99
Else
    oRunLog.WriteLine Now() & " - Updates found and installed.  See %WinDir%\WindowsUpdate.log for details."
    qVal = 98
End If

oRunLog.WriteLine Now() & " - End: Windows Updates All script Complete."
If qVal = 0 Then WScript.Quit(Err.Number)
WScript.Quit(qVal)

 

Trackbacks 0 : Comments 0

Write a comment


[Python] 설치하지 않은 Windows 업데이트 정보 출력

ⓘ Programming 2013.07.09 15:53

---- Python에서 미설치된 업데이트 내역 출력 ---

 

import win32com
import win32com.client

 

print "* Hotfix Check"

 

update = win32com.client.Dispatch('Microsoft.Update.Session')
updateSearcher = update.CreateUpdateSearcher()

searchResult = updateSearcher.Search("IsAssigned=1 and IsInstalled=0 and Type='Software'")

 

print "- Update Count: ", searchResult.Updates.Count

 

for update in searchResult.Updates:

cat = update.Categories

print '1. Title: ' + update.Title.encode("utf-8")
print '2. Descriptiotn: ' + update.Description.encode("utf-8")
print '3. Category: ' + cat.Item(0).Name
continue

 

 

---- update의 멤버변수---

 

update.Title

update.Description

update.IsDownloaded

update.IsHidden

update.Identity.UpdateID

cat = update.Categories   ->  cat.Item(0).Name

Trackbacks 0 : Comments 0

Write a comment


[VBScript] 바이너리 파일 다운로드 받기

ⓘ Programming 2013.03.26 20:56
http://www.codeproject.com/Tips/506439/Downloading-files-with-VBScript

 

 

 strLink = "http://download.windowsupdate.com/microsoftupdate/v6/wsusscan/wsusscn2.cab"
   ' Get file name from URL.
   ' http://download.windowsupdate.com/microsoftupdate/v6/wsusscan/wsusscn2.cab -> wsusscn2.cab
   strSaveName = Mid(strLink, InStrRev(strLink,"/") + 1, Len(strLink))
   strSaveTo = "C:\" & strSaveName
  
   WScript.Echo "HTTPDownload"
   WScript.Echo "-------------"
   WScript.Echo "Download: " & strLink
   WScript.Echo "Save to:  " & strSaveTo
 
     ' Create an HTTP object
     Set objHTTP = CreateObject( "WinHttp.WinHttpRequest.5.1" )
 
     ' Download the specified URL
     objHTTP.Open "GET", strLink, False
     ' Use HTTPREQUEST_SETCREDENTIALS_FOR_PROXY if user and password is for proxy, not for download the file.
     ' objHTTP.SetCredentials "User", "Password", HTTPREQUEST_SETCREDENTIALS_FOR_SERVER
     objHTTP.Send
    
          Set objFSO = CreateObject("Scripting.FileSystemObject")
   If objFSO.FileExists(strSaveTo) Then
    objFSO.DeleteFile(strSaveTo)
   End If
 
      If objHTTP.Status = 200 Then
     Dim objStream
     Set objStream = CreateObject("ADODB.Stream")
     With objStream
      .Type = 1 'adTypeBinary
      .Open
      .Write objHTTP.ResponseBody
      .SaveToFile strSaveTo
      .Close
     End With
     set objStream = Nothing
   End If
  
   If objFSO.FileExists(strSaveTo) Then
    WScript.Echo "Download `" & strSaveName & "` completed successfuly."
   End If  

Trackbacks 0 : Comments 0

Write a comment


[Batch] 배치파일 만들기

ⓘ Programming 2012.11.05 15:15
http://snoopybox.co.kr/1404

 

http://blog.naver.com/nsjung74?Redirect=Log&logNo=110033759180

 

http://bcheul.tistory.com/156

 

 

Trackbacks 0 : Comments 0

Write a comment


[Oracle] DBMS_CRYPTO

ⓘ Programming 2012.01.27 15:21

오라클 데이터베이스를 덤프받아 분석시스템에 복구하면 functions에 존재하는 암호화/복호화 함수가 존재하는 경우가 있는데, 죽어있는 경우(비활성화)가 있다.

이런 경우, 해당 함수를 마우스 우클릭하여 나오는 메뉴에서 compile 해주면 되는데 그 전에 dbms_crypto 관련 권한을 주어야 한다.


1. > sqlplus '/as sysdba'

2. sql> grant grant execute on dbms_crypto to 유저명;
    sql> grant execute on dbms_crypto to 유저명;

3. toad 등을 통한 함수 compile
Trackbacks 0 : Comments 0

Write a comment


[perl] URL, BASE64 Encode/Decode

ⓘ Programming 2011.07.26 10:40

쪽팔리지만...encoding시 문자열 끝에 %0A가 따라붙어서 매우 원시적인 방법으로 제거함..
근본적인 해결책 아시는분 댓글 달아 주시면 감사^^;

 #!/usr/bin/perl

use strict;
use MIME::Base64;
use URI::Escape;
 

 my $str='c3ViYW4%3D';

 # decoding part(방법 1)
 $str=~ s/\%([A-Fa-f0-9]{2})/pack('C', hex($1))/seg;  # url decode
 $str=decode_base64($str);  # base64 decode
 print $str."\n";

 # decoding part(방법 2)
 $str='c3ViYW4%3D';
 $str=uri_unescape($str); # url decode
 $str=decode_base64($str);  # base64 decode
 print $str."\n";

 

 # encoding part(방법 1)
 $str=encode_base64($str);
 $str =~ s/([^A-Za-z0-9])/sprintf("%%%02X", ord($1))/seg; # url encode
 print substr($str,0,length($str)-3)."\n"; # %0A 제거

 # encoding part(방법 2)
 $str='suban';
 $str=encode_base64($str);
 $str=uri_escape($str); # url encode
 print substr($str,0,length($str)-3)."\n"; # %0A 제거
 
exit(0);
 

sub URLDecode {
 my $theURL = $_[0];
 $theURL=~ s/\%([A-Fa-f0-9]{2})/pack('C', hex($1))/seg;
 return $theURL;
}

sub URLEncode {
 my $theURL = $_[0];
 $theURL=~ s/([^A-Za-z0-9])/sprintf("%%%02X", ord($1))/seg;
 return $theURL;
}

'ⓘ Programming' 카테고리의 다른 글

[Batch] 배치파일 만들기  (0) 2012.11.05
[Oracle] DBMS_CRYPTO  (0) 2012.01.27
[perl] URL, BASE64 Encode/Decode  (0) 2011.07.26
[Perl] MCPAN으로 모듈설치하기  (0) 2011.04.15
sikuli(시쿠리)를 아시나요?  (0) 2011.02.11
[mysql] 명령 모음  (0) 2010.09.01
Trackbacks 0 : Comments 0

Write a comment


[Perl] MCPAN으로 모듈설치하기

ⓘ Programming 2011.04.15 13:00

perl에서 yum이나 apt와 같은 시스템을 지원하네요.

완전 뒷북인가...ㅋㅋ 여튼 이제서야 알았다는..

windows 환경에서 perl과 mysql 연동을 위해 방법을 검색하던 중 발견...@.@


 1. perl -MCPAN -e shell

 2. cpan> 프롬프트로 변경

 3. cpan> install DBI

 4. cpan> install DBD::mysql


헉! ppm도 있네요...perl package manager...

'ⓘ Programming' 카테고리의 다른 글

[Oracle] DBMS_CRYPTO  (0) 2012.01.27
[perl] URL, BASE64 Encode/Decode  (0) 2011.07.26
[Perl] MCPAN으로 모듈설치하기  (0) 2011.04.15
sikuli(시쿠리)를 아시나요?  (0) 2011.02.11
[mysql] 명령 모음  (0) 2010.09.01
CString Method(메쏘드)  (0) 2009.10.09
Trackbacks 0 : Comments 0

Write a comment


sikuli(시쿠리)를 아시나요?

ⓘ Programming 2011.02.11 22:28

시쿠리를 아시나요?

전 처음 이 프로그램을 접한 순간...(오바좀 섞어서)상상만 해오던 꿈이 실현된 듯한 느낌?이 들었습니다.

이미지를 이용해 매크로를 만드는 것 같은...활용범위가 높고 사용하기 간편한 것 같습니다.

http://sikuli.org/

Trackbacks 0 : Comments 0

Write a comment


[mysql] 명령 모음

ⓘ Programming 2010.09.01 18:26
아오~ 맨날 검색하기 구찮아~
1. 권한 주기

GRANT ALL PRIVILEGES ON *.* TO '계정'@'localhost' IDENTIFIED BY 'password' WITH GRANT OPTION;

GRANT ALL PRIVILEGES ON *.* TO 'javajigi'@'%' IDENTIFIED BY 'password' WITH GRANT OPTION;
('계정명'@'%'으로 계정을 추가할 경우 Remote에서도 접근하는 것이 가능)

flush privileges;



2. 캐릭터셋 보기 및 설정

mysqld --default-character-set=euckr --default-collation=euckr_korean_ci
(데몬시작시)

SHOW VARIABLES LIKE 'character_set%';
(데이터베이스 캐릭터셋 확인)

CREATE DATABASE db_name DEFAULT CHARACTER SET euckr COLLATE euckr_korean_ci;
(데이터베이스 생성시)

alter database [databasename] charset=utf8
(데이터베이스 설정)

alter table [tablename] charset=utf8
(테이블 설정)

alter table [tablename] change [column name] varchar(10) character set utf8
(컬럼 설정)


- 설정파일 수정(리눅스:my.cnf, 윈도우:my.ini)

[client]
port = 3306
socket = /var/run/mysqld/mysqld.sock
default-character-set = euckr

[mysqld]
language = /usr/share/mysql/korean

character-set-client-handshake=FALSE
init_connect="SET collation_connection = euckr_korean_ci"
init_connect="SET NAMES euckr"

default-character-set = euckr
character-set-server = euckr
collation-server = euckr_korean_ci

[mysqldump]
default-character-set = euckr

[mysql]
default-character-set = euckr



3. 백업 및 복구

- 백업
mysqldump -u [user_name] -p [password] [database_name] > [backupfile.sql]
( 특정 데이터베이스만)

mysqldump --default-character-set=euckr -u [user_name] -p [password] [database_name] > [backupfile.sql]
( 특정 데이터베이스만)

mysqldump -u[user_name] -p[password] [database_name] [table_name] > file_name
( 특정 테이블만)


LOAD DATA INFILE '파일경로' INTO TABLE 테이블명
FIELDS TERMINATED BY ',' ENCLOSED BY '"'
ESCAPED BY '\\' LINES TERMINATED BY '\r\n';
( 특정 테이블만-쿼리문)

mysqldump
-u[user_name] -p[password] --all-databases > filename
(모든 데이터베이스 덤프)


- 복구
mysql -uroot -p**** < filename
(통째로 복구)

mysql -uroot -p**** [database_name] < dumpfile_name
(특정 데이터베이스만)

임포트할 데이터베이스 생성 후
mysql> use [created database_name];
mysql> source [파일경로 및 파일이름];



[참고URL]
http://www.master4u.net/bbs/view.php?id=database&no=157
http://www.blueb.net/blog/1271?category=23

Trackbacks 0 : Comments 0

Write a comment


CString Method(메쏘드)

ⓘ Programming 2009.10.09 10:16

메쏘드 종류와 기능 설명

http://www.dreamy.pe.kr/zbxe/15693
Trackbacks 0 : Comments 0

Write a comment


CString 변환하기 - To integer, TCHAR, const char* 변환 등등

ⓘ Programming 2009.10.04 21:26

발견하면서 속으로 올레~!! 를 외친 자료...ㅜㅜ

http://www.flounder.com/cstring.htm#Converting%20a%20CString%20to%20an%20integer

CString을 가지고 형변환하는 방법이 여기에 다 나와있다.

(사실 다 나온 건 아니다...ㅡㅡㅋ)

TIP) CString -> const char* 변환

CString으로 받은 문자열 데이터를 fopen에 사용하려니 const char*로 변환하지 못한다고 vs2005이상 컴파일러가 왈왈거린다.

http://blog.naver.com/programsite?Redirect=Log&logNo=150066965330 에서 소리님이 설명해주셨는데,

(LPSTR)(LPCSTR) 변환,  

(LPCSTR)(LPCTSTR) 변환,

(char*)(const char*)변환,

wcstombs_s()를 사용한 변환,  

(CString).GetBuffer(0)를 통한 변환 등등...


다 안되셨다고 한다. 그렇다. 나도 해봤는데 안되었다. ㅠㅠ(저런거 다 해볼때쯤 졸 짱나죵~)

아래와 같이 하면 된다고 하여 시도한 결과 성공!! 정말 좋은 팁 알려주셔서 이분께 감사하다.


CString   filename;

char*     strTemp; 

sprintf(strTemp, "%S", filename);

(물론 strTemp를 메모리 동적할당(malloc)해주어야 한다.)

뽀인트는 sprintf안의 2번째 인자 %S!!

대문자 S가 키뽀인트다.

'ⓘ Programming' 카테고리의 다른 글

[mysql] 명령 모음  (0) 2010.09.01
CString Method(메쏘드)  (0) 2009.10.09
CString 변환하기 - To integer, TCHAR, const char* 변환 등등  (0) 2009.10.04
VC 디버그 옵션  (0) 2009.09.17
[본문스크랩] 최대공약수 프로그램  (0) 2008.06.17
Undelete a file in NTFS  (1) 2008.05.15
Trackbacks 0 : Comments 0

Write a comment


VC 디버그 옵션

ⓘ Programming 2009.09.17 08:37

 

출처 : http://tong.nate.com/tigglet/42353507

Compiler options for finding Bugs #1

Compiler Options

의미

/W4

 Warning Level을 최대로 하여 컴파일

 ( 모든 빌드 타입에 가능 )

/D "_DEBUG"

 Assetion, Trace 같은 디버깅용 코드가 컴파일시 포함되록 만든다.

 ( 디버그 빌드에서만 )

/GZ

 생성시에 초기화 되지 않는 변수를 특정 값으로 채워 흔히 디버그에서는 나타나지 않고 릴리즈 빌드에서 나타나는 에러를 사전에 검사할 수 있게 하여 디버그에 도움이 되게 함. ( 디버그 빌드에서만 )

/Od

 최적화하지 않는다. 코드를 디버그에 적합하게 만든다.

 ( 디버그 빌드에서만 )

/GF

 실행 파일에 들어갈 스트링이 중복될 경우 이를 제거, 공동으로 사용되는 이 스트링이 할당된 메모리를 읽기 전용으로 설정하여 우발적인 메모리 쓰임으로 부터 보호함. ( 정적 문자열.. )

 

 char *s = "This is a character buffer";

 char *t = "This is a character buffer";

 

위와 같은 경우 같은 스트링이므로 스트링을 서로 공유 함.

( 릴리즈 모드에서 명시적으로 사용시 )

/Gf

 실행파일에 들어갈 스트링을 공유하는 것은 위와 같으나 우발적인 메모리 쓰임으로 부터 보호 하지 않음.

/ZI

 디버깅 심벌용 프로그램 데이터베이스를 만듬.

 디버그로 실행시에 코드를 편집후 연속해서 디버깅이 가능하게 정보를 관리.

 ( 디버그 빌드에서만 )

/Zi

 디버깅 심벌용 프로그램 데이터베이스를 만듬.

 ( 릴리즈 빌드에서만 )

 

 

 

Compiler options for a debug build #1

Linker Options

의미

/MDd, /MLd, /MTd

 디버그 런타임 라이브러리 사용.

/Od

 최적화하지 않는다.

/D "_DEBUG"

 디버그용 코드가 컴파일 되게 한다.

/ZI

 편집, 연속 디버깅이 가능하게 디버그용 데이터배이스를 만듬.

/GZ

 디버그 빌드에서의 흔한 실수로 릴리즈에서 나타나는 에러를 디버그모드에서 검출.

/Gm

 빌드 시간을 재빌드시에 감축시키기.

 

 

 Compiler options for a release build #1

Linker Options

의미

/MD, /ML, /MT

 릴리즈 런타임 라이브러리 사용.

/O1 or /O2

 속도 최적화나 사이즈 작게 최적화 같은 것을 가능하게.

/D "NDEBUG"

 디버그용 코드가 컴파일되지 않게 함.

/GF

 중복된 문자열을 방지, 읽기 전용으로 데이터를 보호함.

 

디버그 런타임 라이브러리 사용시 특징 #1

  • 디버그 런타임 라이브러리는 메모리 할당을 추적하고 메모리 누수를 점검한다.
  • 힙에서 새로이 메모리 할당되어 초기화 되지 않은 데이터에 "0XCD"의 바이트 패턴으로 써놓는다. ( ex : 0xCDCDCDCD )
    지역 변수인 경우,  초기화 되지 않은 데이터에 "0XCC“의 바이트 패턴으로 써놓는다. ( ex : 0xCCCCCCCC, /GZ" 컴파일러 옵션 사용시, 미사용시에는 디버그 모드에서 0 로 초기화 함 - 이것은 잠제적인 버그 유발 가능성이 많다. )
  • 힙에서 메모리 할당이 해제될 경우에 “0XDD"의 바이트 패턴으로 표시를 하여 해제된 메모리라고 알 수 있도록 표시한다. ( 0xDDDDDDDD 혹은 0xFEEEFEEE )
  • 할당된 메모리 버퍼의 양쪽 끝 부분에 4byte 로 “0XFD"의 바이트 패턴으로 표시를 해둬서 memory overwritememory underwrite를 체크할 수 있게 한다. ( "0xFDFDFDFD" 즉 디버그 모드에서는 메모리 할당시에 양쪽에 각각 4 byte 의 공간이 마킹하기 위해서 추가적으로 할당이 된다. )
  • 메모리 할당시 소스코드 상에서의 위치를 알아 내는데 도움이 되도록 소스코드의 파일 이름과 해당줄을 추적을 위해서 넣어 놓는다.

 

 

릴리즈 모드에서 디버깅 하기 #1'

 

 설정을 변경하면 디버깅은 잘되나 배포판을 만들 경우에는 변경된 옵션을 환원하고 빌드하자.

자주 써야 할 경우 빌드 타입을 하나 더 만들어서 사용하는 것도 한가지 방법이다.

 

 

vs 6.0 기준

  1. Project/Settings/Project Setting"을 선택.
  2. C/C++“ 탭에서 ”General" 카테고리를 선택해서 "Optimizations"을 “Disable(Debug)"로 선택하고 “Debug info" 항목을 ”Program Database“로 수정.
  3. "Link" 탭에서 “Debug" 카테고리를 선택하면 ”Debug info" 항목이 있는데 여기서 "Microsoft format"을 선택.
  4. Link" 탭에있는 ”Project Options" 박스에 들어 있는 내용의 맨 끝에 "/OPT:REF"를 추가 한다.
  5. 반드시 “Rebuild All"로 제 컴파일을 한다.

 

vs .net 기준

  1. 솔루션 탐색기에서 프로젝트를 선택한 다음 메뉴의 “프로젝트/ XXX 속성"을 선택.
  2. C/C++의 일반 항목중에서, 디버깅 정보 형식을 “사용안함"에서 “편집하며 계속하기를 위한 프로그램 데이터베이스(/ZI)"로 변경.
  3. C/C++의 최적화 항목중에서, 최적화를 “속도 최대화(/O2)" 혹은 "크기 최소화(/O1)”등에서 “사용안함(/Od)"로 변경.
  4. C/C++의 최적화 항목중에서, 인라인 함수 확장을 “__inline만 확장(/Ob1)"  혹은 "적합한것 모두(/Ob2)"등에서 "기본값"으로 변경.링링커의 디버그 항목중에서, 디버그 정보 생성을 “아니요”에서 “예(/DEBUG)"로 변경
  5.  

 

Registers And Pseudo-registers #1

 Register값은 “Registers" 윈도우에서 확인이 가능하지만 단순하고 값만을 알수 있다. 이 값들을 ”Address(Watch)" 박스에서도 확인이 가능하며 여러 부가 기능과 같이 쓸수 있다.

 예를 들어 EAX의 값을 확인 해볼려고 하면 Watch 항목에 “@EAX"혹은 ”@eax"와 같이 대소문자를 구분하지 않고 넣으면 이 래지스터의 값을 확인 할 수 있다.

 또한 Pseudo-register"의 값또한 확인 할수 있는데. "@ERR"Pseudo-register 값은 매우 유용하게 사용할 수 있는데 이 값이 GetLastError의 값을 나타내기 때문이다. 만약 “@ERR,hr"이라고 입력한다면 Win32의 에러코드에 해당하는 택스트를 보여 줄것이다.

 

 

 Pseudo-register

의미

@ERR

GetLastError API로 알 수 있는 가장 최근에 반환된 에러 코드를 보여줌

@CLK

누적시간(MicroSecond)을 보여줌.

@TIB

TIB의 주소를 보여줌.

 

 

 

Pseudo-registers that the Watch window supports #1

 

Register

사용(용도)

@EAX

일반 용도, 함수의 return 값으로 사용

@EBX

일반 용도

@ECX

일반 용도, 오브젝트의 this 포인터로 사용.

@EDX

일반 용도, 64비트의 return값의 경우 상위 값의 반환에 사용.

@ESI

메모리 이동과 비교 연산시의 원본 메모리

@EDI

메모리 이동과 비교 연산시에 대상 메모리

@EIP

명령 포인터 ( 코드의 현제 위치 )

@ESP

스텍 포인터 ( 스텍의 현제 위치 )

@EBP

스텍 배이스 포인터 ( 현제 스텍 프레임의 바닥 )

@EFL

비교나 수학 연산을 위한 플래그 비트

@CS

Code segment

@SS

Stack segment

@DS

Data segment

@ES

Extra segment

@FS

Another extra segment, used to point to the TIB

@GS

Yet another extra segment

 

Watch Window Formatting Symbols #1

 Watch 윈도우는 변수의 값을 볼수 있게 해주는데, 값을 십진수나 16진수로서 확인할 수 있다. 16진수는 팝업 메뉴에서 “Hexadecimal Display"를 선택하면 볼수 있다. 이 이외에도 여러 가지 옵션을 주어서 사용할 수 있는데 이들은 Watch Window에 등록되는 변수명 뒤에 ","를 삽입하고 그뒤에 옵션을 주어 사용할 수 있다.

 

Symbol

Format

Example

Output

d, i

부호있는 10진 정수

-42,d

-42

u

부호없는 10진 정수

42,u

42

o

부호없는 8진 정수

42,o

052

x

16진 정수

42,x

0x0000002a

X

16진 정수

42,X

0x0000002A

h

Short prefix for d,i,u,o,x

42,hx

0x002a

f

실수

1.5,f

1.500000

e

부호 있는 과학용 표기

1.5,e

1.500000e+000

g

Compact float

1.5,g

1.5

c

문자

42,c

'*'

s

ANSI 문자열

"bugs",s

"bugs"

su

UNICODE 문자열

"bugs",su

L"bugs"

st

기본 문자열형 ( s, su중에서 )

"bugs",st

"bugs"

hr

HRESULT, Win32 error code

0x06,hr

The handle is invaid

wm

Wndows message number

0x01,wm

WM_CREATE

[digits]

배열

s,5

배열 5개의 항목 표시

 

 

 

 

디버깅에 도움이 되는 메모리 마킹 패턴 #1'

 

 

Byte Pattern

의미

0xCCCCCCCC

초기화 되지 않은 stack 메모리

0xCDCDCDCD

초기화 되지 않은 heap 메모리

0xDDDDDDDD

힙에서 해지된 메모리 영역

0xFDFDFDFD

힙에 할당된 메모리 블록 양쪽 4byte의 공간 마킹

0xABABABAB

LocalAlloc()로 할당된 메모리

0xBAADF00D

LocalAlloc(LMEM_FIXED, )로 할당된 메모리

0xFEEEFEEE

HeapFree()로 해지된 상태

 

가끔 오류가 발생했을 경우에  만날수 있는 magic number. ( 디버깅 모드에서만 byte pattern 으로 마킹됨. )

 

non-MFC 프로젝트에서 메모리 릭(Memory Leck) 검출

 mfc 프로젝트에서는 DEBUG_NEW 가 기본적으로 제공되므로 메모리 릭을 검출하기가 용의하다. 하지만 일반 프로젝트에서는 추가적인 설정이 필요하다.

// CRT's memory leak detection
#if !defined(_AFXDLL)
   #include <windows.h>
   #include <crtdbg.h>
   #if defined(DEBUG) | defined(_DEBUG)
      #if !defined(DEBUG_NEW)
         #define DEBUG_NEW new(_CLIENT_BLOCK, __FILE__, __LINE__)
      #endif
   #endif
#endif

 위와 같은 코드를 기초 인클루드 파일에 추가하면 된다. ( 예를 들어 StdAfx.h 와 같은 곳에.. )

그리고 아랫 내용을 cpp 파일의 상단(인클루드 아랫 부분)에 추가하면 된다.

 #ifdef _DEBUG
#define new DEBUG_NEW
#endif

그리고

  1. WinMain( ... )
  2. {

    1. _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
    2. .
    3. .
    4. .
  3. };

위와 같이 App 최초 구동시 메모리 릭 검출 디버깅 옵션을 켜준다.

 

그러면 디버그 모드로 실행 했을 경우 App 종료시 output 창에 메모리 릭 발생시 메모리 릭 정보가  해당 소스 파일과 라인등 정보와 함께 출력되는 것을 볼수 있을 것이다.

 

실수 연산 오류 발생시 Exception 발생 시키기 #2

    int stat = _controlfp(0, 0);
   stat &= ~(EM_ZERODIVIDE);
   _controlfp(stat, MCW_EM);

와 같이  EM_ZERODIVIDE 옵션을 추가하였다면 0으로 나눌 경우 해당 코드 부분에서 exception이 발생하므로 발생 부분을 즉시 확인할 수 있는 효과가 있다. 기타 다른 옵션은 MSDN 에서 _controlfp를 찾아서 확인하자.

 

Special Floating-Point Values and Their Representations #3

Value

Hex

Signed 32-Bit Int

Name

-1.#QNAN

FFFFFFFF

~

FF800001

-1

~

-8388607

Negative NaNs

-1.#INF

FF800000

-8388608

-∞

0

 

 

 

0

 

 

 

 

 

 

+∞

+1.#QNAN

7F800001

~

7FFFFFFF

2139095041

~

2147483647

Positive NaNs

 

*, 1.#QNAN 의 경우 1.#INF ( 무한대의 값 ) 으로 연산시에 발생함.

 

 Pure virtual Function Call #4

순수 가상 함수를 파괴자 등에서 호출하여 생기는 오류 검출 방법.

 

  1.  _set_purecall_handler(_purecall_handler function);

 

위의 함수를 사용하여 순수 가상 함수 호출시 임의의 오류 처리 함수를 호출하도록 하여 해당 부분을 검출해낼수 있다.

아래와 같이 설정하였다면 순수 가상 함수가 호출되는 순간 assert 가 호출되므로 해당 부분의 call-stack 을 확인해보자.

 

  1. void my_purecall_handler(void)
  2. {

    1. assert(0 && "pure virtual function call !!!");
    2. printf("pure virtual function call !!!");
  3. }
  4.  
  5. void main(int argc, char* argv[])
  6. {

    1. _set_purecall_handler(my_purecall_handler);
    2.  
  7. }
Trackbacks 0 : Comments 0

Write a comment


[본문스크랩] 최대공약수 프로그램

ⓘ Programming 2008.06.17 13:59

#include

void gcm(int&,int&);//최대공약수 함수 정의
void main()
{
int i,j,result;//변수 정의
int n,m;
cout<<"☆다음 프로그램은 최대 공약수를 구하는 프로그램입니다..☆"<cout<<"두 정수를 입력하시오"<cin>>i>>j;//임의의 정수 i,j를 입력
n=i; m=j;
gcm(n,m); //gcm함수 호출
if(m==0)//gcm 함수 중 y가 0일때
{
result=n;
}
else//gcm 함수 x가 0일때
{
result=m;
}
cout<}

void gcm(int& x,int& y)//x는 i의 값을 y는 j의 값을 갖는다.
{
while(x!=0 && y!=0)//x나 y 둘중 하나가 0이 될때 까지 반복 실행
{

if(x>y)//x가 y보다 크면
x=x%y;//x를 y로 나눈 나머지 값이 x

else//만약 x의 값이 y의 값과 같거나 y가 크면 실행하고
y=y%x;//위의 if문 실행 결과 y가 x보다 커지면 다시 실행 합니다
}
}

Trackbacks 0 : Comments 0

Write a comment


Undelete a file in NTFS

ⓘ Programming 2008.05.15 14:56

출처 : http://www.codeproject.com/KB/files/NTFSUndelete.aspx

NTFS에서의 파일복구에 대해 설명하고 있습니다.

요즘 파일시스템 공부하고 있는데 공부하다 보니 파일복구에 관심을 가지게 되었습니다.

그래서 여기저기 쑤셔보고 다니는데 파일시스템을 공부하는 사람들이 적다고 하네요

그래서인지 검색하다보면 한국사이트에서는 잘못된 정보들이 대부분입니다.

낚이시지 않으시길 바라면서...

파일시스템 같이 공부하시는 분 있으면 정보 공유 했으면 좋겟네요

p.s. 파일 복구 소스 구하고 있는데...그닥 쉽지가 않은데다...프로그래밍 내공도 별로여서 참 힘드네요 ㅋㅋ;;

Trackbacks 0 : Comments 1
  1. dayone 2011.07.28 09:14 Modify/Delete Reply

    filesystem쪽으로 직장을 구하게 될 거 같은데 함께 공유하고 공부하고 싶습니다^^

Write a comment


[본문스크랩] API FAQ

ⓘ Programming 2008.05.13 19:41
[API 프로그래밍][MFC 프로그래밍][ATL 프로그래밍][VB 프로그래밍][HTML/ASP 프로그래밍]

API 프로그래밍에 대한 Q&A입니다.

1. 특정 디렉토리 뒤지기

지정한 디렉토리에 있는 모든 파일을 찾아내는 코드를 만들려면 어떻게 해야 합니까 ?

이 때 사용할 수 있는 API가 바로 FindFirstFile과 FindNextFile, FindClose라는 API들입니다. 사용 예제는 다음과 같습니다.

	WIN32_FIND_DATA  findFileData;	HANDLE hFileHandle;	// szDir에 뒤지고자 하는 디렉토리의 경로명을 준다. 예를 들면 "C:\TEMP\*.*"        // 찾아진 파일의 속성은 findFileData의 dwFileAttributes를 살펴본다.	hFileHandle = FindFirstFile(m_szDir, &findFileData);  	if (hFileHandle != INVALID_HANDLE_VALUE)   // 파일을 찾은 경우 	{		// 찾은 파일의 이름은 cFileName 필드로 들어온다.		...		// 다음 파일을 찾는다.		while(FindNextFile(hFileHandle, &findFileData)) 		{			...		}		FindClose(hFileHandle);	}     

2. API를 이용하는 유니코드와 ANSI 문자열간의 변환 방법

API를 이용해서 유니코드와 ANSI 문자열간의 변환은 어떻게 수행합니까 ?

Visual C++에서 유니코드 문자열은 BSTR이란 타입으로 표시됩니다. 또 유니코드와 ANSI 문자열간의 변환을 위해서 윈도우 시스템에는 MultiByteToWideChar와 WideCharToMultiByte라는 API가 존재합니다. MFC에서의 BSTR 타입 변환방법이나 ATL로 하는 BSTR 타입 변환도 참고하시기 바랍니다.

  • ANSI 문자열에서 유니코드로의 변환 방법
    	// sTime이란 ANSI 문자열을 bstr이란 이름의 유니코드(BSTR 타입) 변수로 변환	char sTime[] = "유니코드 변환 예제";	BSTR bstr;	// sTime을 유니코드로 변환하기에 앞서 먼저 그 길이를 알아야 한다.	int nLen = MultiByteToWideChar(CP_ACP, 0, sTime, lstrlen(sTime), NULL, NULL);	// 얻어낸 길이만큼 메모리를 할당한다.	bstr = SysAllocStringLen(NULL, nLen);	// 이제 변환을 수행한다.	MultiByteToWideChar(CP_ACP, 0, sTime, lstrlen(sTime), bstr, nLen);         // 필요없어지면 제거한다.         SysFreeString(bstr);
  • 유니코드에서 ANSI 문자열로의 변환 방법
    	// newVal이란 BSTR 타입에 있는 유니코드 문자열을 sTime이라는 ANSI 문자열로 변환	char *sTime;         int nLen = WideCharToMultiByte(CP_ACP, 0, newVal, -1, sTime, 0, NULL, NULL);         sTime = malloc(nLen+1);	WideCharToMultiByte(CP_ACP, 0, newVal, -1, sTime, 128, NULL, NULL);        // 필요없으면 메모리를 제거한다.        free(sTime);
  • 유니코드 문자열을 UTF-8으로 변환하기
         WideCharToMultiByte 함수를 호출할 때 첫 번째 인자로 CP_UTF8을 지정하면 된다. UTF-8은 유니코드의 인코딩 스킴 중의 하나로 쉽게 말하자면 문자열 스트림에서 0을 빼고 표현하는 방법이라고 볼 수 있다.

    3. 레지스트리 읽기/쓰기

    API를 이용해서 레지스트리에 한 항목을 생성하거나 기존 항목의 값을 읽어들이려면 어떻게 해야합니까 ?

    레지스트리 관련 API를 사용하려면 winreg.h라는 헤더 파일을 소스에 포함해야 합니다. 레지스트리에 키를 생성하는 방법과 레지스트리에 존재하는 키의 값을 읽는 방법을 차례로 살펴보겠습니다.

  • 레지스트리 키 생성 예제
    	// 예를 들어 HKEY_LOCAL_MACHINE밑의 SystemCurrentControlSetServicesGenPort라는 키를        // 생성하고 거기에 DWORD 타입의 값으로 Type을 만들고 문자열 타입의 값으로 Group        // 을 만들어 본다.	#include "winreg.h"	LONG error = 0;	HKEY hKey;	DWORD dwDisp, dwData;	char lpData[] = "Write this down";	// 먼저 만들려는 키가 이미 존재하는 것인지 살혀본다.	error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "System\CurrentControlSet\Services\GenPort",                         0, KEY_ALL_ACCESS, &hKey);	if (error != ERROR_SUCCESS) // 없다면 새로 생성한다.	{		// 키를 생성한다.		error = RegCreateKeyEx(HKEY_LOCAL_MACHINE,			"System\CurrentControlSet\Services\GenPort",	0, "REG_BINARY", 		        REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hKey, &dwDisp);                // 위의 키 밑에 Type이란 DWORD 타입의 값을 만들고 1로 초기화		dwData = 0x1;		error = RegSetValueEx( hKey, "Type", 0, REG_DWORD,&dwData,4);                 // 위의 키 밑에 Group이란 문자열 타입의 값을 만들고 lpData의 값으로 초기화		error = RegSetValueEx( hKey, "Group", 0, REG_SZ, lpData, strlen(lpData));                 // 키를 닫는다.		RegCloseKey(hKey);		}
  • 기존의 레지스트리 키에서 값 읽기
    	// HKEY_CURRENT_USERSoftwareNetscapeNetscape NavigatorMain 밑의 Install Directory        // 값의 문자열 값을 읽어들인다.	DWORD dwType, cbData;	HKEY hSubKey; 	long lRet;	char pszString[255];	// 키를 오픈한다.	if ((lRet = RegOpenKeyEx(HKEY_CURRENT_USER, 	                "Software\Netscape\Netscape Navigator\Main",			0, KEY_READ | KEY_QUERY_VALUE , &hSubKey)) == ERROR_SUCCESS)	{		cbData = 255;	// 문자열 값을 읽어올 데이터의 크기를 준다.		if ((lRet = RegQueryValueEx(hSubKey, "Install Directory",			NULL, &dwType, pszString, &cbData)) == ERROR_SUCCESS)		{			// 제대로 읽힌 경우		}		else		{			// 에러가 발생한 경우		}		RegCloseKey(hSubKey);	}
  • 레지스트리 키 삭제하기 - RegDeleteKey 함수를 사용한다.

    4. 윈도우 탐색기로부터의 Drag&Drop을 받으려면

    윈도우 탐색기로부터 제가 만든 윈도우로의 drag&drop이 가능하게 하려면 어떻게 해야 합니까 ?

    다음 순서를 따라서 프로그래밍하시면 됩니다.

    1. 프로그램의 초기화시에 DragAcceptFiles(hWnd, TRUE) 함수를 호출한다. 첫 번째 인자인 hWnd는 드롭의 타겟이 되는 윈도우의 핸들이다.
    2. 탐색기로부터 파일이 드롭되는 순간에 WM_DROPFILES 메시지가 날라온다. 이를 처리한다.
      	case WM_DROPFILES :	{		POINT pt;		// 어느 위치에 드롭되었는지 그 항목을 알아낸다.		if (DragQueryPoint((HDROP)wParam, &pt)) 		{			UINT i = 0;			// 모두 몇 개의 파일이 드롭되었는지 알아낸다.			// 만일 폴더가 드롭되었다면 폴더의 이름만 넘어온다.			UINT uCount = DragQueryFile((HDROP)wParam, 0xFFFFFFFF, NULL ,0);			for(i = 0;i < uCount;i++)			{				// 드롭된 파일의 이름을 알아온다.				DragQueryFile((HDROP)wParam, i, buffer ,255);				// 드롭된 파일 이름을 출력해본다.				MessageBox(hWnd, buffer, "File Name", MB_OK);			}		}		// drag and drop 작업을 끝낸다.		DragFinish((HDROP)wParam);		break;	}
    3. Drag&drop을 더 사용할 필요가 없어지면 DragAcceptFiles를 호출한다.
      	DragAcceptFiles(hWnd, FALSE);

    5. 시스템의 모든 드라이브 알아내기

    현재 시스템에 붙어있는 모든 드라이브(네트웍 드라이브 포함)에 대한 정보를 알아내고 싶습니다.

    1. GetLogicalDriveStrings로 시스템에 마운트되어있는 모든 드라이브 정보를 알아낸다. 두 번째 인자인 buffer로 드라이브 정보가 들어오는데 그 구조는 c:,d:과 같은 형식이며 리턴값으로 그 버퍼의 크기가 들어온다.
      	char buffer[256];	DWORD dwRet;	LPSTR token;	dwRet = GetLogicalDriveStrings(256, buffer);
    2. 루프를 돌면서 드라이브별 정보를 알아낸다. 이 때는 GetVolumeInformation 함수를 이용한다.
      	token = buffer; // token이 지금 처리해야할 드라이브를 가리킨다.	while (dwRet > 0)	{		DWORD FileSystemFlag;		char FileSystemName[64];						strcpy(DriveString, token);		// VolumeName으로 드라이브에 대한 설명 문자열이 넘어온다.		if (GetVolumeInformation(token, VolumeName, 255, NULL, NULL,                           &FileSystemFlag, FileSystemName, 63))		{	        // 원하는 작업을 수행한다.				}		dwRet -= (strlen(token)+1);		token = token + strlen(token)+1; // 다음 드라이브로 진행한다.	}

    6. 드라이브/디렉토리/파일의 이미지 리스트 인덱스 얻기

    특정 드라이브/디렉토리/파일이 시스템 이미지 리스트에서 어떤 인덱스를 갖는지 알고 싶습니다.

    각 파일이나 드라이브 및 디렉토리에 대한 정보는 Shell 라이브러리에서 제공해주는 SHGetFileInfo 함수를 이용하면 됩니다. 다음의 함수는 첫 번째 인자인 lpFileName으로 주어진 파일에 대한 설명을 두 번째 인자로 받아오고 세 번째 인자로는 시스템 이미지 리스트에서의 인덱스를 얻어옵니다.

    	void GetFileInfo(LPSTR lpFileName, LPSTR lpDesc, int *nIndex)	{	    DWORD dwAttr;	    SHFILEINFO sfi;	    int hIcon = SHGetFileInfo(lpFileName, dwAttr, &sfi, sizeof(SHFILEINFO), 				SHGFI_TYPENAME | SHGFI_SYSICONINDEX); 	    *nIndex = sfi.iIcon;	    strcpy(lpDesc, sfi.szTypeName);	}

    7. 리스트 컨트롤에 칼럼 헤더 넣기

    리포트뷰 형식의 리스트 컨트롤에 컬럼 헤더를 집어 넣으려면 어떻게 해야합니까 ?

    	// <문서명, 등록날짜, 상태> : 3개의 헤더를 만든다.	LV_COLUMN col;	col.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;	col.fmt = LVCFMT_LEFT;	col.cx = 100;	col.pszText = "문서명";	col.cchTextMax = strlen(col.pszText);	ListView_SetColumn(hListView, 0, &col); 	col.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;	col.fmt = LVCFMT_LEFT;	col.cx = 100;	col.pszText = "등록날짜";	col.cchTextMax = strlen(col.pszText);	ListView_InsertColumn(hListView, 0, &col); 	col.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;	col.fmt = LVCFMT_LEFT;	col.cx = 100;	col.pszText = "상태";	col.cchTextMax = strlen(col.pszText);	ListView_InsertColumn(hListView, 1, &col); 

    8. 리스트뷰에 항목 삽입하기

    리스트뷰에 한 항목을 추가하고 싶습니다.

    	// 이미지 리스트와 부가 정보를 사용하지 않는 리스트뷰 컨트롤이다.	int nIndex;	LV_ITEM item;	// - 첫번째 컬럼 -	item.mask = LVIF_TEXT; // 이미지 리스트를 사용하려면 LVIF_IMAGE를 추가하고                               // 부가정보를 지정해야할 일이 있다면 LVIF_PARAM을 추가한다.	item.pszText = lpDocName;	item.cchTextMax = strlen(lpDocName);	item.iItem = 1;	item.iSubItem = 0;	nIndex = ListView_InsertItem(hListView, &item);		// - 두번째 컬럼 -	item.mask = LVIF_TEXT;	item.iItem   = nIndex;	item.pszText = lpDate;	item.cchTextMax = strlen(lpDate);	item.iSubItem = 1;	ListView_SetItem(hListView, &item); 	// - 세번째 컬럼 -	item.mask = LVIF_TEXT;	item.iItem   = nIndex;	item.pszText = "";	item.cchTextMax = strlen(lpDocName);	item.iSubItem = 2;	ListView_SetItem(hListView, &item); 

    9. 리스트뷰 컨트롤에서의 정렬 구현

    리스트뷰 컨트롤에서 칼럼 헤더를 눌렀을 때 정렬이 되도록 하려면 어떻게 해야합니까 ?

    1. 일단 리스트뷰 컨트롤의 생성시 윈도우 스타일로 LVS_NOSORTHEADER를 주지 않는다.
    2. 리스트뷰로부터 칼럼 헤더가 눌렸을 때 오는 이벤트를 받아들인다.
      	NM_LISTVIEW *pnmtv = (NM_LISTVIEW FAR *)lParam;	switch(pnmtv->hdr.code)	{		case LVN_COLUMNCLICK :		{			// 어느 항목(pnmtv->iSubItem)이 눌렸는지부터 검사한다. 			// g_iSubItem은 어느 항목이 눌렸는지 기록해두는 인덱스이다.			g_iSubItem = pnmtv->iSubItem;			// 정렬함수를 호출한다. CompareFunc가 정렬함수이다.			ListView_SortItems(hListView, (PFNLVCOMPARE)CompareFunc, (LPARAM)this); 			break;		}
    3. 리스트뷰 항목을 정렬하는데 사용되는 CompareFunc라는 함수를 만든다. 이는 보통 C 함수로 만들거나 클래스를 사용할 경우에는 클래스 내의 static 함수로 만든다. CompareFunc의 코드는 다음과 같다.
      	int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)	{		LV_FINDINFO lvfi;		int iFirstItem, iSecondItem;		lvfi.flags = LVFI_PARAM;		lvfi.lParam = lParam1;		iFirstItem = ListView_FindItem(hListWnd, -1, &lvfi); 		lvfi.flags = LVFI_PARAM;		lvfi.lParam = lParam2;		iSecondItem = ListView_FindItem(hListWnd, -1, &lvfi); 		char lpFirst[100];		char lpSecond[100];		ListView_GetItemText(hListWnd, iFirstItem, g_iSubItem, lpFisrt, 100);		ListView_GetItemText(hListWnd, iSecondItem, g_iSubItem, lpSecond, 100);		// g_iSubItem 컬럼의 성격에 따라 비교한다. 문자열이라면 아래와 같이 한다.		int iRet = strcmpi(lpFirst, lpSecond);			return iRet;	}

    10. 버전 정보 알아내기 코드

    파일의 버전을 API를 통해 알아내려면 어떻게 해야합니까 ?

    Resource의 한 타입으로 VERSIONINFO라는 것이 존재합니다. 여기에 해당 파일의 버전 정보를 기록하도록 되어있습니다. 이 버전 정보를 읽어오는데 ver.dll이라는 DLL에 들어있는 API들을 사용합니다. 주의할 점은 버전 리소스는 언어별로 설정이 되기 때문에 영어로도 읽어보고 한국어 로도 읽어봐야 한다는 것입니다. 다음 예제를 참고하시기 바랍니다.

    	// szDrvName이란 파일에 들어있는 버전 정보를 읽어온다. 	#include 	DWORD      dwSize, handle;	LPSTR      lpstrVffInfo;	HANDLE     hMem;	LPSTR      lpVersion;	   // 이 변수로 파일의 버전 정보가 들어온다.	char       szDrvName[80];  // 버전 정보를 알아내고자 하는 파일 이름이 여기에 들어온다.	....	// 버전 정보 블록의 크기를 알아온다.	dwSize = GetFileVersionInfoSize(szDrvName , &handle);	if (dwSize) // 버전 정보 블록이 존재하면	{ 		// 버전 정보 블록을 포함할 메모리 블록을 할당 받아둔다.		hMem = GlobalAlloc(GMEM_MOVEABLE, dwSize);		lpstrVffInfo  = GlobalLock(hMem);		// 버전 정보 블록의 내용을 읽어온다.			GetFileVersionInfo(szDrvName, handle, dwSize, lpstrVffInfo);	        // 버전 정보 블록에서 버전 정보를 읽어온다.        	VerQueryValue((LPVOID)lpstrVffInfo,                         (LPSTR)"\StringFileInfo\041204B0\FileVersion",                        (void FAR* FAR*)&lpVersion, (UINT FAR *)&dwSize);		// lpVersion에 들어있는 버전 정보를 사용한다.		....		GlobalUnlock(hMem);		GlobalFree(hMem);    }
    위에서 041204B0가 바로 버전 리소스에 사용된 언어가 무엇인지를 나타냅니다. 이는 영어를 나타내며 한국어의 경우에는 040904B0를 사용하면 됩니다. 이 밖에도 version.lib를 링크의 라이브러리 항목에 추가해야 합니다.

    11. 시스템 사양 알아내기

    현재 시스템에 부착되어 있는 메인 메모리의 양과 CPU와 운영체제의 종류를 알고 싶습니다.

    먼저 시스템에 부착되어 있는 메인 메모리의 크기는 GlobalMemoryStatus라는 API를 이용하면 됩니다. 예제 코드는 다음과 같습니다.

    	//===========================================================	// lMemTotal      : 실제 메모리의 전체 크기 (KB 단위)	// lAvailMemTotal : 사용 가능한 실제 메모리의 크기 (KB 단위)	// lVirtualTotal  : 가상 메모리의 전체 크기  (KB 단위)	//===========================================================	void GetMemoryStatus(long *lMemTotal, long *lAvailMemTotal, long *lVirtualTotal)	{		double var;		MEMORYSTATUS memoryStatus;		memset (&memoryStatus, sizeof (MEMORYSTATUS), 0);		memoryStatus.dwLength = sizeof (MEMORYSTATUS);		GlobalMemoryStatus (&memoryStatus);		lMemTotal = memoryStatus.dwTotalPhys / 1024;		lAvailMemTotal = memoryStatus.dwAvailPhys / 1024;		lVirtualTotal = memoryStatus.dwTotalVirtual / 1024;	}
    다음으로 CPU의 종류를 알아내는 코드는 다음과 같습니다.
    	//===============================================================	// GetProcessorInfo : 프로세서에 대한 정보를 읽어온다.	// lpCPUSpeed      : CPU의 속도. 기록된 시스템에서만 읽어온다.	// lpProcessorType : 프로세서의 종류	// lpNumProcessors : 프로세서의 개수. NT의 경우에만 의미가 있다.	//===============================================================	void GetProcessorInfo(LPSTR lpCPUSpeed, LPSTR lpProcessorType, LPSTR lpNumProcessors)	{		SYSTEM_INFO sysInfo;		LONG result;		HKEY hKey;		DWORD data;		DWORD dataSize;		lpCPUSpeed[0] = 0;		// ---------------------------------------------		// 프로세서의 속도를 얻어낸다.		// ---------------------------------------------		result = ::RegOpenKeyEx (HKEY_LOCAL_MACHINE,			"Hardware\Description\System\CentralProcessor\0", 0, KEY_QUERY_VALUE, &hKey);		if (result == ERROR_SUCCESS) 		{			result = ::RegQueryValueEx (hKey, "~MHz", NULL, NULL,(LPBYTE)&data, &dataSize);			wsprintf(lpCPUSpeed, "%d MHz", data);		}		RegCloseKey (hKey);		// ------------------------------------------		// 하드웨어 정보를 얻어낸다.		// ------------------------------------------		GetSystemInfo (&sysInfo);		// 프로세서 타입부터 검사한다.		if (sysInfo.dwProcessorType  == PROCESSOR_INTEL_386)			strcpy(lpProcessorType,  "Intel 386");		else if (sysInfo.dwProcessorType  == PROCESSOR_INTEL_486)			strcpy(lpProcessorType,  "Intel 486");		else if (sysInfo.dwProcessorType  == PROCESSOR_INTEL_PENTIUM)		{			if (sysInfo.wProcessorLevel == 6) 				strcpy(lpProcessorType, "Intel Pentium (II/Pro)");			else				strcpy(lpProcessorType,  "Intel Pentium");		}		else 			strcpy(lpProcessorType, "알 수 없는 시스템");		// 프로세서의 갯수를 검사한다.		wsprintf(lpNumProcessors, "%d", sysInfo.dwNumberOfProcessors);	}
    다음으로 현재 사용 중인 운영체제의 종류를 알아내는 코드는 다음과 같습니다.
    	//===============================================================	// GetOSVersion : OS의 버전을 얻어온다.	// --------------------------------------------------------------	// lpstInfo	// lpstBuildNumber	// lpstServicePack	//===============================================================	void GetOSVersion (LPSTR lpstInfo, LPSTR lpstBuildNumber, LPSTR lpstServicePack)	{		int stat = 0;		TCHAR data [64];		DWORD dataSize;		DWORD win95Info;		OSVERSIONINFO versionInfo;		HKEY hKey;		LONG result;		lpstServicePack[0] = 0;		versionInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);		// 버전 정보를 얻어낸다.		if (!::GetVersionEx (&versionInfo)) 		{			strcpy(lpstInfo, "운영체제 정보를 얻을 수 없습니다.");			return;		}		// NT이면 서버인지 웍스테이션인지 검사한다. 이는 레지스트리를 보고 검사한다.		if (versionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) 		{			strcpy(lpstInfo, "Windows NT");			dataSize = sizeof (data);					result = ::RegOpenKeyEx (HKEY_LOCAL_MACHINE,				"System\CurrentControlSet\Control\ProductOptions", 0, KEY_QUERY_VALUE, &hKey);			if (result != ERROR_SUCCESS) 				return;			result = ::RegQueryValueEx (hKey, "ProductType", NULL, NULL, (LPBYTE) data, &dataSize);			RegCloseKey (hKey);			if (result != ERROR_SUCCESS) 				return;			if (lstrcmpi (data, "WinNT") == 0) 				strcpy(lpstInfo, "Windows NT Workstation");			else if (lstrcmpi (data, "ServerNT") == 0) 				strcpy(lpstInfo, "Windows NT Server");			else 				strcpy(lpstInfo, "Windows NT Server - Domain Controller");			// NT 버전을 알아낸다.			if (versionInfo.dwMajorVersion == 3 || versionInfo.dwMinorVersion == 51) 				strcat(lpstInfo, " 3.51");			else if (versionInfo.dwMajorVersion == 5) // 윈도우 2000의 경우				strcat(lpstInfo, " 5.0");			else 				strcat(lpstInfo, " 4.0");			// Build 번호를 알아낸다.			wsprintf(lpstBuildNumber, "%d", versionInfo.dwBuildNumber);		}		else if (versionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) 		{			strcpy(lpstInfo, "Windows 95");			if ((versionInfo.dwMajorVersion > 4) || ((versionInfo.dwMajorVersion == 4)				&& (versionInfo.dwMinorVersion > 0))) 			{				strcpy(lpstInfo, "Windows 98");			}			// 윈도우 95는 Build 번호가 하위 워드에 들어간다.			win95Info = (DWORD)(LOBYTE(LOWORD(versionInfo.dwBuildNumber)));			wsprintf(lpstBuildNumber, "%d", win95Info);		}		else 			wsprintf(lpstInfo, "Windows 3.1");		// 서비스 팩 정보를 얻어낸다.		strcpy(lpstServicePack, versionInfo.szCSDVersion);	}

    12. IE의 설치 여부와 버전 확인

    현재 시스템에 IE가 설치되었는지 여부와 그 버전을 알려면 어떻게 해야합니까 ?

    사실 동작시켜보지 않고서는 IE가 제대로 설치되어있는지 알아내는 방법은 없지만 레지스트리를 통해 IE가 설치되었는지 여부와 버전을 확인할 수 있습니다. 그 함수는 다음과 같습니다.

    	//===========================================================================	// GetIEVersion : IE의 버전을 얻는다. 정보를 찾을 수 없으면 FALSE를 리턴한다.	//===========================================================================	BOOL GetIEVersion(LPSTR lpVer)	{			LONG result;		HKEY hKey;		DWORD dwType; 		char data[65];		DWORD dataSize = 64;		// --------------------		// IE의 버전을 얻는다.		// --------------------		result = ::RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Software\Microsoft\Internet Explorer", 0, KEY_QUERY_VALUE, &hKey);		if (result == ERROR_SUCCESS) 		{			result = ::RegQueryValueEx (hKey, "Version", NULL, &dwType, (unsigned char *)data, &dataSize);			strcpy(lpVer, data);		}		else			return FALSE;		RegCloseKey (hKey);		return TRUE;	}

    13. IE의 보안 설정 보기

    IE에 보면 네 단계의 보안 영역이 있습니다. 그 영역별로 설정되어있는 보안 설정값을 읽으려면 어떻게 해야합니까 ?

    IE에는 다음과 같은 네 가지 보안 영역이 존재합니다.

    • 인터넷 영역
    • 로컬 인터넷 영역
    • 신뢰할 수 있는 사이트 영역
    • 제한된 사이트 영역
    IE는 보안 영역 설정과 관련하여 Internet Security Manager와 Internet Zone Manager라는 인터페이스가 존재합니다. 이를 이용해 보안 영역의 보안을 설정하고 특정 IP나 도메인 이름을 등록할 수 있습니다. 자세한 사항은 레퍼런스를 찾아보기 바랍니다.
     	#include "objbase.h"	#include "urlmon.h"	char szTemp1[256];	char szTemp2[256];	HRESULT hr;	IInternetSecurityManager *pSecurityMgr;	IInternetZoneManager *pZoneMgr;	DWORD dwEnum, dwZoneCount;	// --- 변수 선언부	DWORD dwZone;	ZONEATTRIBUTES zoneAttr;	int nLevel = 2;	// COM 라이브러리를 초기화한다.	CoInitialize(NULL);	dwEnum = 0;	pSecurityMgr = NULL;	pZoneMgr = NULL;	// Internet Security 인터페이스 초기화	hr = CoCreateInstance(CLSID_InternetSecurityManager, NULL, CLSCTX_ALL, //INPROC_SERVER,			IID_IInternetSecurityManager, (void**)&pSecurityMgr);	if (hr != S_OK)	{		return;	}	hr = CoCreateInstance(CLSID_InternetZoneManager, NULL, CLSCTX_ALL, //INPROC_SERVER,			IID_IInternetZoneManager, (void**)&pZoneMgr);		if (hr != S_OK)	{		return;	}	dwEnum = 0;	// 보안 영역 열거자(Zone Enumerator)를 초기화한다.	pZoneMgr->CreateZoneEnumerator(&dwEnum, &dwZoneCount, 0);	for(DWORD i = 1;i < dwZoneCount;i++)	{		pZoneMgr->GetZoneAt(dwEnum, i, &dwZone);		pZoneMgr->GetZoneAttributes(dwZone, &zoneAttr);		// zoneAttr.szDisplayName에 보안 영역의 이름이 들어오는데 유니코드이다. 이를 변환한다.		WideCharToMultiByte(CP_ACP, 0, zoneAttr.szDisplayName, -1, szTemp1, 255, NULL, NULL);			// zoneAttr.dwTemplateCurrentLevel에는 보안 영역의 보안값 설정이 들어온다.		wsprintf(szTemp2, "%x", zoneAttr.dwTemplateCurrentLevel);	}	// 보안 영역 열거자(Zone Enumerator)를 제거한다.	if (dwEnum != 0)		pZoneMgr->DestroyZoneEnumerator(dwEnum);	pSecurityMgr->Release();	pZoneMgr->Release();	// COM 라이브러리를 메모리에서 내린다.	CoUninitialize();}

    14. ActiveX 컨트롤의 등록 방법

    Regsvr32 같은 유틸리티를 이용하지 않고 프로그램 내에서 컨트롤을 레지스트리에 등록하려면 어떻게 해야합니까 ?

    모든 AcitveX 컨트롤은 자신을 레지스트리에 등록하기위한 목적으로 DllRegisterServer라는 함수를 갖고 있습니다. ActiveX 컨트롤을 메모리로 로드한 다음에 이 함수를 불러주면 원하는 일을 수행할 수 있습니다. 반대로 ActiveX 컨트롤을 레지스트리에서 제거하기 위한 용도로 DllUnRegisterServer라는 함 수도 존재합니다.

    	// ==============================================================	// RegisterOCX     지정된 ActiveX 컨트롤을 레지스트리에 등록한다.	// --------------------------------------------------------------	// LPSTR pszString 등록하고자 하는 ActiveX 컨트롤의 절대 경로명	// ==============================================================	BOOL WINAPI RegisterOCX(LPSTR pszString)	{		int iReturn = 0;		HRESULT (STDAPICALLTYPE * lpDllEntryPoint)();		HINSTANCE hLib;		// OLE 라이브러리를 초기화한다.						if (FAILED(OleInitialize(NULL)))		{			MessageBox(GetFocus(), "OLE 초기화 실패", "에러", MB_OK);			return FALSE;		}		// 지정된 activeX 컨트롤을 메모리로 로드한다.		hLib = LoadLibrary(pszString);		if (hLib <= NULL)		{			MessageBox(GetFocus(), "파일을 로드하는데 실패했습니다.", "에러", MB_OK);			OleUninitialize();			return FALSE;		}		// "DllRegisterServer" 함수의 위치를 찾는다.		lpDllEntryPoint = (long (__stdcall *)(void))GetProcAddress(hLib, "DllRegisterServer");			// 이 함수를 호출합니다.		if (lpDllEntryPoint)		{			if (FAILED((*lpDllEntryPoint)()))			{				DWORD dwRet;				char szTemp[128];				dwRet = GetLastError();				wsprintf(szTemp, "에러 번호 : %lx", dwRet);				MessageBox(GetFocus(), szTemp, "DllRegisterServer 에러", MB_OK);				FreeLibrary(hLib);				OleUninitialize();				return FALSE;			}		}		else		{			MessageBox(GetFocus(), "DllRegisterServer를 찾을 수 없습니다.", "에러", MB_OK);			FreeLibrary(hLib);			OleUninitialize();			return FALSE;		}		FreeLibrary(hLib);		OleUninitialize();		return TRUE;	}

    15. 데이터 파일의 실행

    탐색기에서 실행 파일이 아닌 데이터 파일을 더블클릭하면 그 데이터 파일과 연결된 실행 파일이 실행되면서 그 파일을 물고 올라갑니다. 이를 구현하는 방법을 알려주세요.

    ShellExecuteEx라는 API를 사용하면 됩니다. 다음 함수는 인자로 데이터 파일 혹은 실행 파일의 경로를 받아서 실행해줍니다. 데이터 파일의 경우에는 연결된 실행 파일을 찾아서 그걸 실행해줍니다.

    	BOOL Execute(LPSTR lpPath)	{		char FilePath[255];		SHELLEXECUTEINFO  ExecInfo;			// lpPath를 나누어 본다.		char drive[_MAX_DRIVE];		char dir[_MAX_DIR];		char fname[_MAX_FNAME];		char ext[_MAX_EXT];		_splitpath(lpPath, drive, dir, fname, ext);		// 디렉토리 경로를 얻는다.		strcpy(FilePath, drive);		strcat(FilePath, dir);		// 파일 이름을 얻는다.		strcat(fname, ".");		strcat(fname, ext);		SHELLEXECUTEINFO  ExecInfo;		ExecInfo.cbSize = sizeof(SHELLEXECUTEINFO); 		ExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS; 		ExecInfo.hwnd = hWnd; 		ExecInfo.lpVerb = "open"; 		ExecInfo.lpFile = fname; 		ExecInfo.lpParameters = NULL; 		ExecInfo.lpDirectory = FilePath; 		ExecInfo.nShow = SW_SHOW; 		ExecInfo.hInstApp = g_hInstance; // g_hInstance는 프로그램의 인스턴스 핸들		return ShellExecuteEx(&ExecInfo);	}

    16. 파일의 존재 여부 테스트

    어떤 파일이 실제로 존재하는 것인지 간단히 테스트해보는 방법은 무엇인가요 ?

    CreateFile API를 사용하면 됩니다. 파일을 열때 플래그 중의 하나로 OPEN_EXISTING이라는 것이 있는데 이를 사용하면 됩니다. 다음 코드를 예로 보시기 바랍니다.

    	hFile = CreateFile("C:\TEMP\test.txt", GENERIC_READ, 0, NULL,  			OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);	if (hFile != INVALID_HANDLE_VALUE)	{		// 파일이 존재하는 경우		CloseHandle(hFile);	}

    17. API를 이용한 파일 I/O

    API를 이용한 파일 입출력에 대한 예제 코드가 없습니까 ?

    프로그래밍을 하다보면 간혹 파일 I/O를 API를 이용해 수행해야 할 경우가 있습니다. 이 때 다음의 예제 코드를 복사해다가 사용하면 편리할 것입니다. MFC의 CFile을 이용한 파일 I/O에 대해 알고 싶으시면 요기를 클릭하세요.

  • 파일 쓰기의 경우
    	HANDLE fp;	DWORD NumberOfBytesWritten;	char lpBuffer[1024];	// FileName이 지정한 파일의 이름이 있으면 그걸 열고 없으면 그 이름으로 하나 생성한다.	if ((fp=CreateFile((LPCTSTR)FileName, GENERIC_WRITE | GENERIC_READ,	0, NULL, 						OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE)	{		// 파일 열기 에러 발생	}  	// 필요한 만큼 WriteFile의 호출을 반복한다. 파일 포인터의 이동시에는 SetFilePointer API를 이용한다.	WriteFile(fp, lpBuffer, 1024, &NumberOfBytesWritten, NULL);	if (NumberOfBytesWritten != 1024)	{		// 파일 쓰기 에러 발생 		CloseHandle(fp);			}	// 작업이 다 끝났으면 파일을 닫는다.	CloseHandle(fp);		
  • 파일 읽기의 경우
    	HANDLE fp;	DWORD NumberOfBytesRead;	char lpBuffer[1024];	if ((fp=CreateFile((LPCTSTR)FileName, GENERIC_READ,			FILE_SHARE_READ, NULL, OPEN_EXISTING, 		FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE)	{		// 파일 열기 에러 발생	}  	// 필요한 만큼 ReadFile의 호출을 반복한다.	ReadFile(fp, lpBuffer, 1024, &NumberOfBytesRead, NULL);	if (NumberOfBytesRead != 1024)	{		// 파일 읽기 에러 발생 		CloseHandle(fp);			}	// 작업이 다 끝났으면 파일을 닫는다.	CloseHandle(fp);		

    파일 포인터의 이동시에는 SetFilePointer라는 API를 사용하고 파일의 크기를 알고 싶을 때는 GetFileSize라는 API를 사용한다.

    18. GetParent API의 리턴값

    다이얼로그 박스에서 GetParent API를 호출했을 때 리턴되는 값이 이상합니다.

    GetParent API의 리턴값은 보통의 윈도우에서는 윈도우 생성시 지정한 부모/자식 윈도우 간의 관계에 따라 달라집니다. 하지만 다이얼로그 박스의 경우에는 다릅니다. 다이얼로그 박스는 GetParent를 호출하면 무조건 그 것이 속한 응용프로그램의 메인 윈도우 핸들이 리턴됩니다.

    19. 특정 프로그램을 실행하고 종료를 기다리기

    특정 프로그램을 실행한 다음에 그 프로그램이 종료될 때 다른 일을 하고 싶습니다. 어떻게 해야합니까 ?

    다음은 CreateProcess를 이용해서 특정 프로그램의 실행이 끝나기를 기다리는 코드입니다.

    	// buffer에 실행하고자하는 파일이름이 들어온다.	void DoCreate(HWND hWnd, LPSTR buffer)	{		STARTUPINFO            sui;		PROCESS_INFORMATION    pi;		DWORD                  ret;		memset(&sui, 0x00, sizeof(STARTUPINFO));		sui.cb = sizeof(STARTUPINFO);    		ret = CreateProcess(buffer, NULL, NULL, NULL, FALSE, 			0, NULL, NULL,&sui, &pi);		if (ret == TRUE) // 제대로 실행되었으면		{			hProcess = pi.hProcess;			// 실행이 끝나기를 대기한다.			WaitForSingleObject(hProcess, 0xffffffff);			CloseHandle(hProcess);		}	}

    20. 파일 열기 다이얼로그 띄우기

    API를 이용해 파일 오픈 다이얼로그를 띄우고 싶습니다.

    API를 이용해 파일 오픈 다이얼로그를 띄우는 방법은 다음과 같습니다.

    	#define MAXCHARS   255	OPENFILENAME       ofn;	char               buffer[MAXCHARS];	memset(&ofn, 0x00, sizeof(OPENFILENAME));	ofn.lStructSize = sizeof(OPENFILENAME);	ofn.hwndOwner = hWnd;	ofn.lpstrFilter = "모든 파일00*.*0000";	ofn.lpstrInitialDir = m_szTemp;	ofn.nFilterIndex = 1;	ofn.lpstrFile = buffer;	ofn.nMaxFile = MAXCHARS;	ofn.lpstrTitle = "파일 선택하기";	if (GetOpenFileName(&ofn))  // 사용자가 파일을 제대로 선택한 경우	{		// ....	}

    21. 긴 파일 이름과 짧은 파일 이름간의 변환 방법

    주어진 긴 파일 이름에 해당하는 짧은 파일 이름을 알려면 어떻게 해야하나요 ?

  • 긴 파일 이름에서 짧은 파일 이름으로의 변환 : GetShortPathName API 사용
  • 짧은 파일 이름에서 긴 파일 이름으로의 변환 : GetFullPathName API 사용

    22. 시스템 이미지 리스트 얻어내기

    탐색기 등에서 사용되는 시스템 이미지 리스트를 사용할 수 있는 방법이 있는지 알고 싶습니다.

    물론 있습니다. SHGetFileInfo라는 API를 이용하면 됩니다. 이를 이용하면 16X16이나 32X32 크기의 이미지 리스트를 얻어낼 수 있습니다.

    	SHFILEINFO sfi;	HIMAGELIST sysSmallList, sysLargeList;	sysSmallList = (HIMAGELIST)SHGetFileInfo(TEXT("C:\"), 0, &sfi,   sizeof(SHFILEINFO), SHGFI_SYSICONINDEX | SHGFI_SMALLICON);	sysLargeList = (HIMAGELIST)SHGetFileInfo(TEXT("C:\"), 0, &sfi,   sizeof(SHFILEINFO), SHGFI_SYSICONINDEX | SHGFI_ICON);

    23. 리스트뷰 컨트롤에서 스타일 동적 변경하기

    리스트뷰 컨트롤에서 리스트(LVS_ICON) 스타일을 사용 중인데 이를 실행 중에 리포트(LVS_REPORT) 스타일로 변경하고 싶습니다. 어떻게 해야할까요 ?

    윈도우의 스타일은 윈도우 엑스트라 바이트라는 영역에 저장됩니다. 이 곳의 데이터를 읽고 쓰는데 GetWindowLong, SetWindowLong 같은 API를 사용하는데 다음 코드를 예로 보시기 바랍니다.

  • 리스트 스타일에서 리포트 스타일로
    	LONG lStyle = GetWindowLong(hListWnd, GWL_STYLE);	SetWindowLong(hListWnd, GWL_STYLE, (lStyle & ~LVS_LIST) | LVS_REPORT);
  • 리포트 스타일에서 리스트 스타일로
    	LONG lStyle = GetWindowLong(hListWnd, GWL_STYLE);	SetWindowLong(hListWnd, GWL_STYLE, (lStyle & ~LVS_REPORT) | LVS_LIST);

    24. 윈도우와 다이얼로그에서 클래스 포인터의 사용

    제가 만든 C++ 클래스내에서 윈도우를 생성합니다. 생성한 윈도우의 윈도우 프로시저는 그 클래스의 정적 멤버 함수로 선언되어 있습니다. 정적 함수의 경우에는 데이터 멤버를 접근하지 못하기 때문에 접근하게 하려고 윈도우를 생성한 그 클래스의 객체에 대한 포인터를 전역 변수로 유지하여 사용하고 있습니다. 별로 깨끗한 방법도 아닌 것 같고 또 동시에 여러 개의 객체가 동작할 경우에는 에러가 날 수밖에 없는데 해결 방법이 없을까요 ?

    이는 다이얼로그의 경우에도 마찬가지입니다. 윈도우 생성시 사용하는 CreateWindow나 CreateWindowEx 같은 함수를 보면 마지막 인자로 윈도우 생성 데이터라는 것을 지정하게 되어있습니다. 다이얼로그 생성시에는 DialogBox라는 API말고 DialogBoxParam이라는 API가 있어서 마지막 인자로 초기화 데이터를 넘겨줄 수 있도록 되어있는데 이것과 윈도우 엑스트라 바이트를 같이 사용하면 정적함수로 선언된 윈도우 프로시저나 다이얼로그박스 프로시저내에서 객체에 대한 포인터를 사용할 수 있습니다. 예를 들어 살펴보겠습니다.

  • 윈도우의 경우

    다음과 같이 CExplorerBar라는 클래스내에서 윈도우를 하나 생성합니다. CreateWindowEx 함수나 CreateWindow 함수의 마지막 인자로 this 포인터를 지정합니다.

    	BOOL CExplorerBar::RegisterAndCreateWindow(void)	{		....		CreateWindowEx( 0,  EB_CLASS_NAME, NULL,                     WS_CHILD | WS_CLIPSIBLINGS | WS_BORDER,                     rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,                     m_hwndParent, NULL, g_hInst, (LPVOID)this);         }

    위에서 생성한 윈도우의 윈도우 프로시저는 WndProc이고 CExplorerBar 클래스의 정적 멤버 함수로 존재한다고 가정하겠습니다.

    	LRESULT CALLBACK CExplorerBar::WndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)	{		CExplorerBar  *pThis = (CExplorerBar*)GetWindowLong(hWnd, GWL_USERDATA);		switch (uMessage)		{			case WM_NCCREATE:			{				LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam;				pThis = (CExplorerBar*)(lpcs->lpCreateParams);				SetWindowLong(hWnd, GWL_USERDATA, (LONG)pThis);			}			break;			case WM_CREATE :				return pThis->OnCreate();

    WM_NCCREATE 메시지에서 lParam 인자로 넘어오는 CExplorerBar 객체에 대한 포인터를 받아서 윈도우 엑스트라 바이트로 저장하고 있습니다. 윈도우 엑스트라 바이트는 윈도우 마다 할당되는 고유의 영역으로 사용자 정의 영역으로 GWL_USERDATA가 정의되어 있습니다. 여기에다 CExplorerBar 객체에 대한 포인터를 저장해두고 윈도우 프로시저에 진입할 때마다 이 값을 pThis라는 변수에 대입해 놓고 사용합니다. 참고로 WM_NCCREATE는 WM_CREATE 메시지보다 먼저 발생하는 메시지입니다.

  • 다이얼로그의 경우

    예를 들어 CKTree라는 클래스내의 한 멤버 함수에서 다이얼로그 박스를 띄운다고 가정하겠습니다.

    	BOOL CKTree::SelectFolder(short sTypes, long dwFolderID, short  bCreationEnabled)	{		// ......		if (DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_FOLDER_SELECT), hWnd, (DLGPROC)SelectFolderDlg, (LPARAM)this))

    DialogBoxParam 함수는 DialogBox 함수보다 인자가 하나 더 있는데 그것이 바로 다이얼로그 프로시저의 WM_INITDIALOG 메시지의 lParam 인자로 넘어갑니다. 여기에 CKTree 객체에 대한 포인터를 넘깁니다. 그리고나서 다이얼로그 박스 프로시저의 WM_INITDIALOG 메시지에서 이를 받아서

    	LRESULT CALLBACK SelectFolderDlg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)	{		switch (message) 		{		        case WM_INITDIALOG:			{				// lParam으로 넘어온 값을 KPointer라는 윈도우 프로퍼티에 저장한다.				SetProp(hDlg, "KPointer", (HANDLE)lParam);				.......			case  WM_NOTIFY :			{				// CKTree 객체에 대한 포인터가 필요하면 KPointer 윈도우 프로퍼티 값을 읽어들인다.				CKTree *pKTree = (CKMartTree *)GetProp(hDlg, "KPointer");				if (pKTree->m_bWait)				{					.....

    여기서는 앞서 윈도우와는 달리 윈도우 프로퍼티라는 것을 이용해서 넘어온 포인터 정보를 저장하고 필요할 때 읽어옵니다. 여기서 앞서의 윈도우 엑스트라 바이트를 사용해도 무방합니다.

    25. 특정 프린터로 출력하기

    제 PC에는 두 대의 프린터가 붙어있습니다. 다이얼로그를 띄우지 않고 상황에 따라 다른 프린터로 출력하고 싶은데 동적으로 HDC를 생성하는 방법을 모르겠습니다.

    CreateDC를 이용하면 됩니다. 시스템 디렉토리의 WIN.INI를 보면 [Devices]라는 섹션이 있는데 이 아래로 이 시스템에 설치되어 있는 모든 프린터 드라이버의 목록이 나옵니다. 예를 들어 다음과 같이 나옵니다.

    	[Devices]	HUNFAX=HUNFAX,FaxModem	삼성 SLB-6216H PCL5=SSMPCL5,\영업팀볼륨프린터	......

    프린터별로 DeviceName=DriverName,OutputName와 같은 구조로 구성되어 있습니다. 이 값들을 CreateDC의 인자로 사용하면 됩니다. 예를 들어 위에서 두 번째 프린터의 DC를 생성하려면 다음과 같이 CreateDC를 호출합니다.

    	// hDC = CreateDC(DriverName, DeviceName, OutputName, NULL);	hDC = CreateDC ("SSMPCL5", "삼성 SLB-6216H PCL5", "\\영업팀\볼륨프린터", NULL) ;

    CreateDC의 마지막 인자로는 프린터의 설정값을 변경할 수 있습니다. 예를 들어 가로로 찍는다든지 2장을 찍는다든지 하는 설정을 변경하는데 사용됩니다. NULL을 주면 디폴트 값을 사용합니다. 다른 설정을 사용하고 싶다면 다음과 같이 합니다. CreateDC 호출 앞에서 DocumentProperties라는 함수를 호출하여 프린터의 기본 설정을 읽어온 다음에 이를 변경합니다. 다음 예는 출력 방향을 가로로 변경하는 예제입니다.

    	// 프린터의 디폴트 설정을 읽어온다.	LPDEVMODE lpoutDevMode;	HANDLE hPrinter;	HDC hPrnDC;	// 프린터의 핸들을 얻는다.	if (OpenPrinter( lpDeviceName, &hPrinter,  NULL))	{		// OpenPrinter로 얻은 프린터의 초기 설정을 DocumentProperties API로 얻어온다.		// 먼저 마지막 인자를 0으로 해서 DocumentProperties를 호출하여 필요한 버퍼의 크기를 알아옵니다.		long lSize = DocumentProperties(GetFocus(), hPrinter, lpPrinterName, NULL, NULL, 0);		lpoutDevMode = (LPDEVMODE)malloc(lSize);		long lRet = DocumentProperties(GetFocus(), hPrinter, lpPrinterName, lpoutDevMode, NULL, DM_OUT_BUFFER);		if (lRet == IDOK)		{			// 프린터의 인쇄 방향 설정을 변경한다.			// 여기서 원하는 변환을 수행한다.			lpoutDevMode->dmOrientation = DMORIENT_LANDSCAPE;		}		hPrnDC = CreateDC (lpDriverName, lpDeviceName, lpOutputName, lpoutDevMode) ;		free(lpoutDevMode);		return hPrnDC;	}

    26. 메뉴 관련 함수

    메뉴 항목을 하나 추가하려고 합니다. InsertMenuItem API를 사용하는데 윈도우 3.1에서와 사용법이 다른 것 같습니다.

    사용법이 달라졌습니다.

    	MENUITEMINFO mii;	memset(&mii, 0x00, sizeof(MENUITEMINFO));	mii.cbSize = sizeof(MENUITEMINFO);	mii.fMask = MIIM_TYPE;	mii.fType = MFT_SEPARATOR;	InsertMenuItem(hSubMenu, GetMenuItemCount(hSubMenu), TRUE,  &mii);								mii.cbSize = sizeof(MENUITEMINFO);	mii.fMask = MIIM_TYPE | MIIM_STATE | MIIM_ID;	mii.fType = MFT_STRING;	mii.fState = MFS_DEFAULT | MFS_UNHILITE;	mii.wID = ID_WORKPLACE_REMOVE;	mii.dwTypeData = "바구니에서 제거";	InsertMenuItem(hSubMenu, GetMenuItemCount(hSubMenu), TRUE,  &mii);

    27. 코드 실행 중에 다른 윈도우 메시지 처리하기

    하나의 함수 내에서 시간이 오래 걸리는 작업을 하고 있습니다. 이 때 작업 취소를 위한 별도의 다이얼로그를 하나 띄워 두었는데 이 쪽의 버튼이 눌리지 않습니다. 어떻게 해야할까요 ?

    시간이 오래 걸리는 작업을 별도의 스레드로 만들어 처리하던지 아니면 시간이 오래 걸리는 작업을 수행하는 함수 안에서 다음 코드를 가끔 호출해주면 됩니다. 만일 루프를 돌고 있다면 루프내에서 한번씩 호출해주면 됩니다.

    	MSG       msg;	while (PeekMessage(&msg, NULL, NULL, NULL, TRUE))	{		TranslateMessage(&msg);		DispatchMessage(&msg);	}

    VB에서라면 DoEvents라는 메소드를 호출해주면 됩니다.

    28. 메인 윈도우에서 캡션을 제거하고 싶습니다. 어떻게 해야 합니까 ?

    윈도우를 생성할 때 WS_CAPTION이란 스타일을 지정하지 않아도 항상 윈도우의 캡션이 보입니다. 이를 제거하려면 어떻게 해야 하나요 ?

    캡션을 제거하려는 윈도우의 WM_NCCREATE 메시지를 처리해야 합니다. 이 메시지는 WM_CREATE 메시지보다 앞서 발생하는 메시지입니다. NC는 Non-Client를 나타냅니다. GetWindowLong과 SetWindowLong API를 이용해서 WS_CAPTION 스타일을 제거합니다. 이 두 API는 앞서 리스트뷰 컨트롤에서 스타일 동적 변경하기에서 이미 사용해본 바 있습니다.

    		case WM_NCCREATE :		{			long lStyle;    			lStyle = GetWindowLong(hWnd, GWL_STYLE);			lStyle = (lStyle & (~WS_CAPTION)); 			SetWindowLong (hWnd, GWL_STYLE, lStyle);			return TRUE;		}

    29. 사각형 형태 이외의 모양을 갖는 윈도우를 띄우고 싶습니다.

    윈도우는 기본 모양이 사각형인데 다른 형태의 모양을 갖는 윈도우를 띄우려면 어떻게 해야합니까 ?

    원하는 모양을 Region이란 것으로 만들어야 합니다. 만든 다음에 이것을 원하는 시점에 SetWindowRgn라는 API를 이용해 윈도우에 설정해주면 됩니다. 예를 들어 타원 모양의 윈도우를 띄우고 싶다면 다음과 같이 해주면 됩니다.

    	HRGN g_hRgn;	g_hRgn = CreateEllipticRgn(0, 0, 700, 600);	SetWindowRgn(hWnd, g_hRgn, FALSE);		

    이렇게 했을 경우 윈도우의 위치 이동이 문제가 됩니다. 보통 캡션을 잡고 이동시켜야 하는데 캡션이 없으니까 문제가 됩니다. 이에 관한 것은 31. 윈도우의 이동 처리하기를 참고하기 바랍니다.

    30. 시스템에 설치되어 있는 모든 프린터 드라이버 알아내기

    현재 시스템에 설치되어 있는 모든 프린터 드라이버의 종류를 알아내고 싶습니다.

    EnumPrinters라는 API를 사용하면 됩니다. 다음 코드는 현재 시스템에 설치되어 있는 모든 프린터 드라이버(로컬과 네트웍 프린터 포함)의 이름을 메시지박스로 보여주는 예제입니다.

    	BOOL bSuccess;	DWORD cbRequired, cbBuffer, nEntries;	PRINTER_INFO_1 *lpBuffer = NULL;	// 버퍼의 크기를 알아낸다. cbRequired로 들어온다.	EnumPrinters(PRINTER_ENUM_CONNECTIONS | PRINTER_ENUM_LOCAL, NULL, 1, (unsigned char *)lpBuffer, 0, &cbRequired, &nEntries);	cbBuffer = cbRequired;	// 버퍼를 다시 버퍼를 잡는다.	lpBuffer = (PRINTER_INFO_1 *)malloc(cbBuffer);	// 프린터의 종류를 알아낸다.	bSuccess =	EnumPrinters(PRINTER_ENUM_CONNECTIONS | PRINTER_ENUM_LOCAL, NULL, 1, (unsigned char *)lpBuffer, cbRequired, &cbRequired, &nEntries);	if (bSuccess == FALSE)	{		free(lpBuffer);		// 다른 이유로 에러가 난 경우		return;	}	// 알아낸 프린터를 하나씩 enumerate한다.	for (int i = 0;i < nEntries; i++)	{		::MessageBox(NULL, lpBuffer[i].pName, "프린터 이름", MB_OK);  	}	free(lpBuffer);

    31. 윈도우의 이동 처리하기

    보통 윈도우는 캡션 영역을 잡고 위치 이동을 수행하게 되는데 윈도우의 특정 영역을 잡고 이동할 수 있게 하려면 어떻게 해야합니까 ?

    WM_NCHITTEST라는 메시지를 잘(?) 처리하면 어느 영역이든 윈도우 이동을 처리할 수 있습니다. 마우스로 윈도우 위를 이동하면 WM_NCHITTEST, WM_SETCURSOR, WM_MOUSEMOVE 같은 메시지들이 발생합니다. WM_NCHITTEST는 현재 마우스가 윈도우의 어느 영역위에 있는지 알아내기 위해 사용됩니다. 이 메시지의 처리부에서 HTCAPTION이란 값을 리턴해주면 윈도우 운영체제는 지금 마우스 포인터가 윈도우의 캡션 부분에 와있다고 생각해서 여기서 드래그 작업이 시작될 경우에 윈도우의 위치를 이동시켜 버립니다. 다음 코드는 WM_NCHITTEST 메시지를 처리하여 현재 마우스 좌표가 정해진 영역에 있으면 HTCAPTION을 돌려주는 예제입니다.

    	case WM_NCHITTEST:	{		// 현재 마우스 위치를 바탕으로 pt 변수를 채운다.		POINT pt(LOWORD(lParam), HIWORD(lParam));		// 마우스 좌표를 윈도우의 좌측 상단 기준의 좌표로 변경한다.		ScreenToClient(hWnd, &pt);		// 지정된 사각형 안에 포함되는 점인지 검사한다. 		// g_TitleRect는 RECT 타입의 변수로 지정된 사각형의 좌표가 들어있다.		if (PtInRect(&g_TitleRect, pt))			return HTCAPTION;					break;	}

    32. 바탕 화면 위의 모든 윈도우를 최소화하거나 모든 최소화 실행 취소

    바탕 화면 위의 모든 윈도우를 최소화하거나 모두 최소화 실행 취소를 프로그램으로 구현하는 방법을 알고 싶습니다.

    태스크바의 빈 공간을 오른쪽 마우스 버튼으로 클릭해보면 팝업 메뉴가 뜨는데 거기에 보면 "모든 창을 최소화(M)"와 "모두 최소화 실행 취소(U)" 명령이 존재하는데 그것을 대신 선택해주는 형식으로 프로그램을 작성해주면 됩니다.

    다음은 "모든 창을 최소화"해주는 루틴입니다. keybd_event API를 이용해서 사용자가 키입력한 것처럼 흉내내줍니다.

    	void IconizeAllWindow()	{ 		keybd_event(0x5b, 0, 0, 0);		keybd_event(77, 0, 0, 0);    // 'M' key		keybd_event(0x5b, 0, 2, 0);	}

    다음은 "모두 최소화 실행 취소" 루틴입니다.

    	void RestoreWindowState()	{		keybd_event(0x5b, 0, 0, 0);		keybd_event(84, 0, 0, 0);    // 'U' key		keybd_event(0x5b, 0, 2, 0);	}

    33. VxD 드라이버 호출하기

    Vxd 드라이버를 동적으로 로드해서 호출하고 싶습니다. 어떻게 해야합니까 ?

    먼저 해당하는 VxD 드라이버의 이름과 위치와 호출하려는 작업의 작업 코드명을 알아야 합니다. 드라이버의 로드는 CreateFile API를 이용합니다. VxD 드라이버의 호출은 DeviceIoControl API를 이용합니다. 자세한 설명은 DeviceIoControl API의 레퍼런스를 참고하기 바랍니다.

    	DWORD byteReturned;	// 먼저 VxD 드라이버를 오픈한다.	hDevice = CreateFile("\\.\NMOUSE.VXD", 0, 0, 0, CREATE_NEW, FILE_FLAG_DELETE_ON_CLOSE, 0);	if (DeviceIoControl(hDevice, W32_SETHWND, &hWnd, 4, NULL, 0, &byteReturned, NULL))	{		// Success !!!	}

    Vxd 드라이버는 kernel 모드(이를 윈도우에서는 Ring 0라고 부릅니다)에서 동작하기 때문에 모든 하드웨어와 메모리를 바로 접근할 수 있습니다. VxD 드라이버를 작성하려면 DDK를 이용하거나 Numega의 DriverStudio나 KRFTech사의 WinDriver를 이용해야 합니다.

    34. Thread 실행시 에러

    CreateThread를 이용해 스레드를 만들어 생성하고 있습니다. 루틴에 이상은 없는 것 같은데 스레드가 많이 생성되어 시간이 좀 지나면 에러가 발생합니다. 이유가 무엇일까요 ?

    정말로 스레드 코드에 별 이상이 없다면 CreateThread API 대신에 beginthread나 beginthreadex를 사용해보기 바랍니다. 자세한 사항은 마이크로소프트의 Knowledge base를 참고하시기 바랍니다.

    35. 윈도우 운영체제 종료하기

    프로그램에서 특정 상황이 되면 윈도우 운영체제를 종료하고 싶습니다.

    ExitWindowsEx API를 사용하면 됩니다. 이 함수의 원형은 다음과 같습니다.

    	BOOL ExitWindowsEx(UINT uFlags, DWORD dwReserved);

    uFlags로 종료방법을 지정할 수 있습니다. 다음과 같은 값이 가능합니다.

    EWX_LOGOFF현재 사용자를 로그오프한다.
    EWX_POWEROFF시스템을 종료하고 파워오프한다. 파워오프는 이를 지원하는 하드웨어에서만 가능하다.
    EWX_REBOOT시스템을 종료하고 시스템을 재시동한다.
    EWX_SHUTDOWN시스템을 종료한다.
    EWX_FORCEWM_QUERYSESSION이나 WM_ENDQUERYSESSION을 보내지 않고 실행중인 모든 프로세스를 종료한다. 위의 네 가지 플래그들과 함께 사용할 수 있다.

    36. 디폴트 웹 브라우저 알아내기

    디폴트로 지정된 웹 브라우저를 실행하는 방법을 알고 싶습니다.

    디폴트로 지정된 웹 브라우저는 레지스트리에 자신을 등록합니다. .htm (혹은 .html) 파일의 편집기로 링크도 되지만 http, ftp, gopher 등의 프로토콜 연결 프로그램으로 등록됩니다. 제 생각에 가장 좋은 것은 http 프로토콜의 연결 프로그램을 찾아보는 것으로 생각됩니다. 다음 레지스트리 항목에 보면 연결된 웹 브라우저의 절대 경로를 알 수 있습니다.

        HKEY_CLASSES_ROOThttpshellopencommand

    이 항목의 값을 읽는 방법은 3. 레지스트리 읽기/쓰기를 참고하고 프로그램의 실행에 관한 부분은 19. 특정 프로그램을 실행하고 종료를 기다리기를 참고하거나 ShellExecute API 혹은 WinExec API를 사용하면 됩니다. 이 기능을 수행하는 함수는 다음과 같습니다.

    void LaunchDefaultWebBrowser(HWND hWnd){    // HKEY_CLASSES_ROOThttpshellopencommand	DWORD dwType, cbData;	HKEY hSubKey; 	long lRet;	LPSTR pszString, pszSrcPath;	// 키를 오픈한다.	if ((lRet = RegOpenKeyEx(HKEY_CLASSES_ROOT, "http\shell\open\command",			0, KEY_READ | KEY_QUERY_VALUE , &hSubKey)) == ERROR_SUCCESS)	{		cbData = 255;	// 문자열 값을 읽어올 데이터의 크기를 준다.        pszString = (LPSTR)malloc(255);        pszSrcPath = pszString;		if ((lRet = RegQueryValueEx(hSubKey, "",			NULL, &dwType, (unsigned char *)pszString, &cbData)) == ERROR_SUCCESS)		{			// pszString에 디폴트 웹 브라우저의 경로가 들어온다.            // pszString에서 "를 제거한다.            RemoveChar(pszString, '"');            WinExec(pszString, SW_SHOWNORMAL);            		}        free(pszString);		RegCloseKey(hSubKey);	}}void RemoveChar(LPSTR lpSrc, char chRemove){	LPTSTR pstrSource = lpSrc;	LPTSTR pstrDest = lpSrc;	LPTSTR pstrEnd = lpSrc + strlen(lpSrc);	while (pstrSource < pstrEnd)	{		if (*pstrSource != chRemove)		{			*pstrDest = *pstrSource;			pstrDest = _tcsinc(pstrDest);		}		pstrSource = _tcsinc(pstrSource);	}	*pstrDest = '';}

    Copyright 1999 한기용Last updated: 07/29/2004 12:27:59 Designed By 한기남

    37. 윈도우의 최대/최소 크기 설정

    윈도우의 캡션을 없앴을 경우 윈도우를 최대화했을 때 아래의 Task Bar가 가려져 버리는 현상이 생기는데.. 캡션이 있으면 Task Bar 위로만 최대화되는데 말입니다. 어떻게 해결할 수 있는 방법이 없나 궁금하네요..

    말씀하신 문제를 해결하려면 WM_GETMINMAXINFO 메시지를 처리해야 합니다. 이는 윈도우의 최대 크기 등을 설정하기 위해 사용되는 메시지입니다. 다음과 같이 처리합니다.

    case WM_GETMINMAXINFO :{    LPMINMAXINFO lpmmi;    RECT rc;    SystemParametersInfo(SPI_GETWORKAREA, 0, &rc,0);    lpmmi = (LPMINMAXINFO)lParam;     lpmmi->ptMaxSize.x = rc.right;     lpmmi->ptMaxSize.y = rc.bottom;     lpmmi->ptMaxPosition.x = 0;     lpmmi->ptMaxPosition.y = 0;     lpmmi->ptMinTrackSize.x = GetSystemMetrics(SM_CXMINTRACK);     lpmmi->ptMinTrackSize.y = GetSystemMetrics(SM_CYMINTRACK);     lpmmi->ptMaxTrackSize.x = GetSystemMetrics(SM_CXMAXTRACK);     lpmmi->ptMaxTrackSize.y = GetSystemMetrics(SM_CYMAXTRACK);     break;}

    38. Thread에서 Automation 메소드 호출시 에러 발생

    Thread를 생성하고 Automation 메소드를 호출했는데 에러가 발생합니다.

    App 클래스의 InitInstance 함수에서 AfxOleInit를 호출하는 부분을 CoInitializeEx(NULL, COINIT_MULTITHREADED)를 호출하는 것으로 변경하기 바랍니다. 그리고 App 클래스에 ExitInstance 함수를 추가하고 거기서 CoUninitialize를 호출하도록 하면 됩니다. MFC의 AfxOleInit는 기본적으로 STA(Single Threading Apartment) 모델을 사용합니다. Thread에서 자신이 생성하지 않는 COM 객체를 접근할 때는 MTA(Multiple Threading Apartment) 모델을 사용해야 합니다.

    39. 최상위 윈도우의 종료 방법

    현재 최상위 윈도우를 찾아서 종료하는 코드를 만들고 싶습니다.

    일단 현재 사용자가 작업 중인 최상위 윈도우의 핸들은 GetForegroundWindow API로 얻어냅니다. 그런데 그 윈도우가 자식 윈도우일 수 있기 때문에 GetParent API를 반복적으로 사용해서 최상위 탑 레벨 윈도우의 핸들을 알아냅니다. 종료하는 방법은 먼저 DestroyWindow를 호출해서 시도해보고 실패하면 시스템 메뉴의 "닫기" 명령을 이용해 처리합니다. 사실 이 것도 실패할 수 있는데 무조건 종료시키고 싶다면 아래 코드에서 주석 처리해 놓은 GetWindowThreadProcessId/Terminate API 부분을 사용하면 됩니다.

        HWND hTopWnd = GetForegroundWindow();    if (hTopWnd == NULL)    {        return;    }    while(GetParent(hTopWnd))    {        hTopWnd = GetParent(hTopWnd);    }    if (DestroyWindow(hTopWnd) == FALSE)    {        SendMessage(hTopWnd, WM_SYSCOMMAND, SC_CLOSE, NULL);        //GetWindowThreadProcessId(hTopWnd, &dwProcessId);        //TerminateProcess(dwProcessId);    }            

    40. 인터넷 익스플로러의 위

  • Trackbacks 0 : Comments 0

    Write a comment


    [본문스크랩] API FAQ

    ⓘ Programming 2008.05.13 19:40
    [API 프로그래밍][MFC 프로그래밍][ATL 프로그래밍][VB 프로그래밍][HTML/ASP 프로그래밍]

    API 프로그래밍에 대한 Q&A입니다.

    1. 특정 디렉토리 뒤지기

    지정한 디렉토리에 있는 모든 파일을 찾아내는 코드를 만들려면 어떻게 해야 합니까 ?

    이 때 사용할 수 있는 API가 바로 FindFirstFile과 FindNextFile, FindClose라는 API들입니다. 사용 예제는 다음과 같습니다.

    	WIN32_FIND_DATA  findFileData;	HANDLE hFileHandle;	// szDir에 뒤지고자 하는 디렉토리의 경로명을 준다. 예를 들면 "C:\TEMP\*.*"        // 찾아진 파일의 속성은 findFileData의 dwFileAttributes를 살펴본다.	hFileHandle = FindFirstFile(m_szDir, &findFileData);  	if (hFileHandle != INVALID_HANDLE_VALUE)   // 파일을 찾은 경우 	{		// 찾은 파일의 이름은 cFileName 필드로 들어온다.		...		// 다음 파일을 찾는다.		while(FindNextFile(hFileHandle, &findFileData)) 		{			...		}		FindClose(hFileHandle);	}     

    2. API를 이용하는 유니코드와 ANSI 문자열간의 변환 방법

    API를 이용해서 유니코드와 ANSI 문자열간의 변환은 어떻게 수행합니까 ?

    Visual C++에서 유니코드 문자열은 BSTR이란 타입으로 표시됩니다. 또 유니코드와 ANSI 문자열간의 변환을 위해서 윈도우 시스템에는 MultiByteToWideChar와 WideCharToMultiByte라는 API가 존재합니다. MFC에서의 BSTR 타입 변환방법이나 ATL로 하는 BSTR 타입 변환도 참고하시기 바랍니다.

  • ANSI 문자열에서 유니코드로의 변환 방법
    	// sTime이란 ANSI 문자열을 bstr이란 이름의 유니코드(BSTR 타입) 변수로 변환	char sTime[] = "유니코드 변환 예제";	BSTR bstr;	// sTime을 유니코드로 변환하기에 앞서 먼저 그 길이를 알아야 한다.	int nLen = MultiByteToWideChar(CP_ACP, 0, sTime, lstrlen(sTime), NULL, NULL);	// 얻어낸 길이만큼 메모리를 할당한다.	bstr = SysAllocStringLen(NULL, nLen);	// 이제 변환을 수행한다.	MultiByteToWideChar(CP_ACP, 0, sTime, lstrlen(sTime), bstr, nLen);         // 필요없어지면 제거한다.         SysFreeString(bstr);
  • 유니코드에서 ANSI 문자열로의 변환 방법
    	// newVal이란 BSTR 타입에 있는 유니코드 문자열을 sTime이라는 ANSI 문자열로 변환	char *sTime;         int nLen = WideCharToMultiByte(CP_ACP, 0, newVal, -1, sTime, 0, NULL, NULL);         sTime = malloc(nLen+1);	WideCharToMultiByte(CP_ACP, 0, newVal, -1, sTime, 128, NULL, NULL);        // 필요없으면 메모리를 제거한다.        free(sTime);
  • 유니코드 문자열을 UTF-8으로 변환하기
         WideCharToMultiByte 함수를 호출할 때 첫 번째 인자로 CP_UTF8을 지정하면 된다. UTF-8은 유니코드의 인코딩 스킴 중의 하나로 쉽게 말하자면 문자열 스트림에서 0을 빼고 표현하는 방법이라고 볼 수 있다.

    3. 레지스트리 읽기/쓰기

    API를 이용해서 레지스트리에 한 항목을 생성하거나 기존 항목의 값을 읽어들이려면 어떻게 해야합니까 ?

    레지스트리 관련 API를 사용하려면 winreg.h라는 헤더 파일을 소스에 포함해야 합니다. 레지스트리에 키를 생성하는 방법과 레지스트리에 존재하는 키의 값을 읽는 방법을 차례로 살펴보겠습니다.

  • 레지스트리 키 생성 예제
    	// 예를 들어 HKEY_LOCAL_MACHINE밑의 SystemCurrentControlSetServicesGenPort라는 키를        // 생성하고 거기에 DWORD 타입의 값으로 Type을 만들고 문자열 타입의 값으로 Group        // 을 만들어 본다.	#include "winreg.h"	LONG error = 0;	HKEY hKey;	DWORD dwDisp, dwData;	char lpData[] = "Write this down";	// 먼저 만들려는 키가 이미 존재하는 것인지 살혀본다.	error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "System\CurrentControlSet\Services\GenPort",                         0, KEY_ALL_ACCESS, &hKey);	if (error != ERROR_SUCCESS) // 없다면 새로 생성한다.	{		// 키를 생성한다.		error = RegCreateKeyEx(HKEY_LOCAL_MACHINE,			"System\CurrentControlSet\Services\GenPort",	0, "REG_BINARY", 		        REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hKey, &dwDisp);                // 위의 키 밑에 Type이란 DWORD 타입의 값을 만들고 1로 초기화		dwData = 0x1;		error = RegSetValueEx( hKey, "Type", 0, REG_DWORD,&dwData,4);                 // 위의 키 밑에 Group이란 문자열 타입의 값을 만들고 lpData의 값으로 초기화		error = RegSetValueEx( hKey, "Group", 0, REG_SZ, lpData, strlen(lpData));                 // 키를 닫는다.		RegCloseKey(hKey);		}
  • 기존의 레지스트리 키에서 값 읽기
    	// HKEY_CURRENT_USERSoftwareNetscapeNetscape NavigatorMain 밑의 Install Directory        // 값의 문자열 값을 읽어들인다.	DWORD dwType, cbData;	HKEY hSubKey; 	long lRet;	char pszString[255];	// 키를 오픈한다.	if ((lRet = RegOpenKeyEx(HKEY_CURRENT_USER, 	                "Software\Netscape\Netscape Navigator\Main",			0, KEY_READ | KEY_QUERY_VALUE , &hSubKey)) == ERROR_SUCCESS)	{		cbData = 255;	// 문자열 값을 읽어올 데이터의 크기를 준다.		if ((lRet = RegQueryValueEx(hSubKey, "Install Directory",			NULL, &dwType, pszString, &cbData)) == ERROR_SUCCESS)		{			// 제대로 읽힌 경우		}		else		{			// 에러가 발생한 경우		}		RegCloseKey(hSubKey);	}
  • 레지스트리 키 삭제하기 - RegDeleteKey 함수를 사용한다.

    4. 윈도우 탐색기로부터의 Drag&Drop을 받으려면

    윈도우 탐색기로부터 제가 만든 윈도우로의 drag&drop이 가능하게 하려면 어떻게 해야 합니까 ?

    다음 순서를 따라서 프로그래밍하시면 됩니다.

    1. 프로그램의 초기화시에 DragAcceptFiles(hWnd, TRUE) 함수를 호출한다. 첫 번째 인자인 hWnd는 드롭의 타겟이 되는 윈도우의 핸들이다.
    2. 탐색기로부터 파일이 드롭되는 순간에 WM_DROPFILES 메시지가 날라온다. 이를 처리한다.
      	case WM_DROPFILES :	{		POINT pt;		// 어느 위치에 드롭되었는지 그 항목을 알아낸다.		if (DragQueryPoint((HDROP)wParam, &pt)) 		{			UINT i = 0;			// 모두 몇 개의 파일이 드롭되었는지 알아낸다.			// 만일 폴더가 드롭되었다면 폴더의 이름만 넘어온다.			UINT uCount = DragQueryFile((HDROP)wParam, 0xFFFFFFFF, NULL ,0);			for(i = 0;i < uCount;i++)			{				// 드롭된 파일의 이름을 알아온다.				DragQueryFile((HDROP)wParam, i, buffer ,255);				// 드롭된 파일 이름을 출력해본다.				MessageBox(hWnd, buffer, "File Name", MB_OK);			}		}		// drag and drop 작업을 끝낸다.		DragFinish((HDROP)wParam);		break;	}
    3. Drag&drop을 더 사용할 필요가 없어지면 DragAcceptFiles를 호출한다.
      	DragAcceptFiles(hWnd, FALSE);

    5. 시스템의 모든 드라이브 알아내기

    현재 시스템에 붙어있는 모든 드라이브(네트웍 드라이브 포함)에 대한 정보를 알아내고 싶습니다.

    1. GetLogicalDriveStrings로 시스템에 마운트되어있는 모든 드라이브 정보를 알아낸다. 두 번째 인자인 buffer로 드라이브 정보가 들어오는데 그 구조는 c:,d:과 같은 형식이며 리턴값으로 그 버퍼의 크기가 들어온다.
      	char buffer[256];	DWORD dwRet;	LPSTR token;	dwRet = GetLogicalDriveStrings(256, buffer);
    2. 루프를 돌면서 드라이브별 정보를 알아낸다. 이 때는 GetVolumeInformation 함수를 이용한다.
      	token = buffer; // token이 지금 처리해야할 드라이브를 가리킨다.	while (dwRet > 0)	{		DWORD FileSystemFlag;		char FileSystemName[64];						strcpy(DriveString, token);		// VolumeName으로 드라이브에 대한 설명 문자열이 넘어온다.		if (GetVolumeInformation(token, VolumeName, 255, NULL, NULL,                           &FileSystemFlag, FileSystemName, 63))		{	        // 원하는 작업을 수행한다.				}		dwRet -= (strlen(token)+1);		token = token + strlen(token)+1; // 다음 드라이브로 진행한다.	}

    6. 드라이브/디렉토리/파일의 이미지 리스트 인덱스 얻기

    특정 드라이브/디렉토리/파일이 시스템 이미지 리스트에서 어떤 인덱스를 갖는지 알고 싶습니다.

    각 파일이나 드라이브 및 디렉토리에 대한 정보는 Shell 라이브러리에서 제공해주는 SHGetFileInfo 함수를 이용하면 됩니다. 다음의 함수는 첫 번째 인자인 lpFileName으로 주어진 파일에 대한 설명을 두 번째 인자로 받아오고 세 번째 인자로는 시스템 이미지 리스트에서의 인덱스를 얻어옵니다.

    	void GetFileInfo(LPSTR lpFileName, LPSTR lpDesc, int *nIndex)	{	    DWORD dwAttr;	    SHFILEINFO sfi;	    int hIcon = SHGetFileInfo(lpFileName, dwAttr, &sfi, sizeof(SHFILEINFO), 				SHGFI_TYPENAME | SHGFI_SYSICONINDEX); 	    *nIndex = sfi.iIcon;	    strcpy(lpDesc, sfi.szTypeName);	}

    7. 리스트 컨트롤에 칼럼 헤더 넣기

    리포트뷰 형식의 리스트 컨트롤에 컬럼 헤더를 집어 넣으려면 어떻게 해야합니까 ?

    	// <문서명, 등록날짜, 상태> : 3개의 헤더를 만든다.	LV_COLUMN col;	col.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;	col.fmt = LVCFMT_LEFT;	col.cx = 100;	col.pszText = "문서명";	col.cchTextMax = strlen(col.pszText);	ListView_SetColumn(hListView, 0, &col); 	col.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;	col.fmt = LVCFMT_LEFT;	col.cx = 100;	col.pszText = "등록날짜";	col.cchTextMax = strlen(col.pszText);	ListView_InsertColumn(hListView, 0, &col); 	col.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;	col.fmt = LVCFMT_LEFT;	col.cx = 100;	col.pszText = "상태";	col.cchTextMax = strlen(col.pszText);	ListView_InsertColumn(hListView, 1, &col); 

    8. 리스트뷰에 항목 삽입하기

    리스트뷰에 한 항목을 추가하고 싶습니다.

    	// 이미지 리스트와 부가 정보를 사용하지 않는 리스트뷰 컨트롤이다.	int nIndex;	LV_ITEM item;	// - 첫번째 컬럼 -	item.mask = LVIF_TEXT; // 이미지 리스트를 사용하려면 LVIF_IMAGE를 추가하고                               // 부가정보를 지정해야할 일이 있다면 LVIF_PARAM을 추가한다.	item.pszText = lpDocName;	item.cchTextMax = strlen(lpDocName);	item.iItem = 1;	item.iSubItem = 0;	nIndex = ListView_InsertItem(hListView, &item);		// - 두번째 컬럼 -	item.mask = LVIF_TEXT;	item.iItem   = nIndex;	item.pszText = lpDate;	item.cchTextMax = strlen(lpDate);	item.iSubItem = 1;	ListView_SetItem(hListView, &item); 	// - 세번째 컬럼 -	item.mask = LVIF_TEXT;	item.iItem   = nIndex;	item.pszText = "";	item.cchTextMax = strlen(lpDocName);	item.iSubItem = 2;	ListView_SetItem(hListView, &item); 

    9. 리스트뷰 컨트롤에서의 정렬 구현

    리스트뷰 컨트롤에서 칼럼 헤더를 눌렀을 때 정렬이 되도록 하려면 어떻게 해야합니까 ?

    1. 일단 리스트뷰 컨트롤의 생성시 윈도우 스타일로 LVS_NOSORTHEADER를 주지 않는다.
    2. 리스트뷰로부터 칼럼 헤더가 눌렸을 때 오는 이벤트를 받아들인다.
      	NM_LISTVIEW *pnmtv = (NM_LISTVIEW FAR *)lParam;	switch(pnmtv->hdr.code)	{		case LVN_COLUMNCLICK :		{			// 어느 항목(pnmtv->iSubItem)이 눌렸는지부터 검사한다. 			// g_iSubItem은 어느 항목이 눌렸는지 기록해두는 인덱스이다.			g_iSubItem = pnmtv->iSubItem;			// 정렬함수를 호출한다. CompareFunc가 정렬함수이다.			ListView_SortItems(hListView, (PFNLVCOMPARE)CompareFunc, (LPARAM)this); 			break;		}
    3. 리스트뷰 항목을 정렬하는데 사용되는 CompareFunc라는 함수를 만든다. 이는 보통 C 함수로 만들거나 클래스를 사용할 경우에는 클래스 내의 static 함수로 만든다. CompareFunc의 코드는 다음과 같다.
      	int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)	{		LV_FINDINFO lvfi;		int iFirstItem, iSecondItem;		lvfi.flags = LVFI_PARAM;		lvfi.lParam = lParam1;		iFirstItem = ListView_FindItem(hListWnd, -1, &lvfi); 		lvfi.flags = LVFI_PARAM;		lvfi.lParam = lParam2;		iSecondItem = ListView_FindItem(hListWnd, -1, &lvfi); 		char lpFirst[100];		char lpSecond[100];		ListView_GetItemText(hListWnd, iFirstItem, g_iSubItem, lpFisrt, 100);		ListView_GetItemText(hListWnd, iSecondItem, g_iSubItem, lpSecond, 100);		// g_iSubItem 컬럼의 성격에 따라 비교한다. 문자열이라면 아래와 같이 한다.		int iRet = strcmpi(lpFirst, lpSecond);			return iRet;	}

    10. 버전 정보 알아내기 코드

    파일의 버전을 API를 통해 알아내려면 어떻게 해야합니까 ?

    Resource의 한 타입으로 VERSIONINFO라는 것이 존재합니다. 여기에 해당 파일의 버전 정보를 기록하도록 되어있습니다. 이 버전 정보를 읽어오는데 ver.dll이라는 DLL에 들어있는 API들을 사용합니다. 주의할 점은 버전 리소스는 언어별로 설정이 되기 때문에 영어로도 읽어보고 한국어 로도 읽어봐야 한다는 것입니다. 다음 예제를 참고하시기 바랍니다.

    	// szDrvName이란 파일에 들어있는 버전 정보를 읽어온다. 	#include 	DWORD      dwSize, handle;	LPSTR      lpstrVffInfo;	HANDLE     hMem;	LPSTR      lpVersion;	   // 이 변수로 파일의 버전 정보가 들어온다.	char       szDrvName[80];  // 버전 정보를 알아내고자 하는 파일 이름이 여기에 들어온다.	....	// 버전 정보 블록의 크기를 알아온다.	dwSize = GetFileVersionInfoSize(szDrvName , &handle);	if (dwSize) // 버전 정보 블록이 존재하면	{ 		// 버전 정보 블록을 포함할 메모리 블록을 할당 받아둔다.		hMem = GlobalAlloc(GMEM_MOVEABLE, dwSize);		lpstrVffInfo  = GlobalLock(hMem);		// 버전 정보 블록의 내용을 읽어온다.			GetFileVersionInfo(szDrvName, handle, dwSize, lpstrVffInfo);	        // 버전 정보 블록에서 버전 정보를 읽어온다.        	VerQueryValue((LPVOID)lpstrVffInfo,                         (LPSTR)"\StringFileInfo\041204B0\FileVersion",                        (void FAR* FAR*)&lpVersion, (UINT FAR *)&dwSize);		// lpVersion에 들어있는 버전 정보를 사용한다.		....		GlobalUnlock(hMem);		GlobalFree(hMem);    }
    위에서 041204B0가 바로 버전 리소스에 사용된 언어가 무엇인지를 나타냅니다. 이는 영어를 나타내며 한국어의 경우에는 040904B0를 사용하면 됩니다. 이 밖에도 version.lib를 링크의 라이브러리 항목에 추가해야 합니다.

    11. 시스템 사양 알아내기

    현재 시스템에 부착되어 있는 메인 메모리의 양과 CPU와 운영체제의 종류를 알고 싶습니다.

    먼저 시스템에 부착되어 있는 메인 메모리의 크기는 GlobalMemoryStatus라는 API를 이용하면 됩니다. 예제 코드는 다음과 같습니다.

    	//===========================================================	// lMemTotal      : 실제 메모리의 전체 크기 (KB 단위)	// lAvailMemTotal : 사용 가능한 실제 메모리의 크기 (KB 단위)	// lVirtualTotal  : 가상 메모리의 전체 크기  (KB 단위)	//===========================================================	void GetMemoryStatus(long *lMemTotal, long *lAvailMemTotal, long *lVirtualTotal)	{		double var;		MEMORYSTATUS memoryStatus;		memset (&memoryStatus, sizeof (MEMORYSTATUS), 0);		memoryStatus.dwLength = sizeof (MEMORYSTATUS);		GlobalMemoryStatus (&memoryStatus);		lMemTotal = memoryStatus.dwTotalPhys / 1024;		lAvailMemTotal = memoryStatus.dwAvailPhys / 1024;		lVirtualTotal = memoryStatus.dwTotalVirtual / 1024;	}
    다음으로 CPU의 종류를 알아내는 코드는 다음과 같습니다.
    	//===============================================================	// GetProcessorInfo : 프로세서에 대한 정보를 읽어온다.	// lpCPUSpeed      : CPU의 속도. 기록된 시스템에서만 읽어온다.	// lpProcessorType : 프로세서의 종류	// lpNumProcessors : 프로세서의 개수. NT의 경우에만 의미가 있다.	//===============================================================	void GetProcessorInfo(LPSTR lpCPUSpeed, LPSTR lpProcessorType, LPSTR lpNumProcessors)	{		SYSTEM_INFO sysInfo;		LONG result;		HKEY hKey;		DWORD data;		DWORD dataSize;		lpCPUSpeed[0] = 0;		// ---------------------------------------------		// 프로세서의 속도를 얻어낸다.		// ---------------------------------------------		result = ::RegOpenKeyEx (HKEY_LOCAL_MACHINE,			"Hardware\Description\System\CentralProcessor\0", 0, KEY_QUERY_VALUE, &hKey);		if (result == ERROR_SUCCESS) 		{			result = ::RegQueryValueEx (hKey, "~MHz", NULL, NULL,(LPBYTE)&data, &dataSize);			wsprintf(lpCPUSpeed, "%d MHz", data);		}		RegCloseKey (hKey);		// ------------------------------------------		// 하드웨어 정보를 얻어낸다.		// ------------------------------------------		GetSystemInfo (&sysInfo);		// 프로세서 타입부터 검사한다.		if (sysInfo.dwProcessorType  == PROCESSOR_INTEL_386)			strcpy(lpProcessorType,  "Intel 386");		else if (sysInfo.dwProcessorType  == PROCESSOR_INTEL_486)			strcpy(lpProcessorType,  "Intel 486");		else if (sysInfo.dwProcessorType  == PROCESSOR_INTEL_PENTIUM)		{			if (sysInfo.wProcessorLevel == 6) 				strcpy(lpProcessorType, "Intel Pentium (II/Pro)");			else				strcpy(lpProcessorType,  "Intel Pentium");		}		else 			strcpy(lpProcessorType, "알 수 없는 시스템");		// 프로세서의 갯수를 검사한다.		wsprintf(lpNumProcessors, "%d", sysInfo.dwNumberOfProcessors);	}
    다음으로 현재 사용 중인 운영체제의 종류를 알아내는 코드는 다음과 같습니다.
    	//===============================================================	// GetOSVersion : OS의 버전을 얻어온다.	// --------------------------------------------------------------	// lpstInfo	// lpstBuildNumber	// lpstServicePack	//===============================================================	void GetOSVersion (LPSTR lpstInfo, LPSTR lpstBuildNumber, LPSTR lpstServicePack)	{		int stat = 0;		TCHAR data [64];		DWORD dataSize;		DWORD win95Info;		OSVERSIONINFO versionInfo;		HKEY hKey;		LONG result;		lpstServicePack[0] = 0;		versionInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);		// 버전 정보를 얻어낸다.		if (!::GetVersionEx (&versionInfo)) 		{			strcpy(lpstInfo, "운영체제 정보를 얻을 수 없습니다.");			return;		}		// NT이면 서버인지 웍스테이션인지 검사한다. 이는 레지스트리를 보고 검사한다.		if (versionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) 		{			strcpy(lpstInfo, "Windows NT");			dataSize = sizeof (data);					result = ::RegOpenKeyEx (HKEY_LOCAL_MACHINE,				"System\CurrentControlSet\Control\ProductOptions", 0, KEY_QUERY_VALUE, &hKey);			if (result != ERROR_SUCCESS) 				return;			result = ::RegQueryValueEx (hKey, "ProductType", NULL, NULL, (LPBYTE) data, &dataSize);			RegCloseKey (hKey);			if (result != ERROR_SUCCESS) 				return;			if (lstrcmpi (data, "WinNT") == 0) 				strcpy(lpstInfo, "Windows NT Workstation");			else if (lstrcmpi (data, "ServerNT") == 0) 				strcpy(lpstInfo, "Windows NT Server");			else 				strcpy(lpstInfo, "Windows NT Server - Domain Controller");			// NT 버전을 알아낸다.			if (versionInfo.dwMajorVersion == 3 || versionInfo.dwMinorVersion == 51) 				strcat(lpstInfo, " 3.51");			else if (versionInfo.dwMajorVersion == 5) // 윈도우 2000의 경우				strcat(lpstInfo, " 5.0");			else 				strcat(lpstInfo, " 4.0");			// Build 번호를 알아낸다.			wsprintf(lpstBuildNumber, "%d", versionInfo.dwBuildNumber);		}		else if (versionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) 		{			strcpy(lpstInfo, "Windows 95");			if ((versionInfo.dwMajorVersion > 4) || ((versionInfo.dwMajorVersion == 4)				&& (versionInfo.dwMinorVersion > 0))) 			{				strcpy(lpstInfo, "Windows 98");			}			// 윈도우 95는 Build 번호가 하위 워드에 들어간다.			win95Info = (DWORD)(LOBYTE(LOWORD(versionInfo.dwBuildNumber)));			wsprintf(lpstBuildNumber, "%d", win95Info);		}		else 			wsprintf(lpstInfo, "Windows 3.1");		// 서비스 팩 정보를 얻어낸다.		strcpy(lpstServicePack, versionInfo.szCSDVersion);	}

    12. IE의 설치 여부와 버전 확인

    현재 시스템에 IE가 설치되었는지 여부와 그 버전을 알려면 어떻게 해야합니까 ?

    사실 동작시켜보지 않고서는 IE가 제대로 설치되어있는지 알아내는 방법은 없지만 레지스트리를 통해 IE가 설치되었는지 여부와 버전을 확인할 수 있습니다. 그 함수는 다음과 같습니다.

    	//===========================================================================	// GetIEVersion : IE의 버전을 얻는다. 정보를 찾을 수 없으면 FALSE를 리턴한다.	//===========================================================================	BOOL GetIEVersion(LPSTR lpVer)	{			LONG result;		HKEY hKey;		DWORD dwType; 		char data[65];		DWORD dataSize = 64;		// --------------------		// IE의 버전을 얻는다.		// --------------------		result = ::RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Software\Microsoft\Internet Explorer", 0, KEY_QUERY_VALUE, &hKey);		if (result == ERROR_SUCCESS) 		{			result = ::RegQueryValueEx (hKey, "Version", NULL, &dwType, (unsigned char *)data, &dataSize);			strcpy(lpVer, data);		}		else			return FALSE;		RegCloseKey (hKey);		return TRUE;	}

    13. IE의 보안 설정 보기

    IE에 보면 네 단계의 보안 영역이 있습니다. 그 영역별로 설정되어있는 보안 설정값을 읽으려면 어떻게 해야합니까 ?

    IE에는 다음과 같은 네 가지 보안 영역이 존재합니다.

    • 인터넷 영역
    • 로컬 인터넷 영역
    • 신뢰할 수 있는 사이트 영역
    • 제한된 사이트 영역
    IE는 보안 영역 설정과 관련하여 Internet Security Manager와 Internet Zone Manager라는 인터페이스가 존재합니다. 이를 이용해 보안 영역의 보안을 설정하고 특정 IP나 도메인 이름을 등록할 수 있습니다. 자세한 사항은 레퍼런스를 찾아보기 바랍니다.
     	#include "objbase.h"	#include "urlmon.h"	char szTemp1[256];	char szTemp2[256];	HRESULT hr;	IInternetSecurityManager *pSecurityMgr;	IInternetZoneManager *pZoneMgr;	DWORD dwEnum, dwZoneCount;	// --- 변수 선언부	DWORD dwZone;	ZONEATTRIBUTES zoneAttr;	int nLevel = 2;	// COM 라이브러리를 초기화한다.	CoInitialize(NULL);	dwEnum = 0;	pSecurityMgr = NULL;	pZoneMgr = NULL;	// Internet Security 인터페이스 초기화	hr = CoCreateInstance(CLSID_InternetSecurityManager, NULL, CLSCTX_ALL, //INPROC_SERVER,			IID_IInternetSecurityManager, (void**)&pSecurityMgr);	if (hr != S_OK)	{		return;	}	hr = CoCreateInstance(CLSID_InternetZoneManager, NULL, CLSCTX_ALL, //INPROC_SERVER,			IID_IInternetZoneManager, (void**)&pZoneMgr);		if (hr != S_OK)	{		return;	}	dwEnum = 0;	// 보안 영역 열거자(Zone Enumerator)를 초기화한다.	pZoneMgr->CreateZoneEnumerator(&dwEnum, &dwZoneCount, 0);	for(DWORD i = 1;i < dwZoneCount;i++)	{		pZoneMgr->GetZoneAt(dwEnum, i, &dwZone);		pZoneMgr->GetZoneAttributes(dwZone, &zoneAttr);		// zoneAttr.szDisplayName에 보안 영역의 이름이 들어오는데 유니코드이다. 이를 변환한다.		WideCharToMultiByte(CP_ACP, 0, zoneAttr.szDisplayName, -1, szTemp1, 255, NULL, NULL);			// zoneAttr.dwTemplateCurrentLevel에는 보안 영역의 보안값 설정이 들어온다.		wsprintf(szTemp2, "%x", zoneAttr.dwTemplateCurrentLevel);	}	// 보안 영역 열거자(Zone Enumerator)를 제거한다.	if (dwEnum != 0)		pZoneMgr->DestroyZoneEnumerator(dwEnum);	pSecurityMgr->Release();	pZoneMgr->Release();	// COM 라이브러리를 메모리에서 내린다.	CoUninitialize();}

    14. ActiveX 컨트롤의 등록 방법

    Regsvr32 같은 유틸리티를 이용하지 않고 프로그램 내에서 컨트롤을 레지스트리에 등록하려면 어떻게 해야합니까 ?

    모든 AcitveX 컨트롤은 자신을 레지스트리에 등록하기위한 목적으로 DllRegisterServer라는 함수를 갖고 있습니다. ActiveX 컨트롤을 메모리로 로드한 다음에 이 함수를 불러주면 원하는 일을 수행할 수 있습니다. 반대로 ActiveX 컨트롤을 레지스트리에서 제거하기 위한 용도로 DllUnRegisterServer라는 함 수도 존재합니다.

    	// ==============================================================	// RegisterOCX     지정된 ActiveX 컨트롤을 레지스트리에 등록한다.	// --------------------------------------------------------------	// LPSTR pszString 등록하고자 하는 ActiveX 컨트롤의 절대 경로명	// ==============================================================	BOOL WINAPI RegisterOCX(LPSTR pszString)	{		int iReturn = 0;		HRESULT (STDAPICALLTYPE * lpDllEntryPoint)();		HINSTANCE hLib;		// OLE 라이브러리를 초기화한다.						if (FAILED(OleInitialize(NULL)))		{			MessageBox(GetFocus(), "OLE 초기화 실패", "에러", MB_OK);			return FALSE;		}		// 지정된 activeX 컨트롤을 메모리로 로드한다.		hLib = LoadLibrary(pszString);		if (hLib <= NULL)		{			MessageBox(GetFocus(), "파일을 로드하는데 실패했습니다.", "에러", MB_OK);			OleUninitialize();			return FALSE;		}		// "DllRegisterServer" 함수의 위치를 찾는다.		lpDllEntryPoint = (long (__stdcall *)(void))GetProcAddress(hLib, "DllRegisterServer");			// 이 함수를 호출합니다.		if (lpDllEntryPoint)		{			if (FAILED((*lpDllEntryPoint)()))			{				DWORD dwRet;				char szTemp[128];				dwRet = GetLastError();				wsprintf(szTemp, "에러 번호 : %lx", dwRet);				MessageBox(GetFocus(), szTemp, "DllRegisterServer 에러", MB_OK);				FreeLibrary(hLib);				OleUninitialize();				return FALSE;			}		}		else		{			MessageBox(GetFocus(), "DllRegisterServer를 찾을 수 없습니다.", "에러", MB_OK);			FreeLibrary(hLib);			OleUninitialize();			return FALSE;		}		FreeLibrary(hLib);		OleUninitialize();		return TRUE;	}

    15. 데이터 파일의 실행

    탐색기에서 실행 파일이 아닌 데이터 파일을 더블클릭하면 그 데이터 파일과 연결된 실행 파일이 실행되면서 그 파일을 물고 올라갑니다. 이를 구현하는 방법을 알려주세요.

    ShellExecuteEx라는 API를 사용하면 됩니다. 다음 함수는 인자로 데이터 파일 혹은 실행 파일의 경로를 받아서 실행해줍니다. 데이터 파일의 경우에는 연결된 실행 파일을 찾아서 그걸 실행해줍니다.

    	BOOL Execute(LPSTR lpPath)	{		char FilePath[255];		SHELLEXECUTEINFO  ExecInfo;			// lpPath를 나누어 본다.		char drive[_MAX_DRIVE];		char dir[_MAX_DIR];		char fname[_MAX_FNAME];		char ext[_MAX_EXT];		_splitpath(lpPath, drive, dir, fname, ext);		// 디렉토리 경로를 얻는다.		strcpy(FilePath, drive);		strcat(FilePath, dir);		// 파일 이름을 얻는다.		strcat(fname, ".");		strcat(fname, ext);		SHELLEXECUTEINFO  ExecInfo;		ExecInfo.cbSize = sizeof(SHELLEXECUTEINFO); 		ExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS; 		ExecInfo.hwnd = hWnd; 		ExecInfo.lpVerb = "open"; 		ExecInfo.lpFile = fname; 		ExecInfo.lpParameters = NULL; 		ExecInfo.lpDirectory = FilePath; 		ExecInfo.nShow = SW_SHOW; 		ExecInfo.hInstApp = g_hInstance; // g_hInstance는 프로그램의 인스턴스 핸들		return ShellExecuteEx(&ExecInfo);	}

    16. 파일의 존재 여부 테스트

    어떤 파일이 실제로 존재하는 것인지 간단히 테스트해보는 방법은 무엇인가요 ?

    CreateFile API를 사용하면 됩니다. 파일을 열때 플래그 중의 하나로 OPEN_EXISTING이라는 것이 있는데 이를 사용하면 됩니다. 다음 코드를 예로 보시기 바랍니다.

    	hFile = CreateFile("C:\TEMP\test.txt", GENERIC_READ, 0, NULL,  			OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);	if (hFile != INVALID_HANDLE_VALUE)	{		// 파일이 존재하는 경우		CloseHandle(hFile);	}

    17. API를 이용한 파일 I/O

    API를 이용한 파일 입출력에 대한 예제 코드가 없습니까 ?

    프로그래밍을 하다보면 간혹 파일 I/O를 API를 이용해 수행해야 할 경우가 있습니다. 이 때 다음의 예제 코드를 복사해다가 사용하면 편리할 것입니다. MFC의 CFile을 이용한 파일 I/O에 대해 알고 싶으시면 요기를 클릭하세요.

  • 파일 쓰기의 경우
    	HANDLE fp;	DWORD NumberOfBytesWritten;	char lpBuffer[1024];	// FileName이 지정한 파일의 이름이 있으면 그걸 열고 없으면 그 이름으로 하나 생성한다.	if ((fp=CreateFile((LPCTSTR)FileName, GENERIC_WRITE | GENERIC_READ,	0, NULL, 						OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE)	{		// 파일 열기 에러 발생	}  	// 필요한 만큼 WriteFile의 호출을 반복한다. 파일 포인터의 이동시에는 SetFilePointer API를 이용한다.	WriteFile(fp, lpBuffer, 1024, &NumberOfBytesWritten, NULL);	if (NumberOfBytesWritten != 1024)	{		// 파일 쓰기 에러 발생 		CloseHandle(fp);			}	// 작업이 다 끝났으면 파일을 닫는다.	CloseHandle(fp);		
  • 파일 읽기의 경우
    	HANDLE fp;	DWORD NumberOfBytesRead;	char lpBuffer[1024];	if ((fp=CreateFile((LPCTSTR)FileName, GENERIC_READ,			FILE_SHARE_READ, NULL, OPEN_EXISTING, 		FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE)	{		// 파일 열기 에러 발생	}  	// 필요한 만큼 ReadFile의 호출을 반복한다.	ReadFile(fp, lpBuffer, 1024, &NumberOfBytesRead, NULL);	if (NumberOfBytesRead != 1024)	{		// 파일 읽기 에러 발생 		CloseHandle(fp);			}	// 작업이 다 끝났으면 파일을 닫는다.	CloseHandle(fp);		

    파일 포인터의 이동시에는 SetFilePointer라는 API를 사용하고 파일의 크기를 알고 싶을 때는 GetFileSize라는 API를 사용한다.

    18. GetParent API의 리턴값

    다이얼로그 박스에서 GetParent API를 호출했을 때 리턴되는 값이 이상합니다.

    GetParent API의 리턴값은 보통의 윈도우에서는 윈도우 생성시 지정한 부모/자식 윈도우 간의 관계에 따라 달라집니다. 하지만 다이얼로그 박스의 경우에는 다릅니다. 다이얼로그 박스는 GetParent를 호출하면 무조건 그 것이 속한 응용프로그램의 메인 윈도우 핸들이 리턴됩니다.

    19. 특정 프로그램을 실행하고 종료를 기다리기

    특정 프로그램을 실행한 다음에 그 프로그램이 종료될 때 다른 일을 하고 싶습니다. 어떻게 해야합니까 ?

    다음은 CreateProcess를 이용해서 특정 프로그램의 실행이 끝나기를 기다리는 코드입니다.

    	// buffer에 실행하고자하는 파일이름이 들어온다.	void DoCreate(HWND hWnd, LPSTR buffer)	{		STARTUPINFO            sui;		PROCESS_INFORMATION    pi;		DWORD                  ret;		memset(&sui, 0x00, sizeof(STARTUPINFO));		sui.cb = sizeof(STARTUPINFO);    		ret = CreateProcess(buffer, NULL, NULL, NULL, FALSE, 			0, NULL, NULL,&sui, &pi);		if (ret == TRUE) // 제대로 실행되었으면		{			hProcess = pi.hProcess;			// 실행이 끝나기를 대기한다.			WaitForSingleObject(hProcess, 0xffffffff);			CloseHandle(hProcess);		}	}

    20. 파일 열기 다이얼로그 띄우기

    API를 이용해 파일 오픈 다이얼로그를 띄우고 싶습니다.

    API를 이용해 파일 오픈 다이얼로그를 띄우는 방법은 다음과 같습니다.

    	#define MAXCHARS   255	OPENFILENAME       ofn;	char               buffer[MAXCHARS];	memset(&ofn, 0x00, sizeof(OPENFILENAME));	ofn.lStructSize = sizeof(OPENFILENAME);	ofn.hwndOwner = hWnd;	ofn.lpstrFilter = "모든 파일00*.*0000";	ofn.lpstrInitialDir = m_szTemp;	ofn.nFilterIndex = 1;	ofn.lpstrFile = buffer;	ofn.nMaxFile = MAXCHARS;	ofn.lpstrTitle = "파일 선택하기";	if (GetOpenFileName(&ofn))  // 사용자가 파일을 제대로 선택한 경우	{		// ....	}

    21. 긴 파일 이름과 짧은 파일 이름간의 변환 방법

    주어진 긴 파일 이름에 해당하는 짧은 파일 이름을 알려면 어떻게 해야하나요 ?

  • 긴 파일 이름에서 짧은 파일 이름으로의 변환 : GetShortPathName API 사용
  • 짧은 파일 이름에서 긴 파일 이름으로의 변환 : GetFullPathName API 사용

    22. 시스템 이미지 리스트 얻어내기

    탐색기 등에서 사용되는 시스템 이미지 리스트를 사용할 수 있는 방법이 있는지 알고 싶습니다.

    물론 있습니다. SHGetFileInfo라는 API를 이용하면 됩니다. 이를 이용하면 16X16이나 32X32 크기의 이미지 리스트를 얻어낼 수 있습니다.

    	SHFILEINFO sfi;	HIMAGELIST sysSmallList, sysLargeList;	sysSmallList = (HIMAGELIST)SHGetFileInfo(TEXT("C:\"), 0, &sfi,   sizeof(SHFILEINFO), SHGFI_SYSICONINDEX | SHGFI_SMALLICON);	sysLargeList = (HIMAGELIST)SHGetFileInfo(TEXT("C:\"), 0, &sfi,   sizeof(SHFILEINFO), SHGFI_SYSICONINDEX | SHGFI_ICON);

    23. 리스트뷰 컨트롤에서 스타일 동적 변경하기

    리스트뷰 컨트롤에서 리스트(LVS_ICON) 스타일을 사용 중인데 이를 실행 중에 리포트(LVS_REPORT) 스타일로 변경하고 싶습니다. 어떻게 해야할까요 ?

    윈도우의 스타일은 윈도우 엑스트라 바이트라는 영역에 저장됩니다. 이 곳의 데이터를 읽고 쓰는데 GetWindowLong, SetWindowLong 같은 API를 사용하는데 다음 코드를 예로 보시기 바랍니다.

  • 리스트 스타일에서 리포트 스타일로
    	LONG lStyle = GetWindowLong(hListWnd, GWL_STYLE);	SetWindowLong(hListWnd, GWL_STYLE, (lStyle & ~LVS_LIST) | LVS_REPORT);
  • 리포트 스타일에서 리스트 스타일로
    	LONG lStyle = GetWindowLong(hListWnd, GWL_STYLE);	SetWindowLong(hListWnd, GWL_STYLE, (lStyle & ~LVS_REPORT) | LVS_LIST);

    24. 윈도우와 다이얼로그에서 클래스 포인터의 사용

    제가 만든 C++ 클래스내에서 윈도우를 생성합니다. 생성한 윈도우의 윈도우 프로시저는 그 클래스의 정적 멤버 함수로 선언되어 있습니다. 정적 함수의 경우에는 데이터 멤버를 접근하지 못하기 때문에 접근하게 하려고 윈도우를 생성한 그 클래스의 객체에 대한 포인터를 전역 변수로 유지하여 사용하고 있습니다. 별로 깨끗한 방법도 아닌 것 같고 또 동시에 여러 개의 객체가 동작할 경우에는 에러가 날 수밖에 없는데 해결 방법이 없을까요 ?

    이는 다이얼로그의 경우에도 마찬가지입니다. 윈도우 생성시 사용하는 CreateWindow나 CreateWindowEx 같은 함수를 보면 마지막 인자로 윈도우 생성 데이터라는 것을 지정하게 되어있습니다. 다이얼로그 생성시에는 DialogBox라는 API말고 DialogBoxParam이라는 API가 있어서 마지막 인자로 초기화 데이터를 넘겨줄 수 있도록 되어있는데 이것과 윈도우 엑스트라 바이트를 같이 사용하면 정적함수로 선언된 윈도우 프로시저나 다이얼로그박스 프로시저내에서 객체에 대한 포인터를 사용할 수 있습니다. 예를 들어 살펴보겠습니다.

  • 윈도우의 경우

    다음과 같이 CExplorerBar라는 클래스내에서 윈도우를 하나 생성합니다. CreateWindowEx 함수나 CreateWindow 함수의 마지막 인자로 this 포인터를 지정합니다.

    	BOOL CExplorerBar::RegisterAndCreateWindow(void)	{		....		CreateWindowEx( 0,  EB_CLASS_NAME, NULL,                     WS_CHILD | WS_CLIPSIBLINGS | WS_BORDER,                     rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,                     m_hwndParent, NULL, g_hInst, (LPVOID)this);         }

    위에서 생성한 윈도우의 윈도우 프로시저는 WndProc이고 CExplorerBar 클래스의 정적 멤버 함수로 존재한다고 가정하겠습니다.

    	LRESULT CALLBACK CExplorerBar::WndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)	{		CExplorerBar  *pThis = (CExplorerBar*)GetWindowLong(hWnd, GWL_USERDATA);		switch (uMessage)		{			case WM_NCCREATE:			{				LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam;				pThis = (CExplorerBar*)(lpcs->lpCreateParams);				SetWindowLong(hWnd, GWL_USERDATA, (LONG)pThis);			}			break;			case WM_CREATE :				return pThis->OnCreate();

    WM_NCCREATE 메시지에서 lParam 인자로 넘어오는 CExplorerBar 객체에 대한 포인터를 받아서 윈도우 엑스트라 바이트로 저장하고 있습니다. 윈도우 엑스트라 바이트는 윈도우 마다 할당되는 고유의 영역으로 사용자 정의 영역으로 GWL_USERDATA가 정의되어 있습니다. 여기에다 CExplorerBar 객체에 대한 포인터를 저장해두고 윈도우 프로시저에 진입할 때마다 이 값을 pThis라는 변수에 대입해 놓고 사용합니다. 참고로 WM_NCCREATE는 WM_CREATE 메시지보다 먼저 발생하는 메시지입니다.

  • 다이얼로그의 경우

    예를 들어 CKTree라는 클래스내의 한 멤버 함수에서 다이얼로그 박스를 띄운다고 가정하겠습니다.

    	BOOL CKTree::SelectFolder(short sTypes, long dwFolderID, short  bCreationEnabled)	{		// ......		if (DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_FOLDER_SELECT), hWnd, (DLGPROC)SelectFolderDlg, (LPARAM)this))

    DialogBoxParam 함수는 DialogBox 함수보다 인자가 하나 더 있는데 그것이 바로 다이얼로그 프로시저의 WM_INITDIALOG 메시지의 lParam 인자로 넘어갑니다. 여기에 CKTree 객체에 대한 포인터를 넘깁니다. 그리고나서 다이얼로그 박스 프로시저의 WM_INITDIALOG 메시지에서 이를 받아서

    	LRESULT CALLBACK SelectFolderDlg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)	{		switch (message) 		{		        case WM_INITDIALOG:			{				// lParam으로 넘어온 값을 KPointer라는 윈도우 프로퍼티에 저장한다.				SetProp(hDlg, "KPointer", (HANDLE)lParam);				.......			case  WM_NOTIFY :			{				// CKTree 객체에 대한 포인터가 필요하면 KPointer 윈도우 프로퍼티 값을 읽어들인다.				CKTree *pKTree = (CKMartTree *)GetProp(hDlg, "KPointer");				if (pKTree->m_bWait)				{					.....

    여기서는 앞서 윈도우와는 달리 윈도우 프로퍼티라는 것을 이용해서 넘어온 포인터 정보를 저장하고 필요할 때 읽어옵니다. 여기서 앞서의 윈도우 엑스트라 바이트를 사용해도 무방합니다.

    25. 특정 프린터로 출력하기

    제 PC에는 두 대의 프린터가 붙어있습니다. 다이얼로그를 띄우지 않고 상황에 따라 다른 프린터로 출력하고 싶은데 동적으로 HDC를 생성하는 방법을 모르겠습니다.

    CreateDC를 이용하면 됩니다. 시스템 디렉토리의 WIN.INI를 보면 [Devices]라는 섹션이 있는데 이 아래로 이 시스템에 설치되어 있는 모든 프린터 드라이버의 목록이 나옵니다. 예를 들어 다음과 같이 나옵니다.

    	[Devices]	HUNFAX=HUNFAX,FaxModem	삼성 SLB-6216H PCL5=SSMPCL5,\영업팀볼륨프린터	......

    프린터별로 DeviceName=DriverName,OutputName와 같은 구조로 구성되어 있습니다. 이 값들을 CreateDC의 인자로 사용하면 됩니다. 예를 들어 위에서 두 번째 프린터의 DC를 생성하려면 다음과 같이 CreateDC를 호출합니다.

    	// hDC = CreateDC(DriverName, DeviceName, OutputName, NULL);	hDC = CreateDC ("SSMPCL5", "삼성 SLB-6216H PCL5", "\\영업팀\볼륨프린터", NULL) ;

    CreateDC의 마지막 인자로는 프린터의 설정값을 변경할 수 있습니다. 예를 들어 가로로 찍는다든지 2장을 찍는다든지 하는 설정을 변경하는데 사용됩니다. NULL을 주면 디폴트 값을 사용합니다. 다른 설정을 사용하고 싶다면 다음과 같이 합니다. CreateDC 호출 앞에서 DocumentProperties라는 함수를 호출하여 프린터의 기본 설정을 읽어온 다음에 이를 변경합니다. 다음 예는 출력 방향을 가로로 변경하는 예제입니다.

    	// 프린터의 디폴트 설정을 읽어온다.	LPDEVMODE lpoutDevMode;	HANDLE hPrinter;	HDC hPrnDC;	// 프린터의 핸들을 얻는다.	if (OpenPrinter( lpDeviceName, &hPrinter,  NULL))	{		// OpenPrinter로 얻은 프린터의 초기 설정을 DocumentProperties API로 얻어온다.		// 먼저 마지막 인자를 0으로 해서 DocumentProperties를 호출하여 필요한 버퍼의 크기를 알아옵니다.		long lSize = DocumentProperties(GetFocus(), hPrinter, lpPrinterName, NULL, NULL, 0);		lpoutDevMode = (LPDEVMODE)malloc(lSize);		long lRet = DocumentProperties(GetFocus(), hPrinter, lpPrinterName, lpoutDevMode, NULL, DM_OUT_BUFFER);		if (lRet == IDOK)		{			// 프린터의 인쇄 방향 설정을 변경한다.			// 여기서 원하는 변환을 수행한다.			lpoutDevMode->dmOrientation = DMORIENT_LANDSCAPE;		}		hPrnDC = CreateDC (lpDriverName, lpDeviceName, lpOutputName, lpoutDevMode) ;		free(lpoutDevMode);		return hPrnDC;	}

    26. 메뉴 관련 함수

    메뉴 항목을 하나 추가하려고 합니다. InsertMenuItem API를 사용하는데 윈도우 3.1에서와 사용법이 다른 것 같습니다.

    사용법이 달라졌습니다.

    	MENUITEMINFO mii;	memset(&mii, 0x00, sizeof(MENUITEMINFO));	mii.cbSize = sizeof(MENUITEMINFO);	mii.fMask = MIIM_TYPE;	mii.fType = MFT_SEPARATOR;	InsertMenuItem(hSubMenu, GetMenuItemCount(hSubMenu), TRUE,  &mii);								mii.cbSize = sizeof(MENUITEMINFO);	mii.fMask = MIIM_TYPE | MIIM_STATE | MIIM_ID;	mii.fType = MFT_STRING;	mii.fState = MFS_DEFAULT | MFS_UNHILITE;	mii.wID = ID_WORKPLACE_REMOVE;	mii.dwTypeData = "바구니에서 제거";	InsertMenuItem(hSubMenu, GetMenuItemCount(hSubMenu), TRUE,  &mii);

    27. 코드 실행 중에 다른 윈도우 메시지 처리하기

    하나의 함수 내에서 시간이 오래 걸리는 작업을 하고 있습니다. 이 때 작업 취소를 위한 별도의 다이얼로그를 하나 띄워 두었는데 이 쪽의 버튼이 눌리지 않습니다. 어떻게 해야할까요 ?

    시간이 오래 걸리는 작업을 별도의 스레드로 만들어 처리하던지 아니면 시간이 오래 걸리는 작업을 수행하는 함수 안에서 다음 코드를 가끔 호출해주면 됩니다. 만일 루프를 돌고 있다면 루프내에서 한번씩 호출해주면 됩니다.

    	MSG       msg;	while (PeekMessage(&msg, NULL, NULL, NULL, TRUE))	{		TranslateMessage(&msg);		DispatchMessage(&msg);	}

    VB에서라면 DoEvents라는 메소드를 호출해주면 됩니다.

    28. 메인 윈도우에서 캡션을 제거하고 싶습니다. 어떻게 해야 합니까 ?

    윈도우를 생성할 때 WS_CAPTION이란 스타일을 지정하지 않아도 항상 윈도우의 캡션이 보입니다. 이를 제거하려면 어떻게 해야 하나요 ?

    캡션을 제거하려는 윈도우의 WM_NCCREATE 메시지를 처리해야 합니다. 이 메시지는 WM_CREATE 메시지보다 앞서 발생하는 메시지입니다. NC는 Non-Client를 나타냅니다. GetWindowLong과 SetWindowLong API를 이용해서 WS_CAPTION 스타일을 제거합니다. 이 두 API는 앞서 리스트뷰 컨트롤에서 스타일 동적 변경하기에서 이미 사용해본 바 있습니다.

    		case WM_NCCREATE :		{			long lStyle;    			lStyle = GetWindowLong(hWnd, GWL_STYLE);			lStyle = (lStyle & (~WS_CAPTION)); 			SetWindowLong (hWnd, GWL_STYLE, lStyle);			return TRUE;		}

    29. 사각형 형태 이외의 모양을 갖는 윈도우를 띄우고 싶습니다.

    윈도우는 기본 모양이 사각형인데 다른 형태의 모양을 갖는 윈도우를 띄우려면 어떻게 해야합니까 ?

    원하는 모양을 Region이란 것으로 만들어야 합니다. 만든 다음에 이것을 원하는 시점에 SetWindowRgn라는 API를 이용해 윈도우에 설정해주면 됩니다. 예를 들어 타원 모양의 윈도우를 띄우고 싶다면 다음과 같이 해주면 됩니다.

    	HRGN g_hRgn;	g_hRgn = CreateEllipticRgn(0, 0, 700, 600);	SetWindowRgn(hWnd, g_hRgn, FALSE);		

    이렇게 했을 경우 윈도우의 위치 이동이 문제가 됩니다. 보통 캡션을 잡고 이동시켜야 하는데 캡션이 없으니까 문제가 됩니다. 이에 관한 것은 31. 윈도우의 이동 처리하기를 참고하기 바랍니다.

    30. 시스템에 설치되어 있는 모든 프린터 드라이버 알아내기

    현재 시스템에 설치되어 있는 모든 프린터 드라이버의 종류를 알아내고 싶습니다.

    EnumPrinters라는 API를 사용하면 됩니다. 다음 코드는 현재 시스템에 설치되어 있는 모든 프린터 드라이버(로컬과 네트웍 프린터 포함)의 이름을 메시지박스로 보여주는 예제입니다.

    	BOOL bSuccess;	DWORD cbRequired, cbBuffer, nEntries;	PRINTER_INFO_1 *lpBuffer = NULL;	// 버퍼의 크기를 알아낸다. cbRequired로 들어온다.	EnumPrinters(PRINTER_ENUM_CONNECTIONS | PRINTER_ENUM_LOCAL, NULL, 1, (unsigned char *)lpBuffer, 0, &cbRequired, &nEntries);	cbBuffer = cbRequired;	// 버퍼를 다시 버퍼를 잡는다.	lpBuffer = (PRINTER_INFO_1 *)malloc(cbBuffer);	// 프린터의 종류를 알아낸다.	bSuccess =	EnumPrinters(PRINTER_ENUM_CONNECTIONS | PRINTER_ENUM_LOCAL, NULL, 1, (unsigned char *)lpBuffer, cbRequired, &cbRequired, &nEntries);	if (bSuccess == FALSE)	{		free(lpBuffer);		// 다른 이유로 에러가 난 경우		return;	}	// 알아낸 프린터를 하나씩 enumerate한다.	for (int i = 0;i < nEntries; i++)	{		::MessageBox(NULL, lpBuffer[i].pName, "프린터 이름", MB_OK);  	}	free(lpBuffer);

    31. 윈도우의 이동 처리하기

    보통 윈도우는 캡션 영역을 잡고 위치 이동을 수행하게 되는데 윈도우의 특정 영역을 잡고 이동할 수 있게 하려면 어떻게 해야합니까 ?

    WM_NCHITTEST라는 메시지를 잘(?) 처리하면 어느 영역이든 윈도우 이동을 처리할 수 있습니다. 마우스로 윈도우 위를 이동하면 WM_NCHITTEST, WM_SETCURSOR, WM_MOUSEMOVE 같은 메시지들이 발생합니다. WM_NCHITTEST는 현재 마우스가 윈도우의 어느 영역위에 있는지 알아내기 위해 사용됩니다. 이 메시지의 처리부에서 HTCAPTION이란 값을 리턴해주면 윈도우 운영체제는 지금 마우스 포인터가 윈도우의 캡션 부분에 와있다고 생각해서 여기서 드래그 작업이 시작될 경우에 윈도우의 위치를 이동시켜 버립니다. 다음 코드는 WM_NCHITTEST 메시지를 처리하여 현재 마우스 좌표가 정해진 영역에 있으면 HTCAPTION을 돌려주는 예제입니다.

    	case WM_NCHITTEST:	{		// 현재 마우스 위치를 바탕으로 pt 변수를 채운다.		POINT pt(LOWORD(lParam), HIWORD(lParam));		// 마우스 좌표를 윈도우의 좌측 상단 기준의 좌표로 변경한다.		ScreenToClient(hWnd, &pt);		// 지정된 사각형 안에 포함되는 점인지 검사한다. 		// g_TitleRect는 RECT 타입의 변수로 지정된 사각형의 좌표가 들어있다.		if (PtInRect(&g_TitleRect, pt))			return HTCAPTION;					break;	}

    32. 바탕 화면 위의 모든 윈도우를 최소화하거나 모든 최소화 실행 취소

    바탕 화면 위의 모든 윈도우를 최소화하거나 모두 최소화 실행 취소를 프로그램으로 구현하는 방법을 알고 싶습니다.

    태스크바의 빈 공간을 오른쪽 마우스 버튼으로 클릭해보면 팝업 메뉴가 뜨는데 거기에 보면 "모든 창을 최소화(M)"와 "모두 최소화 실행 취소(U)" 명령이 존재하는데 그것을 대신 선택해주는 형식으로 프로그램을 작성해주면 됩니다.

    다음은 "모든 창을 최소화"해주는 루틴입니다. keybd_event API를 이용해서 사용자가 키입력한 것처럼 흉내내줍니다.

    	void IconizeAllWindow()	{ 		keybd_event(0x5b, 0, 0, 0);		keybd_event(77, 0, 0, 0);    // 'M' key		keybd_event(0x5b, 0, 2, 0);	}

    다음은 "모두 최소화 실행 취소" 루틴입니다.

    	void RestoreWindowState()	{		keybd_event(0x5b, 0, 0, 0);		keybd_event(84, 0, 0, 0);    // 'U' key		keybd_event(0x5b, 0, 2, 0);	}

    33. VxD 드라이버 호출하기

    Vxd 드라이버를 동적으로 로드해서 호출하고 싶습니다. 어떻게 해야합니까 ?

    먼저 해당하는 VxD 드라이버의 이름과 위치와 호출하려는 작업의 작업 코드명을 알아야 합니다. 드라이버의 로드는 CreateFile API를 이용합니다. VxD 드라이버의 호출은 DeviceIoControl API를 이용합니다. 자세한 설명은 DeviceIoControl API의 레퍼런스를 참고하기 바랍니다.

    	DWORD byteReturned;	// 먼저 VxD 드라이버를 오픈한다.	hDevice = CreateFile("\\.\NMOUSE.VXD", 0, 0, 0, CREATE_NEW, FILE_FLAG_DELETE_ON_CLOSE, 0);	if (DeviceIoControl(hDevice, W32_SETHWND, &hWnd, 4, NULL, 0, &byteReturned, NULL))	{		// Success !!!	}

    Vxd 드라이버는 kernel 모드(이를 윈도우에서는 Ring 0라고 부릅니다)에서 동작하기 때문에 모든 하드웨어와 메모리를 바로 접근할 수 있습니다. VxD 드라이버를 작성하려면 DDK를 이용하거나 Numega의 DriverStudio나 KRFTech사의 WinDriver를 이용해야 합니다.

    34. Thread 실행시 에러

    CreateThread를 이용해 스레드를 만들어 생성하고 있습니다. 루틴에 이상은 없는 것 같은데 스레드가 많이 생성되어 시간이 좀 지나면 에러가 발생합니다. 이유가 무엇일까요 ?

    정말로 스레드 코드에 별 이상이 없다면 CreateThread API 대신에 beginthread나 beginthreadex를 사용해보기 바랍니다. 자세한 사항은 마이크로소프트의 Knowledge base를 참고하시기 바랍니다.

    35. 윈도우 운영체제 종료하기

    프로그램에서 특정 상황이 되면 윈도우 운영체제를 종료하고 싶습니다.

    ExitWindowsEx API를 사용하면 됩니다. 이 함수의 원형은 다음과 같습니다.

    	BOOL ExitWindowsEx(UINT uFlags, DWORD dwReserved);

    uFlags로 종료방법을 지정할 수 있습니다. 다음과 같은 값이 가능합니다.

    EWX_LOGOFF현재 사용자를 로그오프한다.
    EWX_POWEROFF시스템을 종료하고 파워오프한다. 파워오프는 이를 지원하는 하드웨어에서만 가능하다.
    EWX_REBOOT시스템을 종료하고 시스템을 재시동한다.
    EWX_SHUTDOWN시스템을 종료한다.
    EWX_FORCEWM_QUERYSESSION이나 WM_ENDQUERYSESSION을 보내지 않고 실행중인 모든 프로세스를 종료한다. 위의 네 가지 플래그들과 함께 사용할 수 있다.

    36. 디폴트 웹 브라우저 알아내기

    디폴트로 지정된 웹 브라우저를 실행하는 방법을 알고 싶습니다.

    디폴트로 지정된 웹 브라우저는 레지스트리에 자신을 등록합니다. .htm (혹은 .html) 파일의 편집기로 링크도 되지만 http, ftp, gopher 등의 프로토콜 연결 프로그램으로 등록됩니다. 제 생각에 가장 좋은 것은 http 프로토콜의 연결 프로그램을 찾아보는 것으로 생각됩니다. 다음 레지스트리 항목에 보면 연결된 웹 브라우저의 절대 경로를 알 수 있습니다.

        HKEY_CLASSES_ROOThttpshellopencommand

    이 항목의 값을 읽는 방법은 3. 레지스트리 읽기/쓰기를 참고하고 프로그램의 실행에 관한 부분은 19. 특정 프로그램을 실행하고 종료를 기다리기를 참고하거나 ShellExecute API 혹은 WinExec API를 사용하면 됩니다. 이 기능을 수행하는 함수는 다음과 같습니다.

    void LaunchDefaultWebBrowser(HWND hWnd){    // HKEY_CLASSES_ROOThttpshellopencommand	DWORD dwType, cbData;	HKEY hSubKey; 	long lRet;	LPSTR pszString, pszSrcPath;	// 키를 오픈한다.	if ((lRet = RegOpenKeyEx(HKEY_CLASSES_ROOT, "http\shell\open\command",			0, KEY_READ | KEY_QUERY_VALUE , &hSubKey)) == ERROR_SUCCESS)	{		cbData = 255;	// 문자열 값을 읽어올 데이터의 크기를 준다.        pszString = (LPSTR)malloc(255);        pszSrcPath = pszString;		if ((lRet = RegQueryValueEx(hSubKey, "",			NULL, &dwType, (unsigned char *)pszString, &cbData)) == ERROR_SUCCESS)		{			// pszString에 디폴트 웹 브라우저의 경로가 들어온다.            // pszString에서 "를 제거한다.            RemoveChar(pszString, '"');            WinExec(pszString, SW_SHOWNORMAL);            		}        free(pszString);		RegCloseKey(hSubKey);	}}void RemoveChar(LPSTR lpSrc, char chRemove){	LPTSTR pstrSource = lpSrc;	LPTSTR pstrDest = lpSrc;	LPTSTR pstrEnd = lpSrc + strlen(lpSrc);	while (pstrSource < pstrEnd)	{		if (*pstrSource != chRemove)		{			*pstrDest = *pstrSource;			pstrDest = _tcsinc(pstrDest);		}		pstrSource = _tcsinc(pstrSource);	}	*pstrDest = '';}

    Copyright 1999 한기용Last updated: 07/29/2004 12:27:59 Designed By 한기남

    37. 윈도우의 최대/최소 크기 설정

    윈도우의 캡션을 없앴을 경우 윈도우를 최대화했을 때 아래의 Task Bar가 가려져 버리는 현상이 생기는데.. 캡션이 있으면 Task Bar 위로만 최대화되는데 말입니다. 어떻게 해결할 수 있는 방법이 없나 궁금하네요..

    말씀하신 문제를 해결하려면 WM_GETMINMAXINFO 메시지를 처리해야 합니다. 이는 윈도우의 최대 크기 등을 설정하기 위해 사용되는 메시지입니다. 다음과 같이 처리합니다.

    case WM_GETMINMAXINFO :{    LPMINMAXINFO lpmmi;    RECT rc;    SystemParametersInfo(SPI_GETWORKAREA, 0, &rc,0);    lpmmi = (LPMINMAXINFO)lParam;     lpmmi->ptMaxSize.x = rc.right;     lpmmi->ptMaxSize.y = rc.bottom;     lpmmi->ptMaxPosition.x = 0;     lpmmi->ptMaxPosition.y = 0;     lpmmi->ptMinTrackSize.x = GetSystemMetrics(SM_CXMINTRACK);     lpmmi->ptMinTrackSize.y = GetSystemMetrics(SM_CYMINTRACK);     lpmmi->ptMaxTrackSize.x = GetSystemMetrics(SM_CXMAXTRACK);     lpmmi->ptMaxTrackSize.y = GetSystemMetrics(SM_CYMAXTRACK);     break;}

    38. Thread에서 Automation 메소드 호출시 에러 발생

    Thread를 생성하고 Automation 메소드를 호출했는데 에러가 발생합니다.

    App 클래스의 InitInstance 함수에서 AfxOleInit를 호출하는 부분을 CoInitializeEx(NULL, COINIT_MULTITHREADED)를 호출하는 것으로 변경하기 바랍니다. 그리고 App 클래스에 ExitInstance 함수를 추가하고 거기서 CoUninitialize를 호출하도록 하면 됩니다. MFC의 AfxOleInit는 기본적으로 STA(Single Threading Apartment) 모델을 사용합니다. Thread에서 자신이 생성하지 않는 COM 객체를 접근할 때는 MTA(Multiple Threading Apartment) 모델을 사용해야 합니다.

    39. 최상위 윈도우의 종료 방법

    현재 최상위 윈도우를 찾아서 종료하는 코드를 만들고 싶습니다.

    일단 현재 사용자가 작업 중인 최상위 윈도우의 핸들은 GetForegroundWindow API로 얻어냅니다. 그런데 그 윈도우가 자식 윈도우일 수 있기 때문에 GetParent API를 반복적으로 사용해서 최상위 탑 레벨 윈도우의 핸들을 알아냅니다. 종료하는 방법은 먼저 DestroyWindow를 호출해서 시도해보고 실패하면 시스템 메뉴의 "닫기" 명령을 이용해 처리합니다. 사실 이 것도 실패할 수 있는데 무조건 종료시키고 싶다면 아래 코드에서 주석 처리해 놓은 GetWindowThreadProcessId/Terminate API 부분을 사용하면 됩니다.

        HWND hTopWnd = GetForegroundWindow();    if (hTopWnd == NULL)    {        return;    }    while(GetParent(hTopWnd))    {        hTopWnd = GetParent(hTopWnd);    }    if (DestroyWindow(hTopWnd) == FALSE)    {        SendMessage(hTopWnd, WM_SYSCOMMAND, SC_CLOSE, NULL);        //GetWindowThreadProcessId(hTopWnd, &dwProcessId);        //TerminateProcess(dwProcessId);    }            

    40. 인터넷 익스플로러의 위

  • Trackbacks 0 : Comments 0

    Write a comment


    [본문스크랩] [자바스크립트] Base64 인코딩/디코딩

    ⓘ Programming 2008.05.13 14:47




    Base 64 인코딩 자바 스크립트








    Trackbacks 0 : Comments 0

    Write a comment


    [perl] 프로세스 상태관리 프로그램

    ⓘ Programming 2008.01.10 19:07

    프로세스를 관리합니다.

    실행되어 있지 않는 프로세스를 재실행하는 프로그램입니다.

    윤드림님이 펄로 작성하신 프로그램입니다.

    바로가기 : http://teamblog.joinc.co.kr/yundream/353

    Trackbacks 0 : Comments 0

    Write a comment


    [java] db 연결테스트

    ⓘ Programming 2007.12.27 14:09

    출처 : http://blog.naver.com/jeha5/100045271796

    <%@page contentType="text/html; charset=euc-kr"%>
    <%@page import="java.sql.*"%>



    연동 테스트



    JDBC/JSP Connection TEST


    <%
    String url="jdbc:oracle:thin:@xxx.xxx.xxx.xxx:1521:sid_name";

    String id="userid";
    String pass="userpwd";

    try {
    Class.forName("oracle.jdbc.driver.OracleDriver");
    } catch (Exception e ) {
    out.println(e);
    return;
    }

    Connection conn=DriverManager.getConnection(url, id, pass);
    Statement stmt=conn.createStatement();


    String sql="SELECT 'test' as a FROM dual";
    ResultSet rs=stmt.executeQuery(sql);
    rs.next();
    %><%=rs.getString("a")%>

    Trackbacks 0 : Comments 0

    Write a comment


    On lisp 편하게 보기

    ⓘ Programming 2007.12.26 17:33

    한 일본인 분이 On Lisp 을 편하게 HTML 로 볼 수 있도록 작업해두셨더군요.

    www.bookshelf.jp/texi/onlisp/onlisp.html

    참고로 On Lisp 의 일본어 번역본은
    http://j2k.naver.com/j2k_frame.php/korean/user.ecc.u-tokyo.ac.jp/~tt076524/onlispjhtml/
    에서 보실 수 있습니다.

    헐랭이님이 알려주셧어요^^

    Trackbacks 0 : Comments 0

    Write a comment


    lisp가 대체 무엇인고~

    ⓘ Programming 2007.12.26 17:30

    LISP - 리스프 란 LISt
    Processing의 약어로서, 1960년 MIT의 매카시(J.
    Macarthy)등에 의해서 만들어진 언어의 이름을 가리킵니다. 람다(lambda)대수에 이론적 근거를 둔
    적용형(applicative)언어로 프로그램과 데이터가 모두 S-식(S-expression)이라는 일반화된 리스트(generalized list) 형태로 표현되므로 프로그램이 데이터처럼 취급될 수 있다는 특징을 가지고 있으며, 프로그램이 함수로 선언이 되며 일반적으로 함수의 재귀호출(recursive call)로 필요한 작업을 수행할 수 있다는 것이 특징입니다.

    주로 인공지능과 그 응용분야에서 많이 사용이 되고 있으며 식의 전개, 인수분해, 미적분, 정리 증명, 로봇문제, 자연어 처리
    등 다양한 분야에 응용되고 있습니다. 현재 사용되고 있는 리스프에는 많은 변종들이 있는데 리스프의 원래 정의를 충실히 따라 순수하게 함수의
    적용에 의해서만 작업을 하는 순리스프(pure LISP)는 실제로는 거의 사용되지 않고 있으며 커먼 리스프(Common LISP), 프란츠
    리스프(Frantz LISP), LISP 1.5 등 원래의 리스프에 여러 가지 기능을 첨가한 변종들이
    많이 사용이 되고 있는 실정입니다.

    라고 네이버 지식인에서 그러네요.

    헐랭이님이 lips에 대한 좋은 정보를 주는데 그것을 받아 먹지 못하는 저...

    lisp가 먼지 몰라 검색해?f네요

    성능이 좋은건지는 몰라도 인공지능, 로봇문제, 등수준 있는 문제를 다루네요.

    Trackbacks 0 : Comments 0

    Write a comment


    [perl] 고급스러운 펄 프로그래밍 기법

    ⓘ Programming 2007.12.08 21:47

    헐랭이님이 알려주신 사이트인데요..

    펄 잘하는건 아니지만 관심이 있어서 링크 걸었습니다.

    학교서 학사프로그램 짜라고 해서 한학기간 열심히 했던 이후론...손댄적이 없네요...

    그래도~!! 나중에 혹시나 해서...ㅎㅎ

    http://www252.pair.com/comdog/mastering_perl/Chapters/09.dynamic_subroutines.html

    헐랭이님이 추천한 책

    http://www252.pair.com/comdog/mastering_perl/Chapters/

    Trackbacks 0 : Comments 0

    Write a comment


    [링크스크랩] tail log 브라우저로 보기

    ⓘ Programming 2007.12.07 21:51
    Trackbacks 0 : Comments 0

    Write a comment


    [링크스크랩] tail log 브라우저로 보기

    ⓘ Programming 2007.12.07 21:51
    Trackbacks 0 : Comments 0

    Write a comment


    perl을 이용한 하위 파일에 대한 일괄작업

    ⓘ Programming 2007.12.07 11:13

    출처 : http://teamblog.joinc.co.kr/yundream/344

    시스템 관리를 하다보면, 하위 디렉토리의 특정 종류의 파일에 대해서 일괄작업을 해야 하는 경우가 있다. 이를테면 크기가 얼마 이상인 파일을 지워야 한다거나, 파일의 날짜를 변경시켜야 한다거나 하는 등등의 일이다. 노가다를 뛰는 방법도 있겠지만 자고로 시스템 관리자의 미덕은 게으름 아니던가. 스크립트 하나 잘 만들어 두면, 한시간 해야 할일을 1분에 끝낼 수 있다. 다음은 모든 디렉토리의 권한을 변경하기 위한 스크립트로 find(1)를 어떻게 사용하느냐에 따라서 다양한 응용을 할 수 있을 것이다.

    find(1)를 이용해서 파일의 리스트를 얻어온다. C 언어라면 stat() 함수를 이용해야지만 파일의 종류를 알아낼 수 있겠지만 perl 은 -x를 이용해서 간단하게 파일을 테스트 할 수 있다. 다음은 파일테스트에 사용할 수 있는 연산자들이다.

    • -r
      effective uid/gid 에 대해서 읽을 수 있는 파일
    • -w
      effective uid/gid 에 대해서 쓸 수 있는 파일
    • -x
      effective uid/gid 에 대해서 실행가능한 파일.
    • -o
      effective uid 에 대해서 파일을 소유

    • -R
      실제 uid/gid에 대해서 읽을 권한이 있는 파일
    • -W
      실제 uid/gid에 대해서 쓰기 권한이 있는 파일
    • -X
      실제 uid/gid에 대해서 실행권한이 있는 파일
    • -O
      실제 uid에 대해서 소유하고 있는 파일

    • -e
      파일이 존재하는가
    • -z
      파일의 크기가 0인가
    • -s
      파일의 크기가 0이 아닌가 (크기를 리턴한다.)

    • -f
      일반 파일인지
    • -d
      디렉토리 인지
    • -l
      심볼릭 링크인지
    • -p
      named pipe 인지
    • -S
      socket(2) 파일인지
    • -b
      블럭 파일인지
    • -c
      문자장치 파일인지

    • -T
      ASCII 문자 파일인지
    • -B
      이진(binary) 파일인지

    perl 대신 shell 스크립트를 이용할 수 도 있을 것이다.
    #!/usr/bin/perl 

    use File::stat;

    open(FD, "find ./|") || die "execute error";

    while($line = )
    {
    $file = trim($line);
    if (-d $file)
    {
    chmod 0755, $file;
    }
    }

    sub trim($)
    {
    my $string = shift;
    $string =~ s/^s+//;
    $string =~ s/s+$//;
    return $string;
    }

    댓글을 달아 주세요

    1. aero 2007/12/06 19:44 댓글주소 수정/삭제 댓글쓰기

      Perl이야기가 나와서 한 번 끼어들겠습니다. :)

      일단 위 코드에서 File::stat 모듈을 왜 load하신지 모르겠지만 chmod 함수때문이었다면 chmod는 perl의 기본 함수이기 때문에 필요가 없습니다.

      그리고 perl이 기본혹은 모듈로 지원하는 기능은 어떤 unix명령을 실행해서 결과를 넘겨 받는식으로 하는건 별로 추천하지 않습니다. 운영체제간에 호환성 문제도 생기고요.

      제가 위 코드를 다시한번 짜봤습니다.

      #!/usr/bin/env perl
      use strict;
      use warnings;
      use File::Find;

      find( { wanted=>&change, no_chdir=>1 }, './');

      sub change {
      if( -d $_ ) {
      chmod 0755,$File::Find::name;
      }
      }

      File::Find 모듈과 콜백함수를 사용했습니다.

    2. aero 2007/12/06 20:05 댓글주소 수정/삭제 댓글쓰기

      적어놓고 다시 생각해보니 이렇게 더 줄일 수 있겠네요.

      #!/usr/bin/env perl
      use strict;
      use warnings;
      use File::Find;

      find( { wanted=>sub{ chmod 0755,$_ if -d $_; }, no_chdir=>1 }, './');

    3. guest 2007/12/06 21:53 댓글주소 수정/삭제 댓글쓰기

      find . -type d | xargs chmod 0755

    4. aero 2007/12/06 22:13 댓글주소 수정/삭제 댓글쓰기

      guest님이 적어주신 예는 만약 "a b" 처럼 공백이 들어간 디렉토리 이름이 있으면 xargs가 제대로 처리하지 못합니다.
      따라서 find 명령을 통해 퍼미션을 변경하려면
      find . -type d -exec chmod 0755 {} ;
      처럼 해줘야 합니다.

    Trackbacks 0 : Comments 0

    Write a comment


    할당과 InterlockedExchange 중 누가 더 빠를까?

    ⓘ Programming 2007.12.06 13:04

    출처 : http://somma.egloos.com/3515751

    예전에 nop 와 pause 중에 누가 더 많은 clock 을 소비할까.. 궁금해서 약간의 삽질을 한적이 있습니다.
    전 가끔 이런 요상한 짓을 즐겨한답니다. ~@,.@~
    (제 블로그에 계속 오셨던 분이라면 아실 듯 ==> nop vs pause )

    오늘은 갑자기할당 (e.g. a = b) 을 사용하는 것과 InterlockedXXX 함수를 이용하는 것 중에 누가 더 빠를까 하는 궁금증이 생기더군요. >.<
    Interlockedxxx 함수는 lock cmpxchg 인스트럭션을 이용하더군요.
    당연히 LOCK# 시그널을 발생시키고, 어쩌구 저쩌구 하는 일을 하니까InterlockedXXX 함수가 느릴거라 생각했습니다.

    과연... 그럴까요?

    아래는 테스트에 이용한 코드입니다.

    눈여겨 봐야할 코드가 있는데 바로~ ReadTSC() 함수입니다.
    저도 오늘에야 확실하게알게된 내용입니다만, rdtsc 인스터럭션은 serailization 이 보장되지 않는 인스트럭션입니다.
    즉 out-of-order execution 가능성을 가지고 있다는 소립니다.
    아하 ~~ 뭔소린지 모르겠군요. (-_-)

    예를 들면아래와 같은 코드가 있다고 치죠.


    serialization_지원_안하는_명령어_1
    serialization_지원_안하는_명령어_1
    serialization_지원_안하는_명령어_1



    당근 1, 2, 3 명령어 순으로 실행되길 바라지만 실제로는 명령어를 순서대로 처리 하지 않을 수도 있단 겁니다.
    파이프라인을 효율적으로 쓰기위해 CPU 프론트 엔드에서 당연히 그렇게 처리하리라는 예상이 되긴 합니다.
    하여간 이런걸 out-of-order execution 이라고 합니다.
    물론 serialization 이 보장되는 명령어가 있습니다. privilege level 에 관계없이 사용할 수 있는것이 바로 CPUID 명령입니다.


    serialization_지원_안하는_명령어_1
    CPUID
    serialization_지원_안하는_명령어_1
    CPUID
    serialization_지원_안하는_명령어_1
    CPUID



    이렇게 코드를 작성하면 serialization 이 된다는 소리죠. 간단하죠?
    이런 이유로 ReadTSC() 함수에는 rdtsc 만 딸랑 있는 것이 아니라 rdtsc 를 호출하기 전에 cpuid 를 호출해 주는 겁니다.
    실제로 cpuid 명령 없이 rdtsc 만 호출하면 매번 값이 묘하게 나오는걸 확인할 수 있습니다.




    #define ReadTSC( x )
    __asm cpuid
    __asm rdtsc
    __asm mov dword ptr x,eax
    __asm mov dword ptr x+4,edx

    int _tmain(int argc, _TCHAR* argv[])
    {
    __int64 start = 0, end = 0, total = 0, evg = 0;
    LONG target = 0, value = 1;

    for (int x = 0; x < 32; x++)
    {
    // interlocked operation
    //
    for (int i = 0; i < 12800; i++)
    {
    ReadTSC(start);
    InterlockedExchange(&target, value);
    ReadTSC(end);
    evg += end - start;
    }
    _ftprintf(stdout, _T("everage of interlocked operation: %04.2f n"), (double)(evg / 12800));

    // assign
    //
    evg = 0;
    for (int i = 0; i < 12800; i++)
    {
    ReadTSC(start);

    // optimization 땜시롱.. 어셈으로
    //
    //target = value;
    __asm
    {
    mov eax, dword ptr [value]
    mov dword ptr [target], eax
    }
    ReadTSC(end);
    evg += end - start;
    }
    _ftprintf(stdout, _T("everage of assign : %04.2f nn"), (double)(evg / 12800));
    }


    return 0;
    }




    과연 .. 결과는 어떨까요?

    everage of interlocked operation: 697.00
    everage of assign : 537.00

    everage of interlocked operation: 1230.00
    everage of assign : 553.00

    everage of interlocked operation: 1227.00
    everage of assign : 549.00

    everage of interlocked operation: 1205.00
    everage of assign : 793.00

    everage of interlocked operation: 1479.00
    everage of assign : 544.00

    everage of interlocked operation: 1244.00
    everage of assign : 581.00

    everage of interlocked operation: 1233.00
    everage of assign : 538.00

    everage of interlocked operation: 1214.00
    everage of assign : 536.00




    역시 그냥 할당하는게 빠르군요. ^.^


    참고 자료
    - intel white paper : Measuring Instruction Latency and Throughput
    - intel manual volume 3A, 7-4 SERIALIZING INSTRUCTIONS
    Trackbacks 0 : Comments 0

    Write a comment


    [vim] VIM & bash script 예제 (C source to html view)

    ⓘ Programming 2007.12.02 14:30

    출처 : http://minzkn.wowdns.com:2744/tattertools/211

    VIM으로 C 소스를 html 로 보기좋게 바꿔주는 script 예제

    코드:
    #!/bin/bash

    # Script code by JaeHyuk Cho
    # See also moniwiki's vim processor

    if [ -n "$1" ]
    then
    DEF_SOURCE=$1
    else
    echo "Usage: c.sh "
    exit 1
    fi

    if [ -n "$2" ]
    then
    DEF_OUT=$2
    else
    DEF_OUT=out.html
    fi

    DEF_VIM=/usr/bin/vim

    $DEF_VIM -T xterm -e -s "$DEF_SOURCE"
    +"syntax on" +"set syntax=c" +"so $VIMRUNTIME/syntax/2html.vim"
    +"%s/.*title>|</?head>|</?html>|<meta.*>|</?body.*>//g" <BR>+"%s/<pre>/<pre style='font-family,monospace:FixedSys;color:#c0c0c0;background-color:black'>/g" <BR>+"wq! $DEF_OUT" +"q" <BR><BR>exit $? <BR><BR># End of c.sh</TD></TR></TBODY></TABLE></div> </div> <div class="post_footer_contents"> <!-- 태그 --><!--'"--><div class="container_postbtn #post_button_group"> <div class="postbtn_like"> <div class="wrap_btn"> <button type="button" class="btn_post like_btn uoc-icon" data-uoc-svc="tistory" data-uoc-uid="254440_306" data-uoc-sc="" data-uoc-pcUrl="https://suban.tistory.com/306" data-uoc-fetchurl="http://api.kakao.tistory.com/like/fetch?uid=254440_306"> <div class="uoc-icon"> <span class="ico_postbtn ico_like">좋아요</span> <span class="txt_like uoc-text screen_out">공감</span> <span class="txt_like uoc-count"></span> </div> </button> </div> <div class="wrap_btn wrap_btn_share"> <button type="button" class="btn_post sns_btn btn_share" data-thumbnail-url="https://t1.daumcdn.net/tistory_admin/static/images/openGraph/opengraph.png" data-title="[vim] VIM & bash script 예제 (C source to html view)" data-description="출처 : http://minzkn.wowdns.com:2744/tattertools/211 VIM으로 C 소스를 html 로 보기좋게 바꿔주는 script 예제 코드: #!/bin/bash # Script code by JaeHyuk Cho # See also moniwiki's vim processor if [ -n.." data-profile-image="https://t1.daumcdn.net/cfile/tistory/2534173B58DB503D19" data-profile-name="suban" data-pc-url="https://suban.tistory.com/306" data-blog-title="Suban's Security Footprint Pages"> <span class="ico_postbtn ico_share">공유하기</span> </button> </div> <div class="wrap_btn wrap_btn_etc" data-entry-id="306" data-entry-visibility="public" data-category-visibility="public"> <button type="button" class="btn_post btn_etc2"><span class="ico_postbtn ico_etc">글 요소</span></button> </div> </div> <button type="button" class="btn_menu_toolbar btn_subscription #subscribe" data-blog-id="254440" data-url="https://suban.tistory.com/306" data-device="web_pc"> <em class="txt_state">구독하기</em> <strong class="txt_tool_id">Suban's Security Footprint Pages</strong> <span class="img_common_tistory ico_check_type1"></span> </button> <div class="postbtn_ccl" data-ccl-type=""> <a href="https://creativecommons.org/licenses//4.0/deed.ko" target="_blank" class="link_ccl"> <span class="bundle_ccl"> </span> </a> </div> <!-- <rdf:RDF xmlns="http://web.resource.org/cc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <Work rdf:about=""> <license rdf:resource="http://creativecommons.org/licenses/by-/2.0/kr/" /> </Work> <License rdf:about="http://creativecommons.org/licenses/by-/"> <permits rdf:resource="http://web.resource.org/cc/Reproduction"/> <permits rdf:resource="http://web.resource.org/cc/Distribution"/> <requires rdf:resource="http://web.resource.org/cc/Notice"/> <requires rdf:resource="http://web.resource.org/cc/Attribution"/> </License> </rdf:RDF> --> </div><div class="another_category another_category_color_gray"> <h4>'<a href="/category/ⓘ%20Programming">ⓘ Programming</a>' 카테고리의 다른 글</h4> <table> <tr> <th> <a href="/328?category=158669" >perl을 이용한 하위 파일에 대한 일괄작업</a>  <span>(0)</span> </th> <td> 2007.12.07</td> </tr> <tr> <th> <a href="/320?category=158669" >할당과 InterlockedExchange 중 누가 더 빠를까?</a>  <span>(0)</span> </th> <td> 2007.12.06</td> </tr> <tr> <th> <a href="/306?category=158669" class ="current" >[vim] VIM & bash script 예제 (C source to html view)</a>  <span>(0)</span> </th> <td> 2007.12.02</td> </tr> <tr> <th> <a href="/293?category=158669" >MS 컴파일러는 C++의 클래스를 어떻게 처리하는가?</a>  <span>(0)</span> </th> <td> 2007.11.30</td> </tr> <tr> <th> <a href="/287?category=158669" >CSS(Cascading Style Sheet)-Part1</a>  <span>(0)</span> </th> <td> 2007.11.30</td> </tr> <tr> <th> <a href="/286?category=158669" >메뉴 또는 버튼에 좋은 이름을 지어야 하는 이유~</a>  <span>(0)</span> </th> <td> 2007.11.30</td> </tr> </table></div> </div> <!-- tag label --> <!-- trackback, comment --> <div class="tbrp_box"> <a href="#tb" onclick="alert('이 글에는 트랙백을 달 수 없습니다\t'); return false"><span id="trackbackCount306">Trackbacks<span class="cnt"> 0</span></span></a> : <a href="#rp" onclick=""><span id="commentCount306_0"> Comments <span class="cnt">0</span></span></a> <!-- trackback --> <div id="entry306Trackback" style="display:none"> <div> <p>Trackback Address :: </p> <ol> </ol> </div> </div> <!-- comment --> <div id="entry306Comment"><form method="post" action="/comment/add/306" onsubmit="return false" style="margin: 0"> <div> <!-- comment list --> <div> <ol> </ol> </div> <!-- comment write--> <div> <h4>Write a comment</h4> <p> <input type="text" id="name_" name="name" value="" /> <label for="name_"> : name </label> </p> <p> <input type="password" id="password_" name="password" value="" /> <label for="password_"> : password </label> </p> <p> <input type="text" class="homepage" id="homepage_" name="homepage" value="http://"/> <label for="homepage_"> : homepage </label> <input type="checkbox" id="secret_" name="secret" class="checkbox" /> <label for="secret_"> secret mode </label> </p> <p> <textarea name="comment" cols="100%" rows="6" id="comment_"></textarea> </p> <p> <input type="button" value="Submit Comment" onclick="addComment(this, 306); return false;" class="submit" /> </p> </div> </div> </form></div><script type="text/javascript">loadedComments[306]=true;findFragmentAndHighlight(306)</script> </div> </div> <!-- paging --> <div class="paging"> <a >◀ PREV </a> : <a >[<span class="selected">1</span>]</a> : <a href='/category/ⓘ%20Programming?page=2'>[<span >2</span>]</a> : <a href='/category/ⓘ%20Programming?page=2'>NEXT ▶</a> </div> </div> </td> </tr> </table> <div id="footer"> <p><a href="/"> suban</a>'s Blog is powered by <a href="http://daum.net" onclick="window.open(this.href); return false">Daum</a> | Design by <a href="http://smallpark.org">SmallPark</a> and <a href="http://xsis.tistory.com/">Rest</a></p> </div> </div> <script type="text/javascript"> document.oncontextmenu = new Function ('return false'); document.ondragstart = new Function ('return false'); document.onselectstart = new Function ('return false'); document.body.style.MozUserSelect = 'none'; </script> <script type="text/javascript" src="https://t1.daumcdn.net/tistory_admin/assets/blog/3c1bdbe60f493f5812efec48784f9468e1a3f460/blogs/plugins/PreventCopyContents/js/functions.js?_version_=3c1bdbe60f493f5812efec48784f9468e1a3f460"></script> <script src="//search1.daumcdn.net/search/statics/common/js/g/search_dragselection.min.js"></script> <script> (function($) { $("body").bind('copy', function (e) { var url = document.location.href, decodedUrl = decodeURI(url), selection = window.getSelection(); if (typeof window.getSelection == "undefined") {//IE8 or earlier... event.preventDefault(); var pagelink = '\n\n 출처: ' + decodedUrl, copytext = selection + pagelink; if (window.clipboardData) { window.clipboardData.setData('Text', copytext); } return; } var body_element = document.getElementsByTagName('body')[0]; //if the selection is short let's not annoy our users if (("" + selection).length < 30) return; //create a div outside of the visible area var newdiv = document.createElement('div'); newdiv.style.position = 'absolute'; newdiv.style.left = '-99999px'; body_element.appendChild(newdiv); newdiv.appendChild(selection.getRangeAt(0).cloneContents()); //we need a <pre> tag workaround //otherwise the text inside "pre" loses all the line breaks! if (selection.getRangeAt(0).commonAncestorContainer.nodeName == "PRE") { newdiv.innerHTML = "<pre>" + newdiv.innerHTML + "</pre>"; } newdiv.innerHTML += '<br /><br />출처: <a href="' + url + '">' + escapeHTML(decodedUrl) + '</a> [Suban\'s Security Footprint Pages]'; selection.selectAllChildren(newdiv); window.setTimeout(function () { body_element.removeChild(newdiv); }, 200); }); })(tjQuery); </script> <script> lightbox.option({ "fadeDuration": 200, "resizeDuration": 200, "wrapAround": false, "albumLabel": "%1 / %2", "fitImagesInViewport":true , "stopEvent": false }) </script><script src="https://t1.daumcdn.net/tistory_admin/assets/blog/3c1bdbe60f493f5812efec48784f9468e1a3f460/blogs/plugins/RainbowLink/rainbow.js?_version_=3c1bdbe60f493f5812efec48784f9468e1a3f460" type="text/javascript"></script> </body> </html>