출처: http://blog.naver.com/powerms100?Redirect=Log&logNo=120000891617

Global Hooking in Win32
 ====================================================

 후크에는 두가지가 있다. 
   Local Hook   - 하나의 스레드나 프로세스 안에서의 후킹
   Global Hook  - 전역 모든 윈도우들에 대한 후킹

 후크를 하기 위해서는 기본적으로 두가지 자료형을 알아야 한다.
   HHOOK - 후크 핸들  윈도우 시스템에서 한번 이벤트가
           발생하면 후크 체인의 첫 후크핸들에게 이벤트를
           넘긴다. 각 후크들은 다음 후크를 호출하여 후크체인에
           있는 모든 후크 프로시져를 호출하게 된다.
   HOOKPROC - 후크 프로시져로 후크시 호출되는 프로시져이다.
    LRESULT CALLBACK fnHookProc(int nCode, WPARAM wParam, LPARAM lParam)
    라는 자료형을 갖는다.

 1. 로컬 후킹
   SetWindowHookEx를 이용하면 간단히 구현이 가능하다.
   각 후크는 후크 타입이 있는데 아래와 같다.
      WH_CALLWNDPROC - 윈도우 메세지가 목적지로 전달되기 전에
                       메세지를 후크할때 쓴다 (SendMessage)
                       CallWndProc라는 후크프로시져명의 도움말 참조한다.
      WH_CALLWNDPROCRET - 윈도우 메세지가 목적지에 전달되어 처리
                          된 후 후크가 일어난다
                          CallWndRetProc함수명 도움말 참조
      WH_CBT - computer-based training (CBT) application 에 유용한
               후크 타입 CBTProc 함수 참조
      WH_DEBUG - 디버깅에 유용한 후크 DebugProc 참조
      WH_FOREGROUNDIDLE - Foreground상태있는 윈도우가 idle상태로 들어갈
                          때 생기는 후크 이는 idle시 낮은 우선순위
                          (low priority)를 줄때 유용하다 ForegroundIdleProc
      WH_GETMESSAGE - 메세지가 Post된 후 후크됨 (PostMessage)
                      GetMsgProc 함수 참조
      WH_JOURNALPLAYBACK - WH_JOURNALRECORD에 의해서 Record되기 전에
                           일어나는 후크 JournalPlaybackProc
      WH_JOURNALRECORD - Input message가 시스템 메세지 큐로 들어가는것을
                         Record하는 후크 JournalRecordProc 
      WH_KEYBOARD - 등등이 있다.... -_- 도움말 참조..

 
 --------------------- 로컬 후크 예제 ------------------------------
    HHOOK hHook;
    HOOKPROC hProc;
              :
    hProc = CallWndProc;            // CallWndProc 후크 프로시져로 연결
    hHook = ::SetWindowsHookEx(     // 후크를 설치한다. ( 후크체인에 끼워넣는다 )
                 WH_CALLWNDPROC,    // WH_CALLWNDPROC 후크 설치
                 hProc,             // 후크차례가 오면 분기되는 콜백후크 프로시져
                 (HINSTANCE) NULL,  // 전역 후크가 아닌 로컬 후크임을 말한다
                 dwTreadID);        // 특정 스레드를 정한다 0 이면 현재 스레드


    만일 여러 스레드중 한 HWND가 속한 스레드를 얻고 싶으면
    DWORD    dwProcessID = NULL;
    DWORD    dwTreadID = ::GetWindowThreadProcessId( hWnd, &dwProcessID );

    if( dwProcessID )
    {
                 : 
         후크 설치코드 맨 마지막인자에 dwThreadID를 넣으면 된다.     
    }

// 자세한 프로시져 도움말을 보면 자세히 알수 있다.
LRESULT WINAPI CallWndProc(int nCode, WPARAM wParam, LPARAM lParam) 

    CWPSTRUCT* lpWp = (CWPSTRUCT*)lParam;
     //PMSG lpMsg = (PMSG)lParam;    
    if (nCode < 0 && hWnd == lpWp->hwnd )  // do not process message 
        return CallNextHookEx(m_stHookCallProc.hHook, nCode, wParam, lParam); 

    switch(  lpWp->message  )
    {
         case EM_REPLACESEL :
         TRACE("CallWndProc EM_REPLACESEL %s\r\n ", (char*)lpWp->lParam );
         break;

         default : 
         break;
    }    
    return CallNextHookEx(m_stHookCallProc.hHook, nCode, 
        wParam, lParam); 

 
2 전역 후킹 
  전역 후킹을 하기 위해서는 후크 프로시져를 dll안에 넣어야 한다.
 


 --------------------- 전역 후크 예제 --------------------------

  testdll.dll 에서 ............

// dll에서 쓰는 자료는 dll공유를 했다.
// 이 후크 프로시져 dll은 내 프로그램에서 쓰이기도 하지만
// 시스템에 의해서 이 dll이 또 열리게 된다. ( dll의 참조카운트 증가
//  가 일어나지 않고 새로 dll이 생긴다. 따라서 두 dll은 자료가
//  분리되어 있는 셈이다. )
// 그러므로 부득이 하게 자료를 공유자료로 해야 한다.
#pragma data_seg(".shared")
    HHOOK             _hHook = NULL;
    HWND            _hTarget = NULL;
#pragma data_seg()
// 공유 자료로 했을 경우 아래처럼 링커 옵션도 주어야 한다.
#pragma comment(linker, "/SECTION:.shared,RWS")

// 자료 억세스 함수 마련...
extern "C" __declspec(dllexport) void fnSetHook( HHOOK hHook )
{
    _hHook = hHook;
}

extern "C" __declspec(dllexport) void fnSetHWND( HWND hWnd )
{
    _hTarget = hWnd;
    char szBuf[20];
    wsprintf( szBuf, "%lu", (ULONG)_hTarget );
    MessageBox( NULL, szBuf, "fnSetHWND당시의 _hTarget값", MB_OK);


extern "C" __declspec(dllexport) HHOOK fnGetHook()
{
    return _hHook;
}

// 콜백을 위한 CALLBACK 콜링컨벤션 키워드를 넣게 되면 나중에 GetAddressProc시
// NULL값을 리턴하므로 그냥 콜링컨벤션을 무시했다
//extern "C" __declspec(dllexport) LRESULT CALLBACK fnCallWndProc(int nCode, WPARAM wParam, LPARAM 
lParam)
extern "C" __declspec(dllexport) LRESULT fnCallWndProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    CWPSTRUCT* lpWp = (CWPSTRUCT*)lParam;
     
    if( nCode >= 0  ) //&& _hTarget == lpWp->hwnd ) // do not process message 
    { 
        switch(  lpWp->message  )
        {
        case EM_REPLACESEL :
            if( _hTarget == lpWp->hwnd )
            {
                MessageBox( NULL, "EM_REPLACESEL 메세지 발쌩", "메세지 발쌩in 
dll", MB_OK);
            }
            break;

        default : 
            break;
        }    
    }
    return CallNextHookEx( _hHook, nCode, wParam, lParam); 
}


 내 프로그램에서 .........................
HINSTANCE    hInstDll = NULL
HHOOK        hHook = NULL;

// dll을 연다.
hInstDll = LoadLibrary("TestDll.dll"); 
if( hInstDll )
{
    // 후크 프로시져를 찾아낸다.
    LRESULT (*hHookDllProc)(int, WPARAM, LPARAM ) = (LRESULT (*)(int, WPARAM, LPARAM ))
GetProcAddress(hInstDll, "fnCallWndProc"); 
    if( hHookDllProc ) // 있으면 후크를 설치한다.
        hHook = SetWindowsHookEx( WH_CALLWNDPROC, (HOOKPROC)hHookDllProc, hInstDll, 0); 
    
        // dll내의 자료를 세팅한다. HHOOK와 HWND 값 세팅
    void (*lpfnSetHook)(HHOOK) = (void (*)(HHOOK))GetProcAddress(hInstDll, "fnSetHook");
    if( lpfnSetHook )
        (*lpfnSetHook)( hHook );
        void (*lpfnSetHWND)(HWND) = (void (*)(HWND))GetProcAddress
(hInstDll, "fnSetHWND");
    if( lpfnSetHWND )
        (*lpfnSetHWND)( m_hTarget );
}


AND

출처: http://support.microsoft.com/kb/183110/ko

요약
WinInet은 단일 HTTP 서버에 시도되는 동시 연결 수를 제한합니다. 이 한도를 초과하면 현재 연결 중 하나가 완료할 때까지 요청이 차단됩...

WinInet은 단일 HTTP 서버에 시도되는 동시 연결 수를 제한합니다. 이 한도를 초과하면 현재 연결 중 하나가 완료할 때까지 요청이 차단됩니다. 이것은 의도적으로 설계된 동작으로 HTTP 사양 및 업계 표준과 일치합니다.

추가 정보
WinInet은 단일 HTTP 1.0 서버에 대한 동시 연결 수를 4개로 제한합니다. 단일 HTTP 1.1 서버에 대한 동시 연결은 2개로 제한...

WinInet은 단일 HTTP 1.0 서버에 대한 동시 연결 수를 4개로 제한합니다. 단일 HTTP 1.1 서버에 대한 동시 연결은 2개로 제한됩니다. HTTP 1.1 사양(RFC2616)에서는 연결 수를 2개로 제한할 것을 요구합니다. 그러나 HTTP 1.0에 대한 4개의 연결 수 제한은 많은 웹 브라우저에서 사용하는 표준과 일치하는 자체 제한입니다.

응용 프로그램에 대한 이러한 제한은 HttpSendRequestInternetOpenURL 같은 호출이 완료되는 데 오래 걸리는 것을 통해서 알 수 있습니다. 이러한 지연은 해당 호출에서 요청을 보내기 전에 이전 연결이 해제되기를 기다리기 때문에 발생합니다.

다음 레지스트리 항목을 만들고 설정하여 WinInet이 이 제한을 초과하도록 구성할 수 있습니다.

참고 이러한 설정을 변경하면 WinInet이 HTTP 프로토콜 사양의 권고안에 맞지 않게 됩니다. 꼭 필요할 때만 설정을 변경해야 하며 다음 설정이 적용될 때는 표준 웹 검색을 수행하지 않아야 합니다.
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings

MaxConnectionsPerServer REG_DWORD(기본값 2)
단일 HTTP 1.1 서버에 대한 동시 요청 수를 설정합니다.

MaxConnectionsPer1_0Server REG_DWORD(기본값 4)
단일 HTTP 1.0 서버에 대한 동시 요청 수를 설정합니다.
이러한 설정은 특정 사용자에게만 적용되고 해당 컴퓨터에 로그온하는 다른 사용자에게는 영향을 미치지 않습니다.

