diff --git a/reactos/dll/win32/crypt32/chain.c b/reactos/dll/win32/crypt32/chain.c
index 5943117ddda..2e414cdddf8 100644
--- a/reactos/dll/win32/crypt32/chain.c
+++ b/reactos/dll/win32/crypt32/chain.c
@@ -306,7 +306,13 @@ static BOOL CRYPT_AddCertToSimpleChain(PCertificateChainEngine engine,
= subjectInfoStatus;
/* FIXME: initialize the rest of element */
if (!(chain->cElement % engine->CycleDetectionModulus))
+ {
CRYPT_CheckSimpleChainForCycles(chain);
+ /* Reinitialize the element pointer in case the chain is
+ * cyclic, in which case the chain is truncated.
+ */
+ element = chain->rgpElement[chain->cElement - 1];
+ }
CRYPT_CombineTrustStatus(&chain->TrustStatus,
&element->TrustStatus);
ret = TRUE;
diff --git a/reactos/dll/win32/crypt32/decode.c b/reactos/dll/win32/crypt32/decode.c
index cda8b62aed1..2c2b543e852 100644
--- a/reactos/dll/win32/crypt32/decode.c
+++ b/reactos/dll/win32/crypt32/decode.c
@@ -1724,9 +1724,8 @@ static BOOL CRYPT_AsnDecodeUnicodeNameValueInternal(const BYTE *pbEncoded,
case ASN_UTF8STRING:
value->Value.cbData = MultiByteToWideChar(CP_UTF8, 0,
(LPCSTR)pbEncoded + 1 + lenBytes, dataLen,
- str, bytesNeeded - sizeof(CERT_NAME_VALUE)) * 2;
- value->Value.pbData[value->Value.cbData / sizeof(WCHAR)]
- = 0;
+ str, bytesNeeded - sizeof(CERT_NAME_VALUE)) * sizeof(WCHAR);
+ *(WCHAR *)(value->Value.pbData + value->Value.cbData) = 0;
value->Value.cbData += sizeof(WCHAR);
break;
}
diff --git a/reactos/dll/win32/jscript/jsutils.c b/reactos/dll/win32/jscript/jsutils.c
index defddd4b0cd..73bac94d7e8 100644
--- a/reactos/dll/win32/jscript/jsutils.c
+++ b/reactos/dll/win32/jscript/jsutils.c
@@ -27,6 +27,7 @@
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(jscript);
+WINE_DECLARE_DEBUG_CHANNEL(heap);
const char *debugstr_variant(const VARIANT *v)
{
@@ -51,6 +52,7 @@ const char *debugstr_variant(const VARIANT *v)
}
#define MIN_BLOCK_SIZE 128
+#define ARENA_FREE_FILLER 0xaa
static inline DWORD block_size(DWORD block)
{
@@ -83,26 +85,26 @@ void *jsheap_alloc(jsheap_t *heap, DWORD size)
heap->block_cnt = 1;
}
- if(heap->offset + size < block_size(heap->last_block)) {
+ if(heap->offset + size <= block_size(heap->last_block)) {
tmp = ((BYTE*)heap->blocks[heap->last_block])+heap->offset;
heap->offset += size;
return tmp;
}
- if(size < block_size(heap->last_block+1)) {
+ if(size <= block_size(heap->last_block+1)) {
if(heap->last_block+1 == heap->block_cnt) {
tmp = heap_realloc(heap->blocks, (heap->block_cnt+1)*sizeof(void*));
if(!tmp)
return NULL;
+
heap->blocks = tmp;
+ heap->blocks[heap->block_cnt] = heap_alloc(block_size(heap->block_cnt));
+ if(!heap->blocks[heap->block_cnt])
+ return NULL;
+
+ heap->block_cnt++;
}
- tmp = heap_alloc(block_size(heap->block_cnt+1));
- if(!tmp)
- return NULL;
-
- heap->blocks[heap->block_cnt++] = tmp;
-
heap->last_block++;
heap->offset = size;
return heap->blocks[heap->last_block];
@@ -139,7 +141,15 @@ void jsheap_clear(jsheap_t *heap)
heap_free(tmp);
}
+ if(WARN_ON(heap)) {
+ DWORD i;
+
+ for(i=0; i < heap->block_cnt; i++)
+ memset(heap->blocks[i], ARENA_FREE_FILLER, block_size(i));
+ }
+
heap->last_block = heap->offset = 0;
+ heap->mark = FALSE;
}
void jsheap_free(jsheap_t *heap)
diff --git a/reactos/dll/win32/mapi32/mapi32.rbuild b/reactos/dll/win32/mapi32/mapi32.rbuild
index 39e527d1a8c..1c73d3ad8a4 100644
--- a/reactos/dll/win32/mapi32/mapi32.rbuild
+++ b/reactos/dll/win32/mapi32/mapi32.rbuild
@@ -11,6 +11,7 @@
prop.c
sendmail.c
util.c
+ version.rc
wine
shlwapi
shell32
diff --git a/reactos/dll/win32/mapi32/version.rc b/reactos/dll/win32/mapi32/version.rc
new file mode 100644
index 00000000000..0f955162b37
--- /dev/null
+++ b/reactos/dll/win32/mapi32/version.rc
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2009 Vincent Povirk for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define WINE_FILEDESCRIPTION_STR "Wine Messaging API"
+#define WINE_FILENAME_STR "mapi32.dll"
+
+#include "wine/wine_common_ver.rc"
diff --git a/reactos/dll/win32/mlang/mlang.c b/reactos/dll/win32/mlang/mlang.c
index 11fa366c5e8..f9c3f8e9baa 100644
--- a/reactos/dll/win32/mlang/mlang.c
+++ b/reactos/dll/win32/mlang/mlang.c
@@ -1912,9 +1912,34 @@ static HRESULT WINAPI fnIMLangFontLink_GetStrCodePages(
DWORD* pdwCodePages,
long* pcchCodePages)
{
- FIXME("(pszSrc=%s, cchSrc=%ld, dwPriorityCodePages=%d) stub\n", debugstr_w(pszSrc), cchSrc, dwPriorityCodePages);
- *pdwCodePages = 0;
- *pcchCodePages = 1;
+ long i;
+ DWORD cps = 0;
+
+ TRACE("(%p)->%s %ld %x %p %p\n", iface, debugstr_wn(pszSrc,cchSrc),cchSrc,dwPriorityCodePages,pdwCodePages,pcchCodePages);
+
+ if (pdwCodePages) *pdwCodePages = 0;
+ if (pcchCodePages) *pcchCodePages = 0;
+
+ if (!pszSrc || !cchSrc || cchSrc < 0)
+ return E_INVALIDARG;
+
+ for (i = 0; i < cchSrc; i++)
+ {
+ DWORD cp;
+ HRESULT ret;
+
+ ret = fnIMLangFontLink_GetCharCodePages(iface, pszSrc[i], &cp);
+ if (ret != S_OK) return E_FAIL;
+
+ if (!cps) cps = cp;
+ else cps &= cp;
+
+ /* FIXME: not tested */
+ if (dwPriorityCodePages & cps) break;
+ }
+
+ if (pdwCodePages) *pdwCodePages = cps;
+ if (pcchCodePages) *pcchCodePages = i;
return S_OK;
}
@@ -3179,10 +3204,8 @@ static HRESULT WINAPI fnIMLangFontLink2_GetStrCodePages( IMLangFontLink2* This,
const WCHAR *pszSrc, long cchSrc, DWORD dwPriorityCodePages,
DWORD *pdwCodePages, long *pcchCodePages)
{
- FIXME("(%p)->%s %li %x %p %p\n",This, debugstr_wn(pszSrc,cchSrc),cchSrc,dwPriorityCodePages,pdwCodePages,pcchCodePages);
- *pdwCodePages = 0;
- *pcchCodePages = 1;
- return S_OK;
+ return fnIMLangFontLink_GetStrCodePages((IMLangFontLink *)This,
+ pszSrc, cchSrc, dwPriorityCodePages, pdwCodePages, pcchCodePages);
}
static HRESULT WINAPI fnIMLangFontLink2_CodePageToCodePages(IMLangFontLink2* This,
diff --git a/reactos/dll/win32/msctf/categorymgr.c b/reactos/dll/win32/msctf/categorymgr.c
index 23580724286..648352af85a 100644
--- a/reactos/dll/win32/msctf/categorymgr.c
+++ b/reactos/dll/win32/msctf/categorymgr.c
@@ -168,9 +168,67 @@ static HRESULT WINAPI CategoryMgr_EnumItemsInCategory ( ITfCategoryMgr *iface,
static HRESULT WINAPI CategoryMgr_FindClosestCategory ( ITfCategoryMgr *iface,
REFGUID rguid, GUID *pcatid, const GUID **ppcatidList, ULONG ulCount)
{
+ static const WCHAR fmt[] = { '%','s','\\','%','s','\\','C','a','t','e','g','o','r','y','\\','I','t','e','m','\\','%','s',0};
+
+ WCHAR fullkey[110];
+ WCHAR buf[39];
+ HKEY key;
+ HRESULT hr = S_FALSE;
+ INT index = 0;
CategoryMgr *This = (CategoryMgr*)iface;
- FIXME("STUB:(%p)\n",This);
- return E_NOTIMPL;
+
+ TRACE("(%p)\n",This);
+
+ if (!pcatid || (ulCount && ppcatidList == NULL))
+ return E_INVALIDARG;
+
+ StringFromGUID2(rguid, buf, 39);
+ sprintfW(fullkey,fmt,szwSystemTIPKey,buf,buf);
+ *pcatid = GUID_NULL;
+
+ if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,fullkey, 0, KEY_READ, &key ) !=
+ ERROR_SUCCESS)
+ return S_FALSE;
+
+ while (1)
+ {
+ HRESULT hr2;
+ ULONG res;
+ GUID guid;
+ WCHAR catid[39];
+ DWORD cName;
+
+ cName = 39;
+ res = RegEnumKeyExW(key, index, catid, &cName, NULL, NULL, NULL, NULL);
+ if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) break;
+ index ++;
+
+ hr2 = CLSIDFromString(catid, &guid);
+ if (FAILED(hr2)) continue;
+
+ if (ulCount)
+ {
+ int j;
+ BOOL found = FALSE;
+ for (j = 0; j < ulCount; j++)
+ if (IsEqualGUID(&guid, ppcatidList[j]))
+ {
+ found = TRUE;
+ *pcatid = guid;
+ hr = S_OK;
+ break;
+ }
+ if (found) break;
+ }
+ else
+ {
+ *pcatid = guid;
+ hr = S_OK;
+ break;
+ }
+ }
+
+ return hr;
}
static HRESULT WINAPI CategoryMgr_RegisterGUIDDescription (
diff --git a/reactos/dll/win32/msctf/inputprocessor.c b/reactos/dll/win32/msctf/inputprocessor.c
index de39af977a5..7df55753360 100644
--- a/reactos/dll/win32/msctf/inputprocessor.c
+++ b/reactos/dll/win32/msctf/inputprocessor.c
@@ -72,6 +72,7 @@ typedef struct tagEnumTfLanguageProfiles {
DWORD lang_index;
LANGID langid;
+ ITfCategoryMgr *catmgr;
} EnumTfLanguageProfiles;
static HRESULT ProfilesEnumGuid_Constructor(IEnumGUID **ppOut);
@@ -670,6 +671,7 @@ static void EnumTfLanguageProfiles_Destructor(EnumTfLanguageProfiles *This)
RegCloseKey(This->tipkey);
if (This->langkey)
RegCloseKey(This->langkey);
+ ITfCategoryMgr_Release(This->catmgr);
HeapFree(GetProcessHeap(),0,This);
}
@@ -746,6 +748,9 @@ static INT next_LanguageProfile(EnumTfLanguageProfiles *This, CLSID clsid, TF_LA
if (tflp)
{
+ static const GUID * tipcats[3] = { &GUID_TFCAT_TIP_KEYBOARD,
+ &GUID_TFCAT_TIP_SPEECH,
+ &GUID_TFCAT_TIP_HANDWRITING };
res = CLSIDFromString(profileid, &profile);
if (FAILED(res)) return 0;
@@ -754,7 +759,10 @@ static INT next_LanguageProfile(EnumTfLanguageProfiles *This, CLSID clsid, TF_LA
/* FIXME */
tflp->fActive = FALSE;
tflp->guidProfile = profile;
- /* FIXME set catid */
+ if (ITfCategoryMgr_FindClosestCategory(This->catmgr, &clsid,
+ &tflp->catid, tipcats, 3) != S_OK)
+ ITfCategoryMgr_FindClosestCategory(This->catmgr, &clsid,
+ &tflp->catid, NULL, 0);
}
return 1;
@@ -865,6 +873,7 @@ static const IEnumTfLanguageProfilesVtbl IEnumTfLanguageProfiles_Vtbl ={
static HRESULT EnumTfLanguageProfiles_Constructor(LANGID langid, IEnumTfLanguageProfiles **ppOut)
{
+ HRESULT hr;
EnumTfLanguageProfiles *This;
This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(EnumTfLanguageProfiles));
@@ -875,6 +884,13 @@ static HRESULT EnumTfLanguageProfiles_Constructor(LANGID langid, IEnumTfLanguage
This->refCount = 1;
This->langid = langid;
+ hr = CategoryMgr_Constructor(NULL,(IUnknown**)&This->catmgr);
+ if (FAILED(hr))
+ {
+ HeapFree(GetProcessHeap(),0,This);
+ return hr;
+ }
+
if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, szwSystemTIPKey, 0, NULL, 0,
KEY_READ | KEY_WRITE, NULL, &This->tipkey, NULL) != ERROR_SUCCESS)
return E_FAIL;
diff --git a/reactos/dll/win32/msvcrt20/msvcrt20.spec b/reactos/dll/win32/msvcrt20/msvcrt20.spec
index 339cb1c063f..56f961ca3df 100644
--- a/reactos/dll/win32/msvcrt20/msvcrt20.spec
+++ b/reactos/dll/win32/msvcrt20/msvcrt20.spec
@@ -437,22 +437,22 @@
@ stub ?xsgetn@streambuf@@UAEHPADH@Z #
@ stub ?xsputn@streambuf@@UAEHPBDH@Z #
@ stub $I10_OUTPUT #
-@ cdecl _CIacos() msvcrt._CIacos
-@ cdecl _CIasin() msvcrt._CIasin
-@ cdecl _CIatan() msvcrt._CIatan
-@ cdecl _CIatan2() msvcrt._CIatan2
-@ cdecl _CIcos() msvcrt._CIcos
-@ cdecl _CIcosh() msvcrt._CIcosh
-@ cdecl _CIexp() msvcrt._CIexp
-@ cdecl _CIfmod() msvcrt._CIfmod
-@ cdecl _CIlog() msvcrt._CIlog
-@ cdecl _CIlog10() msvcrt._CIlog10
-@ cdecl _CIpow() msvcrt._CIpow
-@ cdecl _CIsin() msvcrt._CIsin
-@ cdecl _CIsinh() msvcrt._CIsinh
-@ cdecl _CIsqrt() msvcrt._CIsqrt
-@ cdecl _CItan() msvcrt._CItan
-@ cdecl _CItanh() msvcrt._CItanh
+@ cdecl -arch=i386 _CIacos() msvcrt._CIacos
+@ cdecl -arch=i386 _CIasin() msvcrt._CIasin
+@ cdecl -arch=i386 _CIatan() msvcrt._CIatan
+@ cdecl -arch=i386 _CIatan2() msvcrt._CIatan2
+@ cdecl -arch=i386 _CIcos() msvcrt._CIcos
+@ cdecl -arch=i386 _CIcosh() msvcrt._CIcosh
+@ cdecl -arch=i386 _CIexp() msvcrt._CIexp
+@ cdecl -arch=i386 _CIfmod() msvcrt._CIfmod
+@ cdecl -arch=i386 _CIlog() msvcrt._CIlog
+@ cdecl -arch=i386 _CIlog10() msvcrt._CIlog10
+@ cdecl -arch=i386 _CIpow() msvcrt._CIpow
+@ cdecl -arch=i386 _CIsin() msvcrt._CIsin
+@ cdecl -arch=i386 _CIsinh() msvcrt._CIsinh
+@ cdecl -arch=i386 _CIsqrt() msvcrt._CIsqrt
+@ cdecl -arch=i386 _CItan() msvcrt._CItan
+@ cdecl -arch=i386 _CItanh() msvcrt._CItanh
@ cdecl _CxxThrowException(long long) msvcrt._CxxThrowException
@ extern _HUGE msvcrt._HUGE
@ cdecl _XcptFilter(long ptr) msvcrt._XcptFilter
@@ -471,32 +471,32 @@
@ cdecl __iscsymf(long) msvcrt.__iscsymf
@ cdecl __lconv_init() msvcrt.__lconv_init
@ extern __mb_cur_max msvcrt.__mb_cur_max
-@ cdecl __p___argc() msvcrt.__p___argc
-@ cdecl __p___argv() msvcrt.__p___argv
-@ cdecl __p___initenv() msvcrt.__p___initenv
-@ cdecl __p___mb_cur_max() msvcrt.__p___mb_cur_max
-@ cdecl __p___wargv() msvcrt.__p___wargv
-@ cdecl __p___winitenv() msvcrt.__p___winitenv
-@ cdecl __p__acmdln() msvcrt.__p__acmdln
-@ cdecl __p__amblksiz() msvcrt.__p__amblksiz
-@ cdecl __p__commode() msvcrt.__p__commode
-@ cdecl __p__daylight() msvcrt.__p__daylight
-@ cdecl __p__environ() msvcrt.__p__environ
-@ cdecl __p__fmode() msvcrt.__p__fmode
-@ cdecl __p__iob() msvcrt.__p__iob
-@ cdecl __p__mbctype() msvcrt.__p__mbctype
-@ cdecl __p__osver() msvcrt.__p__osver
-@ cdecl __p__pctype() msvcrt.__p__pctype
-@ cdecl __p__pgmptr() msvcrt.__p__pgmptr
-@ cdecl __p__pwctype() msvcrt.__p__pwctype
-@ cdecl __p__timezone() msvcrt.__p__timezone
-@ cdecl __p__tzname() msvcrt.__p__tzname
-@ cdecl __p__wcmdln() msvcrt.__p__wcmdln
-@ cdecl __p__wenviron() msvcrt.__p__wenviron
-@ cdecl __p__winmajor() msvcrt.__p__winmajor
-@ cdecl __p__winminor() msvcrt.__p__winminor
-@ cdecl __p__winver() msvcrt.__p__winver
-@ cdecl __p__wpgmptr() msvcrt.__p__wpgmptr
+@ cdecl -arch=i386 __p___argc() msvcrt.__p___argc
+@ cdecl -arch=i386 __p___argv() msvcrt.__p___argv
+@ cdecl -arch=i386 __p___initenv() msvcrt.__p___initenv
+@ cdecl -arch=i386 __p___mb_cur_max() msvcrt.__p___mb_cur_max
+@ cdecl -arch=i386 __p___wargv() msvcrt.__p___wargv
+@ cdecl -arch=i386 __p___winitenv() msvcrt.__p___winitenv
+@ cdecl -arch=i386 __p__acmdln() msvcrt.__p__acmdln
+@ cdecl -arch=i386 __p__amblksiz() msvcrt.__p__amblksiz
+@ cdecl -arch=i386 __p__commode() msvcrt.__p__commode
+@ cdecl -arch=i386 __p__daylight() msvcrt.__p__daylight
+@ cdecl -arch=i386 __p__environ() msvcrt.__p__environ
+@ cdecl -arch=i386 __p__fmode() msvcrt.__p__fmode
+@ cdecl -arch=i386 __p__iob() msvcrt.__p__iob
+@ cdecl -arch=i386 __p__mbctype() msvcrt.__p__mbctype
+@ cdecl -arch=i386 __p__osver() msvcrt.__p__osver
+@ cdecl -arch=i386 __p__pctype() msvcrt.__p__pctype
+@ cdecl -arch=i386 __p__pgmptr() msvcrt.__p__pgmptr
+@ cdecl -arch=i386 __p__pwctype() msvcrt.__p__pwctype
+@ cdecl -arch=i386 __p__timezone() msvcrt.__p__timezone
+@ cdecl -arch=i386 __p__tzname() msvcrt.__p__tzname
+@ cdecl -arch=i386 __p__wcmdln() msvcrt.__p__wcmdln
+@ cdecl -arch=i386 __p__wenviron() msvcrt.__p__wenviron
+@ cdecl -arch=i386 __p__winmajor() msvcrt.__p__winmajor
+@ cdecl -arch=i386 __p__winminor() msvcrt.__p__winminor
+@ cdecl -arch=i386 __p__winver() msvcrt.__p__winver
+@ cdecl -arch=i386 __p__wpgmptr() msvcrt.__p__wpgmptr
@ cdecl __pxcptinfoptrs() msvcrt.__pxcptinfoptrs
@ cdecl __threadhandle() msvcrt.__threadhandle
@ cdecl __threadid() msvcrt.__threadid
diff --git a/reactos/dll/win32/msvcrt40/msvcrt40.c b/reactos/dll/win32/msvcrt40/msvcrt40.c
index 48e4af0da59..f178ea0bafa 100644
--- a/reactos/dll/win32/msvcrt40/msvcrt40.c
+++ b/reactos/dll/win32/msvcrt40/msvcrt40.c
@@ -22,9 +22,6 @@
#include "windef.h"
#include "winbase.h"
-#include "wine/debug.h"
-
-WINE_DEFAULT_DEBUG_CHANNEL(msvcrt40);
BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved )
{
diff --git a/reactos/dll/win32/msvcrt40/msvcrt40.spec b/reactos/dll/win32/msvcrt40/msvcrt40.spec
index e46b157d544..fd2559a7a45 100644
--- a/reactos/dll/win32/msvcrt40/msvcrt40.spec
+++ b/reactos/dll/win32/msvcrt40/msvcrt40.spec
@@ -481,22 +481,22 @@
@ stub ?xsgetn@streambuf@@UAEHPADH@Z
@ stub ?xsputn@streambuf@@UAEHPBDH@Z
@ cdecl $I10_OUTPUT() msvcrt.$I10_OUTPUT
-@ cdecl _CIacos() msvcrt._CIacos
-@ cdecl _CIasin() msvcrt._CIasin
-@ cdecl _CIatan() msvcrt._CIatan
-@ cdecl _CIatan2() msvcrt._CIatan2
-@ cdecl _CIcos() msvcrt._CIcos
-@ cdecl _CIcosh() msvcrt._CIcosh
-@ cdecl _CIexp() msvcrt._CIexp
-@ cdecl _CIfmod() msvcrt._CIfmod
-@ cdecl _CIlog() msvcrt._CIlog
-@ cdecl _CIlog10() msvcrt._CIlog10
-@ cdecl _CIpow() msvcrt._CIpow
-@ cdecl _CIsin() msvcrt._CIsin
-@ cdecl _CIsinh() msvcrt._CIsinh
-@ cdecl _CIsqrt() msvcrt._CIsqrt
-@ cdecl _CItan() msvcrt._CItan
-@ cdecl _CItanh() msvcrt._CItanh
+@ cdecl -arch=i386 _CIacos() msvcrt._CIacos
+@ cdecl -arch=i386 _CIasin() msvcrt._CIasin
+@ cdecl -arch=i386 _CIatan() msvcrt._CIatan
+@ cdecl -arch=i386 _CIatan2() msvcrt._CIatan2
+@ cdecl -arch=i386 _CIcos() msvcrt._CIcos
+@ cdecl -arch=i386 _CIcosh() msvcrt._CIcosh
+@ cdecl -arch=i386 _CIexp() msvcrt._CIexp
+@ cdecl -arch=i386 _CIfmod() msvcrt._CIfmod
+@ cdecl -arch=i386 _CIlog() msvcrt._CIlog
+@ cdecl -arch=i386 _CIlog10() msvcrt._CIlog10
+@ cdecl -arch=i386 _CIpow() msvcrt._CIpow
+@ cdecl -arch=i386 _CIsin() msvcrt._CIsin
+@ cdecl -arch=i386 _CIsinh() msvcrt._CIsinh
+@ cdecl -arch=i386 _CIsqrt() msvcrt._CIsqrt
+@ cdecl -arch=i386 _CItan() msvcrt._CItan
+@ cdecl -arch=i386 _CItanh() msvcrt._CItanh
@ cdecl _CxxThrowException(long long) msvcrt._CxxThrowException
@ cdecl -i386 _EH_prolog() msvcrt._EH_prolog
@ extern _HUGE msvcrt._HUGE
@@ -519,33 +519,33 @@
@ cdecl __iscsymf(long) msvcrt.__iscsymf
@ cdecl __lconv_init() msvcrt.__lconv_init
@ extern __mb_cur_max msvcrt.__mb_cur_max
-@ cdecl __p___argc() msvcrt.__p___argc
-@ cdecl __p___argv() msvcrt.__p___argv
-@ cdecl __p___initenv() msvcrt.__p___initenv
-@ cdecl __p___mb_cur_max() msvcrt.__p___mb_cur_max
-@ cdecl __p___wargv() msvcrt.__p___wargv
-@ cdecl __p___winitenv() msvcrt.__p___winitenv
-@ cdecl __p__acmdln() msvcrt.__p__acmdln
-@ cdecl __p__amblksiz() msvcrt.__p__amblksiz
-@ cdecl __p__commode() msvcrt.__p__commode
-@ cdecl __p__daylight() msvcrt.__p__daylight
-@ cdecl __p__dstbias() msvcrt.__p__dstbias
-@ cdecl __p__environ() msvcrt.__p__environ
-@ cdecl __p__fmode() msvcrt.__p__fmode
-@ cdecl __p__iob() msvcrt.__p__iob
-@ cdecl __p__mbctype() msvcrt.__p__mbctype
-@ cdecl __p__osver() msvcrt.__p__osver
-@ cdecl __p__pctype() msvcrt.__p__pctype
-@ cdecl __p__pgmptr() msvcrt.__p__pgmptr
-@ cdecl __p__pwctype() msvcrt.__p__pwctype
-@ cdecl __p__timezone() msvcrt.__p__timezone
-@ cdecl __p__tzname() msvcrt.__p__tzname
-@ cdecl __p__wcmdln() msvcrt.__p__wcmdln
-@ cdecl __p__wenviron() msvcrt.__p__wenviron
-@ cdecl __p__winmajor() msvcrt.__p__winmajor
-@ cdecl __p__winminor() msvcrt.__p__winminor
-@ cdecl __p__winver() msvcrt.__p__winver
-@ cdecl __p__wpgmptr() msvcrt.__p__wpgmptr
+@ cdecl -arch=i386 __p___argc() msvcrt.__p___argc
+@ cdecl -arch=i386 __p___argv() msvcrt.__p___argv
+@ cdecl -arch=i386 __p___initenv() msvcrt.__p___initenv
+@ cdecl -arch=i386 __p___mb_cur_max() msvcrt.__p___mb_cur_max
+@ cdecl -arch=i386 __p___wargv() msvcrt.__p___wargv
+@ cdecl -arch=i386 __p___winitenv() msvcrt.__p___winitenv
+@ cdecl -arch=i386 __p__acmdln() msvcrt.__p__acmdln
+@ cdecl -arch=i386 __p__amblksiz() msvcrt.__p__amblksiz
+@ cdecl -arch=i386 __p__commode() msvcrt.__p__commode
+@ cdecl -arch=i386 __p__daylight() msvcrt.__p__daylight
+@ cdecl -arch=i386 __p__dstbias() msvcrt.__p__dstbias
+@ cdecl -arch=i386 __p__environ() msvcrt.__p__environ
+@ cdecl -arch=i386 __p__fmode() msvcrt.__p__fmode
+@ cdecl -arch=i386 __p__iob() msvcrt.__p__iob
+@ cdecl -arch=i386 __p__mbctype() msvcrt.__p__mbctype
+@ cdecl -arch=i386 __p__osver() msvcrt.__p__osver
+@ cdecl -arch=i386 __p__pctype() msvcrt.__p__pctype
+@ cdecl -arch=i386 __p__pgmptr() msvcrt.__p__pgmptr
+@ cdecl -arch=i386 __p__pwctype() msvcrt.__p__pwctype
+@ cdecl -arch=i386 __p__timezone() msvcrt.__p__timezone
+@ cdecl -arch=i386 __p__tzname() msvcrt.__p__tzname
+@ cdecl -arch=i386 __p__wcmdln() msvcrt.__p__wcmdln
+@ cdecl -arch=i386 __p__wenviron() msvcrt.__p__wenviron
+@ cdecl -arch=i386 __p__winmajor() msvcrt.__p__winmajor
+@ cdecl -arch=i386 __p__winminor() msvcrt.__p__winminor
+@ cdecl -arch=i386 __p__winver() msvcrt.__p__winver
+@ cdecl -arch=i386 __p__wpgmptr() msvcrt.__p__wpgmptr
@ cdecl __pxcptinfoptrs() msvcrt.__pxcptinfoptrs
@ cdecl __set_app_type(long) msvcrt.__set_app_type
@ cdecl __setusermatherr(ptr) msvcrt.__setusermatherr
diff --git a/reactos/dll/win32/msxml3/node.c b/reactos/dll/win32/msxml3/node.c
index 7baef30823d..72cc61e4c15 100644
--- a/reactos/dll/win32/msxml3/node.c
+++ b/reactos/dll/win32/msxml3/node.c
@@ -387,6 +387,11 @@ static HRESULT get_node(
if ( !out )
return E_INVALIDARG;
+
+ /* if we dont have a doc, use our parent. */
+ if(node && !node->doc && node->parent)
+ node->doc = node->parent->doc;
+
*out = create_node( node );
if (!*out)
return S_FALSE;
diff --git a/reactos/dll/win32/snmpapi/main.c b/reactos/dll/win32/snmpapi/main.c
index f8d65150f33..0fabba444b6 100644
--- a/reactos/dll/win32/snmpapi/main.c
+++ b/reactos/dll/win32/snmpapi/main.c
@@ -19,6 +19,8 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include "config.h"
+
#include
#include
diff --git a/reactos/dll/win32/urlmon/binding.c b/reactos/dll/win32/urlmon/binding.c
index 41fa677bc28..fb30367954a 100644
--- a/reactos/dll/win32/urlmon/binding.c
+++ b/reactos/dll/win32/urlmon/binding.c
@@ -1200,7 +1200,7 @@ static void report_data(Binding *This, DWORD bscf, ULONG progress, ULONG progres
TRACE("(%p)->(%d %u %u)\n", This, bscf, progress, progress_max);
- if(This->download_state == END_DOWNLOAD)
+ if(This->download_state == END_DOWNLOAD || (This->state & BINDING_STOPPED))
return;
if(GetCurrentThreadId() != This->apartment_thread)
diff --git a/reactos/dll/win32/urlmon/ftp.c b/reactos/dll/win32/urlmon/ftp.c
index 7b528adb8e2..dbdd7a7fd37 100644
--- a/reactos/dll/win32/urlmon/ftp.c
+++ b/reactos/dll/win32/urlmon/ftp.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2005 Jacek Caban
+ * Copyright 2005-2009 Jacek Caban for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -22,13 +22,63 @@
WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
typedef struct {
+ Protocol base;
+
const IInternetProtocolVtbl *lpInternetProtocolVtbl;
+ const IInternetPriorityVtbl *lpInternetPriorityVtbl;
+
LONG ref;
} FtpProtocol;
-#define PROTOCOL_THIS(iface) DEFINE_THIS(FtpProtocol, InternetProtocol, iface)
-
#define PROTOCOL(x) ((IInternetProtocol*) &(x)->lpInternetProtocolVtbl)
+#define PRIORITY(x) ((IInternetPriority*) &(x)->lpInternetPriorityVtbl)
+
+#define ASYNCPROTOCOL_THIS(iface) DEFINE_THIS2(FtpProtocol, base, iface)
+
+static HRESULT FtpProtocol_open_request(Protocol *prot, LPCWSTR url, DWORD request_flags,
+ IInternetBindInfo *bind_info)
+{
+ FtpProtocol *This = ASYNCPROTOCOL_THIS(prot);
+
+ This->base.request = InternetOpenUrlW(This->base.internet, url, NULL, 0,
+ request_flags|INTERNET_FLAG_EXISTING_CONNECT|INTERNET_FLAG_PASSIVE,
+ (DWORD_PTR)&This->base);
+ if (!This->base.request && GetLastError() != ERROR_IO_PENDING) {
+ WARN("InternetOpenUrl failed: %d\n", GetLastError());
+ return INET_E_RESOURCE_NOT_FOUND;
+ }
+
+ return S_OK;
+}
+
+static HRESULT FtpProtocol_start_downloading(Protocol *prot)
+{
+ FtpProtocol *This = ASYNCPROTOCOL_THIS(prot);
+ DWORD size;
+ BOOL res;
+
+ res = FtpGetFileSize(This->base.request, &size);
+ if(res)
+ This->base.content_length = size;
+ else
+ WARN("FtpGetFileSize failed: %d\n", GetLastError());
+
+ return S_OK;
+}
+
+static void FtpProtocol_close_connection(Protocol *prot)
+{
+}
+
+#undef ASYNCPROTOCOL_THIS
+
+static const ProtocolVtbl AsyncProtocolVtbl = {
+ FtpProtocol_open_request,
+ FtpProtocol_start_downloading,
+ FtpProtocol_close_connection
+};
+
+#define PROTOCOL_THIS(iface) DEFINE_THIS(FtpProtocol, InternetProtocol, iface)
static HRESULT WINAPI FtpProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
{
@@ -44,6 +94,9 @@ static HRESULT WINAPI FtpProtocol_QueryInterface(IInternetProtocol *iface, REFII
}else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv);
*ppv = PROTOCOL(This);
+ }else if(IsEqualGUID(&IID_IInternetPriority, riid)) {
+ TRACE("(%p)->(IID_IInternetPriority %p)\n", This, ppv);
+ *ppv = PRIORITY(This);
}
if(*ppv) {
@@ -71,6 +124,7 @@ static ULONG WINAPI FtpProtocol_Release(IInternetProtocol *iface)
TRACE("(%p) ref=%d\n", This, ref);
if(!ref) {
+ protocol_close_connection(&This->base);
heap_free(This);
URLMON_UnlockModule();
@@ -84,16 +138,25 @@ static HRESULT WINAPI FtpProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
DWORD grfPI, DWORD dwReserved)
{
FtpProtocol *This = PROTOCOL_THIS(iface);
- FIXME("(%p)->(%s %p %p %08x %d)\n", This, debugstr_w(szUrl), pOIProtSink,
- pOIBindInfo, grfPI, dwReserved);
- return E_NOTIMPL;
+
+ static const WCHAR ftpW[] = {'f','t','p',':'};
+
+ TRACE("(%p)->(%s %p %p %08x %d)\n", This, debugstr_w(szUrl), pOIProtSink,
+ pOIBindInfo, grfPI, dwReserved);
+
+ if(strncmpW(szUrl, ftpW, sizeof(ftpW)/sizeof(WCHAR)))
+ return MK_E_SYNTAX;
+
+ return protocol_start(&This->base, PROTOCOL(This), szUrl, pOIProtSink, pOIBindInfo);
}
static HRESULT WINAPI FtpProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
{
FtpProtocol *This = PROTOCOL_THIS(iface);
- FIXME("(%p)->(%p)\n", This, pProtocolData);
- return E_NOTIMPL;
+
+ TRACE("(%p)->(%p)\n", This, pProtocolData);
+
+ return protocol_continue(&This->base, pProtocolData);
}
static HRESULT WINAPI FtpProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
@@ -107,8 +170,11 @@ static HRESULT WINAPI FtpProtocol_Abort(IInternetProtocol *iface, HRESULT hrReas
static HRESULT WINAPI FtpProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
{
FtpProtocol *This = PROTOCOL_THIS(iface);
- FIXME("(%p)->(%08x)\n", This, dwOptions);
- return E_NOTIMPL;
+
+ TRACE("(%p)->(%08x)\n", This, dwOptions);
+
+ protocol_close_connection(&This->base);
+ return S_OK;
}
static HRESULT WINAPI FtpProtocol_Suspend(IInternetProtocol *iface)
@@ -129,8 +195,10 @@ static HRESULT WINAPI FtpProtocol_Read(IInternetProtocol *iface, void *pv,
ULONG cb, ULONG *pcbRead)
{
FtpProtocol *This = PROTOCOL_THIS(iface);
- FIXME("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
- return E_NOTIMPL;
+
+ TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
+
+ return protocol_read(&This->base, pv, cb, pcbRead);
}
static HRESULT WINAPI FtpProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
@@ -144,15 +212,19 @@ static HRESULT WINAPI FtpProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER d
static HRESULT WINAPI FtpProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
{
FtpProtocol *This = PROTOCOL_THIS(iface);
- FIXME("(%p)->(%08x)\n", This, dwOptions);
- return E_NOTIMPL;
+
+ TRACE("(%p)->(%08x)\n", This, dwOptions);
+
+ return protocol_lock_request(&This->base);
}
static HRESULT WINAPI FtpProtocol_UnlockRequest(IInternetProtocol *iface)
{
FtpProtocol *This = PROTOCOL_THIS(iface);
- FIXME("(%p)\n", This);
- return E_NOTIMPL;
+
+ TRACE("(%p)\n", This);
+
+ return protocol_unlock_request(&This->base);
}
#undef PROTOCOL_THIS
@@ -173,6 +245,56 @@ static const IInternetProtocolVtbl FtpProtocolVtbl = {
FtpProtocol_UnlockRequest
};
+#define PRIORITY_THIS(iface) DEFINE_THIS(FtpProtocol, InternetPriority, iface)
+
+static HRESULT WINAPI FtpPriority_QueryInterface(IInternetPriority *iface, REFIID riid, void **ppv)
+{
+ FtpProtocol *This = PRIORITY_THIS(iface);
+ return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
+}
+
+static ULONG WINAPI FtpPriority_AddRef(IInternetPriority *iface)
+{
+ FtpProtocol *This = PRIORITY_THIS(iface);
+ return IInternetProtocol_AddRef(PROTOCOL(This));
+}
+
+static ULONG WINAPI FtpPriority_Release(IInternetPriority *iface)
+{
+ FtpProtocol *This = PRIORITY_THIS(iface);
+ return IInternetProtocol_Release(PROTOCOL(This));
+}
+
+static HRESULT WINAPI FtpPriority_SetPriority(IInternetPriority *iface, LONG nPriority)
+{
+ FtpProtocol *This = PRIORITY_THIS(iface);
+
+ TRACE("(%p)->(%d)\n", This, nPriority);
+
+ This->base.priority = nPriority;
+ return S_OK;
+}
+
+static HRESULT WINAPI FtpPriority_GetPriority(IInternetPriority *iface, LONG *pnPriority)
+{
+ FtpProtocol *This = PRIORITY_THIS(iface);
+
+ TRACE("(%p)->(%p)\n", This, pnPriority);
+
+ *pnPriority = This->base.priority;
+ return S_OK;
+}
+
+#undef PRIORITY_THIS
+
+static const IInternetPriorityVtbl FtpPriorityVtbl = {
+ FtpPriority_QueryInterface,
+ FtpPriority_AddRef,
+ FtpPriority_Release,
+ FtpPriority_SetPriority,
+ FtpPriority_GetPriority
+};
+
HRESULT FtpProtocol_Construct(IUnknown *pUnkOuter, LPVOID *ppobj)
{
FtpProtocol *ret;
@@ -181,9 +303,11 @@ HRESULT FtpProtocol_Construct(IUnknown *pUnkOuter, LPVOID *ppobj)
URLMON_LockModule();
- ret = heap_alloc(sizeof(FtpProtocol));
+ ret = heap_alloc_zero(sizeof(FtpProtocol));
+ ret->base.vtbl = &AsyncProtocolVtbl;
ret->lpInternetProtocolVtbl = &FtpProtocolVtbl;
+ ret->lpInternetPriorityVtbl = &FtpPriorityVtbl;
ret->ref = 1;
*ppobj = PROTOCOL(ret);
diff --git a/reactos/dll/win32/urlmon/http.c b/reactos/dll/win32/urlmon/http.c
index 9bb4ffafb91..80eefbed204 100644
--- a/reactos/dll/win32/urlmon/http.c
+++ b/reactos/dll/win32/urlmon/http.c
@@ -29,215 +29,283 @@
WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
-/* Flags are needed for, among other things, return HRESULTs from the Read function
- * to conform to native. For example, Read returns:
- *
- * 1. E_PENDING if called before the request has completed,
- * (flags = 0)
- * 2. S_FALSE after all data has been read and S_OK has been reported,
- * (flags = FLAG_REQUEST_COMPLETE | FLAG_ALL_DATA_READ | FLAG_RESULT_REPORTED)
- * 3. INET_E_DATA_NOT_AVAILABLE if InternetQueryDataAvailable fails. The first time
- * this occurs, INET_E_DATA_NOT_AVAILABLE will also be reported to the sink,
- * (flags = FLAG_REQUEST_COMPLETE)
- * but upon subsequent calls to Read no reporting will take place, yet
- * InternetQueryDataAvailable will still be called, and, on failure,
- * INET_E_DATA_NOT_AVAILABLE will still be returned.
- * (flags = FLAG_REQUEST_COMPLETE | FLAG_RESULT_REPORTED)
- *
- * FLAG_FIRST_DATA_REPORTED and FLAG_LAST_DATA_REPORTED are needed for proper
- * ReportData reporting. For example, if OnResponse returns S_OK, Continue will
- * report BSCF_FIRSTDATANOTIFICATION, and when all data has been read Read will
- * report BSCF_INTERMEDIATEDATANOTIFICATION|BSCF_LASTDATANOTIFICATION. However,
- * if OnResponse does not return S_OK, Continue will not report data, and Read
- * will report BSCF_FIRSTDATANOTIFICATION|BSCF_LASTDATANOTIFICATION when all
- * data has been read.
- */
-#define FLAG_REQUEST_COMPLETE 0x1
-#define FLAG_FIRST_CONTINUE_COMPLETE 0x2
-#define FLAG_FIRST_DATA_REPORTED 0x4
-#define FLAG_ALL_DATA_READ 0x8
-#define FLAG_LAST_DATA_REPORTED 0x10
-#define FLAG_RESULT_REPORTED 0x20
-
typedef struct {
+ Protocol base;
+
const IInternetProtocolVtbl *lpInternetProtocolVtbl;
const IInternetPriorityVtbl *lpInternetPriorityVtbl;
BOOL https;
- DWORD flags, grfBINDF;
- BINDINFO bind_info;
- IInternetProtocolSink *protocol_sink;
IHttpNegotiate *http_negotiate;
- HINTERNET internet, connect, request;
LPWSTR full_header;
- HANDLE lock;
- ULONG current_position, content_length, available_bytes;
- LONG priority;
LONG ref;
} HttpProtocol;
+#define PROTOCOL(x) ((IInternetProtocol*) &(x)->lpInternetProtocolVtbl)
+#define PRIORITY(x) ((IInternetPriority*) &(x)->lpInternetPriorityVtbl)
+
/* Default headers from native */
static const WCHAR wszHeaders[] = {'A','c','c','e','p','t','-','E','n','c','o','d','i','n','g',
':',' ','g','z','i','p',',',' ','d','e','f','l','a','t','e',0};
-/*
- * Helpers
- */
-
-static void HTTPPROTOCOL_ReportResult(HttpProtocol *This, HRESULT hres)
-{
- if (!(This->flags & FLAG_RESULT_REPORTED) &&
- This->protocol_sink)
- {
- This->flags |= FLAG_RESULT_REPORTED;
- IInternetProtocolSink_ReportResult(This->protocol_sink, hres, 0, NULL);
- }
-}
-
-static void HTTPPROTOCOL_ReportData(HttpProtocol *This)
-{
- DWORD bscf;
- if (!(This->flags & FLAG_LAST_DATA_REPORTED) &&
- This->protocol_sink)
- {
- if (This->flags & FLAG_FIRST_DATA_REPORTED)
- {
- bscf = BSCF_INTERMEDIATEDATANOTIFICATION;
- }
- else
- {
- This->flags |= FLAG_FIRST_DATA_REPORTED;
- bscf = BSCF_FIRSTDATANOTIFICATION;
- }
- if (This->flags & FLAG_ALL_DATA_READ &&
- !(This->flags & FLAG_LAST_DATA_REPORTED))
- {
- This->flags |= FLAG_LAST_DATA_REPORTED;
- bscf |= BSCF_LASTDATANOTIFICATION;
- }
- IInternetProtocolSink_ReportData(This->protocol_sink, bscf,
- This->current_position+This->available_bytes,
- This->content_length);
- }
-}
-
-static void HTTPPROTOCOL_AllDataRead(HttpProtocol *This)
-{
- if (!(This->flags & FLAG_ALL_DATA_READ))
- This->flags |= FLAG_ALL_DATA_READ;
- HTTPPROTOCOL_ReportData(This);
- HTTPPROTOCOL_ReportResult(This, S_OK);
-}
-
-static void HTTPPROTOCOL_Close(HttpProtocol *This)
-{
- if (This->http_negotiate)
- {
- IHttpNegotiate_Release(This->http_negotiate);
- This->http_negotiate = 0;
- }
- if (This->request)
- InternetCloseHandle(This->request);
- if (This->connect)
- InternetCloseHandle(This->connect);
- if (This->internet)
- {
- InternetCloseHandle(This->internet);
- This->internet = 0;
- }
- if (This->full_header)
- {
- if (This->full_header != wszHeaders)
- heap_free(This->full_header);
- This->full_header = 0;
- }
- This->flags = 0;
-}
-
-static void CALLBACK HTTPPROTOCOL_InternetStatusCallback(
- HINTERNET hInternet, DWORD_PTR dwContext, DWORD dwInternetStatus,
- LPVOID lpvStatusInformation, DWORD dwStatusInformationLength)
-{
- HttpProtocol *This = (HttpProtocol *)dwContext;
- PROTOCOLDATA data;
- ULONG ulStatusCode;
-
- switch (dwInternetStatus)
- {
- case INTERNET_STATUS_RESOLVING_NAME:
- ulStatusCode = BINDSTATUS_FINDINGRESOURCE;
- break;
- case INTERNET_STATUS_CONNECTING_TO_SERVER:
- ulStatusCode = BINDSTATUS_CONNECTING;
- break;
- case INTERNET_STATUS_SENDING_REQUEST:
- ulStatusCode = BINDSTATUS_SENDINGREQUEST;
- break;
- case INTERNET_STATUS_REQUEST_COMPLETE:
- This->flags |= FLAG_REQUEST_COMPLETE;
- /* PROTOCOLDATA same as native */
- memset(&data, 0, sizeof(data));
- data.dwState = 0xf1000000;
- if (This->flags & FLAG_FIRST_CONTINUE_COMPLETE)
- data.pData = (LPVOID)BINDSTATUS_ENDDOWNLOADCOMPONENTS;
- else
- data.pData = (LPVOID)BINDSTATUS_DOWNLOADINGDATA;
- if (This->grfBINDF & BINDF_FROMURLMON)
- IInternetProtocolSink_Switch(This->protocol_sink, &data);
- else
- IInternetProtocol_Continue((IInternetProtocol *)This, &data);
- return;
- case INTERNET_STATUS_HANDLE_CREATED:
- IInternetProtocol_AddRef((IInternetProtocol *)This);
- return;
- case INTERNET_STATUS_HANDLE_CLOSING:
- if (*(HINTERNET *)lpvStatusInformation == This->connect)
- {
- This->connect = 0;
- }
- else if (*(HINTERNET *)lpvStatusInformation == This->request)
- {
- This->request = 0;
- if (This->protocol_sink)
- {
- IInternetProtocolSink_Release(This->protocol_sink);
- This->protocol_sink = 0;
- }
- if (This->bind_info.cbSize)
- {
- ReleaseBindInfo(&This->bind_info);
- memset(&This->bind_info, 0, sizeof(This->bind_info));
- }
- }
- IInternetProtocol_Release((IInternetProtocol *)This);
- return;
- default:
- WARN("Unhandled Internet status callback %d\n", dwInternetStatus);
- return;
- }
-
- IInternetProtocolSink_ReportProgress(This->protocol_sink, ulStatusCode, (LPWSTR)lpvStatusInformation);
-}
-
-static inline LPWSTR strndupW(LPCWSTR string, int len)
+static LPWSTR query_http_info(HttpProtocol *This, DWORD option)
{
LPWSTR ret = NULL;
- if (string &&
- (ret = heap_alloc((len+1)*sizeof(WCHAR))) != NULL)
- {
- memcpy(ret, string, len*sizeof(WCHAR));
- ret[len] = 0;
+ DWORD len = 0;
+ BOOL res;
+
+ res = HttpQueryInfoW(This->base.request, option, NULL, &len, NULL);
+ if (!res && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
+ ret = heap_alloc(len);
+ res = HttpQueryInfoW(This->base.request, option, ret, &len, NULL);
}
+ if(!res) {
+ TRACE("HttpQueryInfoW(%d) failed: %08x\n", option, GetLastError());
+ heap_free(ret);
+ return NULL;
+ }
+
return ret;
}
-/*
- * Interface implementations
- */
+#define ASYNCPROTOCOL_THIS(iface) DEFINE_THIS2(HttpProtocol, base, iface)
-#define PROTOCOL(x) ((IInternetProtocol*) &(x)->lpInternetProtocolVtbl)
-#define PRIORITY(x) ((IInternetPriority*) &(x)->lpInternetPriorityVtbl)
+static HRESULT HttpProtocol_open_request(Protocol *prot, LPCWSTR url, DWORD request_flags,
+ IInternetBindInfo *bind_info)
+{
+ HttpProtocol *This = ASYNCPROTOCOL_THIS(prot);
+ LPWSTR addl_header = NULL, post_cookie = NULL, optional = NULL;
+ IServiceProvider *service_provider = NULL;
+ IHttpNegotiate2 *http_negotiate2 = NULL;
+ LPWSTR host, user, pass, path;
+ LPOLESTR accept_mimes[257];
+ URL_COMPONENTSW url_comp;
+ BYTE security_id[512];
+ DWORD len = 0;
+ ULONG num = 0;
+ BOOL res;
+ HRESULT hres;
+
+ static const WCHAR wszBindVerb[BINDVERB_CUSTOM][5] =
+ {{'G','E','T',0},
+ {'P','O','S','T',0},
+ {'P','U','T',0}};
+
+ memset(&url_comp, 0, sizeof(url_comp));
+ url_comp.dwStructSize = sizeof(url_comp);
+ url_comp.dwSchemeLength = url_comp.dwHostNameLength = url_comp.dwUrlPathLength =
+ url_comp.dwUserNameLength = url_comp.dwPasswordLength = 1;
+ if (!InternetCrackUrlW(url, 0, 0, &url_comp))
+ return MK_E_SYNTAX;
+
+ if(!url_comp.nPort)
+ url_comp.nPort = This->https ? INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT;
+
+ host = heap_strndupW(url_comp.lpszHostName, url_comp.dwHostNameLength);
+ user = heap_strndupW(url_comp.lpszUserName, url_comp.dwUserNameLength);
+ pass = heap_strndupW(url_comp.lpszPassword, url_comp.dwPasswordLength);
+ This->base.connection = InternetConnectW(This->base.internet, host, url_comp.nPort, user, pass,
+ INTERNET_SERVICE_HTTP, This->https ? INTERNET_FLAG_SECURE : 0, (DWORD_PTR)&This->base);
+ heap_free(pass);
+ heap_free(user);
+ heap_free(host);
+ if(!This->base.connection) {
+ WARN("InternetConnect failed: %d\n", GetLastError());
+ return INET_E_CANNOT_CONNECT;
+ }
+
+ num = sizeof(accept_mimes)/sizeof(accept_mimes[0])-1;
+ hres = IInternetBindInfo_GetBindString(bind_info, BINDSTRING_ACCEPT_MIMES, accept_mimes, num, &num);
+ if(hres != S_OK) {
+ WARN("GetBindString BINDSTRING_ACCEPT_MIMES failed: %08x\n", hres);
+ return INET_E_NO_VALID_MEDIA;
+ }
+ accept_mimes[num] = 0;
+
+ path = heap_strndupW(url_comp.lpszUrlPath, url_comp.dwUrlPathLength);
+ if(This->https)
+ request_flags |= INTERNET_FLAG_SECURE;
+ This->base.request = HttpOpenRequestW(This->base.connection,
+ This->base.bind_info.dwBindVerb < BINDVERB_CUSTOM
+ ? wszBindVerb[This->base.bind_info.dwBindVerb] : This->base.bind_info.szCustomVerb,
+ path, NULL, NULL, (LPCWSTR *)accept_mimes, request_flags, (DWORD_PTR)&This->base);
+ heap_free(path);
+ while (numbase.request) {
+ WARN("HttpOpenRequest failed: %d\n", GetLastError());
+ return INET_E_RESOURCE_NOT_FOUND;
+ }
+
+ hres = IInternetProtocolSink_QueryInterface(This->base.protocol_sink, &IID_IServiceProvider,
+ (void **)&service_provider);
+ if (hres != S_OK) {
+ WARN("IInternetProtocolSink_QueryInterface IID_IServiceProvider failed: %08x\n", hres);
+ return hres;
+ }
+
+ hres = IServiceProvider_QueryService(service_provider, &IID_IHttpNegotiate,
+ &IID_IHttpNegotiate, (void **)&This->http_negotiate);
+ if (hres != S_OK) {
+ WARN("IServiceProvider_QueryService IID_IHttpNegotiate failed: %08x\n", hres);
+ return hres;
+ }
+
+ hres = IHttpNegotiate_BeginningTransaction(This->http_negotiate, url, wszHeaders,
+ 0, &addl_header);
+ if(hres != S_OK) {
+ WARN("IHttpNegotiate_BeginningTransaction failed: %08x\n", hres);
+ IServiceProvider_Release(service_provider);
+ return hres;
+ }
+
+ if(addl_header) {
+ int len_addl_header = strlenW(addl_header);
+
+ This->full_header = heap_alloc(len_addl_header*sizeof(WCHAR)+sizeof(wszHeaders));
+
+ lstrcpyW(This->full_header, addl_header);
+ lstrcpyW(&This->full_header[len_addl_header], wszHeaders);
+ CoTaskMemFree(addl_header);
+ }else {
+ This->full_header = (LPWSTR)wszHeaders;
+ }
+
+ hres = IServiceProvider_QueryService(service_provider, &IID_IHttpNegotiate2,
+ &IID_IHttpNegotiate2, (void **)&http_negotiate2);
+ IServiceProvider_Release(service_provider);
+ if(hres != S_OK) {
+ WARN("IServiceProvider_QueryService IID_IHttpNegotiate2 failed: %08x\n", hres);
+ /* No goto done as per native */
+ }else {
+ len = sizeof(security_id)/sizeof(security_id[0]);
+ hres = IHttpNegotiate2_GetRootSecurityId(http_negotiate2, security_id, &len, 0);
+ IHttpNegotiate2_Release(http_negotiate2);
+ if (hres != S_OK)
+ WARN("IHttpNegotiate2_GetRootSecurityId failed: %08x\n", hres);
+ }
+
+ /* FIXME: Handle security_id. Native calls undocumented function IsHostInProxyBypassList. */
+
+ if(This->base.bind_info.dwBindVerb == BINDVERB_POST) {
+ num = 0;
+ hres = IInternetBindInfo_GetBindString(bind_info, BINDSTRING_POST_COOKIE, &post_cookie, 1, &num);
+ if(hres == S_OK && num) {
+ if(!InternetSetOptionW(This->base.request, INTERNET_OPTION_SECONDARY_CACHE_KEY,
+ post_cookie, lstrlenW(post_cookie)))
+ WARN("InternetSetOption INTERNET_OPTION_SECONDARY_CACHE_KEY failed: %d\n", GetLastError());
+ CoTaskMemFree(post_cookie);
+ }
+ }
+
+ if(This->base.bind_info.dwBindVerb != BINDVERB_GET) {
+ /* Native does not use GlobalLock/GlobalUnlock, so we won't either */
+ if (This->base.bind_info.stgmedData.tymed != TYMED_HGLOBAL)
+ WARN("Expected This->base.bind_info.stgmedData.tymed to be TYMED_HGLOBAL, not %d\n",
+ This->base.bind_info.stgmedData.tymed);
+ else
+ optional = (LPWSTR)This->base.bind_info.stgmedData.u.hGlobal;
+ }
+
+ res = HttpSendRequestW(This->base.request, This->full_header, lstrlenW(This->full_header),
+ optional, optional ? This->base.bind_info.cbstgmedData : 0);
+ if(!res && GetLastError() != ERROR_IO_PENDING) {
+ WARN("HttpSendRequest failed: %d\n", GetLastError());
+ return INET_E_DOWNLOAD_FAILURE;
+ }
+
+ return S_OK;
+}
+
+static HRESULT HttpProtocol_start_downloading(Protocol *prot)
+{
+ HttpProtocol *This = ASYNCPROTOCOL_THIS(prot);
+ LPWSTR content_type = 0, content_length = 0;
+ DWORD len = sizeof(DWORD);
+ DWORD status_code;
+ BOOL res;
+ HRESULT hres;
+
+ static const WCHAR wszDefaultContentType[] =
+ {'t','e','x','t','/','h','t','m','l',0};
+
+ if(!This->http_negotiate) {
+ WARN("Expected IHttpNegotiate pointer to be non-NULL\n");
+ return S_OK;
+ }
+
+ res = HttpQueryInfoW(This->base.request, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
+ &status_code, &len, NULL);
+ if(res) {
+ LPWSTR response_headers = query_http_info(This, HTTP_QUERY_RAW_HEADERS_CRLF);
+ if(response_headers) {
+ hres = IHttpNegotiate_OnResponse(This->http_negotiate, status_code, response_headers,
+ NULL, NULL);
+ heap_free(response_headers);
+ if (hres != S_OK) {
+ WARN("IHttpNegotiate_OnResponse failed: %08x\n", hres);
+ return S_OK;
+ }
+ }
+ }else {
+ WARN("HttpQueryInfo failed: %d\n", GetLastError());
+ }
+
+ if(This->https)
+ IInternetProtocolSink_ReportProgress(This->base.protocol_sink, BINDSTATUS_ACCEPTRANGES, NULL);
+
+ content_type = query_http_info(This, HTTP_QUERY_CONTENT_TYPE);
+ if(content_type) {
+ /* remove the charset, if present */
+ LPWSTR p = strchrW(content_type, ';');
+ if (p) *p = '\0';
+
+ IInternetProtocolSink_ReportProgress(This->base.protocol_sink,
+ (This->base.bindf & BINDF_FROMURLMON)
+ ? BINDSTATUS_MIMETYPEAVAILABLE : BINDSTATUS_RAWMIMETYPE,
+ content_type);
+ heap_free(content_type);
+ }else {
+ WARN("HttpQueryInfo failed: %d\n", GetLastError());
+ IInternetProtocolSink_ReportProgress(This->base.protocol_sink,
+ (This->base.bindf & BINDF_FROMURLMON)
+ ? BINDSTATUS_MIMETYPEAVAILABLE : BINDSTATUS_RAWMIMETYPE,
+ wszDefaultContentType);
+ }
+
+ content_length = query_http_info(This, HTTP_QUERY_CONTENT_LENGTH);
+ if(content_length) {
+ This->base.content_length = atoiW(content_length);
+ heap_free(content_length);
+ }
+
+ return S_OK;
+}
+
+static void HttpProtocol_close_connection(Protocol *prot)
+{
+ HttpProtocol *This = ASYNCPROTOCOL_THIS(prot);
+
+ if(This->http_negotiate) {
+ IHttpNegotiate_Release(This->http_negotiate);
+ This->http_negotiate = 0;
+ }
+
+ if(This->full_header) {
+ if(This->full_header != wszHeaders)
+ heap_free(This->full_header);
+ This->full_header = 0;
+ }
+}
+
+#undef ASYNCPROTOCOL_THIS
+
+static const ProtocolVtbl AsyncProtocolVtbl = {
+ HttpProtocol_open_request,
+ HttpProtocol_start_downloading,
+ HttpProtocol_close_connection
+};
#define PROTOCOL_THIS(iface) DEFINE_THIS(HttpProtocol, InternetProtocol, iface)
@@ -285,7 +353,7 @@ static ULONG WINAPI HttpProtocol_Release(IInternetProtocol *iface)
TRACE("(%p) ref=%d\n", This, ref);
if(!ref) {
- HTTPPROTOCOL_Close(This);
+ protocol_close_connection(&This->base);
heap_free(This);
URLMON_UnlockModule();
@@ -299,422 +367,28 @@ static HRESULT WINAPI HttpProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl
DWORD grfPI, DWORD dwReserved)
{
HttpProtocol *This = PROTOCOL_THIS(iface);
- URL_COMPONENTSW url;
- DWORD len = 0, request_flags = INTERNET_FLAG_KEEP_CONNECTION;
- ULONG num = 0;
- IServiceProvider *service_provider = 0;
- IHttpNegotiate2 *http_negotiate2 = 0;
- LPWSTR host = 0, path = 0, user = 0, pass = 0, addl_header = 0,
- post_cookie = 0, optional = 0;
- BYTE security_id[512];
- LPOLESTR user_agent = NULL, accept_mimes[257];
- HRESULT hres;
static const WCHAR httpW[] = {'h','t','t','p',':'};
static const WCHAR httpsW[] = {'h','t','t','p','s',':'};
- static const WCHAR wszBindVerb[BINDVERB_CUSTOM][5] =
- {{'G','E','T',0},
- {'P','O','S','T',0},
- {'P','U','T',0}};
TRACE("(%p)->(%s %p %p %08x %d)\n", This, debugstr_w(szUrl), pOIProtSink,
pOIBindInfo, grfPI, dwReserved);
- IInternetProtocolSink_AddRef(pOIProtSink);
- This->protocol_sink = pOIProtSink;
-
- memset(&This->bind_info, 0, sizeof(This->bind_info));
- This->bind_info.cbSize = sizeof(BINDINFO);
- hres = IInternetBindInfo_GetBindInfo(pOIBindInfo, &This->grfBINDF, &This->bind_info);
- if (hres != S_OK)
- {
- WARN("GetBindInfo failed: %08x\n", hres);
- goto done;
- }
-
if(This->https
? strncmpW(szUrl, httpsW, sizeof(httpsW)/sizeof(WCHAR))
: strncmpW(szUrl, httpW, sizeof(httpW)/sizeof(WCHAR)))
- {
- hres = MK_E_SYNTAX;
- goto done;
- }
+ return MK_E_SYNTAX;
- memset(&url, 0, sizeof(url));
- url.dwStructSize = sizeof(url);
- url.dwSchemeLength = url.dwHostNameLength = url.dwUrlPathLength = url.dwUserNameLength =
- url.dwPasswordLength = 1;
- if (!InternetCrackUrlW(szUrl, 0, 0, &url))
- {
- hres = MK_E_SYNTAX;
- goto done;
- }
- host = strndupW(url.lpszHostName, url.dwHostNameLength);
- path = strndupW(url.lpszUrlPath, url.dwUrlPathLength);
- user = strndupW(url.lpszUserName, url.dwUserNameLength);
- pass = strndupW(url.lpszPassword, url.dwPasswordLength);
- if (!url.nPort)
- url.nPort = This->https ? INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT;
-
- if(!(This->grfBINDF & BINDF_FROMURLMON))
- IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_DIRECTBIND, NULL);
-
- hres = IInternetBindInfo_GetBindString(pOIBindInfo, BINDSTRING_USER_AGENT, &user_agent,
- 1, &num);
- if (hres != S_OK || !num)
- {
- CHAR null_char = 0;
- LPSTR user_agenta = NULL;
- len = 0;
- if ((hres = ObtainUserAgentString(0, &null_char, &len)) != E_OUTOFMEMORY)
- {
- WARN("ObtainUserAgentString failed: %08x\n", hres);
- }
- else if (!(user_agenta = heap_alloc(len*sizeof(CHAR))))
- {
- WARN("Out of memory\n");
- }
- else if ((hres = ObtainUserAgentString(0, user_agenta, &len)) != S_OK)
- {
- WARN("ObtainUserAgentString failed: %08x\n", hres);
- }
- else
- {
- if (!(user_agent = CoTaskMemAlloc((len)*sizeof(WCHAR))))
- WARN("Out of memory\n");
- else
- MultiByteToWideChar(CP_ACP, 0, user_agenta, -1, user_agent, len);
- }
- heap_free(user_agenta);
- }
-
- This->internet = InternetOpenW(user_agent, 0, NULL, NULL, INTERNET_FLAG_ASYNC);
- if (!This->internet)
- {
- WARN("InternetOpen failed: %d\n", GetLastError());
- hres = INET_E_NO_SESSION;
- goto done;
- }
-
- /* Native does not check for success of next call, so we won't either */
- InternetSetStatusCallbackW(This->internet, HTTPPROTOCOL_InternetStatusCallback);
-
- This->connect = InternetConnectW(This->internet, host, url.nPort, user,
- pass, INTERNET_SERVICE_HTTP,
- This->https ? INTERNET_FLAG_SECURE : 0,
- (DWORD_PTR)This);
- if (!This->connect)
- {
- WARN("InternetConnect failed: %d\n", GetLastError());
- hres = INET_E_CANNOT_CONNECT;
- goto done;
- }
-
- num = sizeof(accept_mimes)/sizeof(accept_mimes[0])-1;
- hres = IInternetBindInfo_GetBindString(pOIBindInfo, BINDSTRING_ACCEPT_MIMES,
- accept_mimes,
- num, &num);
- if (hres != S_OK)
- {
- WARN("GetBindString BINDSTRING_ACCEPT_MIMES failed: %08x\n", hres);
- hres = INET_E_NO_VALID_MEDIA;
- goto done;
- }
- accept_mimes[num] = 0;
-
- if (This->grfBINDF & BINDF_NOWRITECACHE)
- request_flags |= INTERNET_FLAG_NO_CACHE_WRITE;
- if (This->grfBINDF & BINDF_NEEDFILE)
- request_flags |= INTERNET_FLAG_NEED_FILE;
- if (This->https)
- request_flags |= INTERNET_FLAG_SECURE;
- This->request = HttpOpenRequestW(This->connect, This->bind_info.dwBindVerb < BINDVERB_CUSTOM ?
- wszBindVerb[This->bind_info.dwBindVerb] :
- This->bind_info.szCustomVerb,
- path, NULL, NULL, (LPCWSTR *)accept_mimes,
- request_flags, (DWORD_PTR)This);
- if (!This->request)
- {
- WARN("HttpOpenRequest failed: %d\n", GetLastError());
- hres = INET_E_RESOURCE_NOT_FOUND;
- goto done;
- }
-
- hres = IInternetProtocolSink_QueryInterface(This->protocol_sink, &IID_IServiceProvider,
- (void **)&service_provider);
- if (hres != S_OK)
- {
- WARN("IInternetProtocolSink_QueryInterface IID_IServiceProvider failed: %08x\n", hres);
- goto done;
- }
-
- hres = IServiceProvider_QueryService(service_provider, &IID_IHttpNegotiate,
- &IID_IHttpNegotiate, (void **)&This->http_negotiate);
- if (hres != S_OK)
- {
- WARN("IServiceProvider_QueryService IID_IHttpNegotiate failed: %08x\n", hres);
- goto done;
- }
-
- hres = IHttpNegotiate_BeginningTransaction(This->http_negotiate, szUrl, wszHeaders,
- 0, &addl_header);
- if (hres != S_OK)
- {
- WARN("IHttpNegotiate_BeginningTransaction failed: %08x\n", hres);
- goto done;
- }
- else if (addl_header == NULL)
- {
- This->full_header = (LPWSTR)wszHeaders;
- }
- else
- {
- int len_addl_header = lstrlenW(addl_header);
- This->full_header = heap_alloc(len_addl_header*sizeof(WCHAR)+sizeof(wszHeaders));
- if (!This->full_header)
- {
- WARN("Out of memory\n");
- hres = E_OUTOFMEMORY;
- goto done;
- }
- lstrcpyW(This->full_header, addl_header);
- lstrcpyW(&This->full_header[len_addl_header], wszHeaders);
- }
-
- hres = IServiceProvider_QueryService(service_provider, &IID_IHttpNegotiate2,
- &IID_IHttpNegotiate2, (void **)&http_negotiate2);
- if (hres != S_OK)
- {
- WARN("IServiceProvider_QueryService IID_IHttpNegotiate2 failed: %08x\n", hres);
- /* No goto done as per native */
- }
- else
- {
- len = sizeof(security_id)/sizeof(security_id[0]);
- hres = IHttpNegotiate2_GetRootSecurityId(http_negotiate2, security_id, &len, 0);
- if (hres != S_OK)
- {
- WARN("IHttpNegotiate2_GetRootSecurityId failed: %08x\n", hres);
- /* No goto done as per native */
- }
- }
-
- /* FIXME: Handle security_id. Native calls undocumented function IsHostInProxyBypassList. */
-
- if (This->bind_info.dwBindVerb == BINDVERB_POST)
- {
- num = 0;
- hres = IInternetBindInfo_GetBindString(pOIBindInfo, BINDSTRING_POST_COOKIE, &post_cookie,
- 1, &num);
- if (hres == S_OK && num &&
- !InternetSetOptionW(This->request, INTERNET_OPTION_SECONDARY_CACHE_KEY,
- post_cookie, lstrlenW(post_cookie)))
- {
- WARN("InternetSetOption INTERNET_OPTION_SECONDARY_CACHE_KEY failed: %d\n",
- GetLastError());
- }
- }
-
- if (This->bind_info.dwBindVerb != BINDVERB_GET)
- {
- /* Native does not use GlobalLock/GlobalUnlock, so we won't either */
- if (This->bind_info.stgmedData.tymed != TYMED_HGLOBAL)
- WARN("Expected This->bind_info.stgmedData.tymed to be TYMED_HGLOBAL, not %d\n",
- This->bind_info.stgmedData.tymed);
- else
- optional = (LPWSTR)This->bind_info.stgmedData.u.hGlobal;
- }
- if (!HttpSendRequestW(This->request, This->full_header, lstrlenW(This->full_header),
- optional,
- optional ? This->bind_info.cbstgmedData : 0) &&
- GetLastError() != ERROR_IO_PENDING)
- {
- WARN("HttpSendRequest failed: %d\n", GetLastError());
- hres = INET_E_DOWNLOAD_FAILURE;
- goto done;
- }
-
- hres = S_OK;
-done:
- if (hres != S_OK)
- {
- IInternetProtocolSink_ReportResult(This->protocol_sink, hres, 0, NULL);
- HTTPPROTOCOL_Close(This);
- }
-
- CoTaskMemFree(post_cookie);
- CoTaskMemFree(addl_header);
- if (http_negotiate2)
- IHttpNegotiate2_Release(http_negotiate2);
- if (service_provider)
- IServiceProvider_Release(service_provider);
-
- while (numbase, PROTOCOL(This), szUrl, pOIProtSink, pOIBindInfo);
}
static HRESULT WINAPI HttpProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
{
HttpProtocol *This = PROTOCOL_THIS(iface);
- DWORD len = sizeof(DWORD), status_code;
- LPWSTR response_headers = 0, content_type = 0, content_length = 0;
-
- static const WCHAR wszDefaultContentType[] =
- {'t','e','x','t','/','h','t','m','l',0};
TRACE("(%p)->(%p)\n", This, pProtocolData);
- if (!pProtocolData)
- {
- WARN("Expected pProtocolData to be non-NULL\n");
- return S_OK;
- }
- else if (!This->request)
- {
- WARN("Expected request to be non-NULL\n");
- return S_OK;
- }
- else if (!This->http_negotiate)
- {
- WARN("Expected IHttpNegotiate pointer to be non-NULL\n");
- return S_OK;
- }
- else if (!This->protocol_sink)
- {
- WARN("Expected IInternetProtocolSink pointer to be non-NULL\n");
- return S_OK;
- }
-
- if (pProtocolData->pData == (LPVOID)BINDSTATUS_DOWNLOADINGDATA)
- {
- if (!HttpQueryInfoW(This->request, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
- &status_code, &len, NULL))
- {
- WARN("HttpQueryInfo failed: %d\n", GetLastError());
- }
- else
- {
- len = 0;
- if ((!HttpQueryInfoW(This->request, HTTP_QUERY_RAW_HEADERS_CRLF, response_headers, &len,
- NULL) &&
- GetLastError() != ERROR_INSUFFICIENT_BUFFER) ||
- !(response_headers = heap_alloc(len)) ||
- !HttpQueryInfoW(This->request, HTTP_QUERY_RAW_HEADERS_CRLF, response_headers, &len,
- NULL))
- {
- WARN("HttpQueryInfo failed: %d\n", GetLastError());
- }
- else
- {
- HRESULT hres = IHttpNegotiate_OnResponse(This->http_negotiate, status_code,
- response_headers, NULL, NULL);
- if (hres != S_OK)
- {
- WARN("IHttpNegotiate_OnResponse failed: %08x\n", hres);
- goto done;
- }
- }
- }
-
- if(This->https)
- IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_ACCEPTRANGES, NULL);
-
- len = 0;
- if ((!HttpQueryInfoW(This->request, HTTP_QUERY_CONTENT_TYPE, content_type, &len, NULL) &&
- GetLastError() != ERROR_INSUFFICIENT_BUFFER) ||
- !(content_type = heap_alloc(len)) ||
- !HttpQueryInfoW(This->request, HTTP_QUERY_CONTENT_TYPE, content_type, &len, NULL))
- {
- WARN("HttpQueryInfo failed: %d\n", GetLastError());
- IInternetProtocolSink_ReportProgress(This->protocol_sink,
- (This->grfBINDF & BINDF_FROMURLMON) ?
- BINDSTATUS_MIMETYPEAVAILABLE :
- BINDSTATUS_RAWMIMETYPE,
- wszDefaultContentType);
- }
- else
- {
- /* remove the charset, if present */
- LPWSTR p = strchrW(content_type, ';');
- if (p) *p = '\0';
-
- IInternetProtocolSink_ReportProgress(This->protocol_sink,
- (This->grfBINDF & BINDF_FROMURLMON) ?
- BINDSTATUS_MIMETYPEAVAILABLE :
- BINDSTATUS_RAWMIMETYPE,
- content_type);
- }
-
- len = 0;
- if ((!HttpQueryInfoW(This->request, HTTP_QUERY_CONTENT_LENGTH, content_length, &len, NULL) &&
- GetLastError() != ERROR_INSUFFICIENT_BUFFER) ||
- !(content_length = heap_alloc(len)) ||
- !HttpQueryInfoW(This->request, HTTP_QUERY_CONTENT_LENGTH, content_length, &len, NULL))
- {
- WARN("HttpQueryInfo failed: %d\n", GetLastError());
- This->content_length = 0;
- }
- else
- {
- This->content_length = atoiW(content_length);
- }
-
- if(This->grfBINDF & BINDF_NEEDFILE) {
- WCHAR cache_file[MAX_PATH];
- DWORD buflen = sizeof(cache_file);
-
- if(InternetQueryOptionW(This->request, INTERNET_OPTION_DATAFILE_NAME,
- cache_file, &buflen))
- {
- IInternetProtocolSink_ReportProgress(This->protocol_sink,
- BINDSTATUS_CACHEFILENAMEAVAILABLE,
- cache_file);
- }else {
- FIXME("Could not get cache file\n");
- }
- }
-
- This->flags |= FLAG_FIRST_CONTINUE_COMPLETE;
- }
-
- if (pProtocolData->pData >= (LPVOID)BINDSTATUS_DOWNLOADINGDATA)
- {
- /* InternetQueryDataAvailable may immediately fork and perform its asynchronous
- * read, so clear the flag _before_ calling so it does not incorrectly get cleared
- * after the status callback is called */
- This->flags &= ~FLAG_REQUEST_COMPLETE;
- if (!InternetQueryDataAvailable(This->request, &This->available_bytes, 0, 0))
- {
- if (GetLastError() != ERROR_IO_PENDING)
- {
- This->flags |= FLAG_REQUEST_COMPLETE;
- WARN("InternetQueryDataAvailable failed: %d\n", GetLastError());
- HTTPPROTOCOL_ReportResult(This, INET_E_DATA_NOT_AVAILABLE);
- }
- }
- else
- {
- This->flags |= FLAG_REQUEST_COMPLETE;
- HTTPPROTOCOL_ReportData(This);
- }
- }
-
-done:
- heap_free(response_headers);
- heap_free(content_type);
- heap_free(content_length);
-
- /* Returns S_OK on native */
- return S_OK;
+ return protocol_continue(&This->base, pProtocolData);
}
static HRESULT WINAPI HttpProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
@@ -730,8 +404,8 @@ static HRESULT WINAPI HttpProtocol_Terminate(IInternetProtocol *iface, DWORD dwO
HttpProtocol *This = PROTOCOL_THIS(iface);
TRACE("(%p)->(%08x)\n", This, dwOptions);
- HTTPPROTOCOL_Close(This);
+ protocol_close_connection(&This->base);
return S_OK;
}
@@ -753,80 +427,10 @@ static HRESULT WINAPI HttpProtocol_Read(IInternetProtocol *iface, void *pv,
ULONG cb, ULONG *pcbRead)
{
HttpProtocol *This = PROTOCOL_THIS(iface);
- ULONG read = 0, len = 0;
- HRESULT hres = S_FALSE;
TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
- if (!(This->flags & FLAG_REQUEST_COMPLETE))
- {
- hres = E_PENDING;
- }
- else while (!(This->flags & FLAG_ALL_DATA_READ) &&
- read < cb)
- {
- if (This->available_bytes == 0)
- {
- /* InternetQueryDataAvailable may immediately fork and perform its asynchronous
- * read, so clear the flag _before_ calling so it does not incorrectly get cleared
- * after the status callback is called */
- This->flags &= ~FLAG_REQUEST_COMPLETE;
- if (!InternetQueryDataAvailable(This->request, &This->available_bytes, 0, 0))
- {
- if (GetLastError() == ERROR_IO_PENDING)
- {
- hres = E_PENDING;
- }
- else
- {
- WARN("InternetQueryDataAvailable failed: %d\n", GetLastError());
- hres = INET_E_DATA_NOT_AVAILABLE;
- HTTPPROTOCOL_ReportResult(This, hres);
- }
- goto done;
- }
- else if (This->available_bytes == 0)
- {
- HTTPPROTOCOL_AllDataRead(This);
- }
- }
- else
- {
- if (!InternetReadFile(This->request, ((BYTE *)pv)+read,
- This->available_bytes > cb-read ?
- cb-read : This->available_bytes, &len))
- {
- WARN("InternetReadFile failed: %d\n", GetLastError());
- hres = INET_E_DOWNLOAD_FAILURE;
- HTTPPROTOCOL_ReportResult(This, hres);
- goto done;
- }
- else if (len == 0)
- {
- HTTPPROTOCOL_AllDataRead(This);
- }
- else
- {
- read += len;
- This->current_position += len;
- This->available_bytes -= len;
- }
- }
- }
-
- /* Per MSDN this should be if (read == cb), but native returns S_OK
- * if any bytes were read, so we will too */
- if (read)
- hres = S_OK;
-
-done:
- if (pcbRead)
- *pcbRead = read;
-
- if (hres != E_PENDING)
- This->flags |= FLAG_REQUEST_COMPLETE;
-
- return hres;
+ return protocol_read(&This->base, pv, cb, pcbRead);
}
static HRESULT WINAPI HttpProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
@@ -843,10 +447,7 @@ static HRESULT WINAPI HttpProtocol_LockRequest(IInternetProtocol *iface, DWORD d
TRACE("(%p)->(%08x)\n", This, dwOptions);
- if (!InternetLockRequestFile(This->request, &This->lock))
- WARN("InternetLockRequest failed: %d\n", GetLastError());
-
- return S_OK;
+ return protocol_lock_request(&This->base);
}
static HRESULT WINAPI HttpProtocol_UnlockRequest(IInternetProtocol *iface)
@@ -855,18 +456,27 @@ static HRESULT WINAPI HttpProtocol_UnlockRequest(IInternetProtocol *iface)
TRACE("(%p)\n", This);
- if (This->lock)
- {
- if (!InternetUnlockRequestFile(This->lock))
- WARN("InternetUnlockRequest failed: %d\n", GetLastError());
- This->lock = 0;
- }
-
- return S_OK;
+ return protocol_unlock_request(&This->base);
}
#undef PROTOCOL_THIS
+static const IInternetProtocolVtbl HttpProtocolVtbl = {
+ HttpProtocol_QueryInterface,
+ HttpProtocol_AddRef,
+ HttpProtocol_Release,
+ HttpProtocol_Start,
+ HttpProtocol_Continue,
+ HttpProtocol_Abort,
+ HttpProtocol_Terminate,
+ HttpProtocol_Suspend,
+ HttpProtocol_Resume,
+ HttpProtocol_Read,
+ HttpProtocol_Seek,
+ HttpProtocol_LockRequest,
+ HttpProtocol_UnlockRequest
+};
+
#define PRIORITY_THIS(iface) DEFINE_THIS(HttpProtocol, InternetPriority, iface)
static HRESULT WINAPI HttpPriority_QueryInterface(IInternetPriority *iface, REFIID riid, void **ppv)
@@ -893,7 +503,7 @@ static HRESULT WINAPI HttpPriority_SetPriority(IInternetPriority *iface, LONG nP
TRACE("(%p)->(%d)\n", This, nPriority);
- This->priority = nPriority;
+ This->base.priority = nPriority;
return S_OK;
}
@@ -903,7 +513,7 @@ static HRESULT WINAPI HttpPriority_GetPriority(IInternetPriority *iface, LONG *p
TRACE("(%p)->(%p)\n", This, pnPriority);
- *pnPriority = This->priority;
+ *pnPriority = This->base.priority;
return S_OK;
}
@@ -917,22 +527,6 @@ static const IInternetPriorityVtbl HttpPriorityVtbl = {
HttpPriority_GetPriority
};
-static const IInternetProtocolVtbl HttpProtocolVtbl = {
- HttpProtocol_QueryInterface,
- HttpProtocol_AddRef,
- HttpProtocol_Release,
- HttpProtocol_Start,
- HttpProtocol_Continue,
- HttpProtocol_Abort,
- HttpProtocol_Terminate,
- HttpProtocol_Suspend,
- HttpProtocol_Resume,
- HttpProtocol_Read,
- HttpProtocol_Seek,
- HttpProtocol_LockRequest,
- HttpProtocol_UnlockRequest
-};
-
static HRESULT create_http_protocol(BOOL https, void **ppobj)
{
HttpProtocol *ret;
@@ -941,6 +535,7 @@ static HRESULT create_http_protocol(BOOL https, void **ppobj)
if(!ret)
return E_OUTOFMEMORY;
+ ret->base.vtbl = &AsyncProtocolVtbl;
ret->lpInternetProtocolVtbl = &HttpProtocolVtbl;
ret->lpInternetPriorityVtbl = &HttpPriorityVtbl;
diff --git a/reactos/dll/win32/urlmon/protocol.c b/reactos/dll/win32/urlmon/protocol.c
new file mode 100644
index 00000000000..b3d979e95f4
--- /dev/null
+++ b/reactos/dll/win32/urlmon/protocol.c
@@ -0,0 +1,430 @@
+/*
+ * Copyright 2007 Misha Koshelev
+ * Copyright 2009 Jacek Caban for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "urlmon_main.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
+
+/* Flags are needed for, among other things, return HRESULTs from the Read function
+ * to conform to native. For example, Read returns:
+ *
+ * 1. E_PENDING if called before the request has completed,
+ * (flags = 0)
+ * 2. S_FALSE after all data has been read and S_OK has been reported,
+ * (flags = FLAG_REQUEST_COMPLETE | FLAG_ALL_DATA_READ | FLAG_RESULT_REPORTED)
+ * 3. INET_E_DATA_NOT_AVAILABLE if InternetQueryDataAvailable fails. The first time
+ * this occurs, INET_E_DATA_NOT_AVAILABLE will also be reported to the sink,
+ * (flags = FLAG_REQUEST_COMPLETE)
+ * but upon subsequent calls to Read no reporting will take place, yet
+ * InternetQueryDataAvailable will still be called, and, on failure,
+ * INET_E_DATA_NOT_AVAILABLE will still be returned.
+ * (flags = FLAG_REQUEST_COMPLETE | FLAG_RESULT_REPORTED)
+ *
+ * FLAG_FIRST_DATA_REPORTED and FLAG_LAST_DATA_REPORTED are needed for proper
+ * ReportData reporting. For example, if OnResponse returns S_OK, Continue will
+ * report BSCF_FIRSTDATANOTIFICATION, and when all data has been read Read will
+ * report BSCF_INTERMEDIATEDATANOTIFICATION|BSCF_LASTDATANOTIFICATION. However,
+ * if OnResponse does not return S_OK, Continue will not report data, and Read
+ * will report BSCF_FIRSTDATANOTIFICATION|BSCF_LASTDATANOTIFICATION when all
+ * data has been read.
+ */
+#define FLAG_REQUEST_COMPLETE 0x0001
+#define FLAG_FIRST_CONTINUE_COMPLETE 0x0002
+#define FLAG_FIRST_DATA_REPORTED 0x0004
+#define FLAG_ALL_DATA_READ 0x0008
+#define FLAG_LAST_DATA_REPORTED 0x0010
+#define FLAG_RESULT_REPORTED 0x0020
+
+static inline HRESULT report_progress(Protocol *protocol, ULONG status_code, LPCWSTR status_text)
+{
+ return IInternetProtocolSink_ReportProgress(protocol->protocol_sink, status_code, status_text);
+}
+
+static inline HRESULT report_result(Protocol *protocol, HRESULT hres)
+{
+ if (!(protocol->flags & FLAG_RESULT_REPORTED) && protocol->protocol_sink) {
+ protocol->flags |= FLAG_RESULT_REPORTED;
+ IInternetProtocolSink_ReportResult(protocol->protocol_sink, hres, 0, NULL);
+ }
+
+ return hres;
+}
+
+static void report_data(Protocol *protocol)
+{
+ DWORD bscf;
+
+ if((protocol->flags & FLAG_LAST_DATA_REPORTED) || !protocol->protocol_sink)
+ return;
+
+ if(protocol->flags & FLAG_FIRST_DATA_REPORTED) {
+ bscf = BSCF_INTERMEDIATEDATANOTIFICATION;
+ }else {
+ protocol->flags |= FLAG_FIRST_DATA_REPORTED;
+ bscf = BSCF_FIRSTDATANOTIFICATION;
+ }
+
+ if(protocol->flags & FLAG_ALL_DATA_READ && !(protocol->flags & FLAG_LAST_DATA_REPORTED)) {
+ protocol->flags |= FLAG_LAST_DATA_REPORTED;
+ bscf |= BSCF_LASTDATANOTIFICATION;
+ }
+
+ IInternetProtocolSink_ReportData(protocol->protocol_sink, bscf,
+ protocol->current_position+protocol->available_bytes,
+ protocol->content_length);
+}
+
+static void all_data_read(Protocol *protocol)
+{
+ protocol->flags |= FLAG_ALL_DATA_READ;
+
+ report_data(protocol);
+ report_result(protocol, S_OK);
+}
+
+static void request_complete(Protocol *protocol, INTERNET_ASYNC_RESULT *ar)
+{
+ PROTOCOLDATA data;
+
+ if(!ar->dwResult) {
+ WARN("request failed: %d\n", ar->dwError);
+ return;
+ }
+
+ protocol->flags |= FLAG_REQUEST_COMPLETE;
+
+ if(!protocol->request) {
+ TRACE("setting request handle %p\n", (HINTERNET)ar->dwResult);
+ protocol->request = (HINTERNET)ar->dwResult;
+ }
+
+ /* PROTOCOLDATA same as native */
+ memset(&data, 0, sizeof(data));
+ data.dwState = 0xf1000000;
+ if(protocol->flags & FLAG_FIRST_CONTINUE_COMPLETE)
+ data.pData = (LPVOID)BINDSTATUS_ENDDOWNLOADCOMPONENTS;
+ else
+ data.pData = (LPVOID)BINDSTATUS_DOWNLOADINGDATA;
+
+ if (protocol->bindf & BINDF_FROMURLMON)
+ IInternetProtocolSink_Switch(protocol->protocol_sink, &data);
+ else
+ protocol_continue(protocol, &data);
+}
+
+static void WINAPI internet_status_callback(HINTERNET internet, DWORD_PTR context,
+ DWORD internet_status, LPVOID status_info, DWORD status_info_len)
+{
+ Protocol *protocol = (Protocol*)context;
+
+ switch(internet_status) {
+ case INTERNET_STATUS_RESOLVING_NAME:
+ TRACE("%p INTERNET_STATUS_RESOLVING_NAME\n", protocol);
+ report_progress(protocol, BINDSTATUS_FINDINGRESOURCE, (LPWSTR)status_info);
+ break;
+
+ case INTERNET_STATUS_CONNECTING_TO_SERVER:
+ TRACE("%p INTERNET_STATUS_CONNECTING_TO_SERVER\n", protocol);
+ report_progress(protocol, BINDSTATUS_CONNECTING, (LPWSTR)status_info);
+ break;
+
+ case INTERNET_STATUS_SENDING_REQUEST:
+ TRACE("%p INTERNET_STATUS_SENDING_REQUEST\n", protocol);
+ report_progress(protocol, BINDSTATUS_SENDINGREQUEST, (LPWSTR)status_info);
+ break;
+
+ case INTERNET_STATUS_REQUEST_COMPLETE:
+ request_complete(protocol, status_info);
+ break;
+
+ case INTERNET_STATUS_HANDLE_CREATED:
+ TRACE("%p INTERNET_STATUS_HANDLE_CREATED\n", protocol);
+ IInternetProtocol_AddRef(protocol->protocol);
+ break;
+
+ case INTERNET_STATUS_HANDLE_CLOSING:
+ TRACE("%p INTERNET_STATUS_HANDLE_CLOSING\n", protocol);
+
+ if(*(HINTERNET *)status_info == protocol->request) {
+ protocol->request = NULL;
+ if(protocol->protocol_sink) {
+ IInternetProtocolSink_Release(protocol->protocol_sink);
+ protocol->protocol_sink = NULL;
+ }
+
+ if(protocol->bind_info.cbSize) {
+ ReleaseBindInfo(&protocol->bind_info);
+ memset(&protocol->bind_info, 0, sizeof(protocol->bind_info));
+ }
+ }else if(*(HINTERNET *)status_info == protocol->connection) {
+ protocol->connection = NULL;
+ }
+
+ IInternetProtocol_Release(protocol->protocol);
+ break;
+
+ default:
+ WARN("Unhandled Internet status callback %d\n", internet_status);
+ }
+}
+
+HRESULT protocol_start(Protocol *protocol, IInternetProtocol *prot, LPCWSTR url,
+ IInternetProtocolSink *protocol_sink, IInternetBindInfo *bind_info)
+{
+ LPOLESTR user_agent = NULL;
+ DWORD request_flags;
+ ULONG size = 0;
+ HRESULT hres;
+
+ protocol->protocol = prot;
+
+ IInternetProtocolSink_AddRef(protocol_sink);
+ protocol->protocol_sink = protocol_sink;
+
+ memset(&protocol->bind_info, 0, sizeof(protocol->bind_info));
+ protocol->bind_info.cbSize = sizeof(BINDINFO);
+ hres = IInternetBindInfo_GetBindInfo(bind_info, &protocol->bindf, &protocol->bind_info);
+ if(hres != S_OK) {
+ WARN("GetBindInfo failed: %08x\n", hres);
+ return report_result(protocol, hres);
+ }
+
+ if(!(protocol->bindf & BINDF_FROMURLMON))
+ report_progress(protocol, BINDSTATUS_DIRECTBIND, NULL);
+
+ hres = IInternetBindInfo_GetBindString(bind_info, BINDSTRING_USER_AGENT, &user_agent, 1, &size);
+ if (hres != S_OK || !size) {
+ DWORD len;
+ CHAR null_char = 0;
+ LPSTR user_agenta = NULL;
+
+ len = 0;
+ if ((hres = ObtainUserAgentString(0, &null_char, &len)) != E_OUTOFMEMORY) {
+ WARN("ObtainUserAgentString failed: %08x\n", hres);
+ }else if (!(user_agenta = heap_alloc(len*sizeof(CHAR)))) {
+ WARN("Out of memory\n");
+ }else if ((hres = ObtainUserAgentString(0, user_agenta, &len)) != S_OK) {
+ WARN("ObtainUserAgentString failed: %08x\n", hres);
+ }else {
+ if(!(user_agent = CoTaskMemAlloc((len)*sizeof(WCHAR))))
+ WARN("Out of memory\n");
+ else
+ MultiByteToWideChar(CP_ACP, 0, user_agenta, -1, user_agent, len);
+ }
+ heap_free(user_agenta);
+ }
+
+ protocol->internet = InternetOpenW(user_agent, 0, NULL, NULL, INTERNET_FLAG_ASYNC);
+ CoTaskMemFree(user_agent);
+ if(!protocol->internet) {
+ WARN("InternetOpen failed: %d\n", GetLastError());
+ return report_result(protocol, INET_E_NO_SESSION);
+ }
+
+ /* Native does not check for success of next call, so we won't either */
+ InternetSetStatusCallbackW(protocol->internet, internet_status_callback);
+
+ request_flags = INTERNET_FLAG_KEEP_CONNECTION;
+ if(protocol->bindf & BINDF_NOWRITECACHE)
+ request_flags |= INTERNET_FLAG_NO_CACHE_WRITE;
+ if(protocol->bindf & BINDF_NEEDFILE)
+ request_flags |= INTERNET_FLAG_NEED_FILE;
+
+ hres = protocol->vtbl->open_request(protocol, url, request_flags, bind_info);
+ if(FAILED(hres)) {
+ protocol_close_connection(protocol);
+ return report_result(protocol, hres);
+ }
+
+ return S_OK;
+}
+
+HRESULT protocol_continue(Protocol *protocol, PROTOCOLDATA *data)
+{
+ HRESULT hres;
+
+ if (!data) {
+ WARN("Expected pProtocolData to be non-NULL\n");
+ return S_OK;
+ }
+
+ if(!protocol->request) {
+ WARN("Expected request to be non-NULL\n");
+ return S_OK;
+ }
+
+ if(!protocol->protocol_sink) {
+ WARN("Expected IInternetProtocolSink pointer to be non-NULL\n");
+ return S_OK;
+ }
+
+ if(data->pData == (LPVOID)BINDSTATUS_DOWNLOADINGDATA) {
+ hres = protocol->vtbl->start_downloading(protocol);
+ if(FAILED(hres)) {
+ protocol_close_connection(protocol);
+ report_result(protocol, hres);
+ return S_OK;
+ }
+
+ if(protocol->bindf & BINDF_NEEDFILE) {
+ WCHAR cache_file[MAX_PATH];
+ DWORD buflen = sizeof(cache_file);
+
+ if(InternetQueryOptionW(protocol->request, INTERNET_OPTION_DATAFILE_NAME,
+ cache_file, &buflen)) {
+ report_progress(protocol, BINDSTATUS_CACHEFILENAMEAVAILABLE, cache_file);
+ }else {
+ FIXME("Could not get cache file\n");
+ }
+ }
+
+ protocol->flags |= FLAG_FIRST_CONTINUE_COMPLETE;
+ }
+
+ if(data->pData >= (LPVOID)BINDSTATUS_DOWNLOADINGDATA) {
+ BOOL res;
+
+ /* InternetQueryDataAvailable may immediately fork and perform its asynchronous
+ * read, so clear the flag _before_ calling so it does not incorrectly get cleared
+ * after the status callback is called */
+ protocol->flags &= ~FLAG_REQUEST_COMPLETE;
+ res = InternetQueryDataAvailable(protocol->request, &protocol->available_bytes, 0, 0);
+ if(res) {
+ protocol->flags |= FLAG_REQUEST_COMPLETE;
+ report_data(protocol);
+ }else if(GetLastError() != ERROR_IO_PENDING) {
+ protocol->flags |= FLAG_REQUEST_COMPLETE;
+ WARN("InternetQueryDataAvailable failed: %d\n", GetLastError());
+ report_result(protocol, INET_E_DATA_NOT_AVAILABLE);
+ }
+ }
+
+ return S_OK;
+}
+
+HRESULT protocol_read(Protocol *protocol, void *buf, ULONG size, ULONG *read_ret)
+{
+ ULONG read = 0;
+ BOOL res;
+ HRESULT hres = S_FALSE;
+
+ if(!(protocol->flags & FLAG_REQUEST_COMPLETE)) {
+ *read_ret = 0;
+ return E_PENDING;
+ }
+
+ if(protocol->flags & FLAG_ALL_DATA_READ) {
+ *read_ret = 0;
+ return S_FALSE;
+ }
+
+ while(read < size) {
+ if(protocol->available_bytes) {
+ ULONG len;
+
+ res = InternetReadFile(protocol->request, ((BYTE *)buf)+read,
+ protocol->available_bytes > size-read ? size-read : protocol->available_bytes, &len);
+ if(!res) {
+ WARN("InternetReadFile failed: %d\n", GetLastError());
+ hres = INET_E_DOWNLOAD_FAILURE;
+ report_result(protocol, hres);
+ break;
+ }
+
+ if(!len) {
+ all_data_read(protocol);
+ break;
+ }
+
+ read += len;
+ protocol->current_position += len;
+ protocol->available_bytes -= len;
+ }else {
+ /* InternetQueryDataAvailable may immediately fork and perform its asynchronous
+ * read, so clear the flag _before_ calling so it does not incorrectly get cleared
+ * after the status callback is called */
+ protocol->flags &= ~FLAG_REQUEST_COMPLETE;
+ res = InternetQueryDataAvailable(protocol->request, &protocol->available_bytes, 0, 0);
+ if(!res) {
+ if (GetLastError() == ERROR_IO_PENDING) {
+ hres = E_PENDING;
+ }else {
+ WARN("InternetQueryDataAvailable failed: %d\n", GetLastError());
+ hres = INET_E_DATA_NOT_AVAILABLE;
+ report_result(protocol, hres);
+ }
+ break;
+ }
+
+ if(!protocol->available_bytes) {
+ all_data_read(protocol);
+ break;
+ }
+ }
+ }
+
+ *read_ret = read;
+
+ if (hres != E_PENDING)
+ protocol->flags |= FLAG_REQUEST_COMPLETE;
+ if(FAILED(hres))
+ return hres;
+
+ return read ? S_OK : S_FALSE;
+}
+
+HRESULT protocol_lock_request(Protocol *protocol)
+{
+ if (!InternetLockRequestFile(protocol->request, &protocol->lock))
+ WARN("InternetLockRequest failed: %d\n", GetLastError());
+
+ return S_OK;
+}
+
+HRESULT protocol_unlock_request(Protocol *protocol)
+{
+ if(!protocol->lock)
+ return S_OK;
+
+ if(!InternetUnlockRequestFile(protocol->lock))
+ WARN("InternetUnlockRequest failed: %d\n", GetLastError());
+ protocol->lock = 0;
+
+ return S_OK;
+}
+
+void protocol_close_connection(Protocol *protocol)
+{
+ protocol->vtbl->close_connection(protocol);
+
+ if(protocol->request)
+ InternetCloseHandle(protocol->request);
+
+ if(protocol->connection)
+ InternetCloseHandle(protocol->connection);
+
+ if(protocol->internet) {
+ InternetCloseHandle(protocol->internet);
+ protocol->internet = 0;
+ }
+
+ protocol->flags = 0;
+}
diff --git a/reactos/dll/win32/urlmon/umon.c b/reactos/dll/win32/urlmon/umon.c
index bbaed5b7a2a..c338b1505db 100644
--- a/reactos/dll/win32/urlmon/umon.c
+++ b/reactos/dll/win32/urlmon/umon.c
@@ -532,8 +532,6 @@ static HRESULT URLMonikerImpl_BindToStorage_hack(LPCWSTR URLName, IBindCtx* pbc,
if(SUCCEEDED(hres)) {
URL_COMPONENTSW url;
WCHAR *host, *path, *user, *pass;
- DWORD dwService = 0;
- BOOL bSuccess;
TRACE("got bindinfo. bindf = %08x extrainfo = %s bindinfof = %08x bindverb = %08x iid %s\n",
bindf, debugstr_w(bi.szExtraInfo), bi.grfBindInfoF, bi.dwBindVerb, debugstr_guid(&bi.iid));
@@ -583,23 +581,10 @@ static HRESULT URLMonikerImpl_BindToStorage_hack(LPCWSTR URLName, IBindCtx* pbc,
break;
}
- switch ((DWORD) url.nScheme)
- {
- case INTERNET_SCHEME_FTP:
- if (!url.nPort)
- url.nPort = INTERNET_DEFAULT_FTP_PORT;
- dwService = INTERNET_SERVICE_FTP;
- break;
-
- case INTERNET_SCHEME_GOPHER:
- if (!url.nPort)
- url.nPort = INTERNET_DEFAULT_GOPHER_PORT;
- dwService = INTERNET_SERVICE_GOPHER;
- break;
- }
-
+ if (!url.nPort)
+ url.nPort = INTERNET_DEFAULT_GOPHER_PORT;
bind->hconnect = InternetConnectW(bind->hinternet, host, url.nPort, user, pass,
- dwService, 0, (DWORD_PTR)bind);
+ INTERNET_SERVICE_GOPHER, 0, (DWORD_PTR)bind);
if (!bind->hconnect)
{
hres = HRESULT_FROM_WIN32(GetLastError());
@@ -612,37 +597,12 @@ static HRESULT URLMonikerImpl_BindToStorage_hack(LPCWSTR URLName, IBindCtx* pbc,
hres = IBindStatusCallback_OnProgress(bind->pbscb, 0, 0, BINDSTATUS_CONNECTING, NULL);
hres = IBindStatusCallback_OnProgress(bind->pbscb, 0, 0, BINDSTATUS_SENDINGREQUEST, NULL);
- bSuccess = FALSE;
-
- switch (dwService)
- {
- case INTERNET_SERVICE_GOPHER:
- bind->hrequest = GopherOpenFileW(bind->hconnect,
- path,
- 0,
- INTERNET_FLAG_RELOAD,
- 0);
- if (bind->hrequest)
- bSuccess = TRUE;
- else
- hres = HRESULT_FROM_WIN32(GetLastError());
- break;
-
- case INTERNET_SERVICE_FTP:
- bind->hrequest = FtpOpenFileW(bind->hconnect,
- path,
- GENERIC_READ,
- FTP_TRANSFER_TYPE_BINARY |
- INTERNET_FLAG_TRANSFER_BINARY |
- INTERNET_FLAG_RELOAD,
- 0);
- if (bind->hrequest)
- bSuccess = TRUE;
- else
- hres = HRESULT_FROM_WIN32(GetLastError());
- break;
- }
- if(bSuccess)
+ bind->hrequest = GopherOpenFileW(bind->hconnect,
+ path,
+ 0,
+ INTERNET_FLAG_RELOAD,
+ 0);
+ if (bind->hrequest)
{
TRACE("res = %d gle = %u url len = %d\n", hres, GetLastError(), bind->expected_size);
@@ -660,7 +620,10 @@ static HRESULT URLMonikerImpl_BindToStorage_hack(LPCWSTR URLName, IBindCtx* pbc,
}
InternetCloseHandle(bind->hrequest);
hres = S_OK;
+ }else {
+ hres = HRESULT_FROM_WIN32(GetLastError());
}
+
InternetCloseHandle(bind->hconnect);
InternetCloseHandle(bind->hinternet);
@@ -704,9 +667,7 @@ static HRESULT WINAPI URLMonikerImpl_BindToStorage(IMoniker* iface,
return E_FAIL;
}
- if(IsEqualGUID(&IID_IStream, riid) &&
- ( url.nScheme == INTERNET_SCHEME_FTP
- || url.nScheme == INTERNET_SCHEME_GOPHER))
+ if(IsEqualGUID(&IID_IStream, riid) && url.nScheme == INTERNET_SCHEME_GOPHER)
return URLMonikerImpl_BindToStorage_hack(This->URLName, pbc, ppvObject);
TRACE("(%p)->(%p %p %s %p)\n", This, pbc, pmkToLeft, debugstr_guid(riid), ppvObject);
diff --git a/reactos/dll/win32/urlmon/urlmon.rbuild b/reactos/dll/win32/urlmon/urlmon.rbuild
index 0699b9ab3a0..6828cffa6ba 100644
--- a/reactos/dll/win32/urlmon/urlmon.rbuild
+++ b/reactos/dll/win32/urlmon/urlmon.rbuild
@@ -18,6 +18,7 @@
http.c
internet.c
mk.c
+ protocol.c
regsvr.c
sec_mgr.c
session.c
diff --git a/reactos/dll/win32/urlmon/urlmon_main.h b/reactos/dll/win32/urlmon/urlmon_main.h
index 17cbd7637ad..10776f9193a 100644
--- a/reactos/dll/win32/urlmon/urlmon_main.h
+++ b/reactos/dll/win32/urlmon/urlmon_main.h
@@ -1,5 +1,6 @@
/*
* Copyright 2002 Huw D M Davies for CodeWeavers
+ * Copyright 2009 Jacek Caban for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -30,6 +31,7 @@
#include "winuser.h"
#include "ole2.h"
#include "urlmon.h"
+#include "wininet.h"
#include "wine/unicode.h"
@@ -50,7 +52,8 @@ static inline void URLMON_LockModule(void) { InterlockedIncrement( &URLMON_refCo
static inline void URLMON_UnlockModule(void) { InterlockedDecrement( &URLMON_refCount ); }
#define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field))
-#define DEFINE_THIS(cls,ifc,iface) ((cls*)((BYTE*)(iface)-offsetof(cls,lp ## ifc ## Vtbl)))
+#define DEFINE_THIS2(cls,ifc,iface) ((cls*)((BYTE*)(iface)-offsetof(cls,ifc)))
+#define DEFINE_THIS(cls,ifc,iface) DEFINE_THIS2(cls,lp ## ifc ## Vtbl,iface)
typedef struct
{
@@ -76,6 +79,43 @@ HRESULT bind_to_object(IMoniker *mon, LPCWSTR url, IBindCtx *pbc, REFIID riid, v
HRESULT create_binding_protocol(LPCWSTR url, BOOL from_urlmon, IInternetProtocol **protocol);
void set_binding_sink(IInternetProtocol *bind_protocol, IInternetProtocolSink *sink);
+typedef struct ProtocolVtbl ProtocolVtbl;
+
+typedef struct {
+ const ProtocolVtbl *vtbl;
+
+ IInternetProtocol *protocol;
+ IInternetProtocolSink *protocol_sink;
+
+ DWORD bindf;
+ BINDINFO bind_info;
+
+ HINTERNET internet;
+ HINTERNET request;
+ HINTERNET connection;
+ DWORD flags;
+ HANDLE lock;
+
+ ULONG current_position;
+ ULONG content_length;
+ ULONG available_bytes;
+
+ LONG priority;
+} Protocol;
+
+struct ProtocolVtbl {
+ HRESULT (*open_request)(Protocol*,LPCWSTR,DWORD,IInternetBindInfo*);
+ HRESULT (*start_downloading)(Protocol*);
+ void (*close_connection)(Protocol*);
+};
+
+HRESULT protocol_start(Protocol*,IInternetProtocol*,LPCWSTR,IInternetProtocolSink*,IInternetBindInfo*);
+HRESULT protocol_continue(Protocol*,PROTOCOLDATA*);
+HRESULT protocol_read(Protocol*,void*,ULONG,ULONG*);
+HRESULT protocol_lock_request(Protocol*);
+HRESULT protocol_unlock_request(Protocol*);
+void protocol_close_connection(Protocol*);
+
static inline void *heap_alloc(size_t len)
{
return HeapAlloc(GetProcessHeap(), 0, len);
@@ -111,6 +151,21 @@ static inline LPWSTR heap_strdupW(LPCWSTR str)
return ret;
}
+static inline LPWSTR heap_strndupW(LPCWSTR str, int len)
+{
+ LPWSTR ret = NULL;
+
+ if(str) {
+ ret = heap_alloc((len+1)*sizeof(WCHAR));
+ if(ret) {
+ memcpy(ret, str, len*sizeof(WCHAR));
+ ret[len] = 0;
+ }
+ }
+
+ return ret;
+}
+
static inline LPWSTR heap_strdupAtoW(const char *str)
{
LPWSTR ret = NULL;