Microsoft Windows HTTP Services (WinHTTP) is targeted at middle-tier and back-end server applications that require access to an HTTP client stack.Microsoft Windows Internet (WinINet) provides an HTTP client stack for client applications, as well as access to the File Transfer Protocol (FTP), SOCKSv4, and Gopher protocols. This overview can help determine whether porting your WinINet applications to WinHTTP would be beneficial. It also describes specific conversion requirements.
Opposite behavior of the ICU_ESCAPE flag: with InternetCrackUrl, this flag causes escape sequences (%xx) to be converted to characters, but with WinHttpCrackUrl, it causes characters that must be escaped from in an HTTP request to be converted to escape sequences.
Be aware that in WinINet and WinHTTP, some functions can complete asynchronous requests either synchronously or asynchronously. Your application must handle either situation. There are significant differences in how WinINet and WinHTTP handle these potentially asynchronous functions.
WinINet
Synchronous completion: If a potentially asynchronous WinINet function call completes synchronously, the OUT parameters of the function return the results of the operation. When an error occurs, retrieve the error code by calling GetLastError after the WinINet function call.
Asynchronous completion: If a potentially asynchronous function call completes asynchronously, the results of the operation, and any errors, are accessible in the callback function. The callback function is executed on a worker thread, not on the thread that made the initial function call.
In other words, your application must duplicate logic to handle the results of such operations in two places: both immediately after the function call and in the callback function.
WinHTTP simplifies this model by enabling you to implement the operational logic only in the callback function, which receives a completion notification regardless of whether the operation completed synchronously or asynchronously. When asynchronous operation is enabled, the OUT parameters of WinHTTP functions do not return meaningful data and must be set to NULL.
The only significant difference between asynchronous and synchronous completion in WinHTTP, from the application perspective, is in where the callback function is executed.
WinHTTP
Synchronous completion: When an operation completes synchronously, the results are returned in a callback function that executes in the same thread as the original function call.
Asynchronous completion: When an operation completes asynchronously, the results are returned in a callback function that executes in a worker thread.
Although most errors can also be handled entirely within the callback function, WinHTTP applications must still be prepared for a function to return FALSEbecause of an ERROR_INVALID_PARAMETER or other similar error retrieved by calling GetLastError.
Unlike WinINet, which can execute multiple asynchronous operations simultaneously, WinHTTP enforces a policy of one pending asynchronous operation per request handle. If one operation is pending and another WinHTTP function is called, the second function fails and GetLastError returns ERROR_INVALID_OPERATION.
WinHTTP simplifies this model by enabling you to implement the operational logic only in the callback function, which receives a completion notification regardless of whether the operation completed synchronously or asynchronously. When asynchronous operation is enabled, the OUT parameters of WinHTTP functions do not return meaningful data and must be set to NULL.
Differences in WinHTTP Callback Notifications
The status callback function receives updates on the status of operations through notification flags. In WinHTTP, notifications are selected using thedwNotificationFlags parameter of the WinHttpSetStatusCallback function. Use the WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS flag to be notified of all status updates.
Notifications that indicate a particular operation is complete are called completion notifications, or just completions. In WinINet, each time the callback function receives a completion, the lpvStatusInformation parameter contains an INTERNET_ASYNC_RESULT structure. In WinHTTP, this structure is not available for all completions. It is important to review the reference page for WINHTTP_STATUS_CALLBACK, which contains information about notifications and what type of data can be expected for each.
In WinHTTP, a single completion, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, indicates that an operation failed. All other completions indicate a successful operation.
Both WinINet and WinHTTP use a user-defined context value to pass information from the main thread to the status callback function, which can be executed on a worker thread. In WinINet, the context value used by the status callback function is set by calling one of several functions. In WinHTTP, the context value is set only with WinHttpSendRequest or WinHttpSetOption. Because of this, it is possible in WinHTTP for a notification to occur before a context value is set. If the callback function receives a notification before the context value is set, the application must be prepared to receive NULL in the dwContextparameter of the callback function.
Authentication Differences
In WinINet, user credentials are set by calling the InternetSetOption function, using code similar to that provided in the following code example.
// Use the WinINet InternetSetOption function to set the
// user credentials to the user name contained in strUsername
// and the password to the contents of strPassword.
InternetSetOption( hRequest, INTERNET_OPTION_PROXY_USERNAME,
strUsername, strlen(strUsername) + 1 );
InternetSetOption( hRequest, INTERNET_OPTION_PROXY_PASSWORD,
strPassword, strlen(strPassword) + 1 );
For compatibility, user credentials can similarly be set in WinHTTP using the WinHttpSetOption function, but this is not recommended because it can pose a security vulnerability.
Instead, when an application receives a 401 status code in WinHTTP, the recommended method of setting credentials is first to identify an authentication scheme using WinHttpQueryAuthSchemes and, second, set the credentials using WinHttpSetCredentials. The following code example shows how to do this.
DWORD dwSupportedSchemes;
DWORD dwPrefered;
DWORD dwTarget;
// Obtain the supported and first schemes.
WinHttpQueryAuthSchemes( hRequest, &dwSupportedSchemes, &dwPrefered, &dwTarget );
// Set the credentials before resending the request.
WinHttpSetCredentials( hRequest, dwTarget, dwPrefered, strUsername, strPassword, NULL );
Because there is no equivalent to InternetErrorDlg in WinHTTP, applications that obtain credentials through a user interface must provide their own interface.
Unlike WinINet, WinHTTP does not cache passwords. Valid user credentials must be supplied for each request.
WinHTTP does not support the Distributed Password Authentication (DPA) scheme supported by WinINet. WinHTTP does, however, support Microsoft Passport 1.4. For more information about using Passport authentication in WinHTTP, see Passport Authentication in WinHTTP.
WinHTTP does not rely on Internet Explorer settings to determine the automatic logon policy. Instead, the auto-logon policy is set with WinHttpSetOption. For more information about authentication in WinHTTP, including the auto-logon policy, see Authentication in WinHTTP.
In a secure HTTP transaction, server certificates can be used to authenticate a server to the client. In WinINet, if a server certificate contains errors,HttpSendRequest fails and provides details about the certificate errors.
In WinHttp, server certificate errors are handled according to the version as follows:
Starting with WinHttp 5.1, if a server certificate fails or contains errors, the call to WinHttpSendRequest reports aWINHTTP_CALLBACK_STATUS_SECURE_FAILURE in the callback function. If the error generated by WinHttpSendRequest is ignored, subsequent calls to WinHttpReceiveResponse fail with an ERROR_WINHTTP_OPERATION_CANCELLED error.
In WinHTTP 5.0, errors in server certificates do not, by default, cause a request to fail. Instead, the errors are reported in the callback function with theWINHTTP_CALLBACK_STATUS_SECURE_FAILURE notification.
On some earlier platforms, WinINet supported the Private Communication Technology (PCT) and/or Fortezza protocols, although not on Windows XP.
WinHTTP does not support the PCT and Fortezza protocols on any platform, and instead relies on Secure Sockets Layer (SSL) 2.0, SSL 3.0, or Transport Layer Security (TLS) 1.0.
TortoiseSVN의 Diff, Log, Blame 기능만 사용해도 충분하다면 다음과 같이 설정한다.
If you're using Visual Studio,
you can integrate TortoiseSVN commands to various context menus. Of course,
there are Subversion plugins for Visual Studio like AnkhSVN or VisualSVN, with the latter
already using TortoiseSVN for many of its UI. Those plugins also have the
advantage that when you do refactoring, they automatically record the renames
and moves in SVN.
But if you're using one of the free versions of Visual Studio, you can not
use those plugins. And sometimes it's still nice to have some of the TortoiseSVN
commands available from Visual Studio directly, even if you have such a plugin
installed.
The first step is to add the TortoiseSVN commands as external tools,
under the menu TOOLS->External Tools....
한국어 버전 ->
Add the name of the command, the path to TortoiseProc.exe and then
the parameters for the command.
Use the VS variables wherever needed. Since I add my commands to the context
menu of the open file tab, here's the parameters I used:
Notice the /line: parameter: this will make TortoiseBlame
automatically scroll to the same line the cursor is located in the opened file
in Visual Studio.
Now to add those new commands to the file tab context menu, go to
TOOLS->Customize..., select the Commands tab,
click the radio button Context menu and then select Other Context
Menus | Easy MDI Document Window.
한국어 버전 ->
Then click the Add command... button:
한국어 버전 ->
Now you have to select the commands. Problem is that the custom commands are
not shown with their title but only as External Command X with
X being the number of the external command.
In my case, the commands were number 9-11, you might have to do some
trial-and-error here. Just add the commands you think are the ones you added and
then check if the right ones show up in the context menu.
음... 외부 도구에서 추가한 기능의 이름이 안 보이고 그냥 '외부 명령 XX' 요렇게 보이는 것에 주의 필요합니다.
대충 제일 아래쪽부터 순서대로 찍으면 될듯... ^^;
And this is how the context menu of the open file tab looks like:
warning LNK4099: '~.pdb' PDB를 '~.lib' 또는 '~.pdb'에서 찾을 수 없습니다. 디버그 정보가 없는 것처럼 개체를 링크합니다. 이런 경고가 떠서 컴파일 할때마다 신경이 쓰여요.. ㅠㅠ 왜 이런 에러가 뜨는 거죠? 떠도 괜찮은 건지.. _________________ (만지작 거리는 단계)
warning LNK4099: '~.pdb' PDB를 '~.lib' 또는 '~.pdb'에서 찾을 수 없습니다. 디버그 정보가 없는 것처럼 개체를 링크합니다. 이런 경고가 떠서 컴파일 할때마다 신경이 쓰여요.. ㅠㅠ 왜 이런 에러가 뜨는 거죠? 떠도 괜찮은 건지..
올바른 PDB 정보를 찾지 못할때 그렇습니다. LIB를 만들때 프로그램 디버깅 정보(심볼 및 기타 Debug & Continue 정보)가 LIB 파일에 들어가는 경우와 LIB 파일과 같이 생성되는 PDB 파일에 포함되는 경우가 있습니다.
LIB에 같이 포함되게 하기 위해서는 디버깅 정보를 /Z7 으로 변경하고 C/C++ Command Line 옵션에 /Yd를 수동으로 입력해주는 것으로 해결이 됩니다. 일단 PDB가 생성되기 시작하면 /Z7을 쓰더라도 PDB안에 디버깅 정보가 몰려가기때문에(이건 M$가 신경을 좀 덜써준듯) 이렇게 사용할 경우 LIB 프로젝트에 pch 생성을 사용해서는 안됩니다. pch를 생성하기 위해선 PDB 파일이 만들어져야 하는데 PDB 파일이 있으면 디버깅 정보가 생성되면서 LIB(내의 obj)안에 포함되어지지 않고 무조건 PDB 파일에 기록되게 되어 있습니다.
Edit & Continue 가 지원되도록 디버깅 정보 레벨을 올리면서 디버깅 정보를 배포하기 위해선 컴파일시 생성되는 PDB 파일을 LIB와 같이 위치 시켜야 하는데 LIB 프로젝트는 EXE와 달리 최종 PDB를 모아주지 않기 때문에 /Release/vc70.pdb, /Debug/vc70.pdb 파일들을 사용해야 합니다. 이름이 보기 좋지 않고 obj 파일 내에 이 파일에 대한 절대 경로가 포함되기 때문에 같은 폴더에 ~~~.lib, vc70.pdb 를 같이 넣어주거나 C++ 프로젝트 셋팅을 바꿔서 vc70.pdb를 ~~~.pdb 식으로 이름을 변경해주도록 설정해주는게 좋습니다.
Thanks for the error report - this isn't the first time we've had this request. Unfortunately, we just don't have the resources to address the issue during this product cycle. We will try to revisit the issue in future product cycles.
위와 같은 버그가 있을때!! 해당 PDB 파일에 접근을 못할경우가 대다수 더군요. 그래서 저는 임시로 PDB 파일의 이름을 바꿔줍니다. 이상하게 지우지는 못하면서 이름은 바꿔지더군요. 가끔 정상종료를 못했을 때 다음번 빌드에서 PDB파일에 접근하지 못하는 버그 같은데요. 일단 이름 바꿔주면 괜찮습니다.
설치는 위에서 설명한 "log4cxx 빌드 (Visual Studio 2008)" 의 "1. Download Installation File" 와 "2. Installation" 까지 진행 후
log4cxx 솔루션 파일(log4cxx/projects/log4cxx.dsw) 을 Visual Studio 2010으로 열면 프로젝트 자동변환을 진행하고
아래 데로 변경하면 됩니다. (일단 32bit 기준)
설치 바이너리 버전 : apache-log4cxx-0.10.0.zip, apr-1.4.5-win32-src.zip, apr-util-1.3.12-win32-src.zip, sed-4.2.1-setup.exe
log4cxx\src\main\include\log4cxx/helpers/simpledateformat.h(78): error C2252: 템플릿은 네임스페이스 범위에서만 명시적으로 인스턴스화할 수 있습니다.
LOG4CXX_LIST_DEF(..) 를 class 정의 밖으로 옮긴다. (namespace 정의 안, class 정의 밖)
LOG4CXX_LIST_DEF(ConnectionList, Connection); 의 경우 윗줄의
typedef log4cxx::helpers::SocketPtr Connection; 도 같이 옮긴다.
에러 유형 2. KeySet namespace 관련..
..\src\main\cpp\propertiespatternconverter.cpp(62): error C2039: 'KeySet' : 'log4cxx::spi::LoggingEvent'의 멤버가 아닙니다.
LoggingEvent::KeySet keySet 를 KeySet keySet으로 변경. (namespace 제거)
에러 유형 3. iterator 관련..
..\src\main\cpp\propertiespatternconverter.cpp(64): error C2065: 'const_iterator' : 선언되지 않은 식별자입니다.
#include <iterator> 추가
에러 유형 4. apr, aprutil 링크 에러
library 참조 수동 설정 필요. 아래와 같이 Debug, Release 에 대해 수동 설정. Debug는 LibD, Release는 LibR 폴더에 생성됨.
"log4cxx > 프로젝트 속성 > 링커 > 일반 > 추가 라이브러리 디렉토리 " 추가 (Release 모드는 LibD)
..\..\apr\LibD
..\..\apr-util\LibD
..\..\apr-util\xml\expat\lib\LibD
"log4cxx > 프로젝트 속성 > 링커 > 입력 > 추가 종속성 " 추가
apr.lib
aprutil.lib
xml.lib
2. apr 프로젝트
D:\Program Files\MSBuild\Microsoft.Cpp\v4.0\Microsoft.CppBuild.targets(1151,5): warning MSB8012: TargetPath(E:\SRC\NewBaseApp\WISM\Library\log4cxx\apr\.\LibR\apr.lib)이(가) Library의 OutputFile 속성 값(E:\SRC\NewBaseApp\WISM\Library\log4cxx\apr\LibR\apr-1.lib)과 일치하지 않습니다. 이로 인해 프로젝트가 잘못 빌드될 수 있습니다. 이를 수정하려면 $(OutDir), $(TargetName) 및 $(TargetExt) 속성 값이 %(Lib.OutputFile)에 지정된 값과 일치해야 합니다.
D:\Program Files\MSBuild\Microsoft.Cpp\v4.0\Microsoft.CppBuild.targets(1153,5): warning MSB8012: TargetName(apr)이(가) Library의 OutputFile 속성 값(apr-1)과 일치하지 않습니다. 이로 인해 프로젝트가 잘못 빌드될 수 있습니다. 이를 수정하려면 $(OutDir), $(TargetName) 및 $(TargetExt) 속성 값이 %(Lib.OutputFile)에 지정된 값과 일치해야 합니다.
apr 프로젝트 속성의 "라이브러리 관리자 > 일반 > 출력 파일" 을 LibR\apr.lib 로 변경. ("일반>대상이름"과 일치 시키기. 디버그 모드는 LibD\apr.lib)
3. aprutil 프로젝트
D:\Program Files\MSBuild\Microsoft.Cpp\v4.0\Microsoft.CppBuild.targets(1151,5): warning MSB8012: TargetPath(..\log4cxx\apr-util\.\LibR\aprutil.lib)이(가) Library의 OutputFile 속성 값(E:\SRC\NewBaseApp\WISM\Library\log4cxx\apr-util\LibR\aprutil-1.lib)과 일치하지 않습니다. 이로 인해 프로젝트가 잘못 빌드될 수 있습니다. 이를 수정하려면 $(OutDir), $(TargetName) 및 $(TargetExt) 속성 값이 %(Lib.OutputFile)에 지정된 값과 일치해야 합니다.
D:\Program Files\MSBuild\Microsoft.Cpp\v4.0\Microsoft.CppBuild.targets(1153,5): warning MSB8012: TargetName(aprutil)이(가) Library의 OutputFile 속성 값(aprutil-1)과 일치하지 않습니다. 이로 인해 프로젝트가 잘못 빌드될 수 있습니다. 이를 수정하려면 $(OutDir), $(TargetName) 및 $(TargetExt) 속성 값이 %(Lib.OutputFile)에 지정된 값과 일치해야 합니다.
aprutil 프로젝트 속성의 "라이브러리 관리자 > 일반 > 출력 파일" 을 LibR\aprutil.lib 로 변경. ("일반>대상이름"과 일치 시키기. 디버그 모드는 LibD\aprutil.lib)
4. apr, aprutil, xml 빌드 후 log4cxx 프로젝트 빌드
log4cxx\projects\Debug 에 log4cxx.lib, log4cxx.dll 파일 생성
log4cxx 64 bit은 컴파일 구성 추가 후 빌드하면 된다는 것 같은데 아직 안해봤습니다.