Internet Explorer 5에서는 NULL 핸들에 대해 다음 플래그로 InternetSetOption 함수를 호출하여 연결 제한을 프로그래밍 방식으로 변경할 수 있습니다. 이렇게 하면 프로세스 전체에 대한 연결 제한이 변경됩니다.
INTERNET_OPTION_MAX_CONNS_PER_SERVER INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER
참고 프로세스에 서버에 대한 연결이 설정되어 있는 경우 InternetSetOption 함수를 호출하여 연결 제한을 변경해도 동일한 서버의 후속 연결에는 영향을 주지 않습니다. 이는 이전 연결을 끊은 후에 InternetSetOption을 호출하는 경우에도 해당됩니다. 연결 제한은 다른 모든 서버에 영향을 줍니다.



Microsoft 제품 관련 기술 전문가들과 온라인으로 정보를 교환하시려면 Microsoft 뉴스 그룹 (http://support.microsoft.com/newsgroups/default.aspx) 에 참여하시기 바랍니다.

본 문서의 정보는 다음의 제품에 적용됩니다.
  • Microsoft Internet Explorer (Programming) 6.0
  • Microsoft Internet Explorer 5.5
  • Microsoft Internet Explorer 5.0
  • Microsoft Internet Explorer 4.01 서비스 팩 2
  • Microsoft Internet Explorer 4.0 128-Bit Edition




example)
http://newsgroups.cryer.info/microsoft/public.inetsdk.programming.wininet/200707/0707162258.html



#include "stdafx.h"
#include <windows.h>
#include <wininet.h>


int _tmain(int argc, _TCHAR* argv[])
{

    unsigned long nSize = sizeof(DWORD);
    DWORD http1_0 = 4;
    DWORD http1_1 = 2;


    if(!InternetSetOption(NULL, INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER,
&http1_0, nSize))
    {
        return -1;
    }

    if(!InternetSetOption(NULL, INTERNET_OPTION_MAX_CONNS_PER_SERVER,
&http1_1, nSize))
    {
        return -1;
    }


    if(!InternetSetOption(NULL, INTERNET_OPTION_SETTINGS_CHANGED, NULL,
0))
    {
        return -1;
    }

    if(!InternetSetOption(NULL, INTERNET_OPTION_REFRESH, NULL, 0))
    {
        return -1;
    }

    return 0;
}

AND

출처: http://www.answers.com/topic/terminal-services
Load Balancer für WTS
Auslastungsabhängige Verteilung mit Session Directory Integration 
www.kemptechnologies.com
Why spend on Citrix?
Get 70% discount when replacing Citrix with Jetro CockpIT 
www.jetroplatforms.com

Software from Microsoft that provides a centralized, terminal-based, multiuser environment for Windows servers. Using Microsoft's RDP protocol, which governs keyboard, mouse and screen transfer, a client PC is turned into an input/output (I/O) terminal to the Windows server, which runs any and all applications that might normally be run on a desktop PC. Low-cost, dedicated RDP terminals from various companies can also be used.

Introduced in Windows NT 4.0, the client part of Terminal Services is known as the Remote Desktop Connection (RDC), and the server side is Terminal Server. The software that provides the shared terminal services for multiple users is based on Citrix's MultiWin technology (see MultiWin). See thin client, Citrix XenApp and centralized processing.

