4 * Copyright 1999 Corel Corporation
5 * Copyright 2002 CodeWeavers Inc.
6 * Copyright 2002 Jaco Greeff
7 * Copyright 2002 TransGaming Technologies Inc.
8 * Copyright 2004 Mike McCormack for CodeWeavers
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 #include "wine/port.h"
32 #define MAXHOSTNAME 100 /* from http.c */
37 #include <sys/types.h>
38 #ifdef HAVE_SYS_SOCKET_H
39 # include <sys/socket.h>
41 #ifdef HAVE_SYS_TIME_H
42 # include <sys/time.h>
57 #include "wine/debug.h"
59 #define NO_SHLWAPI_STREAM
62 #include "wine/exception.h"
67 #include "wine/unicode.h"
69 WINE_DEFAULT_DEBUG_CHANNEL(wininet
);
71 #define MAX_IDLE_WORKER 1000*60*1
72 #define MAX_WORKER_THREADS 10
73 #define RESPONSE_TIMEOUT 30
75 #define GET_HWININET_FROM_LPWININETFINDNEXT(lpwh) \
76 (LPWININETAPPINFOW)(((LPWININETFTPSESSIONW)(lpwh->hdr.lpwhparent))->hdr.lpwhparent)
82 CHAR response
[MAX_REPLY_LEN
];
83 } WITHREADERROR
, *LPWITHREADERROR
;
85 static VOID
INTERNET_CloseHandle(LPWININETHANDLEHEADER hdr
);
86 BOOL WINAPI
INTERNET_FindNextFileW(LPWININETFINDNEXTW lpwh
, LPVOID lpvFindData
);
87 HINTERNET WINAPI
INTERNET_InternetOpenUrlW(LPWININETAPPINFOW hIC
, LPCWSTR lpszUrl
,
88 LPCWSTR lpszHeaders
, DWORD dwHeadersLength
, DWORD dwFlags
, DWORD dwContext
);
89 static VOID
INTERNET_ExecuteWork();
91 DWORD g_dwTlsErrIndex
= TLS_OUT_OF_INDEXES
;
93 DWORD dwNumIdleThreads
;
95 HANDLE hEventArray
[2];
96 #define hQuitEvent hEventArray[0]
97 #define hWorkEvent hEventArray[1]
98 CRITICAL_SECTION csQueue
;
99 LPWORKREQUEST lpHeadWorkQueue
;
100 LPWORKREQUEST lpWorkQueueTail
;
102 extern void URLCacheContainers_CreateDefaults();
103 extern void URLCacheContainers_DeleteAll();
105 #define HANDLE_CHUNK_SIZE 0x10
107 static CRITICAL_SECTION WININET_cs
;
108 static CRITICAL_SECTION_DEBUG WININET_cs_debug
=
111 { &WININET_cs_debug
.ProcessLocksList
, &WININET_cs_debug
.ProcessLocksList
},
112 0, 0, { 0, (DWORD
)(__FILE__
": WININET_cs") }
114 static CRITICAL_SECTION WININET_cs
= { &WININET_cs_debug
, -1, 0, 0, 0, 0 };
116 static LPWININETHANDLEHEADER
*WININET_Handles
;
117 static UINT WININET_dwNextHandle
;
118 static UINT WININET_dwMaxHandles
;
120 HINTERNET
WININET_AllocHandle( LPWININETHANDLEHEADER info
)
122 LPWININETHANDLEHEADER
*p
;
123 UINT handle
= 0, num
;
125 EnterCriticalSection( &WININET_cs
);
126 if( !WININET_dwMaxHandles
)
128 num
= HANDLE_CHUNK_SIZE
;
129 p
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
134 WININET_dwMaxHandles
= num
;
136 if( WININET_dwMaxHandles
== WININET_dwNextHandle
)
138 num
= WININET_dwMaxHandles
+ HANDLE_CHUNK_SIZE
;
139 p
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
140 WININET_Handles
, sizeof (UINT
)* num
);
144 WININET_dwMaxHandles
= num
;
147 handle
= WININET_dwNextHandle
;
148 if( WININET_Handles
[handle
] )
149 ERR("handle isn't free but should be\n");
150 WININET_Handles
[handle
] = WININET_AddRef( info
);
152 while( WININET_Handles
[WININET_dwNextHandle
] &&
153 (WININET_dwNextHandle
< WININET_dwMaxHandles
) )
154 WININET_dwNextHandle
++;
157 LeaveCriticalSection( &WININET_cs
);
159 return (HINTERNET
) (handle
+1);
162 HINTERNET
WININET_FindHandle( LPWININETHANDLEHEADER info
)
166 EnterCriticalSection( &WININET_cs
);
167 for( i
=0; i
<WININET_dwMaxHandles
; i
++ )
169 if( info
== WININET_Handles
[i
] )
171 WININET_AddRef( info
);
176 LeaveCriticalSection( &WININET_cs
);
178 return (HINTERNET
) handle
;
181 LPWININETHANDLEHEADER
WININET_AddRef( LPWININETHANDLEHEADER info
)
184 TRACE("%p -> refcount = %ld\n", info
, info
->dwRefCount
);
188 LPWININETHANDLEHEADER
WININET_GetObject( HINTERNET hinternet
)
190 LPWININETHANDLEHEADER info
= NULL
;
191 UINT handle
= (UINT
) hinternet
;
193 EnterCriticalSection( &WININET_cs
);
195 if( (handle
> 0) && ( handle
<= WININET_dwMaxHandles
) )
196 info
= WININET_AddRef( WININET_Handles
[handle
-1] );
198 LeaveCriticalSection( &WININET_cs
);
200 TRACE("handle %d -> %p\n", handle
, info
);
205 BOOL
WININET_Release( LPWININETHANDLEHEADER info
)
208 TRACE( "object %p refcount = %ld\n", info
, info
->dwRefCount
);
209 if( !info
->dwRefCount
)
211 TRACE( "destroying object %p\n", info
);
212 info
->destroy( info
);
217 BOOL
WININET_FreeHandle( HINTERNET hinternet
)
220 UINT handle
= (UINT
) hinternet
;
221 LPWININETHANDLEHEADER info
= NULL
;
223 EnterCriticalSection( &WININET_cs
);
225 if( (handle
> 0) && ( handle
<= WININET_dwMaxHandles
) )
228 if( WININET_Handles
[handle
] )
230 info
= WININET_Handles
[handle
];
231 TRACE( "destroying handle %d for object %p\n", handle
+1, info
);
232 WININET_Handles
[handle
] = NULL
;
234 if( WININET_dwNextHandle
> handle
)
235 WININET_dwNextHandle
= handle
;
239 LeaveCriticalSection( &WININET_cs
);
242 WININET_Release( info
);
247 /***********************************************************************
248 * DllMain [Internal] Initializes the internal 'WININET.DLL'.
251 * hinstDLL [I] handle to the DLL's instance
253 * lpvReserved [I] reserved, must be NULL
260 BOOL WINAPI
DllMain (HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
)
262 TRACE("%p,%lx,%p\n", hinstDLL
, fdwReason
, lpvReserved
);
265 case DLL_PROCESS_ATTACH
:
267 g_dwTlsErrIndex
= TlsAlloc();
269 if (g_dwTlsErrIndex
== TLS_OUT_OF_INDEXES
)
272 hQuitEvent
= CreateEventA(0, TRUE
, FALSE
, NULL
);
273 hWorkEvent
= CreateEventA(0, FALSE
, FALSE
, NULL
);
274 InitializeCriticalSection(&csQueue
);
276 URLCacheContainers_CreateDefaults();
279 dwNumIdleThreads
= 0;
282 case DLL_THREAD_ATTACH
:
284 LPWITHREADERROR lpwite
= HeapAlloc(GetProcessHeap(), 0, sizeof(WITHREADERROR
));
288 TlsSetValue(g_dwTlsErrIndex
, (LPVOID
)lpwite
);
292 case DLL_THREAD_DETACH
:
293 if (g_dwTlsErrIndex
!= TLS_OUT_OF_INDEXES
)
295 LPVOID lpwite
= TlsGetValue(g_dwTlsErrIndex
);
297 HeapFree(GetProcessHeap(), 0, lpwite
);
301 case DLL_PROCESS_DETACH
:
303 URLCacheContainers_DeleteAll();
305 if (g_dwTlsErrIndex
!= TLS_OUT_OF_INDEXES
)
307 HeapFree(GetProcessHeap(), 0, TlsGetValue(g_dwTlsErrIndex
));
308 TlsFree(g_dwTlsErrIndex
);
311 SetEvent(hQuitEvent
);
313 CloseHandle(hQuitEvent
);
314 CloseHandle(hWorkEvent
);
315 DeleteCriticalSection(&csQueue
);
323 /***********************************************************************
324 * InternetInitializeAutoProxyDll (WININET.@)
326 * Setup the internal proxy
335 BOOL WINAPI
InternetInitializeAutoProxyDll(DWORD dwReserved
)
338 INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
342 /***********************************************************************
343 * DetectAutoProxyUrl (WININET.@)
345 * Auto detect the proxy url
351 BOOL WINAPI
DetectAutoProxyUrl(LPSTR lpszAutoProxyUrl
,
352 DWORD dwAutoProxyUrlLength
, DWORD dwDetectFlags
)
355 INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
360 /***********************************************************************
361 * INTERNET_ConfigureProxyFromReg
364 * The proxy may be specified in the form 'http=proxy.my.org'
365 * Presumably that means there can be ftp=ftpproxy.my.org too.
367 static BOOL
INTERNET_ConfigureProxyFromReg( LPWININETAPPINFOW lpwai
)
370 DWORD r
, keytype
, len
, enabled
;
371 LPSTR lpszInternetSettings
=
372 "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
373 static const WCHAR szProxyServer
[] = { 'P','r','o','x','y','S','e','r','v','e','r', 0 };
375 r
= RegOpenKeyA(HKEY_CURRENT_USER
, lpszInternetSettings
, &key
);
376 if ( r
!= ERROR_SUCCESS
)
379 len
= sizeof enabled
;
380 r
= RegQueryValueExA( key
, "ProxyEnable", NULL
, &keytype
,
381 (BYTE
*)&enabled
, &len
);
382 if( (r
== ERROR_SUCCESS
) && enabled
)
384 TRACE("Proxy is enabled.\n");
386 /* figure out how much memory the proxy setting takes */
387 r
= RegQueryValueExW( key
, szProxyServer
, NULL
, &keytype
,
389 if( (r
== ERROR_SUCCESS
) && len
&& (keytype
== REG_SZ
) )
392 static const WCHAR szHttp
[] = {'h','t','t','p','=',0};
394 szProxy
=HeapAlloc( GetProcessHeap(), 0, len
);
395 RegQueryValueExW( key
, szProxyServer
, NULL
, &keytype
,
396 (BYTE
*)szProxy
, &len
);
398 /* find the http proxy, and strip away everything else */
399 p
= strstrW( szProxy
, szHttp
);
402 p
+= lstrlenW(szHttp
);
403 lstrcpyW( szProxy
, p
);
405 p
= strchrW( szProxy
, ' ' );
409 lpwai
->dwAccessType
= INTERNET_OPEN_TYPE_PROXY
;
410 lpwai
->lpszProxy
= szProxy
;
412 TRACE("http proxy = %s\n", debugstr_w(lpwai
->lpszProxy
));
415 ERR("Couldn't read proxy server settings.\n");
418 TRACE("Proxy is not enabled.\n");
424 /***********************************************************************
425 * InternetOpenW (WININET.@)
427 * Per-application initialization of wininet
430 * HINTERNET on success
434 HINTERNET WINAPI
InternetOpenW(LPCWSTR lpszAgent
, DWORD dwAccessType
,
435 LPCWSTR lpszProxy
, LPCWSTR lpszProxyBypass
, DWORD dwFlags
)
437 LPWININETAPPINFOW lpwai
= NULL
;
438 HINTERNET handle
= NULL
;
440 if (TRACE_ON(wininet
)) {
441 #define FE(x) { x, #x }
442 static const wininet_flag_info access_type
[] = {
443 FE(INTERNET_OPEN_TYPE_PRECONFIG
),
444 FE(INTERNET_OPEN_TYPE_DIRECT
),
445 FE(INTERNET_OPEN_TYPE_PROXY
),
446 FE(INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY
)
448 static const wininet_flag_info flag
[] = {
449 FE(INTERNET_FLAG_ASYNC
),
450 FE(INTERNET_FLAG_FROM_CACHE
),
451 FE(INTERNET_FLAG_OFFLINE
)
455 const char *access_type_str
= "Unknown";
456 DWORD flag_val
= dwFlags
;
458 TRACE("(%s, %li, %s, %s, %li)\n", debugstr_w(lpszAgent
), dwAccessType
,
459 debugstr_w(lpszProxy
), debugstr_w(lpszProxyBypass
), dwFlags
);
460 for (i
= 0; i
< (sizeof(access_type
) / sizeof(access_type
[0])); i
++) {
461 if (access_type
[i
].val
== dwAccessType
) {
462 access_type_str
= access_type
[i
].name
;
466 TRACE(" access type : %s\n", access_type_str
);
468 for (i
= 0; i
< (sizeof(flag
) / sizeof(flag
[0])); i
++) {
469 if (flag
[i
].val
& flag_val
) {
470 DPRINTF(" %s", flag
[i
].name
);
471 flag_val
&= ~flag
[i
].val
;
474 if (flag_val
) DPRINTF(" Unknown flags (%08lx)", flag_val
);
478 /* Clear any error information */
479 INTERNET_SetLastError(0);
481 lpwai
= HeapAlloc(GetProcessHeap(), 0, sizeof(WININETAPPINFOW
));
484 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
488 memset(lpwai
, 0, sizeof(WININETAPPINFOW
));
489 lpwai
->hdr
.htype
= WH_HINIT
;
490 lpwai
->hdr
.lpwhparent
= NULL
;
491 lpwai
->hdr
.dwFlags
= dwFlags
;
492 lpwai
->hdr
.dwRefCount
= 1;
493 lpwai
->hdr
.destroy
= INTERNET_CloseHandle
;
494 lpwai
->dwAccessType
= dwAccessType
;
495 lpwai
->lpszProxyUsername
= NULL
;
496 lpwai
->lpszProxyPassword
= NULL
;
498 handle
= WININET_AllocHandle( &lpwai
->hdr
);
501 HeapFree( GetProcessHeap(), 0, lpwai
);
502 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
506 if (NULL
!= lpszAgent
)
508 lpwai
->lpszAgent
= HeapAlloc( GetProcessHeap(),0,
509 (strlenW(lpszAgent
)+1)*sizeof(WCHAR
));
510 if (lpwai
->lpszAgent
)
511 lstrcpyW( lpwai
->lpszAgent
, lpszAgent
);
513 if(dwAccessType
== INTERNET_OPEN_TYPE_PRECONFIG
)
514 INTERNET_ConfigureProxyFromReg( lpwai
);
515 else if (NULL
!= lpszProxy
)
517 lpwai
->lpszProxy
= HeapAlloc( GetProcessHeap(), 0,
518 (strlenW(lpszProxy
)+1)*sizeof(WCHAR
));
519 if (lpwai
->lpszProxy
)
520 lstrcpyW( lpwai
->lpszProxy
, lpszProxy
);
523 if (NULL
!= lpszProxyBypass
)
525 lpwai
->lpszProxyBypass
= HeapAlloc( GetProcessHeap(), 0,
526 (strlenW(lpszProxyBypass
)+1)*sizeof(WCHAR
));
527 if (lpwai
->lpszProxyBypass
)
528 lstrcpyW( lpwai
->lpszProxyBypass
, lpszProxyBypass
);
533 WININET_Release( &lpwai
->hdr
);
535 TRACE("returning %p\n", lpwai
);
541 /***********************************************************************
542 * InternetOpenA (WININET.@)
544 * Per-application initialization of wininet
547 * HINTERNET on success
551 HINTERNET WINAPI
InternetOpenA(LPCSTR lpszAgent
, DWORD dwAccessType
,
552 LPCSTR lpszProxy
, LPCSTR lpszProxyBypass
, DWORD dwFlags
)
554 HINTERNET rc
= (HINTERNET
)NULL
;
556 WCHAR
*szAgent
= NULL
, *szProxy
= NULL
, *szBypass
= NULL
;
558 TRACE("(%s, 0x%08lx, %s, %s, 0x%08lx)\n", debugstr_a(lpszAgent
),
559 dwAccessType
, debugstr_a(lpszProxy
), debugstr_a(lpszProxyBypass
), dwFlags
);
563 len
= MultiByteToWideChar(CP_ACP
, 0, lpszAgent
, -1, NULL
, 0);
564 szAgent
= HeapAlloc(GetProcessHeap(), 0, len
*sizeof(WCHAR
));
565 MultiByteToWideChar(CP_ACP
, 0, lpszAgent
, -1, szAgent
, len
);
570 len
= MultiByteToWideChar(CP_ACP
, 0, lpszProxy
, -1, NULL
, 0);
571 szProxy
= HeapAlloc(GetProcessHeap(), 0, len
*sizeof(WCHAR
));
572 MultiByteToWideChar(CP_ACP
, 0, lpszProxy
, -1, szProxy
, len
);
575 if( lpszProxyBypass
)
577 len
= MultiByteToWideChar(CP_ACP
, 0, lpszProxyBypass
, -1, NULL
, 0);
578 szBypass
= HeapAlloc(GetProcessHeap(), 0, len
*sizeof(WCHAR
));
579 MultiByteToWideChar(CP_ACP
, 0, lpszProxyBypass
, -1, szBypass
, len
);
582 rc
= InternetOpenW(szAgent
, dwAccessType
, szProxy
, szBypass
, dwFlags
);
585 HeapFree(GetProcessHeap(), 0, szAgent
);
587 HeapFree(GetProcessHeap(), 0, szProxy
);
589 HeapFree(GetProcessHeap(), 0, szBypass
);
594 /***********************************************************************
595 * InternetGetLastResponseInfoA (WININET.@)
597 * Return last wininet error description on the calling thread
600 * TRUE on success of writing to buffer
604 BOOL WINAPI
InternetGetLastResponseInfoA(LPDWORD lpdwError
,
605 LPSTR lpszBuffer
, LPDWORD lpdwBufferLength
)
607 LPWITHREADERROR lpwite
= (LPWITHREADERROR
)TlsGetValue(g_dwTlsErrIndex
);
611 *lpdwError
= lpwite
->dwError
;
614 strncpy(lpszBuffer
, lpwite
->response
, *lpdwBufferLength
);
615 *lpdwBufferLength
= strlen(lpszBuffer
);
618 *lpdwBufferLength
= 0;
624 /***********************************************************************
625 * InternetGetConnectedState (WININET.@)
627 * Return connected state
631 * if lpdwStatus is not null, return the status (off line,
632 * modem, lan...) in it.
633 * FALSE if not connected
635 BOOL WINAPI
InternetGetConnectedState(LPDWORD lpdwStatus
, DWORD dwReserved
)
637 TRACE("(%p, 0x%08lx)\n", lpdwStatus
, dwReserved
);
640 FIXME("always returning LAN connection.\n");
641 *lpdwStatus
= INTERNET_CONNECTION_LAN
;
646 /***********************************************************************
647 * InternetGetConnectedStateEx (WININET.@)
649 * Return connected state
653 * if lpdwStatus is not null, return the status (off line,
654 * modem, lan...) in it.
655 * FALSE if not connected
657 BOOL WINAPI
InternetGetConnectedStateExW(LPDWORD lpdwStatus
, LPWSTR lpszConnectionName
,
658 DWORD dwNameLen
, DWORD dwReserved
)
660 TRACE("(%p, %s, %ld, 0x%08lx)\n", lpdwStatus
, debugstr_w(lpszConnectionName
), dwNameLen
, dwReserved
);
667 FIXME("always returning LAN connection.\n");
668 *lpdwStatus
= INTERNET_CONNECTION_LAN
;
673 /***********************************************************************
674 * InternetConnectW (WININET.@)
676 * Open a ftp, gopher or http session
679 * HINTERNET a session handle on success
683 HINTERNET WINAPI
InternetConnectW(HINTERNET hInternet
,
684 LPCWSTR lpszServerName
, INTERNET_PORT nServerPort
,
685 LPCWSTR lpszUserName
, LPCWSTR lpszPassword
,
686 DWORD dwService
, DWORD dwFlags
, DWORD dwContext
)
688 LPWININETAPPINFOW hIC
;
689 HINTERNET rc
= (HINTERNET
) NULL
;
691 TRACE("(%p, %s, %i, %s, %s, %li, %li, %li)\n", hInternet
, debugstr_w(lpszServerName
),
692 nServerPort
, debugstr_w(lpszUserName
), debugstr_w(lpszPassword
),
693 dwService
, dwFlags
, dwContext
);
695 /* Clear any error information */
696 INTERNET_SetLastError(0);
697 hIC
= (LPWININETAPPINFOW
) WININET_GetObject( hInternet
);
698 if ( (hIC
== NULL
) || (hIC
->hdr
.htype
!= WH_HINIT
) )
703 case INTERNET_SERVICE_FTP
:
704 rc
= FTP_Connect(hIC
, lpszServerName
, nServerPort
,
705 lpszUserName
, lpszPassword
, dwFlags
, dwContext
, 0);
708 case INTERNET_SERVICE_HTTP
:
709 rc
= HTTP_Connect(hIC
, lpszServerName
, nServerPort
,
710 lpszUserName
, lpszPassword
, dwFlags
, dwContext
, 0);
713 case INTERNET_SERVICE_GOPHER
:
719 WININET_Release( &hIC
->hdr
);
721 TRACE("returning %p\n", rc
);
726 /***********************************************************************
727 * InternetConnectA (WININET.@)
729 * Open a ftp, gopher or http session
732 * HINTERNET a session handle on success
736 HINTERNET WINAPI
InternetConnectA(HINTERNET hInternet
,
737 LPCSTR lpszServerName
, INTERNET_PORT nServerPort
,
738 LPCSTR lpszUserName
, LPCSTR lpszPassword
,
739 DWORD dwService
, DWORD dwFlags
, DWORD dwContext
)
741 HINTERNET rc
= (HINTERNET
)NULL
;
743 LPWSTR szServerName
= NULL
;
744 LPWSTR szUserName
= NULL
;
745 LPWSTR szPassword
= NULL
;
749 len
= MultiByteToWideChar(CP_ACP
, 0, lpszServerName
, -1, NULL
, 0);
750 szServerName
= HeapAlloc(GetProcessHeap(), 0, len
*sizeof(WCHAR
));
751 MultiByteToWideChar(CP_ACP
, 0, lpszServerName
, -1, szServerName
, len
);
755 len
= MultiByteToWideChar(CP_ACP
, 0, lpszUserName
, -1, NULL
, 0);
756 szUserName
= HeapAlloc(GetProcessHeap(), 0, len
*sizeof(WCHAR
));
757 MultiByteToWideChar(CP_ACP
, 0, lpszUserName
, -1, szUserName
, len
);
761 len
= MultiByteToWideChar(CP_ACP
, 0, lpszPassword
, -1, NULL
, 0);
762 szPassword
= HeapAlloc(GetProcessHeap(), 0, len
*sizeof(WCHAR
));
763 MultiByteToWideChar(CP_ACP
, 0, lpszPassword
, -1, szPassword
, len
);
767 rc
= InternetConnectW(hInternet
, szServerName
, nServerPort
,
768 szUserName
, szPassword
, dwService
, dwFlags
, dwContext
);
770 if (szServerName
) HeapFree(GetProcessHeap(), 0, szServerName
);
771 if (szUserName
) HeapFree(GetProcessHeap(), 0, szUserName
);
772 if (szPassword
) HeapFree(GetProcessHeap(), 0, szPassword
);
777 /***********************************************************************
778 * InternetFindNextFileA (WININET.@)
780 * Continues a file search from a previous call to FindFirstFile
787 BOOL WINAPI
InternetFindNextFileA(HINTERNET hFind
, LPVOID lpvFindData
)
792 ret
= InternetFindNextFileW(hFind
, lpvFindData
?&fd
:NULL
);
794 WININET_find_data_WtoA(&fd
, (LPWIN32_FIND_DATAA
)lpvFindData
);
798 /***********************************************************************
799 * InternetFindNextFileW (WININET.@)
801 * Continues a file search from a previous call to FindFirstFile
808 BOOL WINAPI
InternetFindNextFileW(HINTERNET hFind
, LPVOID lpvFindData
)
810 LPWININETAPPINFOW hIC
= NULL
;
811 LPWININETFINDNEXTW lpwh
;
812 BOOL bSuccess
= FALSE
;
816 lpwh
= (LPWININETFINDNEXTW
) WININET_GetObject( hFind
);
817 if (NULL
== lpwh
|| lpwh
->hdr
.htype
!= WH_HFINDNEXT
)
819 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
823 hIC
= GET_HWININET_FROM_LPWININETFINDNEXT(lpwh
);
824 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
826 WORKREQUEST workRequest
;
827 struct WORKREQ_INTERNETFINDNEXTW
*req
;
829 workRequest
.asyncall
= INTERNETFINDNEXTW
;
830 workRequest
.hdr
= WININET_AddRef( &lpwh
->hdr
);
831 req
= &workRequest
.u
.InternetFindNextW
;
832 req
->lpFindFileData
= lpvFindData
;
834 bSuccess
= INTERNET_AsyncCall(&workRequest
);
838 bSuccess
= INTERNET_FindNextFileW(lpwh
, lpvFindData
);
842 WININET_Release( &lpwh
->hdr
);
846 /***********************************************************************
847 * INTERNET_FindNextFileW (Internal)
849 * Continues a file search from a previous call to FindFirstFile
856 BOOL WINAPI
INTERNET_FindNextFileW(LPWININETFINDNEXTW lpwh
, LPVOID lpvFindData
)
858 BOOL bSuccess
= TRUE
;
859 LPWININETAPPINFOW hIC
= NULL
;
860 LPWIN32_FIND_DATAW lpFindFileData
;
864 assert (lpwh
->hdr
.htype
== WH_HFINDNEXT
);
866 /* Clear any error information */
867 INTERNET_SetLastError(0);
869 if (lpwh
->hdr
.lpwhparent
->htype
!= WH_HFTPSESSION
)
871 FIXME("Only FTP find next supported\n");
872 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
876 TRACE("index(%ld) size(%ld)\n", lpwh
->index
, lpwh
->size
);
878 lpFindFileData
= (LPWIN32_FIND_DATAW
) lpvFindData
;
879 ZeroMemory(lpFindFileData
, sizeof(WIN32_FIND_DATAA
));
881 if (lpwh
->index
>= lpwh
->size
)
883 INTERNET_SetLastError(ERROR_NO_MORE_FILES
);
888 FTP_ConvertFileProp(&lpwh
->lpafp
[lpwh
->index
], lpFindFileData
);
891 TRACE("\nName: %s\nSize: %ld\n", debugstr_w(lpFindFileData
->cFileName
), lpFindFileData
->nFileSizeLow
);
895 hIC
= GET_HWININET_FROM_LPWININETFINDNEXT(lpwh
);
896 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
898 INTERNET_ASYNC_RESULT iar
;
900 iar
.dwResult
= (DWORD
)bSuccess
;
901 iar
.dwError
= iar
.dwError
= bSuccess
? ERROR_SUCCESS
:
902 INTERNET_GetLastError();
904 SendAsyncCallback(hIC
, &lpwh
->hdr
, lpwh
->hdr
.dwContext
,
905 INTERNET_STATUS_REQUEST_COMPLETE
, &iar
,
906 sizeof(INTERNET_ASYNC_RESULT
));
913 /***********************************************************************
914 * INTERNET_CloseHandle (internal)
916 * Close internet handle
922 static VOID
INTERNET_CloseHandle(LPWININETHANDLEHEADER hdr
)
924 LPWININETAPPINFOW lpwai
= (LPWININETAPPINFOW
) hdr
;
928 if (lpwai
->lpszAgent
)
929 HeapFree(GetProcessHeap(), 0, lpwai
->lpszAgent
);
931 if (lpwai
->lpszProxy
)
932 HeapFree(GetProcessHeap(), 0, lpwai
->lpszProxy
);
934 if (lpwai
->lpszProxyBypass
)
935 HeapFree(GetProcessHeap(), 0, lpwai
->lpszProxyBypass
);
937 if (lpwai
->lpszProxyUsername
)
938 HeapFree(GetProcessHeap(), 0, lpwai
->lpszProxyUsername
);
940 if (lpwai
->lpszProxyPassword
)
941 HeapFree(GetProcessHeap(), 0, lpwai
->lpszProxyPassword
);
943 HeapFree(GetProcessHeap(), 0, lpwai
);
947 /***********************************************************************
948 * InternetCloseHandle (WININET.@)
950 * Generic close handle function
957 BOOL WINAPI
InternetCloseHandle(HINTERNET hInternet
)
959 LPWININETHANDLEHEADER lpwh
, parent
;
960 LPWININETAPPINFOW hIC
;
962 TRACE("%p\n",hInternet
);
964 lpwh
= WININET_GetObject( hInternet
);
967 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
972 while( parent
&& (parent
->htype
!= WH_HINIT
) )
973 parent
= parent
->lpwhparent
;
975 hIC
= (LPWININETAPPINFOW
) parent
;
976 SendAsyncCallback(hIC
, lpwh
, lpwh
->dwContext
,
977 INTERNET_STATUS_HANDLE_CLOSING
, hInternet
,
980 if( lpwh
->lpwhparent
)
981 WININET_Release( lpwh
->lpwhparent
);
982 WININET_FreeHandle( hInternet
);
983 WININET_Release( lpwh
);
989 /***********************************************************************
990 * ConvertUrlComponentValue (Internal)
992 * Helper function for InternetCrackUrlW
995 void ConvertUrlComponentValue(LPSTR
* lppszComponent
, LPDWORD dwComponentLen
,
996 LPWSTR lpwszComponent
, DWORD dwwComponentLen
,
1000 if (*dwComponentLen
!= 0)
1002 DWORD nASCIILength
=WideCharToMultiByte(CP_ACP
,0,lpwszComponent
,dwwComponentLen
,NULL
,0,NULL
,NULL
);
1003 if (*lppszComponent
== NULL
)
1005 int nASCIIOffset
=WideCharToMultiByte(CP_ACP
,0,lpwszStart
,lpwszComponent
-lpwszStart
,NULL
,0,NULL
,NULL
);
1006 *lppszComponent
= (LPSTR
)lpszStart
+nASCIIOffset
;
1007 *dwComponentLen
= nASCIILength
;
1011 DWORD ncpylen
= min((*dwComponentLen
)-1, nASCIILength
);
1012 WideCharToMultiByte(CP_ACP
,0,lpwszComponent
,dwwComponentLen
,*lppszComponent
,ncpylen
+1,NULL
,NULL
);
1013 (*lppszComponent
)[ncpylen
]=0;
1014 *dwComponentLen
= ncpylen
;
1020 /***********************************************************************
1021 * InternetCrackUrlA (WININET.@)
1023 * Break up URL into its components
1025 * TODO: Handle dwFlags
1032 BOOL WINAPI
InternetCrackUrlA(LPCSTR lpszUrl
, DWORD dwUrlLength
, DWORD dwFlags
,
1033 LPURL_COMPONENTSA lpUrlComponents
)
1036 URL_COMPONENTSW UCW
;
1041 nLength
=MultiByteToWideChar(CP_ACP
,0,lpszUrl
,dwUrlLength
,NULL
,0);
1042 lpwszUrl
=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WCHAR
)*nLength
);
1043 MultiByteToWideChar(CP_ACP
,0,lpszUrl
,dwUrlLength
,lpwszUrl
,nLength
);
1045 memset(&UCW
,0,sizeof(UCW
));
1046 if(lpUrlComponents
->dwHostNameLength
!=0)
1047 UCW
.dwHostNameLength
=1;
1048 if(lpUrlComponents
->dwUserNameLength
!=0)
1049 UCW
.dwUserNameLength
=1;
1050 if(lpUrlComponents
->dwPasswordLength
!=0)
1051 UCW
.dwPasswordLength
=1;
1052 if(lpUrlComponents
->dwUrlPathLength
!=0)
1053 UCW
.dwUrlPathLength
=1;
1054 if(lpUrlComponents
->dwSchemeLength
!=0)
1055 UCW
.dwSchemeLength
=1;
1056 if(lpUrlComponents
->dwExtraInfoLength
!=0)
1057 UCW
.dwExtraInfoLength
=1;
1058 if(!InternetCrackUrlW(lpwszUrl
,nLength
,dwFlags
,&UCW
))
1060 HeapFree(GetProcessHeap(), 0, lpwszUrl
);
1063 ConvertUrlComponentValue(&lpUrlComponents
->lpszHostName
, &lpUrlComponents
->dwHostNameLength
,
1064 UCW
.lpszHostName
, UCW
.dwHostNameLength
,
1066 ConvertUrlComponentValue(&lpUrlComponents
->lpszUserName
, &lpUrlComponents
->dwUserNameLength
,
1067 UCW
.lpszUserName
, UCW
.dwUserNameLength
,
1069 ConvertUrlComponentValue(&lpUrlComponents
->lpszPassword
, &lpUrlComponents
->dwPasswordLength
,
1070 UCW
.lpszPassword
, UCW
.dwPasswordLength
,
1072 ConvertUrlComponentValue(&lpUrlComponents
->lpszUrlPath
, &lpUrlComponents
->dwUrlPathLength
,
1073 UCW
.lpszUrlPath
, UCW
.dwUrlPathLength
,
1075 ConvertUrlComponentValue(&lpUrlComponents
->lpszScheme
, &lpUrlComponents
->dwSchemeLength
,
1076 UCW
.lpszScheme
, UCW
.dwSchemeLength
,
1078 ConvertUrlComponentValue(&lpUrlComponents
->lpszExtraInfo
, &lpUrlComponents
->dwExtraInfoLength
,
1079 UCW
.lpszExtraInfo
, UCW
.dwExtraInfoLength
,
1081 lpUrlComponents
->nScheme
=UCW
.nScheme
;
1082 lpUrlComponents
->nPort
=UCW
.nPort
;
1083 HeapFree(GetProcessHeap(), 0, lpwszUrl
);
1085 TRACE("%s: scheme(%s) host(%s) path(%s) extra(%s)\n", lpszUrl
,
1086 debugstr_an(lpUrlComponents
->lpszScheme
,lpUrlComponents
->dwSchemeLength
),
1087 debugstr_an(lpUrlComponents
->lpszHostName
,lpUrlComponents
->dwHostNameLength
),
1088 debugstr_an(lpUrlComponents
->lpszUrlPath
,lpUrlComponents
->dwUrlPathLength
),
1089 debugstr_an(lpUrlComponents
->lpszExtraInfo
,lpUrlComponents
->dwExtraInfoLength
));
1094 /***********************************************************************
1095 * GetInternetSchemeW (internal)
1101 * INTERNET_SCHEME_UNKNOWN on failure
1104 static INTERNET_SCHEME
GetInternetSchemeW(LPCWSTR lpszScheme
, DWORD nMaxCmp
)
1106 INTERNET_SCHEME iScheme
=INTERNET_SCHEME_UNKNOWN
;
1107 static const WCHAR lpszFtp
[]={'f','t','p',0};
1108 static const WCHAR lpszGopher
[]={'g','o','p','h','e','r',0};
1109 static const WCHAR lpszHttp
[]={'h','t','t','p',0};
1110 static const WCHAR lpszHttps
[]={'h','t','t','p','s',0};
1111 static const WCHAR lpszFile
[]={'f','i','l','e',0};
1112 static const WCHAR lpszNews
[]={'n','e','w','s',0};
1113 static const WCHAR lpszMailto
[]={'m','a','i','l','t','o',0};
1114 static const WCHAR lpszRes
[]={'r','e','s',0};
1115 WCHAR
* tempBuffer
=NULL
;
1117 if(lpszScheme
==NULL
)
1118 return INTERNET_SCHEME_UNKNOWN
;
1120 tempBuffer
=HeapAlloc(GetProcessHeap(),0,(nMaxCmp
+1)*sizeof(WCHAR
));
1121 strncpyW(tempBuffer
,lpszScheme
,nMaxCmp
);
1122 tempBuffer
[nMaxCmp
]=0;
1123 strlwrW(tempBuffer
);
1124 if (nMaxCmp
==strlenW(lpszFtp
) && !strncmpW(lpszFtp
, tempBuffer
, nMaxCmp
))
1125 iScheme
=INTERNET_SCHEME_FTP
;
1126 else if (nMaxCmp
==strlenW(lpszGopher
) && !strncmpW(lpszGopher
, tempBuffer
, nMaxCmp
))
1127 iScheme
=INTERNET_SCHEME_GOPHER
;
1128 else if (nMaxCmp
==strlenW(lpszHttp
) && !strncmpW(lpszHttp
, tempBuffer
, nMaxCmp
))
1129 iScheme
=INTERNET_SCHEME_HTTP
;
1130 else if (nMaxCmp
==strlenW(lpszHttps
) && !strncmpW(lpszHttps
, tempBuffer
, nMaxCmp
))
1131 iScheme
=INTERNET_SCHEME_HTTPS
;
1132 else if (nMaxCmp
==strlenW(lpszFile
) && !strncmpW(lpszFile
, tempBuffer
, nMaxCmp
))
1133 iScheme
=INTERNET_SCHEME_FILE
;
1134 else if (nMaxCmp
==strlenW(lpszNews
) && !strncmpW(lpszNews
, tempBuffer
, nMaxCmp
))
1135 iScheme
=INTERNET_SCHEME_NEWS
;
1136 else if (nMaxCmp
==strlenW(lpszMailto
) && !strncmpW(lpszMailto
, tempBuffer
, nMaxCmp
))
1137 iScheme
=INTERNET_SCHEME_MAILTO
;
1138 else if (nMaxCmp
==strlenW(lpszRes
) && !strncmpW(lpszRes
, tempBuffer
, nMaxCmp
))
1139 iScheme
=INTERNET_SCHEME_RES
;
1140 HeapFree(GetProcessHeap(),0,tempBuffer
);
1144 /***********************************************************************
1145 * SetUrlComponentValueW (Internal)
1147 * Helper function for InternetCrackUrlW
1154 static BOOL
SetUrlComponentValueW(LPWSTR
* lppszComponent
, LPDWORD dwComponentLen
, LPCWSTR lpszStart
, DWORD len
)
1156 TRACE("%s (%ld)\n", debugstr_wn(lpszStart
,len
), len
);
1158 if ( (*dwComponentLen
== 0) && (*lppszComponent
== NULL
) )
1161 if (*dwComponentLen
!= 0 || *lppszComponent
== NULL
)
1163 if (*lppszComponent
== NULL
)
1165 *lppszComponent
= (LPWSTR
)lpszStart
;
1166 *dwComponentLen
= len
;
1170 DWORD ncpylen
= min((*dwComponentLen
)-1, len
);
1171 strncpyW(*lppszComponent
, lpszStart
, ncpylen
);
1172 (*lppszComponent
)[ncpylen
] = '\0';
1173 *dwComponentLen
= ncpylen
;
1180 /***********************************************************************
1181 * InternetCrackUrlW (WININET.@)
1183 BOOL WINAPI
InternetCrackUrlW(LPCWSTR lpszUrl
, DWORD dwUrlLength
, DWORD dwFlags
,
1184 LPURL_COMPONENTSW lpUC
)
1188 * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
1191 LPCWSTR lpszParam
= NULL
;
1192 BOOL bIsAbsolute
= FALSE
;
1193 LPCWSTR lpszap
= lpszUrl
;
1194 LPCWSTR lpszcp
= NULL
;
1195 const WCHAR lpszSeparators
[3]={';','?',0};
1196 const WCHAR lpszSlash
[2]={'/',0};
1198 dwUrlLength
=strlenW(lpszUrl
);
1202 /* Determine if the URI is absolute. */
1203 while (*lpszap
!= '\0')
1205 if (isalnumW(*lpszap
))
1210 if ((*lpszap
== ':') && (lpszap
- lpszUrl
>= 2))
1217 lpszcp
= lpszUrl
; /* Relative url */
1223 /* Parse <params> */
1224 lpszParam
= strpbrkW(lpszap
, lpszSeparators
);
1225 if (lpszParam
!= NULL
)
1227 SetUrlComponentValueW(&lpUC
->lpszExtraInfo
, &lpUC
->dwExtraInfoLength
,
1228 lpszParam
, dwUrlLength
-(lpszParam
-lpszUrl
));
1231 if (bIsAbsolute
) /* Parse <protocol>:[//<net_loc>] */
1234 static const WCHAR wszAbout
[]={'a','b','o','u','t',':',0};
1236 /* Get scheme first. */
1237 lpUC
->nScheme
= GetInternetSchemeW(lpszUrl
, lpszcp
- lpszUrl
);
1238 SetUrlComponentValueW(&lpUC
->lpszScheme
, &lpUC
->dwSchemeLength
,
1239 lpszUrl
, lpszcp
- lpszUrl
);
1241 /* Eat ':' in protocol. */
1244 /* if the scheme is "about", there is no host */
1245 if(strncmpW(wszAbout
,lpszUrl
, lpszcp
- lpszUrl
)==0)
1247 SetUrlComponentValueW(&lpUC
->lpszUserName
, &lpUC
->dwUserNameLength
, NULL
, 0);
1248 SetUrlComponentValueW(&lpUC
->lpszPassword
, &lpUC
->dwPasswordLength
, NULL
, 0);
1249 SetUrlComponentValueW(&lpUC
->lpszHostName
, &lpUC
->dwHostNameLength
, NULL
, 0);
1254 /* Skip over slashes. */
1266 lpszNetLoc
= strpbrkW(lpszcp
, lpszSlash
);
1270 lpszNetLoc
= min(lpszNetLoc
, lpszParam
);
1272 lpszNetLoc
= lpszParam
;
1274 else if (!lpszNetLoc
)
1275 lpszNetLoc
= lpszcp
+ dwUrlLength
-(lpszcp
-lpszUrl
);
1283 /* [<user>[<:password>]@]<host>[:<port>] */
1284 /* First find the user and password if they exist */
1286 lpszHost
= strchrW(lpszcp
, '@');
1287 if (lpszHost
== NULL
|| lpszHost
> lpszNetLoc
)
1289 /* username and password not specified. */
1290 SetUrlComponentValueW(&lpUC
->lpszUserName
, &lpUC
->dwUserNameLength
, NULL
, 0);
1291 SetUrlComponentValueW(&lpUC
->lpszPassword
, &lpUC
->dwPasswordLength
, NULL
, 0);
1293 else /* Parse out username and password */
1295 LPCWSTR lpszUser
= lpszcp
;
1296 LPCWSTR lpszPasswd
= lpszHost
;
1298 while (lpszcp
< lpszHost
)
1301 lpszPasswd
= lpszcp
;
1306 SetUrlComponentValueW(&lpUC
->lpszUserName
, &lpUC
->dwUserNameLength
,
1307 lpszUser
, lpszPasswd
- lpszUser
);
1309 if (lpszPasswd
!= lpszHost
)
1311 SetUrlComponentValueW(&lpUC
->lpszPassword
, &lpUC
->dwPasswordLength
,
1312 lpszPasswd
== lpszHost
? NULL
: lpszPasswd
,
1313 lpszHost
- lpszPasswd
);
1315 lpszcp
++; /* Advance to beginning of host */
1318 /* Parse <host><:port> */
1321 lpszPort
= lpszNetLoc
;
1323 /* special case for res:// URLs: there is no port here, so the host is the
1324 entire string up to the first '/' */
1325 if(lpUC
->nScheme
==INTERNET_SCHEME_RES
)
1327 SetUrlComponentValueW(&lpUC
->lpszHostName
, &lpUC
->dwHostNameLength
,
1328 lpszHost
, lpszPort
- lpszHost
);
1334 while (lpszcp
< lpszNetLoc
)
1342 /* If the scheme is "file" and the host is just one letter, it's not a host */
1343 if(lpUC
->nScheme
==INTERNET_SCHEME_FILE
&& (lpszPort
-lpszHost
)==1)
1346 SetUrlComponentValueW(&lpUC
->lpszHostName
, &lpUC
->dwHostNameLength
,
1352 SetUrlComponentValueW(&lpUC
->lpszHostName
, &lpUC
->dwHostNameLength
,
1353 lpszHost
, lpszPort
- lpszHost
);
1354 if (lpszPort
!= lpszNetLoc
)
1355 lpUC
->nPort
= atoiW(++lpszPort
);
1364 /* Here lpszcp points to:
1366 * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
1367 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1369 if (lpszcp
!= 0 && *lpszcp
!= '\0' && (!lpszParam
|| lpszcp
< lpszParam
))
1373 /* Only truncate the parameter list if it's already been saved
1374 * in lpUC->lpszExtraInfo.
1376 if (lpszParam
&& lpUC
->dwExtraInfoLength
&& lpUC
->lpszExtraInfo
)
1377 len
= lpszParam
- lpszcp
;
1380 /* Leave the parameter list in lpszUrlPath. Strip off any trailing
1381 * newlines if necessary.
1383 LPWSTR lpsznewline
= strchrW(lpszcp
, '\n');
1384 if (lpsznewline
!= NULL
)
1385 len
= lpsznewline
- lpszcp
;
1387 len
= dwUrlLength
-(lpszcp
-lpszUrl
);
1390 SetUrlComponentValueW(&lpUC
->lpszUrlPath
, &lpUC
->dwUrlPathLength
,
1395 lpUC
->dwUrlPathLength
= 0;
1398 TRACE("%s: host(%s) path(%s) extra(%s)\n", debugstr_wn(lpszUrl
,dwUrlLength
),
1399 debugstr_wn(lpUC
->lpszHostName
,lpUC
->dwHostNameLength
),
1400 debugstr_wn(lpUC
->lpszUrlPath
,lpUC
->dwUrlPathLength
),
1401 debugstr_wn(lpUC
->lpszExtraInfo
,lpUC
->dwExtraInfoLength
));
1406 /***********************************************************************
1407 * InternetAttemptConnect (WININET.@)
1409 * Attempt to make a connection to the internet
1412 * ERROR_SUCCESS on success
1413 * Error value on failure
1416 DWORD WINAPI
InternetAttemptConnect(DWORD dwReserved
)
1419 return ERROR_SUCCESS
;
1423 /***********************************************************************
1424 * InternetCanonicalizeUrlA (WININET.@)
1426 * Escape unsafe characters and spaces
1433 BOOL WINAPI
InternetCanonicalizeUrlA(LPCSTR lpszUrl
, LPSTR lpszBuffer
,
1434 LPDWORD lpdwBufferLength
, DWORD dwFlags
)
1437 TRACE("%s %p %p %08lx\n",debugstr_a(lpszUrl
), lpszBuffer
,
1438 lpdwBufferLength
, dwFlags
);
1440 /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
1441 dwFlags
^= ICU_NO_ENCODE
;
1443 dwFlags
|= 0x80000000; /* Don't know what this means */
1445 hr
= UrlCanonicalizeA(lpszUrl
, lpszBuffer
, lpdwBufferLength
, dwFlags
);
1447 return (hr
== S_OK
) ? TRUE
: FALSE
;
1450 /***********************************************************************
1451 * InternetCanonicalizeUrlW (WININET.@)
1453 * Escape unsafe characters and spaces
1460 BOOL WINAPI
InternetCanonicalizeUrlW(LPCWSTR lpszUrl
, LPWSTR lpszBuffer
,
1461 LPDWORD lpdwBufferLength
, DWORD dwFlags
)
1464 TRACE("%s %p %p %08lx\n", debugstr_w(lpszUrl
), lpszBuffer
,
1465 lpdwBufferLength
, dwFlags
);
1467 /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
1468 dwFlags
^= ICU_NO_ENCODE
;
1470 dwFlags
|= 0x80000000; /* Don't know what this means */
1472 hr
= UrlCanonicalizeW(lpszUrl
, lpszBuffer
, lpdwBufferLength
, dwFlags
);
1474 return (hr
== S_OK
) ? TRUE
: FALSE
;
1478 /***********************************************************************
1479 * InternetSetStatusCallbackA (WININET.@)
1481 * Sets up a callback function which is called as progress is made
1482 * during an operation.
1485 * Previous callback or NULL on success
1486 * INTERNET_INVALID_STATUS_CALLBACK on failure
1489 INTERNET_STATUS_CALLBACK WINAPI
InternetSetStatusCallbackA(
1490 HINTERNET hInternet
,INTERNET_STATUS_CALLBACK lpfnIntCB
)
1492 INTERNET_STATUS_CALLBACK retVal
= INTERNET_INVALID_STATUS_CALLBACK
;
1493 LPWININETAPPINFOW lpwai
;
1495 TRACE("(%p, %p)\n", hInternet
, lpfnIntCB
);
1497 lpwai
= (LPWININETAPPINFOW
)WININET_GetObject(hInternet
);
1501 if (lpwai
->hdr
.htype
== WH_HINIT
)
1503 lpwai
->hdr
.dwInternalFlags
&= ~INET_CALLBACKW
;
1504 retVal
= lpwai
->lpfnStatusCB
;
1505 lpwai
->lpfnStatusCB
= lpfnIntCB
;
1507 WININET_Release( &lpwai
->hdr
);
1512 /***********************************************************************
1513 * InternetSetStatusCallbackW (WININET.@)
1515 * Sets up a callback function which is called as progress is made
1516 * during an operation.
1519 * Previous callback or NULL on success
1520 * INTERNET_INVALID_STATUS_CALLBACK on failure
1523 INTERNET_STATUS_CALLBACK WINAPI
InternetSetStatusCallbackW(
1524 HINTERNET hInternet
,INTERNET_STATUS_CALLBACK lpfnIntCB
)
1526 INTERNET_STATUS_CALLBACK retVal
= INTERNET_INVALID_STATUS_CALLBACK
;
1527 LPWININETAPPINFOW lpwai
;
1529 TRACE("(%p, %p)\n", hInternet
, lpfnIntCB
);
1531 lpwai
= (LPWININETAPPINFOW
)WININET_GetObject(hInternet
);
1535 if (lpwai
->hdr
.htype
== WH_HINIT
)
1537 lpwai
->hdr
.dwInternalFlags
|= INET_CALLBACKW
;
1538 retVal
= lpwai
->lpfnStatusCB
;
1539 lpwai
->lpfnStatusCB
= lpfnIntCB
;
1542 WININET_Release( &lpwai
->hdr
);
1547 /***********************************************************************
1548 * InternetSetFilePointer (WININET.@)
1550 DWORD WINAPI
InternetSetFilePointer(HINTERNET f1
, LONG f2
, PVOID f3
, DWORD f4
, DWORD f5
)
1556 /***********************************************************************
1557 * InternetWriteFile (WININET.@)
1559 * Write data to an open internet file
1566 BOOL WINAPI
InternetWriteFile(HINTERNET hFile
, LPCVOID lpBuffer
,
1567 DWORD dwNumOfBytesToWrite
, LPDWORD lpdwNumOfBytesWritten
)
1569 BOOL retval
= FALSE
;
1571 LPWININETHANDLEHEADER lpwh
;
1574 lpwh
= (LPWININETHANDLEHEADER
) WININET_GetObject( hFile
);
1578 switch (lpwh
->htype
)
1581 FIXME("This shouldn't be here! We don't support this kind"
1582 " of connection anymore. Must use NETCON functions,"
1583 " especially if using SSL\n");
1584 nSocket
= ((LPWININETHTTPREQW
)lpwh
)->netConnection
.socketFD
;
1588 nSocket
= ((LPWININETFILE
)lpwh
)->nDataSocket
;
1597 int res
= send(nSocket
, lpBuffer
, dwNumOfBytesToWrite
, 0);
1598 retval
= (res
>= 0);
1599 *lpdwNumOfBytesWritten
= retval
? res
: 0;
1601 WININET_Release( lpwh
);
1607 /***********************************************************************
1608 * InternetReadFile (WININET.@)
1610 * Read data from an open internet file
1617 BOOL WINAPI
InternetReadFile(HINTERNET hFile
, LPVOID lpBuffer
,
1618 DWORD dwNumOfBytesToRead
, LPDWORD dwNumOfBytesRead
)
1620 BOOL retval
= FALSE
;
1622 LPWININETHANDLEHEADER lpwh
;
1624 TRACE("%p %p %ld %p\n", hFile
, lpBuffer
, dwNumOfBytesToRead
, dwNumOfBytesRead
);
1626 lpwh
= (LPWININETHANDLEHEADER
) WININET_GetObject( hFile
);
1630 /* FIXME: this should use NETCON functions! */
1631 switch (lpwh
->htype
)
1634 if (!NETCON_recv(&((LPWININETHTTPREQW
)lpwh
)->netConnection
, lpBuffer
,
1635 dwNumOfBytesToRead
, MSG_WAITALL
, (int *)dwNumOfBytesRead
))
1637 *dwNumOfBytesRead
= 0;
1638 retval
= TRUE
; /* Under windows, it seems to return 0 even if nothing was read... */
1645 /* FIXME: FTP should use NETCON_ stuff */
1646 nSocket
= ((LPWININETFILE
)lpwh
)->nDataSocket
;
1649 int res
= recv(nSocket
, lpBuffer
, dwNumOfBytesToRead
, MSG_WAITALL
);
1650 retval
= (res
>= 0);
1651 *dwNumOfBytesRead
= retval
? res
: 0;
1658 WININET_Release( lpwh
);
1660 TRACE("-- %s (bytes read: %ld)\n", retval
? "TRUE": "FALSE", dwNumOfBytesRead
? *dwNumOfBytesRead
: -1);
1664 /***********************************************************************
1665 * InternetReadFileExA (WININET.@)
1667 * Read data from an open internet file
1674 BOOL WINAPI
InternetReadFileExA(HINTERNET hFile
, LPINTERNET_BUFFERSA lpBuffer
,
1675 DWORD dwFlags
, DWORD dwContext
)
1681 /***********************************************************************
1682 * InternetReadFileExW (WININET.@)
1684 * Read data from an open internet file
1691 BOOL WINAPI
InternetReadFileExW(HINTERNET hFile
, LPINTERNET_BUFFERSW lpBuffer
,
1692 DWORD dwFlags
, DWORD dwContext
)
1696 INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1700 /***********************************************************************
1701 * INET_QueryOptionHelper (internal)
1703 static BOOL
INET_QueryOptionHelper(BOOL bIsUnicode
, HINTERNET hInternet
, DWORD dwOption
,
1704 LPVOID lpBuffer
, LPDWORD lpdwBufferLength
)
1706 LPWININETHANDLEHEADER lpwhh
;
1707 BOOL bSuccess
= FALSE
;
1709 TRACE("(%p, 0x%08lx, %p, %p)\n", hInternet
, dwOption
, lpBuffer
, lpdwBufferLength
);
1711 lpwhh
= (LPWININETHANDLEHEADER
) WININET_GetObject( hInternet
);
1715 case INTERNET_OPTION_HANDLE_TYPE
:
1721 WARN("Invalid hInternet handle\n");
1722 SetLastError(ERROR_INVALID_HANDLE
);
1726 type
= lpwhh
->htype
;
1728 TRACE("INTERNET_OPTION_HANDLE_TYPE: %ld\n", type
);
1730 if (*lpdwBufferLength
< sizeof(ULONG
))
1731 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1734 memcpy(lpBuffer
, &type
, sizeof(ULONG
));
1735 *lpdwBufferLength
= sizeof(ULONG
);
1741 case INTERNET_OPTION_REQUEST_FLAGS
:
1744 TRACE("INTERNET_OPTION_REQUEST_FLAGS: %ld\n", flags
);
1745 if (*lpdwBufferLength
< sizeof(ULONG
))
1746 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1749 memcpy(lpBuffer
, &flags
, sizeof(ULONG
));
1750 *lpdwBufferLength
= sizeof(ULONG
);
1756 case INTERNET_OPTION_URL
:
1757 case INTERNET_OPTION_DATAFILE_NAME
:
1761 WARN("Invalid hInternet handle\n");
1762 SetLastError(ERROR_INVALID_HANDLE
);
1765 if (lpwhh
->htype
== WH_HHTTPREQ
)
1767 LPWININETHTTPREQW lpreq
= (LPWININETHTTPREQW
) lpwhh
;
1769 static const WCHAR szFmt
[] = {'h','t','t','p',':','/','/','%','s','%','s',0};
1771 sprintfW(url
,szFmt
,lpreq
->lpszHostName
,lpreq
->lpszPath
);
1772 TRACE("INTERNET_OPTION_URL: %s\n",debugstr_w(url
));
1773 if (*lpdwBufferLength
< strlenW(url
)+1)
1774 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1779 *lpdwBufferLength
=WideCharToMultiByte(CP_ACP
,0,url
,-1,lpBuffer
,*lpdwBufferLength
,NULL
,NULL
);
1783 strcpyW(lpBuffer
, url
);
1784 *lpdwBufferLength
= strlenW(url
)+1;
1791 case INTERNET_OPTION_HTTP_VERSION
:
1794 * Presently hardcoded to 1.1
1796 ((HTTP_VERSION_INFO
*)lpBuffer
)->dwMajorVersion
= 1;
1797 ((HTTP_VERSION_INFO
*)lpBuffer
)->dwMinorVersion
= 1;
1801 case INTERNET_OPTION_CONNECTED_STATE
:
1803 INTERNET_CONNECTED_INFO
* pCi
= (INTERNET_CONNECTED_INFO
*)lpBuffer
;
1804 FIXME("INTERNET_OPTION_CONNECTED_STATE: semi-stub\n");
1805 pCi
->dwConnectedState
= INTERNET_STATE_CONNECTED
;
1810 case INTERNET_OPTION_SECURITY_FLAGS
:
1811 FIXME("INTERNET_OPTION_SECURITY_FLAGS: Stub\n");
1815 FIXME("Stub! %ld \n",dwOption
);
1819 WININET_Release( lpwhh
);
1824 /***********************************************************************
1825 * InternetQueryOptionW (WININET.@)
1827 * Queries an options on the specified handle
1834 BOOL WINAPI
InternetQueryOptionW(HINTERNET hInternet
, DWORD dwOption
,
1835 LPVOID lpBuffer
, LPDWORD lpdwBufferLength
)
1837 return INET_QueryOptionHelper(TRUE
, hInternet
, dwOption
, lpBuffer
, lpdwBufferLength
);
1840 /***********************************************************************
1841 * InternetQueryOptionA (WININET.@)
1843 * Queries an options on the specified handle
1850 BOOL WINAPI
InternetQueryOptionA(HINTERNET hInternet
, DWORD dwOption
,
1851 LPVOID lpBuffer
, LPDWORD lpdwBufferLength
)
1853 return INET_QueryOptionHelper(FALSE
, hInternet
, dwOption
, lpBuffer
, lpdwBufferLength
);
1857 /***********************************************************************
1858 * InternetSetOptionW (WININET.@)
1860 * Sets an options on the specified handle
1867 BOOL WINAPI
InternetSetOptionW(HINTERNET hInternet
, DWORD dwOption
,
1868 LPVOID lpBuffer
, DWORD dwBufferLength
)
1870 LPWININETHANDLEHEADER lpwhh
;
1873 TRACE("0x%08lx\n", dwOption
);
1875 lpwhh
= (LPWININETHANDLEHEADER
) WININET_GetObject( hInternet
);
1881 case INTERNET_OPTION_HTTP_VERSION
:
1883 HTTP_VERSION_INFO
* pVersion
=(HTTP_VERSION_INFO
*)lpBuffer
;
1884 FIXME("Option INTERNET_OPTION_HTTP_VERSION(%ld,%ld): STUB\n",pVersion
->dwMajorVersion
,pVersion
->dwMinorVersion
);
1887 case INTERNET_OPTION_ERROR_MASK
:
1889 unsigned long flags
=*(unsigned long*)lpBuffer
;
1890 FIXME("Option INTERNET_OPTION_ERROR_MASK(%ld): STUB\n",flags
);
1893 case INTERNET_OPTION_CODEPAGE
:
1895 unsigned long codepage
=*(unsigned long*)lpBuffer
;
1896 FIXME("Option INTERNET_OPTION_CODEPAGE (%ld): STUB\n",codepage
);
1899 case INTERNET_OPTION_REQUEST_PRIORITY
:
1901 unsigned long priority
=*(unsigned long*)lpBuffer
;
1902 FIXME("Option INTERNET_OPTION_REQUEST_PRIORITY (%ld): STUB\n",priority
);
1905 case INTERNET_OPTION_CONNECT_TIMEOUT
:
1907 unsigned long connecttimeout
=*(unsigned long*)lpBuffer
;
1908 FIXME("Option INTERNET_OPTION_CONNECT_TIMEOUT (%ld): STUB\n",connecttimeout
);
1911 case INTERNET_OPTION_DATA_RECEIVE_TIMEOUT
:
1913 unsigned long receivetimeout
=*(unsigned long*)lpBuffer
;
1914 FIXME("Option INTERNET_OPTION_DATA_RECEIVE_TIMEOUT (%ld): STUB\n",receivetimeout
);
1917 case INTERNET_OPTION_RESET_URLCACHE_SESSION
:
1918 FIXME("Option INTERNET_OPTION_RESET_URLCACHE_SESSION: STUB\n");
1920 case INTERNET_OPTION_END_BROWSER_SESSION
:
1921 FIXME("Option INTERNET_OPTION_END_BROWSER_SESSION: STUB\n");
1923 case INTERNET_OPTION_CONNECTED_STATE
:
1924 FIXME("Option INTERNET_OPTION_CONNECTED_STATE: STUB\n");
1927 FIXME("Option %ld STUB\n",dwOption
);
1928 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
1932 WININET_Release( lpwhh
);
1938 /***********************************************************************
1939 * InternetSetOptionA (WININET.@)
1941 * Sets an options on the specified handle.
1948 BOOL WINAPI
InternetSetOptionA(HINTERNET hInternet
, DWORD dwOption
,
1949 LPVOID lpBuffer
, DWORD dwBufferLength
)
1957 case INTERNET_OPTION_PROXY
:
1959 LPINTERNET_PROXY_INFOA pi
= (LPINTERNET_PROXY_INFOA
) lpBuffer
;
1960 LPINTERNET_PROXY_INFOW piw
;
1961 DWORD proxlen
, prbylen
;
1964 proxlen
= MultiByteToWideChar( CP_ACP
, 0, pi
->lpszProxy
, -1, NULL
, 0);
1965 prbylen
= MultiByteToWideChar( CP_ACP
, 0, pi
->lpszProxyBypass
, -1, NULL
, 0);
1966 wlen
= sizeof(*piw
) + proxlen
+ prbylen
;
1967 wbuffer
= HeapAlloc( GetProcessHeap(), 0, wlen
*sizeof(WCHAR
) );
1968 piw
= (LPINTERNET_PROXY_INFOW
) wbuffer
;
1969 piw
->dwAccessType
= pi
->dwAccessType
;
1970 prox
= (LPWSTR
) &piw
[1];
1971 prby
= &prox
[proxlen
+1];
1972 MultiByteToWideChar( CP_ACP
, 0, pi
->lpszProxy
, -1, prox
, proxlen
);
1973 MultiByteToWideChar( CP_ACP
, 0, pi
->lpszProxyBypass
, -1, prby
, prbylen
);
1974 piw
->lpszProxy
= prox
;
1975 piw
->lpszProxyBypass
= prby
;
1978 case INTERNET_OPTION_USER_AGENT
:
1979 case INTERNET_OPTION_USERNAME
:
1980 case INTERNET_OPTION_PASSWORD
:
1981 wlen
= MultiByteToWideChar( CP_ACP
, 0, lpBuffer
, dwBufferLength
,
1983 wbuffer
= HeapAlloc( GetProcessHeap(), 0, wlen
*sizeof(WCHAR
) );
1984 MultiByteToWideChar( CP_ACP
, 0, lpBuffer
, dwBufferLength
,
1989 wlen
= dwBufferLength
;
1992 r
= InternetSetOptionW(hInternet
,dwOption
, wbuffer
, wlen
);
1994 if( lpBuffer
!= wbuffer
)
1995 HeapFree( GetProcessHeap(), 0, wbuffer
);
2001 /***********************************************************************
2002 * InternetSetOptionExA (WININET.@)
2004 BOOL WINAPI
InternetSetOptionExA(HINTERNET hInternet
, DWORD dwOption
,
2005 LPVOID lpBuffer
, DWORD dwBufferLength
, DWORD dwFlags
)
2007 FIXME("Flags %08lx ignored\n", dwFlags
);
2008 return InternetSetOptionA( hInternet
, dwOption
, lpBuffer
, dwBufferLength
);
2011 /***********************************************************************
2012 * InternetSetOptionExW (WININET.@)
2014 BOOL WINAPI
InternetSetOptionExW(HINTERNET hInternet
, DWORD dwOption
,
2015 LPVOID lpBuffer
, DWORD dwBufferLength
, DWORD dwFlags
)
2017 FIXME("Flags %08lx ignored\n", dwFlags
);
2018 if( dwFlags
& ~ISO_VALID_FLAGS
)
2020 SetLastError( ERROR_INVALID_PARAMETER
);
2023 return InternetSetOptionW( hInternet
, dwOption
, lpBuffer
, dwBufferLength
);
2027 /***********************************************************************
2028 * InternetCheckConnectionA (WININET.@)
2030 * Pings a requested host to check internet connection
2033 * TRUE on success and FALSE on failure. If a failure then
2034 * ERROR_NOT_CONNECTED is placesd into GetLastError
2037 BOOL WINAPI
InternetCheckConnectionA( LPCSTR lpszUrl
, DWORD dwFlags
, DWORD dwReserved
)
2040 * this is a kludge which runs the resident ping program and reads the output.
2042 * Anyone have a better idea?
2053 * Crack or set the Address
2055 if (lpszUrl
== NULL
)
2058 * According to the doc we are supost to use the ip for the next
2059 * server in the WnInet internal server database. I have
2060 * no idea what that is or how to get it.
2062 * So someone needs to implement this.
2064 FIXME("Unimplemented with URL of NULL\n");
2069 URL_COMPONENTSA componets
;
2071 ZeroMemory(&componets
,sizeof(URL_COMPONENTSA
));
2072 componets
.lpszHostName
= (LPSTR
)&host
;
2073 componets
.dwHostNameLength
= 1024;
2075 if (!InternetCrackUrlA(lpszUrl
,0,0,&componets
))
2078 TRACE("host name : %s\n",componets
.lpszHostName
);
2082 * Build our ping command
2084 strcpy(command
,"ping -w 1 ");
2085 strcat(command
,host
);
2086 strcat(command
," >/dev/null 2>/dev/null");
2088 TRACE("Ping command is : %s\n",command
);
2090 status
= system(command
);
2092 TRACE("Ping returned a code of %i \n",status
);
2094 /* Ping return code of 0 indicates success */
2101 SetLastError(ERROR_NOT_CONNECTED
);
2107 /***********************************************************************
2108 * InternetCheckConnectionW (WININET.@)
2110 * Pings a requested host to check internet connection
2113 * TRUE on success and FALSE on failure. If a failure then
2114 * ERROR_NOT_CONNECTED is placed into GetLastError
2117 BOOL WINAPI
InternetCheckConnectionW(LPCWSTR lpszUrl
, DWORD dwFlags
, DWORD dwReserved
)
2123 len
= WideCharToMultiByte(CP_ACP
, 0, lpszUrl
, -1, NULL
, 0, NULL
, NULL
);
2124 if (!(szUrl
= (CHAR
*)HeapAlloc(GetProcessHeap(), 0, len
*sizeof(CHAR
))))
2126 WideCharToMultiByte(CP_ACP
, 0, lpszUrl
, -1, szUrl
, len
, NULL
, NULL
);
2127 rc
= InternetCheckConnectionA((LPCSTR
)szUrl
, dwFlags
, dwReserved
);
2128 HeapFree(GetProcessHeap(), 0, szUrl
);
2134 /**********************************************************
2135 * INTERNET_InternetOpenUrlW (internal)
2140 * handle of connection or NULL on failure
2142 HINTERNET WINAPI
INTERNET_InternetOpenUrlW(LPWININETAPPINFOW hIC
, LPCWSTR lpszUrl
,
2143 LPCWSTR lpszHeaders
, DWORD dwHeadersLength
, DWORD dwFlags
, DWORD dwContext
)
2145 URL_COMPONENTSW urlComponents
;
2146 WCHAR protocol
[32], hostName
[MAXHOSTNAME
], userName
[1024];
2147 WCHAR password
[1024], path
[2048], extra
[1024];
2148 HINTERNET client
= NULL
, client1
= NULL
;
2150 TRACE("(%p, %s, %s, %08lx, %08lx, %08lx\n", hIC
, debugstr_w(lpszUrl
), debugstr_w(lpszHeaders
),
2151 dwHeadersLength
, dwFlags
, dwContext
);
2153 urlComponents
.dwStructSize
= sizeof(URL_COMPONENTSW
);
2154 urlComponents
.lpszScheme
= protocol
;
2155 urlComponents
.dwSchemeLength
= 32;
2156 urlComponents
.lpszHostName
= hostName
;
2157 urlComponents
.dwHostNameLength
= MAXHOSTNAME
;
2158 urlComponents
.lpszUserName
= userName
;
2159 urlComponents
.dwUserNameLength
= 1024;
2160 urlComponents
.lpszPassword
= password
;
2161 urlComponents
.dwPasswordLength
= 1024;
2162 urlComponents
.lpszUrlPath
= path
;
2163 urlComponents
.dwUrlPathLength
= 2048;
2164 urlComponents
.lpszExtraInfo
= extra
;
2165 urlComponents
.dwExtraInfoLength
= 1024;
2166 if(!InternetCrackUrlW(lpszUrl
, strlenW(lpszUrl
), 0, &urlComponents
))
2168 switch(urlComponents
.nScheme
) {
2169 case INTERNET_SCHEME_FTP
:
2170 if(urlComponents
.nPort
== 0)
2171 urlComponents
.nPort
= INTERNET_DEFAULT_FTP_PORT
;
2172 client
= FTP_Connect(hIC
, hostName
, urlComponents
.nPort
,
2173 userName
, password
, dwFlags
, dwContext
, INET_OPENURL
);
2176 client1
= FtpOpenFileW(client
, path
, GENERIC_READ
, dwFlags
, dwContext
);
2177 if(client1
== NULL
) {
2178 InternetCloseHandle(client
);
2183 case INTERNET_SCHEME_HTTP
:
2184 case INTERNET_SCHEME_HTTPS
: {
2185 static const WCHAR szStars
[] = { '*','/','*', 0 };
2186 LPCWSTR accept
[2] = { szStars
, NULL
};
2187 if(urlComponents
.nPort
== 0) {
2188 if(urlComponents
.nScheme
== INTERNET_SCHEME_HTTP
)
2189 urlComponents
.nPort
= INTERNET_DEFAULT_HTTP_PORT
;
2191 urlComponents
.nPort
= INTERNET_DEFAULT_HTTPS_PORT
;
2193 /* FIXME: should use pointers, not handles, as handles are not thread-safe */
2194 client
= HTTP_Connect(hIC
, hostName
, urlComponents
.nPort
,
2195 userName
, password
, dwFlags
, dwContext
, INET_OPENURL
);
2198 client1
= HttpOpenRequestW(client
, NULL
, path
, NULL
, NULL
, accept
, dwFlags
, dwContext
);
2199 if(client1
== NULL
) {
2200 InternetCloseHandle(client
);
2203 HttpAddRequestHeadersW(client1
, lpszHeaders
, dwHeadersLength
, HTTP_ADDREQ_FLAG_ADD
);
2204 if (!HttpSendRequestW(client1
, NULL
, 0, NULL
, 0)) {
2205 InternetCloseHandle(client1
);
2210 case INTERNET_SCHEME_GOPHER
:
2211 /* gopher doesn't seem to be implemented in wine, but it's supposed
2212 * to be supported by InternetOpenUrlA. */
2217 TRACE(" %p <--\n", client1
);
2222 /**********************************************************
2223 * InternetOpenUrlW (WININET.@)
2228 * handle of connection or NULL on failure
2230 HINTERNET WINAPI
InternetOpenUrlW(HINTERNET hInternet
, LPCWSTR lpszUrl
,
2231 LPCWSTR lpszHeaders
, DWORD dwHeadersLength
, DWORD dwFlags
, DWORD dwContext
)
2233 HINTERNET ret
= NULL
;
2234 LPWININETAPPINFOW hIC
= NULL
;
2236 TRACE("(%p, %s, %s, %08lx, %08lx, %08lx\n", hInternet
, debugstr_w(lpszUrl
), debugstr_w(lpszHeaders
),
2237 dwHeadersLength
, dwFlags
, dwContext
);
2239 hIC
= (LPWININETAPPINFOW
) WININET_GetObject( hInternet
);
2240 if (NULL
== hIC
|| hIC
->hdr
.htype
!= WH_HINIT
) {
2241 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
2245 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
) {
2246 WORKREQUEST workRequest
;
2247 struct WORKREQ_INTERNETOPENURLW
*req
;
2249 workRequest
.asyncall
= INTERNETOPENURLW
;
2250 workRequest
.hdr
= WININET_AddRef( &hIC
->hdr
);
2251 req
= &workRequest
.u
.InternetOpenUrlW
;
2253 req
->lpszUrl
= WININET_strdupW(lpszUrl
);
2257 req
->lpszHeaders
= WININET_strdupW(lpszHeaders
);
2259 req
->lpszHeaders
= 0;
2260 req
->dwHeadersLength
= dwHeadersLength
;
2261 req
->dwFlags
= dwFlags
;
2262 req
->dwContext
= dwContext
;
2264 INTERNET_AsyncCall(&workRequest
);
2266 * This is from windows.
2268 SetLastError(ERROR_IO_PENDING
);
2270 ret
= INTERNET_InternetOpenUrlW(hIC
, lpszUrl
, lpszHeaders
, dwHeadersLength
, dwFlags
, dwContext
);
2275 WININET_Release( &hIC
->hdr
);
2276 TRACE(" %p <--\n", ret
);
2281 /**********************************************************
2282 * InternetOpenUrlA (WININET.@)
2287 * handle of connection or NULL on failure
2289 HINTERNET WINAPI
InternetOpenUrlA(HINTERNET hInternet
, LPCSTR lpszUrl
,
2290 LPCSTR lpszHeaders
, DWORD dwHeadersLength
, DWORD dwFlags
, DWORD dwContext
)
2292 HINTERNET rc
= (HINTERNET
)NULL
;
2296 LPWSTR szUrl
= NULL
;
2297 LPWSTR szHeaders
= NULL
;
2302 lenUrl
= MultiByteToWideChar(CP_ACP
, 0, lpszUrl
, -1, NULL
, 0 );
2303 szUrl
= HeapAlloc(GetProcessHeap(), 0, lenUrl
*sizeof(WCHAR
));
2305 return (HINTERNET
)NULL
;
2306 MultiByteToWideChar(CP_ACP
, 0, lpszUrl
, -1, szUrl
, lenUrl
);
2310 lenHeaders
= MultiByteToWideChar(CP_ACP
, 0, lpszHeaders
, dwHeadersLength
, NULL
, 0 );
2311 szHeaders
= HeapAlloc(GetProcessHeap(), 0, lenHeaders
*sizeof(WCHAR
));
2313 if(szUrl
) HeapFree(GetProcessHeap(), 0, szUrl
);
2314 return (HINTERNET
)NULL
;
2316 MultiByteToWideChar(CP_ACP
, 0, lpszHeaders
, dwHeadersLength
, szHeaders
, lenHeaders
);
2319 rc
= InternetOpenUrlW(hInternet
, szUrl
, szHeaders
,
2320 lenHeaders
, dwFlags
, dwContext
);
2322 if(szUrl
) HeapFree(GetProcessHeap(), 0, szUrl
);
2323 if(szHeaders
) HeapFree(GetProcessHeap(), 0, szHeaders
);
2329 /***********************************************************************
2330 * INTERNET_SetLastError (internal)
2332 * Set last thread specific error
2337 void INTERNET_SetLastError(DWORD dwError
)
2339 LPWITHREADERROR lpwite
= (LPWITHREADERROR
)TlsGetValue(g_dwTlsErrIndex
);
2341 SetLastError(dwError
);
2343 lpwite
->dwError
= dwError
;
2347 /***********************************************************************
2348 * INTERNET_GetLastError (internal)
2350 * Get last thread specific error
2355 DWORD
INTERNET_GetLastError()
2357 LPWITHREADERROR lpwite
= (LPWITHREADERROR
)TlsGetValue(g_dwTlsErrIndex
);
2358 return lpwite
->dwError
;
2362 /***********************************************************************
2363 * INTERNET_WorkerThreadFunc (internal)
2365 * Worker thread execution function
2370 DWORD
INTERNET_WorkerThreadFunc(LPVOID
*lpvParam
)
2377 INTERNET_ExecuteWork();
2380 dwWaitRes
= WaitForMultipleObjects(2, hEventArray
, FALSE
, MAX_IDLE_WORKER
);
2382 if (dwWaitRes
== WAIT_OBJECT_0
+ 1)
2383 INTERNET_ExecuteWork();
2387 InterlockedIncrement(&dwNumIdleThreads
);
2390 InterlockedDecrement(&dwNumIdleThreads
);
2391 InterlockedDecrement(&dwNumThreads
);
2392 TRACE("Worker thread exiting\n");
2397 /***********************************************************************
2398 * INTERNET_InsertWorkRequest (internal)
2400 * Insert work request into queue
2405 BOOL
INTERNET_InsertWorkRequest(LPWORKREQUEST lpWorkRequest
)
2407 BOOL bSuccess
= FALSE
;
2408 LPWORKREQUEST lpNewRequest
;
2412 lpNewRequest
= HeapAlloc(GetProcessHeap(), 0, sizeof(WORKREQUEST
));
2415 memcpy(lpNewRequest
, lpWorkRequest
, sizeof(WORKREQUEST
));
2416 lpNewRequest
->prev
= NULL
;
2418 EnterCriticalSection(&csQueue
);
2420 lpNewRequest
->next
= lpWorkQueueTail
;
2421 if (lpWorkQueueTail
)
2422 lpWorkQueueTail
->prev
= lpNewRequest
;
2423 lpWorkQueueTail
= lpNewRequest
;
2424 if (!lpHeadWorkQueue
)
2425 lpHeadWorkQueue
= lpWorkQueueTail
;
2427 LeaveCriticalSection(&csQueue
);
2430 InterlockedIncrement(&dwNumJobs
);
2437 /***********************************************************************
2438 * INTERNET_GetWorkRequest (internal)
2440 * Retrieves work request from queue
2445 BOOL
INTERNET_GetWorkRequest(LPWORKREQUEST lpWorkRequest
)
2447 BOOL bSuccess
= FALSE
;
2448 LPWORKREQUEST lpRequest
= NULL
;
2452 EnterCriticalSection(&csQueue
);
2454 if (lpHeadWorkQueue
)
2456 lpRequest
= lpHeadWorkQueue
;
2457 lpHeadWorkQueue
= lpHeadWorkQueue
->prev
;
2458 if (lpRequest
== lpWorkQueueTail
)
2459 lpWorkQueueTail
= lpHeadWorkQueue
;
2462 LeaveCriticalSection(&csQueue
);
2466 memcpy(lpWorkRequest
, lpRequest
, sizeof(WORKREQUEST
));
2467 HeapFree(GetProcessHeap(), 0, lpRequest
);
2469 InterlockedDecrement(&dwNumJobs
);
2476 /***********************************************************************
2477 * INTERNET_AsyncCall (internal)
2479 * Retrieves work request from queue
2484 BOOL
INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest
)
2488 BOOL bSuccess
= FALSE
;
2492 if (InterlockedDecrement(&dwNumIdleThreads
) < 0)
2494 InterlockedIncrement(&dwNumIdleThreads
);
2496 if (InterlockedIncrement(&dwNumThreads
) > MAX_WORKER_THREADS
||
2497 !(hThread
= CreateThread(NULL
, 0,
2498 (LPTHREAD_START_ROUTINE
)INTERNET_WorkerThreadFunc
, NULL
, 0, &dwTID
)))
2500 InterlockedDecrement(&dwNumThreads
);
2501 INTERNET_SetLastError(ERROR_INTERNET_ASYNC_THREAD_FAILED
);
2505 TRACE("Created new thread\n");
2509 INTERNET_InsertWorkRequest(lpWorkRequest
);
2510 SetEvent(hWorkEvent
);
2518 /***********************************************************************
2519 * INTERNET_ExecuteWork (internal)
2524 static VOID
INTERNET_ExecuteWork()
2526 WORKREQUEST workRequest
;
2530 if (!INTERNET_GetWorkRequest(&workRequest
))
2533 switch (workRequest
.asyncall
)
2537 struct WORKREQ_FTPPUTFILEW
*req
= &workRequest
.u
.FtpPutFileW
;
2538 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) workRequest
.hdr
;
2540 TRACE("FTPPUTFILEW %p\n", lpwfs
);
2542 FTP_FtpPutFileW(lpwfs
, req
->lpszLocalFile
,
2543 req
->lpszNewRemoteFile
, req
->dwFlags
, req
->dwContext
);
2545 HeapFree(GetProcessHeap(), 0, req
->lpszLocalFile
);
2546 HeapFree(GetProcessHeap(), 0, req
->lpszNewRemoteFile
);
2550 case FTPSETCURRENTDIRECTORYW
:
2552 struct WORKREQ_FTPSETCURRENTDIRECTORYW
*req
;
2553 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) workRequest
.hdr
;
2555 TRACE("FTPSETCURRENTDIRECTORYW %p\n", lpwfs
);
2557 req
= &workRequest
.u
.FtpSetCurrentDirectoryW
;
2558 FTP_FtpSetCurrentDirectoryW(lpwfs
, req
->lpszDirectory
);
2559 HeapFree(GetProcessHeap(), 0, req
->lpszDirectory
);
2563 case FTPCREATEDIRECTORYW
:
2565 struct WORKREQ_FTPCREATEDIRECTORYW
*req
;
2566 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) workRequest
.hdr
;
2568 TRACE("FTPCREATEDIRECTORYW %p\n", lpwfs
);
2570 req
= &workRequest
.u
.FtpCreateDirectoryW
;
2571 FTP_FtpCreateDirectoryW(lpwfs
, req
->lpszDirectory
);
2572 HeapFree(GetProcessHeap(), 0, req
->lpszDirectory
);
2576 case FTPFINDFIRSTFILEW
:
2578 struct WORKREQ_FTPFINDFIRSTFILEW
*req
;
2579 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) workRequest
.hdr
;
2581 TRACE("FTPFINDFIRSTFILEW %p\n", lpwfs
);
2583 req
= &workRequest
.u
.FtpFindFirstFileW
;
2584 FTP_FtpFindFirstFileW(lpwfs
, req
->lpszSearchFile
,
2585 req
->lpFindFileData
, req
->dwFlags
, req
->dwContext
);
2586 if (req
->lpszSearchFile
!= NULL
)
2587 HeapFree(GetProcessHeap(), 0, req
->lpszSearchFile
);
2591 case FTPGETCURRENTDIRECTORYW
:
2593 struct WORKREQ_FTPGETCURRENTDIRECTORYW
*req
;
2594 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) workRequest
.hdr
;
2596 TRACE("FTPGETCURRENTDIRECTORYW %p\n", lpwfs
);
2598 req
= &workRequest
.u
.FtpGetCurrentDirectoryW
;
2599 FTP_FtpGetCurrentDirectoryW(lpwfs
,
2600 req
->lpszDirectory
, req
->lpdwDirectory
);
2606 struct WORKREQ_FTPOPENFILEW
*req
= &workRequest
.u
.FtpOpenFileW
;
2607 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) workRequest
.hdr
;
2609 TRACE("FTPOPENFILEW %p\n", lpwfs
);
2611 FTP_FtpOpenFileW(lpwfs
, req
->lpszFilename
,
2612 req
->dwAccess
, req
->dwFlags
, req
->dwContext
);
2613 HeapFree(GetProcessHeap(), 0, req
->lpszFilename
);
2619 struct WORKREQ_FTPGETFILEW
*req
= &workRequest
.u
.FtpGetFileW
;
2620 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) workRequest
.hdr
;
2622 TRACE("FTPGETFILEW %p\n", lpwfs
);
2624 FTP_FtpGetFileW(lpwfs
, req
->lpszRemoteFile
,
2625 req
->lpszNewFile
, req
->fFailIfExists
,
2626 req
->dwLocalFlagsAttribute
, req
->dwFlags
, req
->dwContext
);
2627 HeapFree(GetProcessHeap(), 0, req
->lpszRemoteFile
);
2628 HeapFree(GetProcessHeap(), 0, req
->lpszNewFile
);
2632 case FTPDELETEFILEW
:
2634 struct WORKREQ_FTPDELETEFILEW
*req
= &workRequest
.u
.FtpDeleteFileW
;
2635 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) workRequest
.hdr
;
2637 TRACE("FTPDELETEFILEW %p\n", lpwfs
);
2639 FTP_FtpDeleteFileW(lpwfs
, req
->lpszFilename
);
2640 HeapFree(GetProcessHeap(), 0, req
->lpszFilename
);
2644 case FTPREMOVEDIRECTORYW
:
2646 struct WORKREQ_FTPREMOVEDIRECTORYW
*req
;
2647 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) workRequest
.hdr
;
2649 TRACE("FTPREMOVEDIRECTORYW %p\n", lpwfs
);
2651 req
= &workRequest
.u
.FtpRemoveDirectoryW
;
2652 FTP_FtpRemoveDirectoryW(lpwfs
, req
->lpszDirectory
);
2653 HeapFree(GetProcessHeap(), 0, req
->lpszDirectory
);
2657 case FTPRENAMEFILEW
:
2659 struct WORKREQ_FTPRENAMEFILEW
*req
= &workRequest
.u
.FtpRenameFileW
;
2660 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) workRequest
.hdr
;
2662 TRACE("FTPRENAMEFILEW %p\n", lpwfs
);
2664 FTP_FtpRenameFileW(lpwfs
, req
->lpszSrcFile
, req
->lpszDestFile
);
2665 HeapFree(GetProcessHeap(), 0, req
->lpszSrcFile
);
2666 HeapFree(GetProcessHeap(), 0, req
->lpszDestFile
);
2670 case INTERNETFINDNEXTW
:
2672 struct WORKREQ_INTERNETFINDNEXTW
*req
;
2673 LPWININETFINDNEXTW lpwh
= (LPWININETFINDNEXTW
) workRequest
.hdr
;
2675 TRACE("INTERNETFINDNEXTW %p\n", lpwh
);
2677 req
= &workRequest
.u
.InternetFindNextW
;
2678 INTERNET_FindNextFileW(lpwh
, req
->lpFindFileData
);
2682 case HTTPSENDREQUESTW
:
2684 struct WORKREQ_HTTPSENDREQUESTW
*req
= &workRequest
.u
.HttpSendRequestW
;
2685 LPWININETHTTPREQW lpwhr
= (LPWININETHTTPREQW
) workRequest
.hdr
;
2687 TRACE("HTTPSENDREQUESTW %p\n", lpwhr
);
2689 HTTP_HttpSendRequestW(lpwhr
, req
->lpszHeader
,
2690 req
->dwHeaderLength
, req
->lpOptional
, req
->dwOptionalLength
);
2692 HeapFree(GetProcessHeap(), 0, req
->lpszHeader
);
2696 case HTTPOPENREQUESTW
:
2698 struct WORKREQ_HTTPOPENREQUESTW
*req
= &workRequest
.u
.HttpOpenRequestW
;
2699 LPWININETHTTPSESSIONW lpwhs
= (LPWININETHTTPSESSIONW
) workRequest
.hdr
;
2701 TRACE("HTTPOPENREQUESTW %p\n", lpwhs
);
2703 HTTP_HttpOpenRequestW(lpwhs
, req
->lpszVerb
,
2704 req
->lpszObjectName
, req
->lpszVersion
, req
->lpszReferrer
,
2705 req
->lpszAcceptTypes
, req
->dwFlags
, req
->dwContext
);
2707 HeapFree(GetProcessHeap(), 0, req
->lpszVerb
);
2708 HeapFree(GetProcessHeap(), 0, req
->lpszObjectName
);
2709 HeapFree(GetProcessHeap(), 0, req
->lpszVersion
);
2710 HeapFree(GetProcessHeap(), 0, req
->lpszReferrer
);
2716 struct WORKREQ_SENDCALLBACK
*req
= &workRequest
.u
.SendCallback
;
2717 LPWININETAPPINFOW hIC
= (LPWININETAPPINFOW
) workRequest
.hdr
;
2719 TRACE("SENDCALLBACK %p\n", hIC
);
2721 SendAsyncCallbackInt(hIC
, req
->hdr
,
2722 req
->dwContext
, req
->dwInternetStatus
, req
->lpvStatusInfo
,
2723 req
->dwStatusInfoLength
);
2727 case INTERNETOPENURLW
:
2729 struct WORKREQ_INTERNETOPENURLW
*req
= &workRequest
.u
.InternetOpenUrlW
;
2730 LPWININETAPPINFOW hIC
= (LPWININETAPPINFOW
) workRequest
.hdr
;
2732 TRACE("INTERNETOPENURLW %p\n", hIC
);
2734 INTERNET_InternetOpenUrlW(hIC
, req
->lpszUrl
,
2735 req
->lpszHeaders
, req
->dwHeadersLength
, req
->dwFlags
, req
->dwContext
);
2736 HeapFree(GetProcessHeap(), 0, req
->lpszUrl
);
2737 HeapFree(GetProcessHeap(), 0, req
->lpszHeaders
);
2741 WININET_Release( workRequest
.hdr
);
2745 /***********************************************************************
2746 * INTERNET_GetResponseBuffer
2751 LPSTR
INTERNET_GetResponseBuffer()
2753 LPWITHREADERROR lpwite
= (LPWITHREADERROR
)TlsGetValue(g_dwTlsErrIndex
);
2755 return lpwite
->response
;
2758 /***********************************************************************
2759 * INTERNET_GetNextLine (internal)
2761 * Parse next line in directory string listing
2764 * Pointer to beginning of next line
2769 LPSTR
INTERNET_GetNextLine(INT nSocket
, LPDWORD dwLen
)
2773 BOOL bSuccess
= FALSE
;
2775 LPSTR lpszBuffer
= INTERNET_GetResponseBuffer();
2780 FD_SET(nSocket
, &infd
);
2781 tv
.tv_sec
=RESPONSE_TIMEOUT
;
2784 while (nRecv
< MAX_REPLY_LEN
)
2786 if (select(nSocket
+1,&infd
,NULL
,NULL
,&tv
) > 0)
2788 if (recv(nSocket
, &lpszBuffer
[nRecv
], 1, 0) <= 0)
2790 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS
);
2794 if (lpszBuffer
[nRecv
] == '\n')
2799 if (lpszBuffer
[nRecv
] != '\r')
2804 INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT
);
2812 lpszBuffer
[nRecv
] = '\0';
2814 TRACE(":%d %s\n", nRecv
, lpszBuffer
);
2823 /***********************************************************************
2826 BOOL WINAPI
InternetQueryDataAvailable( HINTERNET hFile
,
2827 LPDWORD lpdwNumberOfBytesAvailble
,
2828 DWORD dwFlags
, DWORD dwConext
)
2830 LPWININETHTTPREQW lpwhr
;
2834 lpwhr
= (LPWININETHTTPREQW
) WININET_GetObject( hFile
);
2837 SetLastError(ERROR_NO_MORE_FILES
);
2841 TRACE("--> %p %i\n",lpwhr
,lpwhr
->hdr
.htype
);
2843 switch (lpwhr
->hdr
.htype
)
2846 if (!NETCON_recv(&lpwhr
->netConnection
, buffer
,
2847 4048, MSG_PEEK
, (int *)lpdwNumberOfBytesAvailble
))
2849 SetLastError(ERROR_NO_MORE_FILES
);
2857 FIXME("unsupported file type\n");
2860 WININET_Release( &lpwhr
->hdr
);
2862 TRACE("<-- %i\n",retval
);
2867 /***********************************************************************
2870 BOOL WINAPI
InternetLockRequestFile( HINTERNET hInternet
, HANDLE
2877 BOOL WINAPI
InternetUnlockRequestFile( HANDLE hLockHandle
)
2884 /***********************************************************************
2887 * On windows this function is supposed to dial the default internet
2888 * connection. We don't want to have Wine dial out to the internet so
2889 * we return TRUE by default. It might be nice to check if we are connected.
2896 BOOL WINAPI
InternetAutodial(DWORD dwFlags
, HWND hwndParent
)
2900 /* Tell that we are connected to the internet. */
2904 /***********************************************************************
2905 * InternetAutodialHangup
2907 * Hangs up an connection made with InternetAutodial
2916 BOOL WINAPI
InternetAutodialHangup(DWORD dwReserved
)
2920 /* we didn't dial, we don't disconnect */
2924 /***********************************************************************
2926 * InternetCombineUrlA
2928 * Combine a base URL with a relative URL
2936 BOOL WINAPI
InternetCombineUrlA(LPCSTR lpszBaseUrl
, LPCSTR lpszRelativeUrl
,
2937 LPSTR lpszBuffer
, LPDWORD lpdwBufferLength
,
2942 TRACE("(%s, %s, %p, %p, 0x%08lx)\n", debugstr_a(lpszBaseUrl
), debugstr_a(lpszRelativeUrl
), lpszBuffer
, lpdwBufferLength
, dwFlags
);
2944 /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
2945 dwFlags
^= ICU_NO_ENCODE
;
2946 hr
=UrlCombineA(lpszBaseUrl
,lpszRelativeUrl
,lpszBuffer
,lpdwBufferLength
,dwFlags
);
2951 /***********************************************************************
2953 * InternetCombineUrlW
2955 * Combine a base URL with a relative URL
2963 BOOL WINAPI
InternetCombineUrlW(LPCWSTR lpszBaseUrl
, LPCWSTR lpszRelativeUrl
,
2964 LPWSTR lpszBuffer
, LPDWORD lpdwBufferLength
,
2969 TRACE("(%s, %s, %p, %p, 0x%08lx)\n", debugstr_w(lpszBaseUrl
), debugstr_w(lpszRelativeUrl
), lpszBuffer
, lpdwBufferLength
, dwFlags
);
2971 /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
2972 dwFlags
^= ICU_NO_ENCODE
;
2973 hr
=UrlCombineW(lpszBaseUrl
,lpszRelativeUrl
,lpszBuffer
,lpdwBufferLength
,dwFlags
);
2978 /***********************************************************************
2980 * InternetCreateUrlA
2987 BOOL WINAPI
InternetCreateUrlA(LPURL_COMPONENTSA lpUrlComponents
, DWORD dwFlags
,
2988 LPSTR lpszUrl
, LPDWORD lpdwUrlLength
)
2994 /***********************************************************************
2996 * InternetCreateUrlW
3003 BOOL WINAPI
InternetCreateUrlW(LPURL_COMPONENTSW lpUrlComponents
, DWORD dwFlags
,
3004 LPWSTR lpszUrl
, LPDWORD lpdwUrlLength
)