RDP and ICA Protocols
The Terminal Services native protocol is Microsoft's Remote Desktop Protocol (RDP). Citrix XenApp (formerly Citrix Presentation Server) adds the ICA protocol and numerous enhancements (see Citrix XenApp).



    Search unanswered questions...
    Enter a word or phrase...
    Community Q&A Reference topics
    OpenBSD ThinClient
    Günstiger und sicherer ThinClient als Arbeitsplatz-Computer 
    www.bytemine.net/openbsd-thinclient
    Windows Terminal Server
    Multiple Remote Connections. Free Trial, Low Cost! 
    Eval.Terminal-Server.com
    Wikipedia: Terminal Services
    Top
    Terminal Services
    Remote Desktop Connection Icon
    Developed by Microsoft
    Latest release 6.0.6001.18000 / February 4, 2008
    OS Microsoft Windows, Mac OS X
    License MS-EULA
    Website www.microsoft.com

    Terminal Services, renamed as Remote Desktop Services from Windows Server 2008 R2 onwards, is one of the components of Microsoft Windows (both server and client versions) that allows a user to access applications and data on a remote computer over a network. Terminal Services is Microsoft's implementation of thin-client terminal server computing, where Windows applications, or even the entire desktop of the computer running terminal services, are made accessible to a remote client machine. The client can either be a fully-fledged computer, running any operating system as long as the terminal services protocol is supported, or a bare-bones machine powerful enough to support the protocol (such as Windows FLP). With terminal services, only the user interface of an application is presented at the client. Any input to it is redirected over the network to the server, where all application processing takes place.[1] This is in contrast to appstreaming systems, like Microsoft Application Virtualization, in which the applications, while still stored on a centralized server, are streamed to the client on-demand and then processed by the client machine.

    Contents

    [hide]

    Overview

    Terminal Services was first introduced in Windows NT 4.0 Terminal Server Edition. It was significantly improved for Windows 2000 and Windows Server 2003. Both the underlying protocol as well as the service was again overhauled for Windows Vista and Windows Server 2008 [2]. Windows includes two client applications which utilize terminal services: the first, Remote Assistance is available in all versions of Windows XP and successors and allows one user to assist another user. The second, Remote Desktop, allows a user to log in to a remote system and access the desktop, applications and data on the system as well as control it remotely. However, this is only available in certain Windows editions. These are Windows NT Terminal Server; subsequent Windows server editions, Windows XP Professional, and Windows Vista Business, Enterprise and Ultimate. In the client versions of Windows, Terminal Services supports only one logged in user at a time, whereas in the server operating systems, concurrent remote sessions are allowed.

    Microsoft provides the client software Remote Desktop Connection (formerly called Terminal Services Client), available for most 32-bit versions of Windows including Windows Mobile and Apple's Mac OS X, that allows a user to connect to a server running Terminal Services. On Windows, both Terminal Services client and Remote Desktop Protocol (RDP) use TCP port 3389 by default, which is editable in the Windows registry. It also includes an ActiveX control to embed the functionality in other applications or even a web page.[3] A Windows CE version of the client software is also available.[1] Server versions of Windows OSs also include the Remote Desktop for Administration client (a special mode of the Remote Desktop Connection client), which allows remote connection to the traditional session 0 console of the server. In Windows Vista and later this session is reserved for services and users always log onto session >0. The server functionality is provided by the Terminal Server component, which is able to handle Remote Assistance, Remote Desktop as well as the Remote Administration clients.[1] Third-party developers have created client software for other platforms, including the open source rdesktop client for common Unix platforms.

    For an enterprise, Terminal Services allows IT departments to install applications on a central server. For example, instead of deploying database or accounting software on all desktops, the applications can simply be installed on a server and remote users can log on and use them via the Internet. This centralization makes upgrading, troubleshooting, and software management much easier. As long as employees have Remote Desktop software, they will be able to use enterprise software. Terminal Services can also integrate with Windows authentication systems to prevent unauthorized users from accessing the applications or data.

    Microsoft has a longstanding agreement with Citrix to facilitate sharing of technologies and patent licensing between Microsoft Terminal Services and Citrix Presentation Server (formerly Citrix MetaFrame) which has now been renamed to Citrix XenApp. In this arrangement, Citrix has access to key source code for the Windows platform enabling their developers to improve the security and performance of the Terminal Services platform. In late December, 2004 the two companies announced a five-year renewal of this arrangement to cover Windows Vista.

    Architecture

    The server component of Terminal Services (Terminal Server) listens on TCP port 3389 (termdd.sys). When an RDP client connects to this port, it is tagged with a unique SessionID and associated with a freshly spawned console session (Session 0, keyboard, mouse and character mode UI only). The login subsystem (winlogon.exe) and the GDI graphics subsystem is then initiated, which handles the job of authenticating the user and presenting the GUI. These executables are loaded in a new session, rather than the console session. When creating the new session, the graphics and keyboard/mouse device drivers are replaced with RDP-specific drivers: RdpDD.sys and RdpWD.sys. The RdpDD.sys is the device driver and it captures the UI rendering calls into a format that is transmittable over RDP. RdpWD.sys acts as keyboard and mouse driver; it receives keyboard and mouse input over the TCP connection and presents them as keyboard or mouse inputs. It also allows creation of virtual channels, which allow other devices, such as disc, audio, printers, and COM ports to be redirected, i.e., the channels act as replacement for these devices. The channels connect to the client over the TCP connection; as the channels are accessed for data, the client is informed of the request, which is then transferred over the TCP connection to the application. This entire procedure is done by the terminal server and the client, with the RDP protocol mediating the correct transfer, and is entirely transparent to the applications.[4] RDP communications are encrypted using 128-bit RC4 encryption. Windows Server 2003 onwards, it can use a FIPS 140 compliant encryption scheme.[1]

    Once a client initiates a connection and is informed of a successful invocation of the terminal services stack at the server, it loads up the device as well as the keyboard/mouse drivers. The UI data received over RDP is decoded and rendered as UI, whereas the keyboard and mouse inputs to the Window hosting the UI is intercepted by the drivers, and transmitted over RDP to the server. It also creates the other virtual channels and sets up the redirection. RDP communication can be encrypted; using either low, medium or high encryption. With low encryption, only the channels transferring sensitive information like passwords are encrypted. With medium encryption, UI packets are encrypted as well. And with high encryption, keyboard/mouse inputs are also scrambled.[4]

    Terminal Server

    Terminal Server is the server component of Terminal services. It handles the job of authenticating clients, as well as making the applications available remotely. It is also entrusted with the job of restricting the clients according to the level of access they have. The Terminal Server respects the configured software restriction policies, so as to restrict the availability of certain software to only a certain group of users. The remote session information is stored in specialized directories, called Session Directory which is stored at the server. Session directories are used to store state information about a session, and can be used to resume interrupted sessions. The terminal server also has to manage these directories. Terminal Servers can be used in a cluster as well.[1]

    In Windows Server 2008, it has been significantly overhauled. While logging in, if the user logged on to the local system using a Windows Server Domain account, the credentials from the same sign-on can be used to authenticate the remote session. However, this requires Windows Server 2008 to be the terminal server OS, while the client OS is limited to either Windows Server 2008 or Windows Vista. In addition, the terminal server can provide access to only a single program, rather than the entire desktop, by means of a feature named RemoteApp. Terminal Services Web Access (TS Web Access) makes a RemoteApp session invocable from the web browser. It includes the TS Web Access Web Part control which maintains the list of RemoteApps deployed on the server and keeps the list up to date. A Terminal server session can also be tunneled through a gateway via the TS Gateway service. It makes the server available over the Internet by tunneling the RDP data over a HTTPS channel. Both Windows Server 2008 and Windows Home Server can act as TS Gateway servers. Terminal Server can also integrate with Windows System Resource Manager to throttle resource usage of remote applications.[2]

    Terminal Server is managed by the Terminal Server Manager MMC snap-in. It can be used to configure the sign in requirements, as well as to enforce a single instance of remote session. It can also be configured by using Group Policy or WMI. It is, however, not available in client versions of Windows OS, where the server is pre-configured to allow only one session and enforce the rights of the user account on the remote session, without any customization.[1]

    Remote Desktop Connection

    Remote Desktop Connection client in Windows XP.

    Remote Desktop Connection (RDC, also called Remote Desktop) is the client application for Terminal Services. It allows a user to remotely log in to a networked computer running the terminal services server. RDC presents the desktop interface of the remote system, as if it were accessed locally.[1] With the latest version (version 6.0), if the Desktop Experience component is plugged into the remote server, the chrome of the applications will resemble the local applications, rather than the remote one. In this scenario, the remote applications will use the Aero theme if a Windows Vista machine running Aero is connected to the server.[2] Later versions of the protocol also support rendering the UI in full 24 bit color, as well as resource redirection for printers, COM ports, disk drives, mic and keyboards. With resource redirection, remote applications are able to use the resources of the local computer. Audio is also redirected, so that any sounds generated by a remote application are played back at the client system.[1][2] In addition to regular username/password for authorizing for the remote session, RDC also supports using smart cards for authorization[1] With RDC 6.0, the resolution of a remote session can be set independently of the settings at the remote computer. In addition, a remote session can also span multiple monitors at the client system, independent of the multi-monitor settings at the server. It also prioritizes UI data as well as keyboard and mouse inputs over print jobs or file transfers so as to make the applications more responsive. It also redirects plug and play devices such as cameras, portable music players, and scanners, so that input from these devices can be used by the remote applications as well.[2] RDC can also be used to connect to WMC remote sessions; however, since WMC streams does not stream video using Remote Desktop Protocol, only the applications can be viewed this way, not any media. RDC can also be used to connect to computers, which are exposed via Windows Home Server RDP Gateway over the Internet.

    RemoteApp

    RemoteApp (or TS RemoteApp) is a special mode of Terminal Services, available only in Remote Desktop Connection 6.1 and above (with Windows Server 2008 being the RemoteApp server), where a remote session connects to a specific application only rather than the entire Windows desktop. The RDP 6.1 client ships with Windows XP SP3, KB952155 for Windows XP SP2 users [5], Windows Vista SP1 and Windows Server 2008. The UI for the RemoteApp is rendered in a window over the local desktop, and is managed like any other window for local applications. The end result of this is that remote applications behave largely like local applications. The task of establishing the remote session, as well as redirecting local resources to the remote application, is transparent to the end user.[6] Multiple applications can be started in a single RemoteApp session, each with their own windows.[7]

    A RemoteApp can be packaged either as a .rdp file or distributed via an .msi Windows Installer package. When packaged as an .rdp file (which contains the address of the RemoteApp server, authentication schemes to be used, and other settings), a RemoteApp can be launched by double clicking the file. It will invoke the Remote Desktop Connection client, which will connect to the server and render the UI. The RemoteApp can also be packaged in an Windows Installer database, installing which can register the RemoteApp in the Start Menu as well as create shortcuts to launch it. A RemoteApp can also be registered as handlers for filetypes or URIs. Opening a file registered with RemoteApp will first invoke Remote Desktop Connection, which will connect to the terminal server and the open the file. Any application, which can be accessed over Remote Desktop, can be served as a RemoteApp.[6]

    Windows Desktop Sharing

    Windows Vista onwards, Terminal Services also includes a multi-party desktop sharing capability known as Windows Desktop Sharing. Unlike Terminal Services, which creates a new user session for every RDP connection, Windows Desktop Sharing can host the remote session in the context of the currently logged in user without creating a new session, and make the Desktop, or a subset of it, available over Remote Desktop Protocol.[8] Windows Desktop Sharing can be used to share the entire desktop, a specific region, or a particular application.[9] Windows Desktop Sharing can also be used to share multi-monitor desktops. When sharing applications individually (rather than the entire desktop), the windows are managed (whether they are minimized or maximized) independently at the server and the client side.[9]

    The functionality is only provided via a public API, which can be used by any application to provide screen sharing functionality. Windows Desktop Sharing API exposes two objects: RDPSession for the sharing session and RDPViewer for the viewer. Multiple viewer objects can be instantiated for one Session object. A viewer can either be a passive viewer, who is just able to watch the application like a screencast, or an interactive viewer, who is able to interact in real time with the remote application.[8] The RDPSession object contains all the shared applications, represented as Application objects, each with Windowobjects representing their on-screen windows. Per-application filters capture the application Windows and package them as Window objects.[10] A viewer must authenticate itself before it can connect to a sharing session. This is done by generating an Invitation using the RDPSession. It contains an authentication ticket and password. The object is serialized and sent to the viewers, who need to present the Invitation when connecting.[8][10]

    Windows Desktop Sharing API is used by Windows Meeting Space for providing application sharing functionality among peers; however, the application does not expose all the features supported by the API.[9] It is also used by Remote Assistance.

    See also

    References

    External links



    AND

    출처: http://www.bcpark.net/bbs/245321


    32비트 Windows용 Internet Explorer 버전/빌드

     

    버전  제품
    4.40.308  Internet Explorer 1.0(Windows 95용 Plus!)
    4.40.520  Internet Explorer 2.0
    4.70.1155  Internet Explorer 3.0
    4.70.1158  Internet Explorer 3.0(Windows 95 OSR2)
    4.70.1215  Internet Explorer 3.01
    4.70.1300  Internet Explorer 3.02 및 3.02a
    4.71.544   Internet Explorer 4.0 Platform Preview 1.0(PP1)
    4.71.1008.3  Internet Explorer 4.0 Platform Preview 2.0(PP2)
    4.71.1712.6  Internet Explorer 4.0
    4.72.2106.8  Internet Explorer 4.01
    4.72.3110.8  Internet Explorer 4.01 서비스 팩 1(Windows 98)
    4.72.3110.8  Internet Explorer 4.01 SP1a(Windows 98/ 1998.10)
    --SP1a에는 Microsoft virtual machine(MS VM) 4.79.2435이 포함된 완성판--
    4.72.3612.1713  Internet Explorer 4.01 서비스 팩 2
    5.00.0518.10  Internet Explorer 5 Developer Preview(베타 1)
    5.00.0910.1309  Internet Explorer 5 베타(베타 2)
    5.00.2014.0216  Internet Explorer 5
    5.00.2314.1003  Internet Explorer 5(Office 2000)
    5.00.2614.3500  Internet Explorer 5(Windows 98 Second Edition)
    5.00.2516.1900  Internet Explorer 5.01(Windows 2000 베타 3, 빌드 5.00.2031)
    5.00.2919.800  Internet Explorer 5.01(Windows 2000 RC1, 빌드 5.00.2072)
    5.00.2919.3800  Internet Explorer 5.01(Windows 2000 RC2, 빌드 5.00.2128)
    5.00.2919.6307  Internet Explorer 5.01(Office 2000 SR-1)
    5.00.2920.0000  Internet Explorer 5.01(Windows 2000, 빌드 5.00.2195)
    5.00.3103.1000  Internet Explorer 5.01 SP1(Windows 2000 SP1)
    5.00.3105.0106  Internet Explorer 5.01 SP1(Windows 95/98 및 Windows NT 4.0)
    5.00.3314.2101  Internet Explorer 5.01 SP2(Windows 95/98 및 Windows NT 4.0)
    5.00.3315.1000  Internet Explorer 5.01 SP2(Windows 2000 SP2)
    5.00.3502.1000  Internet Explorer 5.01 SP3(Windows 2000 SP3만 해당)
    5.00.3700.1000  Internet Explorer 5.01 SP4(Windows 2000 SP4만 해당)
    5.50.3825.1300  Internet Explorer 5.5 Developer Preview(베타)
    5.50.4030.2400  Internet Explorer 5.5 및 인터넷 도구 베타
    5.50.4134.0100  Windows Me용 Internet Explorer 5.5(4.90.3000)
    5.50.4134.0600  Internet Explorer 5.5
    5.50.4308.2900  Internet Explorer 5.5 Advanced Security Privacy 베타
    5.50.4522.1800  Internet Explorer 5.5 서비스 팩 1
    5.50.4807.2300  Internet Explorer 5.5 서비스 팩 2
    6.00.2462.0000  Internet Explorer 6 Public Preview(베타)
    6.00.2479.0006  Internet Explorer 6 Public Preview(베타) Refresh
    6.00.2600.0000  Internet Explorer 6(Windows XP)
    6.00.2800.1106  Internet Explorer 6 서비스 팩 1(Windows XP SP1)
    6.00.3663.0000  Microsoft Windows Server 2003 RC1용 Internet Explorer 6
    6.00.3718.0000  Windows Server 2003 RC2용 Internet Explorer 6
    6.00.3790.0000  Windows Server 2003용 Internet Explorer 6(릴리스)

    출처: http://support.microsoft.com/kb/164539
    아래는 윈도우즈 버전별 대응가능한 인터넷 탐색기의
    버전/빌드 표래요.(휴.. 어려웠음;;)

    Windows version / Internet Explorer Version / Internet Explorer Build ID
    NT4 SP6 / 4.01 SP2 / 4.72.3612.1713
          / 5.0 / 5.00.2314.1003
          / 5.01 / 5.00.2919.6307
          / 5.01 SP2 / 5.00.3314.2101
          / 5.5 SP1 / 5.50.4522.1800
          / 5.5 SP2 / 5.50.4807.2300
          / 6.0 / 6.0.2600.0000
          / 6.0 SP1 / 6.0.2800.1106

    98 / 4.01 SP1a 4.72.3110.8
       / 4.01 SP2 / 4.72.3612.1713
       / 5.0 / 5.00.2314.1003
       / 5.01 / 5.00.2919.6307
       / 5.01 SP2 / 5.00.3314.2101
       / 5.5 SP1 / 5.50.4522.1800
       / 5.5 SP2 / 5.50.4807.2300
       / 6.0 / 6.0.2600.0000
       / 6.0 SP1 / 6.0.2800.1106

    98SE / 5.0 / 5.00.2314.1003
        / 5.01 / 5.00.2919.6307
        / 5.01 SP2 / 5.00.3314.2101
        / 5.5 SP1 / 5.50.4522.1800
        / 5.5 SP2 / 5.50.4807.2300
        / 6.0 / 6.0.2600.0000
        / 6.0 SP1 / 6.0.2800.1106

    NT5.0(2000) / 5.01 / 5.00.2920.0000
          / 5.01 SP2 / 5.00.3315.1000
          / 5.5 SP1 / 5.50.4522.1800
          / 5.5 SP2 / 5.50.4807.2300
          / 6.0 / 6.0.2600.0000
          / 6.0 SP1 / 6.0.2800.1106

    NT5.0(2000) SP2 / 5.5 SP2 / 5.50.4807.2300

    NT5.0(2000) SP3 / 5.01 SP3 / 5.00.3502.1000
            / 5.5 SP1 / 5.50.4522.1800
            / 5.5 SP2 / 5.50.4807.2300
            / 6.0 / 6.0.2600.0000
            / 6.0 SP1 / 6.0.2800.1106

    ME / 5.5 / 4.90.3000
       / 5.5 SP1 / 5.5.4522.1800
       / 5.5 SP2 / 5.50.4807.2300
       / 6.0 / 6.0.2600.0000
       / 6.0 SP1 / 6.0.2800.1106

    NT5.1(XP) / 6.0 /6.0.2600.0000
          /6.0 SP1 /6.0.2800.1106
    AND

     [답변]통상적인 WIN32에서는 BSTR도 WCHAR*입니다. 2008-08-20 오후 10:04:17
    번호: 738452   / 평점:  (9.0)  

    통상적인 WIN32에서는 BSTR도 WCHAR*입니다.

     

    통상적으로 쓰는 WCHAR  문자열과 다른 점은, 첫문자 앞에 4바이트가 추가로 할당되어 문자열의 길이를 저장합니다.

     

     

    문자열크기

    (4바이트)

    첫번째 문자

    (2바이트)

    두번째 문자

    (2바이트)

    세번째 문자

    (2바이트)

    NULL

    (2바이트)

     

     

     

     

     

    이런 구조이구요, BSTR 자체는 WCHAR*로, 첫번째 문자의 주소를 가리키고 있는 포인터입니다.

    보통 메모리를 할당하면, 가장 첫번째 요소의 주소를 가지고 핸들링 하는데,

    BSTR은 약간 특이하게 문자열의 크기가 아니라 첫번째 문자의 포인터입니다.

    그래서 C언어에서 사용할 때, 통상적인 WCHAR*과 비슷하게 사용할 수 있긴 하죠.

     

    조금 헷갈릴 수 있는 게 C언어에서 메모리를 할당하거나 해제할 때는 가장 첫번째 요소의 포인터를 사용하는데,

    BSTR 문자열을 할당하려면 할당한 메모리의 첫번째 주소에 4바이트를 더한 주소를 사용하셔야 하고,

    BSTR 문자열을 해제하려면 주소에서 4바이트 빼서 해제 하셔야 하죠.

     

    실제로는 직접 이렇게 하진 않고 SysAllocString이나 SysFreeString으로 이 과정을 대신합니다.


    //////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////
    출처: http://bektekk.wo.to/str03.htm

    백택 (bektekk@yahoo.co.kr)
    홈페이지 : http://bektekk.wo.to

    문자열(스트링) 전격 분석 2부 1강

    본강좌는 코드 프로젝트에 제가 좋아하는 프로그래머인 Michael Dunn의 강좌
    The Complete Guide to C++ Strings, Part I 과 II 를 번역한 글입니다.
    최대한 의역을 하려고 노력했지만, 이런쪽의 경험이 부족하다 보니 많이 모자란
    강좌가 되겠지만, 많은 도움이 되셨으면 합니다.
    기타 문의 사항이나 질문은 쪽지나 메일을 이용해 주셨으면 합니다.
    본강좌는 제 홈페이지(위의 링크)를 통해서도 보실수 있습니다.

    이번강 까지도 좀 지루하겠네요.
    다음강을 마지막으로 실제 클래스들을 다루어 보겠습니다.

    소개

    C스타일 스트링은 에러를 유발하기 쉽고, 관리하기가 매우 까다로울뿐만 아니라, 해커에게 오버런 버그를 노출하는 타겟이 될 수도 있기 때문에, 수많은 스트링 랩퍼 클래스들이 생겨났다. 하지만 불행히도 어떤 상황에서 어떤 클래스를 써야하고 혹은 C스트링을 어떻게 랩퍼 클래스를 이용해 처리해야 하는지는 가끔씩 우리를 해깔리게 한다.

    이번 강좌 2부의 내용은 Win32 API, MFC, STL, WTL과 VC런타임 라이브러리의 모든 스트링 랩퍼 클래스들을 다루고 있다. 각 클래스는 어떻게 생성하고 사용하며, 각각 어떻게 변환할수 있는지 설명할 것이다.

    2부의 내용을 제대로 소화하기 위해서는 1부 1,2강에서 설명한 캐릭터 타입들과 인코딩 방식에 대한 충분한 이해가 필요할 것이다.

    스트링 클래스의 가장 중요한 규칙

    만약 문서화되어 있어 형변환에 문제가 없다는 확신이 없으면 강제 형변환은 피할것.

    어떤 스트링랩퍼 클래스 X와 또다른 클래스 Z사이의 형변환에 관한 내용은 특히 초급 프로그래머들이 많이 궁금해 하는 내용이다. 주로 초급 프로그래머들은 강제 형변환을 시도한 후 왜 제대로 동작하지 않는가에 대해 많이 궁금해 하곤 한다. 수많은 스트링 타입들, 특히 BSTR 같은 타입은 명확히 문서화 되어있지 않은 게 현실이다. 따라서 많은 사람들은 쉽게 잘못된 코드를 작성할 가능성이 많았다.

    무엇보다 중요한 점은 랩퍼클래스에서 형변환 연산자를 재정의 하지 않았다면 형변환은 사실 스트링 사이에서 아무 일도 하지 않는다. 그래서 만약 아래와 같은 코드를 작성 했다면:

    void SomeFunc ( LPCWSTR widestr );
     
    main()
    {
      SomeFunc ( (LPCWSTR) "C:\\foo.txt" );  // WRONG!
    }

    위의 코드는 백이면 백 잘못된 결과를 초래할 것이다. 사실 위의 코드는 에러 없이 컴파일 된다. 하지만 컴파일이 된다고 그 코드가 옳바르다고 장담할수는 없는 것이다.

    강의를 진행하면서 어떤 형변환이 옳바른 것인지 설명하도록 하겠다.

    C-style strings and typedefs

    지난 강의에서 살펴 보았듯이, Win API는 TCHAR 방식으로 정의되 있다. 그것은 컴파일 시에 문맥에 따라 MBCS방식으로 전환될수도 있고, 유니코드가 될수도 있다. 편의를 위해 지난 강의에 보여줬던 표를 다시 보여 주도록 하겠다.

    타입 MBCS환경에서 유니코드 환경에서
    WCHAR wchar_t wchar_t
    LPSTR 0으로 끝나는 char형의 문자열(char*) 0으로 끝나는 char형의 문자열 (char*)
    LPCSTR 0으로 끝나는 const char형의 문자열 (const char*) 0으로 끝나는 const char형의 문자열 (const char*)
    LPWSTR 0으로 끝나는 유니코드형의 문자열 (wchar_t*) 0으로 끝나는 유니코드형의 문자열 (wchar_t*)
    LPCWSTR 0으로 끝나는 const 유니코드형의 문자열 (const wchar_t*) 0으로 끝나는 const 유니코드형의 문자열 (const wchar_t*
    TCHAR char wchar_t
    LPTSTR 0으로 끝나는 TCHAR형의 문자열 (TCHAR* -> char* 0으로 끝나는 TCHAR형의 문자열 (TCHAR*->wchar_t*)
    LPCTSTR 0으로 끝나는 const TCHAR형의 문자열 (const TCHAR*) 0으로 끝나는 const TCHAR형의 문자열 (const TCHAR*)

    타입을 하나 추가 하자면 OLECHAR을 들수 있겠다. 이 타입은 주로 자동화 인터페이스에서 사용된다. 이 타입은 보통 wchar_t 으로 정의되 있으나, 셋팅을 변경하거나 #define 문으로 OLE2ANSI 를 정의하면 단순 char 타입으로 전환된다. 하지만 사실상 요즘엔 OLE2ANSI 를 적용할 이유는 없다. (사실, MFC3 버젼에서 사용되어졌던 것이다. 구시대의 유물^^), 따라서 지금부터 그냥 단순히 OLECHAR 타입을 유니코드로 간주할 것이다.

    아래의 표는 OLECHAR 와 관계된 typedef 문으로 정의된 데이터 타입을 보여준다. :

    타입 의미
    OLECHAR 유니코드 케릭터 (wchar_t)
    LPOLESTR 유니코드 스트링 (OLECHAR*)
    LPCOLESTR const 형 유니코드 스트링 (const OLECHAR*)

    문자열을 다룰 때 유니코드 MBCS 방식에 관계없이 일관된 표현을 할수 있게 해주는 두가지 마크로가 있다. _T 마크로는 지난 강의에서도 다루었던 부분이다. :

    마크로 의미
    _T(x) L 유니코드빌드일때 L을 앞에 주가해 준다.
    OLESTR(x) LPOLESTR 타입으로 만들기 위해 L을 앞에 추가해 준다.

    또한 _T에서 변형된 형태의 하지만 같은 역활을 하는 몇몇 마크로 들이 더 있다. -- TEXT, _TEXT, __TEXT, and __T 이 마크로 들은 모두 같은 일을 한다.

    COM에서의 스트링 - BSTR

    많은 자동화객체 인터페이스나 COM 인터페이스는 스트링으로 BSTR 타입을 사용한다. 하지만 BSTR타입은 다루기 매우 까다롭고, 에러를 유발하기 쉽다. 따라서 BSTR을 이번 파트에 다뤄 보도록 하겠다.

    BSTR 타입은 파스칼 스타일의 스트링과 C 스트링 사이의 잡종 즉 서로 짬뽕되서 생긴 타입이다. 파스칼에서는 문자열타입에 그 길이가 내부적으로 저장된다. 하지만 C스트링에서는 마지막 제로바이트를 통해서 그 문자열의 끝을 알수있게끔 되어 있다. 사실 BSTR 타입은 문자일 길이를 문자열 시작 바로 전에 저장하고 이어서 유니코드 스트링을 저장하는 방식의 타입니다. 또한 제로바이트로 그 끝을 표시한다. 아래는 "Bob" 이라는 BSTR 타입의 스트링의 메모리 구조를 보여준다.:

    06 00 00 00  42 00  6F 00  62 00  00 00

    길이

    B

    o

    b

    스트링끝

    눈치채셨다 시피 문자열의 길이가 DWORD타입으로 (즉 4바이트) 실제 문자 앞에 저장된다. 하지만 이는 마지막 00 00의 제로바이트를 포함하지 않은 길이 이다. 위의 경우 "Bob" 문자열은 총 6바이트의 3개의 유니코드 캐릭터를 가지고 있다. 길이 정보를 포함하는 이유는 COM 라이브러리가 다른 곳으로 마샬링 될때 얼마나 많은 바이트를 보내야 하는지 그 정보가 필요하기 때문이다. (사실, BSTR 은 단지 스트링뿐만 아니라 임의의 어떤 데이타가 들어 있어도 상관이 없다.)

    BSTR 변수는 C++에서 첫번째 캐릭터를 가리키는 포인터 변수 이다. BSTR 타입은 이렇게 정의 되있다. :

      typedef OLECHAR* BSTR;

    불행히도 이런방식의 정의는 많은 문제를 유발할수 있다. 위에서도 설명했듯이 실제로는 BSTR은 유니코드 스트링과는 다른 특성을 가진 타입이다. 따라서 BSTR과 LPOLESTR은 마음대로 섞어 써도 컴파일러는 에러를 발생하지 않는다. LPOLESTR을 인자로 받는 함수에 BSTR 타입을 전달하는 것은 안전하다. 그렇지만 그 반대의 경우는 다르다. 따라서 함수가 받는 인자의 타입을 정확히 알고 정확히 전달하는 것이 중요하다.

    BSTR 타입을 받는 함수에 LPOLESTR을 전달하는것이 왜 안전하지 못하냐 하면, BSTR이 가리키는 메모리 바로 앞 4바이트는 그 문자열의 길이를 포함하는 정보를 담고 있어여 한다. 아마 BSTR을 받는 함수에서는 그 정보가 포함되 있다는 가정하에 그 정보를 이용할 것이다. 하지만 LPOLESTR 타입에는 그러한 정보는 없다. 이는 안전하지 못한 결과를 낳을 것이다. 위에서 말했다 시피 COM객체에서는 BSTR 의 문자열 앞에 존재하는 문자열길이 정보를 이용해 그 만큼의 데이터를 전송한다고 있다. BSTR대신 LPOLESTR을 전달하면 얼마만큼의 바이트가 전송될지는 아무도 장담할 수가 없게 되는 것이다.

    따라서 BSTR을 다루기 위한 몇몇 API들이 존재하지만 그중 가장 중요한 것은 두가지 이다. 하나는 BSTR을 생성시키기 위한 것이고, 다른하나는 제거하기 위한 것이다. BSTR을 생성하는 함수는 SysAllocString() 이고 제거하는것은 SysFreeString()이다.  SysAllocString() 은 매개변수로 받은 유니코드 스트링을 BSTR형태로 만들어 주는 역할은 한다. (새로운 메모리를 할당한 후에 아마 문자열 길이를 계산해서 문자열 앞에 그 길이정보를 추가해 주는 정도의 일을 할 것이다.) 반면 SysFreeString()BSTR 을 메모리에서 제거하는 역할을 한다.

    BSTR bstr = NULL;
     
      bstr = SysAllocString ( L"Hi Bob!" );
     
      if ( NULL == bstr )
        // 메모리가 부족
     
      // bstr을 마음껏 사용^^
     
      SysFreeString ( bstr );

    사실, 스트링 하나 사용하겠다고 이런 일련의 함수를 계속적으로 사용하는 것은 굉장히 피곤하다. 따라서 자연스럽게 메모리 할당, 제거를 자동적으로 해주는 몇몇 랩퍼 클래스들이 생겨나게 됐다. 그에 대해서 뒤에 살펴보기로 하자.

     

    AND

    출처: http://www.jigi.net/2281?category=0


    Chapter 2. Kernel Object
    Copyright© 1998 by chpark95
    Without my agreement, You can’t use this material for commercial purpose.

    WHAT IS KERNEL OBJECT?        2
    USAGE COUNTER        2
    SECURITY        3
    A PROCESS’S KERNEL OBJECT HANDLE TABLE        4
    CREATING A KERNEL OBJECT        4
    CLOSING A KERNEL OBJECT        5
    SHARING KERNEL OBJECTS ACROSS PROCESS BOUNDARIES        6
    OBJECT HANDLE INHERITANCE        6
    CHANGING THE HANDLES FLAGS        8
    NAMED OBJECTS        8
    DUPLICATING OBJECT HANDLES        10


      윈도우 시스템에 대한 이해는 일단 커널 오브젝트(Kernel Object)를 이해하는 것에서부터 출발한다.  이 장에서는 각각의 커널 오브젝트를 그리 상세히 다루지는 않는다.  대신 커널 오브젝트의 개념을 다룸으로써 윈도우 시스템의 전반적인 이해를 돕도록 하겠다.

    What is Kernel Object?
    커널 오브젝트란 무엇인가를 논하기 전에 커널 오브젝트에는 무엇이 있는가를 먼저 살펴보겠다.
    1.        Event Objects
    2.        File-mapping objects
    3.        File objects
    4.        Mailslot objects
    5.        Mutex Objects
    6.        Pipe Objects
    7.        Process Objects
    8.        Semaphore Objects
    9.        Thread Objects
    위에 있는 것들을 통칭하여 커널 오브젝트라고 한다.  커널 오브젝트는 커널에 의하여 관리되며 System-wide하게 존재한다.  각 커널 오브젝트의 실상은 사실 커널 메모리내에 존재하는 구조체라고 볼 수 있다.  예를 들어 파일 오브젝트를 생각해보자.  파일이라는 것은 원래 자신의 시스템 상에 오직 하나만 존재하며(같은 이름의 파일이 있으면 어떻해요?..  라든가 이런류의 질문은 하지 말기를..)  만약 사용자가 CreateFile() 등의 함수를 이용하여 파일 오브젝트를 생성하게 되면 커널안에 파일에 관련된 구조체가 생성되고 시스템 전체에서 오직 하나만 관리되게 된다.  따라서 하나의 파일 오브젝트는 여러 프로세스에서 공유될 수 있다.  또한 모든 커널 오브젝트는 비록 구조체 형태로 존재하기는 하지만 사용자가 바로 이 구조체에 접근하여 필드값들을 바꿀 수는 없다.  대신 바로 Win32 API를 이용하여 이 구조체에 접근하여 값을 읽고 설정할 수 있다.  만약 여러분이 OS를 배웠다면 OS에서의 시스템 콜에 대한 개념에 대하여 알고 있을 것이며 위의 이야기와 시스템 콜의 개념이 매우 비슷하다는 것을 알 수 있을 것이다.  윈도우 커널은 생성된 커널 오브젝트에 대한 프로세스내에서만 통용되는 DWORD(32-bit)값의 커널 오브젝트 ID를 사용자에게 리턴하게 되고 사용자는 이 핸들(통상 이런걸 핸들이라고 부른다.  윈도우 핸들, 파일 핸들..)과 Win32 API를 이용하여 커널 오브젝트를 manage하게 된다.

    Usage Counter
    커널 오브젝트는 그 커널 오브젝트를 생성한 프로세스가 아닌 커널 자체에 포함된다.(무슨말인지..  헷갈릴 것이다.)  예를 들어 A라는 프로세스가 Kernel-A라는 커널 오브젝트를 생성했다고 하자.  만약 A가 작업을 끝내고 죽는다면 Kernel-A라는 커널 오브젝트로 죽게될까?  답은 그럴수도 있고 아닐수도 있다이다.  만약 A프로세스가 생성한 Kernel-A 오브젝트를 B라는 프로세스에서 사용하고 있다면 A프로세스가 죽어도 Kernel-A 오브젝트는 계속 커널 위의 메모리에 남게 될 것이다.  커널은 이러한 관리를 위하여 Usage Count라는 것을 생성된 커널 오브젝트마다 유지하고 있다.(흠..  이부분은 만약 COM을 공부하는 분이 있다면..  쉽게 이해할 것이다.)

    Security
    커널 오브젝트는 기본적으로 보안 항목(Security Descriptor)을 가지고 있다.  예를 들어 자신을 생성한 것은 누구이며, 누가 커널 오브젝트에 접근할 수 있나등등..  이 부분은 주로 서버 프로그램에서 주로 사용하는 기능이며, 따라서 윈도우95/98에서는 해당사항이 없다.  커널 오브젝트를 생성하는 거의 모든 Win32 API들은 SECURITY_ATTRIBUTES 라는 매개변수 필드를 가지고 있다.  물론 윈도우95/98의 커널 오브젝트 생성 Win32 API에도 이 매개변수 필드는 있다.(당연하지..  같은 Win32 API를 쓰는데..  전에도 이야기했지만 Win32 API는 윈도우 95/98/NT/CE/2000에서 공통으로 쓰이는 프로그래밍 인터페이스다.)  그러나 실제로 이 필드에 어떠한 값을 넣어도 윈도우 95/98은 이 값을 무시한다.  다시 본론으로 돌아가서 하나 예를 들어보자.  다음의 CreateFileMapping이라는 함수는 Memory-Mapped File을 생성할때 쓰이는 함수이다.  여하튼 이 함수의 원형을 보면,
    HANDLE CreateFileMapping(        HANDLE hFile,
    LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
    DWORD flProtect,
    DWORD dwMaximumSizeHigh,
    DWORD dwMaximumSizeLow,
    LPCTSTR lpName                );

    두번째 파라미터가 바로 이 커널 오브젝트에 보안을 설정하는 파라미터이다.  대부분의 경우는 이 부분에 NULL값을 대입한다.  그렇게 되면 기본값이 설정된다.  기본 설정은 이 커널 오브젝트를 만든 사용자(시스템 로그온한 아이디로 구별)에게 최대한의 접근을 허용하고  다른 사용자는 접근거부하는 것이다.  그럼 여기서 SECURITY_ATTRIBUTES 구조체를 살펴보도록하자.
    typedef struct _SECURITY_ATTRIBUTES {
            DWORD         nLength;
            LPVOID         lpSecurityDescriptor;
            BOOL         bInheritHandle;
    } SECURITY_ATTRIBUTES;

    nLength는 이 구조체의 크기를 나타내는 것이며, 세번째의 bInheritHandle은 뒤에 나오니 설명 생략한다.  마지막으로 가운데 값이 바로 Security Descriptor에 대한 포인터값이 된다.  예제 코드를 들자면
    SECURITY_ATTRIBUTES sa;
    sa.nLength = sizeof(sa);
    sa.lpSecurityDescriptor = pSD;
    sa.bInheritHandle = FALSE;
    HANDLE hFileMapping = CreateFileMapping((HANDLE)0xffffffff, &sa, PAGE_READWRITE, 0, 1024, “MyFileMapping”);

    커널 오브젝트에 덧붙여서, 커서, 마우스 포인터, 아이콘, GDI Object(font, brush, window..)등의 오브젝트들도 존재한다.  이러한 오브젝트들도 System-wide하게 존재하며 커널이 관리한다.  그러나 이것들을 커널 오브젝트라고 부르지는 않는다.  위에 나열한 것들은 통상 User Object, GDI Object라고 부른다.  그렇다면 커널 오브젝트와 사용자 오브젝트(흠..  말이 길어서 줄여씀..)의 차이점은 무엇일까?  그것은 바로 사용자 오브젝트에는 보안 설정이 존재하지 않는다는 것이다.  예를 들어 아이콘 같은 경우는 누가 가져다 쓰던 문제가 되지 않을 것이다.  따라서 사용자 오브젝트를 생성하는 함수에는 보안 필드가 빠져있다.

    A Process’s Kernel Object Handle Table
    다음에 나오는 내용은 제프리가 자기 예상에 윈도우 커널에는 분명히 이런 구조가 있을 것이다라고 예상하고 쓴 것이므로 믿지 말기 바란다.  이 내용 자체가 MS에서만 알고 있는 비밀이고 따라서 어떠한 문서도 없으므로 아래의 내용이 사실이라고 확인 할 수가 없다.  그러니 제프리의 말처럼 이 내용을 윈도우 시스템이 이렇게 되어 있구나 하고 배울 생각으로 보지말고 같은 프로그래머의 입장에서 같이 생각해보는 입장으로 보기를 바란다.  
    일단 맨 처음 프로세스가 생성되면 다음과 같은 핸들 테이블을 생성할 것이다.
    index        커널 오브젝트에 대단 메모리 블록 주소        Access Mask        Flags
    1        0x????????        0x????????        0x????????
    2        0x????????        0x????????        0x????????
    …        …        …        …

    Creating a Kernel Object
    처음 프로세스가 생성되면 위의 핸들테이블은 빈 상태가 된다.  만약 프로세스에서 처음으로 커널 오브젝트를 생성하게되면 (예를 들어 CreateFileMapping() 등의 함수를 호출하여서..) 커널은 일단 프로세스의 핸들 테이블에서 빈 자리를 찾게되고, 지금의 경우는 프로세스가 생성된 후, 처음 커널 오브젝트를 생성하는 것이므로 맨 처음 인덱스에 해당되는 커널 오브젝트 구조체(앞에서 이야기했음)의 시작주소를 넣고, Access 필드와 Inheritance 필드를 채우게 된다.  다시 말하지만 커널 오브젝트 구조체는 커널 내부에 존재하게 된다.  다음의 함수들은 여러 종류의 커널 오브젝트를 만드는 함수들이다.
    HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId);

    HANDLE CreateFile(LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDistribution, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile);

    HANDLE CreateFileMapping(HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCTSTR lpName);

    HANDLE CreateSemaphore(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount, LPCTSTR lpName);

    위의 함수들은 전부 다 커널 오브젝트에 대한 핸들값을 리턴한다.  실제 이 핸들값들은 핸들 테이블에서의 커널 오브젝트의 인덱스 값이라고 볼 수 있다.(그러나 이 핸들값이라는 것이 MS에 의하여 공식적으로 설명된 적이 없기 때문에 꼭 그렇다고 볼 수는 없다.)  그리고 진짜 중요한 것은 이 커널 오브젝트에 대한 핸들값은 process-relative 하다는 것이다.  이게 왜 중요하냐하면 이 커널 오브젝트에 대한 핸들값이 process-relative 하기 때문에 절대로 이 프로세스 외부의 다른 프로세스에서 이 핸들값으로 커널 오브젝트를 접근할 수 없다는 것이다.  커널 오브젝트는 커널 레벨에서 존재하며 커널이 관리한다.  따라서 system-wide하게 단 하나만 존재한다.  이것은 다른 프로세스에서도 이 커널 오브젝트를 사용할 수 있다는 것이 된다.  그러나 다른 프로세스에서 생성한 커널 오브젝트에 접근하기 위해서는 그냥 커널 오브젝트 핸들값을 넘겨주는 등의 작업과는 다른 작업이 이루어져야한다.  그 이유는 앞에서 이야기한대로 커널 오브젝트에 대한 핸들값이 process-relative하기 때문이다.

    Closing a Kernel Object
    프로세스 내에서 생성한 커널 오브젝트를 시스템에 반환하는 함수는 다음과 같다.
    BOOL CloseHandle(HANDLE hobj);
    여기서 또 주의할 점은 이렇게 커널 오브젝트에 대한 핸들을 닫아준다고 해서 커널 오브젝트가 없어지는 것은 아니라는 것이다.  실상 위의 함수를 이용해 핸들을 닫아주면 일단 커널은 그 프로세스의 핸들 테이블에서 해당하는 핸들값이 있는 인덱스를 클리어시킨다.  그리고 나서 그 커널 오브젝트에 대한  Usage Count를 살펴보고, 만약 0이라면 커널에서 삭제하고 아니라면 그냥 살려둔다.  한번 CloseHandle을 하게되면 그 순간부터 닫힌 커널 오브젝트는 그 프로세스내에서 Invalid 하다.  
    만약 프로그래머가 잘못하여 핸들을 닫지 않았다고 생각해보자.  그렇다고 하더라도 그 프로세스가 죽을때가 되면 커널이 알아서 커널 오브젝트에 대한 Usage Count를 내려주게 된다.  그러나 그 프로세스가 실행되고 있는 동안에는 닫지 않은 커널 오브젝트에 대한 리소스는 낭비되고 있는게 사실이다.  따라서 왠만하며 사용이 끝난 커널 오브젝트는 그 즉시 닫아 주는 것이 좋다.

    Sharing Kernel Objects Across Process Boundaries
    앞에서도 이야기하였지만 커널 오브젝트는 system-wide하게 유지되는 것이며 따라서 그 커널 오브젝트를 만든 프로세스내의 쓰레드 뿐만 아니라 다른 프로세스의 쓰레드에 의해서도 접근가능해야한다.  다음의 예는 커널 오브젝트가 프로세스 사이에 공유되는 경우에 대한 예들이다.

    1.        File-mapping 객체는 두개의 프로세스 사이에 특정 데이터 블록을 공유할 때 쓰일 수 있다.
    2.        Named pipes 같은 경우는 서로 다른 머신(네트워크로 연결된)사이에 일정한 데이터 블록을 전송할 때 쓰일 수 있다.
    3.        Mutex, semaphores, event 들은 다른 프로세스내의 쓰레드들 사이에 동기화가 필요할 때 쓰일 수 있다.

    위의 경우중 3번째 경우는 자바의 synchronized와 같은 경우일 것이다.  
      그러나 문제는 커널 오브젝트에 대한 핸들이 process-relative하다는 것이 문제이다.  어떠한 방법으로 커널 오브젝트에 대한 핸들을 다른 프로세스에게 넘겨준다 하더라도 그 값은 그것을 생성한 프로세스내에서만 의미가 있기 때문에 넘겨받은 프로세스로서는 그것을 가지고 그 커널 오브젝트에 접근할 방법이 없다.  “공유하는 경우가 많은데, 프로세스 사이에 커널 오브젝트 핸들을 공유못하게 한다면 뭔가 잘못되지 않았는가?” 뭐, 이렇게 반문할 수도 있다.  MS쪽에서 이런식으로 커널 오브젝트를 설계한 이유는 다음의 두가지이다.  첫째는 보안문제이며, 두번째는 시스템의 성능때문이다.  뭐, 이것들에 대한 설명은 책에도 자세히 있는바, 어차피 지금 우리가 당면한 문제는 그냥 커널 오브젝트 핸들을 넘겨주는 것으로는 공유가 안된다는 것이고, 그렇다면 공유하는 방법이 있을 것이 분명하다.  다음의 방법들을 잘 읽어보고 그 방법을 터득하기 바란다.(노파심에서 이야기지만, 지금은 이게 뜬구름 잡는 것처럼 들릴지도 모른다.  그러나, 아주 많이 쓰인다.  꼭 알아두길..)

    Object Handle Inheritance
    이 방법은 한 프로세스가 자신의 자식 프로세스를 spawn 할때만 가능한 방법이다.  우리가 커널 오브젝트 생성 함수들을 볼 때 파라미터로 넘겨주는 SECURITY_ATTRIBUTES 구조체에 bInheritHandle 이라는 필드가 끼어 있는 것을 본 것이 기억날 것이다.  바로 이 부분에  TRUE를 넣어주게 되면 이 값을 파라미터로 받아서 생성된 커널 오브젝트는 그 자식 프로세스에게 물려줄 수 있는 상태가 된다.  뭐, 좀 자세히 예를 들어서 설명하면,
    SECUTIRY_ATTRIBUTES sa;
    sa.nLength = sizeof(sa);
    sa.lpSecurityDescriptor = NULL;
    sa.bInheritHandle = TRUE;
    HANDLE hMutex = CreateMutex(&sa, FALSE, NULL);
    .
    뭐, 이렇게 Mutex를 생성했다고 하자.  그렇게 되면 일단 이 커널 오브젝트를 생성한 프로세스의 핸들 테이블은 다음과 같은 상태가 될 것이다.

    index        커널 오브젝트에 대단 메모리 블록 주소        Access Mask        Flags
    1        0x????????        0x????????        0x????????
    2        0xF0000000        0x????????        0x00000001
    …        …        …        …

    위의 표에서 두번째 행에 바로 이 Mutex에 대한 정보가 들어가게 될 것이다.  두번째 행의 맨 끝 열을 보면 플래그가 1로 세팅되어 있는 것을 볼 수 있다.  이것은 위에서 우리가 bInheritHandle을 TRUE로 세팅했기 때문이다.  흠..  일단 이상태에서 이 프로세스가 자신의 자식 프로세스를 생성한다고 해보자.  자식 프로세스를 생성하는 함수는 다음과 같다. (너무 많은 파라미터를 보고 놀라지 말기를..)
    BOOL CreateProcess(LPCTSTR lpApplicationName, LPTSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCTSTR lpCurrentDirectory, LPSTARTUPINFO lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation);
    위의 파라미터 중 bInheritHandles라는 파라미터를 TRUE로 세팅하게 되면 그때부터 이 자식 프로세스는 자기 부모 프로세스의 커널 오브젝트 핸들 중 bInheritHandle(부모 프로세스의 핸들테이블에서..)가 TRUE인 것을 물려받게 된다.  좀 자세히 설명하면 일단 위의 함수를 실행하면 커널은 프로세스를 만들고 그 프로세스에 대한 핸들 테이블도 생성한다.  그 다음 만약 bInheritHandles 파라미터가 TRUE라면 커널은 일단 부모 프로세스의 핸들 테이블을 뒤져서 세번째 열이 TRUE인 인덱스에 있는 커널 오브젝트들을 그대로 카피해서 자식 프로세스의 핸들테이블에 집어 넣는다.  여기서 중요한 것은 만약 부모 프로세스에 2번째 행에 있었으면 자식 프로세스의 핸들 테이블에도 2번째행에 들어간다.  진짜 카피하는 것이다.  이렇게 되면 그때부터 자식 프로세스도 그 커널 오브젝트를 사용할 수 있게 된다.  그러나 이방법에 한가지 문제가 있다.  생성된 자식 프로세스가 어떠한 방법으로든 자신이 어떤 커널 오브젝트의 핸들을 물려받았으며, 그 핸들값이 무엇인지를 알아야한다는 것이다.  다시 한번 이야기하지만 자식 프로세스 핸들 테이블에 카피 된 것은 카피 된것이고 자식 프로세스가 이 커널 오브젝트를 사용하기 위해서는 그 핸들값을 알아야한다.(사실 정확히 이야기하면 그 핸들값이라는 것이 바로 핸들 테이블에서의 인덱스 값이다…)  이 문제는 일단 자식과 부모사이에, 그러니까 프로그래머가 프로그램을 만들 때, 두 프로그램을 전부다 알고 있어야한다는 것이다.  만약 프로그래머가 뻔히 “이 프로그램이 이놈을 생성할때는 이런 핸들값을 넘긴다” 알고 있을 때만 가능하다는 것이다.  만약 그렇다면 뭐, 문제야 간단하다.  그냥 생성될 때 코맨드라인으로 핸들값만 넘기면 된다.  결론을 이야기하자면 이 방법은 별로 안쓴다.(^.^)

    Changing the Handles Flags
    이건 생략..  복잡하고, 잘 쓰지 않는다.

    Named Objects
    가장 많이 쓰는 방법으로서 커널 오브젝트를 생성할 때 이름을 준후 다른 프로세스에서 같은 이름으로 커널 오브젝트를 찾으면 있는 경우는 그 커널 오브젝트를 넘겨주는 방법이다.(흠..  한마디로 쉽다..)  다음과 같은 커널 오브젝트 생성함수를 보도록 하자.

    HANDLE CreateFileMapping(HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCTSTR lpName);

    HANDLE CreateSemaphore(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount, LPCTSTR lpName);

    HANDLE CreateEvent(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL lInitialCount, LONG lMaximumCount, LPCTSTR lpszName);

    HANDLE CreateWaitableTimer(LPSECURITY_ATTRIBUTES lpTimerAttributes, BOOL bManualReset, LPCTSTR lpszName);

    HANDLE CreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCTSTR lpszName);
      위 함수들의 공통점은 모두 다 마지막에 lpszName 파라미터를 가지고 있다는 것이다.  이것이 바로 이 커널 오브젝트의 이름이 된다.  물론 이 값에 NULL을 줄수도 있지만  만약 이 커널 오브젝트 system-wide하게 공유되길 바란다면 이 부분에 이름을 주어야 한다.  다음과 같은 예를 들어보자.
    HANDLE hMutexA = CreateMutex(NULL, FALSE, “chparkmutex”);

    이 다름에 다른 프로세스에서 다음과 같이 한다면
    HANDLE hMutexB = CreateMutex(NULL, FALSE, “chparkmutex”);
    이 함수를 실행시키면 일단 커널은 커널에 chparkmutex라는 이름의 커널 오브젝트가 있는지 검사한다.  만약 있다면 그 다음에는 타입을 검사한다.  다행이도 이 경우는 두가지 다 Mutex를 만든 것이므로 타입도 같다.  그렇게 되면 커널은 새로 커널 오브젝트를 만드는 것이 아니라 기존에 있던 chparkmutex라는 이름을 가진 Mutex 오브젝트의 핸들값을 리턴하고 단지 이 커널 오브젝트의 Usage Count를 하나 증가시킨다.  그러나 만약 다음과 같이 한다면
    HANDLE hSemB = CreateSemaphore(NULL, 1, 1, “chparkmutex”);
    이 코드를 실행시키면 일단 같은 이름을 가진 커널 오브젝트가 있는 것 까지는 괜챦지만, 타입 체크시 에러가 난다.(당연하겠지..)
    그러나 이 방법에도 맹점은 존재한다.  무엇인고 하니 뭐,  타이핑을 잘못하여 이름이 조금 틀려서 chparkmutec이라고 쳤다고해보자.  그러면 일단 커널이 볼때는 이런 이름을 가진 커널 오브젝트가 없으니 새로 하나 만들어서 그 핸들 값을 리턴할 것이다.  이는 우리가 원하는 일이 아니다.  그러나 에러가 안나니 제대로 되는지 전혀 알 수 없다.  이러한 것을 막기 위한 함수들이 존재하는데 다음과 같다.

    HANDLE OpenMutex(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTR lpszName);

    HANDLE OpenEvent(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTR lpszName);

    HANDLE OpenSemaphore(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTR lpszName);

    HANDLE OpenWaitableTimer(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTR lpszName);

    HANDLE OpenFileMapping(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTR lpszName);

      이 함수들을 쓰게 되면 만약 같은 이름을 가진 커널 오브젝트가 없다면 에러를 내게된다.  따라서 함수의 수행이 제대로 되는지 정확히 판단 할 수 있게된다.  결국은 만들어놓은 커널 오브젝트를 얻고자 한다면 Create.. 보다는 Open..을 써야한다는 것이다.

    Duplicating Object Handles
    어~~  머리아파..  뭐, 위에 이름을 이용한 방법이 최고로 많이 쓰인다..  나머지는 읽어봐..  나도 머리아파..
    AND

    출처: http://devdev.tistory.com/348

    Ansi <-> Unicode(유니코드)

     

    간단하게 Unicode는 char를 2 byte로 보고 Ansicode는 1byte로 본다.

    기본적으로 아무 생각안하고 프로그램을 작성 하였다면 Ansicode로 보면 된다.

     

    1. Project -> setting 으로 들어가 컴파일 옵션에 추가해 준다.

     

     

    2. 코드 수정

       "......" 로 묶여져 잇는 부분을 _T(".....")로 바꿔준다.

     

      char -> TCHAR
      LPSTR -> LPTSTR
      LPCSTR -> LPCTSTR

     

      strcpy -> _tcscpy
      strlen -> _tcslen
      strcmp -> _tcscmp

     

      fopen -> _tfopen
      atof -> _tcstod
      atoi -> _ttoi
      atol -> _ttol 

      rename -> MoveFile

     

    3. Unicode <-> Ansicode 유용한 매크로

      #include <atlconv.h>

      USES_CONVERSION;

      Uncode     ->   Ansicode : ANSICODE = T2A(UNICODE)

      Ansicode  ->   Unicode : UNICODE = A2T(ANSICODE)

     

      추가적으로 설명하자면 위의 매크로는 다음 함수이다.

      - T2A 매크로를 따라가 보면 WideCharToMultiByte 임.

      - A2T 매크로를 따라가 보면 MultiByteToWideChar 임.

     

     4. 컴파일에 필요한 파일들 (For Unicode)

       mfc42u.lib
       mfcs42u.lib
       mfcs42u.pdb
      

       복사해 줄 위치

       CD-ROM Drive:\VC98\MFC\LIB
       C:\Program Files\Microsoft Visual Studio\VC98\MFC\Lib

     

    출처: http://tong.nate.com/thisbe71/24531967




    AND

    출처: http://www.codeproject.com/KB/locale/Unicode_Edit_Box.aspx?display=Print


    How to extract Unicode strings (Japanese) from an MFC edit control

    By Chaitanya Seshadri

    How to extract any Unicode string from an MFC edit box.
    C++, Windows, Visual Studio, MFC, Dev

    Posted: 20 Oct 2006
    Updated: 20 Oct 2006
    Views: 13,747
    Bookmarked: 7 times
    10 votes for this Article.
    Popularity: 1.88 Rating: 1.88 out of 5
    7 votes, 70.0%
    1
    1 vote, 10.0%
    2
    1 vote, 10.0%
    3
    0 votes, 0.0%
    4
    1 vote, 10.0%
    5

    Introduction

    This project is a small demo to show how VC++ can be used for localization of existing products.

    Windows 2000 is the suggested OS, as it was completely built on Unicode, and though NT was built on Unicode too, using its full capabilities is difficult. Visual Studio and Visual C++ were used to implement this tool.

    Japanese language is used as an example to implement the case.

    Overview

    Before we get our hands dirty, let us understand the distinction between Internationalization and Localization.

    Internationalization versus Localization

    For the software development process, internationalization means to prepare an application so that the code does not need to be modified each time an additional language is to be displayed. Separate files contain all of the translatable information.

    Localization of an application means to change it to be able to handle a particular language and locale. To localize a program that has already been internationalized involves no changes to the source code. Instead, translatable files are sent to the product or a contractor translation agency for modification.

    For a system to support multiple languages, we need to:

    • Windows 2000 or XP.
    • Visual Studio and Visual C++.

    Setting up Windows 2000 or XP

    Step 1: Install the Japanese language pack.

    Navigate to Start menu->Control Panel->Regional Options->General. Once in the General tab, check the check box left to the Japanese language from the language settings for the System tab.

    Sample screenshot

    Step 2: Setting the input locale.

    Navigate to Start menu->Control Panel->Regional Options->Input Locale. Under the Installed Input Locales section, click Add. From the Input Locale drop down list, select Japanese, and for the Keyboard Layout/IME drop down box, select Japanese Input System (MS-IME2000).

    Sample screenshot

    Step 3: Setting the default locale.

    In the Control Panel - Regional Options, under the General tab, scroll down the list for Language Settings for the System. Highlight Japanese, and click Set Default. Once done, verify it did not change your Input Locale default input language. Click OK.

    Sample screenshot

    Setting up Visual C++ for Unicode compilation

    Step 1: To Unicode enable a project in VC++: in the VC++ IDE, navigate to Project->Settings->C++, in the Preprocessor definitions section, insert WIN32,_DEBUG,_WINDOWS,_AFXDLL,_UNICODE, as normal MFC uses WIN32,_DEBUG,_WINDOWS,_AFXDLL,_MBCS.

    Sample screenshot

    Once _UNICODE has been defined for your project, a few steps need to be taken to ensure that string handling is done properly.

    The first thing you need to understand is that the use of a char or char* for strings is no longer valid. TCHAR should be used in place of this. However, for binary data processing, use of char, char*, and BYTE (typedefed as an unsigned char) are still OK.

    From MSDN:
    • Except for database class member functions, all MFC functions are Unicode-enabled, including CString. CString also provides Unicode/ANSI conversion functions.
    • The run-time library supplies Unicode versions of all string-handling functions. (The run-time library also supplies “portable” versions suitable for Unicode or for MBCS. These are the _tcs macros.)
    • TCHAR.H supplies portable data types and the _T macro for translating literal strings and characters. See Generic-Text Mappings in TCHAR.H.
    • The run-time library provides a wide-character version of main. Use wmain to make your application “Unicode-aware.”

    Step 2: Navigate to the Link tab and select Output in the drop down list in the Category section, and specify wWinMainCRTStartup as the entry point for the program, in the Entry-point symbol edit box.

    Sample screenshot

    Hurry !!! Now, we are all set to build a small application with a dialog box which accepts Japanese language codes and outputs the same text in the output window.

    Implementation

    // I am trying to collect stones from the ocean of knowledge...
    // Today I learnt it how to extract unicode information from
    // edit box which is not supported by MFC but taken help from
    // win32 SDK function, named ::GetWindowTextW() 
    void CUnicode_DialogDlg::OnOK()
    {
      // TODO: Add extra validation here
      USES_CONVERSION;
      CWnd *pWnd=&quot;GetDlgItem(IDC_EDIT_UNICODE);
      LPWSTR lpString = new WCHAR[MAX_PATH];
      ::GetWindowTextW(pWnd->m_hWnd, lpString, MAX_PATH);
      LPWSTR caption = A2W(&quot;Caption&quot;);
      HWND hWnd = this->m_hWnd;
      MessageBoxW(lpString, caption, MB_OK );
      // free the string
      delete[] lpString;
      CDialog::OnOK();
    }
    
    // ******************************* //

    Further reading

    Locale

    Locale programming

    Pros

    The Operating System is responsible for loading the language specific resources.

    Cons

    This project does not demonstrate the conversion of the file dialog and the titles in the application as this is all part of the Windows Common Dialog library.

    License

    This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

    About the Author




    AND

    출처: http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2451129&SiteID=1

     
       

    « Previous Thread
      Next Thread »
      23 Nov 2007, 2:11 PM UTC
    George2
    These stars recognize your participation in the forums. For more information about the different levels of stars, and how points are earned, please see the FAQ.


    Posts 1,149
    SysAllocString
    Answered Question Was this post helpful ?
    Reply Quote

    Hello everyone,

     


    For the SysAllocString API, I am wondering,

     

    1. any special benefits if we use SysAllocString compared with using a simple wide character string, like L"Hello"?

     

    2. If we use SysAllocString to allocate constant string, then does SysAllocString allocate the constant string on heap, stack or on the constant string pool?

     


    thanks in advance,
    George


       Report Abuse  
      23 Nov 2007, 4:20 PM UTC
    Pintu Shukla
    These stars recognize your participation in the forums. For more information about the different levels of stars, and how points are earned, please see the FAQ.


    Posts 1,501
    Re: SysAllocString
    Comment Was this post helpful ?
    Reply Quote
    According to MSDN :-

    This function allocates a new string and copies the passed string into it. This function returns null if there is insufficient memory or if a null pointer is passed in

    BSTR SysAllocString(
    OLECHAR FAR* sz
    );

    sz
    [in] Null-terminated string to copy. The string must be a Unicode string in 32-bit applications, and an ANSI string in 16-bit applications.

    Second thing Because a BSTR allocates memory before the location it nominally points to, a whole different API is necessary for working with BSTRs. For example, one may not initialize a BSTR by saying

    BSTR b = L"A String";


    This will correctly initialize b to a wide character array, but the byte count is uninitialized and so b is not a valid BSTR. The proper way to initialize b is

    BSTR b = :: SysAllocString(L"A String");

     



    Thanx




    Rupesh Shukla

       Report Abuse  
      23 Nov 2007, 4:58 PM UTC
    George2
    These stars recognize your participation in the forums. For more information about the different levels of stars, and how points are earned, please see the FAQ.


    Posts 1,149
    Re: SysAllocString
    Comment Was this post helpful ?
    Reply Quote

    Thanks Pintu,

     

     

     Pintu Shukla wrote:
    According to MSDN :-

    This function allocates a new string and copies the passed string into it. This function returns null if there is insufficient memory or if a null pointer is passed in

    BSTR SysAllocString(
    OLECHAR FAR* sz
    );

    sz
    [in] Null-terminated string to copy. The string must be a Unicode string in 32-bit applications, and an ANSI string in 16-bit applications.

    Second thing Because a BSTR allocates memory before the location it nominally points to, a whole different API is necessary for working with BSTRs. For example, one may not initialize a BSTR by saying

    BSTR b = L"A String";


    This will correctly initialize b to a wide character array, but the byte count is uninitialized and so b is not a valid BSTR. The proper way to initialize b is

    BSTR b = :: SysAllocString(L"A String");

     



    Thanx


     

    I do not quite understand what means,

     

    BSTRs are allocated using COM memory allocation functions. This allows them to be returned from methods without concern for memory allocation.

     

    in the MSDN page you mentioned http://msdn2.microsoft.com/en-us/library/ms221069.aspx

     

    I think when we use SysAllocString to allocate some memory, then we have to *concern* to free it by SysFreeString, why in MSDN, it is mentioned that there is no concern for memory management? Please feel free to correct me if I am wrong.

     

     

    have a good weekend,

    George


       Report Abuse  
      23 Nov 2007, 5:42 PM UTC
    Pintu Shukla
    These stars recognize your participation in the forums. For more information about the different levels of stars, and how points are earned, please see the FAQ.


    Posts 1,501
    Answer Re: SysAllocString
    Answer Was this post helpful ?
    Reply Quote

    Regarding this line "BSTRs are allocated using COM memory allocation functions"

    Few point as i mention in my above post:

    Because a BSTR allocates memory before the location it nominally points to, a whole different API is necessary for working with BSTRs. For example, one may not initialize a BSTR by saying

    BSTR b = L"A String";


    This will correctly initialize b to a wide character array, but the byte count is uninitialized and so b is not a valid BSTR. The proper way to initialize b is

    BSTR b = :: SysAllocString(L"A String");


    Thanx





    Rupesh Shukla

       Report Abuse  
      23 Nov 2007, 6:10 PM UTC
    ildjarn
    These stars recognize your participation in the forums. For more information about the different levels of stars, and how points are earned, please see the FAQ.


    Posts 556
    Re: SysAllocString
    Comment Was this post helpful ?
    Reply Quote

    A BSTR is not a COM object, it is simply a pointer to a specially laid out wide string that is strictly allocated via SysAllocString. The meaning of "BSTRs are allocated using COM memory allocation functions. This allows them to be returned from methods without concern for memory allocation" is not that the string doesn't need to be cleaned up (you must eventually free the string via SysFreeString or it will leak); it means that it is allocated on a COM heap instead of your CRT's heap, so you may return it out of your COM object to another process, and that other process may clean it up (this would not be possible if it were allocated via your process' CRT).

     

    In C++ you typically want to use the _bstr_t class, which will wrap the calls to SysAllocString and SysFreeString for you in a smart-pointer.


       Report Abuse  
      23 Nov 2007, 6:54 PM UTC
    Pintu Shukla
    These stars recognize your participation in the forums. For more information about the different levels of stars, and how points are earned, please see the FAQ.


    Posts 1,501
    Re: SysAllocString
    Comment Was this post helpful ?
    Reply Quote
     ildjarn wrote:
     

    In C++ you typically want to use the _bstr_t class, which will wrap the calls to SysAllocString and SysFreeString for you in a smart-pointer.



    Whenever you plan to use _bstr_t in your code becareful it can create memory leak in your program have a look on this post

    memory leak

    Thanx



    Rupesh Shukla

       Report Abuse  
      26 Nov 2007, 1:10 PM UTC
    George2
    These stars recognize your participation in the forums. For more information about the different levels of stars, and how points are earned, please see the FAQ.


    Posts 1,149
    Re: SysAllocString
    Comment This post has a code sample within it. Was this post helpful ?
    Reply Quote

    Thanks Pintu,

     

     

    I can fully understand your reply. But is your reply answers to my previous question (below)?

     

    BSTRs are allocated using COM memory allocation functions. This allows them to be returned from methods without concern for memory allocation.

     

    My question is why we do not need to concern about memory allocation? We still need to keep in mind when to free (SysFreeString) it. What does the above statement mean?

     

     Pintu Shukla wrote:

    Regarding this line "BSTRs are allocated using COM memory allocation functions"

    Few point as i mention in my above post:

    Because a BSTR allocates memory before the location it nominally points to, a whole different API is necessary for working with BSTRs. For example, one may not initialize a BSTR by saying

    BSTR b = L"A String";


    This will correctly initialize b to a wide character array, but the byte count is uninitialized and so b is not a valid BSTR. The proper way to initialize b is

    BSTR b = :: SysAllocString(L"A String");


    Thanx


     

     

    regards,

    George


       Report Abuse  
      26 Nov 2007, 1:24 PM UTC
    George2
    These stars recognize your participation in the forums. For more information about the different levels of stars, and how points are earned, please see the FAQ.


    Posts 1,149
    Re: SysAllocString
    Comment Was this post helpful ?
    Reply Quote

    Thanks ildjarn,

     

     

    Great reply!

     

     ildjarn wrote:

    A BSTR is not a COM object, it is simply a pointer to a specially laid out wide string that is strictly allocated via SysAllocString. The meaning of "BSTRs are allocated using COM memory allocation functions. This allows them to be returned from methods without concern for memory allocation" is not that the string doesn't need to be cleaned up (you must eventually free the string via SysFreeString or it will leak); it means that it is allocated on a COM heap instead of your CRT's heap, so you may return it out of your COM object to another process, and that other process may clean it up (this would not be possible if it were allocated via your process' CRT).

     

    In C++ you typically want to use the _bstr_t class, which will wrap the calls to SysAllocString and SysFreeString for you in a smart-pointer.

     

     

    regards,

    George


       Report Abuse  
      26 Nov 2007, 2:49 PM UTC
    George2
    These stars recognize your participation in the forums. For more information about the different levels of stars, and how points are earned, please see the FAQ.


    Posts 1,149
    Re: SysAllocString
    Comment Was this post helpful ?
    Reply Quote

    Thanks Pintu,

     

     

    Good learning resource, and I have saved it.

     

     Pintu Shukla wrote:

     ildjarn wrote:
     

    In C++ you typically want to use the _bstr_t class, which will wrap the calls to SysAllocString and SysFreeString for you in a smart-pointer.



    Whenever you plan to use _bstr_t in your code becareful it can create memory leak in your program have a look on this post

    memory leak

    Thanx

     

     

    regards,

    George


    AND

    출처: http://blog.naver.com/kim779?Redirect=Log&logNo=150035365776

    // Array.cpp : Defines the entry point for the console application.
    //
    // 템플릿을 정의할때 두개의 매개변수를 받는 이유는...
    // 템플릿에 사용되는 첫번째 매개변수는 컬렉션 클래스에 저장될 데이터 형식이고
    // 두번째매개변수는 컬렉션 클래스에 데이터를 저장하기 위해 사용하는 멤버 함수의 매개변수 데이터 형식이다..

    #include "stdafx.h"

    CString strData[] = {_T("SUN"), _T("MON"), _T("TUE"),
       _T("WED"), _T("THU"),_T("FRI"), _T("SAT") };

     

    CString strEnglish[] = {
     _T("January"), _T("February"), _T("March"), _T("April"),
     _T("May"), _T("June"), _T("July"), _T("August"), _T("September"),
     _T("October"), _T("Nobember"), _T("December")
    };

    CString strKorean[] = {
     _T("1월"), _T("2월"), _T("3월"), _T("4월"),
     _T("5월"), _T("6월"), _T("7월"), _T("8월"),
     _T("9월"), _T("10월"), _T("11월"), _T("12월"),
    };
     

    void main()
    {
     
     //CArray
     int i;
     CArray <UINT, UINT> array;
     array.SetSize(10);

     for(i=0 ; i < 10 ; i++)
     {
      array[i] = i + 1;
     }

     array.InsertAt(5,20);
     for(i= 0 ; i <array.GetSize() ; i++)
     {
      cout << array[i] << endl;
     }

     

     //CList
     CList <CString, CString> list;
     POSITION pos;
     CString strdata,data;

     for(i = 0 ; i < sizeof(strData)/sizeof(CString) ; i++)
     {
      list.AddTail(strData[i]);
     }

     pos=list.GetHeadPosition();
     while(pos)
     {
      data = list.GetNext(pos);
      cout << data << endl;
     }

     //CMap
     CString strKey, strValue;
     CMap<CString, LPCSTR, CString, CString&> map;

     for(i = 0 ; i < sizeof(strEnglish)/sizeof(CString) ; i++)
     {
      map.SetAt(strEnglish[i], strKorean[i]); 
     }

     pos = map.GetStartPosition();
     for(i = 0 ; i < sizeof(strEnglish)/sizeof(CString) ; i++)
     {
      map.GetNextAssoc(pos, strKey, strValue);
      cout << strKey << strValue << endl;
     }

    }


    AND