diff --git a/base/applications/dxdiag/dxdiag.c b/base/applications/dxdiag/dxdiag.c index 3985fae208d..2c9bc701baf 100644 --- a/base/applications/dxdiag/dxdiag.c +++ b/base/applications/dxdiag/dxdiag.c @@ -126,7 +126,6 @@ InitializeTabCtrl(HWND hwndDlg, PDXDIAG_CONTEXT pContext) pContext->hDialogs[4] = CreateDialogParamW(hInst, MAKEINTRESOURCEW(IDD_HELP_DIALOG), hTabCtrlWnd, HelpPageWndProc, (LPARAM)pContext); /* insert tab ctrl items */ - InsertTabCtrlItem(hTabCtrlWnd, 0, MAKEINTRESOURCEW(IDS_SYSTEM_DIALOG)); InitializeDisplayAdapters(pContext); InitializeDirectSoundPage(pContext); @@ -188,8 +187,19 @@ DxDiagWndProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam) if (LOWORD(wParam) == IDC_BUTTON_NEXT) { - //TODO - /* handle next button */ + INT CurSel; + + /* retrieve current page */ + CurSel = TabCtrl_GetCurSel(hTabCtrlWnd); + CurSel++; + + /* enable/disable next button */ + EnableWindow(GetDlgItem(hwndDlg, IDC_BUTTON_NEXT), + (CurSel != TabCtrl_GetItemCount(hTabCtrlWnd) - 1)); + + /* switch to next page */ + SendMessageW(hTabCtrlWnd, TCM_SETCURSEL, CurSel, 0L); + return TRUE; } @@ -210,6 +220,12 @@ DxDiagWndProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam) pnmh = (LPNMHDR)lParam; if ((pnmh->hwndFrom == hTabCtrlWnd) && (pnmh->idFrom == IDC_TAB_CONTROL) && (pnmh->code == TCN_SELCHANGE)) { + INT CurSel = TabCtrl_GetCurSel(hTabCtrlWnd); + + /* enable/disable next button */ + EnableWindow(GetDlgItem(hwndDlg, IDC_BUTTON_NEXT), + (CurSel != TabCtrl_GetItemCount(hTabCtrlWnd) - 1)); + TabCtrl_OnSelChange(pContext); } break; diff --git a/base/applications/dxdiag/system.c b/base/applications/dxdiag/system.c index 33c1f9d5bde..311fc03cdf7 100644 --- a/base/applications/dxdiag/system.c +++ b/base/applications/dxdiag/system.c @@ -17,7 +17,6 @@ GetRegValue(HKEY hBaseKey, LPWSTR SubKey, LPWSTR ValueName, DWORD Type, LPWSTR R DWORD dwType; DWORD dwSize; - if (RegOpenKeyExW(hBaseKey, SubKey, 0, KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS) return FALSE; @@ -25,10 +24,10 @@ GetRegValue(HKEY hBaseKey, LPWSTR SubKey, LPWSTR ValueName, DWORD Type, LPWSTR R res = RegQueryValueExW(hKey, ValueName, NULL, &dwType, (LPBYTE)Result, &dwSize); RegCloseKey(hKey); - if (dwType != Type) + if (res != ERROR_SUCCESS) return FALSE; - if (res != ERROR_SUCCESS) + if (dwType != Type) return FALSE; if (Size == sizeof(DWORD)) diff --git a/base/applications/rapps/rapps/firefox3.txt b/base/applications/rapps/rapps/firefox3.txt index d4d2272179a..072eee6407b 100644 --- a/base/applications/rapps/rapps/firefox3.txt +++ b/base/applications/rapps/rapps/firefox3.txt @@ -8,35 +8,35 @@ Description = The most popular and one of the best free Web Browsers out there. Size = 7.1M Category = 5 URLSite = http://www.mozilla.com/en-US/ -URLDownload = http://releases.mozilla.org/pub/mozilla.org/firefox/releases/latest-3.0/win32/en-US/Firefox%20Setup%203.0.17.exe +URLDownload = http://releases.mozilla.org/pub/mozilla.org/firefox/releases/latest-3.0/win32/en-US/Firefox%20Setup%203.0.18.exe CDPath = none [Section.0407] Description = Der populärste und einer der besten freien Webbrowser. Size = 6.9M URLSite = http://www.mozilla-europe.org/de/ -URLDownload = http://releases.mozilla.org/pub/mozilla.org/firefox/releases/latest-3.0/win32/de/Firefox%20Setup%203.0.17.exe +URLDownload = http://releases.mozilla.org/pub/mozilla.org/firefox/releases/latest-3.0/win32/de/Firefox%20Setup%203.0.18.exe [Section.040a] Description = El más popular y uno de los mejores navegadores web gratuitos que hay. Size = 7.0M URLSite = http://www.mozilla-europe.org/es/ -URLDownload = http://releases.mozilla.org/pub/mozilla.org/firefox/releases/latest-3.0/win32/es-ES/Firefox%20Setup%203.0.17.exe +URLDownload = http://releases.mozilla.org/pub/mozilla.org/firefox/releases/latest-3.0/win32/es-ES/Firefox%20Setup%203.0.18.exe [Section.0414] Description = Mest populære og best også gratis nettleserene der ute. Size = 6.9M URLSite = http://www.mozilla-europe.org/no/ -URLDownload = http://releases.mozilla.org/pub/mozilla.org/firefox/releases/latest-3.0/win32/nb-NO/Firefox%20Setup%203.0.17.exe +URLDownload = http://releases.mozilla.org/pub/mozilla.org/firefox/releases/latest-3.0/win32/nb-NO/Firefox%20Setup%203.0.18.exe [Section.0415] Description = Najpopularniejsza i jedna z najlepszych darmowych przeglądarek internetowych. Size = 7.8M URLSite = http://www.mozilla-europe.org/pl/ -URLDownload = http://releases.mozilla.org/pub/mozilla.org/firefox/releases/latest-3.0/win32/pl/Firefox%20Setup%203.0.17.exe +URLDownload = http://releases.mozilla.org/pub/mozilla.org/firefox/releases/latest-3.0/win32/pl/Firefox%20Setup%203.0.18.exe [Section.0419] Description = Один из самых популярных и лучших бесплатных браузеров. Size = 7.4M URLSite = http://www.mozilla-europe.org/ru/ -URLDownload = http://releases.mozilla.org/pub/mozilla.org/firefox/releases/latest-3.0/win32/ru/Firefox%20Setup%203.0.17.exe +URLDownload = http://releases.mozilla.org/pub/mozilla.org/firefox/releases/latest-3.0/win32/ru/Firefox%20Setup%203.0.18.exe diff --git a/base/applications/rapps/rapps/openoffice2.4.txt b/base/applications/rapps/rapps/openoffice2.4.txt index 81cae28edf9..d68f92e3418 100644 --- a/base/applications/rapps/rapps/openoffice2.4.txt +++ b/base/applications/rapps/rapps/openoffice2.4.txt @@ -8,23 +8,23 @@ Description = THE Open Source Office Suite. Size = 127MB Category = 6 URLSite = http://www.openoffice.org/ -URLDownload = http://ftp.plusline.de/OpenOffice/stable/2.4.3/OOo_2.4.3_Win32Intel_install_en-US.exe +URLDownload = ftp://archive.services.openoffice.org/pub/openoffice-archive/stable/2.4.3/OOo_2.4.3_Win32Intel_install_en-US.exe CDPath = none [Section.0407] Description = DIE Open Source Office Suite. URLSite = http://de.openoffice.org/ Size = 114.2MB -URLDownload = http://ftp.tu-chemnitz.de/pub/openoffice/localized/de/2.4.3/OOo_2.4.3_Win32Intel_install_de.exe +URLDownload = ftp://archive.services.openoffice.org/pub/openoffice-archive/localized/de/2.4.3/OOo_2.4.3_Win32Intel_install_de.exe [Section.040a] Description = La suite de ofimática de código abierto. URLSite = http://es.openoffice.org/ Size = 113.9MB -URLDownload = http://ftp.tu-chemnitz.de/pub/openoffice/localized/es/2.4.3/OOo_2.4.3_Win32Intel_install_es.exe +URLDownload = ftp://archive.services.openoffice.org/pub/openoffice-archive/localized/es/2.4.3/OOo_2.4.3_Win32Intel_install_es.exe [Section.0415] URLSite = http://pl.openoffice.org/ Description = Otwarty pakiet biurowy. -URLDownload = http://ftp.tu-chemnitz.de/pub/openoffice/localized/pl/2.4.2/OOo_2.4.2_Win32Intel_install_pl.exe +URLDownload = ftp://archive.services.openoffice.org/pub/openoffice-archive/localized/pl/2.4.2/OOo_2.4.2_Win32Intel_install_pl.exe Size = 113.9M diff --git a/base/applications/rapps/rapps/openoffice3.0.txt b/base/applications/rapps/rapps/openoffice3.0.txt index ebfc63ede1c..b9ee71bd025 100644 --- a/base/applications/rapps/rapps/openoffice3.0.txt +++ b/base/applications/rapps/rapps/openoffice3.0.txt @@ -2,30 +2,30 @@ [Section] Name = OpenOffice 3.0 -Version = 3.1.1 +Version = 3.2.0 Licence = LGPL Description = THE Open Source Office Suite. -Size = 134.3MB +Size = 135.4MB Category = 6 URLSite = http://www.openoffice.org/ -URLDownload = http://ftp.tu-chemnitz.de/pub/openoffice/stable/3.1.1/OOo_3.1.1_Win32Intel_install_en-US.exe +URLDownload = http://ftp.tu-chemnitz.de/pub/openoffice/stable/3.2.0/OOo_3.2.0_Win32Intel_install_en-US.exe CDPath = none [Section.0407] Description = DIE Open Source Office Suite. URLSite = http://de.openoffice.org/ -Size = 142.9MB -URLDownload = http://ftp.tu-chemnitz.de/pub/openoffice/localized/de/3.1.1/OOo_3.1.1_Win32Intel_install_de.exe +Size = 145.8MB +URLDownload = http://ftp.tu-chemnitz.de/pub/openoffice/localized/de/3.2.0/OOo_3.2.0_Win32Intel_install_de.exe [Section.040a] Description = La suite de ofimática de código abierto. URLSite = http://es.openoffice.org/ Version = 3.1.0 -Size = 130.0MB -URLDownload = http://ftp.tu-chemnitz.de/pub/openoffice/localized/es/3.1.0/OOo_3.1.0_Win32Intel_install_es.exe +Size = 119.4MB +URLDownload = http://ftp.tu-chemnitz.de/pub/openoffice/localized/es/3.2.0/OOo_3.2.0_Win32Intel_install_es.exe [Section.0415] Description = Otwarty pakiet biurowy. URLSite = http://pl.openoffice.org/ -Size = 147.1MB -URLDownload = http://ftp.tu-chemnitz.de/pub/openoffice/localized/pl/3.1.1/OOo_3.1.1_Win32Intel_install_pl.exe +Size = 133.2MB +URLDownload = http://ftp.tu-chemnitz.de/pub/openoffice/localized/pl/3.2.0/OOo_3.2.0_Win32Intel_install_pl.exe diff --git a/base/applications/rapps/rapps/scite.txt b/base/applications/rapps/rapps/scite.txt index 5e2562dacbe..fc3d9d50cca 100644 --- a/base/applications/rapps/rapps/scite.txt +++ b/base/applications/rapps/rapps/scite.txt @@ -2,13 +2,13 @@ [Section] Name = SciTE -Version = 2.02 +Version = 2.03 Licence = Freeware Description = SciTE is a SCIntilla based Text Editor. Originally built to demonstrate Scintilla, it has grown to be a generally useful editor with facilities for building and running programs. Size = 0.6M Category = 7 URLSite = http://www.scintilla.org/ -URLDownload = http://ovh.dl.sourceforge.net/sourceforge/scintilla/Sc202.exe +URLDownload = http://ovh.dl.sourceforge.net/sourceforge/scintilla/Sc203.exe CDPath = none [Section.0407] diff --git a/base/services/eventlog/eventlog.c b/base/services/eventlog/eventlog.c index 4f0120a662d..70663351ab5 100644 --- a/base/services/eventlog/eventlog.c +++ b/base/services/eventlog/eventlog.c @@ -21,20 +21,76 @@ static SERVICE_TABLE_ENTRYW ServiceTable[2] = { NULL, NULL } }; +SERVICE_STATUS ServiceStatus; +SERVICE_STATUS_HANDLE ServiceStatusHandle; + BOOL onLiveCD = FALSE; // On livecd events will go to debug output only HANDLE MyHeap = NULL; /* FUNCTIONS ****************************************************************/ +static VOID +UpdateServiceStatus(DWORD dwState) +{ + ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + ServiceStatus.dwCurrentState = dwState; + ServiceStatus.dwControlsAccepted = 0; + ServiceStatus.dwWin32ExitCode = 0; + ServiceStatus.dwServiceSpecificExitCode = 0; + ServiceStatus.dwCheckPoint = 0; + + if (dwState == SERVICE_START_PENDING || + dwState == SERVICE_STOP_PENDING || + dwState == SERVICE_PAUSE_PENDING || + dwState == SERVICE_CONTINUE_PENDING) + ServiceStatus.dwWaitHint = 10000; + else + ServiceStatus.dwWaitHint = 0; + + SetServiceStatus(ServiceStatusHandle, + &ServiceStatus); +} + static DWORD WINAPI ServiceControlHandler(DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext) { - /* FIXME */ - DPRINT1("ServiceControlHandler() called (control code %lu)\n", dwControl); - return ERROR_SUCCESS; + DPRINT("ServiceControlHandler() called\n"); + + switch (dwControl) + { + case SERVICE_CONTROL_STOP: + DPRINT(" SERVICE_CONTROL_STOP received\n"); + UpdateServiceStatus(SERVICE_STOPPED); + return ERROR_SUCCESS; + + case SERVICE_CONTROL_PAUSE: + DPRINT(" SERVICE_CONTROL_PAUSE received\n"); + UpdateServiceStatus(SERVICE_PAUSED); + return ERROR_SUCCESS; + + case SERVICE_CONTROL_CONTINUE: + DPRINT(" SERVICE_CONTROL_CONTINUE received\n"); + UpdateServiceStatus(SERVICE_RUNNING); + return ERROR_SUCCESS; + + case SERVICE_CONTROL_INTERROGATE: + DPRINT(" SERVICE_CONTROL_INTERROGATE received\n"); + SetServiceStatus(ServiceStatusHandle, + &ServiceStatus); + return ERROR_SUCCESS; + + case SERVICE_CONTROL_SHUTDOWN: + DPRINT(" SERVICE_CONTROL_SHUTDOWN received\n"); + UpdateServiceStatus(SERVICE_STOPPED); + return ERROR_SUCCESS; + + default : + DPRINT1(" Control %lu received\n"); + return ERROR_CALL_NOT_IMPLEMENTED; + } } @@ -83,8 +139,6 @@ static VOID CALLBACK ServiceMain(DWORD argc, LPWSTR *argv) { - SERVICE_STATUS ServiceStatus; - SERVICE_STATUS_HANDLE ServiceStatusHandle; DWORD dwError; UNREFERENCED_PARAMETER(argc); @@ -102,31 +156,20 @@ ServiceMain(DWORD argc, return; } - ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; - ServiceStatus.dwCurrentState = SERVICE_START_PENDING; - ServiceStatus.dwControlsAccepted = 0; - ServiceStatus.dwWin32ExitCode = NO_ERROR; - ServiceStatus.dwServiceSpecificExitCode = 0; - ServiceStatus.dwCheckPoint = 0; - ServiceStatus.dwWaitHint = 2000; - - SetServiceStatus(ServiceStatusHandle, - &ServiceStatus); + UpdateServiceStatus(SERVICE_START_PENDING); dwError = ServiceInit(); if (dwError != ERROR_SUCCESS) { - DPRINT1("Service stopped\n"); - ServiceStatus.dwCurrentState = SERVICE_STOPPED; + DPRINT("Service stopped (dwError: %lu\n", dwError); + UpdateServiceStatus(SERVICE_START_PENDING); } else { - ServiceStatus.dwCurrentState = SERVICE_RUNNING; + DPRINT("Service started\n"); + UpdateServiceStatus(SERVICE_RUNNING); } - SetServiceStatus(ServiceStatusHandle, - &ServiceStatus); - DPRINT("ServiceMain() done\n"); } diff --git a/base/services/eventlog/eventlog.h b/base/services/eventlog/eventlog.h index 4b9c6a8c341..df0ab151c41 100644 --- a/base/services/eventlog/eventlog.h +++ b/base/services/eventlog/eventlog.h @@ -44,7 +44,8 @@ typedef struct _IO_ERROR_LPC #define ELF_LOGFILE_ARCHIVE_SET 8 /* FIXME: MSDN reads that the following two structs are in winnt.h. Are they? */ -typedef struct _EVENTLOGHEADER { +typedef struct _EVENTLOGHEADER +{ ULONG HeaderSize; ULONG Signature; ULONG MajorVersion; @@ -59,7 +60,8 @@ typedef struct _EVENTLOGHEADER { ULONG EndHeaderSize; } EVENTLOGHEADER, *PEVENTLOGHEADER; -typedef struct _EVENTLOGEOF { +typedef struct _EVENTLOGEOF +{ ULONG RecordSizeBeginning; ULONG Ones; ULONG Twos; @@ -72,13 +74,13 @@ typedef struct _EVENTLOGEOF { ULONG RecordSizeEnd; } EVENTLOGEOF, *PEVENTLOGEOF; -typedef struct +typedef struct _EVENT_OFFSET_INFO { ULONG EventNumber; ULONG EventOffset; } EVENT_OFFSET_INFO, *PEVENT_OFFSET_INFO; -typedef struct +typedef struct _LOGFILE { HANDLE hFile; EVENTLOGHEADER Header; diff --git a/base/services/eventlog/rpc.c b/base/services/eventlog/rpc.c index e3ef33d1611..d399d1e600f 100644 --- a/base/services/eventlog/rpc.c +++ b/base/services/eventlog/rpc.c @@ -480,45 +480,29 @@ NTSTATUS ElfrOpenELA( DWORD MinorVersion, IELF_HANDLE *LogHandle) { - UNICODE_STRING UNCServerNameW = { 0, 0, NULL }; - UNICODE_STRING ModuleNameW = { 0, 0, NULL }; - UNICODE_STRING RegModuleNameW = { 0, 0, NULL }; - NTSTATUS Status; + UNICODE_STRING ModuleNameW; - if (UNCServerName && - !RtlCreateUnicodeStringFromAsciiz(&UNCServerNameW, UNCServerName)) - { - return STATUS_NO_MEMORY; - } + if ((MajorVersion != 1) || (MinorVersion != 1)) + return STATUS_INVALID_PARAMETER; - if (ModuleName && - !RtlAnsiStringToUnicodeString(&ModuleNameW, (PANSI_STRING)ModuleName, TRUE)) - { - RtlFreeUnicodeString(&UNCServerNameW); - return STATUS_NO_MEMORY; - } + /* RegModuleName must be an empty string */ + if (RegModuleName->Length > 0) + return STATUS_INVALID_PARAMETER; - if (RegModuleName && - !RtlAnsiStringToUnicodeString(&RegModuleNameW, (PANSI_STRING)RegModuleName, TRUE)) - { - RtlFreeUnicodeString(&UNCServerNameW); - RtlFreeUnicodeString(&ModuleNameW); - return STATUS_NO_MEMORY; - } + RtlAnsiStringToUnicodeString(&ModuleNameW, (PANSI_STRING)ModuleName, TRUE); - Status = ElfrOpenELW( - UNCServerName ? UNCServerNameW.Buffer : NULL, - ModuleName ? (PRPC_UNICODE_STRING)&ModuleNameW : NULL, - RegModuleName ? (PRPC_UNICODE_STRING)&RegModuleNameW : NULL, - MajorVersion, - MinorVersion, - LogHandle); + /* FIXME: Must verify that caller has read access */ + + *LogHandle = ElfCreateEventLogHandle(ModuleNameW.Buffer, FALSE); - RtlFreeUnicodeString(&UNCServerNameW); RtlFreeUnicodeString(&ModuleNameW); - RtlFreeUnicodeString(&RegModuleNameW); - return Status; + if (*LogHandle == NULL) + { + return STATUS_INVALID_PARAMETER; + } + + return STATUS_SUCCESS; } @@ -531,45 +515,32 @@ NTSTATUS ElfrRegisterEventSourceA( DWORD MinorVersion, IELF_HANDLE *LogHandle) { - UNICODE_STRING UNCServerNameW = { 0, 0, NULL }; UNICODE_STRING ModuleNameW = { 0, 0, NULL }; - if (UNCServerName && - !RtlCreateUnicodeStringFromAsciiz(&UNCServerNameW, UNCServerName)) - { - return STATUS_NO_MEMORY; - } - if (ModuleName && !RtlAnsiStringToUnicodeString(&ModuleNameW, (PANSI_STRING)ModuleName, TRUE)) { - RtlFreeUnicodeString(&UNCServerNameW); return STATUS_NO_MEMORY; } /* RegModuleName must be an empty string */ if (RegModuleName->Length > 0) { - RtlFreeUnicodeString(&UNCServerNameW); RtlFreeUnicodeString(&ModuleNameW); return STATUS_INVALID_PARAMETER; } if ((MajorVersion != 1) || (MinorVersion != 1)) { - RtlFreeUnicodeString(&UNCServerNameW); RtlFreeUnicodeString(&ModuleNameW); return STATUS_INVALID_PARAMETER; } - /*FIXME: UNCServerName must specify the server or empty for local */ - - /*FIXME: Must verify that caller has write access */ + /* FIXME: Must verify that caller has write access */ *LogHandle = ElfCreateEventLogHandle(ModuleNameW.Buffer, TRUE); - RtlFreeUnicodeString(&UNCServerNameW); RtlFreeUnicodeString(&ModuleNameW); return STATUS_SUCCESS; @@ -661,8 +632,32 @@ NTSTATUS ElfrGetLogInformation( DWORD cbBufSize, DWORD *pcbBytesNeeded) { - UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; + NTSTATUS Status = STATUS_SUCCESS; + + /* FIXME: check handle first */ + + switch (InfoLevel) + { + case EVENTLOG_FULL_INFO: + { + LPEVENTLOG_FULL_INFORMATION efi = (LPEVENTLOG_FULL_INFORMATION)Buffer; + + *pcbBytesNeeded = sizeof(EVENTLOG_FULL_INFORMATION); + if (cbBufSize < sizeof(EVENTLOG_FULL_INFORMATION)) + { + return STATUS_BUFFER_TOO_SMALL; + } + + efi->dwFull = 0; /* FIXME */ + } + break; + + default: + Status = STATUS_INVALID_LEVEL; + break; + } + + return Status; } diff --git a/baseaddress.rbuild b/baseaddress.rbuild index 6099bf8c332..cacc80f77f3 100644 --- a/baseaddress.rbuild +++ b/baseaddress.rbuild @@ -3,6 +3,7 @@ + diff --git a/boot/bootdata/packages/reactos.dff b/boot/bootdata/packages/reactos.dff index e5fb874f849..75db78068b1 100644 --- a/boot/bootdata/packages/reactos.dff +++ b/boot/bootdata/packages/reactos.dff @@ -286,6 +286,7 @@ dll\win32\dwmapi\dwmapi.dll 1 dll\win32\devmgr\devmgr.dll 1 dll\win32\dhcpcsvc\dhcpcsvc.dll 1 dll\win32\dnsapi\dnsapi.dll 1 +dll\win32\faultrep\faultrep.dll 1 dll\win32\fmifs\fmifs.dll 1 dll\win32\fusion\fusion.dll 1 dll\win32\gdi32\gdi32.dll 1 diff --git a/boot/freeldr/freeldr/windows/winldr.c b/boot/freeldr/freeldr/windows/winldr.c index 4ba7b1bcb29..f3f7cd199b7 100644 --- a/boot/freeldr/freeldr/windows/winldr.c +++ b/boot/freeldr/freeldr/windows/winldr.c @@ -232,7 +232,7 @@ WinLdrLoadDeviceDriver(PLOADER_PARAMETER_BLOCK LoaderBlock, PVOID DriverBase; // Separate the path to file name and directory path - sprintf(DriverPath, "%S", FilePath->Buffer); + snprintf(DriverPath, sizeof(DriverPath), "%wZ", FilePath); DriverNamePos = strrchr(DriverPath, '\\'); if (DriverNamePos != NULL) { @@ -261,7 +261,7 @@ WinLdrLoadDeviceDriver(PLOADER_PARAMETER_BLOCK LoaderBlock, } // It's not loaded, we have to load it - sprintf(FullPath,"%s%S", BootPath, FilePath->Buffer); + snprintf(FullPath, sizeof(FullPath), "%s%wZ", BootPath, FilePath); Status = WinLdrLoadImage(FullPath, LoaderBootDriver, &DriverBase); if (!Status) return FALSE; diff --git a/dll/directx/ksproxy/datatype.cpp b/dll/directx/ksproxy/datatype.cpp index 3d132890dfd..5006b68a121 100644 --- a/dll/directx/ksproxy/datatype.cpp +++ b/dll/directx/ksproxy/datatype.cpp @@ -42,12 +42,25 @@ public: HRESULT STDMETHODCALLTYPE KsQueryExtendedSize(OUT ULONG* ExtendedSize); HRESULT STDMETHODCALLTYPE KsSetMediaType(IN const AM_MEDIA_TYPE* AmMediaType); - CKsDataTypeHandler() : m_Ref(0){}; - virtual ~CKsDataTypeHandler(){}; + CKsDataTypeHandler() : m_Ref(0), m_Type(0){}; + virtual ~CKsDataTypeHandler() + { + if (m_Type) + { + if (m_Type->pbFormat) + CoTaskMemFree(m_Type->pbFormat); + + if (m_Type->pUnk) + m_Type->pUnk->Release(); + + CoTaskMemFree(m_Type); + } + + }; protected: - //CMediaType * m_Type; LONG m_Ref; + AM_MEDIA_TYPE * m_Type; }; @@ -85,8 +98,68 @@ STDMETHODCALLTYPE CKsDataTypeHandler::KsIsMediaTypeInRanges( IN PVOID DataRanges) { - OutputDebugString("UNIMPLEMENTED\n"); - return E_NOTIMPL; + PKSMULTIPLE_ITEM DataList; + PKSDATARANGE DataRange; + ULONG Index; + HRESULT hr = S_FALSE; + + OutputDebugStringW(L"CKsDataTypeHandler::KsIsMediaTypeInRanges\n"); + + DataList = (PKSMULTIPLE_ITEM)DataRanges; + DataRange = (PKSDATARANGE)(DataList + 1); + + for(Index = 0; Index < DataList->Count; Index++) + { + BOOL bMatch = FALSE; + + if (DataRange->FormatSize >= sizeof(KSDATARANGE)) + { + bMatch = IsEqualGUID(DataRange->MajorFormat, GUID_NULL); + } + + if (!bMatch && DataRange->FormatSize >= sizeof(KSDATARANGE_AUDIO)) + { + bMatch = IsEqualGUID(DataRange->MajorFormat, MEDIATYPE_Audio); + } + + if (bMatch) + { + if (IsEqualGUID(DataRange->SubFormat, m_Type->subtype) || + IsEqualGUID(DataRange->SubFormat, GUID_NULL)) + { + if (IsEqualGUID(DataRange->Specifier, m_Type->formattype) || + IsEqualGUID(DataRange->Specifier, GUID_NULL)) + { + if (!IsEqualGUID(m_Type->formattype, FORMAT_WaveFormatEx) && !IsEqualGUID(DataRange->Specifier, FORMAT_WaveFormatEx)) + { + //found match + hr = S_OK; + break; + } + + if (DataRange->FormatSize >= sizeof(KSDATARANGE_AUDIO) && m_Type->cbFormat >= sizeof(WAVEFORMATEX)) + { + LPWAVEFORMATEX Format = (LPWAVEFORMATEX)m_Type->pbFormat; + PKSDATARANGE_AUDIO AudioRange = (PKSDATARANGE_AUDIO)DataRange; + + if (Format->nSamplesPerSec >= AudioRange->MinimumSampleFrequency && + Format->nSamplesPerSec <= AudioRange->MaximumSampleFrequency && + Format->wBitsPerSample >= AudioRange->MinimumSampleFrequency && + Format->wBitsPerSample <= AudioRange->MaximumBitsPerSample && + Format->nChannels <= AudioRange->MaximumChannels) + { + // found match + hr = S_OK; + break; + } + } + } + } + } + + DataRange = (PKSDATARANGE)(((ULONG_PTR)DataRange + DataRange->FormatSize + 7) & ~7); + } + return S_OK; } HRESULT @@ -106,7 +179,6 @@ CKsDataTypeHandler::KsQueryExtendedSize( { /* no header extension required */ *ExtendedSize = 0; - return NOERROR; } @@ -115,19 +187,38 @@ STDMETHODCALLTYPE CKsDataTypeHandler::KsSetMediaType( IN const AM_MEDIA_TYPE* AmMediaType) { -#if 0 + OutputDebugString("CKsDataTypeHandler::KsSetMediaType\n"); + if (m_Type) { /* media type can only be set once */ return E_FAIL; } -#endif - /* - * TODO: allocate CMediaType and copy parameters - */ - OutputDebugString("UNIMPLEMENTED\n"); - return E_NOTIMPL; + m_Type = (AM_MEDIA_TYPE*)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)); + if (!m_Type) + return E_OUTOFMEMORY; + + CopyMemory(m_Type, AmMediaType, sizeof(AM_MEDIA_TYPE)); + + if (m_Type->cbFormat) + { + m_Type->pbFormat = (BYTE*)CoTaskMemAlloc(m_Type->cbFormat); + + if (!m_Type->pbFormat) + { + CoTaskMemFree(m_Type); + return E_OUTOFMEMORY; + } + + CopyMemory(m_Type->pbFormat, AmMediaType->pbFormat, m_Type->cbFormat); + } + + if (m_Type->pUnk) + m_Type->pUnk->AddRef(); + + + return S_OK; } HRESULT @@ -138,7 +229,6 @@ CKsDataTypeHandler_Constructor ( LPVOID * ppv) { OutputDebugStringW(L"CKsDataTypeHandler_Constructor\n"); - CKsDataTypeHandler * handler = new CKsDataTypeHandler(); if (!handler) diff --git a/dll/directx/ksproxy/input_pin.cpp b/dll/directx/ksproxy/input_pin.cpp index ce2cef4600d..e95894f4efa 100644 --- a/dll/directx/ksproxy/input_pin.cpp +++ b/dll/directx/ksproxy/input_pin.cpp @@ -1,20 +1,21 @@ /* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS WDM Streaming ActiveMovie Proxy - * FILE: dll/directx/ksproxy/input_cpp.cpp + * FILE: dll/directx/ksproxy/input_pin.cpp * PURPOSE: InputPin of Proxy Filter * * PROGRAMMERS: Johannes Anderwald (janderwald@reactos.org) */ #include "precomp.h" -const GUID IID_IKsPinEx = {0x7bb38260L, 0xd19c, 0x11d2, {0xb3, 0x8a, 0x00, 0xa0, 0xc9, 0x5e, 0xc2, 0x2e}}; +const GUID IID_IKsPinPipe = {0xe539cd90, 0xa8b4, 0x11d1, {0x81, 0x89, 0x00, 0xa0, 0xc9, 0x06, 0x28, 0x02}}; +const GUID IID_IKsPinEx = {0x7bb38260L, 0xd19c, 0x11d2, {0xb3, 0x8a, 0x00, 0xa0, 0xc9, 0x5e, 0xc2, 0x2e}}; + #ifndef _MSC_VER + const GUID KSPROPSETID_Connection = {0x1D58C920L, 0xAC9B, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}}; -#endif -#ifndef _MSC_VER KSPIN_INTERFACE StandardPinInterface = { {STATIC_KSINTERFACESETID_Standard}, @@ -52,15 +53,13 @@ class CInputPin : public IPin, public IKsControl, public IKsObject, public IKsPinEx, - public IMemInputPin -/* - public IQualityControl, + public IMemInputPin, public IKsPinPipe, - public ISpecifyPropertyPages, - public IStreamBuilder, public IKsPinFactory, - public IKsAggregateControl -*/ + public IStreamBuilder, + public IKsAggregateControl, + public IQualityControl, + public ISpecifyPropertyPages { public: STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface); @@ -81,6 +80,19 @@ public: return m_Ref; } + //IKsPinPipe + HRESULT STDMETHODCALLTYPE KsGetPinFramingCache(PKSALLOCATOR_FRAMING_EX *FramingEx, PFRAMING_PROP FramingProp, FRAMING_CACHE_OPS Option); + HRESULT STDMETHODCALLTYPE KsSetPinFramingCache(PKSALLOCATOR_FRAMING_EX FramingEx, PFRAMING_PROP FramingProp, FRAMING_CACHE_OPS Option); + IPin* STDMETHODCALLTYPE KsGetConnectedPin(); + IKsAllocatorEx* STDMETHODCALLTYPE KsGetPipe(KSPEEKOPERATION Operation); + HRESULT STDMETHODCALLTYPE KsSetPipe(IKsAllocatorEx *KsAllocator); + ULONG STDMETHODCALLTYPE KsGetPipeAllocatorFlag(); + HRESULT STDMETHODCALLTYPE KsSetPipeAllocatorFlag(ULONG Flag); + GUID STDMETHODCALLTYPE KsGetPinBusCache(); + HRESULT STDMETHODCALLTYPE KsSetPinBusCache(GUID Bus); + PWCHAR STDMETHODCALLTYPE KsGetPinName(); + PWCHAR STDMETHODCALLTYPE KsGetFilterName(); + //IPin methods HRESULT STDMETHODCALLTYPE Connect(IPin *pReceivePin, const AM_MEDIA_TYPE *pmt); HRESULT STDMETHODCALLTYPE ReceiveConnection(IPin *pConnector, const AM_MEDIA_TYPE *pmt); @@ -98,6 +110,9 @@ public: HRESULT STDMETHODCALLTYPE EndFlush(); HRESULT STDMETHODCALLTYPE NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); + // ISpecifyPropertyPages + HRESULT STDMETHODCALLTYPE GetPages(CAUUID *pPages); + //IKsObject methods HANDLE STDMETHODCALLTYPE KsGetObjectHandle(); @@ -136,11 +151,26 @@ public: HRESULT STDMETHODCALLTYPE ReceiveMultiple(IMediaSample **pSamples, long nSamples, long *nSamplesProcessed); HRESULT STDMETHODCALLTYPE ReceiveCanBlock( void); + //IKsPinFactory + HRESULT STDMETHODCALLTYPE KsPinFactory(ULONG* PinFactory); + + //IStreamBuilder + HRESULT STDMETHODCALLTYPE Render(IPin *ppinOut, IGraphBuilder *pGraph); + HRESULT STDMETHODCALLTYPE Backout(IPin *ppinOut, IGraphBuilder *pGraph); + + //IKsAggregateControl + HRESULT STDMETHODCALLTYPE KsAddAggregate(IN REFGUID AggregateClass); + HRESULT STDMETHODCALLTYPE KsRemoveAggregate(REFGUID AggregateClass); + + //IQualityControl + HRESULT STDMETHODCALLTYPE Notify(IBaseFilter *pSelf, Quality q); + HRESULT STDMETHODCALLTYPE SetSink(IQualityControl *piqc); + //--------------------------------------------------------------- HRESULT STDMETHODCALLTYPE CheckFormat(const AM_MEDIA_TYPE *pmt); HRESULT STDMETHODCALLTYPE CreatePin(const AM_MEDIA_TYPE *pmt); HRESULT STDMETHODCALLTYPE CreatePinHandle(PKSPIN_MEDIUM Medium, PKSPIN_INTERFACE Interface, const AM_MEDIA_TYPE *pmt); - CInputPin(IBaseFilter * ParentFilter, LPCWSTR PinName, HANDLE hFilter, ULONG PinId, KSPIN_COMMUNICATION Communication) : m_Ref(0), m_ParentFilter(ParentFilter), m_PinName(PinName), m_hFilter(hFilter), m_hPin(0), m_PinId(PinId), m_MemAllocator(0), m_IoCount(0), m_Communication(Communication), m_Pin(0), m_ReadOnly(0){}; + CInputPin(IBaseFilter * ParentFilter, LPCWSTR PinName, HANDLE hFilter, ULONG PinId, KSPIN_COMMUNICATION Communication); virtual ~CInputPin(){}; protected: @@ -157,8 +187,42 @@ protected: KSPIN_MEDIUM m_Medium; IPin * m_Pin; BOOL m_ReadOnly; + IKsInterfaceHandler * m_InterfaceHandler; + IKsAllocatorEx * m_KsAllocatorEx; + ULONG m_PipeAllocatorFlag; + BOOL m_bPinBusCacheInitialized; + GUID m_PinBusCache; + LPWSTR m_FilterName; + FRAMING_PROP m_FramingProp[4]; + PKSALLOCATOR_FRAMING_EX m_FramingEx[4]; }; +CInputPin::CInputPin( + IBaseFilter * ParentFilter, + LPCWSTR PinName, + HANDLE hFilter, + ULONG PinId, + KSPIN_COMMUNICATION Communication) : m_Ref(0), + m_ParentFilter(ParentFilter), + m_PinName(PinName), + m_hFilter(hFilter), + m_hPin(INVALID_HANDLE_VALUE), + m_PinId(PinId), + m_MemAllocator(0), + m_IoCount(0), + m_Communication(Communication), + m_Pin(0), + m_ReadOnly(0), + m_InterfaceHandler(0), + m_KsAllocatorEx(0), + m_PipeAllocatorFlag(0), + m_bPinBusCacheInitialized(0), + m_FilterName(0) +{ + ZeroMemory(m_FramingProp, sizeof(m_FramingProp)); + ZeroMemory(m_FramingEx, sizeof(m_FramingEx)); +} + HRESULT STDMETHODCALLTYPE CInputPin::QueryInterface( @@ -205,7 +269,44 @@ CInputPin::QueryInterface( reinterpret_cast(*Output)->AddRef(); return NOERROR; } - + else if (IsEqualGUID(refiid, IID_IKsPinPipe)) + { + *Output = (IKsPinPipe*)(this); + reinterpret_cast(*Output)->AddRef(); + return NOERROR; + } + else if (IsEqualGUID(refiid, IID_IKsPinFactory)) + { + *Output = (IKsPinFactory*)(this); + reinterpret_cast(*Output)->AddRef(); + return NOERROR; + } +#if 0 + else if (IsEqualGUID(refiid, IID_IStreamBuilder)) + { + *Output = (IStreamBuilder*)(this); + reinterpret_cast(*Output)->AddRef(); + return NOERROR; + } +#endif + else if (IsEqualGUID(refiid, IID_IKsAggregateControl)) + { + *Output = (IKsAggregateControl*)(this); + reinterpret_cast(*Output)->AddRef(); + return NOERROR; + } + else if (IsEqualGUID(refiid, IID_IQualityControl)) + { + *Output = (IQualityControl*)(this); + reinterpret_cast(*Output)->AddRef(); + return NOERROR; + } + else if (IsEqualGUID(refiid, IID_ISpecifyPropertyPages)) + { + *Output = (ISpecifyPropertyPages*)(this); + reinterpret_cast(*Output)->AddRef(); + return NOERROR; + } WCHAR Buffer[MAX_PATH]; LPOLESTR lpstr; @@ -216,6 +317,249 @@ CInputPin::QueryInterface( return E_NOINTERFACE; } +//------------------------------------------------------------------- +// IQualityControl interface +// +HRESULT +STDMETHODCALLTYPE +CInputPin::Notify( + IBaseFilter *pSelf, + Quality q) +{ + OutputDebugStringW(L"CInputPin::Notify NotImplemented\n"); + return E_NOTIMPL; +} + +HRESULT +STDMETHODCALLTYPE +CInputPin::SetSink( + IQualityControl *piqc) +{ + OutputDebugStringW(L"CInputPin::SetSink NotImplemented\n"); + return E_NOTIMPL; +} + + +//------------------------------------------------------------------- +// IKsAggregateControl interface +// +HRESULT +STDMETHODCALLTYPE +CInputPin::KsAddAggregate( + IN REFGUID AggregateClass) +{ + OutputDebugStringW(L"CInputPin::KsAddAggregate NotImplemented\n"); + return E_NOTIMPL; +} + +HRESULT +STDMETHODCALLTYPE +CInputPin::KsRemoveAggregate( + REFGUID AggregateClass) +{ + OutputDebugStringW(L"CInputPin::KsRemoveAggregate NotImplemented\n"); + return E_NOTIMPL; +} + +//------------------------------------------------------------------- +// IStreamBuilder +// + +HRESULT +STDMETHODCALLTYPE +CInputPin::Render( + IPin *ppinOut, + IGraphBuilder *pGraph) +{ + OutputDebugStringW(L"CInputPin::Render\n"); + return S_OK; +} + +HRESULT +STDMETHODCALLTYPE +CInputPin::Backout( + IPin *ppinOut, + IGraphBuilder *pGraph) +{ + OutputDebugStringW(L"CInputPin::Backout\n"); + return S_OK; +} + +//------------------------------------------------------------------- +// IKsPinFactory +// + +HRESULT +STDMETHODCALLTYPE +CInputPin::KsPinFactory( + ULONG* PinFactory) +{ + OutputDebugStringW(L"CInputPin::KsPinFactory\n"); + *PinFactory = m_PinId; + return S_OK; +} + +//------------------------------------------------------------------- +// IKsPinPipe +// + +HRESULT +STDMETHODCALLTYPE +CInputPin::KsGetPinFramingCache( + PKSALLOCATOR_FRAMING_EX *FramingEx, + PFRAMING_PROP FramingProp, + FRAMING_CACHE_OPS Option) +{ + if (Option > Framing_Cache_Write || Option < Framing_Cache_ReadLast) + { + // invalid argument + return E_INVALIDARG; + } + + // get framing properties + *FramingProp = m_FramingProp[Option]; + *FramingEx = m_FramingEx[Option]; + + return NOERROR; +} + +HRESULT +STDMETHODCALLTYPE +CInputPin::KsSetPinFramingCache( + PKSALLOCATOR_FRAMING_EX FramingEx, + PFRAMING_PROP FramingProp, + FRAMING_CACHE_OPS Option) +{ + ULONG Index; + ULONG RefCount = 0; + + if (m_FramingEx[Option]) + { + for(Index = 1; Index < 4; Index++) + { + if (m_FramingEx[Index] == m_FramingEx[Option]) + RefCount++; + } + + if (RefCount == 1) + { + // existing framing is only used once + CoTaskMemFree(m_FramingEx[Option]); + } + } + + // store framing + m_FramingEx[Option] = FramingEx; + m_FramingProp[Option] = *FramingProp; + + return S_OK; +} + +IPin* +STDMETHODCALLTYPE +CInputPin::KsGetConnectedPin() +{ + return m_Pin; +} + +IKsAllocatorEx* +STDMETHODCALLTYPE +CInputPin::KsGetPipe( + KSPEEKOPERATION Operation) +{ + if (Operation == KsPeekOperation_AddRef) + { + if (m_KsAllocatorEx) + m_KsAllocatorEx->AddRef(); + } + return m_KsAllocatorEx; +} + +HRESULT +STDMETHODCALLTYPE +CInputPin::KsSetPipe( + IKsAllocatorEx *KsAllocator) +{ + if (KsAllocator) + KsAllocator->AddRef(); + + if (m_KsAllocatorEx) + m_KsAllocatorEx->Release(); + + m_KsAllocatorEx = KsAllocator; + return NOERROR; +} + +ULONG +STDMETHODCALLTYPE +CInputPin::KsGetPipeAllocatorFlag() +{ + return m_PipeAllocatorFlag; +} + + +HRESULT +STDMETHODCALLTYPE +CInputPin::KsSetPipeAllocatorFlag( + ULONG Flag) +{ + m_PipeAllocatorFlag = Flag; + return NOERROR; +} + +GUID +STDMETHODCALLTYPE +CInputPin::KsGetPinBusCache() +{ + if (!m_bPinBusCacheInitialized) + { + CopyMemory(&m_PinBusCache, &m_Medium.Set, sizeof(GUID)); + m_bPinBusCacheInitialized = TRUE; + } + + return m_PinBusCache; +} + +HRESULT +STDMETHODCALLTYPE +CInputPin::KsSetPinBusCache( + GUID Bus) +{ + CopyMemory(&m_PinBusCache, &Bus, sizeof(GUID)); + return NOERROR; +} + +PWCHAR +STDMETHODCALLTYPE +CInputPin::KsGetPinName() +{ + return (PWCHAR)m_PinName; +} + + +PWCHAR +STDMETHODCALLTYPE +CInputPin::KsGetFilterName() +{ + return m_FilterName; +} + +//------------------------------------------------------------------- +// ISpecifyPropertyPages +// + +HRESULT +STDMETHODCALLTYPE +CInputPin::GetPages(CAUUID *pPages) +{ + if (!pPages) + return E_POINTER; + + pPages->cElems = 0; + pPages->pElems = NULL; + + return S_OK; +} //------------------------------------------------------------------- // IMemInputPin @@ -299,7 +643,6 @@ CInputPin::ReceiveCanBlock( void) return S_FALSE; } - //------------------------------------------------------------------- // IKsPin // @@ -641,16 +984,17 @@ CInputPin::ReceiveConnection(IPin *pConnector, const AM_MEDIA_TYPE *pmt) if (m_Pin) { + // already connected return VFW_E_ALREADY_CONNECTED; } // first check format hr = CheckFormat(pmt); if (FAILED(hr)) + { + // format is not supported return hr; - - if (FAILED(CheckFormat(pmt))) - return hr; + } hr = CreatePin(pmt); if (FAILED(hr)) @@ -658,9 +1002,8 @@ CInputPin::ReceiveConnection(IPin *pConnector, const AM_MEDIA_TYPE *pmt) return hr; } - //FIXME create pin - m_Pin = pConnector; - m_Pin->AddRef(); + m_Pin = pConnector; + m_Pin->AddRef(); return S_OK; } @@ -828,6 +1171,7 @@ CInputPin::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) return E_NOTIMPL; } + //------------------------------------------------------------------- HRESULT STDMETHODCALLTYPE @@ -900,6 +1244,7 @@ CInputPin::CreatePin( PKSMULTIPLE_ITEM InterfaceList; PKSPIN_MEDIUM Medium; PKSPIN_INTERFACE Interface; + IKsInterfaceHandler * InterfaceHandler; HRESULT hr; // query for pin medium @@ -938,8 +1283,43 @@ CInputPin::CreatePin( Interface = &StandardPinInterface; } - // now create pin - hr = CreatePinHandle(Medium, Interface, pmt); + if (m_Communication != KSPIN_COMMUNICATION_BRIDGE && m_Communication != KSPIN_COMMUNICATION_NONE) + { + // now load the IKsInterfaceHandler plugin + hr = CoCreateInstance(Interface->Set, NULL, CLSCTX_INPROC_SERVER, IID_IKsInterfaceHandler, (void**)&InterfaceHandler); + if (FAILED(hr)) + { + // failed to load interface handler plugin + OutputDebugStringW(L"CInputPin::CreatePin failed to load InterfaceHandlerPlugin\n"); + CoTaskMemFree(MediumList); + CoTaskMemFree(InterfaceList); + + return hr; + } + + // now set the pin + hr = InterfaceHandler->KsSetPin((IKsPin*)this); + if (FAILED(hr)) + { + // failed to load interface handler plugin + OutputDebugStringW(L"CInputPin::CreatePin failed to initialize InterfaceHandlerPlugin\n"); + InterfaceHandler->Release(); + CoTaskMemFree(MediumList); + CoTaskMemFree(InterfaceList); + return hr; + } + + // store interface handler + m_InterfaceHandler = InterfaceHandler; + + // now create pin + hr = CreatePinHandle(Medium, Interface, pmt); + if (FAILED(hr)) + { + m_InterfaceHandler->Release(); + m_InterfaceHandler = InterfaceHandler; + } + } // free medium / interface / dataformat CoTaskMemFree(MediumList); diff --git a/dll/directx/ksproxy/interface.cpp b/dll/directx/ksproxy/interface.cpp index 4289cd1fc11..930f7e00b73 100644 --- a/dll/directx/ksproxy/interface.cpp +++ b/dll/directx/ksproxy/interface.cpp @@ -35,14 +35,27 @@ public: HRESULT STDMETHODCALLTYPE KsProcessMediaSamples(IKsDataTypeHandler *KsDataTypeHandler, IMediaSample** SampleList, PLONG SampleCount, KSIOOPERATION IoOperation, PKSSTREAM_SEGMENT *StreamSegment); HRESULT STDMETHODCALLTYPE KsCompleteIo(PKSSTREAM_SEGMENT StreamSegment); - CKsInterfaceHandler() : m_Ref(0), m_Handle(NULL){}; + CKsInterfaceHandler() : m_Ref(0), m_Handle(NULL), m_Pin(0){}; virtual ~CKsInterfaceHandler(){}; protected: LONG m_Ref; HANDLE m_Handle; + IKsPinEx * m_Pin; }; +typedef struct +{ + KSSTREAM_SEGMENT StreamSegment; + IMediaSample * MediaSample[64]; + + ULONG SampleCount; + ULONG ExtendedSize; + PKSSTREAM_HEADER StreamHeader; + OVERLAPPED Overlapped; +}KSSTREAM_SEGMENT_EXT, *PKSSTREAM_SEGMENT_EXT; + + HRESULT STDMETHODCALLTYPE CKsInterfaceHandler::QueryInterface( @@ -66,22 +79,43 @@ CKsInterfaceHandler::KsSetPin( { HRESULT hr; IKsObject * KsObject; + IKsPinEx * Pin; - // check if IKsObject is supported - hr = KsPin->QueryInterface(IID_IKsObject, (void**)&KsObject); - + // get IKsPinEx interface + hr = KsPin->QueryInterface(IID_IKsPinEx, (void**)&Pin); if (SUCCEEDED(hr)) { - // get pin handle - m_Handle = KsObject->KsGetObjectHandle(); + // check if IKsObject is supported + hr = KsPin->QueryInterface(IID_IKsObject, (void**)&KsObject); - // release IKsObject interface - KsObject->Release(); - - if (!m_Handle) + if (SUCCEEDED(hr)) { - // expected a file handle - return E_UNEXPECTED; + // get pin handle + m_Handle = KsObject->KsGetObjectHandle(); + + // release IKsObject interface + KsObject->Release(); + + if (!m_Handle) + { + // expected a file handle + hr = E_UNEXPECTED; + Pin->Release(); + } + else + { + if (m_Pin) + { + // release old interface + m_Pin->Release(); + } + m_Pin = Pin; + } + } + else + { + //release IKsPinEx interface + Pin->Release(); } } @@ -96,19 +130,330 @@ CKsInterfaceHandler::KsProcessMediaSamples( IMediaSample** SampleList, PLONG SampleCount, KSIOOPERATION IoOperation, - PKSSTREAM_SEGMENT *StreamSegment) + PKSSTREAM_SEGMENT *OutStreamSegment) { - OutputDebugString("UNIMPLEMENTED\n"); - return E_NOTIMPL; + PKSSTREAM_SEGMENT_EXT StreamSegment; + ULONG ExtendedSize, Index, BytesReturned; + HRESULT hr = S_OK; + + OutputDebugString("CKsInterfaceHandler::KsProcessMediaSamples\n"); + + // sanity check + assert(*SampleCount); + + if (*SampleCount == 0 || *SampleCount < 0) + return E_FAIL; + + // zero stream segment + *OutStreamSegment = NULL; + + // allocate stream segment + StreamSegment = (PKSSTREAM_SEGMENT_EXT)CoTaskMemAlloc(sizeof(KSSTREAM_SEGMENT_EXT)); + if (!StreamSegment) + return E_OUTOFMEMORY; + + // zero stream segment + ZeroMemory(StreamSegment, sizeof(KSSTREAM_SEGMENT_EXT)); + + //allocate event + StreamSegment->StreamSegment.CompletionEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + if (!StreamSegment->StreamSegment.CompletionEvent) + { + // failed to create event + CoTaskMemFree(StreamSegment); + return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError()); + } + + // increase our own reference count + AddRef(); + + // setup stream segment + StreamSegment->StreamSegment.KsDataTypeHandler = KsDataTypeHandler; + StreamSegment->StreamSegment.KsInterfaceHandler = (IKsInterfaceHandler*)this; + StreamSegment->StreamSegment.IoOperation = IoOperation; + StreamSegment->Overlapped.hEvent = StreamSegment->StreamSegment.CompletionEvent; + + + // ge extension size + ExtendedSize = 0; + if (KsDataTypeHandler) + { + // query extension size + KsDataTypeHandler->KsQueryExtendedSize(&ExtendedSize); + + if (ExtendedSize) + { + // increment reference count + KsDataTypeHandler->AddRef(); + } + else + { + // no need for the datatype handler + StreamSegment->StreamSegment.KsDataTypeHandler = NULL; + } + } + + StreamSegment->ExtendedSize = ExtendedSize; + StreamSegment->SampleCount = (ULONG)*SampleCount; + + // calculate stream header size count + ULONG StreamHeaderSize = StreamSegment->SampleCount * (sizeof(KSSTREAM_HEADER) + ExtendedSize); + + // allocate stream header + StreamSegment->StreamHeader = (PKSSTREAM_HEADER)CoTaskMemAlloc(StreamHeaderSize); + if (!StreamSegment->StreamHeader) + { + // not enough memory + CloseHandle(StreamSegment->StreamSegment.CompletionEvent); + + if (StreamSegment->StreamSegment.KsDataTypeHandler) + StreamSegment->StreamSegment.KsDataTypeHandler->Release(); + + // free stream segment + CoTaskMemFree(StreamSegment); + + //release our reference count + Release(); + return E_OUTOFMEMORY; + } + + // zero stream headers + ZeroMemory(StreamSegment->StreamHeader, StreamHeaderSize); + + PKSSTREAM_HEADER CurStreamHeader = StreamSegment->StreamHeader; + + // initialize all stream headers + for(Index = 0; Index < StreamSegment->SampleCount; Index++) + { + if (ExtendedSize) + { + // initialize extended size + hr = KsDataTypeHandler->KsPrepareIoOperation(SampleList[Index], (CurStreamHeader + 1), IoOperation); + // sanity check + assert(hr == NOERROR); + } + + // query for IMediaSample2 interface + IMediaSample2 * MediaSample; + AM_SAMPLE2_PROPERTIES Properties; + + hr = SampleList[Index]->QueryInterface(IID_IMediaSample2, (void**)&MediaSample); + if (SUCCEEDED(hr)) + { + //get properties + + hr = MediaSample->GetProperties(sizeof(AM_SAMPLE2_PROPERTIES), (BYTE*)&Properties); + + //release IMediaSample2 interface + MediaSample->Release(); + } + else + { + // get properties + hr = SampleList[Index]->GetPointer((BYTE**)&Properties.pbBuffer); + assert(hr == NOERROR); + hr = SampleList[Index]->GetTime(&Properties.tStart, &Properties.tStop); + assert(hr == NOERROR); + + Properties.dwSampleFlags = 0; + + if (SampleList[Index]->IsDiscontinuity() == S_OK) + Properties.dwSampleFlags |= AM_SAMPLE_DATADISCONTINUITY; + + if (SampleList[Index]->IsPreroll() == S_OK) + Properties.dwSampleFlags |= AM_SAMPLE_PREROLL; + + if (SampleList[Index]->IsSyncPoint() == S_OK) + Properties.dwSampleFlags |= AM_SAMPLE_SPLICEPOINT; + } + + WCHAR Buffer[100]; + swprintf(Buffer, L"BufferLength %lu Property Buffer %p ExtendedSize %u lActual %u\n", Properties.cbBuffer, Properties.pbBuffer, ExtendedSize, Properties.lActual); + OutputDebugStringW(Buffer); + + CurStreamHeader->Size = sizeof(KSSTREAM_HEADER) + ExtendedSize; + CurStreamHeader->PresentationTime.Denominator = 1; + CurStreamHeader->PresentationTime.Numerator = 1; + CurStreamHeader->FrameExtent = Properties.cbBuffer; + CurStreamHeader->Data = Properties.pbBuffer; + + if (IoOperation == KsIoOperation_Write) + { + // set flags + CurStreamHeader->OptionsFlags = Properties.dwSampleFlags; + CurStreamHeader->DataUsed = Properties.lActual; + // increment reference count + SampleList[Index]->AddRef(); + } + + // store sample in stream segment + StreamSegment->MediaSample[Index] = SampleList[Index]; + + // move to next header + CurStreamHeader = (PKSSTREAM_HEADER)((ULONG_PTR)CurStreamHeader + CurStreamHeader->Size); + } + + // submit to device + m_Pin->KsIncrementPendingIoCount(); + + if (DeviceIoControl(m_Handle, + IoOperation == KsIoOperation_Write ? IOCTL_KS_WRITE_STREAM : IOCTL_KS_READ_STREAM, + NULL, 0, + StreamSegment->StreamHeader, + StreamHeaderSize, + &BytesReturned, + &StreamSegment->Overlapped)) + { + // signal completion + SetEvent(StreamSegment->StreamSegment.CompletionEvent); + hr = S_OK; + *OutStreamSegment = (PKSSTREAM_SEGMENT)StreamSegment; + } + else + { + if (GetLastError() == ERROR_IO_PENDING) + { + *OutStreamSegment = (PKSSTREAM_SEGMENT)StreamSegment; + hr = S_OK; + } + } + return hr; } HRESULT STDMETHODCALLTYPE CKsInterfaceHandler::KsCompleteIo( - PKSSTREAM_SEGMENT StreamSegment) + PKSSTREAM_SEGMENT InStreamSegment) { - OutputDebugString("UNIMPLEMENTED\n"); - return E_NOTIMPL; + PKSSTREAM_SEGMENT_EXT StreamSegment; + PKSSTREAM_HEADER CurStreamHeader; + DWORD dwError = ERROR_SUCCESS, BytesReturned; + BOOL bOverlapped; + ULONG Index; + HRESULT hr; + IMediaSample2 * MediaSample; + AM_SAMPLE2_PROPERTIES Properties; + REFERENCE_TIME Start, Stop; + + OutputDebugStringW(L"CKsInterfaceHandler::KsCompleteIo\n"); + + // get private stream segment + StreamSegment = (PKSSTREAM_SEGMENT_EXT)InStreamSegment; + + // get result + bOverlapped = GetOverlappedResult(m_Handle, &StreamSegment->Overlapped, &BytesReturned, FALSE); + dwError = GetLastError(); + + CurStreamHeader = StreamSegment->StreamHeader; + + //iterate through all stream headers + for(Index = 0; Index < StreamSegment->SampleCount; Index++) + { + if (!bOverlapped) + { + // operation failed + m_Pin->KsNotifyError(StreamSegment->MediaSample[Index], MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwError)); + } + + // query IMediaSample2 interface + hr = StreamSegment->MediaSample[Index]->QueryInterface(IID_IMediaSample2, (void**)&MediaSample); + if (SUCCEEDED(hr)) + { + // media sample properties + hr = MediaSample->GetProperties(sizeof(AM_SAMPLE2_PROPERTIES), (BYTE*)&Properties); + if (SUCCEEDED(hr)) + { + //update media sample properties + Properties.dwTypeSpecificFlags = CurStreamHeader->TypeSpecificFlags; + Properties.dwSampleFlags |= (CurStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_TIMEDISCONTINUITY); + + MediaSample->SetProperties(sizeof(AM_SAMPLE2_PROPERTIES), (BYTE*)&Properties); + } + // release IMediaSample2 interface + MediaSample->Release(); + } + + // was an extended header used + if (StreamSegment->ExtendedSize) + { + // unprepare stream header extension + StreamSegment->StreamSegment.KsDataTypeHandler->KsCompleteIoOperation(StreamSegment->MediaSample[Index], (CurStreamHeader + 1), StreamSegment->StreamSegment.IoOperation, bOverlapped == FALSE); + } + + Start = 0; + Stop = 0; + if (bOverlapped && StreamSegment->StreamSegment.IoOperation == KsIoOperation_Read) + { + // update common media sample details + StreamSegment->MediaSample[Index]->SetSyncPoint((CurStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_SPLICEPOINT)); + StreamSegment->MediaSample[Index]->SetPreroll((CurStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_PREROLL)); + StreamSegment->MediaSample[Index]->SetDiscontinuity((CurStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY)); + + if (CurStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_TIMEVALID) + { + // use valid timestamp + Start = CurStreamHeader->PresentationTime.Time; + + if (CurStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_DURATIONVALID) + { + Stop = CurStreamHeader->PresentationTime.Time + CurStreamHeader->Duration; + } + } + } + + // now set time + hr = StreamSegment->MediaSample[Index]->SetTime(&Start, &Stop); + if (FAILED(hr)) + { + // use start time + StreamSegment->MediaSample[Index]->SetTime(&Start, &Start); + } + + // set valid data length + StreamSegment->MediaSample[Index]->SetActualDataLength(CurStreamHeader->DataUsed); + + if (StreamSegment->StreamSegment.IoOperation == KsIoOperation_Read) + { + if (bOverlapped) + { + // deliver sample + m_Pin->KsDeliver(StreamSegment->MediaSample[Index], CurStreamHeader->OptionsFlags); + } + } + else if (StreamSegment->StreamSegment.IoOperation == KsIoOperation_Write) + { + // release media sample reference + StreamSegment->MediaSample[Index]->Release(); + } + + CurStreamHeader = (PKSSTREAM_HEADER)((ULONG_PTR)CurStreamHeader + CurStreamHeader->Size); + } + + // delete stream headers + CoTaskMemFree(StreamSegment->StreamHeader); + + if (StreamSegment->StreamSegment.KsDataTypeHandler) + { + // release reference + StreamSegment->StreamSegment.KsDataTypeHandler->Release(); + } + + // decrement pending i/o count + m_Pin->KsDecrementPendingIoCount(); + + //notify of completion + m_Pin->KsMediaSamplesCompleted(InStreamSegment); + + //destroy stream segment + CoTaskMemFree(StreamSegment); + + //release reference to ourselves + Release(); + + // done + // Event handle is closed by caller + return S_OK; } HRESULT diff --git a/dll/directx/ksproxy/ksproxy.cpp b/dll/directx/ksproxy/ksproxy.cpp index 237b0390427..f79a154574b 100644 --- a/dll/directx/ksproxy/ksproxy.cpp +++ b/dll/directx/ksproxy/ksproxy.cpp @@ -13,10 +13,10 @@ const GUID CLSID_KsClockForwarder = {0x877e4351, 0x6fea, 0x11d0, {0xb8, 0x63, 0x00, 0xaa, 0x00, 0xa2, 0x16, 0xa1}}; const GUID CLSID_KsQualityForwarder = {0xe05592e4, 0xc0b5, 0x11d0, {0xa4, 0x39, 0x00, 0xa0, 0xc9, 0x22, 0x31, 0x96}}; -const GUID CLSID_KsIBasicAudioInterfaceHandler = {0xb9f8ac3e, 0x0f71, 0x11d2, {0xb7, 0x2c, 0x00, 0xc0, 0x4f, 0xb6, 0xbd, 0x3d}}; #ifndef _MSC_VER +const GUID CLSID_KsIBasicAudioInterfaceHandler = {0xb9f8ac3e, 0x0f71, 0x11d2, {0xb7, 0x2c, 0x00, 0xc0, 0x4f, 0xb6, 0xbd, 0x3d}}; const GUID KSPROPSETID_Pin = {0x8C134960, 0x51AD, 0x11CF, {0x87, 0x8A, 0x94, 0xF8, 0x01, 0xC1, 0x00, 0x00}}; const GUID KSINTERFACESETID_Standard = {STATIC_KSINTERFACESETID_Standard}; const GUID CLSID_Proxy = {0x17CCA71B, 0xECD7, 0x11D0, {0xB9, 0x08, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}}; diff --git a/dll/directx/ksproxy/ksproxy.rbuild b/dll/directx/ksproxy/ksproxy.rbuild index 440e279e86a..e5bc87e9b4a 100644 --- a/dll/directx/ksproxy/ksproxy.rbuild +++ b/dll/directx/ksproxy/ksproxy.rbuild @@ -33,6 +33,7 @@ interface.cpp ksproxy.cpp ksproxy.rc + node.cpp output_pin.cpp proxy.cpp qualityforward.cpp diff --git a/dll/directx/ksproxy/node.cpp b/dll/directx/ksproxy/node.cpp new file mode 100644 index 00000000000..d2686bb96a4 --- /dev/null +++ b/dll/directx/ksproxy/node.cpp @@ -0,0 +1,157 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS WDM Streaming ActiveMovie Proxy + * FILE: dll/directx/ksproxy/node.cpp + * PURPOSE: Control Node + * + * PROGRAMMERS: Johannes Anderwald (janderwald@reactos.org) + */ +#include "precomp.h" + +class CKsNode : public IKsControl +{ +public: + STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface); + + STDMETHODIMP_(ULONG) AddRef() + { + InterlockedIncrement(&m_Ref); + return m_Ref; + } + STDMETHODIMP_(ULONG) Release() + { + InterlockedDecrement(&m_Ref); + + if (!m_Ref) + { + delete this; + return 0; + } + return m_Ref; + } + + //IKsControl + HRESULT STDMETHODCALLTYPE KsProperty(PKSPROPERTY Property, ULONG PropertyLength, LPVOID PropertyData, ULONG DataLength, ULONG* BytesReturned); + HRESULT STDMETHODCALLTYPE KsMethod(PKSMETHOD Method, ULONG MethodLength, LPVOID MethodData, ULONG DataLength, ULONG* BytesReturned); + HRESULT STDMETHODCALLTYPE KsEvent(PKSEVENT Event, ULONG EventLength, LPVOID EventData, ULONG DataLength, ULONG* BytesReturned); + + CKsNode(IUnknown * pUnkOuter, HANDLE Handle) : m_Ref(0), m_pUnkOuter(pUnkOuter), m_Handle(Handle){}; + virtual ~CKsNode() + { + CloseHandle(m_Handle); + }; + +protected: + LONG m_Ref; + IUnknown * m_pUnkOuter; + HANDLE m_Handle; +}; + +HRESULT +STDMETHODCALLTYPE +CKsNode::QueryInterface( + IN REFIID refiid, + OUT PVOID* Output) +{ + if (IsEqualGUID(refiid, IID_IUnknown) || + IsEqualGUID(refiid, IID_IKsControl)) + { + *Output = PVOID(this); + reinterpret_cast(*Output)->AddRef(); + return NOERROR; + } + + return E_NOINTERFACE; +} + +//------------------------------------------------------------------- +// IKsControl +// +HRESULT +STDMETHODCALLTYPE +CKsNode::KsProperty( + PKSPROPERTY Property, + ULONG PropertyLength, + LPVOID PropertyData, + ULONG DataLength, + ULONG* BytesReturned) +{ + assert(m_Handle != 0); + return KsSynchronousDeviceControl(m_Handle, IOCTL_KS_PROPERTY, (PVOID)Property, PropertyLength, (PVOID)PropertyData, DataLength, BytesReturned); +} + +HRESULT +STDMETHODCALLTYPE +CKsNode::KsMethod( + PKSMETHOD Method, + ULONG MethodLength, + LPVOID MethodData, + ULONG DataLength, + ULONG* BytesReturned) +{ + assert(m_Handle != 0); + return KsSynchronousDeviceControl(m_Handle, IOCTL_KS_METHOD, (PVOID)Method, MethodLength, (PVOID)MethodData, DataLength, BytesReturned); +} + +HRESULT +STDMETHODCALLTYPE +CKsNode::KsEvent( + PKSEVENT Event, + ULONG EventLength, + LPVOID EventData, + ULONG DataLength, + ULONG* BytesReturned) +{ + assert(m_Handle != 0); + + if (EventLength) + return KsSynchronousDeviceControl(m_Handle, IOCTL_KS_ENABLE_EVENT, (PVOID)Event, EventLength, (PVOID)EventData, DataLength, BytesReturned); + else + return KsSynchronousDeviceControl(m_Handle, IOCTL_KS_DISABLE_EVENT, (PVOID)Event, EventLength, NULL, 0, BytesReturned); +} + +HRESULT +WINAPI +CKsNode_Constructor( + IUnknown * pUnkOuter, + HANDLE ParentHandle, + ULONG NodeId, + ACCESS_MASK DesiredAccess, + REFIID riid, + LPVOID * ppv) +{ + HRESULT hr; + HANDLE handle; + KSNODE_CREATE NodeCreate; + + OutputDebugStringW(L"CKsNode_Constructor\n"); + + //setup request + NodeCreate.CreateFlags = 0; + NodeCreate.Node = NodeId; + + hr = KsCreateTopologyNode(ParentHandle, &NodeCreate, DesiredAccess, &handle); + if (hr != NOERROR) + { + OutputDebugString("CKsNode_Constructor failed to open device\n"); + return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, hr); + } + + CKsNode * quality = new CKsNode(pUnkOuter, handle); + + if (!quality) + { + // free clock handle + CloseHandle(handle); + return E_OUTOFMEMORY; + } + + if (FAILED(quality->QueryInterface(riid, ppv))) + { + /* not supported */ + delete quality; + return E_NOINTERFACE; + } + + return NOERROR; +} diff --git a/dll/directx/ksproxy/output_pin.cpp b/dll/directx/ksproxy/output_pin.cpp index d21f3832f15..52f9cc94f7a 100644 --- a/dll/directx/ksproxy/output_pin.cpp +++ b/dll/directx/ksproxy/output_pin.cpp @@ -1,33 +1,29 @@ /* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS WDM Streaming ActiveMovie Proxy - * FILE: dll/directx/ksproxy/input_cpp.cpp - * PURPOSE: InputPin of Proxy Filter + * FILE: dll/directx/ksproxy/output_pin.cpp + * PURPOSE: OutputPin of Proxy Filter * * PROGRAMMERS: Johannes Anderwald (janderwald@reactos.org) */ #include "precomp.h" -#ifndef _MSC_VER -const GUID IID_IKsPinFactory = {0xCD5EBE6BL, 0x8B6E, 0x11D1, {0x8A, 0xE0, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}}; -#endif - class COutputPin : public IPin, public IKsObject, public IKsPropertySet, public IStreamBuilder, public IKsPinFactory, public ISpecifyPropertyPages, -// public IKsPinPipe, - public IKsControl -/* - public IQualityControl, - public IKsPinEx, - public IKsAggregateControl - public IMediaSeeking, - public IAMStreamConfig, - public IMemAllocatorNotifyCallbackTemp -*/ + public IKsPinEx, + public IKsPinPipe, + public IKsControl, + public IKsAggregateControl, + public IQualityControl, + public IMediaSeeking, + public IAMBufferNegotiation, + public IAMStreamConfig, + public IMemAllocatorNotifyCallbackTemp + { public: STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface); @@ -48,6 +44,23 @@ public: return m_Ref; } + //IKsPin + HRESULT STDMETHODCALLTYPE KsQueryMediums(PKSMULTIPLE_ITEM* MediumList); + HRESULT STDMETHODCALLTYPE KsQueryInterfaces(PKSMULTIPLE_ITEM* InterfaceList); + HRESULT STDMETHODCALLTYPE KsCreateSinkPinHandle(KSPIN_INTERFACE& Interface, KSPIN_MEDIUM& Medium); + HRESULT STDMETHODCALLTYPE KsGetCurrentCommunication(KSPIN_COMMUNICATION *Communication, KSPIN_INTERFACE *Interface, KSPIN_MEDIUM *Medium); + HRESULT STDMETHODCALLTYPE KsPropagateAcquire(); + HRESULT STDMETHODCALLTYPE KsDeliver(IMediaSample* Sample, ULONG Flags); + HRESULT STDMETHODCALLTYPE KsMediaSamplesCompleted(PKSSTREAM_SEGMENT StreamSegment); + IMemAllocator * STDMETHODCALLTYPE KsPeekAllocator(KSPEEKOPERATION Operation); + HRESULT STDMETHODCALLTYPE KsReceiveAllocator(IMemAllocator *MemAllocator); + HRESULT STDMETHODCALLTYPE KsRenegotiateAllocator(); + LONG STDMETHODCALLTYPE KsIncrementPendingIoCount(); + LONG STDMETHODCALLTYPE KsDecrementPendingIoCount(); + HRESULT STDMETHODCALLTYPE KsQualityNotify(ULONG Proportion, REFERENCE_TIME TimeDelta); + // IKsPinEx + VOID STDMETHODCALLTYPE KsNotifyError(IMediaSample* Sample, HRESULT hr); + //IKsPinPipe HRESULT STDMETHODCALLTYPE KsGetPinFramingCache(PKSALLOCATOR_FRAMING_EX *FramingEx, PFRAMING_PROP FramingProp, FRAMING_CACHE_OPS Option); HRESULT STDMETHODCALLTYPE KsSetPinFramingCache(PKSALLOCATOR_FRAMING_EX FramingEx, PFRAMING_PROP FramingProp, FRAMING_CACHE_OPS Option); @@ -101,6 +114,46 @@ public: //IKsPinFactory HRESULT STDMETHODCALLTYPE KsPinFactory(ULONG* PinFactory); + //IKsAggregateControl + HRESULT STDMETHODCALLTYPE KsAddAggregate(IN REFGUID AggregateClass); + HRESULT STDMETHODCALLTYPE KsRemoveAggregate(REFGUID AggregateClass); + + //IQualityControl + HRESULT STDMETHODCALLTYPE Notify(IBaseFilter *pSelf, Quality q); + HRESULT STDMETHODCALLTYPE SetSink(IQualityControl *piqc); + + //IMediaSeeking + HRESULT STDMETHODCALLTYPE GetCapabilities(DWORD *pCapabilities); + HRESULT STDMETHODCALLTYPE CheckCapabilities(DWORD *pCapabilities); + HRESULT STDMETHODCALLTYPE IsFormatSupported(const GUID *pFormat); + HRESULT STDMETHODCALLTYPE QueryPreferredFormat(GUID *pFormat); + HRESULT STDMETHODCALLTYPE GetTimeFormat(GUID *pFormat); + HRESULT STDMETHODCALLTYPE IsUsingTimeFormat(const GUID *pFormat); + HRESULT STDMETHODCALLTYPE SetTimeFormat(const GUID *pFormat); + HRESULT STDMETHODCALLTYPE GetDuration(LONGLONG *pDuration); + HRESULT STDMETHODCALLTYPE GetStopPosition(LONGLONG *pStop); + HRESULT STDMETHODCALLTYPE GetCurrentPosition(LONGLONG *pCurrent); + HRESULT STDMETHODCALLTYPE ConvertTimeFormat(LONGLONG *pTarget, const GUID *pTargetFormat, LONGLONG Source, const GUID *pSourceFormat); + HRESULT STDMETHODCALLTYPE SetPositions(LONGLONG *pCurrent, DWORD dwCurrentFlags, LONGLONG *pStop, DWORD dwStopFlags); + HRESULT STDMETHODCALLTYPE GetPositions(LONGLONG *pCurrent, LONGLONG *pStop); + HRESULT STDMETHODCALLTYPE GetAvailable(LONGLONG *pEarliest, LONGLONG *pLatest); + HRESULT STDMETHODCALLTYPE SetRate(double dRate); + HRESULT STDMETHODCALLTYPE GetRate(double *pdRate); + HRESULT STDMETHODCALLTYPE GetPreroll(LONGLONG *pllPreroll); + + //IAMBufferNegotiation + HRESULT STDMETHODCALLTYPE SuggestAllocatorProperties(const ALLOCATOR_PROPERTIES *pprop); + HRESULT STDMETHODCALLTYPE GetAllocatorProperties(ALLOCATOR_PROPERTIES *pprop); + + //IAMStreamConfig + HRESULT STDMETHODCALLTYPE SetFormat(AM_MEDIA_TYPE *pmt); + HRESULT STDMETHODCALLTYPE GetFormat(AM_MEDIA_TYPE **ppmt); + HRESULT STDMETHODCALLTYPE GetNumberOfCapabilities(int *piCount, int *piSize); + HRESULT STDMETHODCALLTYPE GetStreamCaps(int iIndex, AM_MEDIA_TYPE **ppmt, BYTE *pSCC); + + //IMemAllocatorNotifyCallbackTemp + HRESULT STDMETHODCALLTYPE NotifyRelease(); + COutputPin(IBaseFilter * ParentFilter, LPCWSTR PinName, ULONG PinId); virtual ~COutputPin(); @@ -112,6 +165,20 @@ protected: ULONG m_PinId; IKsObject * m_KsObjectParent; IPin * m_Pin; + IKsAllocatorEx * m_KsAllocatorEx; + ULONG m_PipeAllocatorFlag; + BOOL m_bPinBusCacheInitialized; + GUID m_PinBusCache; + LPWSTR m_FilterName; + FRAMING_PROP m_FramingProp[4]; + PKSALLOCATOR_FRAMING_EX m_FramingEx[4]; + + IMemAllocator * m_MemAllocator; + LONG m_IoCount; + KSPIN_COMMUNICATION m_Communication; + KSPIN_INTERFACE m_Interface; + KSPIN_MEDIUM m_Medium; + IMediaSeeking * m_FilterMediaSeeking; }; COutputPin::~COutputPin() @@ -123,13 +190,32 @@ COutputPin::~COutputPin() COutputPin::COutputPin( IBaseFilter * ParentFilter, LPCWSTR PinName, - ULONG PinId) : m_Ref(0), m_ParentFilter(ParentFilter), m_PinName(PinName), m_hPin(0), m_PinId(PinId), m_KsObjectParent(0), m_Pin(0) + ULONG PinId) : m_Ref(0), + m_ParentFilter(ParentFilter), + m_PinName(PinName), + m_hPin(INVALID_HANDLE_VALUE), + m_PinId(PinId), + m_KsObjectParent(0), + m_Pin(0), + m_KsAllocatorEx(0), + m_PipeAllocatorFlag(0), + m_bPinBusCacheInitialized(0), + m_FilterName(0), + m_MemAllocator(0), + m_IoCount(0), + m_Communication(KSPIN_COMMUNICATION_NONE), + m_FilterMediaSeeking(0) { HRESULT hr; hr = m_ParentFilter->QueryInterface(IID_IKsObject, (LPVOID*)&m_KsObjectParent); assert(hr == S_OK); + hr = m_ParentFilter->QueryInterface(IID_IMediaSeeking, (LPVOID*)&m_FilterMediaSeeking); + assert(hr == S_OK); + + ZeroMemory(m_FramingProp, sizeof(m_FramingProp)); + ZeroMemory(m_FramingEx, sizeof(m_FramingEx)); }; HRESULT @@ -142,50 +228,102 @@ COutputPin::QueryInterface( if (IsEqualGUID(refiid, IID_IUnknown) || IsEqualGUID(refiid, IID_IPin)) { + OutputDebugStringW(L"COutputPin::QueryInterface IID_IPin\n"); *Output = PVOID(this); reinterpret_cast(*Output)->AddRef(); return NOERROR; } else if (IsEqualGUID(refiid, IID_IKsObject)) { + OutputDebugStringW(L"COutputPin::QueryInterface IID_IKsObject\n"); *Output = (IKsObject*)(this); reinterpret_cast(*Output)->AddRef(); return NOERROR; } + else if (IsEqualGUID(refiid, IID_IKsPin) || IsEqualGUID(refiid, IID_IKsPinEx)) + { + *Output = (IKsPinEx*)(this); + reinterpret_cast(*Output)->AddRef(); + return NOERROR; + } + else if (IsEqualGUID(refiid, IID_IKsPinPipe)) + { + *Output = (IKsPinPipe*)(this); + reinterpret_cast(*Output)->AddRef(); + return NOERROR; + } + else if (IsEqualGUID(refiid, IID_IKsAggregateControl)) + { + *Output = (IKsAggregateControl*)(this); + reinterpret_cast(*Output)->AddRef(); + return NOERROR; + } + else if (IsEqualGUID(refiid, IID_IQualityControl)) + { + *Output = (IQualityControl*)(this); + reinterpret_cast(*Output)->AddRef(); + return NOERROR; + } else if (IsEqualGUID(refiid, IID_IKsPropertySet)) { + OutputDebugStringW(L"COutputPin::QueryInterface IID_IKsPropertySet\n"); + DebugBreak(); *Output = (IKsPropertySet*)(this); reinterpret_cast(*Output)->AddRef(); return NOERROR; } else if (IsEqualGUID(refiid, IID_IKsControl)) { + OutputDebugStringW(L"COutputPin::QueryInterface IID_IKsControl\n"); *Output = (IKsControl*)(this); reinterpret_cast(*Output)->AddRef(); return NOERROR; } +#if 0 else if (IsEqualGUID(refiid, IID_IStreamBuilder)) { *Output = (IStreamBuilder*)(this); reinterpret_cast(*Output)->AddRef(); return NOERROR; } +#endif else if (IsEqualGUID(refiid, IID_IKsPinFactory)) { + OutputDebugStringW(L"COutputPin::QueryInterface IID_IKsPinFactory\n"); *Output = (IKsPinFactory*)(this); reinterpret_cast(*Output)->AddRef(); return NOERROR; } else if (IsEqualGUID(refiid, IID_ISpecifyPropertyPages)) { + OutputDebugStringW(L"COutputPin::QueryInterface IID_ISpecifyPropertyPages\n"); *Output = (ISpecifyPropertyPages*)(this); reinterpret_cast(*Output)->AddRef(); return NOERROR; } - else if (IsEqualGUID(refiid, IID_IBaseFilter)) + else if (IsEqualGUID(refiid, IID_IMediaSeeking)) { - OutputDebugStringW(L"COutputPin::QueryInterface query IID_IBaseFilter\n"); - DebugBreak(); + *Output = (IMediaSeeking*)(this); + reinterpret_cast(*Output)->AddRef(); + return NOERROR; + } + else if (IsEqualGUID(refiid, IID_IAMBufferNegotiation)) + { + *Output = (IAMBufferNegotiation*)(this); + reinterpret_cast(*Output)->AddRef(); + return NOERROR; + } + else if (IsEqualGUID(refiid, IID_IAMStreamConfig)) + { + *Output = (IAMStreamConfig*)(this); + reinterpret_cast(*Output)->AddRef(); + return NOERROR; + } + else if (IsEqualGUID(refiid, IID_IMemAllocatorNotifyCallbackTemp)) + { + *Output = (IMemAllocatorNotifyCallbackTemp*)(this); + reinterpret_cast(*Output)->AddRef(); + return NOERROR; } WCHAR Buffer[MAX_PATH]; @@ -198,6 +336,580 @@ COutputPin::QueryInterface( return E_NOINTERFACE; } +//------------------------------------------------------------------- +// IAMBufferNegotiation interface +// +HRESULT +STDMETHODCALLTYPE +COutputPin::SuggestAllocatorProperties( + const ALLOCATOR_PROPERTIES *pprop) +{ + OutputDebugStringW(L"COutputPin::SuggestAllocatorProperties NotImplemented\n"); + return E_NOTIMPL; +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::GetAllocatorProperties( + ALLOCATOR_PROPERTIES *pprop) +{ + OutputDebugStringW(L"COutputPin::GetAllocatorProperties NotImplemented\n"); + return E_NOTIMPL; +} + +//------------------------------------------------------------------- +// IAMStreamConfig interface +// +HRESULT +STDMETHODCALLTYPE +COutputPin::SetFormat( + AM_MEDIA_TYPE *pmt) +{ + OutputDebugStringW(L"COutputPin::SetFormat NotImplemented\n"); + return E_NOTIMPL; +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::GetFormat(AM_MEDIA_TYPE **ppmt) +{ + OutputDebugStringW(L"COutputPin::GetFormat NotImplemented\n"); + return E_NOTIMPL; +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::GetNumberOfCapabilities( + int *piCount, + int *piSize) +{ + OutputDebugStringW(L"COutputPin::GetNumberOfCapabilities NotImplemented\n"); + return E_NOTIMPL; +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::GetStreamCaps( + int iIndex, + AM_MEDIA_TYPE **ppmt, + BYTE *pSCC) +{ + OutputDebugStringW(L"COutputPin::GetStreamCaps NotImplemented\n"); + return E_NOTIMPL; +} + +//------------------------------------------------------------------- +// IMemAllocatorNotifyCallbackTemp interface +// +HRESULT +STDMETHODCALLTYPE +COutputPin::NotifyRelease() +{ + OutputDebugStringW(L"COutputPin::NotifyRelease NotImplemented\n"); + return E_NOTIMPL; +} + +//------------------------------------------------------------------- +// IMediaSeeking interface +// +HRESULT +STDMETHODCALLTYPE +COutputPin::GetCapabilities( + DWORD *pCapabilities) +{ + return m_FilterMediaSeeking->GetCapabilities(pCapabilities); +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::CheckCapabilities( + DWORD *pCapabilities) +{ + return m_FilterMediaSeeking->CheckCapabilities(pCapabilities); +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::IsFormatSupported( + const GUID *pFormat) +{ + return m_FilterMediaSeeking->IsFormatSupported(pFormat); +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::QueryPreferredFormat( + GUID *pFormat) +{ + return m_FilterMediaSeeking->QueryPreferredFormat(pFormat); +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::GetTimeFormat( + GUID *pFormat) +{ + return m_FilterMediaSeeking->GetTimeFormat(pFormat); +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::IsUsingTimeFormat( + const GUID *pFormat) +{ + return m_FilterMediaSeeking->IsUsingTimeFormat(pFormat); +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::SetTimeFormat( + const GUID *pFormat) +{ + return m_FilterMediaSeeking->SetTimeFormat(pFormat); +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::GetDuration( + LONGLONG *pDuration) +{ + return m_FilterMediaSeeking->GetDuration(pDuration); +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::GetStopPosition( + LONGLONG *pStop) +{ + return m_FilterMediaSeeking->GetStopPosition(pStop); +} + + +HRESULT +STDMETHODCALLTYPE +COutputPin::GetCurrentPosition( + LONGLONG *pCurrent) +{ + return m_FilterMediaSeeking->GetCurrentPosition(pCurrent); +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::ConvertTimeFormat( + LONGLONG *pTarget, + const GUID *pTargetFormat, + LONGLONG Source, + const GUID *pSourceFormat) +{ + return m_FilterMediaSeeking->ConvertTimeFormat(pTarget, pTargetFormat, Source, pSourceFormat); +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::SetPositions( + LONGLONG *pCurrent, + DWORD dwCurrentFlags, + LONGLONG *pStop, + DWORD dwStopFlags) +{ + return m_FilterMediaSeeking->SetPositions(pCurrent, dwCurrentFlags, pStop, dwStopFlags); +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::GetPositions( + LONGLONG *pCurrent, + LONGLONG *pStop) +{ + return m_FilterMediaSeeking->GetPositions(pCurrent, pStop); +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::GetAvailable( + LONGLONG *pEarliest, + LONGLONG *pLatest) +{ + return m_FilterMediaSeeking->GetAvailable(pEarliest, pLatest); +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::SetRate( + double dRate) +{ + return m_FilterMediaSeeking->SetRate(dRate); +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::GetRate( + double *pdRate) +{ + return m_FilterMediaSeeking->GetRate(pdRate); +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::GetPreroll( + LONGLONG *pllPreroll) +{ + return m_FilterMediaSeeking->GetPreroll(pllPreroll); +} + +//------------------------------------------------------------------- +// IQualityControl interface +// +HRESULT +STDMETHODCALLTYPE +COutputPin::Notify( + IBaseFilter *pSelf, + Quality q) +{ + OutputDebugStringW(L"COutputPin::Notify NotImplemented\n"); + return E_NOTIMPL; +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::SetSink( + IQualityControl *piqc) +{ + OutputDebugStringW(L"COutputPin::SetSink NotImplemented\n"); + return E_NOTIMPL; +} + + +//------------------------------------------------------------------- +// IKsAggregateControl interface +// +HRESULT +STDMETHODCALLTYPE +COutputPin::KsAddAggregate( + IN REFGUID AggregateClass) +{ + OutputDebugStringW(L"COutputPin::KsAddAggregate NotImplemented\n"); + return E_NOTIMPL; +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::KsRemoveAggregate( + REFGUID AggregateClass) +{ + OutputDebugStringW(L"COutputPin::KsRemoveAggregate NotImplemented\n"); + return E_NOTIMPL; +} + + +//------------------------------------------------------------------- +// IKsPin +// + +HRESULT +STDMETHODCALLTYPE +COutputPin::KsQueryMediums( + PKSMULTIPLE_ITEM* MediumList) +{ + HANDLE hFilter = m_KsObjectParent->KsGetObjectHandle(); + return KsGetMultiplePinFactoryItems(hFilter, m_PinId, KSPROPERTY_PIN_MEDIUMS, (PVOID*)MediumList); +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::KsQueryInterfaces( + PKSMULTIPLE_ITEM* InterfaceList) +{ + HANDLE hFilter = m_KsObjectParent->KsGetObjectHandle(); + + return KsGetMultiplePinFactoryItems(hFilter, m_PinId, KSPROPERTY_PIN_INTERFACES, (PVOID*)InterfaceList); +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::KsCreateSinkPinHandle( + KSPIN_INTERFACE& Interface, + KSPIN_MEDIUM& Medium) +{ + OutputDebugStringW(L"COutputPin::KsCreateSinkPinHandle NotImplemented\n"); + return E_NOTIMPL; +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::KsGetCurrentCommunication( + KSPIN_COMMUNICATION *Communication, + KSPIN_INTERFACE *Interface, + KSPIN_MEDIUM *Medium) +{ + if (Communication) + { + *Communication = m_Communication; + } + + if (Interface) + { + if (!m_hPin) + return VFW_E_NOT_CONNECTED; + + CopyMemory(Interface, &m_Interface, sizeof(KSPIN_INTERFACE)); + } + + if (Medium) + { + if (!m_hPin) + return VFW_E_NOT_CONNECTED; + + CopyMemory(Medium, &m_Medium, sizeof(KSPIN_MEDIUM)); + } + return NOERROR; +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::KsPropagateAcquire() +{ + OutputDebugStringW(L"COutputPin::KsPropagateAcquire NotImplemented\n"); + return E_NOTIMPL; +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::KsDeliver( + IMediaSample* Sample, + ULONG Flags) +{ + return E_FAIL; +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::KsMediaSamplesCompleted(PKSSTREAM_SEGMENT StreamSegment) +{ + return NOERROR; +} + +IMemAllocator * +STDMETHODCALLTYPE +COutputPin::KsPeekAllocator(KSPEEKOPERATION Operation) +{ + if (Operation == KsPeekOperation_AddRef) + { + // add reference on allocator + m_MemAllocator->AddRef(); + } + + return m_MemAllocator; +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::KsReceiveAllocator(IMemAllocator *MemAllocator) +{ + if (MemAllocator) + { + MemAllocator->AddRef(); + } + + if (m_MemAllocator) + { + m_MemAllocator->Release(); + } + + m_MemAllocator = MemAllocator; + return NOERROR; +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::KsRenegotiateAllocator() +{ + return E_FAIL; +} + +LONG +STDMETHODCALLTYPE +COutputPin::KsIncrementPendingIoCount() +{ + return InterlockedIncrement((volatile LONG*)&m_IoCount); +} + +LONG +STDMETHODCALLTYPE +COutputPin::KsDecrementPendingIoCount() +{ + return InterlockedDecrement((volatile LONG*)&m_IoCount); +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::KsQualityNotify( + ULONG Proportion, + REFERENCE_TIME TimeDelta) +{ + OutputDebugStringW(L"COutputPin::KsQualityNotify NotImplemented\n"); + return E_NOTIMPL; +} + +//------------------------------------------------------------------- +// IKsPinEx +// + +VOID +STDMETHODCALLTYPE +COutputPin::KsNotifyError( + IMediaSample* Sample, + HRESULT hr) +{ + OutputDebugStringW(L"COutputPin::KsNotifyError NotImplemented\n"); +} + + +//------------------------------------------------------------------- +// IKsPinPipe +// + +HRESULT +STDMETHODCALLTYPE +COutputPin::KsGetPinFramingCache( + PKSALLOCATOR_FRAMING_EX *FramingEx, + PFRAMING_PROP FramingProp, + FRAMING_CACHE_OPS Option) +{ + if (Option > Framing_Cache_Write || Option < Framing_Cache_ReadLast) + { + // invalid argument + return E_INVALIDARG; + } + + // get framing properties + *FramingProp = m_FramingProp[Option]; + *FramingEx = m_FramingEx[Option]; + + return NOERROR; +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::KsSetPinFramingCache( + PKSALLOCATOR_FRAMING_EX FramingEx, + PFRAMING_PROP FramingProp, + FRAMING_CACHE_OPS Option) +{ + ULONG Index; + ULONG RefCount = 0; + + if (m_FramingEx[Option]) + { + for(Index = 1; Index < 4; Index++) + { + if (m_FramingEx[Index] == m_FramingEx[Option]) + RefCount++; + } + + if (RefCount == 1) + { + // existing framing is only used once + CoTaskMemFree(m_FramingEx[Option]); + } + } + + // store framing + m_FramingEx[Option] = FramingEx; + m_FramingProp[Option] = *FramingProp; + + return S_OK; +} + +IPin* +STDMETHODCALLTYPE +COutputPin::KsGetConnectedPin() +{ + return m_Pin; +} + +IKsAllocatorEx* +STDMETHODCALLTYPE +COutputPin::KsGetPipe( + KSPEEKOPERATION Operation) +{ + if (Operation == KsPeekOperation_AddRef) + { + if (m_KsAllocatorEx) + m_KsAllocatorEx->AddRef(); + } + return m_KsAllocatorEx; +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::KsSetPipe( + IKsAllocatorEx *KsAllocator) +{ + if (KsAllocator) + KsAllocator->AddRef(); + + if (m_KsAllocatorEx) + m_KsAllocatorEx->Release(); + + m_KsAllocatorEx = KsAllocator; + return NOERROR; +} + +ULONG +STDMETHODCALLTYPE +COutputPin::KsGetPipeAllocatorFlag() +{ + return m_PipeAllocatorFlag; +} + + +HRESULT +STDMETHODCALLTYPE +COutputPin::KsSetPipeAllocatorFlag( + ULONG Flag) +{ + m_PipeAllocatorFlag = Flag; + return NOERROR; +} + +GUID +STDMETHODCALLTYPE +COutputPin::KsGetPinBusCache() +{ + if (!m_bPinBusCacheInitialized) + { + CopyMemory(&m_PinBusCache, &m_Medium.Set, sizeof(GUID)); + m_bPinBusCacheInitialized = TRUE; + } + + return m_PinBusCache; +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::KsSetPinBusCache( + GUID Bus) +{ + CopyMemory(&m_PinBusCache, &Bus, sizeof(GUID)); + return NOERROR; +} + +PWCHAR +STDMETHODCALLTYPE +COutputPin::KsGetPinName() +{ + return (PWCHAR)m_PinName; +} + + +PWCHAR +STDMETHODCALLTYPE +COutputPin::KsGetFilterName() +{ + return m_FilterName; +} + //------------------------------------------------------------------- // ISpecifyPropertyPages // @@ -226,6 +938,7 @@ STDMETHODCALLTYPE COutputPin::KsPinFactory( ULONG* PinFactory) { + OutputDebugStringW(L"COutputPin::KsPinFactory\n"); *PinFactory = m_PinId; return S_OK; } @@ -241,6 +954,7 @@ COutputPin::Render( IPin *ppinOut, IGraphBuilder *pGraph) { + OutputDebugStringW(L"COutputPin::Render\n"); return S_OK; } @@ -250,6 +964,7 @@ COutputPin::Backout( IPin *ppinOut, IGraphBuilder *pGraph) { + OutputDebugStringW(L"COutputPin::Backout\n"); return S_OK; } //------------------------------------------------------------------- @@ -259,6 +974,7 @@ HANDLE STDMETHODCALLTYPE COutputPin::KsGetObjectHandle() { + OutputDebugStringW(L"COutputPin::KsGetObjectHandle\n"); assert(m_hPin); return m_hPin; } @@ -276,6 +992,7 @@ COutputPin::KsProperty( ULONG* BytesReturned) { assert(m_hPin != 0); + OutputDebugStringW(L"COutputPin::KsProperty\n"); return KsSynchronousDeviceControl(m_hPin, IOCTL_KS_PROPERTY, (PVOID)Property, PropertyLength, (PVOID)PropertyData, DataLength, BytesReturned); } @@ -289,6 +1006,7 @@ COutputPin::KsMethod( ULONG* BytesReturned) { assert(m_hPin != 0); + OutputDebugStringW(L"COutputPin::KsMethod\n"); return KsSynchronousDeviceControl(m_hPin, IOCTL_KS_METHOD, (PVOID)Method, MethodLength, (PVOID)MethodData, DataLength, BytesReturned); } @@ -303,6 +1021,8 @@ COutputPin::KsEvent( { assert(m_hPin != 0); + OutputDebugStringW(L"COutputPin::KsEvent\n"); + if (EventLength) return KsSynchronousDeviceControl(m_hPin, IOCTL_KS_ENABLE_EVENT, (PVOID)Event, EventLength, (PVOID)EventData, DataLength, BytesReturned); else @@ -325,6 +1045,8 @@ COutputPin::Set( { ULONG BytesReturned; + OutputDebugStringW(L"COutputPin::Set\n"); + if (cbInstanceData) { PKSPROPERTY Property = (PKSPROPERTY)CoTaskMemAlloc(sizeof(KSPROPERTY) + cbInstanceData); @@ -367,6 +1089,8 @@ COutputPin::Get( { ULONG BytesReturned; + OutputDebugStringW(L"COutputPin::Get\n"); + if (cbInstanceData) { PKSPROPERTY Property = (PKSPROPERTY)CoTaskMemAlloc(sizeof(KSPROPERTY) + cbInstanceData); @@ -406,6 +1130,8 @@ COutputPin::QuerySupported( KSPROPERTY Property; ULONG BytesReturned; + OutputDebugStringW(L"COutputPin::QuerySupported\n"); + Property.Set = guidPropSet; Property.Id = dwPropID; Property.Flags = KSPROPERTY_TYPE_SETSUPPORT; @@ -470,12 +1196,15 @@ HRESULT STDMETHODCALLTYPE COutputPin::ReceiveConnection(IPin *pConnector, const AM_MEDIA_TYPE *pmt) { + OutputDebugStringW(L"COutputPin::ReceiveConnection\n"); return E_UNEXPECTED; } HRESULT STDMETHODCALLTYPE COutputPin::Disconnect( void) { + OutputDebugStringW(L"COutputPin::Disconnect\n"); + if (!m_Pin) { // pin was not connected @@ -495,6 +1224,8 @@ HRESULT STDMETHODCALLTYPE COutputPin::ConnectedTo(IPin **pPin) { + OutputDebugStringW(L"COutputPin::ConnectedTo\n"); + if (!pPin) return E_POINTER; @@ -520,6 +1251,8 @@ HRESULT STDMETHODCALLTYPE COutputPin::QueryPinInfo(PIN_INFO *pInfo) { + OutputDebugStringW(L"COutputPin::QueryPinInfo\n"); + wcscpy(pInfo->achName, m_PinName); pInfo->dir = PINDIR_OUTPUT; pInfo->pFilter = m_ParentFilter; @@ -531,6 +1264,8 @@ HRESULT STDMETHODCALLTYPE COutputPin::QueryDirection(PIN_DIRECTION *pPinDir) { + OutputDebugStringW(L"COutputPin::QueryDirection\n"); + if (pPinDir) { *pPinDir = PINDIR_OUTPUT; @@ -543,6 +1278,8 @@ HRESULT STDMETHODCALLTYPE COutputPin::QueryId(LPWSTR *Id) { + OutputDebugStringW(L"COutputPin::QueryId\n"); + *Id = (LPWSTR)CoTaskMemAlloc((wcslen(m_PinName)+1)*sizeof(WCHAR)); if (!*Id) return E_OUTOFMEMORY; @@ -580,10 +1317,10 @@ COutputPin::EnumMediaTypes(IEnumMediaTypes **ppEnum) // query media type count hr = KsGetMediaTypeCount(hFilter, m_PinId, &MediaTypeCount); if (FAILED(hr) || !MediaTypeCount) - { + { OutputDebugStringW(L"COutputPin::EnumMediaTypes failed1\n"); return hr; - } + } // allocate media types MediaTypes = (AM_MEDIA_TYPE*)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE) * MediaTypeCount); @@ -605,7 +1342,7 @@ COutputPin::EnumMediaTypes(IEnumMediaTypes **ppEnum) { // failed CoTaskMemFree(MediaTypes); - OutputDebugStringW(L"COutputPin::EnumMediaTypes failed2\n"); + OutputDebugStringW(L"COutputPin::EnumMediaTypes failed\n"); return hr; } } diff --git a/dll/directx/ksproxy/precomp.h b/dll/directx/ksproxy/precomp.h index 5078daef9a9..2ea89aa0887 100644 --- a/dll/directx/ksproxy/precomp.h +++ b/dll/directx/ksproxy/precomp.h @@ -19,8 +19,23 @@ #include #include #include +#include //#include + +interface DECLSPEC_UUID("877E4351-6FEA-11D0-B863-00AA00A216A1") IKsClock; + +#undef INTERFACE +#define INTERFACE IKsClock + +DECLARE_INTERFACE_(IKsClock, IUnknown) +{ + STDMETHOD_(HANDLE, KsGetClockHandle)( + THIS + ) PURE; +}; + + typedef HRESULT (CALLBACK *LPFNCREATEINSTANCE)(IUnknown* pUnkOuter, REFIID riid, LPVOID* ppvObject); typedef struct { @@ -139,4 +154,19 @@ CEnumMediaTypes_fnConstructor( REFIID riid, LPVOID * ppv); +/* node.cpp */ +HRESULT +WINAPI +CKsNode_Constructor( + IUnknown * pUnkOuter, + HANDLE ParentHandle, + ULONG NodeId, + ACCESS_MASK DesiredAccess, + REFIID riid, + LPVOID * ppv); + extern const GUID IID_IKsObject; +extern const GUID IID_IKsPinEx; +extern const GUID IID_IKsAggregateControl; +extern const GUID IID_IKsPinPipe; +extern const GUID IID_IKsPinFactory; diff --git a/dll/directx/ksproxy/proxy.cpp b/dll/directx/ksproxy/proxy.cpp index f74f22ba9f7..371176f2437 100644 --- a/dll/directx/ksproxy/proxy.cpp +++ b/dll/directx/ksproxy/proxy.cpp @@ -14,13 +14,17 @@ const GUID GUID_NULL = {0x00000000L, 0x0000, 0x0000, {0x00, const GUID IID_ISpecifyPropertyPages = {0xB196B28B, 0xBAB4, 0x101A, {0xB6, 0x9C, 0x00, 0xAA, 0x00, 0x34, 0x1D, 0x07}}; const GUID IID_IPersistStream = {0x00000109, 0x0000, 0x0000, {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}}; const GUID KSPROPSETID_MediaSeeking = {0xEE904F0CL, 0xD09B, 0x11D0, {0xAB, 0xE9, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}}; +const GUID KSPROPSETID_Clock = {0xDF12A4C0L, 0xAC17, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}}; +const GUID KSEVENTSETID_Clock = {0x364D8E20L, 0x62C7, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}}; +const GUID KSPROPSETID_Stream = {0x65aaba60L, 0x98ae, 0x11cf, {0xa1, 0x0d, 0x00, 0x20, 0xaf, 0xd1, 0x56, 0xe4}}; +const GUID IID_IPersist = {0x0000010c, 0x0000, 0x0000, {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}}; #endif const GUID IID_IBDA_DeviceControl = {0xFD0A5AF3, 0xB41D, 0x11d2, {0x9C, 0x95, 0x00, 0xC0, 0x4F, 0x79, 0x71, 0xE0}}; const GUID IID_IKsAggregateControl = {0x7F40EAC0, 0x3947, 0x11D2, {0x87, 0x4E, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}}; const GUID IID_IKsClockPropertySet = {0x5C5CBD84, 0xE755, 0x11D0, {0xAC, 0x18, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}}; const GUID IID_IKsTopology = {0x28F54683, 0x06FD, 0x11D2, {0xB2, 0x7A, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}}; - +const GUID IID_IKsClock = {0x877E4351, 0x6FEA, 0x11D0, {0xB8, 0x63, 0x00, 0xAA, 0x00, 0xA2, 0x16, 0xA1}}; /* Needs IKsClock, IKsNotifyEvent */ @@ -35,6 +39,7 @@ class CKsProxy : public IBaseFilter, public IReferenceClock, public IMediaSeeking, public IKsPropertySet, + public IKsClock, public IKsClockPropertySet, public IAMFilterMiscFlags, public IKsControl, @@ -148,6 +153,9 @@ public: // IKsObject HANDLE STDMETHODCALLTYPE KsGetObjectHandle(); + // IKsClock + HANDLE STDMETHODCALLTYPE KsGetClockHandle(); + //IAMDeviceRemoval HRESULT STDMETHODCALLTYPE DeviceInfo(CLSID *pclsidInterfaceClass, LPWSTR *pwszSymbolicLink); HRESULT STDMETHODCALLTYPE Reassociate(void); @@ -163,7 +171,7 @@ public: HRESULT STDMETHODCALLTYPE GetPages(CAUUID *pPages); - CKsProxy() : m_Ref(0), m_pGraph(0), m_ReferenceClock(0), m_FilterState(State_Stopped), m_hDevice(0), m_Plugins(), m_Pins(), m_DevicePath(0) {}; + CKsProxy() : m_Ref(0), m_pGraph(0), m_ReferenceClock(0), m_FilterState(State_Stopped), m_hDevice(0), m_Plugins(), m_Pins(), m_DevicePath(0), m_hClock(0) {}; ~CKsProxy() { if (m_hDevice) @@ -178,6 +186,9 @@ public: HRESULT STDMETHODCALLTYPE GetPinName(ULONG PinId, KSPIN_DATAFLOW DataFlow, ULONG PinCount, LPWSTR * OutPinName); HRESULT STDMETHODCALLTYPE GetPinCommunication(ULONG PinId, KSPIN_COMMUNICATION * Communication); HRESULT STDMETHODCALLTYPE CreatePins(); + HRESULT STDMETHODCALLTYPE GetMediaSeekingFormats(PKSMULTIPLE_ITEM *FormatList); + HRESULT STDMETHODCALLTYPE CreateClockInstance(); + HRESULT STDMETHODCALLTYPE PerformClockProperty(ULONG PropertyId, ULONG PropertyFlags, PVOID OutputBuffer, ULONG OutputBufferSize); protected: LONG m_Ref; IFilterGraph *m_pGraph; @@ -188,6 +199,7 @@ protected: PinVector m_Pins; LPWSTR m_DevicePath; CLSID m_DeviceInterfaceGUID; + HANDLE m_hClock; }; HRESULT @@ -196,7 +208,7 @@ CKsProxy::QueryInterface( IN REFIID refiid, OUT PVOID* Output) { - *Output = (PVOID)0xDEADDEAD;//NULL; + *Output = NULL; if (IsEqualGUID(refiid, IID_IUnknown) || IsEqualGUID(refiid, IID_IBaseFilter)) @@ -223,14 +235,33 @@ CKsProxy::QueryInterface( reinterpret_cast(*Output)->AddRef(); return NOERROR; } + else if (IsEqualGUID(refiid, IID_IPersist)) + { + *Output = (IPersistStream*)(this); + reinterpret_cast(*Output)->AddRef(); + return NOERROR; + } else if (IsEqualGUID(refiid, IID_IKsObject)) { *Output = (IKsObject*)(this); reinterpret_cast(*Output)->AddRef(); return NOERROR; } + else if (IsEqualGUID(refiid, IID_IKsClock)) + { + *Output = (IKsClock*)(this); + reinterpret_cast(*Output)->AddRef(); + return NOERROR; + } else if (IsEqualGUID(refiid, IID_IReferenceClock)) { + if (!m_hClock) + { + HRESULT hr = CreateClockInstance(); + if (FAILED(hr)) + return hr; + } + *Output = (IReferenceClock*)(this); reinterpret_cast(*Output)->AddRef(); return NOERROR; @@ -273,6 +304,13 @@ CKsProxy::QueryInterface( } else if (IsEqualGUID(refiid, IID_IKsClockPropertySet)) { + if (!m_hClock) + { + HRESULT hr = CreateClockInstance(); + if (FAILED(hr)) + return hr; + } + *Output = (IKsClockPropertySet*)(this); reinterpret_cast(*Output)->AddRef(); return NOERROR; @@ -335,13 +373,110 @@ CKsProxy::GetPages(CAUUID *pPages) //------------------------------------------------------------------- // IKsClockPropertySet interface // + +HRESULT +STDMETHODCALLTYPE +CKsProxy::CreateClockInstance() +{ + HRESULT hr; + HANDLE hPin = INVALID_HANDLE_VALUE; + ULONG Index; + PIN_DIRECTION PinDir; + IKsObject *pObject; + KSCLOCK_CREATE ClockCreate; + + // find output pin and handle + for(Index = 0; Index < m_Pins.size(); Index++) + { + //get pin + IPin * pin = m_Pins[Index]; + if (!pin) + continue; + + // get direction + hr = pin->QueryDirection(&PinDir); + if (FAILED(hr)) + continue; + + // query IKsObject interface + hr = pin->QueryInterface(IID_IKsObject, (void**)&pObject); + if (FAILED(hr)) + continue; + + + // get pin handle + hPin = pObject->KsGetObjectHandle(); + + //release IKsObject + pObject->Release(); + + if (hPin != INVALID_HANDLE_VALUE) + break; + } + + if (hPin == INVALID_HANDLE_VALUE) + { + // clock can only be instantiated on a pin handle + return E_NOTIMPL; + } + + if (m_hClock) + { + // release clock handle + CloseHandle(m_hClock); + } + + //setup clock create request + ClockCreate.CreateFlags = 0; + + // setup clock create request + hr = KsCreateClock(hPin, &ClockCreate, &m_hClock); // FIXME KsCreateClock returns NTSTATUS + if (SUCCEEDED(hr)) + { + // failed to create clock + return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError()); + } + + return S_OK; +} + +HRESULT +STDMETHODCALLTYPE +CKsProxy::PerformClockProperty( + ULONG PropertyId, + ULONG PropertyFlags, + PVOID OutputBuffer, + ULONG OutputBufferSize) +{ + KSPROPERTY Property; + HRESULT hr; + ULONG BytesReturned; + + if (!m_hClock) + { + // create clock + hr = CreateClockInstance(); + if (FAILED(hr)) + return hr; + } + + // setup request + Property.Set = KSPROPSETID_Clock; + Property.Id = PropertyId; + Property.Flags = PropertyFlags; + + hr = KsSynchronousDeviceControl(m_hClock, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)OutputBuffer, OutputBufferSize, &BytesReturned); + + return hr; +} + HRESULT STDMETHODCALLTYPE CKsProxy::KsGetTime( LONGLONG* Time) { - OutputDebugStringW(L"CKsProxy::KsGetTime NotImplemented\n"); - return E_NOTIMPL; + OutputDebugStringW(L"CKsProxy::KsGetTime\n"); + return PerformClockProperty(KSPROPERTY_CLOCK_TIME, KSPROPERTY_TYPE_GET, (PVOID)Time, sizeof(LONGLONG)); } HRESULT @@ -349,8 +484,8 @@ STDMETHODCALLTYPE CKsProxy::KsSetTime( LONGLONG Time) { - OutputDebugStringW(L"CKsProxy::KsSetTime NotImplemented\n"); - return E_NOTIMPL; + OutputDebugStringW(L"CKsProxy::KsSetTime\n"); + return PerformClockProperty(KSPROPERTY_CLOCK_TIME, KSPROPERTY_TYPE_SET, (PVOID)&Time, sizeof(LONGLONG)); } HRESULT @@ -358,8 +493,8 @@ STDMETHODCALLTYPE CKsProxy::KsGetPhysicalTime( LONGLONG* Time) { - OutputDebugStringW(L"CKsProxy::KsGetPhysicalTime NotImplemented\n"); - return E_NOTIMPL; + OutputDebugStringW(L"CKsProxy::KsGetPhysicalTime\n"); + return PerformClockProperty(KSPROPERTY_CLOCK_PHYSICALTIME, KSPROPERTY_TYPE_GET, (PVOID)Time, sizeof(LONGLONG)); } HRESULT @@ -368,7 +503,7 @@ CKsProxy::KsSetPhysicalTime( LONGLONG Time) { OutputDebugStringW(L"CKsProxy::KsSetPhysicalTime NotImplemented\n"); - return E_NOTIMPL; + return PerformClockProperty(KSPROPERTY_CLOCK_PHYSICALTIME, KSPROPERTY_TYPE_SET, (PVOID)&Time, sizeof(LONGLONG)); } HRESULT @@ -376,8 +511,8 @@ STDMETHODCALLTYPE CKsProxy::KsGetCorrelatedTime( KSCORRELATED_TIME* CorrelatedTime) { - OutputDebugStringW(L"CKsProxy::KsGetCorrelatedTime NotImplemented\n"); - return E_NOTIMPL; + OutputDebugStringW(L"CKsProxy::KsGetCorrelatedTime\n"); + return PerformClockProperty(KSPROPERTY_CLOCK_CORRELATEDTIME, KSPROPERTY_TYPE_GET, (PVOID)CorrelatedTime, sizeof(KSCORRELATED_TIME)); } HRESULT @@ -385,8 +520,8 @@ STDMETHODCALLTYPE CKsProxy::KsSetCorrelatedTime( KSCORRELATED_TIME* CorrelatedTime) { - OutputDebugStringW(L"CKsProxy::KsSetCorrelatedTime NotImplemented\n"); - return E_NOTIMPL; + OutputDebugStringW(L"CKsProxy::KsSetCorrelatedTime\n"); + return PerformClockProperty(KSPROPERTY_CLOCK_CORRELATEDTIME, KSPROPERTY_TYPE_SET, (PVOID)CorrelatedTime, sizeof(KSCORRELATED_TIME)); } HRESULT @@ -394,8 +529,8 @@ STDMETHODCALLTYPE CKsProxy::KsGetCorrelatedPhysicalTime( KSCORRELATED_TIME* CorrelatedTime) { - OutputDebugStringW(L"CKsProxy::KsGetCorrelatedPhysicalTime NotImplemented\n"); - return E_NOTIMPL; + OutputDebugStringW(L"CKsProxy::KsGetCorrelatedPhysicalTime\n"); + return PerformClockProperty(KSPROPERTY_CLOCK_CORRELATEDPHYSICALTIME, KSPROPERTY_TYPE_GET, (PVOID)CorrelatedTime, sizeof(KSCORRELATED_TIME)); } HRESULT @@ -403,8 +538,8 @@ STDMETHODCALLTYPE CKsProxy::KsSetCorrelatedPhysicalTime( KSCORRELATED_TIME* CorrelatedTime) { - OutputDebugStringW(L"CKsProxy::KsSetCorrelatedPhysicalTime NotImplemented\n"); - return E_NOTIMPL; + OutputDebugStringW(L"CKsProxy::KsSetCorrelatedPhysicalTime\n"); + return PerformClockProperty(KSPROPERTY_CLOCK_CORRELATEDPHYSICALTIME, KSPROPERTY_TYPE_SET, (PVOID)CorrelatedTime, sizeof(KSCORRELATED_TIME)); } HRESULT @@ -412,8 +547,8 @@ STDMETHODCALLTYPE CKsProxy::KsGetResolution( KSRESOLUTION* Resolution) { - OutputDebugStringW(L"CKsProxy::KsGetResolution NotImplemented\n"); - return E_NOTIMPL; + OutputDebugStringW(L"CKsProxy::KsGetResolution\n"); + return PerformClockProperty(KSPROPERTY_CLOCK_RESOLUTION, KSPROPERTY_TYPE_GET, (PVOID)Resolution, sizeof(KSRESOLUTION)); } HRESULT @@ -421,8 +556,8 @@ STDMETHODCALLTYPE CKsProxy::KsGetState( KSSTATE* State) { - OutputDebugStringW(L"CKsProxy::KsGetState NotImplemented\n"); - return E_NOTIMPL; + OutputDebugStringW(L"CKsProxy::KsGetState\n"); + return PerformClockProperty(KSPROPERTY_CLOCK_STATE, KSPROPERTY_TYPE_GET, (PVOID)State, sizeof(KSSTATE)); } //------------------------------------------------------------------- @@ -433,8 +568,40 @@ STDMETHODCALLTYPE CKsProxy::GetTime( REFERENCE_TIME *pTime) { - OutputDebugStringW(L"CKsProxy::GetTime NotImplemented\n"); - return E_NOTIMPL; + HRESULT hr; + KSPROPERTY Property; + ULONG BytesReturned; + + OutputDebugStringW(L"CKsProxy::GetTime\n"); + + if (!pTime) + return E_POINTER; + + // + //FIXME locks + // + + if (!m_hClock) + { + // create clock + hr = CreateClockInstance(); + if (FAILED(hr)) + return hr; + } + + // setup request + Property.Set = KSPROPSETID_Clock; + Property.Id = KSPROPERTY_CLOCK_TIME; + Property.Flags = KSPROPERTY_TYPE_GET; + + // perform request + hr = KsSynchronousDeviceControl(m_hClock, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pTime, sizeof(REFERENCE_TIME), &BytesReturned); + + // TODO + // increment value + // + + return hr; } HRESULT @@ -445,8 +612,62 @@ CKsProxy::AdviseTime( HEVENT hEvent, DWORD_PTR *pdwAdviseCookie) { - OutputDebugStringW(L"CKsProxy::AdviseTime NotImplemented\n"); - return E_NOTIMPL; + HRESULT hr; + KSEVENT Property; + ULONG BytesReturned; + PKSEVENT_TIME_MARK Event; + + OutputDebugStringW(L"CKsProxy::AdviseTime\n"); + + // + //FIXME locks + // + + if (!pdwAdviseCookie) + return E_POINTER; + + if (!m_hClock) + { + // create clock + hr = CreateClockInstance(); + if (FAILED(hr)) + return hr; + } + + // allocate event entry + Event = (PKSEVENT_TIME_MARK)CoTaskMemAlloc(sizeof(KSEVENT_TIME_MARK)); + if (Event) + { + // setup request + Property.Set = KSEVENTSETID_Clock; + Property.Id = KSEVENT_CLOCK_POSITION_MARK; + Property.Flags = KSEVENT_TYPE_ENABLE; + + Event->EventData.NotificationType = KSEVENTF_EVENT_HANDLE; + Event->EventData.EventHandle.Event = (HANDLE)hEvent; + Event->EventData.Alignment.Alignment[0] = 0; + Event->EventData.Alignment.Alignment[1] = 0; + Event->MarkTime = baseTime + streamTime; + + // perform request + hr = KsSynchronousDeviceControl(m_hClock, IOCTL_KS_ENABLE_EVENT, (PVOID)&Property, sizeof(KSEVENT), (PVOID)Event, sizeof(KSEVENT_TIME_MARK), &BytesReturned); + if (SUCCEEDED(hr)) + { + // store event handle + *pdwAdviseCookie = (DWORD_PTR)Event; + } + else + { + // failed to enable event + CoTaskMemFree(Event); + } + } + else + { + hr = E_OUTOFMEMORY; + } + + return hr; } HRESULT @@ -457,8 +678,63 @@ CKsProxy::AdvisePeriodic( HSEMAPHORE hSemaphore, DWORD_PTR *pdwAdviseCookie) { - OutputDebugStringW(L"CKsProxy::AdvisePeriodic NotImplemented\n"); - return E_NOTIMPL; + HRESULT hr; + KSEVENT Property; + ULONG BytesReturned; + PKSEVENT_TIME_INTERVAL Event; + + OutputDebugStringW(L"CKsProxy::AdvisePeriodic\n"); + + // + //FIXME locks + // + + if (!pdwAdviseCookie) + return E_POINTER; + + if (!m_hClock) + { + // create clock + hr = CreateClockInstance(); + if (FAILED(hr)) + return hr; + } + + // allocate event entry + Event = (PKSEVENT_TIME_INTERVAL)CoTaskMemAlloc(sizeof(KSEVENT_TIME_INTERVAL)); + if (Event) + { + // setup request + Property.Set = KSEVENTSETID_Clock; + Property.Id = KSEVENT_CLOCK_INTERVAL_MARK; + Property.Flags = KSEVENT_TYPE_ENABLE; + + Event->EventData.NotificationType = KSEVENTF_SEMAPHORE_HANDLE; + Event->EventData.SemaphoreHandle.Semaphore = (HANDLE)hSemaphore; + Event->EventData.SemaphoreHandle.Reserved = 0; + Event->EventData.SemaphoreHandle.Adjustment = 1; + Event->TimeBase = startTime; + Event->Interval = periodTime; + + // perform request + hr = KsSynchronousDeviceControl(m_hClock, IOCTL_KS_ENABLE_EVENT, (PVOID)&Property, sizeof(KSEVENT), (PVOID)Event, sizeof(KSEVENT_TIME_INTERVAL), &BytesReturned); + if (SUCCEEDED(hr)) + { + // store event handle + *pdwAdviseCookie = (DWORD_PTR)Event; + } + else + { + // failed to enable event + CoTaskMemFree(Event); + } + } + else + { + hr = E_OUTOFMEMORY; + } + + return hr; } HRESULT @@ -466,8 +742,28 @@ STDMETHODCALLTYPE CKsProxy::Unadvise( DWORD_PTR dwAdviseCookie) { - OutputDebugStringW(L"CKsProxy::Unadvise NotImplemented\n"); - return E_NOTIMPL; + HRESULT hr; + ULONG BytesReturned; + + OutputDebugStringW(L"CKsProxy::Unadvise\n"); + + if (m_hClock) + { + //lets disable the event + hr = KsSynchronousDeviceControl(m_hClock, IOCTL_KS_DISABLE_EVENT, (PVOID)dwAdviseCookie, sizeof(KSEVENTDATA), 0, 0, &BytesReturned); + if (SUCCEEDED(hr)) + { + // lets free event data + CoTaskMemFree((LPVOID)dwAdviseCookie); + } + } + else + { + // no clock available + hr = E_FAIL; + } + + return hr; } //------------------------------------------------------------------- @@ -478,8 +774,55 @@ STDMETHODCALLTYPE CKsProxy::GetCapabilities( DWORD *pCapabilities) { - OutputDebugStringW(L"CKsProxy::GetCapabilities NotImplemented\n"); - return E_NOTIMPL; + KSPROPERTY Property; + ULONG BytesReturned, Index; + HRESULT hr = S_OK; + DWORD TempCaps; + + Property.Set = KSPROPSETID_MediaSeeking; + Property.Id = KSPROPERTY_MEDIASEEKING_CAPABILITIES; + Property.Flags = KSPROPERTY_TYPE_GET; + + OutputDebugStringW(L"CKsProxy::GetCapabilities\n"); + + if (!pCapabilities) + return E_POINTER; + + + *pCapabilities = (KS_SEEKING_CanSeekAbsolute | KS_SEEKING_CanSeekForwards | KS_SEEKING_CanSeekBackwards | KS_SEEKING_CanGetCurrentPos | + KS_SEEKING_CanGetStopPos | KS_SEEKING_CanGetDuration | KS_SEEKING_CanPlayBackwards); + + KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&pCapabilities, sizeof(KS_SEEKING_CAPABILITIES), &BytesReturned); + // check if plugins support it + for(Index = 0; Index < m_Plugins.size(); Index++) + { + // get plugin + IUnknown * Plugin = m_Plugins[Index]; + + if (!Plugin) + continue; + + // query for IMediaSeeking interface + IMediaSeeking *pSeek = NULL; + hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek); + if (FAILED(hr)) + { + *pCapabilities = 0; + return hr; + } + + TempCaps = 0; + // set time format + hr = pSeek->GetCapabilities(&TempCaps); + if (SUCCEEDED(hr)) + { + // and with supported flags + *pCapabilities = (*pCapabilities & TempCaps); + } + // release IMediaSeeking interface + pSeek->Release(); + } + return hr; } HRESULT @@ -487,27 +830,49 @@ STDMETHODCALLTYPE CKsProxy::CheckCapabilities( DWORD *pCapabilities) { - OutputDebugStringW(L"CKsProxy::CheckCapabilities NotImplemented\n"); - return E_NOTIMPL; + DWORD Capabilities; + HRESULT hr; + + OutputDebugStringW(L"CKsProxy::CheckCapabilities\n"); + + if (!pCapabilities) + return E_POINTER; + + if (!*pCapabilities) + return E_FAIL; + + hr = GetCapabilities(&Capabilities); + if (SUCCEEDED(hr)) + { + if ((Capabilities | *pCapabilities) == Capabilities) + { + // all present + return S_OK; + } + + Capabilities = (Capabilities & *pCapabilities); + if (Capabilities) + { + // not all present + *pCapabilities = Capabilities; + return S_FALSE; + } + // no capabilities are present + return E_FAIL; + } + + return hr; } HRESULT STDMETHODCALLTYPE -CKsProxy::IsFormatSupported( - const GUID *pFormat) +CKsProxy::GetMediaSeekingFormats( + PKSMULTIPLE_ITEM *FormatList) { KSPROPERTY Property; - PKSMULTIPLE_ITEM FormatList; - LPGUID pGuid; - ULONG Index; - HRESULT hr = S_FALSE; + HRESULT hr; ULONG BytesReturned; - OutputDebugStringW(L"CKsProxy::IsFormatSupported\n"); - - if (!pFormat) - return E_POINTER; - Property.Set = KSPROPSETID_MediaSeeking; Property.Id = KSPROPERTY_MEDIASEEKING_FORMATS; Property.Flags = KSPROPERTY_TYPE_GET; @@ -518,21 +883,49 @@ CKsProxy::IsFormatSupported( if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_MORE_DATA)) { // allocate format list - FormatList = (PKSMULTIPLE_ITEM)CoTaskMemAlloc(BytesReturned); - if (!FormatList) + *FormatList = (PKSMULTIPLE_ITEM)CoTaskMemAlloc(BytesReturned); + if (!*FormatList) { // not enough memory return E_OUTOFMEMORY; } // get format list - hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)FormatList, BytesReturned, &BytesReturned); + hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)*FormatList, BytesReturned, &BytesReturned); if (FAILED(hr)) { // failed to query format list CoTaskMemFree(FormatList); - return hr; } + } + return hr; +} + +HRESULT +STDMETHODCALLTYPE +CKsProxy::IsFormatSupported( + const GUID *pFormat) +{ + PKSMULTIPLE_ITEM FormatList; + LPGUID pGuid; + ULONG Index; + HRESULT hr = S_FALSE; + + WCHAR Buffer[100]; + LPOLESTR pstr; + StringFromCLSID(*pFormat, &pstr); + swprintf(Buffer, L"CKsProxy::IsFormatSupported %s\n",pstr); + OutputDebugStringW(Buffer); + + if (!pFormat) + return E_POINTER; + + // get media formats + hr = GetMediaSeekingFormats(&FormatList); + if (SUCCEEDED(hr)) + { + swprintf(Buffer, L"CKsProxy::IsFormatSupported NumFormat %lu\n",FormatList->Count); + OutputDebugStringW(Buffer); //iterate through format list pGuid = (LPGUID)(FormatList + 1); @@ -540,14 +933,11 @@ CKsProxy::IsFormatSupported( { if (IsEqualGUID(*pGuid, *pFormat)) { - OutputDebugStringW(L"CKsProxy::IsFormatSupported found format\n"); CoTaskMemFree(FormatList); return S_OK; } pGuid++; } - - OutputDebugStringW(L"CKsProxy::IsFormatSupported FormatNotFound\n"); // free format list CoTaskMemFree(FormatList); } @@ -589,8 +979,55 @@ STDMETHODCALLTYPE CKsProxy::QueryPreferredFormat( GUID *pFormat) { - OutputDebugStringW(L"CKsProxy::QueryPreferredFormat NotImplemented\n"); - return E_NOTIMPL; + PKSMULTIPLE_ITEM FormatList; + HRESULT hr; + ULONG Index; + + OutputDebugStringW(L"CKsProxy::QueryPreferredFormat\n"); + + if (!pFormat) + return E_POINTER; + + hr = GetMediaSeekingFormats(&FormatList); + if (SUCCEEDED(hr)) + { + if (FormatList->Count) + { + CopyMemory(pFormat, (FormatList + 1), sizeof(GUID)); + CoTaskMemFree(FormatList); + return S_OK; + } + CoTaskMemFree(FormatList); + } + if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND)) + { + // check if plugins support it + for(Index = 0; Index < m_Plugins.size(); Index++) + { + // get plugin + IUnknown * Plugin = m_Plugins[Index]; + + if (!Plugin) + continue; + + // query for IMediaSeeking interface + IMediaSeeking *pSeek = NULL; + hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek); + if (SUCCEEDED(hr)) + { + // get preferred time format + hr = pSeek->QueryPreferredFormat(pFormat); + // release IMediaSeeking interface + pSeek->Release(); + + if (hr != S_FALSE) + return hr; + } + } + hr = S_FALSE; + } + + return hr; } HRESULT @@ -598,8 +1035,45 @@ STDMETHODCALLTYPE CKsProxy::GetTimeFormat( GUID *pFormat) { - OutputDebugStringW(L"CKsProxy::GetTimeFormat NotImplemented\n"); - return E_NOTIMPL; + KSPROPERTY Property; + ULONG BytesReturned, Index; + HRESULT hr; + + Property.Set = KSPROPSETID_MediaSeeking; + Property.Id = KSPROPERTY_MEDIASEEKING_TIMEFORMAT; + Property.Flags = KSPROPERTY_TYPE_GET; + + OutputDebugStringW(L"CKsProxy::GetTimeFormat\n"); + + hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pFormat, sizeof(GUID), &BytesReturned); + if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND)) + { + // check if plugins support it + for(Index = 0; Index < m_Plugins.size(); Index++) + { + hr = E_NOTIMPL; + // get plugin + IUnknown * Plugin = m_Plugins[Index]; + + if (!Plugin) + continue; + + // query for IMediaSeeking interface + IMediaSeeking *pSeek = NULL; + hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek); + if (SUCCEEDED(hr)) + { + // set time format + hr = pSeek->GetTimeFormat(pFormat); + // release IMediaSeeking interface + pSeek->Release(); + + if (hr != S_FALSE) + break; + } + } + } + return hr; } HRESULT @@ -607,8 +1081,17 @@ STDMETHODCALLTYPE CKsProxy::IsUsingTimeFormat( const GUID *pFormat) { - OutputDebugStringW(L"CKsProxy::IsUsingTimeFormat NotImplemented\n"); - return E_NOTIMPL; + GUID Format; + + OutputDebugStringW(L"CKsProxy::IsUsingTimeFormat\n"); + + if (FAILED(QueryPreferredFormat(&Format))) + return S_FALSE; + + if (IsEqualGUID(Format, *pFormat)) + return S_OK; + else + return S_FALSE; } HRESULT @@ -616,8 +1099,47 @@ STDMETHODCALLTYPE CKsProxy::SetTimeFormat( const GUID *pFormat) { - OutputDebugStringW(L"CKsProxy::SetTimeFormat NotImplemented\n"); - return E_NOTIMPL; + KSPROPERTY Property; + ULONG BytesReturned, Index; + HRESULT hr; + + Property.Set = KSPROPSETID_MediaSeeking; + Property.Id = KSPROPERTY_MEDIASEEKING_TIMEFORMAT; + Property.Flags = KSPROPERTY_TYPE_SET; + + OutputDebugStringW(L"CKsProxy::SetTimeFormat\n"); + + hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pFormat, sizeof(GUID), &BytesReturned); + if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND)) + { + // check if plugins support it + for(Index = 0; Index < m_Plugins.size(); Index++) + { + hr = E_NOTIMPL; + // get plugin + IUnknown * Plugin = m_Plugins[Index]; + + if (!Plugin) + continue; + + // query for IMediaSeeking interface + IMediaSeeking *pSeek = NULL; + hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek); + if (FAILED(hr)) + { + //not supported + break; + } + // set time format + hr = pSeek->SetTimeFormat(pFormat); + // release IMediaSeeking interface + pSeek->Release(); + + if (FAILED(hr)) + break; + } + } + return hr; } HRESULT @@ -625,8 +1147,45 @@ STDMETHODCALLTYPE CKsProxy::GetDuration( LONGLONG *pDuration) { - OutputDebugStringW(L"CKsProxy::GetDuration NotImplemented\n"); - return E_NOTIMPL; + KSPROPERTY Property; + ULONG BytesReturned, Index; + HRESULT hr; + + Property.Set = KSPROPSETID_MediaSeeking; + Property.Id = KSPROPERTY_MEDIASEEKING_DURATION; + Property.Flags = KSPROPERTY_TYPE_GET; + + OutputDebugStringW(L"CKsProxy::GetDuration\n"); + + hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pDuration, sizeof(LONGLONG), &BytesReturned); + if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND)) + { + // check if plugins support it + for(Index = 0; Index < m_Plugins.size(); Index++) + { + hr = E_NOTIMPL; + // get plugin + IUnknown * Plugin = m_Plugins[Index]; + + if (!Plugin) + continue; + + // query for IMediaSeeking interface + IMediaSeeking *pSeek = NULL; + hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek); + if (SUCCEEDED(hr)) + { + // get duration + hr = pSeek->GetStopPosition(pDuration); + // release IMediaSeeking interface + pSeek->Release(); + + if (hr != S_FALSE) // plugin implements it + break; + } + } + } + return hr; } HRESULT @@ -634,8 +1193,45 @@ STDMETHODCALLTYPE CKsProxy::GetStopPosition( LONGLONG *pStop) { - OutputDebugStringW(L"CKsProxy::GetStopPosition NotImplemented\n"); - return E_NOTIMPL; + KSPROPERTY Property; + ULONG BytesReturned, Index; + HRESULT hr; + + Property.Set = KSPROPSETID_MediaSeeking; + Property.Id = KSPROPERTY_MEDIASEEKING_STOPPOSITION; + Property.Flags = KSPROPERTY_TYPE_GET; + + OutputDebugStringW(L"CKsProxy::GetStopPosition\n"); + + hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pStop, sizeof(LONGLONG), &BytesReturned); + if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND)) + { + // check if plugins support it + for(Index = 0; Index < m_Plugins.size(); Index++) + { + hr = E_NOTIMPL; + // get plugin + IUnknown * Plugin = m_Plugins[Index]; + + if (!Plugin) + continue; + + // query for IMediaSeeking interface + IMediaSeeking *pSeek = NULL; + hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek); + if (SUCCEEDED(hr)) + { + // get stop position + hr = pSeek->GetStopPosition(pStop); + // release IMediaSeeking interface + pSeek->Release(); + + if (hr != S_FALSE) // plugin implements it + break; + } + } + } + return hr; } HRESULT @@ -643,8 +1239,45 @@ STDMETHODCALLTYPE CKsProxy::GetCurrentPosition( LONGLONG *pCurrent) { - OutputDebugStringW(L"CKsProxy::GetCurrentPosition NotImplemented\n"); - return E_NOTIMPL; + KSPROPERTY Property; + ULONG BytesReturned, Index; + HRESULT hr; + + Property.Set = KSPROPSETID_MediaSeeking; + Property.Id = KSPROPERTY_MEDIASEEKING_POSITION; + Property.Flags = KSPROPERTY_TYPE_GET; + + OutputDebugStringW(L"CKsProxy::GetCurrentPosition\n"); + + hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pCurrent, sizeof(LONGLONG), &BytesReturned); + if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND)) + { + // check if plugins support it + for(Index = 0; Index < m_Plugins.size(); Index++) + { + hr = E_NOTIMPL; + // get plugin + IUnknown * Plugin = m_Plugins[Index]; + + if (!Plugin) + continue; + + // query for IMediaSeeking interface + IMediaSeeking *pSeek = NULL; + hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek); + if (SUCCEEDED(hr)) + { + // get current position + hr = pSeek->GetCurrentPosition(pCurrent); + // release IMediaSeeking interface + pSeek->Release(); + + if (hr != S_FALSE) // plugin implements it + break; + } + } + } + return hr; } HRESULT @@ -655,8 +1288,74 @@ CKsProxy::ConvertTimeFormat( LONGLONG Source, const GUID *pSourceFormat) { - OutputDebugStringW(L"CKsProxy::ConvertTimeFormat NotImplemented\n"); - return E_NOTIMPL; + KSP_TIMEFORMAT Property; + ULONG BytesReturned, Index; + GUID SourceFormat, TargetFormat; + HRESULT hr; + + Property.Property.Set = KSPROPSETID_MediaSeeking; + Property.Property.Id = KSPROPERTY_MEDIASEEKING_CONVERTTIMEFORMAT; + Property.Property.Flags = KSPROPERTY_TYPE_GET; + + OutputDebugStringW(L"CKsProxy::ConvertTimeFormat\n"); + + if (!pTargetFormat) + { + // get current format + hr = GetTimeFormat(&TargetFormat); + if (FAILED(hr)) + return hr; + + pTargetFormat = &TargetFormat; + } + + if (!pSourceFormat) + { + // get current format + hr = GetTimeFormat(&SourceFormat); + if (FAILED(hr)) + return hr; + + pSourceFormat = &SourceFormat; + } + + Property.SourceFormat = *pSourceFormat; + Property.TargetFormat = *pTargetFormat; + Property.Time = Source; + + + hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSP_TIMEFORMAT), (PVOID)pTarget, sizeof(LONGLONG), &BytesReturned); + if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND)) + { + //default error + hr = E_NOTIMPL; + + // check if plugins support it + for(Index = 0; Index < m_Plugins.size(); Index++) + { + // get plugin + IUnknown * Plugin = m_Plugins[Index]; + + if (!Plugin) + continue; + + // query for IMediaSeeking interface + IMediaSeeking *pSeek = NULL; + hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek); + if (SUCCEEDED(hr)) + { + // convert time format + hr = pSeek->ConvertTimeFormat(pTarget, pTargetFormat, Source, pSourceFormat); + // release IMediaSeeking interface + pSeek->Release(); + + if (hr != S_FALSE) // plugin implements it + break; + } + } + } + + return hr; } HRESULT @@ -667,8 +1366,71 @@ CKsProxy::SetPositions( LONGLONG *pStop, DWORD dwStopFlags) { - OutputDebugStringW(L"CKsProxy::SetPositions NotImplemented\n"); - return E_NOTIMPL; + KSPROPERTY Property; + KSPROPERTY_POSITIONS Positions; + ULONG BytesReturned, Index; + HRESULT hr; + + Property.Set = KSPROPSETID_MediaSeeking; + Property.Id = KSPROPERTY_MEDIASEEKING_POSITIONS; + Property.Flags = KSPROPERTY_TYPE_SET; + + Positions.Current = *pCurrent; + Positions.CurrentFlags = (KS_SEEKING_FLAGS)dwCurrentFlags; + Positions.Stop = *pStop; + Positions.StopFlags = (KS_SEEKING_FLAGS)dwStopFlags; + + OutputDebugStringW(L"CKsProxy::SetPositions\n"); + + hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&Positions, sizeof(KSPROPERTY_POSITIONS), &BytesReturned); + if (SUCCEEDED(hr)) + { + if (dwCurrentFlags & AM_SEEKING_ReturnTime) + { + // retrieve current position + hr = GetCurrentPosition(pCurrent); + } + + if (SUCCEEDED(hr)) + { + if (dwStopFlags & AM_SEEKING_ReturnTime) + { + // retrieve current position + hr = GetStopPosition(pStop); + } + } + return hr; + } + if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND)) + { + hr = E_NOTIMPL; + + // check if plugins support it + for(Index = 0; Index < m_Plugins.size(); Index++) + { + // get plugin + IUnknown * Plugin = m_Plugins[Index]; + + if (!Plugin) + continue; + + // query for IMediaSeeking interface + IMediaSeeking *pSeek = NULL; + hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek); + if (SUCCEEDED(hr)) + { + // set positions + hr = pSeek->SetPositions(pCurrent, dwCurrentFlags, pStop, dwStopFlags); + // release IMediaSeeking interface + pSeek->Release(); + + if (FAILED(hr)) + break; + } + } + } + + return hr; } HRESULT @@ -677,8 +1439,15 @@ CKsProxy::GetPositions( LONGLONG *pCurrent, LONGLONG *pStop) { - OutputDebugStringW(L"CKsProxy::GetPositions NotImplemented\n"); - return E_NOTIMPL; + HRESULT hr; + + OutputDebugStringW(L"CKsProxy::GetPositions\n"); + + hr = GetCurrentPosition(pCurrent); + if (SUCCEEDED(hr)) + hr = GetStopPosition(pStop); + + return hr; } HRESULT @@ -687,8 +1456,52 @@ CKsProxy::GetAvailable( LONGLONG *pEarliest, LONGLONG *pLatest) { - OutputDebugStringW(L"CKsProxy::GetAvailable NotImplemented\n"); - return E_NOTIMPL; + KSPROPERTY Property; + KSPROPERTY_MEDIAAVAILABLE Media; + ULONG BytesReturned, Index; + HRESULT hr; + + Property.Set = KSPROPSETID_MediaSeeking; + Property.Id = KSPROPERTY_MEDIASEEKING_AVAILABLE; + Property.Flags = KSPROPERTY_TYPE_GET; + + OutputDebugStringW(L"CKsProxy::GetAvailable\n"); + + hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&Media, sizeof(KSPROPERTY_MEDIAAVAILABLE), &BytesReturned); + if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND)) + { + // check if plugins support it + for(Index = 0; Index < m_Plugins.size(); Index++) + { + hr = E_NOTIMPL; + // get plugin + IUnknown * Plugin = m_Plugins[Index]; + + if (!Plugin) + continue; + + // query for IMediaSeeking interface + IMediaSeeking *pSeek = NULL; + hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek); + if (SUCCEEDED(hr)) + { + // delegate call + hr = pSeek->GetAvailable(pEarliest, pLatest); + // release IMediaSeeking interface + pSeek->Release(); + + if (hr != S_FALSE) // plugin implements it + break; + } + } + } + else if (SUCCEEDED(hr)) + { + *pEarliest = Media.Earliest; + *pLatest = Media.Latest; + } + + return hr; } HRESULT @@ -696,7 +1509,7 @@ STDMETHODCALLTYPE CKsProxy::SetRate( double dRate) { - OutputDebugStringW(L"CKsProxy::SetRate NotImplemented\n"); + OutputDebugStringW(L"CKsProxy::SetRate\n"); return E_NOTIMPL; } @@ -705,7 +1518,7 @@ STDMETHODCALLTYPE CKsProxy::GetRate( double *pdRate) { - OutputDebugStringW(L"CKsProxy::GetRate NotImplemented\n"); + OutputDebugStringW(L"CKsProxy::GetRate\n"); return E_NOTIMPL; } @@ -714,8 +1527,45 @@ STDMETHODCALLTYPE CKsProxy::GetPreroll( LONGLONG *pllPreroll) { - OutputDebugStringW(L"CKsProxy::GetPreroll NotImplemented\n"); - return E_NOTIMPL; + KSPROPERTY Property; + ULONG BytesReturned, Index; + HRESULT hr; + + Property.Set = KSPROPSETID_MediaSeeking; + Property.Id = KSPROPERTY_MEDIASEEKING_PREROLL; + Property.Flags = KSPROPERTY_TYPE_GET; + + OutputDebugStringW(L"CKsProxy::GetPreroll\n"); + + hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pllPreroll, sizeof(LONGLONG), &BytesReturned); + if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND)) + { + // check if all plugins support it + for(Index = 0; Index < m_Plugins.size(); Index++) + { + // get plugin + IUnknown * Plugin = m_Plugins[Index]; + + if (!Plugin) + continue; + + // query for IMediaSeeking interface + IMediaSeeking *pSeek = NULL; + hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek); + if (SUCCEEDED(hr)) + { + // get preroll + hr = pSeek->GetPreroll(pllPreroll); + // release IMediaSeeking interface + pSeek->Release(); + + if (hr != S_FALSE) // plugin implements it + break; + } + } + hr = E_NOTIMPL; + } + return hr; } //------------------------------------------------------------------- @@ -771,6 +1621,7 @@ CKsProxy::KsProperty( ULONG* BytesReturned) { assert(m_hDevice != 0); + OutputDebugStringW(L"CKsProxy::KsProperty\n"); return KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)Property, PropertyLength, (PVOID)PropertyData, DataLength, BytesReturned); } @@ -784,6 +1635,7 @@ CKsProxy::KsMethod( ULONG* BytesReturned) { assert(m_hDevice != 0); + OutputDebugStringW(L"CKsProxy::KsMethod\n"); return KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_METHOD, (PVOID)Method, MethodLength, (PVOID)MethodData, DataLength, BytesReturned); } @@ -797,7 +1649,7 @@ CKsProxy::KsEvent( ULONG* BytesReturned) { assert(m_hDevice != 0); - + OutputDebugStringW(L"CKsProxy::KsEvent\n"); if (EventLength) return KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_ENABLE_EVENT, (PVOID)Event, EventLength, (PVOID)EventData, DataLength, BytesReturned); else @@ -820,6 +1672,8 @@ CKsProxy::Set( { ULONG BytesReturned; + OutputDebugStringW(L"CKsProxy::Set\n"); + if (cbInstanceData) { PKSPROPERTY Property = (PKSPROPERTY)CoTaskMemAlloc(sizeof(KSPROPERTY) + cbInstanceData); @@ -862,6 +1716,8 @@ CKsProxy::Get( { ULONG BytesReturned; + OutputDebugStringW(L"CKsProxy::Get\n"); + if (cbInstanceData) { PKSPROPERTY Property = (PKSPROPERTY)CoTaskMemAlloc(sizeof(KSPROPERTY) + cbInstanceData); @@ -901,6 +1757,8 @@ CKsProxy::QuerySupported( KSPROPERTY Property; ULONG BytesReturned; + OutputDebugStringW(L"CKsProxy::QuerySupported\n"); + Property.Set = guidPropSet; Property.Id = dwPropID; Property.Flags = KSPROPERTY_TYPE_SETSUPPORT; @@ -922,8 +1780,23 @@ CKsProxy::CreateNodeInstance( REFGUID InterfaceId, LPVOID* Interface) { - OutputDebugStringW(L"CKsProxy::CreateNodeInstance NotImplemented\n"); - return E_NOTIMPL; + HRESULT hr; + + OutputDebugStringW(L"CKsProxy::CreateNodeInstance\n"); + + *Interface = NULL; + + if (IsEqualIID(IID_IUnknown, InterfaceId) || !UnkOuter) + { + hr = CKsNode_Constructor(UnkOuter, m_hDevice, NodeId, DesiredAccess, InterfaceId, Interface); + } + else + { + // interface not supported + hr = E_NOINTERFACE; + } + + return hr; } //------------------------------------------------------------------- @@ -1067,6 +1940,9 @@ HRESULT STDMETHODCALLTYPE CKsProxy::DeviceInfo(CLSID *pclsidInterfaceClass, LPWSTR *pwszSymbolicLink) { + + OutputDebugStringW(L"CKsProxy::DeviceInfo\n"); + if (!m_DevicePath) { // object not initialized @@ -1090,6 +1966,8 @@ HRESULT STDMETHODCALLTYPE CKsProxy::Reassociate(void) { + OutputDebugStringW(L"CKsProxy::Reassociate\n"); + if (!m_DevicePath || m_hDevice) { // file path not available @@ -1111,6 +1989,8 @@ HRESULT STDMETHODCALLTYPE CKsProxy::Disassociate(void) { + OutputDebugStringW(L"CKsProxy::Disassociate\n"); + if (!m_hDevice) return E_HANDLE; @@ -1119,7 +1999,17 @@ CKsProxy::Disassociate(void) return NOERROR; } +//------------------------------------------------------------------- +// IKsClock interface +// +HANDLE +STDMETHODCALLTYPE +CKsProxy::KsGetClockHandle() +{ + OutputDebugStringW(L"CKsProxy::KsGetClockHandle\n"); + return m_hClock; +} //------------------------------------------------------------------- @@ -1130,6 +2020,7 @@ HANDLE STDMETHODCALLTYPE CKsProxy::KsGetObjectHandle() { + OutputDebugStringW(L"CKsProxy::KsGetObjectHandle\n"); return m_hDevice; } @@ -1140,6 +2031,7 @@ HRESULT STDMETHODCALLTYPE CKsProxy::InitNew( void) { + OutputDebugStringW(L"CKsProxy::InitNew\n"); return S_OK; } @@ -1512,6 +2404,7 @@ CKsProxy::Load(IPropertyBag *pPropBag, IErrorLog *pErrorLog) HDEVINFO hList; SP_DEVICE_INTERFACE_DATA DeviceInterfaceData; + OutputDebugStringW(L"CKsProxy::Load\n"); // read device path varName.vt = VT_BSTR; @@ -1524,6 +2417,10 @@ CKsProxy::Load(IPropertyBag *pPropBag, IErrorLog *pErrorLog) return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError()); } + OutputDebugStringW(L"DevicePath: "); + OutputDebugStringW(varName.bstrVal); + OutputDebugStringW(L"\n"); + // create device list hList = SetupDiCreateDeviceInfoListExW(NULL, NULL, NULL, NULL); if (hList == INVALID_HANDLE_VALUE) @@ -1591,6 +2488,7 @@ HRESULT STDMETHODCALLTYPE CKsProxy::Save(IPropertyBag *pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties) { + OutputDebugStringW(L"CKsProxy::Save\n"); return E_NOTIMPL; } @@ -1603,8 +2501,10 @@ STDMETHODCALLTYPE CKsProxy::GetClassID( CLSID *pClassID) { - OutputDebugStringW(L"CKsProxy::GetClassID : NotImplemented\n"); - return E_NOTIMPL; + OutputDebugStringW(L"CKsProxy::GetClassID\n"); + CopyMemory(pClassID, &CLSID_Proxy, sizeof(GUID)); + + return S_OK; } HRESULT @@ -1647,6 +2547,90 @@ STDMETHODCALLTYPE CKsProxy::SetSyncSource( IReferenceClock *pClock) { + HRESULT hr; + IKsClock *pKsClock; + HANDLE hClock, hPin; + ULONG Index; + IPin * pin; + IKsObject * pObject; + KSPROPERTY Property; + ULONG BytesReturned; + PIN_DIRECTION PinDir; + +// Plug In Distributor: IKsClock + OutputDebugStringW(L"CKsProxy::SetSyncSource\n"); + + // FIXME + // need locks + + if (!pClock) + return E_POINTER; + + hr = pClock->QueryInterface(IID_IKsClock, (void**)&pKsClock); + if (FAILED(hr)) + return hr; + + // get clock handle + hClock = pKsClock->KsGetClockHandle(); + if (!hClock || hClock == INVALID_HANDLE_VALUE) + { + // failed + pKsClock->Release(); + return E_FAIL; + } + + // distribute clock to all pins + for(Index = 0; Index < m_Pins.size(); Index++) + { + // get current pin + pin = m_Pins[Index]; + if (!pin) + continue; + + // get IKsObject interface + hr = pin->QueryInterface(IID_IKsObject, (void **)&pObject); + if (SUCCEEDED(hr)) + { + // get pin handle + hPin = pObject->KsGetObjectHandle(); + if (hPin != INVALID_HANDLE_VALUE && hPin) + { + // set clock + Property.Set = KSPROPSETID_Stream; + Property.Id = KSPROPERTY_STREAM_MASTERCLOCK; + Property.Flags = KSPROPERTY_TYPE_SET; + + // set master clock + hr = KsSynchronousDeviceControl(hPin, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)hClock, sizeof(HANDLE), &BytesReturned); + + if (FAILED(hr)) + { + if (hr != MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND) && + hr != MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND)) + { + // failed to set master clock + pKsClock->Release(); + pObject->Release(); + return hr; + } + } + } + // release IKsObject + pObject->Release(); + } + + // now get the direction + hr = pin->QueryDirection(&PinDir); + if (SUCCEEDED(hr)) + { + if (PinDir == PINDIR_OUTPUT) + { + // notify pin via + //CBaseStreamControl::SetSyncSource(pClock) + } + } + } + if (pClock) { pClock->AddRef(); @@ -1666,6 +2650,8 @@ STDMETHODCALLTYPE CKsProxy::GetSyncSource( IReferenceClock **pClock) { + OutputDebugStringW(L"CKsProxy::GetSyncSource\n"); + if (!pClock) return E_POINTER; @@ -1681,6 +2667,7 @@ STDMETHODCALLTYPE CKsProxy::EnumPins( IEnumPins **ppEnum) { + OutputDebugStringW(L"CKsProxy::EnumPins\n"); return CEnumPins_fnConstructor(m_Pins, IID_IEnumPins, (void**)ppEnum); } @@ -1691,6 +2678,8 @@ CKsProxy::FindPin( { ULONG PinId; + OutputDebugStringW(L"CKsProxy::FindPin\n"); + if (!ppPin) return E_POINTER; @@ -1725,9 +2714,14 @@ CKsProxy::QueryFilterInfo( if (!pInfo) return E_POINTER; + OutputDebugStringW(L"CKsProxy::QueryFilterInfo\n"); + pInfo->achName[0] = L'\0'; pInfo->pGraph = m_pGraph; + if (m_pGraph) + m_pGraph->AddRef(); + return S_OK; } @@ -1737,6 +2731,8 @@ CKsProxy::JoinFilterGraph( IFilterGraph *pGraph, LPCWSTR pName) { + OutputDebugStringW(L"CKsProxy::JoinFilterGraph\n"); + if (pGraph) { // joining filter graph @@ -1757,8 +2753,8 @@ STDMETHODCALLTYPE CKsProxy::QueryVendorInfo( LPWSTR *pVendorInfo) { - OutputDebugStringW(L"CKsProxy::QueryVendorInfo : NotImplemented\n"); - return E_NOTIMPL; + OutputDebugStringW(L"CKsProxy::QueryVendorInfo\n"); + return StringFromCLSID(CLSID_Proxy, pVendorInfo); } //------------------------------------------------------------------- diff --git a/dll/directx/ksuser/ksuser.c b/dll/directx/ksuser/ksuser.c index 8d565231c70..8f62abf950d 100644 --- a/dll/directx/ksuser/ksuser.c +++ b/dll/directx/ksuser/ksuser.c @@ -92,7 +92,7 @@ KsiCreateObjectType( HANDLE hHandle, * *--*/ KSDDKAPI -NTSTATUS +DWORD NTAPI KsCreateAllocator(HANDLE ConnectionHandle, PKSALLOCATOR_FRAMING AllocatorFraming, @@ -130,7 +130,7 @@ KsCreateAllocator(HANDLE ConnectionHandle, * *--*/ KSDDKAPI -NTSTATUS +DWORD NTAPI KsCreateClock(HANDLE ConnectionHandle, PKSCLOCK_CREATE ClockCreate, @@ -225,7 +225,7 @@ KsCreatePin(HANDLE FilterHandle, * *--*/ KSDDKAPI -NTSTATUS +DWORD NTAPI KsCreateTopologyNode(HANDLE ParentHandle, PKSNODE_CREATE NodeCreate, diff --git a/dll/win32/advapi32/reg/reg.c b/dll/win32/advapi32/reg/reg.c index 4a2ce7e96d6..686101e7f1b 100644 --- a/dll/win32/advapi32/reg/reg.c +++ b/dll/win32/advapi32/reg/reg.c @@ -1916,9 +1916,9 @@ RegpApplyRestrictions(DWORD dwFlags, { DWORD cbExpect = 0; - if ((dwFlags & RRF_RT_DWORD) == RRF_RT_DWORD) + if ((dwFlags & RRF_RT_ANY) == RRF_RT_DWORD) cbExpect = 4; - else if ((dwFlags & RRF_RT_QWORD) == RRF_RT_QWORD) + else if ((dwFlags & RRF_RT_ANY) == RRF_RT_QWORD) cbExpect = 8; if (cbExpect && cbData != cbExpect) diff --git a/dll/win32/advapi32/sec/sid.c b/dll/win32/advapi32/sec/sid.c index 6dac3dac683..ed466a58914 100644 --- a/dll/win32/advapi32/sec/sid.c +++ b/dll/win32/advapi32/sec/sid.c @@ -805,6 +805,9 @@ static BOOL ParseStringSidToSid(LPCWSTR StringSid, PSID pSid, LPDWORD cBytes) return FALSE; } + while (*StringSid == ' ') + StringSid++; + *cBytes = ComputeStringSidSize(StringSid); if (!pisid) /* Simply compute the size */ { diff --git a/dll/win32/advapi32/service/eventlog.c b/dll/win32/advapi32/service/eventlog.c index 7327532b74b..8cb4b22664e 100644 --- a/dll/win32/advapi32/service/eventlog.c +++ b/dll/win32/advapi32/service/eventlog.c @@ -42,7 +42,7 @@ EVENTLOG_HANDLE_A_bind(EVENTLOG_HANDLE_A UNCServerName) status = RpcStringBindingComposeA(NULL, (UCHAR *)"ncacn_np", (UCHAR *)UNCServerName, - (UCHAR *)"\\pipe\\ntsvcs", + (UCHAR *)"\\pipe\\EventLog", NULL, (UCHAR **)&pszStringBinding); if (status) @@ -147,20 +147,17 @@ BOOL WINAPI BackupEventLogA(IN HANDLE hEventLog, IN LPCSTR lpBackupFileName) { - RPC_STRING BackupFileName; + ANSI_STRING BackupFileName; NTSTATUS Status; TRACE("%p, %s\n", hEventLog, lpBackupFileName); - BackupFileName.Buffer = (LPSTR)lpBackupFileName; - BackupFileName.Length = BackupFileName.MaximumLength = - lpBackupFileName ? strlen(lpBackupFileName) : 0; - BackupFileName.MaximumLength += sizeof(CHAR); + RtlInitAnsiString(&BackupFileName, lpBackupFileName); RpcTryExcept { Status = ElfrBackupELFA(hEventLog, - &BackupFileName); + (PRPC_STRING)&BackupFileName); } RpcExcept(EXCEPTION_EXECUTE_HANDLER) { @@ -188,20 +185,17 @@ BOOL WINAPI BackupEventLogW(IN HANDLE hEventLog, IN LPCWSTR lpBackupFileName) { - RPC_UNICODE_STRING BackupFileName; + UNICODE_STRING BackupFileName; NTSTATUS Status; TRACE("%p, %s\n", hEventLog, debugstr_w(lpBackupFileName)); - BackupFileName.Buffer = (LPWSTR)lpBackupFileName; - BackupFileName.Length = BackupFileName.MaximumLength = - lpBackupFileName ? wcslen(lpBackupFileName) * sizeof(WCHAR) : 0; - BackupFileName.MaximumLength += sizeof(WCHAR); + RtlInitUnicodeString(&BackupFileName, lpBackupFileName); RpcTryExcept { Status = ElfrBackupELFW(hEventLog, - &BackupFileName); + (PRPC_UNICODE_STRING)&BackupFileName); } RpcExcept(EXCEPTION_EXECUTE_HANDLER) { @@ -226,20 +220,17 @@ BOOL WINAPI ClearEventLogA(IN HANDLE hEventLog, IN LPCSTR lpBackupFileName) { - RPC_STRING BackupFileName; + ANSI_STRING BackupFileName; NTSTATUS Status; TRACE("%p, %s\n", hEventLog, lpBackupFileName); - BackupFileName.Buffer = (LPSTR)lpBackupFileName; - BackupFileName.Length = BackupFileName.MaximumLength = - lpBackupFileName ? strlen(lpBackupFileName) : 0; - BackupFileName.MaximumLength += sizeof(CHAR); + RtlInitAnsiString(&BackupFileName, lpBackupFileName); RpcTryExcept { Status = ElfrClearELFA(hEventLog, - &BackupFileName); + (PRPC_STRING)&BackupFileName); } RpcExcept(EXCEPTION_EXECUTE_HANDLER) { @@ -264,20 +255,17 @@ BOOL WINAPI ClearEventLogW(IN HANDLE hEventLog, IN LPCWSTR lpBackupFileName) { - RPC_UNICODE_STRING BackupFileName; + UNICODE_STRING BackupFileName; NTSTATUS Status; TRACE("%p, %s\n", hEventLog, debugstr_w(lpBackupFileName)); - BackupFileName.Buffer = (LPWSTR)lpBackupFileName; - BackupFileName.Length = BackupFileName.MaximumLength = - lpBackupFileName ? wcslen(lpBackupFileName) * sizeof(WCHAR) : 0; - BackupFileName.MaximumLength += sizeof(WCHAR); + RtlInitUnicodeString(&BackupFileName,lpBackupFileName); RpcTryExcept { Status = ElfrClearELFW(hEventLog, - &BackupFileName); + (PRPC_UNICODE_STRING)&BackupFileName); } RpcExcept(EXCEPTION_EXECUTE_HANDLER) { @@ -380,6 +368,12 @@ GetEventLogInformation(IN HANDLE hEventLog, { NTSTATUS Status; + if (dwInfoLevel != EVENTLOG_FULL_INFO) + { + SetLastError(ERROR_INVALID_LEVEL); + return FALSE; + } + RpcTryExcept { Status = ElfrGetLogInformation(hEventLog, @@ -562,21 +556,18 @@ HANDLE WINAPI OpenBackupEventLogW(IN LPCWSTR lpUNCServerName, IN LPCWSTR lpFileName) { - RPC_UNICODE_STRING FileName; + UNICODE_STRING FileName; IELF_HANDLE LogHandle; NTSTATUS Status; TRACE("%s, %s\n", debugstr_w(lpUNCServerName), debugstr_w(lpFileName)); - FileName.Buffer = (LPWSTR)lpFileName; - FileName.Length = FileName.MaximumLength = - lpFileName ? wcslen(lpFileName) * sizeof(WCHAR) : 0; - FileName.MaximumLength += sizeof(WCHAR); + RtlInitUnicodeString(&FileName, lpFileName); RpcTryExcept { Status = ElfrOpenBELW((LPWSTR)lpUNCServerName, - &FileName, + (PRPC_UNICODE_STRING)&FileName, 1, 1, &LogHandle); @@ -903,21 +894,18 @@ HANDLE WINAPI RegisterEventSourceW(IN LPCWSTR lpUNCServerName, IN LPCWSTR lpSourceName) { - RPC_UNICODE_STRING SourceName; + UNICODE_STRING SourceName; IELF_HANDLE LogHandle; NTSTATUS Status; TRACE("%s, %s\n", debugstr_w(lpUNCServerName), debugstr_w(lpSourceName)); - SourceName.Buffer = (LPWSTR)lpSourceName; - SourceName.Length = SourceName.MaximumLength = - lpSourceName ? wcslen(lpSourceName) * sizeof(WCHAR) : 0; - SourceName.MaximumLength += sizeof(WCHAR); + RtlInitUnicodeString(&SourceName, lpSourceName); RpcTryExcept { Status = ElfrRegisterEventSourceW((LPWSTR)lpUNCServerName, - &SourceName, + (PRPC_UNICODE_STRING)&SourceName, &EmptyStringU, 1, 1, diff --git a/dll/win32/advapi32/service/scm.c b/dll/win32/advapi32/service/scm.c index e10e7f1fb4c..c3a05da4bf9 100644 --- a/dll/win32/advapi32/service/scm.c +++ b/dll/win32/advapi32/service/scm.c @@ -131,61 +131,6 @@ SVCCTL_HANDLEW_unbind(SVCCTL_HANDLEW szMachineName, } -handle_t __RPC_USER -RPC_SERVICE_STATUS_HANDLE_bind(RPC_SERVICE_STATUS_HANDLE hServiceStatus) -{ - handle_t hBinding = NULL; - LPWSTR pszStringBinding; - RPC_STATUS status; - - TRACE("RPC_SERVICE_STATUS_HANDLE_bind() called\n"); - - status = RpcStringBindingComposeW(NULL, - L"ncacn_np", - NULL, - L"\\pipe\\ntsvcs", - NULL, - &pszStringBinding); - if (status != RPC_S_OK) - { - ERR("RpcStringBindingCompose returned 0x%x\n", status); - return NULL; - } - - /* Set the binding handle that will be used to bind to the server. */ - status = RpcBindingFromStringBindingW(pszStringBinding, - &hBinding); - if (status != RPC_S_OK) - { - ERR("RpcBindingFromStringBinding returned 0x%x\n", status); - } - - status = RpcStringFreeW(&pszStringBinding); - if (status != RPC_S_OK) - { - ERR("RpcStringFree returned 0x%x\n", status); - } - - return hBinding; -} - - -void __RPC_USER -RPC_SERVICE_STATUS_HANDLE_unbind(RPC_SERVICE_STATUS_HANDLE hServiceStatus, - handle_t hBinding) -{ - RPC_STATUS status; - - TRACE("RPC_SERVICE_STATUS_HANDLE_unbind() called\n"); - - status = RpcBindingFree(&hBinding); - if (status != RPC_S_OK) - { - ERR("RpcBindingFree returned 0x%x\n", status); - } -} - - DWORD ScmRpcStatusToWinError(RPC_STATUS Status) { diff --git a/dll/win32/advapi32/service/sctrl.c b/dll/win32/advapi32/service/sctrl.c index ca6f1648fe0..90810bcca3c 100644 --- a/dll/win32/advapi32/service/sctrl.c +++ b/dll/win32/advapi32/service/sctrl.c @@ -41,10 +41,87 @@ typedef struct _ACTIVE_SERVICE static DWORD dwActiveServiceCount = 0; static PACTIVE_SERVICE lpActiveServices = NULL; +static handle_t hStatusBinding = NULL; /* FUNCTIONS *****************************************************************/ +handle_t __RPC_USER +RPC_SERVICE_STATUS_HANDLE_bind(RPC_SERVICE_STATUS_HANDLE hServiceStatus) +{ + return hStatusBinding; +} + + +void __RPC_USER +RPC_SERVICE_STATUS_HANDLE_unbind(RPC_SERVICE_STATUS_HANDLE hServiceStatus, + handle_t hBinding) +{ +} + + +static RPC_STATUS +ScCreateStatusBinding(VOID) +{ + LPWSTR pszStringBinding; + RPC_STATUS status; + + TRACE("ScCreateStatusBinding() called\n"); + + status = RpcStringBindingComposeW(NULL, + L"ncacn_np", + NULL, + L"\\pipe\\ntsvcs", + NULL, + &pszStringBinding); + if (status != RPC_S_OK) + { + ERR("RpcStringBindingCompose returned 0x%x\n", status); + return status; + } + + /* Set the binding handle that will be used to bind to the server. */ + status = RpcBindingFromStringBindingW(pszStringBinding, + &hStatusBinding); + if (status != RPC_S_OK) + { + ERR("RpcBindingFromStringBinding returned 0x%x\n", status); + } + + status = RpcStringFreeW(&pszStringBinding); + if (status != RPC_S_OK) + { + ERR("RpcStringFree returned 0x%x\n", status); + } + + return status; +} + + +static RPC_STATUS +ScDestroyStatusBinding(VOID) +{ + RPC_STATUS status; + + TRACE("ScDestroyStatusBinding() called\n"); + + if (hStatusBinding == NULL) + return RPC_S_OK; + + status = RpcBindingFree(&hStatusBinding); + if (status != RPC_S_OK) + { + ERR("RpcBindingFree returned 0x%x\n", status); + } + else + { + hStatusBinding = NULL; + } + + return status; +} + + static PACTIVE_SERVICE ScLookupServiceByServiceName(LPCWSTR lpServiceName) { @@ -259,7 +336,6 @@ ScConnectControlPipe(HANDLE *hPipe) TRACE("Sent Process ID %lu\n", dwProcessId); - return ERROR_SUCCESS; } @@ -403,7 +479,7 @@ ScServiceDispatcher(HANDLE hPipe, } else { - dwError = ERROR_NOT_FOUND; + dwError = ERROR_SERVICE_DOES_NOT_EXIST; } ReplyPacket.dwError = dwError; @@ -747,7 +823,12 @@ StartServiceCtrlDispatcherA(const SERVICE_TABLE_ENTRYA * lpServiceStartTable) return FALSE; } + ScCreateStatusBinding(); + ScServiceDispatcher(hPipe, lpMessageBuffer, 256); + + ScDestroyStatusBinding(); + CloseHandle(hPipe); /* Free the message buffer */ @@ -837,7 +918,12 @@ StartServiceCtrlDispatcherW(const SERVICE_TABLE_ENTRYW * lpServiceStartTable) return FALSE; } + ScCreateStatusBinding(); + ScServiceDispatcher(hPipe, lpMessageBuffer, 256); + + ScDestroyStatusBinding(); + CloseHandle(hPipe); /* Free the message buffer */ diff --git a/dll/win32/dbghelp/coff.c b/dll/win32/dbghelp/coff.c index ef8632b0f09..720f00b58af 100644 --- a/dll/win32/dbghelp/coff.c +++ b/dll/win32/dbghelp/coff.c @@ -108,12 +108,18 @@ static int coff_add_file(struct CoffFileSet* coff_files, struct module* module, if (coff_files->nfiles + 1 >= coff_files->nfiles_alloc) { - coff_files->nfiles_alloc += 10; - coff_files->files = (coff_files->files) ? - HeapReAlloc(GetProcessHeap(), 0, coff_files->files, - coff_files->nfiles_alloc * sizeof(struct CoffFile)) : - HeapAlloc(GetProcessHeap(), 0, - coff_files->nfiles_alloc * sizeof(struct CoffFile)); + if (coff_files->files) + { + coff_files->nfiles_alloc *= 2; + coff_files->files = HeapReAlloc(GetProcessHeap(), 0, coff_files->files, + coff_files->nfiles_alloc * sizeof(struct CoffFile)); + } + else + { + coff_files->nfiles_alloc = 16; + coff_files->files = HeapAlloc(GetProcessHeap(), 0, + coff_files->nfiles_alloc * sizeof(struct CoffFile)); + } } file = coff_files->files + coff_files->nfiles; file->startaddr = 0xffffffff; @@ -132,7 +138,7 @@ static void coff_add_symbol(struct CoffFile* coff_file, struct symt* sym) { if (coff_file->neps + 1 >= coff_file->neps_alloc) { - coff_file->neps_alloc += 10; + coff_file->neps_alloc *= 2; coff_file->entries = (coff_file->entries) ? HeapReAlloc(GetProcessHeap(), 0, coff_file->entries, coff_file->neps_alloc * sizeof(struct symt*)) : @@ -389,6 +395,7 @@ BOOL coff_process_info(const struct msc_debug_info* msc_dbg) { if (coff_files.files[j].entries != NULL) { + symt_cmp_addr_module = msc_dbg->module; qsort(coff_files.files[j].entries, coff_files.files[j].neps, sizeof(struct symt*), symt_cmp_addr); } @@ -413,7 +420,7 @@ BOOL coff_process_info(const struct msc_debug_info* msc_dbg) for (;;) { if (l+1 >= coff_files.files[j].neps) break; - symt_get_info(coff_files.files[j].entries[l+1], TI_GET_ADDRESS, &addr); + symt_get_info(msc_dbg->module, coff_files.files[j].entries[l+1], TI_GET_ADDRESS, &addr); if (((msc_dbg->module->module.BaseOfImage + linepnt->Type.VirtualAddress) < addr)) break; l++; @@ -426,7 +433,7 @@ BOOL coff_process_info(const struct msc_debug_info* msc_dbg) * start of the function, so we need to subtract that offset * first. */ - symt_get_info(coff_files.files[j].entries[l+1], TI_GET_ADDRESS, &addr); + symt_get_info(msc_dbg->module, coff_files.files[j].entries[l+1], TI_GET_ADDRESS, &addr); symt_add_func_line(msc_dbg->module, (struct symt_function*)coff_files.files[j].entries[l+1], coff_files.files[j].compiland->source, linepnt->Linenumber, msc_dbg->module->module.BaseOfImage + linepnt->Type.VirtualAddress - addr); diff --git a/dll/win32/dbghelp/cpu_i386.c b/dll/win32/dbghelp/cpu_i386.c new file mode 100644 index 00000000000..f3de6523539 --- /dev/null +++ b/dll/win32/dbghelp/cpu_i386.c @@ -0,0 +1,412 @@ +/* + * File cpu_i386.c + * + * Copyright (C) 2009-2009, Eric Pouech. + * + * 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 + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "dbghelp_private.h" +#include "wine/winbase16.h" +#include "winternl.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dbghelp); + +#define STEP_FLAG 0x00000100 /* single step flag */ +#define V86_FLAG 0x00020000 + +#define IS_VM86_MODE(ctx) (ctx->EFlags & V86_FLAG) + +#ifdef __i386__ +static ADDRESS_MODE get_selector_type(HANDLE hThread, const CONTEXT* ctx, WORD sel) +{ + LDT_ENTRY le; + + if (IS_VM86_MODE(ctx)) return AddrModeReal; + /* null or system selector */ + if (!(sel & 4) || ((sel >> 3) < 17)) return AddrModeFlat; + if (hThread && GetThreadSelectorEntry(hThread, sel, &le)) + return le.HighWord.Bits.Default_Big ? AddrMode1632 : AddrMode1616; + /* selector doesn't exist */ + return -1; +} + +static unsigned i386_build_addr(HANDLE hThread, const CONTEXT* ctx, ADDRESS64* addr, + unsigned seg, unsigned long offset) +{ + addr->Mode = AddrModeFlat; + addr->Segment = seg; + addr->Offset = offset; + if (seg) + { + switch (addr->Mode = get_selector_type(hThread, ctx, seg)) + { + case AddrModeReal: + case AddrMode1616: + addr->Offset &= 0xffff; + break; + case AddrModeFlat: + case AddrMode1632: + break; + default: + return FALSE; + } + } + return TRUE; +} +#endif + +static unsigned i386_get_addr(HANDLE hThread, const CONTEXT* ctx, + enum cpu_addr ca, ADDRESS64* addr) +{ +#ifdef __i386__ + switch (ca) + { + case cpu_addr_pc: return i386_build_addr(hThread, ctx, addr, ctx->SegCs, ctx->Eip); + case cpu_addr_stack: return i386_build_addr(hThread, ctx, addr, ctx->SegSs, ctx->Esp); + case cpu_addr_frame: return i386_build_addr(hThread, ctx, addr, ctx->SegSs, ctx->Ebp); + } +#endif + return FALSE; +} + +enum st_mode {stm_start, stm_32bit, stm_16bit, stm_done}; + +/* indexes in Reserved array */ +#define __CurrentMode 0 +#define __CurrentSwitch 1 +#define __NextSwitch 2 + +#define curr_mode (frame->Reserved[__CurrentMode]) +#define curr_switch (frame->Reserved[__CurrentSwitch]) +#define next_switch (frame->Reserved[__NextSwitch]) + +static BOOL i386_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame) +{ + STACK32FRAME frame32; + STACK16FRAME frame16; + char ch; + ADDRESS64 tmp; + DWORD p; + WORD val; + BOOL do_switch; + + /* sanity check */ + if (curr_mode >= stm_done) return FALSE; + + TRACE("Enter: PC=%s Frame=%s Return=%s Stack=%s Mode=%s cSwitch=%p nSwitch=%p\n", + wine_dbgstr_addr(&frame->AddrPC), + wine_dbgstr_addr(&frame->AddrFrame), + wine_dbgstr_addr(&frame->AddrReturn), + wine_dbgstr_addr(&frame->AddrStack), + curr_mode == stm_start ? "start" : (curr_mode == stm_16bit ? "16bit" : "32bit"), + (void*)(DWORD_PTR)curr_switch, (void*)(DWORD_PTR)next_switch); + + if (curr_mode == stm_start) + { + THREAD_BASIC_INFORMATION info; + + if ((frame->AddrPC.Mode == AddrModeFlat) && + (frame->AddrFrame.Mode != AddrModeFlat)) + { + WARN("Bad AddrPC.Mode / AddrFrame.Mode combination\n"); + goto done_err; + } + + /* Init done */ + curr_mode = (frame->AddrPC.Mode == AddrModeFlat) ? stm_32bit : stm_16bit; + + /* cur_switch holds address of WOW32Reserved field in TEB in debuggee + * address space + */ + if (NtQueryInformationThread(csw->hThread, ThreadBasicInformation, &info, + sizeof(info), NULL) == STATUS_SUCCESS) + { + curr_switch = (unsigned long)info.TebBaseAddress + FIELD_OFFSET(TEB, WOW32Reserved); + if (!sw_read_mem(csw, curr_switch, &p, sizeof(p))) + { + WARN("Can't read TEB:WOW32Reserved\n"); + goto done_err; + } + next_switch = p; + if (!next_switch) /* no 16-bit stack */ + { + curr_switch = 0; + } + else if (curr_mode == stm_16bit) + { + if (!sw_read_mem(csw, next_switch, &frame32, sizeof(frame32))) + { + WARN("Bad stack frame %p\n", (void*)(DWORD_PTR)next_switch); + goto done_err; + } + curr_switch = (DWORD)frame32.frame16; + tmp.Mode = AddrMode1616; + tmp.Segment = SELECTOROF(curr_switch); + tmp.Offset = OFFSETOF(curr_switch); + if (!sw_read_mem(csw, sw_xlat_addr(csw, &tmp), &ch, sizeof(ch))) + curr_switch = 0xFFFFFFFF; + } + else + { + tmp.Mode = AddrMode1616; + tmp.Segment = SELECTOROF(next_switch); + tmp.Offset = OFFSETOF(next_switch); + p = sw_xlat_addr(csw, &tmp); + if (!sw_read_mem(csw, p, &frame16, sizeof(frame16))) + { + WARN("Bad stack frame 0x%08x\n", p); + goto done_err; + } + curr_switch = (DWORD_PTR)frame16.frame32; + + if (!sw_read_mem(csw, curr_switch, &ch, sizeof(ch))) + curr_switch = 0xFFFFFFFF; + } + } + else + /* FIXME: this will allow to work when we're not attached to a live target, + * but the 16 <=> 32 switch facility won't be available. + */ + curr_switch = 0; + frame->AddrReturn.Mode = frame->AddrStack.Mode = (curr_mode == stm_16bit) ? AddrMode1616 : AddrModeFlat; + /* don't set up AddrStack on first call. Either the caller has set it up, or + * we will get it in the next frame + */ + memset(&frame->AddrBStore, 0, sizeof(frame->AddrBStore)); + } + else + { + if (frame->AddrFrame.Offset == 0) goto done_err; + if (frame->AddrFrame.Mode == AddrModeFlat) + { + assert(curr_mode == stm_32bit); + do_switch = curr_switch && frame->AddrFrame.Offset >= curr_switch; + } + else + { + assert(curr_mode == stm_16bit); + do_switch = curr_switch && + frame->AddrFrame.Segment == SELECTOROF(curr_switch) && + frame->AddrFrame.Offset >= OFFSETOF(curr_switch); + } + + if (do_switch) + { + if (curr_mode == stm_16bit) + { + if (!sw_read_mem(csw, next_switch, &frame32, sizeof(frame32))) + { + WARN("Bad stack frame %p\n", (void*)(DWORD_PTR)next_switch); + goto done_err; + } + + frame->AddrPC.Mode = AddrModeFlat; + frame->AddrPC.Segment = 0; + frame->AddrPC.Offset = frame32.retaddr; + frame->AddrFrame.Mode = AddrModeFlat; + frame->AddrFrame.Segment = 0; + frame->AddrFrame.Offset = frame32.ebp; + + frame->AddrStack.Mode = AddrModeFlat; + frame->AddrStack.Segment = 0; + frame->AddrReturn.Mode = AddrModeFlat; + frame->AddrReturn.Segment = 0; + + next_switch = curr_switch; + tmp.Mode = AddrMode1616; + tmp.Segment = SELECTOROF(next_switch); + tmp.Offset = OFFSETOF(next_switch); + p = sw_xlat_addr(csw, &tmp); + + if (!sw_read_mem(csw, p, &frame16, sizeof(frame16))) + { + WARN("Bad stack frame 0x%08x\n", p); + goto done_err; + } + curr_switch = (DWORD_PTR)frame16.frame32; + curr_mode = stm_32bit; + if (!sw_read_mem(csw, curr_switch, &ch, sizeof(ch))) + curr_switch = 0; + } + else + { + tmp.Mode = AddrMode1616; + tmp.Segment = SELECTOROF(next_switch); + tmp.Offset = OFFSETOF(next_switch); + p = sw_xlat_addr(csw, &tmp); + + if (!sw_read_mem(csw, p, &frame16, sizeof(frame16))) + { + WARN("Bad stack frame 0x%08x\n", p); + goto done_err; + } + + TRACE("Got a 16 bit stack switch:" + "\n\tframe32: %08lx" + "\n\tedx:%08x ecx:%08x ebp:%08x" + "\n\tds:%04x es:%04x fs:%04x gs:%04x" + "\n\tcall_from_ip:%08x module_cs:%04x relay=%08x" + "\n\tentry_ip:%04x entry_point:%08x" + "\n\tbp:%04x ip:%04x cs:%04x\n", + (unsigned long)frame16.frame32, + frame16.edx, frame16.ecx, frame16.ebp, + frame16.ds, frame16.es, frame16.fs, frame16.gs, + frame16.callfrom_ip, frame16.module_cs, frame16.relay, + frame16.entry_ip, frame16.entry_point, + frame16.bp, frame16.ip, frame16.cs); + + frame->AddrPC.Mode = AddrMode1616; + frame->AddrPC.Segment = frame16.cs; + frame->AddrPC.Offset = frame16.ip; + + frame->AddrFrame.Mode = AddrMode1616; + frame->AddrFrame.Segment = SELECTOROF(next_switch); + frame->AddrFrame.Offset = frame16.bp; + + frame->AddrStack.Mode = AddrMode1616; + frame->AddrStack.Segment = SELECTOROF(next_switch); + + frame->AddrReturn.Mode = AddrMode1616; + frame->AddrReturn.Segment = frame16.cs; + + next_switch = curr_switch; + if (!sw_read_mem(csw, next_switch, &frame32, sizeof(frame32))) + { + WARN("Bad stack frame %p\n", (void*)(DWORD_PTR)next_switch); + goto done_err; + } + curr_switch = (DWORD)frame32.frame16; + tmp.Mode = AddrMode1616; + tmp.Segment = SELECTOROF(curr_switch); + tmp.Offset = OFFSETOF(curr_switch); + + if (!sw_read_mem(csw, sw_xlat_addr(csw, &tmp), &ch, sizeof(ch))) + curr_switch = 0; + curr_mode = stm_16bit; + } + } + else + { + frame->AddrPC = frame->AddrReturn; + if (curr_mode == stm_16bit) + { + frame->AddrStack.Offset = frame->AddrFrame.Offset + 2 * sizeof(WORD); + /* "pop up" previous BP value */ + if (!sw_read_mem(csw, sw_xlat_addr(csw, &frame->AddrFrame), + &val, sizeof(WORD))) + goto done_err; + frame->AddrFrame.Offset = val; + } + else + { + frame->AddrStack.Offset = frame->AddrFrame.Offset + 2 * sizeof(DWORD); + /* "pop up" previous EBP value */ + if (!sw_read_mem(csw, frame->AddrFrame.Offset, + &frame->AddrFrame.Offset, sizeof(DWORD))) + goto done_err; + } + } + } + + if (curr_mode == stm_16bit) + { + unsigned int i; + + p = sw_xlat_addr(csw, &frame->AddrFrame); + if (!sw_read_mem(csw, p + sizeof(WORD), &val, sizeof(WORD))) + goto done_err; + frame->AddrReturn.Offset = val; + /* get potential cs if a far call was used */ + if (!sw_read_mem(csw, p + 2 * sizeof(WORD), &val, sizeof(WORD))) + goto done_err; + if (frame->AddrFrame.Offset & 1) + frame->AddrReturn.Segment = val; /* far call assumed */ + else + { + /* not explicitly marked as far call, + * but check whether it could be anyway + */ + if ((val & 7) == 7 && val != frame->AddrReturn.Segment) + { + LDT_ENTRY le; + + if (GetThreadSelectorEntry(csw->hThread, val, &le) && + (le.HighWord.Bits.Type & 0x08)) /* code segment */ + { + /* it is very uncommon to push a code segment cs as + * a parameter, so this should work in most cases + */ + frame->AddrReturn.Segment = val; + } + } + } + frame->AddrFrame.Offset &= ~1; + /* we "pop" parameters as 16 bit entities... of course, this won't + * work if the parameter is in fact bigger than 16bit, but + * there's no way to know that here + */ + for (i = 0; i < sizeof(frame->Params) / sizeof(frame->Params[0]); i++) + { + sw_read_mem(csw, p + (2 + i) * sizeof(WORD), &val, sizeof(val)); + frame->Params[i] = val; + } + } + else + { + if (!sw_read_mem(csw, frame->AddrFrame.Offset + sizeof(DWORD), + &frame->AddrReturn.Offset, sizeof(DWORD))) + { + WARN("Cannot read new frame offset %p\n", + (void*)(DWORD_PTR)(frame->AddrFrame.Offset + (int)sizeof(DWORD))); + goto done_err; + } + sw_read_mem(csw, frame->AddrFrame.Offset + 2 * sizeof(DWORD), + frame->Params, sizeof(frame->Params)); + } + + frame->Far = TRUE; + frame->Virtual = TRUE; + p = sw_xlat_addr(csw, &frame->AddrPC); + if (p && sw_module_base(csw, p)) + frame->FuncTableEntry = sw_table_access(csw, p); + else + frame->FuncTableEntry = NULL; + + TRACE("Leave: PC=%s Frame=%s Return=%s Stack=%s Mode=%s cSwitch=%p nSwitch=%p FuncTable=%p\n", + wine_dbgstr_addr(&frame->AddrPC), + wine_dbgstr_addr(&frame->AddrFrame), + wine_dbgstr_addr(&frame->AddrReturn), + wine_dbgstr_addr(&frame->AddrStack), + curr_mode == stm_start ? "start" : (curr_mode == stm_16bit ? "16bit" : "32bit"), + (void*)(DWORD_PTR)curr_switch, (void*)(DWORD_PTR)next_switch, frame->FuncTableEntry); + + return TRUE; +done_err: + curr_mode = stm_done; + return FALSE; +} + +struct cpu cpu_i386 = { + IMAGE_FILE_MACHINE_I386, + 4, + i386_get_addr, + i386_stack_walk, +}; diff --git a/dll/win32/dbghelp/cpu_ppc.c b/dll/win32/dbghelp/cpu_ppc.c new file mode 100644 index 00000000000..fca5ec76ccf --- /dev/null +++ b/dll/win32/dbghelp/cpu_ppc.c @@ -0,0 +1,62 @@ +/* + * File cpu_ppc.c + * + * Copyright (C) 2009-2009, Eric Pouech. + * + * 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 + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "dbghelp_private.h" +#include "winternl.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dbghelp); + +static unsigned ppc_get_addr(HANDLE hThread, const CONTEXT* ctx, + enum cpu_addr ca, ADDRESS64* addr) +{ + switch (ca) + { +#if defined(__powerpc__) + case cpu_addr_pc: + addr->Mode = AddrModeFlat; + addr->Segment = 0; /* don't need segment */ + addr->Offset = ctx->Iar; + return TRUE; +#endif + default: + case cpu_addr_stack: + case cpu_addr_frame: + FIXME("not done\n"); + } + return FALSE; +} + +static BOOL ppc_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame) +{ + FIXME("not done\n"); + return FALSE; +} + +struct cpu cpu_ppc = { + IMAGE_FILE_MACHINE_POWERPC, + 4, + ppc_get_addr, + ppc_stack_walk, +}; diff --git a/dll/win32/dbghelp/cpu_x86_64.c b/dll/win32/dbghelp/cpu_x86_64.c new file mode 100644 index 00000000000..cd0e32c5081 --- /dev/null +++ b/dll/win32/dbghelp/cpu_x86_64.c @@ -0,0 +1,132 @@ +/* + * File cpu_x86_64.c + * + * Copyright (C) 2009-2009, Eric Pouech. + * + * 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 + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "dbghelp_private.h" +#include "winternl.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dbghelp); + +static unsigned x86_64_get_addr(HANDLE hThread, const CONTEXT* ctx, + enum cpu_addr ca, ADDRESS64* addr) +{ + addr->Mode = AddrModeFlat; + switch (ca) + { +#ifdef __x86_64__ + case cpu_addr_pc: addr->Segment = ctx->SegCs; addr->Offset = ctx->Rip; return TRUE; + case cpu_addr_stack: addr->Segment = ctx->SegSs; addr->Offset = ctx->Rsp; return TRUE; + case cpu_addr_frame: addr->Segment = ctx->SegSs; addr->Offset = ctx->Rbp; return TRUE; +#endif + default: addr->Mode = -1; + return FALSE; + } +} + +enum st_mode {stm_start, stm_64bit, stm_done}; + +/* indexes in Reserved array */ +#define __CurrentMode 0 +#define __CurrentSwitch 1 +#define __NextSwitch 2 + +#define curr_mode (frame->Reserved[__CurrentMode]) +#define curr_switch (frame->Reserved[__CurrentSwitch]) +#define next_switch (frame->Reserved[__NextSwitch]) + +static BOOL x86_64_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame) +{ + /* sanity check */ + if (curr_mode >= stm_done) return FALSE; + assert(!csw->is32); + + TRACE("Enter: PC=%s Frame=%s Return=%s Stack=%s Mode=%s\n", + wine_dbgstr_addr(&frame->AddrPC), + wine_dbgstr_addr(&frame->AddrFrame), + wine_dbgstr_addr(&frame->AddrReturn), + wine_dbgstr_addr(&frame->AddrStack), + curr_mode == stm_start ? "start" : "64bit"); + + if (curr_mode == stm_start) + { + if ((frame->AddrPC.Mode == AddrModeFlat) && + (frame->AddrFrame.Mode != AddrModeFlat)) + { + WARN("Bad AddrPC.Mode / AddrFrame.Mode combination\n"); + goto done_err; + } + + /* Init done */ + curr_mode = stm_64bit; + curr_switch = 0; + frame->AddrReturn.Mode = frame->AddrStack.Mode = AddrModeFlat; + /* don't set up AddrStack on first call. Either the caller has set it up, or + * we will get it in the next frame + */ + memset(&frame->AddrBStore, 0, sizeof(frame->AddrBStore)); + } + else + { + if (frame->AddrReturn.Offset == 0) goto done_err; + frame->AddrPC = frame->AddrReturn; + } + + if (!sw_read_mem(csw, frame->AddrStack.Offset, + &frame->AddrReturn.Offset, sizeof(DWORD64))) + { + WARN("Cannot read new frame offset %s\n", + wine_dbgstr_longlong(frame->AddrFrame.Offset + sizeof(DWORD64))); + goto done_err; + } + /* FIXME: simplistic stuff... need to handle both dwarf & PE stack information */ + frame->AddrStack.Offset += sizeof(DWORD64); + memset(&frame->Params, 0, sizeof(frame->Params)); + + frame->Far = TRUE; + frame->Virtual = TRUE; + if (frame->AddrPC.Offset && sw_module_base(csw, frame->AddrPC.Offset)) + frame->FuncTableEntry = sw_table_access(csw, frame->AddrPC.Offset); + else + frame->FuncTableEntry = NULL; + + TRACE("Leave: PC=%s Frame=%s Return=%s Stack=%s Mode=%s FuncTable=%p\n", + wine_dbgstr_addr(&frame->AddrPC), + wine_dbgstr_addr(&frame->AddrFrame), + wine_dbgstr_addr(&frame->AddrReturn), + wine_dbgstr_addr(&frame->AddrStack), + curr_mode == stm_start ? "start" : "64bit", + frame->FuncTableEntry); + + return TRUE; +done_err: + curr_mode = stm_done; + return FALSE; +} + +struct cpu cpu_x86_64 = { + IMAGE_FILE_MACHINE_AMD64, + 8, + x86_64_get_addr, + x86_64_stack_walk, +}; diff --git a/dll/win32/dbghelp/crc32.c b/dll/win32/dbghelp/crc32.c new file mode 100644 index 00000000000..edd42eacfba --- /dev/null +++ b/dll/win32/dbghelp/crc32.c @@ -0,0 +1,149 @@ +/* + * File crc32.c - calculate CRC32 checksum of a file + * + * Copyright (C) 1996, Eric Youngdale. + * 1999-2007 Eric Pouech + * + * 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 "config.h" +#include "wine/port.h" + +#include + +#include "dbghelp_private.h" + +/* Copyright (C) 1986 Gary S. Brown. Modified by Robert Shearman. You may use + the following calc_crc32 code or tables extracted from it, as desired without + restriction. */ + +/**********************************************************************\ +|* Demonstration program to compute the 32-bit CRC used as the frame *| +|* check sequence in ADCCP (ANSI X3.66, also known as FIPS PUB 71 *| +|* and FED-STD-1003, the U.S. versions of CCITT's X.25 link-level *| +|* protocol). The 32-bit FCS was added via the Federal Register, *| +|* 1 June 1982, p.23798. I presume but don't know for certain that *| +|* this polynomial is or will be included in CCITT V.41, which *| +|* defines the 16-bit CRC (often called CRC-CCITT) polynomial. FIPS *| +|* PUB 78 says that the 32-bit FCS reduces otherwise undetected *| +|* errors by a factor of 10^-5 over 16-bit FCS. *| +\**********************************************************************/ + +/* First, the polynomial itself and its table of feedback terms. The */ +/* polynomial is */ +/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */ +/* Note that we take it "backwards" and put the highest-order term in */ +/* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ +/* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ +/* the MSB being 1. */ + +/* Note that the usual hardware shift register implementation, which */ +/* is what we're using (we're merely optimizing it by doing eight-bit */ +/* chunks at a time) shifts bits into the lowest-order term. In our */ +/* implementation, that means shifting towards the right. Why do we */ +/* do it this way? Because the calculated CRC must be transmitted in */ +/* order from highest-order term to lowest-order term. UARTs transmit */ +/* characters in order from LSB to MSB. By storing the CRC this way, */ +/* we hand it to the UART in the order low-byte to high-byte; the UART */ +/* sends each low-bit to hight-bit; and the result is transmission bit */ +/* by bit from highest- to lowest-order term without requiring any bit */ +/* shuffling on our part. Reception works similarly. */ + +/* The feedback terms table consists of 256, 32-bit entries. Notes: */ +/* */ +/* 1. The table can be generated at runtime if desired; code to do so */ +/* is shown later. It might not be obvious, but the feedback */ +/* terms simply represent the results of eight shift/xor opera- */ +/* tions for all combinations of data and CRC register values. */ +/* */ +/* 2. The CRC accumulation logic is the same for all CRC polynomials, */ +/* be they sixteen or thirty-two bits wide. You simply choose the */ +/* appropriate table. Alternatively, because the table can be */ +/* generated at runtime, you can start by generating the table for */ +/* the polynomial in question and use exactly the same "updcrc", */ +/* if your application needn't simultaneously handle two CRC */ +/* polynomials. (Note, however, that XMODEM is strange.) */ +/* */ +/* 3. For 16-bit CRCs, the table entries need be only 16 bits wide; */ +/* of course, 32-bit entries work OK if the high 16 bits are zero. */ +/* */ +/* 4. The values must be right-shifted by eight bits by the "updcrc" */ +/* logic; the shift must be unsigned (bring in zeroes). On some */ +/* hardware you could probably optimize the shift in assembler by */ +/* using byte-swap instructions. */ + + +DWORD calc_crc32(int fd) +{ +#define UPDC32(octet,crc) (crc_32_tab[((crc) ^ (octet)) & 0xff] ^ ((crc) >> 8)) + static const DWORD crc_32_tab[] = + { /* CRC polynomial 0xedb88320 */ + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d + }; + int i, r; + unsigned char buffer[8192]; + DWORD crc = ~0; + + _lseek(fd, 0, SEEK_SET); + while ((r = _read(fd, buffer, sizeof(buffer))) > 0) + { + for (i = 0; i < r; i++) crc = UPDC32(buffer[i], crc); + } + return ~crc; +#undef UPDC32 +} diff --git a/dll/win32/dbghelp/dbghelp.c b/dll/win32/dbghelp/dbghelp.c index 1bfc338e596..d9a828fcef9 100644 --- a/dll/win32/dbghelp/dbghelp.c +++ b/dll/win32/dbghelp/dbghelp.c @@ -106,7 +106,7 @@ struct process* process_find_by_handle(HANDLE hProcess) */ BOOL validate_addr64(DWORD64 addr) { - if (addr >> 32) + if (sizeof(void*) == sizeof(int) && (addr >> 32)) { FIXME("Unsupported address %s\n", wine_dbgstr_longlong(addr)); SetLastError(ERROR_INVALID_PARAMETER); @@ -133,6 +133,48 @@ void* fetch_buffer(struct process* pcs, unsigned size) return pcs->buffer; } +const char* wine_dbgstr_addr(const ADDRESS64* addr) +{ + if (!addr) return "(null)"; + switch (addr->Mode) + { + case AddrModeFlat: + return wine_dbg_sprintf("flat<%s>", wine_dbgstr_longlong(addr->Offset)); + case AddrMode1616: + return wine_dbg_sprintf("1616<%04x:%04x>", addr->Segment, (DWORD)addr->Offset); + case AddrMode1632: + return wine_dbg_sprintf("1632<%04x:%08x>", addr->Segment, (DWORD)addr->Offset); + case AddrModeReal: + return wine_dbg_sprintf("real<%04x:%04x>", addr->Segment, (DWORD)addr->Offset); + default: + return "unknown"; + } +} + +extern struct cpu cpu_i386, cpu_x86_64; + +static struct cpu* dbghelp_cpus[] = {&cpu_i386, &cpu_x86_64, NULL}; +struct cpu* dbghelp_current_cpu = +#if defined(__i386__) + &cpu_i386 +#elif defined(__x86_64__) + &cpu_x86_64 +#else +#error define support for your CPU +#endif + ; + +struct cpu* cpu_find(DWORD machine) +{ + struct cpu** cpu; + + for (cpu = dbghelp_cpus ; *cpu; cpu++) + { + if (cpu[0]->machine == machine) return cpu[0]; + } + return NULL; +} + /****************************************************************** * SymSetSearchPathW (DBGHELP.@) * @@ -211,16 +253,16 @@ BOOL WINAPI SymGetSearchPath(HANDLE hProcess, PSTR szSearchPath, * SymInitialize helper: loads in dbghelp all known (and loaded modules) * this assumes that hProcess is a handle on a valid process */ -static BOOL WINAPI process_invade_cb(PCSTR name, ULONG base, ULONG size, PVOID user) +static BOOL WINAPI process_invade_cb(PCWSTR name, ULONG64 base, ULONG size, PVOID user) { - char tmp[MAX_PATH]; + WCHAR tmp[MAX_PATH]; HANDLE hProcess = user; - if (!GetModuleFileNameExA(hProcess, (HMODULE)base, - tmp, sizeof(tmp))) - lstrcpynA(tmp, name, sizeof(tmp)); + if (!GetModuleFileNameExW(hProcess, (HMODULE)(DWORD_PTR)base, + tmp, sizeof(tmp) / sizeof(WCHAR))) + lstrcpynW(tmp, name, sizeof(tmp) / sizeof(WCHAR)); - SymLoadModule(hProcess, 0, tmp, name, base, size); + SymLoadModuleExW(hProcess, 0, tmp, name, base, size, NULL, 0); return TRUE; } @@ -232,7 +274,8 @@ static BOOL check_live_target(struct process* pcs) { if (!GetProcessId(pcs->handle)) return FALSE; if (GetEnvironmentVariableA("DBGHELP_NOLIVE", NULL, 0)) return FALSE; - elf_read_wine_loader_dbg_info(pcs); + if (!elf_read_wine_loader_dbg_info(pcs)) + macho_read_wine_loader_dbg_info(pcs); return TRUE; } @@ -325,8 +368,9 @@ BOOL WINAPI SymInitializeW(HANDLE hProcess, PCWSTR UserSearchPath, BOOL fInvadeP if (check_live_target(pcs)) { if (fInvadeProcess) - EnumerateLoadedModules(hProcess, process_invade_cb, hProcess); + EnumerateLoadedModulesW64(hProcess, process_invade_cb, hProcess); elf_synchronize_module_list(pcs); + macho_synchronize_module_list(pcs); } else if (fInvadeProcess) { @@ -459,25 +503,25 @@ BOOL WINAPI SymSetContext(HANDLE hProcess, PIMAGEHLP_STACK_FRAME StackFrame, */ static BOOL CALLBACK reg_cb64to32(HANDLE hProcess, ULONG action, ULONG64 data, ULONG64 user) { - PSYMBOL_REGISTERED_CALLBACK cb32 = (PSYMBOL_REGISTERED_CALLBACK)(DWORD)(user >> 32); - DWORD user32 = (DWORD)user; + struct process* pcs = process_find_by_handle(hProcess); void* data32; IMAGEHLP_DEFERRED_SYMBOL_LOAD64* idsl64; IMAGEHLP_DEFERRED_SYMBOL_LOAD idsl; + if (!pcs) return FALSE; switch (action) { case CBA_DEBUG_INFO: case CBA_DEFERRED_SYMBOL_LOAD_CANCEL: case CBA_SET_OPTIONS: case CBA_SYMBOLS_UNLOADED: - data32 = (void*)(DWORD)data; + data32 = (void*)(DWORD_PTR)data; break; case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE: case CBA_DEFERRED_SYMBOL_LOAD_FAILURE: case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL: case CBA_DEFERRED_SYMBOL_LOAD_START: - idsl64 = (IMAGEHLP_DEFERRED_SYMBOL_LOAD64*)(DWORD)data; + idsl64 = (IMAGEHLP_DEFERRED_SYMBOL_LOAD64*)(DWORD_PTR)data; if (!validate_addr64(idsl64->BaseOfImage)) return FALSE; idsl.SizeOfStruct = sizeof(idsl); @@ -495,7 +539,7 @@ static BOOL CALLBACK reg_cb64to32(HANDLE hProcess, ULONG action, ULONG64 data, U FIXME("No mapping for action %u\n", action); return FALSE; } - return cb32(hProcess, action, data32, (PVOID)user32); + return pcs->reg_cb32(hProcess, action, data32, (PVOID)(DWORD_PTR)user); } /****************************************************************** @@ -522,7 +566,7 @@ BOOL pcs_callback(const struct process* pcs, ULONG action, void* data) case CBA_DEFERRED_SYMBOL_LOAD_FAILURE: case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL: case CBA_DEFERRED_SYMBOL_LOAD_START: - idslW = (IMAGEHLP_DEFERRED_SYMBOL_LOADW64*)(DWORD)data; + idslW = data; idsl.SizeOfStruct = sizeof(idsl); idsl.BaseOfImage = idslW->BaseOfImage; idsl.CheckSum = idslW->CheckSum; @@ -548,14 +592,16 @@ BOOL pcs_callback(const struct process* pcs, ULONG action, void* data) * * Helper for registering a callback. */ -static BOOL sym_register_cb(HANDLE hProcess, +static BOOL sym_register_cb(HANDLE hProcess, PSYMBOL_REGISTERED_CALLBACK64 cb, + PSYMBOL_REGISTERED_CALLBACK cb32, DWORD64 user, BOOL unicode) { struct process* pcs = process_find_by_handle(hProcess); if (!pcs) return FALSE; pcs->reg_cb = cb; + pcs->reg_cb32 = cb32; pcs->reg_is_unicode = unicode; pcs->reg_user = user; @@ -569,10 +615,9 @@ BOOL WINAPI SymRegisterCallback(HANDLE hProcess, PSYMBOL_REGISTERED_CALLBACK CallbackFunction, PVOID UserContext) { - DWORD64 tmp = ((ULONGLONG)(DWORD)CallbackFunction << 32) | (DWORD)UserContext; TRACE("(%p, %p, %p)\n", hProcess, CallbackFunction, UserContext); - return sym_register_cb(hProcess, reg_cb64to32, tmp, FALSE); + return sym_register_cb(hProcess, reg_cb64to32, CallbackFunction, (DWORD_PTR)UserContext, FALSE); } /*********************************************************************** @@ -584,7 +629,7 @@ BOOL WINAPI SymRegisterCallback64(HANDLE hProcess, { TRACE("(%p, %p, %s)\n", hProcess, CallbackFunction, wine_dbgstr_longlong(UserContext)); - return sym_register_cb(hProcess, CallbackFunction, UserContext, FALSE); + return sym_register_cb(hProcess, CallbackFunction, NULL, UserContext, FALSE); } /*********************************************************************** @@ -596,7 +641,7 @@ BOOL WINAPI SymRegisterCallbackW64(HANDLE hProcess, { TRACE("(%p, %p, %s)\n", hProcess, CallbackFunction, wine_dbgstr_longlong(UserContext)); - return sym_register_cb(hProcess, CallbackFunction, UserContext, TRUE); + return sym_register_cb(hProcess, CallbackFunction, NULL, UserContext, TRUE); } /* This is imagehlp version not dbghelp !! */ diff --git a/dll/win32/dbghelp/dbghelp.rbuild b/dll/win32/dbghelp/dbghelp.rbuild index 59bf735bcf0..26b829a0fe4 100644 --- a/dll/win32/dbghelp/dbghelp.rbuild +++ b/dll/win32/dbghelp/dbghelp.rbuild @@ -9,10 +9,15 @@ coff.c + cpu_i386.c + cpu_ppc.c + cpu_x86_64.c + crc32.c dbghelp.c dwarf.c elf_module.c image.c + macho_module.c memory.c minidump.c module.c @@ -27,6 +32,7 @@ storage.c symbol.c type.c + version.rc wine psapi version diff --git a/dll/win32/dbghelp/dbghelp_private.h b/dll/win32/dbghelp/dbghelp_private.h index 31dc7027e3b..e7e3c7c3c37 100644 --- a/dll/win32/dbghelp/dbghelp_private.h +++ b/dll/win32/dbghelp/dbghelp_private.h @@ -29,6 +29,7 @@ #include "objbase.h" #include "oaidl.h" #include "winnls.h" +#include "wine/list.h" #include "wine/unicode.h" #include "cvconst.h" @@ -37,13 +38,14 @@ struct pool /* poor's man */ { - struct pool_arena* first; - unsigned arena_size; + struct list arena_list; + struct list arena_full; + size_t arena_size; }; -void pool_init(struct pool* a, unsigned arena_size); +void pool_init(struct pool* a, size_t arena_size); void pool_destroy(struct pool* a); -void* pool_alloc(struct pool* a, unsigned len); +void* pool_alloc(struct pool* a, size_t len); char* pool_strdup(struct pool* a, const char* str); struct vector @@ -96,7 +98,6 @@ void hash_table_init(struct pool* pool, struct hash_table* ht, unsigned num_buckets); void hash_table_destroy(struct hash_table* ht); void hash_table_add(struct hash_table* ht, struct hash_table_elt* elt); -unsigned hash_table_hash(const char* name, unsigned num_buckets); struct hash_table_iter { @@ -116,7 +117,7 @@ void* hash_table_iter_up(struct hash_table_iter* hti); extern unsigned dbghelp_options; /* some more Wine extensions */ -#define SYMOPT_WINE_WITH_ELF_MODULES 0x40000000 +#define SYMOPT_WINE_WITH_NATIVE_MODULES 0x40000000 enum location_kind {loc_error, /* reg is the error code */ loc_absolute, /* offset is the location */ @@ -226,8 +227,6 @@ struct symt_public struct symt* container; /* compiland */ unsigned long address; unsigned long size; - unsigned in_code : 1, - is_function : 1; }; struct symt_thunk @@ -245,7 +244,7 @@ struct symt_array { struct symt symt; int start; - int end; + int end; /* end index if > 0, or -array_len (in bytes) if < 0 */ struct symt* base_type; struct symt* index_type; }; @@ -308,6 +307,7 @@ enum module_type DMT_UNKNOWN, /* for lookup, not actually used for a module */ DMT_ELF, /* a real ELF shared module */ DMT_PE, /* a native or builtin PE module */ + DMT_MACHO, /* a real Mach-O shared module */ DMT_PDB, /* .PDB file */ DMT_DBG, /* .DBG file */ }; @@ -327,12 +327,17 @@ struct module struct elf_module_info* elf_info; struct dwarf2_module_info_s*dwarf2_info; + struct macho_module_info* macho_info; + /* memory allocation pool */ struct pool pool; /* symbols & symbol tables */ + struct vector vsymt; int sortlist_valid; unsigned num_sorttab; /* number of symbols with addresses */ + unsigned num_symbols; + unsigned sorttab_size; struct symt_ht** addr_sorttab; struct hash_table ht_symbols; void (*loc_compute)(struct process* pcs, @@ -355,8 +360,9 @@ struct process struct process* next; HANDLE handle; WCHAR* search_path; - + PSYMBOL_REGISTERED_CALLBACK64 reg_cb; + PSYMBOL_REGISTERED_CALLBACK reg_cb32; BOOL reg_is_unicode; DWORD64 reg_user; @@ -411,17 +417,62 @@ struct pdb_lookup } u; }; +struct cpu_stack_walk +{ + HANDLE hProcess; + HANDLE hThread; + BOOL is32; + union + { + struct + { + PREAD_PROCESS_MEMORY_ROUTINE f_read_mem; + PTRANSLATE_ADDRESS_ROUTINE f_xlat_adr; + PFUNCTION_TABLE_ACCESS_ROUTINE f_tabl_acs; + PGET_MODULE_BASE_ROUTINE f_modl_bas; + } s32; + struct + { + PREAD_PROCESS_MEMORY_ROUTINE64 f_read_mem; + PTRANSLATE_ADDRESS_ROUTINE64 f_xlat_adr; + PFUNCTION_TABLE_ACCESS_ROUTINE64 f_tabl_acs; + PGET_MODULE_BASE_ROUTINE64 f_modl_bas; + } s64; + } u; +}; + +enum cpu_addr {cpu_addr_pc, cpu_addr_stack, cpu_addr_frame}; +struct cpu +{ + DWORD machine; + DWORD word_size; + /* address manipulation */ + unsigned (*get_addr)(HANDLE hThread, const CONTEXT* ctx, + enum cpu_addr, ADDRESS64* addr); + + /* stack manipulation */ + BOOL (*stack_walk)(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame); +}; + +extern struct cpu* dbghelp_current_cpu; + /* dbghelp.c */ extern struct process* process_find_by_handle(HANDLE hProcess); extern HANDLE hMsvcrt; extern BOOL validate_addr64(DWORD64 addr); extern BOOL pcs_callback(const struct process* pcs, ULONG action, void* data); extern void* fetch_buffer(struct process* pcs, unsigned size); +extern const char* wine_dbgstr_addr(const ADDRESS64* addr); +extern struct cpu* cpu_find(DWORD); + +/* crc32.c */ +extern DWORD calc_crc32(int fd); + +typedef BOOL (*enum_modules_cb)(const WCHAR*, unsigned long addr, void* user); /* elf_module.c */ -#define ELF_NO_MAP ((const void*)0xffffffff) -typedef BOOL (*elf_enum_modules_cb)(const WCHAR*, unsigned long addr, void* user); -extern BOOL elf_enum_modules(HANDLE hProc, elf_enum_modules_cb, void*); +#define ELF_NO_MAP ((const void*)-1) +extern BOOL elf_enum_modules(HANDLE hProc, enum_modules_cb, void*); extern BOOL elf_fetch_file_info(const WCHAR* name, DWORD* base, DWORD* size, DWORD* checksum); struct elf_file_map; extern BOOL elf_load_debug_info(struct module* module, struct elf_file_map* fmap); @@ -431,21 +482,27 @@ extern BOOL elf_read_wine_loader_dbg_info(struct process* pcs); extern BOOL elf_synchronize_module_list(struct process* pcs); struct elf_thunk_area; extern int elf_is_in_thunk_area(unsigned long addr, const struct elf_thunk_area* thunks); -extern DWORD WINAPI addr_to_linear(HANDLE hProcess, HANDLE hThread, ADDRESS* addr); + +/* macho_module.c */ +#define MACHO_NO_MAP ((const void*)-1) +extern BOOL macho_enum_modules(HANDLE hProc, enum_modules_cb, void*); +extern BOOL macho_fetch_file_info(const WCHAR* name, DWORD* base, DWORD* size, DWORD* checksum); +struct macho_file_map; +extern BOOL macho_load_debug_info(struct module* module, struct macho_file_map* fmap); +extern struct module* + macho_load_module(struct process* pcs, const WCHAR* name, unsigned long); +extern BOOL macho_read_wine_loader_dbg_info(struct process* pcs); +extern BOOL macho_synchronize_module_list(struct process* pcs); /* module.c */ extern const WCHAR S_ElfW[]; extern const WCHAR S_WineLoaderW[]; -extern const WCHAR S_WinePThreadW[]; -extern const WCHAR S_WineKThreadW[]; +extern const WCHAR S_WineW[]; extern const WCHAR S_SlashW[]; extern struct module* module_find_by_addr(const struct process* pcs, unsigned long addr, enum module_type type); -extern struct module* - module_find_by_name(const struct process* pcs, - const WCHAR* name); extern struct module* module_find_by_nameA(const struct process* pcs, const char* name); @@ -456,11 +513,8 @@ extern BOOL module_get_debug(struct module_pair*); extern struct module* module_new(struct process* pcs, const WCHAR* name, enum module_type type, BOOL virtual, - unsigned long addr, unsigned long size, + DWORD64 addr, DWORD64 size, unsigned long stamp, unsigned long checksum); -extern struct module* - module_get_container(const struct process* pcs, - const struct module* inner); extern struct module* module_get_containee(const struct process* pcs, const struct module* inner); @@ -485,13 +539,13 @@ extern BOOL path_find_symbol_file(const struct process* pcs, PCSTR full_ BOOL* is_unmatched); /* pe_module.c */ -extern BOOL pe_load_nt_header(HANDLE hProc, DWORD base, IMAGE_NT_HEADERS* nth); +extern BOOL pe_load_nt_header(HANDLE hProc, DWORD64 base, IMAGE_NT_HEADERS* nth); extern struct module* pe_load_native_module(struct process* pcs, const WCHAR* name, HANDLE hFile, DWORD base, DWORD size); extern struct module* pe_load_builtin_module(struct process* pcs, const WCHAR* name, - DWORD base, DWORD size); + DWORD64 base, DWORD64 size); extern BOOL pe_load_debug_info(const struct process* pcs, struct module* module); /* source.c */ @@ -499,9 +553,14 @@ extern unsigned source_new(struct module* module, const char* basedir, const extern const char* source_get(const struct module* module, unsigned idx); /* stabs.c */ +typedef void (*stabs_def_cb)(struct module* module, unsigned long load_offset, + const char* name, unsigned long offset, + BOOL is_public, BOOL is_global, unsigned char other, + struct symt_compiland* compiland, void* user); extern BOOL stabs_parse(struct module* module, unsigned long load_offset, const void* stabs, int stablen, - const char* strs, int strtablen); + const char* strs, int strtablen, + stabs_def_cb callback, void* user); /* dwarf.c */ extern BOOL dwarf2_parse(struct module* module, unsigned long load_offset, @@ -512,12 +571,19 @@ extern BOOL dwarf2_parse(struct module* module, unsigned long load_offse const unsigned char* line, unsigned int line_size, const unsigned char* loclist, unsigned int loclist_size); +/* stack.c */ +extern BOOL sw_read_mem(struct cpu_stack_walk* csw, DWORD64 addr, void* ptr, DWORD sz); +extern DWORD64 sw_xlat_addr(struct cpu_stack_walk* csw, ADDRESS64* addr); +extern void* sw_table_access(struct cpu_stack_walk* csw, DWORD64 addr); +extern DWORD64 sw_module_base(struct cpu_stack_walk* csw, DWORD64 addr); + /* symbol.c */ extern const char* symt_get_name(const struct symt* sym); +extern struct module* symt_cmp_addr_module; extern int symt_cmp_addr(const void* p1, const void* p2); extern void copy_symbolW(SYMBOL_INFOW* siw, const SYMBOL_INFO* si); extern struct symt_ht* - symt_find_nearest(struct module* module, DWORD addr); + symt_find_nearest(struct module* module, DWORD_PTR addr); extern struct symt_compiland* symt_new_compiland(struct module* module, unsigned long address, unsigned src_idx); @@ -525,8 +591,7 @@ extern struct symt_public* symt_new_public(struct module* module, struct symt_compiland* parent, const char* typename, - unsigned long address, unsigned size, - BOOL in_code, BOOL is_func); + unsigned long address, unsigned size); extern struct symt_data* symt_new_global_variable(struct module* module, struct symt_compiland* parent, @@ -540,7 +605,7 @@ extern struct symt_function* unsigned long addr, unsigned long size, struct symt* type); extern BOOL symt_normalize_function(struct module* module, - struct symt_function* func); + const struct symt_function* func); extern void symt_add_func_line(struct module* module, struct symt_function* func, unsigned source_idx, int line_num, @@ -558,7 +623,7 @@ extern struct symt_block* unsigned pc, unsigned len); extern struct symt_block* symt_close_func_block(struct module* module, - struct symt_function* func, + const struct symt_function* func, struct symt_block* block, unsigned pc); extern struct symt_hierarchy_point* symt_add_function_point(struct module* module, @@ -568,8 +633,8 @@ extern struct symt_hierarchy_point* const char* name); extern BOOL symt_fill_func_line_info(const struct module* module, const struct symt_function* func, - DWORD addr, IMAGEHLP_LINE* line); -extern BOOL symt_get_func_line_next(const struct module* module, PIMAGEHLP_LINE line); + DWORD64 addr, IMAGEHLP_LINE64* line); +extern BOOL symt_get_func_line_next(const struct module* module, PIMAGEHLP_LINE64 line); extern struct symt_thunk* symt_new_thunk(struct module* module, struct symt_compiland* parent, @@ -584,10 +649,12 @@ extern struct symt_hierarchy_point* symt_new_label(struct module* module, struct symt_compiland* compiland, const char* name, unsigned long address); +extern struct symt* symt_index2ptr(struct module* module, DWORD id); +extern DWORD symt_ptr2index(struct module* module, const struct symt* sym); /* type.c */ extern void symt_init_basic(struct module* module); -extern BOOL symt_get_info(const struct symt* type, +extern BOOL symt_get_info(struct module* module, const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req, void* pInfo); extern struct symt_basic* symt_new_basic(struct module* module, enum BasicType, diff --git a/dll/win32/dbghelp/dwarf.c b/dll/win32/dbghelp/dwarf.c index 3667c6769cc..433dca88ff4 100644 --- a/dll/win32/dbghelp/dwarf.c +++ b/dll/win32/dbghelp/dwarf.c @@ -72,7 +72,7 @@ static void dump(const void* ptr, unsigned len) int i, j; BYTE msg[128]; static const char hexof[] = "0123456789abcdef"; - const BYTE* x = (const BYTE*)ptr; + const BYTE* x = ptr; for (i = 0; i < len; i += 16) { @@ -217,7 +217,7 @@ static unsigned char dwarf2_parse_byte(dwarf2_traverse_context_t* ctx) static unsigned short dwarf2_get_u2(const unsigned char* ptr) { - return *(const unsigned short*)ptr; + return *(const UINT16*)ptr; } static unsigned short dwarf2_parse_u2(dwarf2_traverse_context_t* ctx) @@ -229,7 +229,7 @@ static unsigned short dwarf2_parse_u2(dwarf2_traverse_context_t* ctx) static unsigned long dwarf2_get_u4(const unsigned char* ptr) { - return *(const unsigned long*)ptr; + return *(const UINT32*)ptr; } static unsigned long dwarf2_parse_u4(dwarf2_traverse_context_t* ctx) @@ -239,6 +239,18 @@ static unsigned long dwarf2_parse_u4(dwarf2_traverse_context_t* ctx) return uvalue; } +static DWORD64 dwarf2_get_u8(const unsigned char* ptr) +{ + return *(const UINT64*)ptr; +} + +static DWORD64 dwarf2_parse_u8(dwarf2_traverse_context_t* ctx) +{ + DWORD64 uvalue = dwarf2_get_u8(ctx->data); + ctx->data += 8; + return uvalue; +} + static unsigned long dwarf2_get_leb128_as_unsigned(const unsigned char* ptr, const unsigned char** end) { unsigned long ret = 0; @@ -309,6 +321,13 @@ static unsigned dwarf2_leb128_length(const dwarf2_traverse_context_t* ctx) return ret + 1; } +/****************************************************************** + * dwarf2_get_addr + * + * Returns an address. + * We assume that in all cases word size from Dwarf matches the size of + * addresses in platform where the exec is compiled. + */ static unsigned long dwarf2_get_addr(const unsigned char* ptr, unsigned word_size) { unsigned long ret; @@ -318,6 +337,9 @@ static unsigned long dwarf2_get_addr(const unsigned char* ptr, unsigned word_siz case 4: ret = dwarf2_get_u4(ptr); break; + case 8: + ret = dwarf2_get_u8(ptr); + break; default: FIXME("Unsupported Word Size %u\n", word_size); ret = 0; @@ -490,7 +512,9 @@ static void dwarf2_fill_attr(const dwarf2_parse_context_t* ctx, break; case DW_FORM_data8: - FIXME("Unhandled 64bits support\n"); + attr->u.block.size = 8; + attr->u.block.ptr = data; + data += 8; break; case DW_FORM_ref1: @@ -652,7 +676,7 @@ static enum location_error compute_location(dwarf2_traverse_context_t* ctx, struct location* loc, HANDLE hproc, const struct location* frame) { - unsigned long stack[64]; + DWORD_PTR tmp, stack[64]; unsigned stk; unsigned char op; BOOL piece_found = FALSE; @@ -665,27 +689,11 @@ compute_location(dwarf2_traverse_context_t* ctx, struct location* loc, while (ctx->data < ctx->end_data) { op = dwarf2_parse_byte(ctx); - switch (op) + + if (op >= DW_OP_lit0 && op <= DW_OP_lit31) + stack[++stk] = op - DW_OP_lit0; + else if (op >= DW_OP_reg0 && op <= DW_OP_reg31) { - case DW_OP_addr: stack[++stk] = dwarf2_parse_addr(ctx); break; - case DW_OP_const1u: stack[++stk] = dwarf2_parse_byte(ctx); break; - case DW_OP_const1s: stack[++stk] = (long)(signed char)dwarf2_parse_byte(ctx); break; - case DW_OP_const2u: stack[++stk] = dwarf2_parse_u2(ctx); break; - case DW_OP_const2s: stack[++stk] = (long)(short)dwarf2_parse_u2(ctx); break; - case DW_OP_const4u: stack[++stk] = dwarf2_parse_u4(ctx); break; - case DW_OP_const4s: stack[++stk] = dwarf2_parse_u4(ctx); break; - case DW_OP_constu: stack[++stk] = dwarf2_leb128_as_unsigned(ctx); break; - case DW_OP_consts: stack[++stk] = dwarf2_leb128_as_signed(ctx); break; - case DW_OP_plus_uconst: - stack[stk] += dwarf2_leb128_as_unsigned(ctx); break; - case DW_OP_reg0: case DW_OP_reg1: case DW_OP_reg2: case DW_OP_reg3: - case DW_OP_reg4: case DW_OP_reg5: case DW_OP_reg6: case DW_OP_reg7: - case DW_OP_reg8: case DW_OP_reg9: case DW_OP_reg10: case DW_OP_reg11: - case DW_OP_reg12: case DW_OP_reg13: case DW_OP_reg14: case DW_OP_reg15: - case DW_OP_reg16: case DW_OP_reg17: case DW_OP_reg18: case DW_OP_reg19: - case DW_OP_reg20: case DW_OP_reg21: case DW_OP_reg22: case DW_OP_reg23: - case DW_OP_reg24: case DW_OP_reg25: case DW_OP_reg26: case DW_OP_reg27: - case DW_OP_reg28: case DW_OP_reg29: case DW_OP_reg30: case DW_OP_reg31: /* dbghelp APIs don't know how to cope with this anyway * (for example 'long long' stored in two registers) * FIXME: We should tell winedbg how to deal with it (sigh) @@ -698,15 +706,9 @@ compute_location(dwarf2_traverse_context_t* ctx, struct location* loc, loc->reg = dwarf2_map_register(op - DW_OP_reg0); } loc->kind = loc_register; - break; - case DW_OP_breg0: case DW_OP_breg1: case DW_OP_breg2: case DW_OP_breg3: - case DW_OP_breg4: case DW_OP_breg5: case DW_OP_breg6: case DW_OP_breg7: - case DW_OP_breg8: case DW_OP_breg9: case DW_OP_breg10: case DW_OP_breg11: - case DW_OP_breg12: case DW_OP_breg13: case DW_OP_breg14: case DW_OP_breg15: - case DW_OP_breg16: case DW_OP_breg17: case DW_OP_breg18: case DW_OP_breg19: - case DW_OP_breg20: case DW_OP_breg21: case DW_OP_breg22: case DW_OP_breg23: - case DW_OP_breg24: case DW_OP_breg25: case DW_OP_breg26: case DW_OP_breg27: - case DW_OP_breg28: case DW_OP_breg29: case DW_OP_breg30: case DW_OP_breg31: + } + else if (op >= DW_OP_breg0 && op <= DW_OP_breg31) + { /* dbghelp APIs don't know how to cope with this anyway * (for example 'long long' stored in two registers) * FIXME: We should tell winedbg how to deal with it (sigh) @@ -714,13 +716,71 @@ compute_location(dwarf2_traverse_context_t* ctx, struct location* loc, if (!piece_found) { if (loc->reg != Wine_DW_no_register) - FIXME("Only supporting one reg (%d -> %d)\n", + FIXME("Only supporting one breg (%d -> %d)\n", loc->reg, dwarf2_map_register(op - DW_OP_breg0)); loc->reg = dwarf2_map_register(op - DW_OP_breg0); } stack[++stk] = dwarf2_leb128_as_signed(ctx); loc->kind = loc_regrel; break; + } + else switch (op) + { + case DW_OP_nop: break; + case DW_OP_addr: stack[++stk] = dwarf2_parse_addr(ctx); break; + case DW_OP_const1u: stack[++stk] = dwarf2_parse_byte(ctx); break; + case DW_OP_const1s: stack[++stk] = dwarf2_parse_byte(ctx); break; + case DW_OP_const2u: stack[++stk] = dwarf2_parse_u2(ctx); break; + case DW_OP_const2s: stack[++stk] = dwarf2_parse_u2(ctx); break; + case DW_OP_const4u: stack[++stk] = dwarf2_parse_u4(ctx); break; + case DW_OP_const4s: stack[++stk] = dwarf2_parse_u4(ctx); break; + case DW_OP_const8u: stack[++stk] = dwarf2_parse_u8(ctx); break; + case DW_OP_const8s: stack[++stk] = dwarf2_parse_u8(ctx); break; + case DW_OP_constu: stack[++stk] = dwarf2_leb128_as_unsigned(ctx); break; + case DW_OP_consts: stack[++stk] = dwarf2_leb128_as_signed(ctx); break; + case DW_OP_dup: stack[stk + 1] = stack[stk]; stk++; break; + case DW_OP_drop: stk--; break; + case DW_OP_over: stack[stk + 1] = stack[stk - 1]; stk++; break; + case DW_OP_pick: stack[stk + 1] = stack[stk - dwarf2_parse_byte(ctx)]; stk++; break; + case DW_OP_swap: tmp = stack[stk]; stack[stk] = stack[stk-1]; stack[stk-1] = tmp; break; + case DW_OP_rot: tmp = stack[stk]; stack[stk] = stack[stk-1]; stack[stk-1] = stack[stk-2]; stack[stk-2] = tmp; break; + case DW_OP_abs: stack[stk] = labs(stack[stk]); break; + case DW_OP_neg: stack[stk] = -stack[stk]; break; + case DW_OP_not: stack[stk] = ~stack[stk]; break; + case DW_OP_and: stack[stk-1] &= stack[stk]; stk--; break; + case DW_OP_or: stack[stk-1] |= stack[stk]; stk--; break; + case DW_OP_minus: stack[stk-1] -= stack[stk]; stk--; break; + case DW_OP_mul: stack[stk-1] *= stack[stk]; stk--; break; + case DW_OP_plus: stack[stk-1] += stack[stk]; stk--; break; + case DW_OP_xor: stack[stk-1] ^= stack[stk]; stk--; break; + case DW_OP_shl: stack[stk-1] <<= stack[stk]; stk--; break; + case DW_OP_shr: stack[stk-1] >>= stack[stk]; stk--; break; + case DW_OP_plus_uconst: stack[stk] += dwarf2_leb128_as_unsigned(ctx); break; + case DW_OP_shra: stack[stk-1] = stack[stk-1] / (1 << stack[stk]); stk--; break; + case DW_OP_div: stack[stk-1] = stack[stk-1] / stack[stk]; stk--; break; + case DW_OP_mod: stack[stk-1] = stack[stk-1] % stack[stk]; stk--; break; + case DW_OP_ge: stack[stk-1] = (stack[stk-1] >= stack[stk]); stk--; break; + case DW_OP_gt: stack[stk-1] = (stack[stk-1] > stack[stk]); stk--; break; + case DW_OP_le: stack[stk-1] = (stack[stk-1] <= stack[stk]); stk--; break; + case DW_OP_lt: stack[stk-1] = (stack[stk-1] < stack[stk]); stk--; break; + case DW_OP_eq: stack[stk-1] = (stack[stk-1] == stack[stk]); stk--; break; + case DW_OP_ne: stack[stk-1] = (stack[stk-1] != stack[stk]); stk--; break; + case DW_OP_skip: tmp = dwarf2_parse_u2(ctx); ctx->data += tmp; break; + case DW_OP_bra: tmp = dwarf2_parse_u2(ctx); if (!stack[stk--]) ctx->data += tmp; break; + case DW_OP_regx: + if (loc->reg != Wine_DW_no_register) + FIXME("Only supporting one regx\n"); + loc->reg = dwarf2_map_register(dwarf2_leb128_as_unsigned(ctx)); + loc->kind = loc_register; + break; + case DW_OP_bregx: + tmp = dwarf2_leb128_as_unsigned(ctx); + ctx->data++; + if (loc->reg != Wine_DW_no_register) + FIXME("Only supporting one regx\n"); + loc->reg = dwarf2_map_register(tmp) + dwarf2_leb128_as_signed(ctx); + loc->kind = loc_register; + break; case DW_OP_fbreg: if (loc->reg != Wine_DW_no_register) FIXME("Only supporting one reg (%d -> -2)\n", loc->reg); @@ -765,12 +825,12 @@ compute_location(dwarf2_traverse_context_t* ctx, struct location* loc, } if (hproc) { - DWORD addr = stack[stk--]; - DWORD deref; + DWORD_PTR addr = stack[stk--]; + DWORD_PTR deref; if (!ReadProcessMemory(hproc, (void*)addr, &deref, sizeof(deref), NULL)) { - WARN("Couldn't read memory at %x\n", addr); + WARN("Couldn't read memory at %lx\n", addr); return loc_err_cant_read; } stack[++stk] = deref; @@ -780,8 +840,46 @@ compute_location(dwarf2_traverse_context_t* ctx, struct location* loc, loc->kind = loc_dwarf2_block; } break; + case DW_OP_deref_size: + if (!stk) + { + FIXME("Unexpected empty stack\n"); + return loc_err_internal; + } + if (loc->reg != Wine_DW_no_register) + { + WARN("Too complex expression for deref\n"); + return loc_err_too_complex; + } + if (hproc) + { + DWORD_PTR addr = stack[stk--]; + BYTE derefsize = dwarf2_parse_byte(ctx); + DWORD64 deref; + + if (!ReadProcessMemory(hproc, (void*)addr, &deref, derefsize, NULL)) + { + WARN("Couldn't read memory at %lx\n", addr); + return loc_err_cant_read; + } + + switch (derefsize) + { + case 1: stack[++stk] = *(unsigned char*)&deref; break; + case 2: stack[++stk] = *(unsigned short*)&deref; break; + case 4: stack[++stk] = *(DWORD*)&deref; break; + case 8: if (ctx->word_size >= derefsize) stack[++stk] = deref; break; + } + } + else + { + loc->kind = loc_dwarf2_block; + } + break; default: - FIXME("Unhandled attr op: %x\n", op); + if (op < DW_OP_lo_user) /* as DW_OP_hi_user is 0xFF, we don't need to test against it */ + FIXME("Unhandled attr op: %x\n", op); + /* FIXME else unhandled extension */ return loc_err_internal; } } @@ -1163,7 +1261,8 @@ static void dwarf2_parse_udt_member(dwarf2_parse_context_t* ctx, if (!dwarf2_find_attribute(ctx, di, DW_AT_byte_size, &nbytes)) { DWORD64 size; - nbytes.u.uvalue = symt_get_info(elt_type, TI_GET_LENGTH, &size) ? (unsigned long)size : 0; + nbytes.u.uvalue = symt_get_info(ctx->module, elt_type, TI_GET_LENGTH, &size) ? + (unsigned long)size : 0; } bit_offset.u.uvalue = nbytes.u.uvalue * 8 - bit_offset.u.uvalue - bit_size.u.uvalue; } @@ -1214,6 +1313,10 @@ static struct symt* dwarf2_parse_udt_type(dwarf2_parse_context_t* ctx, case DW_TAG_union_type: case DW_TAG_typedef: /* FIXME: we need to handle nested udt definitions */ + case DW_TAG_inheritance: + case DW_TAG_subprogram: + case DW_TAG_variable: + /* FIXME: some C++ related stuff */ break; default: FIXME("Unhandled Tag type 0x%lx at %s, for %s\n", @@ -1334,6 +1437,8 @@ static void dwarf2_parse_variable(dwarf2_subprogram_t* subpgm, switch (loc.kind) { + case loc_error: + break; case loc_absolute: /* it's a global variable */ /* FIXME: we don't handle its scope yet */ @@ -1389,11 +1494,28 @@ static void dwarf2_parse_variable(dwarf2_subprogram_t* subpgm, v.n1.n2.n3.byref = pool_strdup(&subpgm->ctx->module->pool, value.u.string); break; - case DW_FORM_data8: case DW_FORM_block: case DW_FORM_block1: case DW_FORM_block2: case DW_FORM_block4: + v.n1.n2.vt = VT_I4; + switch (value.u.block.size) + { + case 1: v.n1.n2.n3.lVal = *(BYTE*)value.u.block.ptr; break; + case 2: v.n1.n2.n3.lVal = *(USHORT*)value.u.block.ptr; break; + case 4: v.n1.n2.n3.lVal = *(DWORD*)value.u.block.ptr; break; + default: + v.n1.n2.vt = VT_I1 | VT_BYREF; + v.n1.n2.n3.byref = pool_alloc(&subpgm->ctx->module->pool, value.u.block.size); + memcpy(v.n1.n2.n3.byref, value.u.block.ptr, value.u.block.size); + } + break; + + case DW_FORM_data8: + v.n1.n2.vt = VT_I1 | VT_BYREF; + v.n1.n2.n3.byref = pool_alloc(&subpgm->ctx->module->pool, value.u.block.size); + memcpy(v.n1.n2.n3.byref, value.u.block.ptr, value.u.block.size); + break; default: FIXME("Unsupported form for const value %s (%lx)\n", @@ -1786,6 +1908,11 @@ static void dwarf2_load_one_entry(dwarf2_parse_context_t* ctx, dwarf2_parse_variable(&subpgm, NULL, di); } break; + /* silence a couple of C++ defines */ + case DW_TAG_namespace: + case DW_TAG_imported_module: + case DW_TAG_imported_declaration: + break; default: FIXME("Unhandled Tag type 0x%lx at %s, for %lu\n", di->abbrev->tag, dwarf2_debug_ctx(ctx), di->abbrev->entry_code); @@ -2010,7 +2137,7 @@ static BOOL dwarf2_parse_compilation_unit(const dwarf2_section_t* sections, cu_ctx.word_size = dwarf2_parse_byte(&cu_ctx); TRACE("Compilation Unit Header found at 0x%x:\n", - comp_unit_start - sections[section_debug].address); + (int)(comp_unit_start - sections[section_debug].address)); TRACE("- length: %lu\n", cu_length); TRACE("- version: %u\n", cu_version); TRACE("- abbrev_offset: %lu\n", cu_abbrev_offset); diff --git a/dll/win32/dbghelp/dwarf.h b/dll/win32/dbghelp/dwarf.h index e7a0a7e4824..a590df2c9f0 100644 --- a/dll/win32/dbghelp/dwarf.h +++ b/dll/win32/dbghelp/dwarf.h @@ -376,6 +376,18 @@ typedef enum dwarf_operation_e DW_OP_call2 = 0x98, DW_OP_call4 = 0x99, DW_OP_call_ref = 0x9a, + DW_OP_form_tls_address = 0x9b, + DW_OP_call_frame_cfa = 0x9c, + DW_OP_bit_piece = 0x9d, + + /* Implementation defined extensions */ + DW_OP_lo_user = 0xe0, + DW_OP_hi_user = 0xff, + + /* GNU extensions */ + DW_OP_GNU_push_tls_address = 0xe0, + DW_OP_GNU_uninit = 0xf0, + DW_OP_GNU_encoded_addr = 0xf1, } dwarf_operation_t; enum dwarf_calling_convention diff --git a/dll/win32/dbghelp/elf_module.c b/dll/win32/dbghelp/elf_module.c index 30b7a3c0102..6a8a1515f9d 100644 --- a/dll/win32/dbghelp/elf_module.c +++ b/dll/win32/dbghelp/elf_module.c @@ -77,7 +77,7 @@ struct elf_module_info { - unsigned long elf_addr; + DWORD_PTR elf_addr; unsigned short elf_mark : 1, elf_loader : 1; }; @@ -93,22 +93,36 @@ WINE_DEFAULT_DEBUG_CHANNEL(dbghelp); struct elf_info { unsigned flags; /* IN one (or several) of the ELF_INFO constants */ - unsigned long dbg_hdr_addr; /* OUT address of debug header (if ELF_INFO_DEBUG_HEADER is set) */ + DWORD_PTR dbg_hdr_addr; /* OUT address of debug header (if ELF_INFO_DEBUG_HEADER is set) */ struct module* module; /* OUT loaded module (if ELF_INFO_MODULE is set) */ const WCHAR* module_name; /* OUT found module name (if ELF_INFO_NAME is set) */ }; +#ifdef _WIN64 +#define Elf_Ehdr Elf64_Ehdr +#define Elf_Shdr Elf64_Shdr +#define Elf_Phdr Elf64_Phdr +#define Elf_Dyn Elf64_Dyn +#define Elf_Sym Elf64_Sym +#else +#define Elf_Ehdr Elf32_Ehdr +#define Elf_Shdr Elf32_Shdr +#define Elf_Phdr Elf32_Phdr +#define Elf_Dyn Elf32_Dyn +#define Elf_Sym Elf32_Sym +#endif + /* structure holding information while handling an ELF image * allows one by one section mapping for memory savings */ struct elf_file_map { - Elf32_Ehdr elfhdr; + Elf_Ehdr elfhdr; size_t elf_size; size_t elf_start; struct { - Elf32_Shdr shdr; + Elf_Shdr shdr; const char* mapped; }* sect; int fd; @@ -125,7 +139,7 @@ struct elf_section_map struct symtab_elt { struct hash_table_elt ht_elt; - const Elf32_Sym* symp; + const Elf_Sym* symp; struct symt_compiland* compiland; unsigned used; }; @@ -237,7 +251,7 @@ static void elf_end_find(struct elf_file_map* fmap) * * Get the size of an ELF section */ -static inline unsigned elf_get_map_size(struct elf_section_map* esm) +static inline unsigned elf_get_map_size(const struct elf_section_map* esm) { if (esm->sidx < 0 || esm->sidx >= esm->fmap->elfhdr.e_shnum) return 0; @@ -254,7 +268,7 @@ static BOOL elf_map_file(const WCHAR* filenameW, struct elf_file_map* fmap) static const BYTE elf_signature[4] = { ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3 }; struct stat statbuf; int i; - Elf32_Phdr phdr; + Elf_Phdr phdr; unsigned tmp, page_mask = getpagesize() - 1; char* filename; unsigned len; @@ -279,7 +293,12 @@ static BOOL elf_map_file(const WCHAR* filenameW, struct elf_file_map* fmap) /* and check for an ELF header */ if (memcmp(fmap->elfhdr.e_ident, elf_signature, sizeof(elf_signature))) goto done; - + /* and check 32 vs 64 size according to current machine */ +#ifdef _WIN64 + if (fmap->elfhdr.e_ident[EI_CLASS] != ELFCLASS64) goto done; +#else + if (fmap->elfhdr.e_ident[EI_CLASS] != ELFCLASS32) goto done; +#endif fmap->sect = HeapAlloc(GetProcessHeap(), 0, fmap->elfhdr.e_shnum * sizeof(fmap->sect[0])); if (!fmap->sect) goto done; @@ -350,7 +369,7 @@ int elf_is_in_thunk_area(unsigned long addr, { unsigned i; - for (i = 0; thunks[i].symname; i++) + if (thunks) for (i = 0; thunks[i].symname; i++) { if (addr >= thunks[i].rva_start && addr < thunks[i].rva_end) return i; @@ -372,13 +391,13 @@ static void elf_hash_symtab(struct module* module, struct pool* pool, const char* symname; struct symt_compiland* compiland = NULL; const char* ptr; - const Elf32_Sym* symp; + const Elf_Sym* symp; struct symtab_elt* ste; struct elf_section_map esm, esm_str; if (!elf_find_section(fmap, ".symtab", SHT_SYMTAB, &esm) && !elf_find_section(fmap, ".dynsym", SHT_DYNSYM, &esm)) return; - if ((symp = (const Elf32_Sym*)elf_map_section(&esm)) == ELF_NO_MAP) return; + if ((symp = (const Elf_Sym*)elf_map_section(&esm)) == ELF_NO_MAP) return; esm_str.fmap = fmap; esm_str.sidx = fmap->sect[esm.sidx].shdr.sh_link; if ((strp = elf_map_section(&esm_str)) == ELF_NO_MAP) return; @@ -471,9 +490,9 @@ static void elf_hash_symtab(struct module* module, struct pool* pool, * * lookup a symbol by name in our internal hash table for the symtab */ -static const Elf32_Sym* elf_lookup_symtab(const struct module* module, +static const Elf_Sym* elf_lookup_symtab(const struct module* module, const struct hash_table* ht_symtab, - const char* name, struct symt* compiland) + const char* name, const struct symt* compiland) { struct symtab_elt* weak_result = NULL; /* without compiland name */ struct symtab_elt* result = NULL; @@ -490,7 +509,7 @@ static const Elf32_Sym* elf_lookup_symtab(const struct module* module, if (compiland) { compiland_name = source_get(module, - ((struct symt_compiland*)compiland)->source); + ((const struct symt_compiland*)compiland)->source); compiland_basename = strrchr(compiland_name, '/'); if (!compiland_basename++) compiland_basename = compiland_name; } @@ -542,12 +561,12 @@ static const Elf32_Sym* elf_lookup_symtab(const struct module* module, * - get any relevant information (address & size) from the bits we got from the * stabs debugging information */ -static void elf_finish_stabs_info(struct module* module, struct hash_table* symtab) +static void elf_finish_stabs_info(struct module* module, const struct hash_table* symtab) { struct hash_table_iter hti; void* ptr; struct symt_ht* sym; - const Elf32_Sym* symp; + const Elf_Sym* symp; hash_table_iter_init(&module->ht_symbols, &hti, NULL); while ((ptr = hash_table_iter_up(&hti))) @@ -623,13 +642,13 @@ static void elf_finish_stabs_info(struct module* module, struct hash_table* symt * * creating the thunk objects for a wine native DLL */ -static int elf_new_wine_thunks(struct module* module, struct hash_table* ht_symtab, +static int elf_new_wine_thunks(struct module* module, const struct hash_table* ht_symtab, const struct elf_thunk_area* thunks) { int j; struct hash_table_iter hti; struct symtab_elt* ste; - DWORD addr; + DWORD_PTR addr; struct symt_ht* symt; hash_table_iter_init(ht_symtab, &hti, NULL); @@ -650,8 +669,8 @@ static int elf_new_wine_thunks(struct module* module, struct hash_table* ht_symt ULONG64 ref_addr; symt = symt_find_nearest(module, addr); - if (symt) - symt_get_info(&symt->symt, TI_GET_ADDRESS, &ref_addr); + if (symt && !symt_get_info(module, &symt->symt, TI_GET_ADDRESS, &ref_addr)) + ref_addr = addr; if (!symt || addr != ref_addr) { /* creating public symbols for all the ELF symbols which haven't been @@ -687,9 +706,9 @@ static int elf_new_wine_thunks(struct module* module, struct hash_table* ht_symt ULONG64 xaddr = 0, xsize = 0; DWORD kind = -1; - symt_get_info(&symt->symt, TI_GET_ADDRESS, &xaddr); - symt_get_info(&symt->symt, TI_GET_LENGTH, &xsize); - symt_get_info(&symt->symt, TI_GET_DATAKIND, &kind); + symt_get_info(module, &symt->symt, TI_GET_ADDRESS, &xaddr); + symt_get_info(module, &symt->symt, TI_GET_LENGTH, &xsize); + symt_get_info(module, &symt->symt, TI_GET_DATAKIND, &kind); /* If none of symbols has a correct size, we consider they are both markers * Hence, we can silence this warning @@ -698,7 +717,7 @@ static int elf_new_wine_thunks(struct module* module, struct hash_table* ht_symt */ if ((xsize || ste->symp->st_size) && (kind == (ELF32_ST_BIND(ste->symp->st_info) == STB_LOCAL) ? DataIsFileStatic : DataIsGlobal)) - FIXME("Duplicate in %s: %s<%08x-%08x> %s<%s-%s>\n", + FIXME("Duplicate in %s: %s<%08lx-%08x> %s<%s-%s>\n", debugstr_w(module->module.ModuleName), ste->ht_elt.name, addr, (unsigned int)ste->symp->st_size, symt->hash_elt.name, @@ -716,7 +735,7 @@ static int elf_new_wine_thunks(struct module* module, struct hash_table* ht_symt * * Creates a set of public symbols from an ELF symtab */ -static int elf_new_public_symbols(struct module* module, struct hash_table* symtab) +static int elf_new_public_symbols(struct module* module, const struct hash_table* symtab) { struct hash_table_iter hti; struct symtab_elt* ste; @@ -730,142 +749,19 @@ static int elf_new_public_symbols(struct module* module, struct hash_table* symt { symt_new_public(module, ste->compiland, ste->ht_elt.name, module->elf_info->elf_addr + ste->symp->st_value, - ste->symp->st_size, TRUE /* FIXME */, - ELF32_ST_TYPE(ste->symp->st_info) == STT_FUNC); + ste->symp->st_size); } return TRUE; } -/* Copyright (C) 1986 Gary S. Brown. Modified by Robert Shearman. You may use - the following calc_crc32 code or tables extracted from it, as desired without - restriction. */ - -/**********************************************************************\ -|* Demonstration program to compute the 32-bit CRC used as the frame *| -|* check sequence in ADCCP (ANSI X3.66, also known as FIPS PUB 71 *| -|* and FED-STD-1003, the U.S. versions of CCITT's X.25 link-level *| -|* protocol). The 32-bit FCS was added via the Federal Register, *| -|* 1 June 1982, p.23798. I presume but don't know for certain that *| -|* this polynomial is or will be included in CCITT V.41, which *| -|* defines the 16-bit CRC (often called CRC-CCITT) polynomial. FIPS *| -|* PUB 78 says that the 32-bit FCS reduces otherwise undetected *| -|* errors by a factor of 10^-5 over 16-bit FCS. *| -\**********************************************************************/ - -/* First, the polynomial itself and its table of feedback terms. The */ -/* polynomial is */ -/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */ -/* Note that we take it "backwards" and put the highest-order term in */ -/* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ -/* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ -/* the MSB being 1. */ - -/* Note that the usual hardware shift register implementation, which */ -/* is what we're using (we're merely optimizing it by doing eight-bit */ -/* chunks at a time) shifts bits into the lowest-order term. In our */ -/* implementation, that means shifting towards the right. Why do we */ -/* do it this way? Because the calculated CRC must be transmitted in */ -/* order from highest-order term to lowest-order term. UARTs transmit */ -/* characters in order from LSB to MSB. By storing the CRC this way, */ -/* we hand it to the UART in the order low-byte to high-byte; the UART */ -/* sends each low-bit to hight-bit; and the result is transmission bit */ -/* by bit from highest- to lowest-order term without requiring any bit */ -/* shuffling on our part. Reception works similarly. */ - -/* The feedback terms table consists of 256, 32-bit entries. Notes: */ -/* */ -/* 1. The table can be generated at runtime if desired; code to do so */ -/* is shown later. It might not be obvious, but the feedback */ -/* terms simply represent the results of eight shift/xor opera- */ -/* tions for all combinations of data and CRC register values. */ -/* */ -/* 2. The CRC accumulation logic is the same for all CRC polynomials, */ -/* be they sixteen or thirty-two bits wide. You simply choose the */ -/* appropriate table. Alternatively, because the table can be */ -/* generated at runtime, you can start by generating the table for */ -/* the polynomial in question and use exactly the same "updcrc", */ -/* if your application needn't simultaneously handle two CRC */ -/* polynomials. (Note, however, that XMODEM is strange.) */ -/* */ -/* 3. For 16-bit CRCs, the table entries need be only 16 bits wide; */ -/* of course, 32-bit entries work OK if the high 16 bits are zero. */ -/* */ -/* 4. The values must be right-shifted by eight bits by the "updcrc" */ -/* logic; the shift must be unsigned (bring in zeroes). On some */ -/* hardware you could probably optimize the shift in assembler by */ -/* using byte-swap instructions. */ - - -static DWORD calc_crc32(struct elf_file_map* fmap) -{ -#define UPDC32(octet,crc) (crc_32_tab[((crc) ^ (octet)) & 0xff] ^ ((crc) >> 8)) - static const DWORD crc_32_tab[] = - { /* CRC polynomial 0xedb88320 */ - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, - 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, - 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, - 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, - 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, - 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, - 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, - 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, - 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, - 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, - 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, - 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, - 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, - 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, - 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, - 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, - 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, - 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, - 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, - 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, - 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, - 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, - 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, - 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, - 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, - 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, - 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, - 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, - 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, - 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, - 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, - 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, - 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, - 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, - 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, - 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, - 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d - }; - int i, r; - unsigned char buffer[256]; - DWORD crc = ~0; - - lseek(fmap->fd, 0, SEEK_SET); - while ((r = read(fmap->fd, buffer, sizeof(buffer))) > 0) - { - for (i = 0; i < r; i++) crc = UPDC32(buffer[i], crc); - } - return ~crc; -#undef UPDC32 -} - static BOOL elf_check_debug_link(const WCHAR* file, struct elf_file_map* fmap, DWORD crc) { BOOL ret; if (!elf_map_file(file, fmap)) return FALSE; - if (!(ret = crc == calc_crc32(fmap))) + if (!(ret = crc == calc_crc32(fmap->fd))) { WARN("Bad CRC for file %s (got %08x while expecting %08x)\n", - debugstr_w(file), calc_crc32(fmap), crc); + debugstr_w(file), calc_crc32(fmap->fd), crc); elf_unmap_file(fmap); } return ret; @@ -952,7 +848,7 @@ found: * Parses a .gnu_debuglink section and loads the debug info from * the external file specified there. */ -static BOOL elf_debuglink_parse(struct elf_file_map* fmap, struct module* module, +static BOOL elf_debuglink_parse(struct elf_file_map* fmap, const struct module* module, const BYTE* debuglink) { /* The content of a debug link section is: @@ -1039,7 +935,8 @@ static BOOL elf_load_debug_info_from_map(struct module* module, /* OK, now just parse all of the stabs. */ lret = stabs_parse(module, module->elf_info->elf_addr, stab, elf_get_map_size(&stab_sect), - stabstr, elf_get_map_size(&stabstr_sect)); + stabstr, elf_get_map_size(&stabstr_sect), + NULL, NULL); if (lret) /* and fill in the missing information for stabs */ elf_finish_stabs_info(module, ht_symtab); @@ -1160,7 +1057,7 @@ BOOL elf_fetch_file_info(const WCHAR* name, DWORD* base, if (!elf_map_file(name, &fmap)) return FALSE; if (base) *base = fmap.elf_start; *size = fmap.elf_size; - *checksum = calc_crc32(&fmap); + *checksum = calc_crc32(fmap.fd); elf_unmap_file(&fmap); return TRUE; } @@ -1184,7 +1081,7 @@ static BOOL elf_load_file(struct process* pcs, const WCHAR* filename, TRACE("Processing elf file '%s' at %08lx\n", debugstr_w(filename), load_offset); - if (!elf_map_file(filename, &fmap)) goto leave; + if (!elf_map_file(filename, &fmap)) return ret; /* Next, we need to find a few of the internal ELF headers within * this thing. We need the main executable header, and the section @@ -1206,7 +1103,7 @@ static BOOL elf_load_file(struct process* pcs, const WCHAR* filename, if (elf_find_section(&fmap, ".dynamic", SHT_DYNAMIC, &esm)) { - Elf32_Dyn dyn; + Elf_Dyn dyn; char* ptr = (char*)fmap.sect[esm.sidx].shdr.sh_addr; unsigned long len; @@ -1234,7 +1131,7 @@ static BOOL elf_load_file(struct process* pcs, const WCHAR* filename, if (!elf_module_info) goto leave; elf_info->module = module_new(pcs, filename, DMT_ELF, FALSE, (load_offset) ? load_offset : fmap.elf_start, - fmap.elf_size, 0, calc_crc32(&fmap)); + fmap.elf_size, 0, calc_crc32(fmap.fd)); if (!elf_info->module) { HeapFree(GetProcessHeap(), 0, elf_module_info); @@ -1389,7 +1286,7 @@ static BOOL elf_search_and_load_file(struct process* pcs, const WCHAR* filename, */ static BOOL elf_enum_modules_internal(const struct process* pcs, const WCHAR* main_name, - elf_enum_modules_cb cb, void* user) + enum_modules_cb cb, void* user) { struct r_debug dbg_hdr; void* lm_addr; @@ -1492,9 +1389,7 @@ static BOOL elf_search_loader(struct process* pcs, struct elf_info* elf_info) const char* ptr; /* All binaries are loaded with WINELOADER (if run from tree) or by the - * main executable (either wine-kthread or wine-pthread) - * FIXME: the heuristic used to know whether we need to load wine-pthread - * or wine-kthread is not 100% safe + * main executable */ if ((ptr = getenv("WINELOADER"))) { @@ -1504,8 +1399,7 @@ static BOOL elf_search_loader(struct process* pcs, struct elf_info* elf_info) } else { - ret = elf_search_and_load_file(pcs, S_WineKThreadW, 0, elf_info) || - elf_search_and_load_file(pcs, S_WinePThreadW, 0, elf_info); + ret = elf_search_and_load_file(pcs, S_WineW, 0, elf_info); } return ret; } @@ -1533,7 +1427,7 @@ BOOL elf_read_wine_loader_dbg_info(struct process* pcs) * This function doesn't require that someone has called SymInitialize * on this very process. */ -BOOL elf_enum_modules(HANDLE hProc, elf_enum_modules_cb cb, void* user) +BOOL elf_enum_modules(HANDLE hProc, enum_modules_cb cb, void* user) { struct process pcs; struct elf_info elf_info; @@ -1638,7 +1532,7 @@ BOOL elf_read_wine_loader_dbg_info(struct process* pcs) return FALSE; } -BOOL elf_enum_modules(HANDLE hProc, elf_enum_modules_cb cb, void* user) +BOOL elf_enum_modules(HANDLE hProc, enum_modules_cb cb, void* user) { return FALSE; } diff --git a/dll/win32/dbghelp/macho_module.c b/dll/win32/dbghelp/macho_module.c new file mode 100644 index 00000000000..379596b2f58 --- /dev/null +++ b/dll/win32/dbghelp/macho_module.c @@ -0,0 +1,1434 @@ +/* + * File macho_module.c - processing of Mach-O files + * Originally based on elf_module.c + * + * Copyright (C) 1996, Eric Youngdale. + * 1999-2007 Eric Pouech + * 2009 Ken Thomases, CodeWeavers Inc. + * + * 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 "config.h" +#include "wine/port.h" + +#include "dbghelp_private.h" + +#ifdef __MACH__ + +#include +#include +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef HAVE_SYS_MMAN_H +# include +#endif + +#include +#include +#include + +#ifdef HAVE_MACH_O_DYLD_IMAGES_H +#include +#else +struct dyld_image_info { + const struct mach_header *imageLoadAddress; + const char *imageFilePath; + uintptr_t imageFileModDate; +}; + +struct dyld_all_image_infos { + uint32_t version; + uint32_t infoArrayCount; + const struct dyld_image_info *infoArray; + void* notification; + int processDetachedFromSharedRegion; +}; +#endif + +#include "winternl.h" +#include "wine/library.h" +#include "wine/debug.h" + +#ifdef WORDS_BIGENDIAN +#define swap_ulong_be_to_host(n) (n) +#else +#define swap_ulong_be_to_host(n) (RtlUlongByteSwap(n)) +#endif + +WINE_DEFAULT_DEBUG_CHANNEL(dbghelp_macho); + + +struct macho_module_info +{ + unsigned long load_addr; + unsigned short in_use : 1, + is_loader : 1; +}; + +#define MACHO_INFO_DEBUG_HEADER 0x0001 +#define MACHO_INFO_MODULE 0x0002 +#define MACHO_INFO_NAME 0x0004 + +struct macho_info +{ + unsigned flags; /* IN one (or several) of the MACHO_INFO constants */ + unsigned long dbg_hdr_addr; /* OUT address of debug header (if MACHO_INFO_DEBUG_HEADER is set) */ + struct module* module; /* OUT loaded module (if MACHO_INFO_MODULE is set) */ + const WCHAR* module_name; /* OUT found module name (if MACHO_INFO_NAME is set) */ +}; + +/* structure holding information while handling a Mach-O image */ +#define BITS_PER_ULONG (sizeof(ULONG) * 8) +#define ULONGS_FOR_BITS(nbits) (((nbits) + BITS_PER_ULONG - 1) / BITS_PER_ULONG) +struct macho_file_map +{ + /* A copy of the Mach-O header for an individual architecture. */ + struct mach_header mach_header; + + /* The mapped load commands. */ + const struct load_command* load_commands; + + /* The portion of the file which is this architecture. mach_header was + * read from arch_offset. */ + unsigned arch_offset; + unsigned arch_size; + + /* The range of address space covered by all segments. */ + size_t segs_start; + size_t segs_size; + + /* Map of which sections contain code. Sections are accessed using 1-based + * index. Bit 0 of this bitset indicates if the bitset has been initialized. */ + RTL_BITMAP sect_is_code; + ULONG sect_is_code_buff[ULONGS_FOR_BITS(MAX_SECT + 1)]; + + /* The file. */ + int fd; +}; + +static void macho_unmap_file(struct macho_file_map* fmap); + +/****************************************************************** + * macho_calc_range + * + * For a range (offset & length) of a single architecture within + * a Mach-O file, calculate the page-aligned range of the whole file + * that encompasses it. For a fat binary, the architecture will + * itself be offset within the file, so take that into account. + */ +static void macho_calc_range(const struct macho_file_map* fmap, unsigned offset, + unsigned len, unsigned* out_aligned_offset, + unsigned* out_aligned_end, unsigned* out_aligned_len, + unsigned* out_misalign) +{ + unsigned pagemask = getpagesize() - 1; + unsigned file_offset, misalign; + + file_offset = fmap->arch_offset + offset; + misalign = file_offset & pagemask; + *out_aligned_offset = file_offset - misalign; + *out_aligned_end = (file_offset + len + pagemask) & ~pagemask; + if (out_aligned_len) + *out_aligned_len = *out_aligned_end - *out_aligned_offset; + if (out_misalign) + *out_misalign = misalign; +} + +/****************************************************************** + * macho_map_range + * + * Maps a range (offset, length in bytes) from a Mach-O file into memory + */ +static const char* macho_map_range(const struct macho_file_map* fmap, unsigned offset, unsigned len) +{ + unsigned misalign, aligned_offset, aligned_map_end, map_size; + const void* aligned_ptr; + + TRACE("(%p/%d, 0x%08x, 0x%08x)\n", fmap, fmap->fd, offset, len); + + macho_calc_range(fmap, offset, len, &aligned_offset, &aligned_map_end, + &map_size, &misalign); + + aligned_ptr = mmap(NULL, map_size, PROT_READ, MAP_PRIVATE, fmap->fd, aligned_offset); + + TRACE("Mapped (0x%08x - 0x%08x) to %p\n", aligned_offset, aligned_map_end, aligned_ptr); + + if (aligned_ptr == MAP_FAILED) return MACHO_NO_MAP; + return (const char*)aligned_ptr + misalign; +} + +/****************************************************************** + * macho_unmap_range + * + * Unmaps a range (offset, length in bytes) of a Mach-O file from memory + */ +static void macho_unmap_range(const void** mapped, const struct macho_file_map* fmap, + unsigned offset, unsigned len) +{ + TRACE("(%p, %p/%d, 0x%08x, 0x%08x)\n", mapped, fmap, fmap->fd, offset, len); + + if (mapped && *mapped != MACHO_NO_MAP) + { + unsigned misalign, aligned_offset, aligned_map_end, map_size; + void* aligned_ptr; + + macho_calc_range(fmap, offset, len, &aligned_offset, &aligned_map_end, + &map_size, &misalign); + + aligned_ptr = (char*)*mapped - misalign; + if (munmap(aligned_ptr, map_size) < 0) + WARN("Couldn't unmap the range\n"); + TRACE("Unmapped (0x%08x - 0x%08x) from %p - %p\n", aligned_offset, aligned_map_end, aligned_ptr, (char*)aligned_ptr + map_size); + *mapped = MACHO_NO_MAP; + } +} + +/****************************************************************** + * macho_map_ranges + * + * Maps two ranges (offset, length in bytes) from a Mach-O file + * into memory. If the two ranges overlap, use one mmap so that + * the munmap doesn't fragment the mapping. + */ +static BOOL macho_map_ranges(const struct macho_file_map* fmap, + unsigned offset1, unsigned len1, + unsigned offset2, unsigned len2, + const void** mapped1, const void** mapped2) +{ + unsigned aligned_offset1, aligned_map_end1; + unsigned aligned_offset2, aligned_map_end2; + + TRACE("(%p/%d, 0x%08x, 0x%08x, 0x%08x, 0x%08x, %p, %p)\n", fmap, fmap->fd, + offset1, len1, offset2, len2, mapped1, mapped2); + + macho_calc_range(fmap, offset1, len1, &aligned_offset1, &aligned_map_end1, NULL, NULL); + macho_calc_range(fmap, offset2, len2, &aligned_offset2, &aligned_map_end2, NULL, NULL); + + if (aligned_map_end1 < aligned_offset2 || aligned_map_end2 < aligned_offset1) + { + *mapped1 = macho_map_range(fmap, offset1, len1); + if (*mapped1 != MACHO_NO_MAP) + { + *mapped2 = macho_map_range(fmap, offset2, len2); + if (*mapped2 == MACHO_NO_MAP) + macho_unmap_range(mapped1, fmap, offset1, len1); + } + } + else + { + if (offset1 < offset2) + { + *mapped1 = macho_map_range(fmap, offset1, offset2 + len2 - offset1); + if (*mapped1 != MACHO_NO_MAP) + *mapped2 = (const char*)*mapped1 + offset2 - offset1; + } + else + { + *mapped2 = macho_map_range(fmap, offset2, offset1 + len1 - offset2); + if (*mapped2 != MACHO_NO_MAP) + *mapped1 = (const char*)*mapped2 + offset1 - offset2; + } + } + + TRACE(" => %p, %p\n", *mapped1, *mapped2); + + return (*mapped1 != MACHO_NO_MAP) && (*mapped2 != MACHO_NO_MAP); +} + +/****************************************************************** + * macho_unmap_ranges + * + * Unmaps two ranges (offset, length in bytes) of a Mach-O file + * from memory. Use for ranges which were mapped by + * macho_map_ranges. + */ +static void macho_unmap_ranges(const struct macho_file_map* fmap, + unsigned offset1, unsigned len1, + unsigned offset2, unsigned len2, + const void** mapped1, const void** mapped2) +{ + unsigned aligned_offset1, aligned_map_end1; + unsigned aligned_offset2, aligned_map_end2; + + TRACE("(%p/%d, 0x%08x, 0x%08x, 0x%08x, 0x%08x, %p/%p, %p/%p)\n", fmap, fmap->fd, + offset1, len1, offset2, len2, mapped1, *mapped1, mapped2, *mapped2); + + macho_calc_range(fmap, offset1, len1, &aligned_offset1, &aligned_map_end1, NULL, NULL); + macho_calc_range(fmap, offset2, len2, &aligned_offset2, &aligned_map_end2, NULL, NULL); + + if (aligned_map_end1 < aligned_offset2 || aligned_map_end2 < aligned_offset1) + { + macho_unmap_range(mapped1, fmap, offset1, len1); + macho_unmap_range(mapped2, fmap, offset2, len2); + } + else + { + if (offset1 < offset2) + { + macho_unmap_range(mapped1, fmap, offset1, offset2 + len2 - offset1); + *mapped2 = MACHO_NO_MAP; + } + else + { + macho_unmap_range(mapped2, fmap, offset2, offset1 + len1 - offset2); + *mapped1 = MACHO_NO_MAP; + } + } +} + +/****************************************************************** + * macho_map_load_commands + * + * Maps the load commands from a Mach-O file into memory + */ +static const struct load_command* macho_map_load_commands(struct macho_file_map* fmap) +{ + if (fmap->load_commands == MACHO_NO_MAP) + { + fmap->load_commands = (const struct load_command*) macho_map_range( + fmap, sizeof(fmap->mach_header), fmap->mach_header.sizeofcmds); + TRACE("Mapped load commands: %p\n", fmap->load_commands); + } + + return fmap->load_commands; +} + +/****************************************************************** + * macho_unmap_load_commands + * + * Unmaps the load commands of a Mach-O file from memory + */ +static void macho_unmap_load_commands(struct macho_file_map* fmap) +{ + if (fmap->load_commands != MACHO_NO_MAP) + { + TRACE("Unmapping load commands: %p\n", fmap->load_commands); + macho_unmap_range((const void**)&fmap->load_commands, fmap, + sizeof(fmap->mach_header), fmap->mach_header.sizeofcmds); + } +} + +/****************************************************************** + * macho_next_load_command + * + * Advance to the next load command + */ +static const struct load_command* macho_next_load_command(const struct load_command* lc) +{ + return (const struct load_command*)((const char*)lc + lc->cmdsize); +} + +/****************************************************************** + * macho_enum_load_commands + * + * Enumerates the load commands for a Mach-O file, selecting by + * the command type, calling a callback for each. If the callback + * returns <0, that indicates an error. If it returns >0, that means + * it's not interested in getting any more load commands. + * If this function returns <0, that's an error produced by the + * callback. If >=0, that's the count of load commands successfully + * processed. + */ +static int macho_enum_load_commands(struct macho_file_map* fmap, unsigned cmd, + int (*cb)(struct macho_file_map*, const struct load_command*, void*), + void* user) +{ + const struct load_command* lc; + int i; + int count = 0; + + TRACE("(%p/%d, %u, %p, %p)\n", fmap, fmap->fd, cmd, cb, user); + + if ((lc = macho_map_load_commands(fmap)) == MACHO_NO_MAP) return -1; + + TRACE("%d total commands\n", fmap->mach_header.ncmds); + + for (i = 0; i < fmap->mach_header.ncmds; i++, lc = macho_next_load_command(lc)) + { + int result; + + if (cmd && cmd != lc->cmd) continue; + count++; + + result = cb(fmap, lc, user); + TRACE("load_command[%d] (%p), cmd %u; callback => %d\n", i, lc, lc->cmd, result); + if (result) return (result < 0) ? result : count; + } + + return count; +} + +/****************************************************************** + * macho_accum_segs_range + * + * Callback for macho_enum_load_commands. Accumulates the address + * range covered by the segments of a Mach-O file. All commands + * are expected to be of LC_SEGMENT type. + */ +static int macho_accum_segs_range(struct macho_file_map* fmap, + const struct load_command* lc, void* user) +{ + const struct segment_command* sc = (const struct segment_command*)lc; + unsigned tmp, page_mask = getpagesize() - 1; + + TRACE("(%p/%d, %p, %p) before: 0x%08x - 0x%08x\n", fmap, fmap->fd, lc, user, + (unsigned)fmap->segs_start, (unsigned)fmap->segs_size); + TRACE("Segment command vm: 0x%08x - 0x%08x\n", (unsigned)sc->vmaddr, + (unsigned)sc->vmaddr + sc->vmsize); + + if (!strncmp(sc->segname, "WINE_", 5)) + { + TRACE("Ignoring special Wine segment %s\n", debugstr_an(sc->segname, sizeof(sc->segname))); + return 0; + } + + /* If this segment starts before previously-known earliest, record + * new earliest. */ + if (sc->vmaddr < fmap->segs_start) + fmap->segs_start = sc->vmaddr; + + /* If this segment extends beyond previously-known furthest, record + * new furthest. */ + tmp = (sc->vmaddr + sc->vmsize + page_mask) & ~page_mask; + if (fmap->segs_size < tmp) fmap->segs_size = tmp; + + TRACE("after: 0x%08x - 0x%08x\n", (unsigned)fmap->segs_start, (unsigned)fmap->segs_size); + + return 0; +} + +/****************************************************************** + * macho_map_file + * + * Maps a Mach-O file into memory (and checks it's a real Mach-O file) + */ +static BOOL macho_map_file(const WCHAR* filenameW, struct macho_file_map* fmap) +{ + struct fat_header fat_header; + struct stat statbuf; + int i; + char* filename; + unsigned len; + BOOL ret = FALSE; + + TRACE("(%s, %p)\n", debugstr_w(filenameW), fmap); + + fmap->fd = -1; + fmap->load_commands = MACHO_NO_MAP; + RtlInitializeBitMap(&fmap->sect_is_code, fmap->sect_is_code_buff, MAX_SECT + 1); + + len = WideCharToMultiByte(CP_UNIXCP, 0, filenameW, -1, NULL, 0, NULL, NULL); + if (!(filename = HeapAlloc(GetProcessHeap(), 0, len))) return FALSE; + WideCharToMultiByte(CP_UNIXCP, 0, filenameW, -1, filename, len, NULL, NULL); + + /* check that the file exists */ + if (stat(filename, &statbuf) == -1 || S_ISDIR(statbuf.st_mode)) goto done; + + /* Now open the file, so that we can mmap() it. */ + if ((fmap->fd = open(filename, O_RDONLY)) == -1) goto done; + + if (read(fmap->fd, &fat_header, sizeof(fat_header)) != sizeof(fat_header)) + goto done; + TRACE("... got possible fat header\n"); + + /* Fat header is always in big-endian order. */ + if (swap_ulong_be_to_host(fat_header.magic) == FAT_MAGIC) + { + int narch = swap_ulong_be_to_host(fat_header.nfat_arch); + for (i = 0; i < narch; i++) + { + struct fat_arch fat_arch; + if (read(fmap->fd, &fat_arch, sizeof(fat_arch)) != sizeof(fat_arch)) + goto done; + if (swap_ulong_be_to_host(fat_arch.cputype) == CPU_TYPE_X86) + { + fmap->arch_offset = swap_ulong_be_to_host(fat_arch.offset); + fmap->arch_size = swap_ulong_be_to_host(fat_arch.size); + break; + } + } + if (i >= narch) goto done; + TRACE("... found x86 arch\n"); + } + else + { + fmap->arch_offset = 0; + fmap->arch_size = statbuf.st_size; + TRACE("... not a fat header\n"); + } + + /* Individual architecture (standalone or within a fat file) is in its native byte order. */ + lseek(fmap->fd, fmap->arch_offset, SEEK_SET); + if (read(fmap->fd, &fmap->mach_header, sizeof(fmap->mach_header)) != sizeof(fmap->mach_header)) + goto done; + TRACE("... got possible Mach header\n"); + /* and check for a Mach-O header */ + if (fmap->mach_header.magic != MH_MAGIC || + fmap->mach_header.cputype != CPU_TYPE_X86) goto done; + /* Make sure the file type is one of the ones we expect. */ + switch (fmap->mach_header.filetype) + { + case MH_EXECUTE: + case MH_DYLIB: + case MH_DYLINKER: + case MH_BUNDLE: + break; + default: + goto done; + } + TRACE("... verified Mach x86 header\n"); + + fmap->segs_size = 0; + fmap->segs_start = ~0L; + + if (macho_enum_load_commands(fmap, LC_SEGMENT, macho_accum_segs_range, NULL) < 0) + goto done; + + fmap->segs_size -= fmap->segs_start; + TRACE("segs_start: 0x%08x, segs_size: 0x%08x\n", (unsigned)fmap->segs_start, + (unsigned)fmap->segs_size); + + ret = TRUE; +done: + if (!ret) + macho_unmap_file(fmap); + HeapFree(GetProcessHeap(), 0, filename); + return ret; +} + +/****************************************************************** + * macho_unmap_file + * + * Unmaps a Mach-O file from memory (previously mapped with macho_map_file) + */ +static void macho_unmap_file(struct macho_file_map* fmap) +{ + TRACE("(%p/%d)\n", fmap, fmap->fd); + if (fmap->fd != -1) + { + macho_unmap_load_commands(fmap); + close(fmap->fd); + fmap->fd = -1; + } +} + +/****************************************************************** + * macho_fill_sect_is_code + * + * Callback for macho_enum_load_commands. Determines which segments + * of a Mach-O file contain code. All commands are expected to be + * of LC_SEGMENT type. + */ +static int macho_fill_sect_is_code(struct macho_file_map* fmap, + const struct load_command* lc, void* user) +{ + const struct segment_command* sc = (const struct segment_command*)lc; + const struct section* sections; + int* cursect = user; + int i; + + TRACE("(%p/%d, %p, %p/%d) scanning %u sections\n", fmap, fmap->fd, lc, + cursect, *cursect, sc->nsects); + + sections = (const struct section*)(sc + 1); + for (i = 0; i < sc->nsects; i++) + { + if (*cursect > MAX_SECT) return -1; + (*cursect)++; + + if (!(sections[i].flags & SECTION_TYPE) && + (sections[i].flags & (S_ATTR_PURE_INSTRUCTIONS|S_ATTR_SOME_INSTRUCTIONS))) + RtlSetBits(&fmap->sect_is_code, *cursect, 1); + else + RtlClearBits(&fmap->sect_is_code, *cursect, 1); + TRACE("Section %d (%d of this segment) is%s code\n", *cursect, i, + (RtlAreBitsSet(&fmap->sect_is_code, *cursect, 1) ? "" : " not")); + } + + return 0; +} + +/****************************************************************** + * macho_sect_is_code + * + * Checks if a section, identified by sectidx which is a 1-based + * index into the sections of all segments, in order of load + * commands, contains code. + */ +static BOOL macho_sect_is_code(struct macho_file_map* fmap, unsigned char sectidx) +{ + TRACE("(%p/%d, %u)\n", fmap, fmap->fd, sectidx); + + if (!RtlAreBitsSet(&fmap->sect_is_code, 0, 1)) + { + int cursect = 0; + if (macho_enum_load_commands(fmap, LC_SEGMENT, macho_fill_sect_is_code, &cursect) < 0) + WARN("Couldn't load sect_is_code map\n"); + RtlSetBits(&fmap->sect_is_code, 0, 1); + } + + return RtlAreBitsSet(&fmap->sect_is_code, sectidx, 1); +} + +struct symtab_elt +{ + struct hash_table_elt ht_elt; + struct symt_compiland* compiland; + unsigned long addr; + unsigned char is_code:1, + is_public:1, + is_global:1, + used:1; +}; + +struct macho_debug_info +{ + struct macho_file_map* fmap; + struct module* module; + struct pool pool; + struct hash_table ht_symtab; +}; + +/****************************************************************** + * macho_stabs_def_cb + * + * Callback for stabs_parse. Collect symbol definitions. + */ +static void macho_stabs_def_cb(struct module* module, unsigned long load_offset, + const char* name, unsigned long offset, + BOOL is_public, BOOL is_global, unsigned char sectidx, + struct symt_compiland* compiland, void* user) +{ + struct macho_debug_info* mdi = user; + struct symtab_elt* ste; + + TRACE("(%p, 0x%08lx, %s, 0x%08lx, %d, %d, %u, %p, %p/%p/%d)\n", module, load_offset, + debugstr_a(name), offset, is_public, is_global, sectidx, + compiland, mdi, mdi->fmap, mdi->fmap->fd); + + /* Defer the creation of new non-debugging symbols until after we've + * finished parsing the stabs. */ + ste = pool_alloc(&mdi->pool, sizeof(*ste)); + ste->ht_elt.name = pool_strdup(&mdi->pool, name); + ste->compiland = compiland; + ste->addr = load_offset + offset; + ste->is_code = !!macho_sect_is_code(mdi->fmap, sectidx); + ste->is_public = !!is_public; + ste->is_global = !!is_global; + ste->used = 0; + hash_table_add(&mdi->ht_symtab, &ste->ht_elt); +} + +/****************************************************************** + * macho_parse_symtab + * + * Callback for macho_enum_load_commands. Processes the LC_SYMTAB + * load commands from the Mach-O file. + */ +static int macho_parse_symtab(struct macho_file_map* fmap, + const struct load_command* lc, void* user) +{ + const struct symtab_command* sc = (const struct symtab_command*)lc; + struct macho_debug_info* mdi = user; + const struct nlist* stab; + const char* stabstr; + int ret = 0; + + TRACE("(%p/%d, %p, %p) %u syms at 0x%08x, strings 0x%08x - 0x%08x\n", fmap, fmap->fd, lc, + user, sc->nsyms, sc->symoff, sc->stroff, sc->stroff + sc->strsize); + + if (!macho_map_ranges(fmap, sc->symoff, sc->nsyms * sizeof(struct nlist), + sc->stroff, sc->strsize, (const void**)&stab, (const void**)&stabstr)) + return 0; + + if (!stabs_parse(mdi->module, mdi->module->macho_info->load_addr - fmap->segs_start, + stab, sc->nsyms * sizeof(struct nlist), + stabstr, sc->strsize, macho_stabs_def_cb, mdi)) + ret = -1; + + macho_unmap_ranges(fmap, sc->symoff, sc->nsyms * sizeof(struct nlist), + sc->stroff, sc->strsize, (const void**)&stab, (const void**)&stabstr); + + return ret; +} + +/****************************************************************** + * macho_finish_stabs + * + * Integrate the non-debugging symbols we've gathered into the + * symbols that were generated during stabs parsing. + */ +static void macho_finish_stabs(struct module* module, struct hash_table* ht_symtab) +{ + struct hash_table_iter hti_ours; + struct symtab_elt* ste; + BOOL adjusted = FALSE; + + TRACE("(%p, %p)\n", module, ht_symtab); + + /* For each of our non-debugging symbols, see if it can provide some + * missing details to one of the module's known symbols. */ + hash_table_iter_init(ht_symtab, &hti_ours, NULL); + while ((ste = hash_table_iter_up(&hti_ours))) + { + struct hash_table_iter hti_modules; + void* ptr; + struct symt_ht* sym; + struct symt_function* func; + struct symt_data* data; + + hash_table_iter_init(&module->ht_symbols, &hti_modules, ste->ht_elt.name); + while ((ptr = hash_table_iter_up(&hti_modules))) + { + sym = GET_ENTRY(ptr, struct symt_ht, hash_elt); + + if (strcmp(sym->hash_elt.name, ste->ht_elt.name)) + continue; + + switch (sym->symt.tag) + { + case SymTagFunction: + func = (struct symt_function*)sym; + if (func->address == module->macho_info->load_addr) + { + TRACE("Adjusting function %p/%s!%s from 0x%08lx to 0x%08lx\n", func, + debugstr_w(module->module.ModuleName), sym->hash_elt.name, + func->address, ste->addr); + func->address = ste->addr; + adjusted = TRUE; + } + if (func->address == ste->addr) + ste->used = 1; + break; + case SymTagData: + data = (struct symt_data*)sym; + switch (data->kind) + { + case DataIsGlobal: + case DataIsFileStatic: + if (data->u.var.offset == module->macho_info->load_addr) + { + TRACE("Adjusting data symbol %p/%s!%s from 0x%08lx to 0x%08lx\n", + data, debugstr_w(module->module.ModuleName), sym->hash_elt.name, + data->u.var.offset, ste->addr); + data->u.var.offset = ste->addr; + adjusted = TRUE; + } + if (data->u.var.offset == ste->addr) + { + enum DataKind new_kind; + + new_kind = ste->is_global ? DataIsGlobal : DataIsFileStatic; + if (data->kind != new_kind) + { + WARN("Changing kind for %p/%s!%s from %d to %d\n", sym, + debugstr_w(module->module.ModuleName), sym->hash_elt.name, + (int)data->kind, (int)new_kind); + data->kind = new_kind; + adjusted = TRUE; + } + ste->used = 1; + } + break; + default:; + } + break; + default: + TRACE("Ignoring tag %u\n", sym->symt.tag); + break; + } + } + } + + if (adjusted) + { + /* since we may have changed some addresses, mark the module to be resorted */ + module->sortlist_valid = FALSE; + } + + /* Mark any of our non-debugging symbols which fall on an already-used + * address as "used". This allows us to skip them in the next loop, + * below. We do this in separate loops because symt_new_* marks the + * list as needing sorting and symt_find_nearest sorts if needed, + * causing thrashing. */ + if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY)) + { + hash_table_iter_init(ht_symtab, &hti_ours, NULL); + while ((ste = hash_table_iter_up(&hti_ours))) + { + struct symt_ht* sym; + ULONG64 addr; + + if (ste->used) continue; + + sym = symt_find_nearest(module, ste->addr); + if (sym) + symt_get_info(module, &sym->symt, TI_GET_ADDRESS, &addr); + if (sym && ste->addr == addr) + { + ULONG64 size = 0; + DWORD kind = -1; + + ste->used = 1; + + /* If neither symbol has a correct size (ours never does), we + * consider them both to be markers. No warning is needed in + * that case. + * Also, we check that we don't have two symbols, one local, the other + * global, which is legal. + */ + symt_get_info(module, &sym->symt, TI_GET_LENGTH, &size); + symt_get_info(module, &sym->symt, TI_GET_DATAKIND, &kind); + if (size && kind == (ste->is_global ? DataIsGlobal : DataIsFileStatic)) + FIXME("Duplicate in %s: %s<%08lx> %s<%s-%s>\n", + debugstr_w(module->module.ModuleName), + ste->ht_elt.name, ste->addr, + sym->hash_elt.name, + wine_dbgstr_longlong(addr), wine_dbgstr_longlong(size)); + } + } + } + + /* For any of our remaining non-debugging symbols which have no match + * among the module's known symbols, add them as new symbols. */ + hash_table_iter_init(ht_symtab, &hti_ours, NULL); + while ((ste = hash_table_iter_up(&hti_ours))) + { + if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY) && !ste->used) + { + if (ste->is_code) + { + symt_new_function(module, ste->compiland, ste->ht_elt.name, + ste->addr, 0, NULL); + } + else + { + symt_new_global_variable(module, ste->compiland, ste->ht_elt.name, + !ste->is_global, ste->addr, 0, NULL); + } + + ste->used = 1; + } + + if (ste->is_public && !(dbghelp_options & SYMOPT_NO_PUBLICS)) + { + symt_new_public(module, ste->compiland, ste->ht_elt.name, ste->addr, 0); + } + } +} + +/****************************************************************** + * macho_load_debug_info_from_map + * + * Loads the symbolic information from a Mach-O module. + * Returns + * FALSE if the file doesn't contain symbolic info (or this info + * cannot be read or parsed) + * TRUE on success + */ +static BOOL macho_load_debug_info_from_map(struct module* module, + struct macho_file_map* fmap) +{ + BOOL ret = FALSE; + struct macho_debug_info mdi; + int result; + + TRACE("(%p, %p/%d)\n", module, fmap, fmap->fd); + + module->module.SymType = SymExport; + + mdi.fmap = fmap; + mdi.module = module; + pool_init(&mdi.pool, 65536); + hash_table_init(&mdi.pool, &mdi.ht_symtab, 256); + result = macho_enum_load_commands(fmap, LC_SYMTAB, macho_parse_symtab, &mdi); + if (result > 0) + ret = TRUE; + else if (result < 0) + WARN("Couldn't correctly read stabs\n"); + + macho_finish_stabs(module, &mdi.ht_symtab); + + pool_destroy(&mdi.pool); + return ret; +} + +/****************************************************************** + * macho_load_debug_info + * + * Loads Mach-O debugging information from the module image file. + */ +BOOL macho_load_debug_info(struct module* module, struct macho_file_map* fmap) +{ + BOOL ret = TRUE; + struct macho_file_map my_fmap; + + TRACE("(%p, %p/%d)\n", module, fmap, fmap ? fmap->fd : -1); + + if (module->type != DMT_MACHO || !module->macho_info) + { + ERR("Bad Mach-O module '%s'\n", debugstr_w(module->module.LoadedImageName)); + return FALSE; + } + + if (!fmap) + { + fmap = &my_fmap; + ret = macho_map_file(module->module.LoadedImageName, fmap); + } + if (ret) + ret = macho_load_debug_info_from_map(module, fmap); + + if (fmap == &my_fmap) macho_unmap_file(fmap); + return ret; +} + +/****************************************************************** + * macho_fetch_file_info + * + * Gathers some more information for a Mach-O module from a given file + */ +BOOL macho_fetch_file_info(const WCHAR* name, DWORD* base, + DWORD* size, DWORD* checksum) +{ + struct macho_file_map fmap; + + TRACE("(%s, %p, %p, %p)\n", debugstr_w(name), base, size, checksum); + + if (!macho_map_file(name, &fmap)) return FALSE; + if (base) *base = fmap.segs_start; + *size = fmap.segs_size; + *checksum = calc_crc32(fmap.fd); + macho_unmap_file(&fmap); + return TRUE; +} + +/****************************************************************** + * macho_load_file + * + * Loads the information for Mach-O module stored in 'filename'. + * The module has been loaded at 'load_addr' address. + * returns + * FALSE if the file cannot be found/opened or if the file doesn't + * contain symbolic info (or this info cannot be read or parsed) + * TRUE on success + */ +static BOOL macho_load_file(struct process* pcs, const WCHAR* filename, + unsigned long load_addr, struct macho_info* macho_info) +{ + BOOL ret = TRUE; + struct macho_file_map fmap; + + TRACE("(%p/%p, %s, 0x%08lx, %p/0x%08x)\n", pcs, pcs->handle, debugstr_w(filename), + load_addr, macho_info, macho_info->flags); + + if (!macho_map_file(filename, &fmap)) return FALSE; + + /* Find the dynamic loader's table of images loaded into the process. + */ + if (macho_info->flags & MACHO_INFO_DEBUG_HEADER) + { + static void* dyld_all_image_infos_addr; + + /* This symbol should be in the same place in all processes. */ + if (!dyld_all_image_infos_addr) + { + struct nlist nl[2]; + memset(nl, 0, sizeof(nl)); + nl[0].n_un.n_name = (char*)"_dyld_all_image_infos"; + if (!nlist("/usr/lib/dyld", nl)) + dyld_all_image_infos_addr = (void*)nl[0].n_value; + } + + if (dyld_all_image_infos_addr) + macho_info->dbg_hdr_addr = (unsigned long)dyld_all_image_infos_addr; + else + ret = FALSE; + TRACE("dbg_hdr_addr = 0x%08lx\n", macho_info->dbg_hdr_addr); + } + + if (macho_info->flags & MACHO_INFO_MODULE) + { + struct macho_module_info *macho_module_info = + HeapAlloc(GetProcessHeap(), 0, sizeof(struct macho_module_info)); + if (!macho_module_info) goto leave; + macho_info->module = module_new(pcs, filename, DMT_MACHO, FALSE, load_addr, + fmap.segs_size, 0, calc_crc32(fmap.fd)); + if (!macho_info->module) + { + HeapFree(GetProcessHeap(), 0, macho_module_info); + goto leave; + } + macho_info->module->macho_info = macho_module_info; + macho_info->module->macho_info->load_addr = load_addr; + + if (dbghelp_options & SYMOPT_DEFERRED_LOADS) + macho_info->module->module.SymType = SymDeferred; + else if (!macho_load_debug_info(macho_info->module, &fmap)) + ret = FALSE; + + macho_info->module->macho_info->in_use = 1; + macho_info->module->macho_info->is_loader = 0; + TRACE("module = %p\n", macho_info->module); + } + + if (macho_info->flags & MACHO_INFO_NAME) + { + WCHAR* ptr; + ptr = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(filename) + 1) * sizeof(WCHAR)); + if (ptr) + { + strcpyW(ptr, filename); + macho_info->module_name = ptr; + } + else ret = FALSE; + TRACE("module_name = %p %s\n", macho_info->module_name, debugstr_w(macho_info->module_name)); + } +leave: + macho_unmap_file(&fmap); + + TRACE(" => %d\n", ret); + return ret; +} + +/****************************************************************** + * macho_load_file_from_path + * Tries to load a Mach-O file from a set of paths (separated by ':') + */ +static BOOL macho_load_file_from_path(HANDLE hProcess, + const WCHAR* filename, + unsigned long load_addr, + const char* path, + struct macho_info* macho_info) +{ + BOOL ret = FALSE; + WCHAR *s, *t, *fn; + WCHAR* pathW = NULL; + unsigned len; + + TRACE("(%p, %s, 0x%08lx, %s, %p)\n", hProcess, debugstr_w(filename), load_addr, + debugstr_a(path), macho_info); + + if (!path) return FALSE; + + len = MultiByteToWideChar(CP_UNIXCP, 0, path, -1, NULL, 0); + pathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + if (!pathW) return FALSE; + MultiByteToWideChar(CP_UNIXCP, 0, path, -1, pathW, len); + + for (s = pathW; s && *s; s = (t) ? (t+1) : NULL) + { + t = strchrW(s, ':'); + if (t) *t = '\0'; + fn = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(filename) + 1 + lstrlenW(s) + 1) * sizeof(WCHAR)); + if (!fn) break; + strcpyW(fn, s); + strcatW(fn, S_SlashW); + strcatW(fn, filename); + ret = macho_load_file(hProcess, fn, load_addr, macho_info); + HeapFree(GetProcessHeap(), 0, fn); + if (ret) break; + s = (t) ? (t+1) : NULL; + } + + TRACE(" => %d\n", ret); + HeapFree(GetProcessHeap(), 0, pathW); + return ret; +} + +/****************************************************************** + * macho_load_file_from_dll_path + * + * Tries to load a Mach-O file from the dll path + */ +static BOOL macho_load_file_from_dll_path(HANDLE hProcess, + const WCHAR* filename, + unsigned long load_addr, + struct macho_info* macho_info) +{ + BOOL ret = FALSE; + unsigned int index = 0; + const char *path; + + TRACE("(%p, %s, 0x%08lx, %p)\n", hProcess, debugstr_w(filename), load_addr, + macho_info); + + while (!ret && (path = wine_dll_enum_load_path( index++ ))) + { + WCHAR *name; + unsigned len; + + len = MultiByteToWideChar(CP_UNIXCP, 0, path, -1, NULL, 0); + + name = HeapAlloc( GetProcessHeap(), 0, + (len + lstrlenW(filename) + 2) * sizeof(WCHAR) ); + + if (!name) break; + MultiByteToWideChar(CP_UNIXCP, 0, path, -1, name, len); + strcatW( name, S_SlashW ); + strcatW( name, filename ); + ret = macho_load_file(hProcess, name, load_addr, macho_info); + HeapFree( GetProcessHeap(), 0, name ); + } + TRACE(" => %d\n", ret); + return ret; +} + +/****************************************************************** + * macho_search_and_load_file + * + * Lookup a file in standard Mach-O locations, and if found, load it + */ +static BOOL macho_search_and_load_file(struct process* pcs, const WCHAR* filename, + unsigned long load_addr, + struct macho_info* macho_info) +{ + BOOL ret = FALSE; + struct module* module; + static WCHAR S_libstdcPPW[] = {'l','i','b','s','t','d','c','+','+','\0'}; + const WCHAR* p; + + TRACE("(%p/%p, %s, 0x%08lx, %p)\n", pcs, pcs->handle, debugstr_w(filename), load_addr, + macho_info); + + if (filename == NULL || *filename == '\0') return FALSE; + if ((module = module_is_already_loaded(pcs, filename))) + { + macho_info->module = module; + module->macho_info->in_use = 1; + return module->module.SymType; + } + + if (strstrW(filename, S_libstdcPPW)) return FALSE; /* We know we can't do it */ + + /* If has no directories, try LD_LIBRARY_PATH first. */ + if (!strchrW(filename, '/')) + { + ret = macho_load_file_from_path(pcs, filename, load_addr, + getenv("PATH"), macho_info); + } + /* Try DYLD_LIBRARY_PATH, with just the filename (no directories). */ + if (!ret) + { + if ((p = strrchrW(filename, '/'))) p++; + else p = filename; + ret = macho_load_file_from_path(pcs, p, load_addr, + getenv("DYLD_LIBRARY_PATH"), macho_info); + } + /* Try the path as given. */ + if (!ret) + ret = macho_load_file(pcs, filename, load_addr, macho_info); + /* Try DYLD_FALLBACK_LIBRARY_PATH, with just the filename (no directories). */ + if (!ret) + { + ret = macho_load_file_from_path(pcs, p, load_addr, + getenv("DYLD_FALLBACK_LIBRARY_PATH"), macho_info); + } + if (!ret && !strchrW(filename, '/')) + ret = macho_load_file_from_dll_path(pcs, filename, load_addr, macho_info); + + return ret; +} + +/****************************************************************** + * macho_enum_modules_internal + * + * Enumerate Mach-O modules from a running process + */ +static BOOL macho_enum_modules_internal(const struct process* pcs, + const WCHAR* main_name, + enum_modules_cb cb, void* user) +{ + struct dyld_all_image_infos image_infos; + struct dyld_image_info* info_array = NULL; + unsigned long len; + int i; + char bufstr[256]; + WCHAR bufstrW[MAX_PATH]; + BOOL ret = FALSE; + + TRACE("(%p/%p, %s, %p, %p)\n", pcs, pcs->handle, debugstr_w(main_name), cb, + user); + + if (!pcs->dbg_hdr_addr || + !ReadProcessMemory(pcs->handle, (void*)pcs->dbg_hdr_addr, + &image_infos, sizeof(image_infos), NULL) || + !image_infos.infoArray) + goto done; + TRACE("Process has %u image infos at %p\n", image_infos.infoArrayCount, image_infos.infoArray); + + len = image_infos.infoArrayCount * sizeof(info_array[0]); + info_array = HeapAlloc(GetProcessHeap(), 0, len); + if (!info_array || + !ReadProcessMemory(pcs->handle, image_infos.infoArray, + info_array, len, NULL)) + goto done; + TRACE("... read image infos\n"); + + for (i = 0; i < image_infos.infoArrayCount; i++) + { + if (info_array[i].imageFilePath != NULL && + ReadProcessMemory(pcs->handle, info_array[i].imageFilePath, bufstr, sizeof(bufstr), NULL)) + { + bufstr[sizeof(bufstr) - 1] = '\0'; + TRACE("[%d] image file %s\n", i, debugstr_a(bufstr)); + MultiByteToWideChar(CP_UNIXCP, 0, bufstr, -1, bufstrW, sizeof(bufstrW) / sizeof(WCHAR)); + if (main_name && !bufstrW[0]) strcpyW(bufstrW, main_name); + if (!cb(bufstrW, (unsigned long)info_array[i].imageLoadAddress, user)) break; + } + } + + ret = TRUE; +done: + HeapFree(GetProcessHeap(), 0, info_array); + return ret; +} + +struct macho_sync +{ + struct process* pcs; + struct macho_info macho_info; +}; + +static BOOL macho_enum_sync_cb(const WCHAR* name, unsigned long addr, void* user) +{ + struct macho_sync* ms = user; + + TRACE("(%s, 0x%08lx, %p)\n", debugstr_w(name), addr, user); + macho_search_and_load_file(ms->pcs, name, addr, &ms->macho_info); + return TRUE; +} + +/****************************************************************** + * macho_synchronize_module_list + * + * Rescans the debuggee's modules list and synchronizes it with + * the one from 'pcs', ie: + * - if a module is in debuggee and not in pcs, it's loaded into pcs + * - if a module is in pcs and not in debuggee, it's unloaded from pcs + */ +BOOL macho_synchronize_module_list(struct process* pcs) +{ + struct module* module; + struct macho_sync ms; + + TRACE("(%p/%p)\n", pcs, pcs->handle); + + for (module = pcs->lmodules; module; module = module->next) + { + if (module->type == DMT_MACHO && !module->is_virtual) + module->macho_info->in_use = 0; + } + + ms.pcs = pcs; + ms.macho_info.flags = MACHO_INFO_MODULE; + if (!macho_enum_modules_internal(pcs, NULL, macho_enum_sync_cb, &ms)) + return FALSE; + + module = pcs->lmodules; + while (module) + { + if (module->type == DMT_MACHO && !module->is_virtual && + !module->macho_info->in_use && !module->macho_info->is_loader) + { + module_remove(pcs, module); + /* restart all over */ + module = pcs->lmodules; + } + else module = module->next; + } + return TRUE; +} + +/****************************************************************** + * macho_search_loader + * + * Lookup in a running Mach-O process the loader, and sets its Mach-O link + * address (for accessing the list of loaded images) in pcs. + * If flags is MACHO_INFO_MODULE, the module for the loader is also + * added as a module into pcs. + */ +static BOOL macho_search_loader(struct process* pcs, struct macho_info* macho_info) +{ + BOOL ret; + const char* ptr; + + TRACE("(%p/%p, %p)\n", pcs, pcs->handle, macho_info); + + /* All binaries are loaded with WINELOADER (if run from tree) or by the + * main executable + */ + if ((ptr = getenv("WINELOADER"))) + { + WCHAR tmp[MAX_PATH]; + MultiByteToWideChar(CP_UNIXCP, 0, ptr, -1, tmp, sizeof(tmp) / sizeof(WCHAR)); + ret = macho_search_and_load_file(pcs, tmp, 0, macho_info); + } + else + { + ret = macho_search_and_load_file(pcs, S_WineW, 0, macho_info); + } + return ret; +} + +/****************************************************************** + * macho_read_wine_loader_dbg_info + * + * Try to find a decent wine executable which could have loaded the debuggee + */ +BOOL macho_read_wine_loader_dbg_info(struct process* pcs) +{ + struct macho_info macho_info; + + TRACE("(%p/%p)\n", pcs, pcs->handle); + macho_info.flags = MACHO_INFO_DEBUG_HEADER | MACHO_INFO_MODULE; + if (!macho_search_loader(pcs, &macho_info)) return FALSE; + macho_info.module->macho_info->is_loader = 1; + module_set_module(macho_info.module, S_WineLoaderW); + return (pcs->dbg_hdr_addr = macho_info.dbg_hdr_addr) != 0; +} + +/****************************************************************** + * macho_enum_modules + * + * Enumerates the Mach-O loaded modules from a running target (hProc) + * This function doesn't require that someone has called SymInitialize + * on this very process. + */ +BOOL macho_enum_modules(HANDLE hProc, enum_modules_cb cb, void* user) +{ + struct process pcs; + struct macho_info macho_info; + BOOL ret; + + TRACE("(%p, %p, %p)\n", hProc, cb, user); + memset(&pcs, 0, sizeof(pcs)); + pcs.handle = hProc; + macho_info.flags = MACHO_INFO_DEBUG_HEADER | MACHO_INFO_NAME; + if (!macho_search_loader(&pcs, &macho_info)) return FALSE; + pcs.dbg_hdr_addr = macho_info.dbg_hdr_addr; + ret = macho_enum_modules_internal(&pcs, macho_info.module_name, cb, user); + HeapFree(GetProcessHeap(), 0, (char*)macho_info.module_name); + return ret; +} + +struct macho_load +{ + struct process* pcs; + struct macho_info macho_info; + const WCHAR* name; + BOOL ret; +}; + +/****************************************************************** + * macho_load_cb + * + * Callback for macho_load_module, used to walk the list of loaded + * modules. + */ +static BOOL macho_load_cb(const WCHAR* name, unsigned long addr, void* user) +{ + struct macho_load* ml = user; + const WCHAR* p; + + TRACE("(%s, 0x%08lx, %p)\n", debugstr_w(name), addr, user); + + /* memcmp is needed for matches when bufstr contains also version information + * ml->name: libc.so, name: libc.so.6.0 + */ + p = strrchrW(name, '/'); + if (!p++) p = name; + if (!memcmp(p, ml->name, lstrlenW(ml->name) * sizeof(WCHAR))) + { + ml->ret = macho_search_and_load_file(ml->pcs, name, addr, &ml->macho_info); + return FALSE; + } + return TRUE; +} + +/****************************************************************** + * macho_load_module + * + * Loads a Mach-O module and stores it in process' module list. + * Also, find module real name and load address from + * the real loaded modules list in pcs address space. + */ +struct module* macho_load_module(struct process* pcs, const WCHAR* name, unsigned long addr) +{ + struct macho_load ml; + + TRACE("(%p/%p, %s, 0x%08lx)\n", pcs, pcs->handle, debugstr_w(name), addr); + + ml.macho_info.flags = MACHO_INFO_MODULE; + ml.ret = FALSE; + + if (pcs->dbg_hdr_addr) /* we're debugging a live target */ + { + ml.pcs = pcs; + /* do only the lookup from the filename, not the path (as we lookup module + * name in the process' loaded module list) + */ + ml.name = strrchrW(name, '/'); + if (!ml.name++) ml.name = name; + ml.ret = FALSE; + + if (!macho_enum_modules_internal(pcs, NULL, macho_load_cb, &ml)) + return NULL; + } + else if (addr) + { + ml.name = name; + ml.ret = macho_search_and_load_file(pcs, ml.name, addr, &ml.macho_info); + } + if (!ml.ret) return NULL; + assert(ml.macho_info.module); + return ml.macho_info.module; +} + +#else /* !__MACH__ */ + +BOOL macho_synchronize_module_list(struct process* pcs) +{ + return FALSE; +} + +BOOL macho_fetch_file_info(const WCHAR* name, DWORD* base, + DWORD* size, DWORD* checksum) +{ + return FALSE; +} + +BOOL macho_read_wine_loader_dbg_info(struct process* pcs) +{ + return FALSE; +} + +BOOL macho_enum_modules(HANDLE hProc, enum_modules_cb cb, void* user) +{ + return FALSE; +} + +struct module* macho_load_module(struct process* pcs, const WCHAR* name, unsigned long addr) +{ + return NULL; +} + +BOOL macho_load_debug_info(struct module* module, struct macho_file_map* fmap) +{ + return FALSE; +} +#endif /* __MACH__ */ diff --git a/dll/win32/dbghelp/minidump.c b/dll/win32/dbghelp/minidump.c index cc124157544..3cddb72ee03 100644 --- a/dll/win32/dbghelp/minidump.c +++ b/dll/win32/dbghelp/minidump.c @@ -34,7 +34,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(dbghelp); struct dump_memory { - ULONG base; + ULONG64 base; ULONG size; ULONG rva; }; @@ -42,7 +42,7 @@ struct dump_memory struct dump_module { unsigned is_elf; - ULONG base; + ULONG64 base; ULONG size; DWORD timestamp; DWORD checksum; @@ -59,6 +59,7 @@ struct dump_context /* module information */ struct dump_module* modules; unsigned num_modules; + unsigned alloc_modules; /* exception information */ /* output information */ MINIDUMP_TYPE type; @@ -66,6 +67,7 @@ struct dump_context RVA rva; struct dump_memory* mem; unsigned num_mem; + unsigned alloc_mem; /* callback information */ MINIDUMP_CALLBACK_INFORMATION* cb; }; @@ -98,10 +100,9 @@ static BOOL fetch_processes_info(struct dump_context* dc) dc->spi = dc->pcs_buffer; for (;;) { - if (dc->spi->dwProcessID == dc->pid) return TRUE; - if (!dc->spi->dwOffset) break; - dc->spi = (SYSTEM_PROCESS_INFORMATION*) - ((char*)dc->spi + dc->spi->dwOffset); + if (HandleToUlong(dc->spi->UniqueProcessId) == dc->pid) return TRUE; + if (!dc->spi->NextEntryOffset) break; + dc->spi = (SYSTEM_PROCESS_INFORMATION*)((char*)dc->spi + dc->spi->NextEntryOffset); } } HeapFree(GetProcessHeap(), 0, dc->pcs_buffer); @@ -114,58 +115,25 @@ static void fetch_thread_stack(struct dump_context* dc, const void* teb_addr, const CONTEXT* ctx, MINIDUMP_MEMORY_DESCRIPTOR* mmd) { NT_TIB tib; + ADDRESS64 addr; - if (ReadProcessMemory(dc->hProcess, teb_addr, &tib, sizeof(tib), NULL)) + if (ReadProcessMemory(dc->hProcess, teb_addr, &tib, sizeof(tib), NULL) && + dbghelp_current_cpu && + dbghelp_current_cpu->get_addr(NULL /* FIXME */, ctx, cpu_addr_stack, &addr) && addr.Mode == AddrModeFlat) { -#ifdef __i386__ - /* limiting the stack dumping to the size actually used */ - if (ctx->Esp){ - - /* make sure ESP is within the established range of the stack. It could have + if (addr.Offset) + { + addr.Offset -= dbghelp_current_cpu->word_size; + /* make sure stack pointer is within the established range of the stack. It could have been clobbered by whatever caused the original exception. */ - if (ctx->Esp - 4 < (ULONG_PTR)tib.StackLimit || ctx->Esp - 4 > (ULONG_PTR)tib.StackBase) + if (addr.Offset < (ULONG_PTR)tib.StackLimit || addr.Offset > (ULONG_PTR)tib.StackBase) mmd->StartOfMemoryRange = (ULONG_PTR)tib.StackLimit; else - mmd->StartOfMemoryRange = (ctx->Esp - 4); + mmd->StartOfMemoryRange = addr.Offset; } - else mmd->StartOfMemoryRange = (ULONG_PTR)tib.StackLimit; - -#elif defined(__powerpc__) - if (ctx->Iar){ - - /* make sure IAR is within the established range of the stack. It could have - been clobbered by whatever caused the original exception. */ - if (ctx->Iar - 4 < (ULONG_PTR)tib.StackLimit || ctx->Iar - 4 > (ULONG_PTR)tib.StackBase) - mmd->StartOfMemoryRange = (ULONG_PTR)tib.StackLimit; - - else - mmd->StartOfMemoryRange = (ctx->Iar - 4); - } - - else - mmd->StartOfMemoryRange = (ULONG_PTR)tib.StackLimit; - -#elif defined(__x86_64__) - if (ctx->Rsp){ - - /* make sure RSP is within the established range of the stack. It could have - been clobbered by whatever caused the original exception. */ - if (ctx->Rsp - 8 < (ULONG_PTR)tib.StackLimit || ctx->Rsp - 8 > (ULONG_PTR)tib.StackBase) - mmd->StartOfMemoryRange = (ULONG_PTR)tib.StackLimit; - - else - mmd->StartOfMemoryRange = (ctx->Rsp - 8); - } - - else - mmd->StartOfMemoryRange = (ULONG_PTR)tib.StackLimit; - -#else -#error unsupported CPU -#endif mmd->Memory.DataSize = (ULONG_PTR)tib.StackBase - mmd->StartOfMemoryRange; } } @@ -179,13 +147,13 @@ static BOOL fetch_thread_info(struct dump_context* dc, int thd_idx, const MINIDUMP_EXCEPTION_INFORMATION* except, MINIDUMP_THREAD* mdThd, CONTEXT* ctx) { - DWORD tid = dc->spi->ti[thd_idx].dwThreadID; + DWORD tid = HandleToUlong(dc->spi->ti[thd_idx].ClientId.UniqueThread); HANDLE hThread; THREAD_BASIC_INFORMATION tbi; memset(ctx, 0, sizeof(*ctx)); - mdThd->ThreadId = dc->spi->ti[thd_idx].dwThreadID; + mdThd->ThreadId = tid; mdThd->SuspendCount = 0; mdThd->Teb = 0; mdThd->Stack.StartOfMemoryRange = 0; @@ -198,8 +166,7 @@ static BOOL fetch_thread_info(struct dump_context* dc, int thd_idx, if ((hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, tid)) == NULL) { - FIXME("Couldn't open thread %u (%u)\n", - dc->spi->ti[thd_idx].dwThreadID, GetLastError()); + FIXME("Couldn't open thread %u (%u)\n", tid, GetLastError()); return FALSE; } @@ -230,7 +197,7 @@ static BOOL fetch_thread_info(struct dump_context* dc, int thd_idx, ReadProcessMemory(dc->hProcess, except->ExceptionPointers, &ep, sizeof(ep), NULL); ReadProcessMemory(dc->hProcess, ep.ContextRecord, - &ctx, sizeof(ctx), NULL); + &lctx, sizeof(lctx), NULL); pctx = &lctx; } else pctx = except->ExceptionPointers->ContextRecord; @@ -251,27 +218,38 @@ static BOOL fetch_thread_info(struct dump_context* dc, int thd_idx, * Add a module to a dump context */ static BOOL add_module(struct dump_context* dc, const WCHAR* name, - DWORD base, DWORD size, DWORD timestamp, DWORD checksum, + DWORD64 base, DWORD size, DWORD timestamp, DWORD checksum, BOOL is_elf) { if (!dc->modules) + { + dc->alloc_modules = 32; dc->modules = HeapAlloc(GetProcessHeap(), 0, - ++dc->num_modules * sizeof(*dc->modules)); - else + dc->alloc_modules * sizeof(*dc->modules)); + } + else if(dc->num_modules >= dc->alloc_modules) + { + dc->alloc_modules *= 2; dc->modules = HeapReAlloc(GetProcessHeap(), 0, dc->modules, - ++dc->num_modules * sizeof(*dc->modules)); - if (!dc->modules) return FALSE; + dc->alloc_modules * sizeof(*dc->modules)); + } + if (!dc->modules) + { + dc->alloc_modules = dc->num_modules = 0; + return FALSE; + } if (is_elf || - !GetModuleFileNameExW(dc->hProcess, (HMODULE)base, - dc->modules[dc->num_modules - 1].name, - sizeof(dc->modules[dc->num_modules - 1].name) / sizeof(WCHAR))) - lstrcpynW(dc->modules[dc->num_modules - 1].name, name, - sizeof(dc->modules[dc->num_modules - 1].name) / sizeof(WCHAR)); - dc->modules[dc->num_modules - 1].base = base; - dc->modules[dc->num_modules - 1].size = size; - dc->modules[dc->num_modules - 1].timestamp = timestamp; - dc->modules[dc->num_modules - 1].checksum = checksum; - dc->modules[dc->num_modules - 1].is_elf = is_elf; + !GetModuleFileNameExW(dc->hProcess, (HMODULE)(DWORD_PTR)base, + dc->modules[dc->num_modules].name, + sizeof(dc->modules[dc->num_modules].name) / sizeof(WCHAR))) + lstrcpynW(dc->modules[dc->num_modules].name, name, + sizeof(dc->modules[dc->num_modules].name) / sizeof(WCHAR)); + dc->modules[dc->num_modules].base = base; + dc->modules[dc->num_modules].size = size; + dc->modules[dc->num_modules].timestamp = timestamp; + dc->modules[dc->num_modules].checksum = checksum; + dc->modules[dc->num_modules].is_elf = is_elf; + dc->num_modules++; return TRUE; } @@ -284,13 +262,13 @@ static BOOL add_module(struct dump_context* dc, const WCHAR* name, static BOOL WINAPI fetch_pe_module_info_cb(PCWSTR name, DWORD64 base, ULONG size, PVOID user) { - struct dump_context* dc = (struct dump_context*)user; + struct dump_context* dc = user; IMAGE_NT_HEADERS nth; if (!validate_addr64(base)) return FALSE; if (pe_load_nt_header(dc->hProcess, base, &nth)) - add_module((struct dump_context*)user, name, base, size, + add_module(user, name, base, size, nth.FileHeader.TimeDateStamp, nth.OptionalHeader.CheckSum, FALSE); return TRUE; @@ -304,7 +282,7 @@ static BOOL WINAPI fetch_pe_module_info_cb(PCWSTR name, DWORD64 base, ULONG size static BOOL fetch_elf_module_info_cb(const WCHAR* name, unsigned long base, void* user) { - struct dump_context* dc = (struct dump_context*)user; + struct dump_context* dc = user; DWORD rbase, size, checksum; /* FIXME: there's no relevant timestamp on ELF modules */ @@ -318,6 +296,27 @@ static BOOL fetch_elf_module_info_cb(const WCHAR* name, unsigned long base, return TRUE; } +/****************************************************************** + * fetch_macho_module_info_cb + * + * Callback for accumulating in dump_context a Mach-O modules set + */ +static BOOL fetch_macho_module_info_cb(const WCHAR* name, unsigned long base, + void* user) +{ + struct dump_context* dc = (struct dump_context*)user; + DWORD rbase, size, checksum; + + /* FIXME: there's no relevant timestamp on Mach-O modules */ + /* NB: if we have a non-null base from the live-target use it. If we have + * a null base, then grab its base address from Mach-O file. + */ + if (!macho_fetch_file_info(name, &rbase, &size, &checksum)) + size = checksum = 0; + add_module(dc, name, base ? base : rbase, size, 0 /* FIXME */, checksum, TRUE); + return TRUE; +} + static void fetch_modules_info(struct dump_context* dc) { EnumerateLoadedModulesW64(dc->hProcess, fetch_pe_module_info_cb, dc); @@ -327,6 +326,7 @@ static void fetch_modules_info(struct dump_context* dc) * a given application in a post mortem debugging condition. */ elf_enum_modules(dc->hProcess, fetch_elf_module_info_cb, dc); + macho_enum_modules(dc->hProcess, fetch_macho_module_info_cb, dc); } static void fetch_module_versioninfo(LPCWSTR filename, VS_FIXEDFILEINFO* ffi) @@ -361,18 +361,25 @@ static void fetch_module_versioninfo(LPCWSTR filename, VS_FIXEDFILEINFO* ffi) */ static void add_memory_block(struct dump_context* dc, ULONG64 base, ULONG size, ULONG rva) { - if (dc->mem) - dc->mem = HeapReAlloc(GetProcessHeap(), 0, dc->mem, - ++dc->num_mem * sizeof(*dc->mem)); - else - dc->mem = HeapAlloc(GetProcessHeap(), 0, ++dc->num_mem * sizeof(*dc->mem)); + if (!dc->mem) + { + dc->alloc_mem = 32; + dc->mem = HeapAlloc(GetProcessHeap(), 0, dc->alloc_mem * sizeof(*dc->mem)); + } + else if (dc->num_mem >= dc->alloc_mem) + { + dc->alloc_mem *= 2; + dc->mem = HeapReAlloc(GetProcessHeap(), 0, dc->mem, + dc->alloc_mem * sizeof(*dc->mem)); + } if (dc->mem) { - dc->mem[dc->num_mem - 1].base = base; - dc->mem[dc->num_mem - 1].size = size; - dc->mem[dc->num_mem - 1].rva = rva; + dc->mem[dc->num_mem].base = base; + dc->mem[dc->num_mem].size = size; + dc->mem[dc->num_mem].rva = rva; + dc->num_mem++; } - else dc->num_mem = 0; + else dc->num_mem = dc->alloc_mem = 0; } /****************************************************************** @@ -394,7 +401,7 @@ static void writeat(struct dump_context* dc, RVA rva, const void* data, unsigned * writes a new chunk of data to the minidump, increasing the current * rva in dc */ -static void append(struct dump_context* dc, void* data, unsigned size) +static void append(struct dump_context* dc, const void* data, unsigned size) { writeat(dc, dc->rva, data, size); dc->rva += size; @@ -683,7 +690,7 @@ static unsigned dump_threads(struct dump_context* dc, { MINIDUMP_THREAD mdThd; MINIDUMP_THREAD_LIST mdThdList; - unsigned i; + unsigned i, sz; RVA rva_base; DWORD flags_out; CONTEXT ctx; @@ -691,8 +698,7 @@ static unsigned dump_threads(struct dump_context* dc, mdThdList.NumberOfThreads = 0; rva_base = dc->rva; - dc->rva += sizeof(mdThdList.NumberOfThreads) + - dc->spi->dwThreadCount * sizeof(mdThd); + dc->rva += sz = sizeof(mdThdList.NumberOfThreads) + dc->spi->dwThreadCount * sizeof(mdThd); for (i = 0; i < dc->spi->dwThreadCount; i++) { @@ -713,7 +719,7 @@ static unsigned dump_threads(struct dump_context* dc, cbin.ProcessId = dc->pid; cbin.ProcessHandle = dc->hProcess; cbin.CallbackType = ThreadCallback; - cbin.u.Thread.ThreadId = dc->spi->ti[i].dwThreadID; + cbin.u.Thread.ThreadId = HandleToUlong(dc->spi->ti[i].ClientId.UniqueThread); cbin.u.Thread.ThreadHandle = 0; /* FIXME */ cbin.u.Thread.Context = ctx; cbin.u.Thread.SizeOfContext = sizeof(CONTEXT); @@ -760,7 +766,7 @@ static unsigned dump_threads(struct dump_context* dc, writeat(dc, rva_base, &mdThdList.NumberOfThreads, sizeof(mdThdList.NumberOfThreads)); - return dc->rva - rva_base; + return sz; } /****************************************************************** @@ -795,7 +801,7 @@ static unsigned dump_memory_info(struct dump_context* dc) { len = min(dc->mem[i].size - pos, sizeof(tmp)); if (ReadProcessMemory(dc->hProcess, - (void*)(dc->mem[i].base + pos), + (void*)(DWORD_PTR)(dc->mem[i].base + pos), tmp, len, NULL)) WriteFile(dc->hFile, tmp, len, &written, NULL); } @@ -847,10 +853,12 @@ BOOL WINAPI MiniDumpWriteDump(HANDLE hProcess, DWORD pid, HANDLE hFile, dc.pid = pid; dc.modules = NULL; dc.num_modules = 0; + dc.alloc_modules = 0; dc.cb = CallbackParam; dc.type = DumpType; dc.mem = NULL; dc.num_mem = 0; + dc.alloc_mem = 0; dc.rva = 0; if (!fetch_processes_info(&dc)) return FALSE; @@ -973,7 +981,7 @@ BOOL WINAPI MiniDumpReadDumpStream(PVOID base, ULONG str_idx, PMINIDUMP_DIRECTORY* pdir, PVOID* stream, ULONG* size) { - MINIDUMP_HEADER* mdHead = (MINIDUMP_HEADER*)base; + MINIDUMP_HEADER* mdHead = base; if (mdHead->Signature == MINIDUMP_SIGNATURE) { @@ -985,9 +993,9 @@ BOOL WINAPI MiniDumpReadDumpStream(PVOID base, ULONG str_idx, { if (dir->StreamType == str_idx) { - *pdir = dir; - *stream = (char*)base + dir->Location.Rva; - *size = dir->Location.DataSize; + if (pdir) *pdir = dir; + if (stream) *stream = (char*)base + dir->Location.Rva; + if (size) *size = dir->Location.DataSize; return TRUE; } } diff --git a/dll/win32/dbghelp/module.c b/dll/win32/dbghelp/module.c index ddc6d3d89bd..53f56c25129 100644 --- a/dll/win32/dbghelp/module.c +++ b/dll/win32/dbghelp/module.c @@ -35,10 +35,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(dbghelp); const WCHAR S_ElfW[] = {'<','e','l','f','>','\0'}; const WCHAR S_WineLoaderW[] = {'<','w','i','n','e','-','l','o','a','d','e','r','>','\0'}; static const WCHAR S_DotSoW[] = {'.','s','o','\0'}; +static const WCHAR S_DotDylibW[] = {'.','d','y','l','i','b','\0'}; static const WCHAR S_DotPdbW[] = {'.','p','d','b','\0'}; static const WCHAR S_DotDbgW[] = {'.','d','b','g','\0'}; -const WCHAR S_WinePThreadW[] = {'w','i','n','e','-','p','t','h','r','e','a','d','\0'}; -const WCHAR S_WineKThreadW[] = {'w','i','n','e','-','k','t','h','r','e','a','d','\0'}; +const WCHAR S_WineW[] = {'w','i','n','e',0}; const WCHAR S_SlashW[] = {'/','\0'}; static const WCHAR S_AcmW[] = {'.','a','c','m','\0'}; @@ -87,9 +87,7 @@ static void module_fill_module(const WCHAR* in, WCHAR* out, size_t size) out[len] = '\0'; if (len > 4 && (l = match_ext(out, len))) out[len - l] = '\0'; - else if (len > 12 && - (!strcmpiW(out + len - 12, S_WinePThreadW) || - !strcmpiW(out + len - 12, S_WineKThreadW))) + else if (len > 4 && !strcmpiW(out + len - 4, S_WineW)) lstrcpynW(out, S_WineLoaderW, size); else { @@ -114,6 +112,7 @@ static const char* get_module_type(enum module_type type, BOOL virtual) { case DMT_ELF: return virtual ? "Virtual ELF" : "ELF"; case DMT_PE: return virtual ? "Virtual PE" : "PE"; + case DMT_MACHO: return virtual ? "Virtual Mach-O" : "Mach-O"; default: return "---"; } } @@ -123,20 +122,21 @@ static const char* get_module_type(enum module_type type, BOOL virtual) */ struct module* module_new(struct process* pcs, const WCHAR* name, enum module_type type, BOOL virtual, - unsigned long mod_addr, unsigned long size, + DWORD64 mod_addr, DWORD64 size, unsigned long stamp, unsigned long checksum) { struct module* module; - assert(type == DMT_ELF || type == DMT_PE); + assert(type == DMT_ELF || type == DMT_PE || type == DMT_MACHO); if (!(module = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*module)))) return NULL; module->next = pcs->lmodules; pcs->lmodules = module; - TRACE("=> %s %08lx-%08lx %s\n", - get_module_type(type, virtual), mod_addr, mod_addr + size, + TRACE("=> %s %s-%s %s\n", + get_module_type(type, virtual), + wine_dbgstr_longlong(mod_addr), wine_dbgstr_longlong(mod_addr + size), debugstr_w(name)); pool_init(&module->pool, 65536); @@ -169,7 +169,12 @@ struct module* module_new(struct process* pcs, const WCHAR* name, module->type = type; module->is_virtual = virtual ? TRUE : FALSE; module->sortlist_valid = FALSE; + module->sorttab_size = 0; module->addr_sorttab = NULL; + module->num_sorttab = 0; + module->num_symbols = 0; + + vector_init(&module->vsymt, sizeof(struct symt*), 128); /* FIXME: this seems a bit too high (on a per module basis) * need some statistics about this */ @@ -188,7 +193,7 @@ struct module* module_new(struct process* pcs, const WCHAR* name, * module_find_by_name * */ -struct module* module_find_by_name(const struct process* pcs, const WCHAR* name) +static struct module* module_find_by_name(const struct process* pcs, const WCHAR* name) { struct module* module; @@ -238,7 +243,7 @@ struct module* module_is_already_loaded(const struct process* pcs, const WCHAR* * module_get_container * */ -struct module* module_get_container(const struct process* pcs, +static struct module* module_get_container(const struct process* pcs, const struct module* inner) { struct module* module; @@ -319,6 +324,9 @@ BOOL module_get_debug(struct module_pair* pair) ret ? CBA_DEFERRED_SYMBOL_LOAD_COMPLETE : CBA_DEFERRED_SYMBOL_LOAD_FAILURE, &idslW64); break; + case DMT_MACHO: + ret = macho_load_debug_info(pair->effective, NULL); + break; default: ret = FALSE; break; @@ -344,7 +352,8 @@ struct module* module_find_by_addr(const struct process* pcs, unsigned long addr if (type == DMT_UNKNOWN) { if ((module = module_find_by_addr(pcs, addr, DMT_PE)) || - (module = module_find_by_addr(pcs, addr, DMT_ELF))) + (module = module_find_by_addr(pcs, addr, DMT_ELF)) || + (module = module_find_by_addr(pcs, addr, DMT_MACHO))) return module; } else @@ -361,13 +370,13 @@ struct module* module_find_by_addr(const struct process* pcs, unsigned long addr } /****************************************************************** - * module_is_elf_container_loaded + * module_is_container_loaded * - * checks whether the ELF container, for a (supposed) PE builtin is + * checks whether the native container, for a (supposed) PE builtin is * already loaded */ -static BOOL module_is_elf_container_loaded(const struct process* pcs, - const WCHAR* ImageName, DWORD base) +static BOOL module_is_container_loaded(const struct process* pcs, + const WCHAR* ImageName, DWORD64 base) { size_t len; struct module* module; @@ -379,7 +388,7 @@ static BOOL module_is_elf_container_loaded(const struct process* pcs, for (module = pcs->lmodules; module; module = module->next) { - if (module->type == DMT_ELF && + if ((module->type == DMT_ELF || module->type == DMT_MACHO) && base >= module->module.BaseOfImage && base < module->module.BaseOfImage + module->module.ImageSize) { @@ -419,8 +428,17 @@ enum module_type module_get_type_by_name(const WCHAR* name) } while (len); /* check for terminating .so or .so.[digit] */ + /* FIXME: Can't rely solely on extension; have to check magic or + * stop using .so on Mac OS X. For now, base on platform. */ if (len > 3 && !memcmp(name + len - 3, S_DotSoW, 3)) +#ifdef __APPLE__ + return DMT_MACHO; +#else return DMT_ELF; +#endif + + if (len > 6 && !strncmpiW(name + len - 6, S_DotDylibW, 6)) + return DMT_MACHO; if (len > 4 && !strncmpiW(name + len - 4, S_DotPdbW, 4)) return DMT_PDB; @@ -428,16 +446,27 @@ enum module_type module_get_type_by_name(const WCHAR* name) if (len > 4 && !strncmpiW(name + len - 4, S_DotDbgW, 4)) return DMT_DBG; - /* wine-[kp]thread is also an ELF module */ - if (((len > 12 && name[len - 13] == '/') || len == 12) && - (!strncmpiW(name + len - 12, S_WinePThreadW, 12) || - !strncmpiW(name + len - 12, S_WineKThreadW, 12))) + /* wine is also a native module (Mach-O on Mac OS X, ELF elsewhere) */ + if (((len > 4 && name[len - 5] == '/') || len == 4) && !strcmpiW(name + len - 4, S_WineW)) { +#ifdef __APPLE__ + return DMT_MACHO; +#else return DMT_ELF; +#endif } return DMT_PE; } +/****************************************************************** + * refresh_module_list + */ +static BOOL refresh_module_list(struct process* pcs) +{ + /* force transparent ELF and Mach-O loading / unloading */ + return elf_synchronize_module_list(pcs) || macho_synchronize_module_list(pcs); +} + /*********************************************************************** * SymLoadModule (DBGHELP.@) */ @@ -508,8 +537,9 @@ DWORD64 WINAPI SymLoadModuleExW(HANDLE hProcess, HANDLE hFile, PCWSTR wImageNam if (Flags & SLMFLAG_VIRTUAL) { + if (!wImageName) return FALSE; module = module_new(pcs, wImageName, module_get_type_by_name(wImageName), - TRUE, (DWORD)BaseOfDll, SizeOfDll, 0, 0); + TRUE, BaseOfDll, SizeOfDll, 0, 0); if (!module) return FALSE; if (wModuleName) module_set_module(module, wModuleName); module->module.SymType = SymVirtual; @@ -519,8 +549,7 @@ DWORD64 WINAPI SymLoadModuleExW(HANDLE hProcess, HANDLE hFile, PCWSTR wImageNam if (Flags & ~(SLMFLAG_VIRTUAL)) FIXME("Unsupported Flags %08x for %s\n", Flags, debugstr_w(wImageName)); - /* force transparent ELF loading / unloading */ - elf_synchronize_module_list(pcs); + refresh_module_list(pcs); /* this is a Wine extension to the API just to redo the synchronisation */ if (!wImageName && !hFile) return 0; @@ -531,7 +560,7 @@ DWORD64 WINAPI SymLoadModuleExW(HANDLE hProcess, HANDLE hFile, PCWSTR wImageNam if (wImageName) { module = module_is_already_loaded(pcs, wImageName); - if (!module && module_is_elf_container_loaded(pcs, wImageName, BaseOfDll)) + if (!module && module_is_container_loaded(pcs, wImageName, BaseOfDll)) { /* force the loading of DLL as builtin */ module = pe_load_builtin_module(pcs, wImageName, BaseOfDll, SizeOfDll); @@ -540,11 +569,22 @@ DWORD64 WINAPI SymLoadModuleExW(HANDLE hProcess, HANDLE hFile, PCWSTR wImageNam if (!module) { /* otherwise, try a regular PE module */ - if (!(module = pe_load_native_module(pcs, wImageName, hFile, BaseOfDll, SizeOfDll))) + if (!(module = pe_load_native_module(pcs, wImageName, hFile, BaseOfDll, SizeOfDll)) && + wImageName) { - /* and finally and ELF module */ - if (module_get_type_by_name(wImageName) == DMT_ELF) - module = elf_load_module(pcs, wImageName, BaseOfDll); + /* and finally an ELF or Mach-O module */ + switch (module_get_type_by_name(wImageName)) + { + case DMT_ELF: + module = elf_load_module(pcs, wImageName, BaseOfDll); + break; + case DMT_MACHO: + module = macho_load_module(pcs, wImageName, BaseOfDll); + break; + default: + /* Ignored */ + break; + } } } if (!module) @@ -558,7 +598,8 @@ DWORD64 WINAPI SymLoadModuleExW(HANDLE hProcess, HANDLE hFile, PCWSTR wImageNam */ if (wModuleName) module_set_module(module, wModuleName); - lstrcpynW(module->module.ImageName, wImageName, + if (wImageName) + lstrcpynW(module->module.ImageName, wImageName, sizeof(module->module.ImageName) / sizeof(WCHAR)); return module->module.BaseOfImage; @@ -715,7 +756,8 @@ BOOL WINAPI SymEnumerateModulesW64(HANDLE hProcess, for (module = pcs->lmodules; module; module = module->next) { - if (!(dbghelp_options & SYMOPT_WINE_WITH_ELF_MODULES) && module->type == DMT_ELF) + if (!(dbghelp_options & SYMOPT_WINE_WITH_NATIVE_MODULES) && + (module->type == DMT_ELF || module->type == DMT_MACHO)) continue; if (!EnumModulesCallback(module->module.ModuleName, module->module.BaseOfImage, UserContext)) @@ -1008,7 +1050,9 @@ DWORD64 WINAPI SymGetModuleBase64(HANDLE hProcess, DWORD64 dwAddr) void module_reset_debug_info(struct module* module) { module->sortlist_valid = TRUE; + module->sorttab_size = 0; module->addr_sorttab = NULL; + module->num_sorttab = module->num_symbols = 0; hash_table_destroy(&module->ht_symbols); module->ht_symbols.num_buckets = 0; module->ht_symbols.buckets = NULL; @@ -1020,3 +1064,17 @@ void module_reset_debug_info(struct module* module) module->sources_used = module->sources_alloc = 0; module->sources = NULL; } + +/****************************************************************** + * SymRefreshModuleList (DBGHELP.@) + */ +BOOL WINAPI SymRefreshModuleList(HANDLE hProcess) +{ + struct process* pcs; + + TRACE("(%p)\n", hProcess); + + if (!(pcs = process_find_by_handle(hProcess))) return FALSE; + + return refresh_module_list(pcs); +} diff --git a/dll/win32/dbghelp/msc.c b/dll/win32/dbghelp/msc.c index 47998549bde..ee394cd946c 100644 --- a/dll/win32/dbghelp/msc.c +++ b/dll/win32/dbghelp/msc.c @@ -71,7 +71,7 @@ static void dump(const void* ptr, unsigned len) unsigned int i, j; char msg[128]; const char* hexof = "0123456789abcdef"; - const BYTE* x = (const BYTE*)ptr; + const BYTE* x = ptr; for (i = 0; i < len; i += 16) { @@ -95,7 +95,7 @@ static void dump(const void* ptr, unsigned len) * Process CodeView type information. */ -#define MAX_BUILTIN_TYPES 0x0480 +#define MAX_BUILTIN_TYPES 0x0604 #define FIRST_DEFINABLE_TYPE 0x1000 static struct symt* cv_basic_types[MAX_BUILTIN_TYPES]; @@ -113,6 +113,7 @@ static struct cv_defined_module*cv_current_module; static void codeview_init_basic_types(struct module* module) { + struct symt_udt* udt; /* * These are the common builtin types that are used by VC++. */ @@ -169,6 +170,12 @@ static void codeview_init_basic_types(struct module* module) cv_basic_types[T_32PINT8] = &symt_new_pointer(module, cv_basic_types[T_INT8])->symt; cv_basic_types[T_32PUINT8] = &symt_new_pointer(module, cv_basic_types[T_UINT8])->symt; cv_basic_types[T_32PHRESULT]= &symt_new_pointer(module, cv_basic_types[T_HRESULT])->symt; + + /* The .pdb file can refer to 64 bit pointers values even on 32 bits applications. */ + udt = symt_new_udt(module, "PVOID64", 8, UdtStruct); + symt_add_udt_element(module, udt, "ptr64_low", cv_basic_types[T_LONG], 0, 32); + symt_add_udt_element(module, udt, "ptr64_high", cv_basic_types[T_LONG], 32, 32); + cv_basic_types[0x603]= &udt->symt; } static int leaf_as_variant(VARIANT* v, const unsigned short int* leaf) @@ -486,18 +493,23 @@ static int codeview_add_type(unsigned int typeno, struct symt* dt) if ((typeno >> 24) != 0) FIXME("No module index while inserting type-id assumption is wrong %x\n", typeno); - while (typeno - FIRST_DEFINABLE_TYPE >= cv_current_module->num_defined_types) + if (typeno - FIRST_DEFINABLE_TYPE >= cv_current_module->num_defined_types) { - cv_current_module->num_defined_types += 0x100; if (cv_current_module->defined_types) + { + cv_current_module->num_defined_types = max( cv_current_module->num_defined_types * 2, + typeno - FIRST_DEFINABLE_TYPE + 1 ); cv_current_module->defined_types = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cv_current_module->defined_types, cv_current_module->num_defined_types * sizeof(struct symt*)); + } else + { + cv_current_module->num_defined_types = max( 256, typeno - FIRST_DEFINABLE_TYPE + 1 ); cv_current_module->defined_types = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cv_current_module->num_defined_types * sizeof(struct symt*)); - + } if (cv_current_module->defined_types == NULL) return FALSE; } if (cv_current_module->defined_types[typeno - FIRST_DEFINABLE_TYPE]) @@ -581,15 +593,8 @@ static struct symt* codeview_add_type_array(struct codeview_type_parse* ctp, { struct symt* elem = codeview_fetch_type(ctp, elemtype, FALSE); struct symt* index = codeview_fetch_type(ctp, indextype, FALSE); - DWORD arr_max = 0; - if (elem) - { - DWORD64 elem_size; - symt_get_info(elem, TI_GET_LENGTH, &elem_size); - if (elem_size) arr_max = arr_len / (DWORD)elem_size; - } - return &symt_new_array(ctp->module, 0, arr_max, elem, index)->symt; + return &symt_new_array(ctp->module, 0, -arr_len, elem, index)->symt; } static int codeview_add_type_enum_field_list(struct module* module, @@ -669,7 +674,7 @@ static void codeview_add_udt_element(struct codeview_type_parse* ctp, if (subtype) { DWORD64 elem_size = 0; - symt_get_info(subtype, TI_GET_LENGTH, &elem_size); + symt_get_info(ctp->module, subtype, TI_GET_LENGTH, &elem_size); symt_add_udt_element(ctp->module, symt, name, subtype, value << 3, (DWORD)elem_size << 3); } @@ -1357,48 +1362,72 @@ static void codeview_snarf_linetab(const struct msc_debug_info* msc_dbg, const B } static void codeview_snarf_linetab2(const struct msc_debug_info* msc_dbg, const BYTE* linetab, DWORD size, - const char* strimage, DWORD strsize) + const char* strimage, DWORD strsize) { - DWORD offset; unsigned i; DWORD addr; - const struct codeview_linetab2_block* lbh; - const struct codeview_linetab2_file* fd; + const struct codeview_linetab2* lt2; + const struct codeview_linetab2* lt2_files = NULL; + const struct codeview_lt2blk_lines* lines_blk; + const struct codeview_linetab2_file*fd; unsigned source; struct symt_function* func; - if (*(const DWORD*)linetab != 0x000000f4) return; - offset = *((const DWORD*)linetab + 1); - - for (lbh = (const struct codeview_linetab2_block*)(linetab + 8 + offset); - (const BYTE*)lbh < linetab + size; - lbh = (const struct codeview_linetab2_block*)((const char*)lbh + 8 + lbh->size_of_block)) + /* locate LT2_FILES_BLOCK (if any) */ + lt2 = (const struct codeview_linetab2*)linetab; + while ((const BYTE*)(lt2 + 1) < linetab + size) { - if (lbh->header != 0x000000f2) - /* FIXME: should also check that whole lbh fits in linetab + size */ + if (lt2->header == LT2_FILES_BLOCK) { - TRACE("block end %x\n", lbh->header); + lt2_files = lt2; break; } - addr = codeview_get_address(msc_dbg, lbh->seg, lbh->start); - TRACE("block from %04x:%08x #%x (%x lines)\n", - lbh->seg, lbh->start, lbh->size, lbh->nlines); - fd = (const struct codeview_linetab2_file*)(linetab + 8 + lbh->file_offset); - /* FIXME: should check that string is within strimage + strsize */ - source = source_new(msc_dbg->module, NULL, strimage + fd->offset); - func = (struct symt_function*)symt_find_nearest(msc_dbg->module, addr); - /* FIXME: at least labels support line numbers */ - if (!func || func->symt.tag != SymTagFunction) + lt2 = codeview_linetab2_next_block(lt2); + } + if (!lt2_files) + { + TRACE("No LT2_FILES_BLOCK found\n"); + return; + } + + lt2 = (const struct codeview_linetab2*)linetab; + while ((const BYTE*)(lt2 + 1) < linetab + size) + { + /* FIXME: should also check that whole lines_blk fits in linetab + size */ + switch (lt2->header) { - WARN("--not a func at %04x:%08x %x tag=%d\n", - lbh->seg, lbh->start, addr, func ? func->symt.tag : -1); + case LT2_LINES_BLOCK: + lines_blk = (const struct codeview_lt2blk_lines*)lt2; + /* FIXME: should check that file_offset is within the LT2_FILES_BLOCK we've seen */ + addr = codeview_get_address(msc_dbg, lines_blk->seg, lines_blk->start); + TRACE("block from %04x:%08x #%x (%x lines)\n", + lines_blk->seg, lines_blk->start, lines_blk->size, lines_blk->nlines); + fd = (const struct codeview_linetab2_file*)((const char*)lt2_files + 8 + lines_blk->file_offset); + /* FIXME: should check that string is within strimage + strsize */ + source = source_new(msc_dbg->module, NULL, strimage + fd->offset); + func = (struct symt_function*)symt_find_nearest(msc_dbg->module, addr); + /* FIXME: at least labels support line numbers */ + if (!func || func->symt.tag != SymTagFunction) + { + WARN("--not a func at %04x:%08x %x tag=%d\n", + lines_blk->seg, lines_blk->start, addr, func ? func->symt.tag : -1); + break; + } + for (i = 0; i < lines_blk->nlines; i++) + { + symt_add_func_line(msc_dbg->module, func, source, + lines_blk->l[i].lineno ^ 0x80000000, + lines_blk->l[i].offset); + } + break; + case LT2_FILES_BLOCK: /* skip */ + break; + default: + TRACE("Block end %x\n", lt2->header); + lt2 = (const struct codeview_linetab2*)((const char*)linetab + size); continue; } - for (i = 0; i < lbh->nlines; i++) - { - symt_add_func_line(msc_dbg->module, func, source, - lbh->l[i].lineno ^ 0x80000000, lbh->l[i].offset - lbh->start); - } + lt2 = codeview_linetab2_next_block(lt2); } } @@ -1897,8 +1926,7 @@ static int codeview_snarf_public(const struct msc_debug_info* msc_dbg, const BYT { symt_new_public(msc_dbg->module, compiland, terminate_string(&sym->data_v1.p_name), - codeview_get_address(msc_dbg, sym->data_v1.segment, sym->data_v1.offset), - 1, TRUE /* FIXME */, TRUE /* FIXME */); + codeview_get_address(msc_dbg, sym->data_v1.segment, sym->data_v1.offset), 1); } break; case S_PUB_V2: /* FIXME is this really a 'data_v2' structure ?? */ @@ -1906,8 +1934,7 @@ static int codeview_snarf_public(const struct msc_debug_info* msc_dbg, const BYT { symt_new_public(msc_dbg->module, compiland, terminate_string(&sym->data_v2.p_name), - codeview_get_address(msc_dbg, sym->data_v2.segment, sym->data_v2.offset), - 1, TRUE /* FIXME */, TRUE /* FIXME */); + codeview_get_address(msc_dbg, sym->data_v2.segment, sym->data_v2.offset), 1); } break; @@ -1916,8 +1943,7 @@ static int codeview_snarf_public(const struct msc_debug_info* msc_dbg, const BYT { symt_new_public(msc_dbg->module, compiland, sym->data_v3.name, - codeview_get_address(msc_dbg, sym->data_v3.segment, sym->data_v3.offset), - 1, FALSE /* FIXME */, FALSE); + codeview_get_address(msc_dbg, sym->data_v3.segment, sym->data_v3.offset), 1); } break; case S_PUB_FUNC1_V3: @@ -1928,8 +1954,7 @@ static int codeview_snarf_public(const struct msc_debug_info* msc_dbg, const BYT { symt_new_public(msc_dbg->module, compiland, sym->data_v3.name, - codeview_get_address(msc_dbg, sym->data_v3.segment, sym->data_v3.offset), - 1, TRUE /* FIXME */, TRUE); + codeview_get_address(msc_dbg, sym->data_v3.segment, sym->data_v3.offset), 1); } #endif break; @@ -2150,7 +2175,7 @@ static void pdb_convert_symbol_file(const PDB_SYMBOLS* symbols, { if (symbols->version < 19970000) { - const PDB_SYMBOL_FILE *sym_file = (const PDB_SYMBOL_FILE*)image; + const PDB_SYMBOL_FILE *sym_file = image; memset(sfile, 0, sizeof(*sfile)); sfile->file = sym_file->file; sfile->range.index = sym_file->range.index; @@ -2217,7 +2242,8 @@ static void pdb_process_types(const struct msc_debug_info* msc_dbg, case 19950410: /* VC 4.0 */ case 19951122: case 19961031: /* VC 5.0 / 6.0 */ - case 19990903: + case 19990903: /* VC 7.0 */ + case 20040203: /* VC 8.0 */ break; default: ERR("-Unknown type info version %d\n", types.version); @@ -2385,7 +2411,7 @@ static void pdb_process_symbol_imports(const struct process* pcs, imp = (const PDB_SYMBOL_IMPORT*)((const char*)symbols_image + sizeof(PDB_SYMBOLS) + symbols->module_size + symbols->offset_size + symbols->hash_size + symbols->srcmodule_size); - first = (const char*)imp; + first = imp; last = (const char*)imp + symbols->pdbimport_size; while (imp < (const PDB_SYMBOL_IMPORT*)last) { @@ -2524,7 +2550,7 @@ static BOOL pdb_process_internal(const struct process* pcs, } file_name = (const char*)file + size; file_name += strlen(file_name) + 1; - file = (BYTE*)((DWORD)(file_name + strlen(file_name) + 1 + 3) & ~3); + file = (BYTE*)((DWORD_PTR)(file_name + strlen(file_name) + 1 + 3) & ~3); } /* finish the remaining public and global information */ if (globalimage) diff --git a/dll/win32/dbghelp/path.c b/dll/win32/dbghelp/path.c index e0cfc97a082..12c595b4d1e 100644 --- a/dll/win32/dbghelp/path.c +++ b/dll/win32/dbghelp/path.c @@ -234,7 +234,7 @@ static BOOL do_searchW(PCWSTR file, PWSTR buffer, BOOL recurse, strcpyW(buffer + pos, fd.cFileName); if (recurse && (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) found = do_searchW(file, buffer, TRUE, cb, user); - else if (SymMatchFileNameW(buffer, (WCHAR*)file, NULL, NULL)) + else if (SymMatchFileNameW(buffer, file, NULL, NULL)) { if (!cb || cb(buffer, user)) found = TRUE; } @@ -340,13 +340,13 @@ struct sffip */ static BOOL CALLBACK sffip_cb(PCWSTR buffer, PVOID user) { - struct sffip* s = (struct sffip*)user; + struct sffip* s = user; if (!s->cb) return TRUE; /* yes, EnumDirTree/do_search and SymFindFileInPath callbacks use the opposite * convention to stop/continue enumeration. sigh. */ - return !(s->cb)((WCHAR*)buffer, s->user); + return !(s->cb)(buffer, s->user); } /****************************************************************** @@ -461,7 +461,7 @@ struct module_find */ static BOOL CALLBACK module_find_cb(PCWSTR buffer, PVOID user) { - struct module_find* mf = (struct module_find*)user; + struct module_find* mf = user; DWORD size, checksum, timestamp; unsigned matched = 0; @@ -522,6 +522,21 @@ static BOOL CALLBACK module_find_cb(PCWSTR buffer, PVOID user) return FALSE; } break; + case DMT_MACHO: + if (macho_fetch_file_info(buffer, 0, &size, &checksum)) + { + matched++; + if (checksum == mf->dw1) matched++; + else + WARN("Found %s, but wrong checksums: %08x %08x\n", + debugstr_w(buffer), checksum, mf->dw1); + } + else + { + WARN("Couldn't read %s\n", debugstr_w(buffer)); + return FALSE; + } + break; case DMT_PDB: { struct pdb_lookup pdb_lookup; @@ -580,7 +595,7 @@ static BOOL CALLBACK module_find_cb(PCWSTR buffer, PVOID user) if ((mapping = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) != NULL) { const IMAGE_SEPARATE_DEBUG_HEADER* hdr; - hdr = (const IMAGE_SEPARATE_DEBUG_HEADER*)mapping; + hdr = mapping; if (hdr->Signature == IMAGE_SEPARATE_DEBUG_SIGNATURE) { diff --git a/dll/win32/dbghelp/pe_module.c b/dll/win32/dbghelp/pe_module.c index a79396f5191..76d81ee5512 100644 --- a/dll/win32/dbghelp/pe_module.c +++ b/dll/win32/dbghelp/pe_module.c @@ -35,6 +35,141 @@ WINE_DEFAULT_DEBUG_CHANNEL(dbghelp); +/****************************************************************** + * pe_locate_with_coff_symbol_table + * + * Use the COFF symbol table (if any) from the IMAGE_FILE_HEADER to set the absolute address + * of global symbols. + * Mingw32 requires this for stabs debug information as address for global variables isn't filled in + * (this is similar to what is done in elf_module.c when using the .symtab ELF section) + */ +static BOOL pe_locate_with_coff_symbol_table(struct module* module, IMAGE_NT_HEADERS* nth, void* mapping) +{ + const IMAGE_SYMBOL* isym; + int i, numsym, naux; + const char* strtable; + char tmp[9]; + const char* name; + struct hash_table_iter hti; + void* ptr; + struct symt_data* sym; + const IMAGE_SECTION_HEADER* sect; + + numsym = nth->FileHeader.NumberOfSymbols; + if (!nth->FileHeader.PointerToSymbolTable || !numsym) + return TRUE; + isym = (const IMAGE_SYMBOL*)((char*)mapping + nth->FileHeader.PointerToSymbolTable); + /* FIXME: no way to get strtable size */ + strtable = (const char*)&isym[numsym]; + sect = IMAGE_FIRST_SECTION(nth); + + for (i = 0; i < numsym; i+= naux, isym += naux) + { + if (isym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL && + isym->SectionNumber > 0 && isym->SectionNumber <= nth->FileHeader.NumberOfSections) + { + if (isym->N.Name.Short) + { + name = memcpy(tmp, isym->N.ShortName, 8); + tmp[8] = '\0'; + } + else name = strtable + isym->N.Name.Long; + if (name[0] == '_') name++; + hash_table_iter_init(&module->ht_symbols, &hti, name); + while ((ptr = hash_table_iter_up(&hti))) + { + sym = GET_ENTRY(ptr, struct symt_data, hash_elt); + if (sym->symt.tag == SymTagData && + (sym->kind == DataIsGlobal || sym->kind == DataIsFileStatic) && + !strcmp(sym->hash_elt.name, name)) + { + TRACE("Changing absolute address for %d.%s: %lx -> %s\n", + isym->SectionNumber, name, sym->u.var.offset, + wine_dbgstr_longlong(module->module.BaseOfImage + + sect[isym->SectionNumber - 1].VirtualAddress + isym->Value)); + sym->u.var.offset = module->module.BaseOfImage + + sect[isym->SectionNumber - 1].VirtualAddress + isym->Value; + break; + } + } + } + naux = isym->NumberOfAuxSymbols + 1; + } + return TRUE; +} + +/****************************************************************** + * pe_load_coff_symbol_table + * + * Load public symbols out of the COFF symbol table (if any). + */ +static BOOL pe_load_coff_symbol_table(struct module* module, IMAGE_NT_HEADERS* nth, void* mapping) +{ + const IMAGE_SYMBOL* isym; + int i, numsym, naux; + const char* strtable; + char tmp[9]; + const char* name; + const char* lastfilename = NULL; + struct symt_compiland* compiland = NULL; + const IMAGE_SECTION_HEADER* sect; + + numsym = nth->FileHeader.NumberOfSymbols; + if (!nth->FileHeader.PointerToSymbolTable || !numsym) + return TRUE; + isym = (const IMAGE_SYMBOL*)((char*)mapping + nth->FileHeader.PointerToSymbolTable); + /* FIXME: no way to get strtable size */ + strtable = (const char*)&isym[numsym]; + sect = IMAGE_FIRST_SECTION(nth); + + for (i = 0; i < numsym; i+= naux, isym += naux) + { + if (isym->StorageClass == IMAGE_SYM_CLASS_FILE) + { + lastfilename = (const char*)(isym + 1); + compiland = NULL; + } + if (isym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL && + isym->SectionNumber > 0 && isym->SectionNumber <= nth->FileHeader.NumberOfSections) + { + if (isym->N.Name.Short) + { + name = memcpy(tmp, isym->N.ShortName, 8); + tmp[8] = '\0'; + } + else name = strtable + isym->N.Name.Long; + if (name[0] == '_') name++; + + if (!compiland && lastfilename) + compiland = symt_new_compiland(module, 0, + source_new(module, NULL, lastfilename)); + symt_new_public(module, compiland, name, + module->module.BaseOfImage + sect[isym->SectionNumber - 1].VirtualAddress + isym->Value, + 1); + } + naux = isym->NumberOfAuxSymbols + 1; + } + module->module.SymType = SymCoff; + module->module.LineNumbers = FALSE; + module->module.GlobalSymbols = FALSE; + module->module.TypeInfo = FALSE; + module->module.SourceIndexed = FALSE; + module->module.Publics = TRUE; + + return TRUE; +} + +static inline void* pe_get_sect(IMAGE_NT_HEADERS* nth, void* mapping, + IMAGE_SECTION_HEADER* sect) +{ + return (sect) ? RtlImageRvaToVa(nth, mapping, sect->VirtualAddress, NULL) : NULL; +} + +static inline DWORD pe_get_sect_size(IMAGE_SECTION_HEADER* sect) +{ + return (sect) ? sect->SizeOfRawData : 0; +} + /****************************************************************** * pe_load_stabs * @@ -45,37 +180,85 @@ static BOOL pe_load_stabs(const struct process* pcs, struct module* module, void* mapping, IMAGE_NT_HEADERS* nth) { IMAGE_SECTION_HEADER* section; - int i, stabsize = 0, stabstrsize = 0; - unsigned int stabs = 0, stabstr = 0; + IMAGE_SECTION_HEADER* sect_stabs = NULL; + IMAGE_SECTION_HEADER* sect_stabstr = NULL; + int i; BOOL ret = FALSE; section = (IMAGE_SECTION_HEADER*) ((char*)&nth->OptionalHeader + nth->FileHeader.SizeOfOptionalHeader); for (i = 0; i < nth->FileHeader.NumberOfSections; i++, section++) { - if (!strcasecmp((const char*)section->Name, ".stab")) - { - stabs = section->VirtualAddress; - stabsize = section->SizeOfRawData; - } - else if (!strncasecmp((const char*)section->Name, ".stabstr", 8)) - { - stabstr = section->VirtualAddress; - stabstrsize = section->SizeOfRawData; - } + if (!strcasecmp((const char*)section->Name, ".stab")) sect_stabs = section; + else if (!strncasecmp((const char*)section->Name, ".stabstr", 8)) sect_stabstr = section; } - - if (stabstrsize && stabsize) + if (sect_stabs && sect_stabstr) { - ret = stabs_parse(module, - module->module.BaseOfImage - nth->OptionalHeader.ImageBase, - RtlImageRvaToVa(nth, mapping, stabs, NULL), - stabsize, - RtlImageRvaToVa(nth, mapping, stabstr, NULL), - stabstrsize); + ret = stabs_parse(module, + module->module.BaseOfImage - nth->OptionalHeader.ImageBase, + pe_get_sect(nth, mapping, sect_stabs), pe_get_sect_size(sect_stabs), + pe_get_sect(nth, mapping, sect_stabstr), pe_get_sect_size(sect_stabstr), + NULL, NULL); + if (ret) pe_locate_with_coff_symbol_table(module, nth, mapping); } - TRACE("%s the STABS debug info\n", ret ? "successfully loaded" : "failed to load"); + + return ret; +} + +/****************************************************************** + * pe_load_dwarf + * + * look for dwarf information in PE header (it's also a way for the mingw compiler + * to provide its debugging information) + */ +static BOOL pe_load_dwarf(const struct process* pcs, struct module* module, + void* mapping, IMAGE_NT_HEADERS* nth) +{ + IMAGE_SECTION_HEADER* section; + IMAGE_SECTION_HEADER* sect_debuginfo = NULL; + IMAGE_SECTION_HEADER* sect_debugstr = NULL; + IMAGE_SECTION_HEADER* sect_debugabbrev = NULL; + IMAGE_SECTION_HEADER* sect_debugline = NULL; + IMAGE_SECTION_HEADER* sect_debugloc = NULL; + int i; + const char* strtable; + const char* sectname; + BOOL ret = FALSE; + + if (nth->FileHeader.PointerToSymbolTable && nth->FileHeader.NumberOfSymbols) + /* FIXME: no way to get strtable size */ + strtable = (const char*)mapping + nth->FileHeader.PointerToSymbolTable + + nth->FileHeader.NumberOfSymbols * sizeof(IMAGE_SYMBOL); + else strtable = NULL; + + section = (IMAGE_SECTION_HEADER*) + ((char*)&nth->OptionalHeader + nth->FileHeader.SizeOfOptionalHeader); + for (i = 0; i < nth->FileHeader.NumberOfSections; i++, section++) + { + sectname = (const char*)section->Name; + /* long section names start with a '/' (at least on MinGW32) */ + if (*sectname == '/' && strtable) + sectname = strtable + atoi(sectname + 1); + if (!strcasecmp(sectname, ".debug_info")) sect_debuginfo = section; + else if (!strcasecmp(sectname, ".debug_str")) sect_debugstr = section; + else if (!strcasecmp(sectname, ".debug_abbrev")) sect_debugabbrev = section; + else if (!strcasecmp(sectname, ".debug_line")) sect_debugline = section; + else if (!strcasecmp(sectname, ".debug_loc")) sect_debugloc = section; + } + if (sect_debuginfo) + { + ret = dwarf2_parse(module, + module->module.BaseOfImage - nth->OptionalHeader.ImageBase, + NULL, /* FIXME: some thunks to deal with ? */ + pe_get_sect(nth, mapping, sect_debuginfo), pe_get_sect_size(sect_debuginfo), + pe_get_sect(nth, mapping, sect_debugabbrev), pe_get_sect_size(sect_debugabbrev), + pe_get_sect(nth, mapping, sect_debugstr), pe_get_sect_size(sect_debugstr), + pe_get_sect(nth, mapping, sect_debugline), pe_get_sect_size(sect_debugline), + pe_get_sect(nth, mapping, sect_debugloc), pe_get_sect_size(sect_debugloc)); + } + TRACE("%s the DWARF debug info\n", ret ? "successfully loaded" : "failed to load"); + return ret; } @@ -133,7 +316,7 @@ static BOOL pe_load_dbg_file(const struct process* pcs, struct module* module, */ static BOOL pe_load_msc_debug_info(const struct process* pcs, struct module* module, - void* mapping, IMAGE_NT_HEADERS* nth) + void* mapping, const IMAGE_NT_HEADERS* nth) { BOOL ret = FALSE; const IMAGE_DATA_DIRECTORY* dir; @@ -181,7 +364,7 @@ static BOOL pe_load_msc_debug_info(const struct process* pcs, */ static BOOL pe_load_export_debug_info(const struct process* pcs, struct module* module, - void* mapping, IMAGE_NT_HEADERS* nth) + void* mapping, const IMAGE_NT_HEADERS* nth) { unsigned int i; const IMAGE_EXPORT_DIRECTORY* exports; @@ -193,14 +376,12 @@ static BOOL pe_load_export_debug_info(const struct process* pcs, #if 0 /* Add start of DLL (better use the (yet unimplemented) Exe SymTag for this) */ /* FIXME: module.ModuleName isn't correctly set yet if it's passed in SymLoadModule */ - symt_new_public(module, NULL, module->module.ModuleName, base, 1, - TRUE /* FIXME */, TRUE /* FIXME */); + symt_new_public(module, NULL, module->module.ModuleName, base, 1); #endif /* Add entry point */ symt_new_public(module, NULL, "EntryPoint", - base + nth->OptionalHeader.AddressOfEntryPoint, 1, - TRUE, TRUE); + base + nth->OptionalHeader.AddressOfEntryPoint, 1); #if 0 /* FIXME: we'd better store addresses linked to sections rather than absolute values */ @@ -211,8 +392,7 @@ static BOOL pe_load_export_debug_info(const struct process* pcs, for (i = 0; i < nth->FileHeader.NumberOfSections; i++, section++) { symt_new_public(module, NULL, section->Name, - RtlImageRvaToVa(nth, mapping, section->VirtualAddress, NULL), - 1, TRUE /* FIXME */, TRUE /* FIXME */); + RtlImageRvaToVa(nth, mapping, section->VirtualAddress, NULL), 1); } #endif @@ -237,8 +417,7 @@ static BOOL pe_load_export_debug_info(const struct process* pcs, if (!names[i]) continue; symt_new_public(module, NULL, RtlImageRvaToVa(nth, mapping, names[i], NULL), - base + functions[ordinals[i]], - 1, TRUE /* FIXME */, TRUE /* FIXME */); + base + functions[ordinals[i]], 1); } for (i = 0; i < exports->NumberOfFunctions; i++) @@ -249,8 +428,7 @@ static BOOL pe_load_export_debug_info(const struct process* pcs, if ((ordinals[j] == i) && names[j]) break; if (j < exports->NumberOfNames) continue; snprintf(buffer, sizeof(buffer), "%d", i + exports->Base); - symt_new_public(module, NULL, buffer, base + (DWORD)functions[i], 1, - TRUE /* FIXME */, TRUE /* FIXME */); + symt_new_public(module, NULL, buffer, base + (DWORD)functions[i], 1); } } } @@ -284,7 +462,9 @@ BOOL pe_load_debug_info(const struct process* pcs, struct module* module) if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY)) { ret = pe_load_stabs(pcs, module, mapping, nth) || - pe_load_msc_debug_info(pcs, module, mapping, nth); + pe_load_dwarf(pcs, module, mapping, nth) || + pe_load_msc_debug_info(pcs, module, mapping, nth) || + pe_load_coff_symbol_table(module, nth, mapping); /* if we still have no debug info (we could only get SymExport at this * point), then do the SymExport except if we have an ELF container, * in which case we'll rely on the export's on the ELF side @@ -367,13 +547,13 @@ struct module* pe_load_native_module(struct process* pcs, const WCHAR* name, * pe_load_nt_header * */ -BOOL pe_load_nt_header(HANDLE hProc, DWORD base, IMAGE_NT_HEADERS* nth) +BOOL pe_load_nt_header(HANDLE hProc, DWORD64 base, IMAGE_NT_HEADERS* nth) { IMAGE_DOS_HEADER dos; - return ReadProcessMemory(hProc, (char*)base, &dos, sizeof(dos), NULL) && + return ReadProcessMemory(hProc, (char*)(DWORD_PTR)base, &dos, sizeof(dos), NULL) && dos.e_magic == IMAGE_DOS_SIGNATURE && - ReadProcessMemory(hProc, (char*)(base + dos.e_lfanew), + ReadProcessMemory(hProc, (char*)(DWORD_PTR)(base + dos.e_lfanew), nth, sizeof(*nth), NULL) && nth->Signature == IMAGE_NT_SIGNATURE; } @@ -383,7 +563,7 @@ BOOL pe_load_nt_header(HANDLE hProc, DWORD base, IMAGE_NT_HEADERS* nth) * */ struct module* pe_load_builtin_module(struct process* pcs, const WCHAR* name, - DWORD base, DWORD size) + DWORD64 base, DWORD64 size) { struct module* module = NULL; @@ -435,7 +615,7 @@ PVOID WINAPI ImageDirectoryEntryToDataEx( PVOID base, BOOLEAN image, USHORT dir, *size = nt->OptionalHeader.DataDirectory[dir].Size; if (image || addr < nt->OptionalHeader.SizeOfHeaders) return (char *)base + addr; - return RtlImageRvaToVa( nt, (HMODULE)base, addr, section ); + return RtlImageRvaToVa( nt, base, addr, section ); } /*********************************************************************** diff --git a/dll/win32/dbghelp/rosstubs.c b/dll/win32/dbghelp/rosstubs.c index d6084612536..f4917899f6d 100644 --- a/dll/win32/dbghelp/rosstubs.c +++ b/dll/win32/dbghelp/rosstubs.c @@ -309,42 +309,6 @@ SymGetHomeDirectoryW(DWORD dwType, return NULL; } -BOOL WINAPI -SymGetLineFromName64(HANDLE hProcess, - PCSTR pszModuleName, - PCSTR pszFileName, - DWORD dwLineNumber, - PLONG plDisplacement, - PIMAGEHLP_LINE64 Line) -{ - UNIMPLEMENTED; - return FALSE; -} - -BOOL WINAPI -SymGetLineFromName(HANDLE hProcess, - PCSTR pszModuleName, - PCSTR pszFileName, - DWORD dwLineNumber, - PLONG plDisplacement, - PIMAGEHLP_LINE Line) -{ - UNIMPLEMENTED; - return FALSE; -} - -BOOL WINAPI -SymGetLineFromNameW64(HANDLE hProcess, - PCWSTR pszModuleName, - PCWSTR pszFileName, - DWORD dwLineNumber, - PLONG lpDisplacement, - PIMAGEHLP_LINEW64 Line) -{ - UNIMPLEMENTED; - return FALSE; -} - BOOL WINAPI SymGetLineNextW64(HANDLE hProcess, PIMAGEHLP_LINEW64 Line) @@ -459,31 +423,6 @@ SymGetSourceVarFromTokenW( return FALSE; } -BOOL WINAPI -SymGetSymFromName64(HANDLE hProcess, - PCSTR pszName, - PIMAGEHLP_SYMBOL64 Symbol) -{ - UNIMPLEMENTED; - return FALSE; -} - -BOOL WINAPI -SymGetSymNext64(HANDLE hProcess, - PIMAGEHLP_SYMBOL64 Symbol) -{ - UNIMPLEMENTED; - return FALSE; -} - -BOOL WINAPI -SymGetSymPrev64(HANDLE hProcess, - PIMAGEHLP_SYMBOL64 Symbol) -{ - UNIMPLEMENTED; - return FALSE; -} - BOOL WINAPI SymGetSymbolFile(HANDLE hProcess, PCSTR pszSymPath, @@ -581,16 +520,6 @@ SymPrevW(HANDLE hProcess, return FALSE; } -BOOL -WINAPI -SymRefreshModuleList( - HANDLE hProcess) -{ - UNIMPLEMENTED; - return FALSE; -} - - PCHAR WINAPI SymSetHomeDirectory(HANDLE hProcess, PCSTR pszDir) @@ -766,15 +695,6 @@ SymSrvStoreSupplementW(HANDLE hProcess, return NULL; } -BOOL WINAPI -SymUnDName64(PIMAGEHLP_SYMBOL64 Symbol, - PSTR pszUndecoratedName, - DWORD dwUndecoratedNameLength) -{ - UNIMPLEMENTED; - return FALSE; -} - DWORD WINAPI UnDecorateSymbolNameW(PCWSTR DecoratedName, PWSTR pszUnDecoratedName, diff --git a/dll/win32/dbghelp/source.c b/dll/win32/dbghelp/source.c index 8eef33727cd..c8ecf26c9fc 100644 --- a/dll/win32/dbghelp/source.c +++ b/dll/win32/dbghelp/source.c @@ -26,9 +26,6 @@ #include "dbghelp_private.h" #include "wine/debug.h" -#ifdef HAVE_REGEX_H -# include -#endif WINE_DEFAULT_DEBUG_CHANNEL(dbghelp); @@ -79,13 +76,18 @@ unsigned source_new(struct module* module, const char* base, const char* name) int len = strlen(full) + 1; if (module->sources_used + len + 1 > module->sources_alloc) { - /* Alloc by block of 256 bytes */ - module->sources_alloc = (module->sources_used + len + 1 + 255) & ~255; if (!module->sources) + { + module->sources_alloc = (module->sources_used + len + 1 + 255) & ~255; module->sources = HeapAlloc(GetProcessHeap(), 0, module->sources_alloc); + } else + { + module->sources_alloc = max( module->sources_alloc * 2, + (module->sources_used + len + 1 + 255) & ~255 ); module->sources = HeapReAlloc(GetProcessHeap(), 0, module->sources, module->sources_alloc); + } } ret = module->sources_used; memcpy(module->sources + module->sources_used, full, len); @@ -154,116 +156,6 @@ BOOL WINAPI SymEnumSourceFiles(HANDLE hProcess, ULONG64 ModBase, PCSTR Mask, return TRUE; } -static inline void re_append(char** mask, unsigned* len, char ch) -{ - *mask = HeapReAlloc(GetProcessHeap(), 0, *mask, ++(*len)); - (*mask)[*len - 2] = ch; -} - -static BOOL compile_regex(regex_t* re, const char* srcfile) -{ - char* mask; - unsigned len = 1; - - mask = HeapAlloc(GetProcessHeap(), 0, 1); - re_append(&mask, &len, '^'); - if (!srcfile || !*srcfile) re_append(&mask, &len, '*'); - else while (*srcfile) - { - switch (*srcfile) - { - case '\\': - case '/': - re_append(&mask, &len, '['); - re_append(&mask, &len, '\\'); - re_append(&mask, &len, '\\'); - re_append(&mask, &len, '/'); - re_append(&mask, &len, ']'); - break; - case '.': - re_append(&mask, &len, '\\'); - re_append(&mask, &len, '.'); - break; - default: - re_append(&mask, &len, *srcfile); - break; - } - srcfile++; - } - re_append(&mask, &len, '$'); - mask[len - 1] = '\0'; - len = regcomp(re, mask, REG_NOSUB); - HeapFree(GetProcessHeap(), 0, mask); - if (len) - { - FIXME("Couldn't compile %s\n", mask); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - return TRUE; -} - -/****************************************************************** - * SymEnumLines (DBGHELP.@) - * - */ -BOOL WINAPI SymEnumLines(HANDLE hProcess, ULONG64 base, PCSTR compiland, - PCSTR srcfile, PSYM_ENUMLINES_CALLBACK cb, PVOID user) -{ - struct module_pair pair; - struct hash_table_iter hti; - struct symt_ht* sym; - regex_t re; - struct line_info* dli; - void* ptr; - SRCCODEINFO sci; - const char* file; - - if (!cb) return FALSE; - if (!(dbghelp_options & SYMOPT_LOAD_LINES)) return TRUE; - - pair.pcs = process_find_by_handle(hProcess); - if (!pair.pcs) return FALSE; - if (compiland) FIXME("Unsupported yet (filtering on compiland %s)\n", compiland); - pair.requested = module_find_by_addr(pair.pcs, base, DMT_UNKNOWN); - if (!module_get_debug(&pair)) return FALSE; - if (!compile_regex(&re, srcfile)) return FALSE; - - sci.SizeOfStruct = sizeof(sci); - sci.ModBase = base; - - hash_table_iter_init(&pair.effective->ht_symbols, &hti, NULL); - while ((ptr = hash_table_iter_up(&hti))) - { - unsigned int i; - - sym = GET_ENTRY(ptr, struct symt_ht, hash_elt); - if (sym->symt.tag != SymTagFunction) continue; - - sci.FileName[0] = '\0'; - for (i=0; ivlines); i++) - { - dli = vector_at(&((struct symt_function*)sym)->vlines, i); - if (dli->is_source_file) - { - file = source_get(pair.effective, dli->u.source_file); - if (regexec(&re, file, 0, NULL, 0) != 0) file = ""; - strcpy(sci.FileName, file); - } - else if (sci.FileName[0]) - { - sci.Key = dli; - sci.Obj[0] = '\0'; /* FIXME */ - sci.LineNumber = dli->line_number; - sci.Address = dli->u.pc_offset; - if (!cb(&sci, user)) break; - } - } - } - regfree(&re); - return TRUE; -} - /****************************************************************** * SymGetSourceFileToken (DBGHELP.@) * diff --git a/dll/win32/dbghelp/stabs.c b/dll/win32/dbghelp/stabs.c index a7f0fefae8c..367b04c72dd 100644 --- a/dll/win32/dbghelp/stabs.c +++ b/dll/win32/dbghelp/stabs.c @@ -26,7 +26,7 @@ * The "stabs" debug format * by Julia Menapace, Jim Kingdon, David Mackenzie * of Cygnus Support - * available (hopefully) from http:\\sources.redhat.com\gdb\onlinedocs + * available (hopefully) from http://sources.redhat.com/gdb/onlinedocs */ #include "config.h" @@ -53,6 +53,10 @@ #include #include +#ifdef HAVE_MACH_O_NLIST_H +# include +#endif + #include "windef.h" #include "winbase.h" #include "winnls.h" @@ -65,9 +69,24 @@ WINE_DEFAULT_DEBUG_CHANNEL(dbghelp_stabs); #define strtoull _strtoui64 +/* Masks for n_type field */ +#ifndef N_STAB +#define N_STAB 0xe0 +#endif +#ifndef N_TYPE +#define N_TYPE 0x1e +#endif +#ifndef N_EXT +#define N_EXT 0x01 +#endif + +/* Values for (n_type & N_TYPE) */ #ifndef N_UNDF #define N_UNDF 0x00 #endif +#ifndef N_ABS +#define N_ABS 0x02 +#endif #define N_GSYM 0x20 #define N_FUN 0x24 @@ -81,6 +100,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(dbghelp_stabs); #define N_SLINE 0x44 #define N_ENSYM 0x4e #define N_SO 0x64 +#define N_OSO 0x66 #define N_LSYM 0x80 #define N_BINCL 0x82 #define N_SOL 0x84 @@ -162,14 +182,18 @@ static int stabs_new_include(const char* file, unsigned long val) { if (num_include_def == num_alloc_include_def) { - num_alloc_include_def += 256; if (!include_defs) - include_defs = HeapAlloc(GetProcessHeap(), 0, + { + num_alloc_include_def = 256; + include_defs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(include_defs[0]) * num_alloc_include_def); + } else - include_defs = HeapReAlloc(GetProcessHeap(), 0, include_defs, + { + num_alloc_include_def *= 2; + include_defs = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, include_defs, sizeof(include_defs[0]) * num_alloc_include_def); - memset(include_defs + num_include_def, 0, sizeof(include_defs[0]) * 256); + } } include_defs[num_include_def].name = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(file) + 1), file); include_defs[num_include_def].value = val; @@ -244,13 +268,13 @@ static struct symt** stabs_find_ref(long filenr, long subnr) { if (cu_nrofentries <= subnr) { + cu_nrofentries = max( cu_nrofentries * 2, subnr + 1 ); if (!cu_vector) - cu_vector = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(cu_vector[0]) * (subnr+1)); + cu_vector = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(cu_vector[0]) * cu_nrofentries); else - cu_vector = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - cu_vector, sizeof(cu_vector[0]) * (subnr+1)); - cu_nrofentries = subnr + 1; + cu_vector = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + cu_vector, sizeof(cu_vector[0]) * cu_nrofentries); } ret = &cu_vector[subnr]; } @@ -263,13 +287,13 @@ static struct symt** stabs_find_ref(long filenr, long subnr) if (idef->nrofentries <= subnr) { + idef->nrofentries = max( idef->nrofentries * 2, subnr + 1 ); if (!idef->vector) - idef->vector = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(idef->vector[0]) * (subnr+1)); + idef->vector = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(idef->vector[0]) * idef->nrofentries); else - idef->vector = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - idef->vector, sizeof(idef->vector[0]) * (subnr+1)); - idef->nrofentries = subnr + 1; + idef->vector = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + idef->vector, sizeof(idef->vector[0]) * idef->nrofentries); } ret = &idef->vector[subnr]; } @@ -630,25 +654,21 @@ static inline int stabs_pts_read_aggregate(struct ParseTypedefData* ptd, PTS_ABORTIF(ptd, stabs_pts_read_type_def(ptd, NULL, &adt) == -1); - if (doadd) + if (doadd && adt) { char tmp[256]; - WCHAR* name; DWORD64 size; - symt_get_info(adt, TI_GET_SYMNAME, &name); strcpy(tmp, "__inherited_class_"); - WideCharToMultiByte(CP_ACP, 0, name, -1, - tmp + strlen(tmp), sizeof(tmp) - strlen(tmp), - NULL, NULL); - HeapFree(GetProcessHeap(), 0, name); + strcat(tmp, symt_get_name(adt)); + /* FIXME: TI_GET_LENGTH will not always work, especially when adt * has just been seen as a forward definition and not the real stuff * yet. * As we don't use much the size of members in structs, this may not * be much of a problem */ - symt_get_info(adt, TI_GET_LENGTH, &size); + symt_get_info(ptd->module, adt, TI_GET_LENGTH, &size); symt_add_udt_element(ptd->module, sdt, tmp, adt, ofs, (DWORD)size * 8); } PTS_ABORTIF(ptd, *ptd->ptr++ != ';'); @@ -1094,6 +1114,12 @@ static struct symt* stabs_parse_type(const char* stab) return *stabs_read_type_enum(&c); } +enum pending_obj_kind +{ + PENDING_VAR, + PENDING_LINE, +}; + struct pending_loc_var { char name[256]; @@ -1102,44 +1128,99 @@ struct pending_loc_var struct location loc; }; -struct pending_block +struct pending_line { - struct pending_loc_var* vars; + int source_idx; + int line_num; + unsigned long offset; + unsigned long load_offset; +}; + +struct pending_object +{ + enum pending_obj_kind tag; + union { + struct pending_loc_var var; + struct pending_line line; + } u; +}; + +struct pending_list +{ + struct pending_object* objs; unsigned num; unsigned allocated; }; -static inline void pending_add(struct pending_block* pending, const char* name, - enum DataKind dt, const struct location* loc) +static inline void pending_make_room(struct pending_list* pending) { if (pending->num == pending->allocated) { - pending->allocated += 8; - if (!pending->vars) - pending->vars = HeapAlloc(GetProcessHeap(), 0, - pending->allocated * sizeof(pending->vars[0])); - else - pending->vars = HeapReAlloc(GetProcessHeap(), 0, pending->vars, - pending->allocated * sizeof(pending->vars[0])); + if (!pending->objs) + { + pending->allocated = 8; + pending->objs = HeapAlloc(GetProcessHeap(), 0, + pending->allocated * sizeof(pending->objs[0])); + } + else + { + pending->allocated *= 2; + pending->objs = HeapReAlloc(GetProcessHeap(), 0, pending->objs, + pending->allocated * sizeof(pending->objs[0])); + } } - stab_strcpy(pending->vars[pending->num].name, - sizeof(pending->vars[pending->num].name), name); - pending->vars[pending->num].type = stabs_parse_type(name); - pending->vars[pending->num].kind = dt; - pending->vars[pending->num].loc = *loc; +} + +static inline void pending_add_var(struct pending_list* pending, const char* name, + enum DataKind dt, const struct location* loc) +{ + pending_make_room(pending); + pending->objs[pending->num].tag = PENDING_VAR; + stab_strcpy(pending->objs[pending->num].u.var.name, + sizeof(pending->objs[pending->num].u.var.name), name); + pending->objs[pending->num].u.var.type = stabs_parse_type(name); + pending->objs[pending->num].u.var.kind = dt; + pending->objs[pending->num].u.var.loc = *loc; pending->num++; } -static void pending_flush(struct pending_block* pending, struct module* module, +static inline void pending_add_line(struct pending_list* pending, int source_idx, + int line_num, unsigned long offset, + unsigned long load_offset) +{ + pending_make_room(pending); + pending->objs[pending->num].tag = PENDING_LINE; + pending->objs[pending->num].u.line.source_idx = source_idx; + pending->objs[pending->num].u.line.line_num = line_num; + pending->objs[pending->num].u.line.offset = offset; + pending->objs[pending->num].u.line.load_offset = load_offset; + pending->num++; +} + +static void pending_flush(struct pending_list* pending, struct module* module, struct symt_function* func, struct symt_block* block) { unsigned int i; for (i = 0; i < pending->num; i++) { - symt_add_func_local(module, func, - pending->vars[i].kind, &pending->vars[i].loc, - block, pending->vars[i].type, pending->vars[i].name); + switch (pending->objs[i].tag) + { + case PENDING_VAR: + symt_add_func_local(module, func, + pending->objs[i].u.var.kind, &pending->objs[i].u.var.loc, + block, pending->objs[i].u.var.type, pending->objs[i].u.var.name); + break; + case PENDING_LINE: + if (module->type == DMT_MACHO) + pending->objs[i].u.line.offset -= func->address - pending->objs[i].u.line.load_offset; + symt_add_func_line(module, func, pending->objs[i].u.line.source_idx, + pending->objs[i].u.line.line_num, pending->objs[i].u.line.offset); + break; + default: + ERR("Unknown pending object tag %u\n", (unsigned)pending->objs[i].tag); + break; + } } pending->num = 0; } @@ -1156,7 +1237,7 @@ static void pending_flush(struct pending_block* pending, struct module* module, static void stabs_finalize_function(struct module* module, struct symt_function* func, unsigned long size) { - IMAGEHLP_LINE il; + IMAGEHLP_LINE64 il; struct location loc; if (!func) return; @@ -1175,9 +1256,25 @@ static void stabs_finalize_function(struct module* module, struct symt_function* if (size) func->size = size; } +static inline void stabbuf_append(char **buf, unsigned *buf_size, const char *str) +{ + unsigned str_len, buf_len; + + str_len = strlen(str); + buf_len = strlen(*buf); + + if(str_len+buf_len >= *buf_size) { + *buf_size += buf_len + str_len; + *buf = HeapReAlloc(GetProcessHeap(), 0, *buf, *buf_size); + } + + strcpy(*buf+buf_len, str); +} + BOOL stabs_parse(struct module* module, unsigned long load_offset, const void* pv_stab_ptr, int stablen, - const char* strs, int strtablen) + const char* strs, int strtablen, + stabs_def_cb callback, void* user) { struct symt_function* curr_func = NULL; struct symt_block* block = NULL; @@ -1195,16 +1292,19 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset, unsigned incl[32]; int incl_stk = -1; int source_idx = -1; - struct pending_block pending; + struct pending_list pending_block; + struct pending_list pending_func; BOOL ret = TRUE; struct location loc; + unsigned char type; nstab = stablen / sizeof(struct stab_nlist); strs_end = strs + strtablen; memset(srcpath, 0, sizeof(srcpath)); memset(stabs_basic, 0, sizeof(stabs_basic)); - memset(&pending, 0, sizeof(pending)); + memset(&pending_block, 0, sizeof(pending_block)); + memset(&pending_func, 0, sizeof(pending_func)); /* * Allocate a buffer into which we can build stab strings for cases @@ -1230,23 +1330,22 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset, * next record. Repeat the process until we find a stab without the * '/' character, as this indicates we have the whole thing. */ - unsigned len = strlen(ptr); - if (strlen(stabbuff) + len > stabbufflen) - { - stabbufflen += 65536; - stabbuff = HeapReAlloc(GetProcessHeap(), 0, stabbuff, stabbufflen); - } - strncat(stabbuff, ptr, len - 1); + stabbuf_append(&stabbuff, &stabbufflen, ptr); continue; } else if (stabbuff[0] != '\0') { - strcat(stabbuff, ptr); + stabbuf_append(&stabbuff, &stabbufflen, ptr); ptr = stabbuff; } + if (stab_ptr->n_type & N_STAB) + type = stab_ptr->n_type; + else + type = (stab_ptr->n_type & N_TYPE); + /* only symbol entries contain a typedef */ - switch (stab_ptr->n_type) + switch (type) { case N_GSYM: case N_LCSYM: @@ -1263,7 +1362,8 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset, */ if (ptr != stabbuff) { - strcpy(stabbuff, ptr); + stabbuff[0] = 0; + stabbuf_append(&stabbuff, &stabbufflen, ptr); ptr = stabbuff; } stab_strcpy(symname, sizeof(symname), ptr); @@ -1276,7 +1376,7 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset, } } - switch (stab_ptr->n_type) + switch (type) { case N_GSYM: /* @@ -1305,7 +1405,7 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset, { block = symt_open_func_block(module, curr_func, block, stab_ptr->n_value, 0); - pending_flush(&pending, module, curr_func, block); + pending_flush(&pending_block, module, curr_func, block); } break; case N_RBRAC: @@ -1356,6 +1456,22 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset, case 17: case 18: case 19: loc.reg = CV_REG_ST0 + stab_ptr->n_value - 12; break; + case 21: + case 22: + case 23: + case 24: + case 25: + case 26: + case 27: + case 28: loc.reg = CV_REG_XMM0 + stab_ptr->n_value - 21; break; + case 29: + case 30: + case 31: + case 32: + case 33: + case 34: + case 35: + case 36: loc.reg = CV_REG_MM0 + stab_ptr->n_value - 29; break; default: FIXME("Unknown register value (%lu)\n", stab_ptr->n_value); loc.reg = CV_REG_NONE; @@ -1373,7 +1489,7 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset, param_type); } else - pending_add(&pending, ptr, DataIsLocal, &loc); + pending_add_var(&pending_block, ptr, DataIsLocal, &loc); } break; case N_LSYM: @@ -1381,19 +1497,24 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset, loc.kind = loc_regrel; loc.reg = 0; /* FIXME */ loc.offset = stab_ptr->n_value; - if (curr_func != NULL) pending_add(&pending, ptr, DataIsLocal, &loc); + if (curr_func != NULL) pending_add_var(&pending_block, ptr, DataIsLocal, &loc); break; case N_SLINE: /* * This is a line number. These are always relative to the start * of the function (N_FUN), and this makes the lookup easier. */ + assert(source_idx >= 0); if (curr_func != NULL) { - assert(source_idx >= 0); + unsigned long offset = stab_ptr->n_value; + if (module->type == DMT_MACHO) + offset -= curr_func->address - load_offset; symt_add_func_line(module, curr_func, source_idx, - stab_ptr->n_desc, stab_ptr->n_value); + stab_ptr->n_desc, offset); } + else pending_add_line(&pending_func, source_idx, stab_ptr->n_desc, + stab_ptr->n_value, load_offset); break; case N_FUN: /* @@ -1428,6 +1549,7 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset, curr_func = symt_new_function(module, compiland, symname, load_offset + stab_ptr->n_value, 0, &func_type->symt); + pending_flush(&pending_func, module, curr_func, NULL); } else { @@ -1508,10 +1630,38 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset, break; case N_BNSYM: case N_ENSYM: + case N_OSO: /* Always ignore these, they seem to be used only on Darwin. */ break; + case N_ABS: +#ifdef N_SECT + case N_SECT: +#endif + /* FIXME: Other definition types (N_TEXT, N_DATA, N_BSS, ...)? */ + if (callback) + { + BOOL is_public = (stab_ptr->n_type & N_EXT); + BOOL is_global = is_public; + +#ifdef N_PEXT + /* "private extern"; shared among compilation units in a shared + * library, but not accessible from outside the library. */ + if (stab_ptr->n_type & N_PEXT) + { + is_public = FALSE; + is_global = TRUE; + } +#endif + + if (*ptr == '_') ptr++; + stab_strcpy(symname, sizeof(symname), ptr); + + callback(module, load_offset, symname, stab_ptr->n_value, + is_public, is_global, stab_ptr->n_other, compiland, user); + } + break; default: - ERR("Unknown stab type 0x%02x\n", stab_ptr->n_type); + ERR("Unknown stab type 0x%02x\n", type); break; } stabbuff[0] = '\0'; @@ -1529,7 +1679,8 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset, done: HeapFree(GetProcessHeap(), 0, stabbuff); stabs_free_includes(); - HeapFree(GetProcessHeap(), 0, pending.vars); + HeapFree(GetProcessHeap(), 0, pending_block.objs); + HeapFree(GetProcessHeap(), 0, pending_func.objs); return ret; } diff --git a/dll/win32/dbghelp/stack.c b/dll/win32/dbghelp/stack.c index 3c66fcbc04c..d53629e80b4 100644 --- a/dll/win32/dbghelp/stack.c +++ b/dll/win32/dbghelp/stack.c @@ -27,40 +27,45 @@ #include #include -#include "ntstatus.h" -#define WIN32_NO_STATUS #include "dbghelp_private.h" -#include "winternl.h" -#include "wine/winbase16.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(dbghelp); -enum st_mode {stm_start, stm_32bit, stm_16bit, stm_done}; - -static const char* wine_dbgstr_addr(const ADDRESS* addr) +static DWORD64 WINAPI addr_to_linear(HANDLE hProcess, HANDLE hThread, ADDRESS64* addr) { - if (!addr) return "(null)"; + LDT_ENTRY le; + switch (addr->Mode) { - case AddrModeFlat: - return wine_dbg_sprintf("flat<%08x>", addr->Offset); case AddrMode1616: - return wine_dbg_sprintf("1616<%04x:%04x>", addr->Segment, addr->Offset); + if (GetThreadSelectorEntry(hThread, addr->Segment, &le)) + return (le.HighWord.Bits.BaseHi << 24) + + (le.HighWord.Bits.BaseMid << 16) + le.BaseLow + LOWORD(addr->Offset); + break; case AddrMode1632: - return wine_dbg_sprintf("1632<%04x:%08x>", addr->Segment, addr->Offset); + if (GetThreadSelectorEntry(hThread, addr->Segment, &le)) + return (le.HighWord.Bits.BaseHi << 24) + + (le.HighWord.Bits.BaseMid << 16) + le.BaseLow + addr->Offset; + break; case AddrModeReal: - return wine_dbg_sprintf("real<%04x:%04x>", addr->Segment, addr->Offset); + return (DWORD)(LOWORD(addr->Segment) << 4) + addr->Offset; + case AddrModeFlat: + return addr->Offset; default: - return "unknown"; + FIXME("Unsupported (yet) mode (%x)\n", addr->Mode); + return 0; } + FIXME("Failed to linearize address %04x:%s (mode %x)\n", + addr->Segment, wine_dbgstr_longlong(addr->Offset), addr->Mode); + return 0; } static BOOL CALLBACK read_mem(HANDLE hProcess, DWORD addr, void* buffer, DWORD size, LPDWORD nread) { SIZE_T r; - if (!ReadProcessMemory(hProcess, (void*)addr, buffer, size, &r)) return FALSE; + if (!ReadProcessMemory(hProcess, (void*)(DWORD_PTR)addr, buffer, size, &r)) return FALSE; if (nread) *nread = r; return TRUE; } @@ -74,39 +79,6 @@ static BOOL CALLBACK read_mem64(HANDLE hProcess, DWORD64 addr, void* buffer, return TRUE; } -/* indexes in Reserved array */ -#define __CurrentMode 0 -#define __CurrentSwitch 1 -#define __NextSwitch 2 - -#define curr_mode (frame->Reserved[__CurrentMode]) -#define curr_switch (frame->Reserved[__CurrentSwitch]) -#define next_switch (frame->Reserved[__NextSwitch]) - -struct stack_walk_callback -{ - HANDLE hProcess; - HANDLE hThread; - BOOL is32; - union - { - struct - { - PREAD_PROCESS_MEMORY_ROUTINE f_read_mem; - PTRANSLATE_ADDRESS_ROUTINE f_xlat_adr; - PFUNCTION_TABLE_ACCESS_ROUTINE f_tabl_acs; - PGET_MODULE_BASE_ROUTINE f_modl_bas; - } s32; - struct - { - PREAD_PROCESS_MEMORY_ROUTINE64 f_read_mem; - PTRANSLATE_ADDRESS_ROUTINE64 f_xlat_adr; - PFUNCTION_TABLE_ACCESS_ROUTINE64 f_tabl_acs; - PGET_MODULE_BASE_ROUTINE64 f_modl_bas; - } s64; - } u; -}; - static inline void addr_32to64(const ADDRESS* addr32, ADDRESS64* addr64) { addr64->Offset = (ULONG64)addr32->Offset; @@ -121,379 +93,113 @@ static inline void addr_64to32(const ADDRESS64* addr64, ADDRESS* addr32) addr32->Mode = addr64->Mode; } -static inline BOOL sw_read_mem(struct stack_walk_callback* cb, DWORD addr, void* ptr, DWORD sz) +BOOL sw_read_mem(struct cpu_stack_walk* csw, DWORD64 addr, void* ptr, DWORD sz) { - if (cb->is32) - return cb->u.s32.f_read_mem(cb->hProcess, addr, ptr, sz, NULL); + if (csw->is32) + return csw->u.s32.f_read_mem(csw->hProcess, addr, ptr, sz, NULL); else - return cb->u.s64.f_read_mem(cb->hProcess, addr, ptr, sz, NULL); + return csw->u.s64.f_read_mem(csw->hProcess, addr, ptr, sz, NULL); } -static inline DWORD sw_xlat_addr(struct stack_walk_callback* cb, ADDRESS* addr) +DWORD64 sw_xlat_addr(struct cpu_stack_walk* csw, ADDRESS64* addr) { if (addr->Mode == AddrModeFlat) return addr->Offset; - if (cb->is32) return cb->u.s32.f_xlat_adr(cb->hProcess, cb->hThread, addr); - if (cb->u.s64.f_xlat_adr) + if (csw->is32) { - ADDRESS64 addr64; + ADDRESS addr32; - addr_32to64(addr, &addr64); - return cb->u.s64.f_xlat_adr(cb->hProcess, cb->hThread, &addr64); + addr_64to32(addr, &addr32); + return csw->u.s32.f_xlat_adr(csw->hProcess, csw->hThread, &addr32); } - return addr_to_linear(cb->hProcess, cb->hThread, addr); + else if (csw->u.s64.f_xlat_adr) + return csw->u.s64.f_xlat_adr(csw->hProcess, csw->hThread, addr); + return addr_to_linear(csw->hProcess, csw->hThread, addr); } -static inline void* sw_tabl_acs(struct stack_walk_callback* cb, DWORD addr) +void* sw_table_access(struct cpu_stack_walk* csw, DWORD64 addr) { - if (cb->is32) - return cb->u.s32.f_tabl_acs(cb->hProcess, addr); + if (csw->is32) + return csw->u.s32.f_tabl_acs(csw->hProcess, addr); else - return cb->u.s64.f_tabl_acs(cb->hProcess, addr); + return csw->u.s64.f_tabl_acs(csw->hProcess, addr); } -static inline DWORD sw_modl_bas(struct stack_walk_callback* cb, DWORD addr) +DWORD64 sw_module_base(struct cpu_stack_walk* csw, DWORD64 addr) { - if (cb->is32) - return cb->u.s32.f_modl_bas(cb->hProcess, addr); + if (csw->is32) + return csw->u.s32.f_modl_bas(csw->hProcess, addr); else - return cb->u.s64.f_modl_bas(cb->hProcess, addr); -} - -static BOOL stack_walk(struct stack_walk_callback* cb, LPSTACKFRAME frame) -{ - STACK32FRAME frame32; - STACK16FRAME frame16; - char ch; - ADDRESS tmp; - DWORD p; - WORD val; - BOOL do_switch; - - /* sanity check */ - if (curr_mode >= stm_done) return FALSE; - - TRACE("Enter: PC=%s Frame=%s Return=%s Stack=%s Mode=%s cSwitch=%08x nSwitch=%08x\n", - wine_dbgstr_addr(&frame->AddrPC), - wine_dbgstr_addr(&frame->AddrFrame), - wine_dbgstr_addr(&frame->AddrReturn), - wine_dbgstr_addr(&frame->AddrStack), - curr_mode == stm_start ? "start" : (curr_mode == stm_16bit ? "16bit" : "32bit"), - curr_switch, next_switch); - - if (curr_mode == stm_start) - { - THREAD_BASIC_INFORMATION info; - - if ((frame->AddrPC.Mode == AddrModeFlat) && - (frame->AddrFrame.Mode != AddrModeFlat)) - { - WARN("Bad AddrPC.Mode / AddrFrame.Mode combination\n"); - goto done_err; - } - - /* Init done */ - curr_mode = (frame->AddrPC.Mode == AddrModeFlat) ? - stm_32bit : stm_16bit; - - /* cur_switch holds address of WOW32Reserved field in TEB in debuggee - * address space - */ - if (NtQueryInformationThread(cb->hThread, ThreadBasicInformation, &info, - sizeof(info), NULL) == STATUS_SUCCESS) - { - curr_switch = (unsigned long)info.TebBaseAddress + FIELD_OFFSET(TEB, WOW32Reserved); - if (!sw_read_mem(cb, curr_switch, &next_switch, sizeof(next_switch))) - { - WARN("Can't read TEB:WOW32Reserved\n"); - goto done_err; - } - if (curr_mode == stm_16bit) - { - if (!sw_read_mem(cb, next_switch, &frame32, sizeof(frame32))) - { - WARN("Bad stack frame 0x%08x\n", next_switch); - goto done_err; - } - curr_switch = (DWORD)frame32.frame16; - tmp.Mode = AddrMode1616; - tmp.Segment = SELECTOROF(curr_switch); - tmp.Offset = OFFSETOF(curr_switch); - if (!sw_read_mem(cb, sw_xlat_addr(cb, &tmp), &ch, sizeof(ch))) - curr_switch = 0xFFFFFFFF; - } - else - { - tmp.Mode = AddrMode1616; - tmp.Segment = SELECTOROF(next_switch); - tmp.Offset = OFFSETOF(next_switch); - p = sw_xlat_addr(cb, &tmp); - if (!sw_read_mem(cb, p, &frame16, sizeof(frame16))) - { - WARN("Bad stack frame 0x%08x\n", p); - goto done_err; - } - curr_switch = (DWORD)frame16.frame32; - - if (!sw_read_mem(cb, curr_switch, &ch, sizeof(ch))) - curr_switch = 0xFFFFFFFF; - } - } - else - /* FIXME: this will allow to work when we're not attached to a live target, - * but the 16 <=> 32 switch facility won't be available. - */ - curr_switch = 0; - frame->AddrReturn.Mode = frame->AddrStack.Mode = (curr_mode == stm_16bit) ? AddrMode1616 : AddrModeFlat; - /* don't set up AddrStack on first call. Either the caller has set it up, or - * we will get it in the next frame - */ - memset(&frame->AddrBStore, 0, sizeof(frame->AddrBStore)); - } - else - { - if (frame->AddrFrame.Offset == 0) goto done_err; - if (frame->AddrFrame.Mode == AddrModeFlat) - { - assert(curr_mode == stm_32bit); - do_switch = curr_switch && frame->AddrFrame.Offset >= curr_switch; - } - else - { - assert(curr_mode == stm_16bit); - do_switch = curr_switch && - frame->AddrFrame.Segment == SELECTOROF(curr_switch) && - frame->AddrFrame.Offset >= OFFSETOF(curr_switch); - } - - if (do_switch) - { - if (curr_mode == stm_16bit) - { - if (!sw_read_mem(cb, next_switch, &frame32, sizeof(frame32))) - { - WARN("Bad stack frame 0x%08x\n", next_switch); - goto done_err; - } - - frame->AddrPC.Mode = AddrModeFlat; - frame->AddrPC.Segment = 0; - frame->AddrPC.Offset = frame32.retaddr; - frame->AddrFrame.Mode = AddrModeFlat; - frame->AddrFrame.Segment = 0; - frame->AddrFrame.Offset = frame32.ebp; - - frame->AddrStack.Mode = AddrModeFlat; - frame->AddrStack.Segment = 0; - frame->AddrReturn.Mode = AddrModeFlat; - frame->AddrReturn.Segment = 0; - - next_switch = curr_switch; - tmp.Mode = AddrMode1616; - tmp.Segment = SELECTOROF(next_switch); - tmp.Offset = OFFSETOF(next_switch); - p = sw_xlat_addr(cb, &tmp); - - if (!sw_read_mem(cb, p, &frame16, sizeof(frame16))) - { - WARN("Bad stack frame 0x%08x\n", p); - goto done_err; - } - curr_switch = (DWORD)frame16.frame32; - curr_mode = stm_32bit; - if (!sw_read_mem(cb, curr_switch, &ch, sizeof(ch))) - curr_switch = 0; - } - else - { - tmp.Mode = AddrMode1616; - tmp.Segment = SELECTOROF(next_switch); - tmp.Offset = OFFSETOF(next_switch); - p = sw_xlat_addr(cb, &tmp); - - if (!sw_read_mem(cb, p, &frame16, sizeof(frame16))) - { - WARN("Bad stack frame 0x%08x\n", p); - goto done_err; - } - - TRACE("Got a 16 bit stack switch:" - "\n\tframe32: %08lx" - "\n\tedx:%08x ecx:%08x ebp:%08x" - "\n\tds:%04x es:%04x fs:%04x gs:%04x" - "\n\tcall_from_ip:%08x module_cs:%04x relay=%08x" - "\n\tentry_ip:%04x entry_point:%08x" - "\n\tbp:%04x ip:%04x cs:%04x\n", - (unsigned long)frame16.frame32, - frame16.edx, frame16.ecx, frame16.ebp, - frame16.ds, frame16.es, frame16.fs, frame16.gs, - frame16.callfrom_ip, frame16.module_cs, frame16.relay, - frame16.entry_ip, frame16.entry_point, - frame16.bp, frame16.ip, frame16.cs); - - - frame->AddrPC.Mode = AddrMode1616; - frame->AddrPC.Segment = frame16.cs; - frame->AddrPC.Offset = frame16.ip; - - frame->AddrFrame.Mode = AddrMode1616; - frame->AddrFrame.Segment = SELECTOROF(next_switch); - frame->AddrFrame.Offset = frame16.bp; - - frame->AddrStack.Mode = AddrMode1616; - frame->AddrStack.Segment = SELECTOROF(next_switch); - - frame->AddrReturn.Mode = AddrMode1616; - frame->AddrReturn.Segment = frame16.cs; - - next_switch = curr_switch; - if (!sw_read_mem(cb, next_switch, &frame32, sizeof(frame32))) - { - WARN("Bad stack frame 0x%08x\n", next_switch); - goto done_err; - } - curr_switch = (DWORD)frame32.frame16; - tmp.Mode = AddrMode1616; - tmp.Segment = SELECTOROF(curr_switch); - tmp.Offset = OFFSETOF(curr_switch); - - if (!sw_read_mem(cb, sw_xlat_addr(cb, &tmp), &ch, sizeof(ch))) - curr_switch = 0; - curr_mode = stm_16bit; - } - } - else - { - frame->AddrPC = frame->AddrReturn; - if (curr_mode == stm_16bit) - { - frame->AddrStack.Offset = frame->AddrFrame.Offset + 2 * sizeof(WORD); - /* "pop up" previous BP value */ - if (!sw_read_mem(cb, sw_xlat_addr(cb, &frame->AddrFrame), - &val, sizeof(WORD))) - goto done_err; - frame->AddrFrame.Offset = val; - } - else - { - frame->AddrStack.Offset = frame->AddrFrame.Offset + 2 * sizeof(DWORD); - /* "pop up" previous EBP value */ - if (!sw_read_mem(cb, frame->AddrFrame.Offset, - &frame->AddrFrame.Offset, sizeof(DWORD))) - goto done_err; - } - } - } - - if (curr_mode == stm_16bit) - { - unsigned int i; - - p = sw_xlat_addr(cb, &frame->AddrFrame); - if (!sw_read_mem(cb, p + sizeof(WORD), &val, sizeof(WORD))) - goto done_err; - frame->AddrReturn.Offset = val; - /* get potential cs if a far call was used */ - if (!sw_read_mem(cb, p + 2 * sizeof(WORD), &val, sizeof(WORD))) - goto done_err; - if (frame->AddrFrame.Offset & 1) - frame->AddrReturn.Segment = val; /* far call assumed */ - else - { - /* not explicitly marked as far call, - * but check whether it could be anyway - */ - if ((val & 7) == 7 && val != frame->AddrReturn.Segment) - { - LDT_ENTRY le; - - if (GetThreadSelectorEntry(cb->hThread, val, &le) && - (le.HighWord.Bits.Type & 0x08)) /* code segment */ - { - /* it is very uncommon to push a code segment cs as - * a parameter, so this should work in most cases - */ - frame->AddrReturn.Segment = val; - } - } - } - frame->AddrFrame.Offset &= ~1; - /* we "pop" parameters as 16 bit entities... of course, this won't - * work if the parameter is in fact bigger than 16bit, but - * there's no way to know that here - */ - for (i = 0; i < sizeof(frame->Params) / sizeof(frame->Params[0]); i++) - { - sw_read_mem(cb, p + (2 + i) * sizeof(WORD), &val, sizeof(val)); - frame->Params[i] = val; - } - } - else - { - if (!sw_read_mem(cb, frame->AddrFrame.Offset + sizeof(DWORD), - &frame->AddrReturn.Offset, sizeof(DWORD))) - { - WARN("Cannot read new frame offset %08x\n", frame->AddrFrame.Offset + (int)sizeof(DWORD)); - goto done_err; - } - sw_read_mem(cb, frame->AddrFrame.Offset + 2 * sizeof(DWORD), - frame->Params, sizeof(frame->Params)); - } - - frame->Far = TRUE; - frame->Virtual = TRUE; - p = sw_xlat_addr(cb, &frame->AddrPC); - if (p && sw_modl_bas(cb, p)) - frame->FuncTableEntry = sw_tabl_acs(cb, p); - else - frame->FuncTableEntry = NULL; - - TRACE("Leave: PC=%s Frame=%s Return=%s Stack=%s Mode=%s cSwitch=%08x nSwitch=%08x FuncTable=%p\n", - wine_dbgstr_addr(&frame->AddrPC), - wine_dbgstr_addr(&frame->AddrFrame), - wine_dbgstr_addr(&frame->AddrReturn), - wine_dbgstr_addr(&frame->AddrStack), - curr_mode == stm_start ? "start" : (curr_mode == stm_16bit ? "16bit" : "32bit"), - curr_switch, next_switch, frame->FuncTableEntry); - - return TRUE; -done_err: - curr_mode = stm_done; - return FALSE; + return csw->u.s64.f_modl_bas(csw->hProcess, addr); } /*********************************************************************** * StackWalk (DBGHELP.@) */ BOOL WINAPI StackWalk(DWORD MachineType, HANDLE hProcess, HANDLE hThread, - LPSTACKFRAME frame, PVOID ctx, + LPSTACKFRAME frame32, PVOID ctx, PREAD_PROCESS_MEMORY_ROUTINE f_read_mem, PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine, PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine, PTRANSLATE_ADDRESS_ROUTINE f_xlat_adr) { - struct stack_walk_callback swcb; + struct cpu_stack_walk csw; + STACKFRAME64 frame64; + BOOL ret; + struct cpu* cpu; TRACE("(%d, %p, %p, %p, %p, %p, %p, %p, %p)\n", - MachineType, hProcess, hThread, frame, ctx, + MachineType, hProcess, hThread, frame32, ctx, f_read_mem, FunctionTableAccessRoutine, GetModuleBaseRoutine, f_xlat_adr); - if (MachineType != IMAGE_FILE_MACHINE_I386) + if (!(cpu = cpu_find(MachineType))) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } - swcb.hProcess = hProcess; - swcb.hThread = hThread; - swcb.is32 = TRUE; - /* sigh... MS isn't even consistent in the func prototypes */ - swcb.u.s32.f_read_mem = (f_read_mem) ? f_read_mem : read_mem; - swcb.u.s32.f_xlat_adr = (f_xlat_adr) ? f_xlat_adr : addr_to_linear; - swcb.u.s32.f_tabl_acs = (FunctionTableAccessRoutine) ? FunctionTableAccessRoutine : SymFunctionTableAccess; - swcb.u.s32.f_modl_bas = (GetModuleBaseRoutine) ? GetModuleBaseRoutine : SymGetModuleBase; + addr_32to64(&frame32->AddrPC, &frame64.AddrPC); + addr_32to64(&frame32->AddrReturn, &frame64.AddrReturn); + addr_32to64(&frame32->AddrFrame, &frame64.AddrFrame); + addr_32to64(&frame32->AddrStack, &frame64.AddrStack); + addr_32to64(&frame32->AddrBStore, &frame64.AddrBStore); + frame64.FuncTableEntry = frame32->FuncTableEntry; /* FIXME */ + frame64.Far = frame32->Far; + frame64.Virtual = frame32->Virtual; + frame64.Reserved[0] = frame32->Reserved[0]; + frame64.Reserved[1] = frame32->Reserved[1]; + frame64.Reserved[2] = frame32->Reserved[2]; + /* we don't handle KdHelp */ - return stack_walk(&swcb, frame); + csw.hProcess = hProcess; + csw.hThread = hThread; + csw.is32 = TRUE; + /* sigh... MS isn't even consistent in the func prototypes */ + csw.u.s32.f_read_mem = (f_read_mem) ? f_read_mem : read_mem; + csw.u.s32.f_xlat_adr = f_xlat_adr; + csw.u.s32.f_tabl_acs = (FunctionTableAccessRoutine) ? FunctionTableAccessRoutine : SymFunctionTableAccess; + csw.u.s32.f_modl_bas = (GetModuleBaseRoutine) ? GetModuleBaseRoutine : SymGetModuleBase; + + if ((ret = cpu->stack_walk(&csw, &frame64))) + { + addr_64to32(&frame64.AddrPC, &frame32->AddrPC); + addr_64to32(&frame64.AddrReturn, &frame32->AddrReturn); + addr_64to32(&frame64.AddrFrame, &frame32->AddrFrame); + addr_64to32(&frame64.AddrStack, &frame32->AddrStack); + addr_64to32(&frame64.AddrBStore, &frame32->AddrBStore); + frame32->FuncTableEntry = frame64.FuncTableEntry; /* FIXME */ + frame32->Params[0] = frame64.Params[0]; + frame32->Params[1] = frame64.Params[1]; + frame32->Params[2] = frame64.Params[2]; + frame32->Params[3] = frame64.Params[3]; + frame32->Far = frame64.Far; + frame32->Virtual = frame64.Virtual; + frame32->Reserved[0] = frame64.Reserved[0]; + frame32->Reserved[1] = frame64.Reserved[1]; + frame32->Reserved[2] = frame64.Reserved[2]; + } + + return ret; } @@ -501,78 +207,49 @@ BOOL WINAPI StackWalk(DWORD MachineType, HANDLE hProcess, HANDLE hThread, * StackWalk64 (DBGHELP.@) */ BOOL WINAPI StackWalk64(DWORD MachineType, HANDLE hProcess, HANDLE hThread, - LPSTACKFRAME64 frame64, PVOID ctx, + LPSTACKFRAME64 frame, PVOID ctx, PREAD_PROCESS_MEMORY_ROUTINE64 f_read_mem, PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, PTRANSLATE_ADDRESS_ROUTINE64 f_xlat_adr) { - struct stack_walk_callback swcb; - STACKFRAME frame32; - BOOL ret; + struct cpu_stack_walk csw; + struct cpu* cpu; TRACE("(%d, %p, %p, %p, %p, %p, %p, %p, %p)\n", - MachineType, hProcess, hThread, frame64, ctx, + MachineType, hProcess, hThread, frame, ctx, f_read_mem, FunctionTableAccessRoutine, GetModuleBaseRoutine, f_xlat_adr); - if (MachineType != IMAGE_FILE_MACHINE_I386) + if (!(cpu = cpu_find(MachineType))) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } - addr_64to32(&frame64->AddrPC, &frame32.AddrPC); - addr_64to32(&frame64->AddrReturn, &frame32.AddrReturn); - addr_64to32(&frame64->AddrFrame, &frame32.AddrFrame); - addr_64to32(&frame64->AddrStack, &frame32.AddrStack); - addr_64to32(&frame64->AddrBStore, &frame32.AddrBStore); - frame32.FuncTableEntry = frame64->FuncTableEntry; /* FIXME */ - frame32.Far = frame64->Far; - frame32.Virtual = frame64->Virtual; - frame32.Reserved[0] = (ULONG)frame64->Reserved[0]; - frame32.Reserved[1] = (ULONG)frame64->Reserved[1]; - frame32.Reserved[2] = (ULONG)frame64->Reserved[2]; - /* we don't handle KdHelp */ - - swcb.hProcess = hProcess; - swcb.hThread = hThread; - swcb.is32 = FALSE; + csw.hProcess = hProcess; + csw.hThread = hThread; + csw.is32 = FALSE; /* sigh... MS isn't even consistent in the func prototypes */ - swcb.u.s64.f_read_mem = (f_read_mem) ? f_read_mem : read_mem64; - swcb.u.s64.f_xlat_adr = f_xlat_adr; - swcb.u.s64.f_tabl_acs = (FunctionTableAccessRoutine) ? FunctionTableAccessRoutine : SymFunctionTableAccess64; - swcb.u.s64.f_modl_bas = (GetModuleBaseRoutine) ? GetModuleBaseRoutine : SymGetModuleBase64; + csw.u.s64.f_read_mem = (f_read_mem) ? f_read_mem : read_mem64; + csw.u.s64.f_xlat_adr = (f_xlat_adr) ? f_xlat_adr : addr_to_linear; + csw.u.s64.f_tabl_acs = (FunctionTableAccessRoutine) ? FunctionTableAccessRoutine : SymFunctionTableAccess64; + csw.u.s64.f_modl_bas = (GetModuleBaseRoutine) ? GetModuleBaseRoutine : SymGetModuleBase64; - ret = stack_walk(&swcb, &frame32); + if (!cpu->stack_walk(&csw, frame)) return FALSE; - addr_32to64(&frame32.AddrPC, &frame64->AddrPC); - addr_32to64(&frame32.AddrReturn, &frame64->AddrReturn); - addr_32to64(&frame32.AddrFrame, &frame64->AddrFrame); - addr_32to64(&frame32.AddrStack, &frame64->AddrStack); - addr_32to64(&frame32.AddrBStore, &frame64->AddrBStore); - frame64->FuncTableEntry = frame32.FuncTableEntry; /* FIXME */ - frame64->Params[0] = frame32.Params[0]; - frame64->Params[1] = frame32.Params[1]; - frame64->Params[2] = frame32.Params[2]; - frame64->Params[3] = frame32.Params[3]; - frame64->Far = frame32.Far; - frame64->Virtual = frame32.Virtual; - frame64->Reserved[0] = frame32.Reserved[0]; - frame64->Reserved[1] = frame32.Reserved[1]; - frame64->Reserved[2] = frame32.Reserved[2]; /* we don't handle KdHelp */ - frame64->KdHelp.Thread = 0xC000FADE; - frame64->KdHelp.ThCallbackStack = 0x10; - frame64->KdHelp.ThCallbackBStore = 0; - frame64->KdHelp.NextCallback = 0; - frame64->KdHelp.FramePointer = 0; - frame64->KdHelp.KiCallUserMode = 0xD000DAFE; - frame64->KdHelp.KeUserCallbackDispatcher = 0xE000F000; - frame64->KdHelp.SystemRangeStart = 0xC0000000; - frame64->KdHelp.Reserved[0] /* KiUserExceptionDispatcher */ = 0xE0005000; + frame->KdHelp.Thread = 0xC000FADE; + frame->KdHelp.ThCallbackStack = 0x10; + frame->KdHelp.ThCallbackBStore = 0; + frame->KdHelp.NextCallback = 0; + frame->KdHelp.FramePointer = 0; + frame->KdHelp.KiCallUserMode = 0xD000DAFE; + frame->KdHelp.KeUserCallbackDispatcher = 0xE000F000; + frame->KdHelp.SystemRangeStart = 0xC0000000; + frame->KdHelp.Reserved[0] /* KiUserExceptionDispatcher */ = 0xE0005000; - return ret; + return TRUE; } /****************************************************************** diff --git a/dll/win32/dbghelp/storage.c b/dll/win32/dbghelp/storage.c index baca0530b34..c7f06cc11bd 100644 --- a/dll/win32/dbghelp/storage.c +++ b/dll/win32/dbghelp/storage.c @@ -34,14 +34,16 @@ WINE_DEFAULT_DEBUG_CHANNEL(dbghelp); struct pool_arena { - struct pool_arena* next; - char* current; + struct list entry; + char *current; + char *end; }; -void pool_init(struct pool* a, unsigned arena_size) +void pool_init(struct pool* a, size_t arena_size) { + list_init( &a->arena_list ); + list_init( &a->arena_full ); a->arena_size = arena_size; - a->first = NULL; } void pool_destroy(struct pool* pool) @@ -50,58 +52,73 @@ void pool_destroy(struct pool* pool) struct pool_arena* next; #ifdef USE_STATS - unsigned alloc, used, num; - + size_t alloc, used, num; + alloc = used = num = 0; - arena = pool->first; - while (arena) + LIST_FOR_EACH_ENTRY( arena, &pool->arena_list, struct pool_arena, entry ) { - alloc += pool->arena_size; + alloc += arena->end - (char *)arena; + used += arena->current - (char*)arena; + num++; + } + LIST_FOR_EACH_ENTRY( arena, &pool->arena_full, struct pool_arena, entry ) + { + alloc += arena->end - (char *)arena; used += arena->current - (char*)arena; num++; - arena = arena->next; } if (alloc == 0) alloc = 1; /* avoid division by zero */ - FIXME("STATS: pool %p has allocated %u kbytes, used %u kbytes in %u arenas,\n" - "\t\t\t\tnon-allocation ratio: %.2f%%\n", - pool, alloc >> 10, used >> 10, num, 100.0 - (float)used / (float)alloc * 100.0); + FIXME("STATS: pool %p has allocated %u kbytes, used %u kbytes in %u arenas, non-allocation ratio: %.2f%%\n", + pool, (unsigned)(alloc >> 10), (unsigned)(used >> 10), (unsigned)num, + 100.0 - (float)used / (float)alloc * 100.0); #endif - arena = pool->first; - while (arena) + LIST_FOR_EACH_ENTRY_SAFE( arena, next, &pool->arena_list, struct pool_arena, entry ) { - next = arena->next; + list_remove( &arena->entry ); + HeapFree(GetProcessHeap(), 0, arena); + } + LIST_FOR_EACH_ENTRY_SAFE( arena, next, &pool->arena_full, struct pool_arena, entry ) + { + list_remove( &arena->entry ); HeapFree(GetProcessHeap(), 0, arena); - arena = next; } - pool_init(pool, 0); } -void* pool_alloc(struct pool* pool, unsigned len) +void* pool_alloc(struct pool* pool, size_t len) { struct pool_arena* arena; void* ret; + size_t size; len = (len + 3) & ~3; /* round up size on DWORD boundary */ - assert(sizeof(struct pool_arena) + len <= pool->arena_size && len); - for (arena = pool->first; arena; arena = arena->next) + LIST_FOR_EACH_ENTRY( arena, &pool->arena_list, struct pool_arena, entry ) { - if ((char*)arena + pool->arena_size - arena->current >= len) + if (arena->end - arena->current >= len) { ret = arena->current; arena->current += len; + if (arena->current + 16 >= arena->end) + { + list_remove( &arena->entry ); + list_add_tail( &pool->arena_full, &arena->entry ); + } return ret; } } - arena = HeapAlloc(GetProcessHeap(), 0, pool->arena_size); - if (!arena) {ERR("OOM\n");return NULL;} + size = max( pool->arena_size, len ); + arena = HeapAlloc(GetProcessHeap(), 0, size + sizeof(struct pool_arena)); + if (!arena) return NULL; - ret = (char*)arena + sizeof(*arena); - arena->next = pool->first; - pool->first = arena; + ret = arena + 1; arena->current = (char*)ret + len; + arena->end = (char*)ret + size; + if (arena->current + 16 >= arena->end) + list_add_tail( &pool->arena_full, &arena->entry ); + else + list_add_head( &pool->arena_list, &arena->entry ); return ret; } @@ -298,7 +315,7 @@ unsigned sparse_array_length(const struct sparse_array* sa) return sa->elements.num_elts; } -unsigned hash_table_hash(const char* name, unsigned num_buckets) +static unsigned hash_table_hash(const char* name, unsigned num_buckets) { unsigned hash = 0; while (*name) diff --git a/dll/win32/dbghelp/symbol.c b/dll/win32/dbghelp/symbol.c index 280666d0694..07ba9a37cef 100644 --- a/dll/win32/dbghelp/symbol.c +++ b/dll/win32/dbghelp/symbol.c @@ -48,31 +48,99 @@ static inline int cmp_addr(ULONG64 a1, ULONG64 a2) return 0; } -static inline int cmp_sorttab_addr(const struct module* module, int idx, ULONG64 addr) +static inline int cmp_sorttab_addr(struct module* module, int idx, ULONG64 addr) { ULONG64 ref; - symt_get_info(&module->addr_sorttab[idx]->symt, TI_GET_ADDRESS, &ref); + symt_get_info(module, &module->addr_sorttab[idx]->symt, TI_GET_ADDRESS, &ref); return cmp_addr(ref, addr); } +struct module* symt_cmp_addr_module = NULL; + int symt_cmp_addr(const void* p1, const void* p2) { const struct symt* sym1 = *(const struct symt* const *)p1; const struct symt* sym2 = *(const struct symt* const *)p2; ULONG64 a1, a2; - symt_get_info(sym1, TI_GET_ADDRESS, &a1); - symt_get_info(sym2, TI_GET_ADDRESS, &a2); + symt_get_info(symt_cmp_addr_module, sym1, TI_GET_ADDRESS, &a1); + symt_get_info(symt_cmp_addr_module, sym2, TI_GET_ADDRESS, &a2); return cmp_addr(a1, a2); } -static inline void re_append(char** mask, unsigned* len, char ch) +DWORD symt_ptr2index(struct module* module, const struct symt* sym) { - *mask = HeapReAlloc(GetProcessHeap(), 0, *mask, ++(*len)); - (*mask)[*len - 2] = ch; +#ifdef _WIN64 + const struct symt** c; + int len = vector_length(&module->vsymt), i; + + /* FIXME: this is inefficient */ + for (i = 0; i < len; i++) + { + if (*(struct symt**)vector_at(&module->vsymt, i) == sym) + return i + 1; + } + /* not found */ + c = vector_add(&module->vsymt, &module->pool); + if (c) *c = sym; + return len + 1; +#else + return (DWORD)sym; +#endif } +struct symt* symt_index2ptr(struct module* module, DWORD id) +{ +#ifdef _WIN64 + if (!id-- || id >= vector_length(&module->vsymt)) return NULL; + return *(struct symt**)vector_at(&module->vsymt, id); +#else + return (struct symt*)id; +#endif +} + +static BOOL symt_grow_sorttab(struct module* module, unsigned sz) +{ + struct symt_ht** new; + unsigned int size; + + if (sz <= module->sorttab_size) return TRUE; + if (module->addr_sorttab) + { + size = module->sorttab_size * 2; + new = HeapReAlloc(GetProcessHeap(), 0, module->addr_sorttab, + size * sizeof(struct symt_ht*)); + } + else + { + size = 64; + new = HeapAlloc(GetProcessHeap(), 0, size * sizeof(struct symt_ht*)); + } + if (!new) return FALSE; + module->sorttab_size = size; + module->addr_sorttab = new; + return TRUE; +} + +static void symt_add_module_ht(struct module* module, struct symt_ht* ht) +{ + ULONG64 addr; + + hash_table_add(&module->ht_symbols, &ht->hash_elt); + /* Don't store in sorttab a symbol without address, they are of + * no use here (e.g. constant values) + */ + if (symt_get_info(module, &ht->symt, TI_GET_ADDRESS, &addr) && + symt_grow_sorttab(module, module->num_symbols + 1)) + { + module->addr_sorttab[module->num_symbols++] = ht; + module->sortlist_valid = FALSE; + } +} + +#ifdef HAVE_REGEX_H + /* transforms a dbghelp's regular expression into a POSIX one * Here are the valid dbghelp reg ex characters: * * 0 or more characters @@ -84,47 +152,138 @@ static inline void re_append(char** mask, unsigned* len, char ch) */ static void compile_regex(const char* str, int numchar, regex_t* re, BOOL _case) { - char* mask = HeapAlloc(GetProcessHeap(), 0, 1); - unsigned len = 1; + char *mask, *p; BOOL in_escape = FALSE; unsigned flags = REG_NOSUB; - re_append(&mask, &len, '^'); + if (numchar == -1) numchar = strlen( str ); + + p = mask = HeapAlloc( GetProcessHeap(), 0, 2 * numchar + 3 ); + *p++ = '^'; while (*str && numchar--) { /* FIXME: this shouldn't be valid on '-' */ if (in_escape) { - re_append(&mask, &len, '\\'); - re_append(&mask, &len, *str); + *p++ = '\\'; + *p++ = *str; in_escape = FALSE; } else switch (*str) { case '\\': in_escape = TRUE; break; - case '*': re_append(&mask, &len, '.'); re_append(&mask, &len, '*'); break; - case '?': re_append(&mask, &len, '.'); break; - case '#': re_append(&mask, &len, '*'); break; + case '*': *p++ = '.'; *p++ = '*'; break; + case '?': *p++ = '.'; break; + case '#': *p++ = '*'; break; /* escape some valid characters in dbghelp reg exp:s */ - case '$': re_append(&mask, &len, '\\'); re_append(&mask, &len, '$'); break; + case '$': *p++ = '\\'; *p++ = '$'; break; /* +, [, ], - are the same in dbghelp & POSIX, use them as any other char */ - default: re_append(&mask, &len, *str); break; + default: *p++ = *str; break; } str++; } if (in_escape) { - re_append(&mask, &len, '\\'); - re_append(&mask, &len, '\\'); + *p++ = '\\'; + *p++ = '\\'; } - re_append(&mask, &len, '$'); - mask[len - 1] = '\0'; + *p++ = '$'; + *p = 0; if (_case) flags |= REG_ICASE; if (regcomp(re, mask, flags)) FIXME("Couldn't compile %s\n", mask); HeapFree(GetProcessHeap(), 0, mask); } +static BOOL compile_file_regex(regex_t* re, const char* srcfile) +{ + char *mask, *p; + BOOL ret; + + if (!srcfile || !*srcfile) return regcomp(re, ".*", REG_NOSUB); + + p = mask = HeapAlloc(GetProcessHeap(), 0, 5 * strlen(srcfile) + 4); + *p++ = '^'; + while (*srcfile) + { + switch (*srcfile) + { + case '\\': + case '/': + *p++ = '['; + *p++ = '\\'; + *p++ = '\\'; + *p++ = '/'; + *p++ = ']'; + break; + case '.': + *p++ = '\\'; + *p++ = '.'; + break; + default: + *p++ = *srcfile; + break; + } + srcfile++; + } + *p++ = '$'; + *p = 0; + ret = !regcomp(re, mask, REG_NOSUB); + HeapFree(GetProcessHeap(), 0, mask); + if (!ret) + { + FIXME("Couldn't compile %s\n", mask); + SetLastError(ERROR_INVALID_PARAMETER); + } + return ret; +} + +static int match_regexp( const regex_t *re, const char *str ) +{ + return !regexec( re, str, 0, NULL, 0 ); +} + +#else /* HAVE_REGEX_H */ + +/* if we don't have regexp support, fall back to a simple string comparison */ + +typedef struct +{ + char *str; + BOOL icase; +} regex_t; + +static void compile_regex(const char* str, int numchar, regex_t* re, BOOL _case) +{ + if (numchar == -1) numchar = strlen( str ); + + re->str = HeapAlloc( GetProcessHeap(), 0, numchar + 1 ); + memcpy( re->str, str, numchar ); + re->str[numchar] = 0; + re->icase = _case; +} + +static BOOL compile_file_regex(regex_t* re, const char* srcfile) +{ + if (!srcfile || !*srcfile) re->str = NULL; + else compile_regex( srcfile, -1, re, FALSE ); + return TRUE; +} + +static int match_regexp( const regex_t *re, const char *str ) +{ + if (!re->str) return 1; + if (re->icase) return !lstrcmpiA( re->str, str ); + return !strcmp( re->str, str ); +} + +static void regfree( regex_t *re ) +{ + HeapFree( GetProcessHeap(), 0, re->str ); +} + +#endif /* HAVE_REGEX_H */ + struct symt_compiland* symt_new_compiland(struct module* module, unsigned long address, unsigned src_idx) { @@ -145,8 +304,7 @@ struct symt_compiland* symt_new_compiland(struct module* module, struct symt_public* symt_new_public(struct module* module, struct symt_compiland* compiland, const char* name, - unsigned long address, unsigned size, - BOOL in_code, BOOL is_func) + unsigned long address, unsigned size) { struct symt_public* sym; struct symt** p; @@ -160,13 +318,10 @@ struct symt_public* symt_new_public(struct module* module, { sym->symt.tag = SymTagPublicSymbol; sym->hash_elt.name = pool_strdup(&module->pool, name); - hash_table_add(&module->ht_symbols, &sym->hash_elt); - module->sortlist_valid = FALSE; sym->container = compiland ? &compiland->symt : NULL; sym->address = address; sym->size = size; - sym->in_code = in_code; - sym->is_function = is_func; + symt_add_module_ht(module, (struct symt_ht*)sym); if (compiland) { p = vector_add(&compiland->vchildren, &module->pool); @@ -192,19 +347,18 @@ struct symt_data* symt_new_global_variable(struct module* module, { sym->symt.tag = SymTagData; sym->hash_elt.name = pool_strdup(&module->pool, name); - hash_table_add(&module->ht_symbols, &sym->hash_elt); - module->sortlist_valid = FALSE; sym->kind = is_static ? DataIsFileStatic : DataIsGlobal; sym->container = compiland ? &compiland->symt : NULL; sym->type = type; sym->u.var.offset = addr; - if (type && size && symt_get_info(type, TI_GET_LENGTH, &tsz)) + if (type && size && symt_get_info(module, type, TI_GET_LENGTH, &tsz)) { if (tsz != size) FIXME("Size mismatch for %s.%s between type (%s) and src (%lu)\n", debugstr_w(module->module.ModuleName), name, wine_dbgstr_longlong(tsz), size); } + symt_add_module_ht(module, (struct symt_ht*)sym); if (compiland) { p = vector_add(&compiland->vchildren, &module->pool); @@ -231,14 +385,13 @@ struct symt_function* symt_new_function(struct module* module, { sym->symt.tag = SymTagFunction; sym->hash_elt.name = pool_strdup(&module->pool, name); - hash_table_add(&module->ht_symbols, &sym->hash_elt); - module->sortlist_valid = FALSE; sym->container = &compiland->symt; sym->address = addr; sym->type = sig_type; sym->size = size; vector_init(&sym->vlines, sizeof(struct line_info), 64); vector_init(&sym->vchildren, sizeof(struct symt*), 8); + symt_add_module_ht(module, (struct symt_ht*)sym); if (compiland) { p = vector_add(&compiland->vchildren, &module->pool); @@ -363,7 +516,7 @@ struct symt_block* symt_open_func_block(struct module* module, } struct symt_block* symt_close_func_block(struct module* module, - struct symt_function* func, + const struct symt_function* func, struct symt_block* block, unsigned pc) { assert(func); @@ -395,7 +548,7 @@ struct symt_hierarchy_point* symt_add_function_point(struct module* module, return sym; } -BOOL symt_normalize_function(struct module* module, struct symt_function* func) +BOOL symt_normalize_function(struct module* module, const struct symt_function* func) { unsigned len; struct line_info* dli; @@ -432,12 +585,11 @@ struct symt_thunk* symt_new_thunk(struct module* module, { sym->symt.tag = SymTagThunk; sym->hash_elt.name = pool_strdup(&module->pool, name); - hash_table_add(&module->ht_symbols, &sym->hash_elt); - module->sortlist_valid = FALSE; sym->container = &compiland->symt; sym->address = addr; sym->size = size; sym->ordinal = ord; + symt_add_module_ht(module, (struct symt_ht*)sym); if (compiland) { struct symt** p; @@ -462,12 +614,11 @@ struct symt_data* symt_new_constant(struct module* module, { sym->symt.tag = SymTagData; sym->hash_elt.name = pool_strdup(&module->pool, name); - hash_table_add(&module->ht_symbols, &sym->hash_elt); - module->sortlist_valid = FALSE; sym->kind = DataIsConstant; sym->container = compiland ? &compiland->symt : NULL; sym->type = type; sym->u.value = *v; + symt_add_module_ht(module, (struct symt_ht*)sym); if (compiland) { struct symt** p; @@ -491,11 +642,10 @@ struct symt_hierarchy_point* symt_new_label(struct module* module, { sym->symt.tag = SymTagLabel; sym->hash_elt.name = pool_strdup(&module->pool, name); - hash_table_add(&module->ht_symbols, &sym->hash_elt); - module->sortlist_valid = FALSE; sym->loc.kind = loc_absolute; sym->loc.offset = address; sym->parent = compiland ? &compiland->symt : NULL; + symt_add_module_ht(module, (struct symt_ht*)sym); if (compiland) { struct symt** p; @@ -507,20 +657,21 @@ struct symt_hierarchy_point* symt_new_label(struct module* module, } /* expect sym_info->MaxNameLen to be set before being called */ -static void symt_fill_sym_info(const struct module_pair* pair, +static void symt_fill_sym_info(struct module_pair* pair, const struct symt_function* func, const struct symt* sym, SYMBOL_INFO* sym_info) { const char* name; DWORD64 size; - if (!symt_get_info(sym, TI_GET_TYPE, &sym_info->TypeIndex)) + if (!symt_get_info(pair->effective, sym, TI_GET_TYPE, &sym_info->TypeIndex)) sym_info->TypeIndex = 0; - sym_info->info = (DWORD)sym; + sym_info->info = symt_ptr2index(pair->effective, sym); sym_info->Reserved[0] = sym_info->Reserved[1] = 0; - if (!symt_get_info(sym, TI_GET_LENGTH, &size) && + if (!symt_get_info(pair->effective, sym, TI_GET_LENGTH, &size) && (!sym_info->TypeIndex || - !symt_get_info((struct symt*)sym_info->TypeIndex, TI_GET_LENGTH, &size))) + !symt_get_info(pair->effective, symt_index2ptr(pair->effective, sym_info->TypeIndex), + TI_GET_LENGTH, &size))) size = 0; sym_info->Size = (DWORD)size; sym_info->ModBase = pair->requested->module.BaseOfImage; @@ -569,7 +720,7 @@ static void symt_fill_sym_info(const struct module_pair* pair, break; case DataIsGlobal: case DataIsFileStatic: - symt_get_info(sym, TI_GET_ADDRESS, &sym_info->Address); + symt_get_info(pair->effective, sym, TI_GET_ADDRESS, &sym_info->Address); sym_info->Register = 0; break; case DataIsConstant: @@ -582,7 +733,8 @@ static void symt_fill_sym_info(const struct module_pair* pair, case VT_UI4: sym_info->Value = (ULONG)data->u.value.n1.n2.n3.ulVal; break; case VT_UI2: sym_info->Value = (ULONG)data->u.value.n1.n2.n3.uiVal; break; case VT_UI1: sym_info->Value = (ULONG)data->u.value.n1.n2.n3.bVal; break; - case VT_I1 | VT_BYREF: sym_info->Value = (ULONG)data->u.value.n1.n2.n3.byref; break; + case VT_I1 | VT_BYREF: sym_info->Value = (ULONG64)(DWORD_PTR)data->u.value.n1.n2.n3.byref; break; + case VT_EMPTY: sym_info->Value = 0; break; default: FIXME("Unsupported variant type (%u)\n", data->u.value.n1.n2.vt); sym_info->Value = 0; @@ -596,18 +748,18 @@ static void symt_fill_sym_info(const struct module_pair* pair, break; case SymTagPublicSymbol: sym_info->Flags |= SYMFLAG_EXPORT; - symt_get_info(sym, TI_GET_ADDRESS, &sym_info->Address); + symt_get_info(pair->effective, sym, TI_GET_ADDRESS, &sym_info->Address); break; case SymTagFunction: sym_info->Flags |= SYMFLAG_FUNCTION; - symt_get_info(sym, TI_GET_ADDRESS, &sym_info->Address); + symt_get_info(pair->effective, sym, TI_GET_ADDRESS, &sym_info->Address); break; case SymTagThunk: sym_info->Flags |= SYMFLAG_THUNK; - symt_get_info(sym, TI_GET_ADDRESS, &sym_info->Address); + symt_get_info(pair->effective, sym, TI_GET_ADDRESS, &sym_info->Address); break; default: - symt_get_info(sym, TI_GET_ADDRESS, &sym_info->Address); + symt_get_info(pair->effective, sym, TI_GET_ADDRESS, &sym_info->Address); sym_info->Register = 0; break; } @@ -641,7 +793,7 @@ struct sym_enum char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME]; }; -static BOOL send_symbol(const struct sym_enum* se, const struct module_pair* pair, +static BOOL send_symbol(const struct sym_enum* se, struct module_pair* pair, const struct symt_function* func, const struct symt* sym) { symt_fill_sym_info(pair, func, sym, se->sym_info); @@ -662,8 +814,7 @@ static BOOL symt_enum_module(struct module_pair* pair, const regex_t* regex, while ((ptr = hash_table_iter_up(&hti))) { sym = GET_ENTRY(ptr, struct symt_ht, hash_elt); - if (sym->hash_elt.name && - regexec(regex, sym->hash_elt.name, 0, NULL, 0) == 0) + if (sym->hash_elt.name && match_regexp(regex, sym->hash_elt.name)) { se->sym_info->SizeOfStruct = sizeof(SYMBOL_INFO); se->sym_info->MaxNameLen = sizeof(se->buffer) - sizeof(SYMBOL_INFO); @@ -673,6 +824,26 @@ static BOOL symt_enum_module(struct module_pair* pair, const regex_t* regex, return FALSE; } +static inline unsigned where_to_insert(struct module* module, unsigned high, const struct symt_ht* elt) +{ + unsigned low = 0, mid = high / 2; + ULONG64 addr; + + if (!high) return 0; + symt_get_info(module, &elt->symt, TI_GET_ADDRESS, &addr); + do + { + switch (cmp_sorttab_addr(module, mid, addr)) + { + case 0: return mid; + case -1: low = mid + 1; break; + case 1: high = mid; break; + } + mid = low + (high - low) / 2; + } while (low < high); + return mid; +} + /*********************************************************************** * resort_symbols * @@ -680,55 +851,53 @@ static BOOL symt_enum_module(struct module_pair* pair, const regex_t* regex, */ static BOOL resort_symbols(struct module* module) { - void* ptr; - struct symt_ht* sym; - struct hash_table_iter hti; - ULONG64 addr; - - if (!(module->module.NumSyms = module->ht_symbols.num_elts)) + if (!(module->module.NumSyms = module->num_symbols)) return FALSE; - - if (module->addr_sorttab) - module->addr_sorttab = HeapReAlloc(GetProcessHeap(), 0, - module->addr_sorttab, - module->module.NumSyms * sizeof(struct symt_ht*)); - else - module->addr_sorttab = HeapAlloc(GetProcessHeap(), 0, - module->module.NumSyms * sizeof(struct symt_ht*)); - if (!module->addr_sorttab) return FALSE; - module->num_sorttab = 0; - hash_table_iter_init(&module->ht_symbols, &hti, NULL); - while ((ptr = hash_table_iter_up(&hti))) + /* FIXME: what's the optimal value here ??? */ + if (module->num_sorttab && module->num_symbols <= module->num_sorttab + 30) { - sym = GET_ENTRY(ptr, struct symt_ht, hash_elt); - assert(sym); - /* Don't store in sorttab symbol without address, they are of - * no use here (e.g. constant values) - * As the number of those symbols is very couple (a couple per module) - * we don't bother for the unused spots at the end of addr_sorttab - */ - if (symt_get_info(&sym->symt, TI_GET_ADDRESS, &addr)) - module->addr_sorttab[module->num_sorttab++] = sym; + int i, delta, ins_idx = module->num_sorttab, prev_ins_idx; + struct symt_ht* tmp[30]; + + delta = module->num_symbols - module->num_sorttab; + memcpy(tmp, &module->addr_sorttab[module->num_sorttab], delta * sizeof(struct symt_ht*)); + symt_cmp_addr_module = module; + qsort(tmp, delta, sizeof(struct symt_ht*), symt_cmp_addr); + + for (i = delta - 1; i >= 0; i--) + { + prev_ins_idx = ins_idx; + ins_idx = where_to_insert(module, prev_ins_idx = ins_idx, tmp[i]); + memmove(&module->addr_sorttab[ins_idx + i + 1], + &module->addr_sorttab[ins_idx], + (prev_ins_idx - ins_idx) * sizeof(struct symt_ht*)); + module->addr_sorttab[ins_idx + i] = tmp[i]; + } } - qsort(module->addr_sorttab, module->num_sorttab, sizeof(struct symt_ht*), symt_cmp_addr); + else + { + symt_cmp_addr_module = module; + qsort(module->addr_sorttab, module->num_symbols, sizeof(struct symt_ht*), symt_cmp_addr); + } + module->num_sorttab = module->num_symbols; return module->sortlist_valid = TRUE; } -static void symt_get_length(struct symt* symt, ULONG64* size) +static void symt_get_length(struct module* module, const struct symt* symt, ULONG64* size) { DWORD type_index; - if (symt_get_info(symt, TI_GET_LENGTH, size) && *size) + if (symt_get_info(module, symt, TI_GET_LENGTH, size) && *size) return; - if (symt_get_info(symt, TI_GET_TYPE, &type_index) && - symt_get_info((struct symt*)type_index, TI_GET_LENGTH, size)) return; + if (symt_get_info(module, symt, TI_GET_TYPE, &type_index) && + symt_get_info(module, symt_index2ptr(module, type_index), TI_GET_LENGTH, size)) return; *size = 0x1000; /* arbitrary value */ } /* assume addr is in module */ -struct symt_ht* symt_find_nearest(struct module* module, DWORD addr) +struct symt_ht* symt_find_nearest(struct module* module, DWORD_PTR addr) { int mid, high, low; ULONG64 ref_addr, ref_size; @@ -744,12 +913,12 @@ struct symt_ht* symt_find_nearest(struct module* module, DWORD addr) low = 0; high = module->num_sorttab; - symt_get_info(&module->addr_sorttab[0]->symt, TI_GET_ADDRESS, &ref_addr); + symt_get_info(module, &module->addr_sorttab[0]->symt, TI_GET_ADDRESS, &ref_addr); if (addr < ref_addr) return NULL; if (high) { - symt_get_info(&module->addr_sorttab[high - 1]->symt, TI_GET_ADDRESS, &ref_addr); - symt_get_length(&module->addr_sorttab[high - 1]->symt, &ref_size); + symt_get_info(module, &module->addr_sorttab[high - 1]->symt, TI_GET_ADDRESS, &ref_addr); + symt_get_length(module, &module->addr_sorttab[high - 1]->symt, &ref_size); if (addr >= ref_addr + ref_size) return NULL; } @@ -770,7 +939,7 @@ struct symt_ht* symt_find_nearest(struct module* module, DWORD addr) */ if (module->addr_sorttab[low]->symt.tag == SymTagPublicSymbol) { - symt_get_info(&module->addr_sorttab[low]->symt, TI_GET_ADDRESS, &ref_addr); + symt_get_info(module, &module->addr_sorttab[low]->symt, TI_GET_ADDRESS, &ref_addr); if (low > 0 && module->addr_sorttab[low - 1]->symt.tag != SymTagPublicSymbol && !cmp_sorttab_addr(module, low - 1, ref_addr)) @@ -781,9 +950,9 @@ struct symt_ht* symt_find_nearest(struct module* module, DWORD addr) low++; } /* finally check that we fit into the found symbol */ - symt_get_info(&module->addr_sorttab[low]->symt, TI_GET_ADDRESS, &ref_addr); + symt_get_info(module, &module->addr_sorttab[low]->symt, TI_GET_ADDRESS, &ref_addr); if (addr < ref_addr) return NULL; - symt_get_length(&module->addr_sorttab[low]->symt, &ref_size); + symt_get_length(module, &module->addr_sorttab[low]->symt, &ref_size); if (addr >= ref_addr + ref_size) return NULL; return module->addr_sorttab[low]; @@ -812,7 +981,7 @@ static BOOL symt_enum_locals_helper(struct module_pair* pair, } break; case SymTagData: - if (regexec(preg, symt_get_name(lsym), 0, NULL, 0) == 0) + if (match_regexp(preg, symt_get_name(lsym))) { if (send_symbol(se, pair, func, lsym)) return FALSE; } @@ -900,6 +1069,7 @@ static BOOL sym_enum(HANDLE hProcess, ULONG64 BaseOfDll, PCSTR Mask, regex_t mod_regex, sym_regex; pair.pcs = process_find_by_handle(hProcess); + if (!pair.pcs) return FALSE; if (BaseOfDll == 0) { /* do local variables ? */ @@ -916,22 +1086,22 @@ static BOOL sym_enum(HANDLE hProcess, ULONG64 BaseOfDll, PCSTR Mask, { if (pair.requested->type == DMT_PE && module_get_debug(&pair)) { - if (regexec(&mod_regex, pair.requested->module_name, 0, NULL, 0) == 0 && + if (match_regexp(&mod_regex, pair.requested->module_name) && symt_enum_module(&pair, &sym_regex, se)) break; } } /* not found in PE modules, retry on the ELF ones */ - if (!pair.requested && (dbghelp_options & SYMOPT_WINE_WITH_ELF_MODULES)) + if (!pair.requested && (dbghelp_options & SYMOPT_WINE_WITH_NATIVE_MODULES)) { for (pair.requested = pair.pcs->lmodules; pair.requested; pair.requested = pair.requested->next) { - if (pair.requested->type == DMT_ELF && + if ((pair.requested->type == DMT_ELF || pair.requested->type == DMT_MACHO) && !module_get_containee(pair.pcs, pair.requested) && module_get_debug(&pair)) { - if (regexec(&mod_regex, pair.requested->module_name, 0, NULL, 0) == 0 && + if (match_regexp(&mod_regex, pair.requested->module_name) && symt_enum_module(&pair, &sym_regex, se)) break; } @@ -1046,7 +1216,7 @@ struct sym_enumerate static BOOL CALLBACK sym_enumerate_cb(PSYMBOL_INFO syminfo, ULONG size, void* ctx) { - struct sym_enumerate* se = (struct sym_enumerate*)ctx; + struct sym_enumerate* se = ctx; return (se->cb)(syminfo->Name, syminfo->Address, syminfo->Size, se->ctx); } @@ -1073,7 +1243,7 @@ struct sym_enumerate64 static BOOL CALLBACK sym_enumerate_cb64(PSYMBOL_INFO syminfo, ULONG size, void* ctx) { - struct sym_enumerate64* se = (struct sym_enumerate64*)ctx; + struct sym_enumerate64* se = ctx; return (se->cb)(syminfo->Name, syminfo->Address, syminfo->Size, se->ctx); } @@ -1250,11 +1420,12 @@ BOOL WINAPI SymFromName(HANDLE hProcess, PCSTR Name, PSYMBOL_INFO Symbol) } /* not found in PE modules, retry on the ELF ones */ - if (dbghelp_options & SYMOPT_WINE_WITH_ELF_MODULES) + if (dbghelp_options & SYMOPT_WINE_WITH_NATIVE_MODULES) { for (module = pcs->lmodules; module; module = module->next) { - if (module->type == DMT_ELF && !module_get_containee(pcs, module) && + if ((module->type == DMT_ELF || module->type == DMT_MACHO) && + !module_get_containee(pcs, module) && find_name(pcs, module, Name, Symbol)) return TRUE; } @@ -1262,6 +1433,28 @@ BOOL WINAPI SymFromName(HANDLE hProcess, PCSTR Name, PSYMBOL_INFO Symbol) return FALSE; } +/*********************************************************************** + * SymGetSymFromName64 (DBGHELP.@) + */ +BOOL WINAPI SymGetSymFromName64(HANDLE hProcess, PCSTR Name, PIMAGEHLP_SYMBOL64 Symbol) +{ + char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME]; + SYMBOL_INFO*si = (SYMBOL_INFO*)buffer; + size_t len; + + if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE; + si->SizeOfStruct = sizeof(*si); + si->MaxNameLen = MAX_SYM_NAME; + if (!SymFromName(hProcess, Name, si)) return FALSE; + + Symbol->Address = si->Address; + Symbol->Size = si->Size; + Symbol->Flags = si->Flags; + len = min(Symbol->MaxNameLength, si->MaxNameLen); + lstrcpynA(Symbol->Name, si->Name, len); + return TRUE; +} + /*********************************************************************** * SymGetSymFromName (DBGHELP.@) */ @@ -1290,7 +1483,7 @@ BOOL WINAPI SymGetSymFromName(HANDLE hProcess, PCSTR Name, PIMAGEHLP_SYMBOL Symb * fills information about a file */ BOOL symt_fill_func_line_info(const struct module* module, const struct symt_function* func, - DWORD addr, IMAGEHLP_LINE* line) + DWORD64 addr, IMAGEHLP_LINE64* line) { struct line_info* dli = NULL; BOOL found = FALSE; @@ -1320,9 +1513,9 @@ BOOL symt_fill_func_line_info(const struct module* module, const struct symt_fun } /*********************************************************************** - * SymGetSymNext (DBGHELP.@) + * SymGetSymNext64 (DBGHELP.@) */ -BOOL WINAPI SymGetSymNext(HANDLE hProcess, PIMAGEHLP_SYMBOL Symbol) +BOOL WINAPI SymGetSymNext64(HANDLE hProcess, PIMAGEHLP_SYMBOL64 Symbol) { /* algo: * get module from Symbol.Address @@ -1336,41 +1529,33 @@ BOOL WINAPI SymGetSymNext(HANDLE hProcess, PIMAGEHLP_SYMBOL Symbol) } /*********************************************************************** - * SymGetSymPrev (DBGHELP.@) + * SymGetSymNext (DBGHELP.@) */ - -BOOL WINAPI SymGetSymPrev(HANDLE hProcess, PIMAGEHLP_SYMBOL Symbol) +BOOL WINAPI SymGetSymNext(HANDLE hProcess, PIMAGEHLP_SYMBOL Symbol) { FIXME("(%p, %p): stub\n", hProcess, Symbol); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } -/****************************************************************** - * SymGetLineFromAddr (DBGHELP.@) - * +/*********************************************************************** + * SymGetSymPrev64 (DBGHELP.@) */ -BOOL WINAPI SymGetLineFromAddr(HANDLE hProcess, DWORD dwAddr, - PDWORD pdwDisplacement, PIMAGEHLP_LINE Line) +BOOL WINAPI SymGetSymPrev64(HANDLE hProcess, PIMAGEHLP_SYMBOL64 Symbol) { - struct module_pair pair; - struct symt_ht* symt; + FIXME("(%p, %p): stub\n", hProcess, Symbol); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} - TRACE("%p %08x %p %p\n", hProcess, dwAddr, pdwDisplacement, Line); - - if (Line->SizeOfStruct < sizeof(*Line)) return FALSE; - - pair.pcs = process_find_by_handle(hProcess); - if (!pair.pcs) return FALSE; - pair.requested = module_find_by_addr(pair.pcs, dwAddr, DMT_UNKNOWN); - if (!module_get_debug(&pair)) return FALSE; - if ((symt = symt_find_nearest(pair.effective, dwAddr)) == NULL) return FALSE; - - if (symt->symt.tag != SymTagFunction) return FALSE; - if (!symt_fill_func_line_info(pair.effective, (struct symt_function*)symt, - dwAddr, Line)) return FALSE; - *pdwDisplacement = dwAddr - Line->Address; - return TRUE; +/*********************************************************************** + * SymGetSymPrev (DBGHELP.@) + */ +BOOL WINAPI SymGetSymPrev(HANDLE hProcess, PIMAGEHLP_SYMBOL Symbol) +{ + FIXME("(%p, %p): stub\n", hProcess, Symbol); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; } /****************************************************************** @@ -1390,16 +1575,16 @@ static void copy_line_64_from_32(IMAGEHLP_LINE64* l64, const IMAGEHLP_LINE* l32) * copy_line_W64_from_32 (internal) * */ -static void copy_line_W64_from_32(struct process* pcs, IMAGEHLP_LINEW64* l64, const IMAGEHLP_LINE* l32) +static void copy_line_W64_from_64(struct process* pcs, IMAGEHLP_LINEW64* l64w, const IMAGEHLP_LINE64* l64) { unsigned len; - l64->Key = l32->Key; - l64->LineNumber = l32->LineNumber; - len = MultiByteToWideChar(CP_ACP, 0, l32->FileName, -1, NULL, 0); - if ((l64->FileName = fetch_buffer(pcs, len * sizeof(WCHAR)))) - MultiByteToWideChar(CP_ACP, 0, l32->FileName, -1, l64->FileName, len); - l64->Address = l32->Address; + l64w->Key = l64->Key; + l64w->LineNumber = l64->LineNumber; + len = MultiByteToWideChar(CP_ACP, 0, l64->FileName, -1, NULL, 0); + if ((l64w->FileName = fetch_buffer(pcs, len * sizeof(WCHAR)))) + MultiByteToWideChar(CP_ACP, 0, l64->FileName, -1, l64w->FileName, len); + l64w->Address = l64->Address; } /****************************************************************** @@ -1415,6 +1600,22 @@ static void copy_line_32_from_64(IMAGEHLP_LINE* l32, const IMAGEHLP_LINE64* l64) l32->Address = l64->Address; } +/****************************************************************** + * SymGetLineFromAddr (DBGHELP.@) + * + */ +BOOL WINAPI SymGetLineFromAddr(HANDLE hProcess, DWORD dwAddr, + PDWORD pdwDisplacement, PIMAGEHLP_LINE Line) +{ + IMAGEHLP_LINE64 il64; + + il64.SizeOfStruct = sizeof(il64); + if (!SymGetLineFromAddr64(hProcess, dwAddr, pdwDisplacement, &il64)) + return FALSE; + copy_line_32_from_64(Line, &il64); + return TRUE; +} + /****************************************************************** * SymGetLineFromAddr64 (DBGHELP.@) * @@ -1422,14 +1623,23 @@ static void copy_line_32_from_64(IMAGEHLP_LINE* l32, const IMAGEHLP_LINE64* l64) BOOL WINAPI SymGetLineFromAddr64(HANDLE hProcess, DWORD64 dwAddr, PDWORD pdwDisplacement, PIMAGEHLP_LINE64 Line) { - IMAGEHLP_LINE line32; + struct module_pair pair; + struct symt_ht* symt; + + TRACE("%p %s %p %p\n", hProcess, wine_dbgstr_longlong(dwAddr), pdwDisplacement, Line); if (Line->SizeOfStruct < sizeof(*Line)) return FALSE; - if (!validate_addr64(dwAddr)) return FALSE; - line32.SizeOfStruct = sizeof(line32); - if (!SymGetLineFromAddr(hProcess, (DWORD)dwAddr, pdwDisplacement, &line32)) - return FALSE; - copy_line_64_from_32(Line, &line32); + + pair.pcs = process_find_by_handle(hProcess); + if (!pair.pcs) return FALSE; + pair.requested = module_find_by_addr(pair.pcs, dwAddr, DMT_UNKNOWN); + if (!module_get_debug(&pair)) return FALSE; + if ((symt = symt_find_nearest(pair.effective, dwAddr)) == NULL) return FALSE; + + if (symt->symt.tag != SymTagFunction) return FALSE; + if (!symt_fill_func_line_info(pair.effective, (struct symt_function*)symt, + dwAddr, Line)) return FALSE; + *pdwDisplacement = dwAddr - Line->Address; return TRUE; } @@ -1440,24 +1650,20 @@ BOOL WINAPI SymGetLineFromAddr64(HANDLE hProcess, DWORD64 dwAddr, BOOL WINAPI SymGetLineFromAddrW64(HANDLE hProcess, DWORD64 dwAddr, PDWORD pdwDisplacement, PIMAGEHLP_LINEW64 Line) { - struct process* pcs = process_find_by_handle(hProcess); - IMAGEHLP_LINE line32; + IMAGEHLP_LINE64 il64; - if (!pcs) return FALSE; - if (Line->SizeOfStruct < sizeof(*Line)) return FALSE; - if (!validate_addr64(dwAddr)) return FALSE; - line32.SizeOfStruct = sizeof(line32); - if (!SymGetLineFromAddr(hProcess, (DWORD)dwAddr, pdwDisplacement, &line32)) + il64.SizeOfStruct = sizeof(il64); + if (!SymGetLineFromAddr64(hProcess, dwAddr, pdwDisplacement, &il64)) return FALSE; - copy_line_W64_from_32(pcs, Line, &line32); + copy_line_W64_from_64(process_find_by_handle(hProcess), Line, &il64); return TRUE; } /****************************************************************** - * SymGetLinePrev (DBGHELP.@) + * SymGetLinePrev64 (DBGHELP.@) * */ -BOOL WINAPI SymGetLinePrev(HANDLE hProcess, PIMAGEHLP_LINE Line) +BOOL WINAPI SymGetLinePrev64(HANDLE hProcess, PIMAGEHLP_LINE64 Line) { struct module_pair pair; struct line_info* li; @@ -1473,7 +1679,7 @@ BOOL WINAPI SymGetLinePrev(HANDLE hProcess, PIMAGEHLP_LINE Line) if (!module_get_debug(&pair)) return FALSE; if (Line->Key == 0) return FALSE; - li = (struct line_info*)Line->Key; + li = Line->Key; /* things are a bit complicated because when we encounter a DLIT_SOURCEFILE * element we have to go back until we find the prev one to get the real * source file name for the DLIT_OFFSET element just before @@ -1504,26 +1710,26 @@ BOOL WINAPI SymGetLinePrev(HANDLE hProcess, PIMAGEHLP_LINE Line) } /****************************************************************** - * SymGetLinePrev64 (DBGHELP.@) + * SymGetLinePrev (DBGHELP.@) * */ -BOOL WINAPI SymGetLinePrev64(HANDLE hProcess, PIMAGEHLP_LINE64 Line) +BOOL WINAPI SymGetLinePrev(HANDLE hProcess, PIMAGEHLP_LINE Line) { - IMAGEHLP_LINE line32; + IMAGEHLP_LINE64 line64; - line32.SizeOfStruct = sizeof(line32); - copy_line_32_from_64(&line32, Line); - if (!SymGetLinePrev(hProcess, &line32)) return FALSE; - copy_line_64_from_32(Line, &line32); + line64.SizeOfStruct = sizeof(line64); + copy_line_64_from_32(&line64, Line); + if (!SymGetLinePrev64(hProcess, &line64)) return FALSE; + copy_line_32_from_64(Line, &line64); return TRUE; } - -BOOL symt_get_func_line_next(const struct module* module, PIMAGEHLP_LINE line) + +BOOL symt_get_func_line_next(const struct module* module, PIMAGEHLP_LINE64 line) { struct line_info* li; if (line->Key == 0) return FALSE; - li = (struct line_info*)line->Key; + li = line->Key; while (!li->is_last) { li++; @@ -1540,10 +1746,10 @@ BOOL symt_get_func_line_next(const struct module* module, PIMAGEHLP_LINE line) } /****************************************************************** - * SymGetLineNext (DBGHELP.@) + * SymGetLineNext64 (DBGHELP.@) * */ -BOOL WINAPI SymGetLineNext(HANDLE hProcess, PIMAGEHLP_LINE Line) +BOOL WINAPI SymGetLineNext64(HANDLE hProcess, PIMAGEHLP_LINE64 Line) { struct module_pair pair; @@ -1561,20 +1767,20 @@ BOOL WINAPI SymGetLineNext(HANDLE hProcess, PIMAGEHLP_LINE Line) } /****************************************************************** - * SymGetLineNext64 (DBGHELP.@) + * SymGetLineNext (DBGHELP.@) * */ -BOOL WINAPI SymGetLineNext64(HANDLE hProcess, PIMAGEHLP_LINE64 Line) +BOOL WINAPI SymGetLineNext(HANDLE hProcess, PIMAGEHLP_LINE Line) { - IMAGEHLP_LINE line32; + IMAGEHLP_LINE64 line64; - line32.SizeOfStruct = sizeof(line32); - copy_line_32_from_64(&line32, Line); - if (!SymGetLineNext(hProcess, &line32)) return FALSE; - copy_line_64_from_32(Line, &line32); + line64.SizeOfStruct = sizeof(line64); + copy_line_64_from_32(&line64, Line); + if (!SymGetLineNext64(hProcess, &line64)) return FALSE; + copy_line_32_from_64(Line, &line64); return TRUE; } - + /*********************************************************************** * SymFunctionTableAccess (DBGHELP.@) */ @@ -1598,7 +1804,15 @@ PVOID WINAPI SymFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase) */ BOOL WINAPI SymUnDName(PIMAGEHLP_SYMBOL sym, PSTR UnDecName, DWORD UnDecNameLength) { - TRACE("(%p %s %u)\n", sym, UnDecName, UnDecNameLength); + return UnDecorateSymbolName(sym->Name, UnDecName, UnDecNameLength, + UNDNAME_COMPLETE) != 0; +} + +/*********************************************************************** + * SymUnDName64 (DBGHELP.@) + */ +BOOL WINAPI SymUnDName64(PIMAGEHLP_SYMBOL64 sym, PSTR UnDecName, DWORD UnDecNameLength) +{ return UnDecorateSymbolName(sym->Name, UnDecName, UnDecNameLength, UNDNAME_COMPLETE) != 0; } @@ -1645,7 +1859,7 @@ BOOL WINAPI SymMatchString(PCSTR string, PCSTR re, BOOL _case) TRACE("%s %s %c\n", string, re, _case ? 'Y' : 'N'); compile_regex(re, -1, &preg, _case); - ret = regexec(&preg, string, 0, NULL, 0) == 0; + ret = match_regexp(&preg, string); regfree(&preg); return ret; } @@ -1762,3 +1976,88 @@ BOOL WINAPI SymSetScopeFromAddr(HANDLE hProcess, ULONG64 addr) if (!(pcs = process_find_by_handle(hProcess))) return FALSE; return TRUE; } + +/****************************************************************** + * SymEnumLines (DBGHELP.@) + * + */ +BOOL WINAPI SymEnumLines(HANDLE hProcess, ULONG64 base, PCSTR compiland, + PCSTR srcfile, PSYM_ENUMLINES_CALLBACK cb, PVOID user) +{ + struct module_pair pair; + struct hash_table_iter hti; + struct symt_ht* sym; + regex_t re; + struct line_info* dli; + void* ptr; + SRCCODEINFO sci; + const char* file; + + if (!cb) return FALSE; + if (!(dbghelp_options & SYMOPT_LOAD_LINES)) return TRUE; + + pair.pcs = process_find_by_handle(hProcess); + if (!pair.pcs) return FALSE; + if (compiland) FIXME("Unsupported yet (filtering on compiland %s)\n", compiland); + pair.requested = module_find_by_addr(pair.pcs, base, DMT_UNKNOWN); + if (!module_get_debug(&pair)) return FALSE; + if (!compile_file_regex(&re, srcfile)) return FALSE; + + sci.SizeOfStruct = sizeof(sci); + sci.ModBase = base; + + hash_table_iter_init(&pair.effective->ht_symbols, &hti, NULL); + while ((ptr = hash_table_iter_up(&hti))) + { + unsigned int i; + + sym = GET_ENTRY(ptr, struct symt_ht, hash_elt); + if (sym->symt.tag != SymTagFunction) continue; + + sci.FileName[0] = '\0'; + for (i=0; ivlines); i++) + { + dli = vector_at(&((struct symt_function*)sym)->vlines, i); + if (dli->is_source_file) + { + file = source_get(pair.effective, dli->u.source_file); + if (!match_regexp(&re, file)) file = ""; + strcpy(sci.FileName, file); + } + else if (sci.FileName[0]) + { + sci.Key = dli; + sci.Obj[0] = '\0'; /* FIXME */ + sci.LineNumber = dli->line_number; + sci.Address = dli->u.pc_offset; + if (!cb(&sci, user)) break; + } + } + } + regfree(&re); + return TRUE; +} + +BOOL WINAPI SymGetLineFromName(HANDLE hProcess, PCSTR ModuleName, PCSTR FileName, + DWORD dwLineNumber, PLONG plDisplacement, PIMAGEHLP_LINE Line) +{ + FIXME("(%p) (%s, %s, %d %p %p): stub\n", hProcess, ModuleName, FileName, + dwLineNumber, plDisplacement, Line); + return FALSE; +} + +BOOL WINAPI SymGetLineFromName64(HANDLE hProcess, PCSTR ModuleName, PCSTR FileName, + DWORD dwLineNumber, PLONG lpDisplacement, PIMAGEHLP_LINE64 Line) +{ + FIXME("(%p) (%s, %s, %d %p %p): stub\n", hProcess, ModuleName, FileName, + dwLineNumber, lpDisplacement, Line); + return FALSE; +} + +BOOL WINAPI SymGetLineFromNameW64(HANDLE hProcess, PCWSTR ModuleName, PCWSTR FileName, + DWORD dwLineNumber, PLONG plDisplacement, PIMAGEHLP_LINEW64 Line) +{ + FIXME("(%p) (%s, %s, %d %p %p): stub\n", hProcess, debugstr_w(ModuleName), debugstr_w(FileName), + dwLineNumber, plDisplacement, Line); + return FALSE; +} diff --git a/dll/win32/dbghelp/type.c b/dll/win32/dbghelp/type.c index 947eb49095e..2ef4bb45095 100644 --- a/dll/win32/dbghelp/type.c +++ b/dll/win32/dbghelp/type.c @@ -304,6 +304,21 @@ struct symt_array* symt_new_array(struct module* module, int min, int max, return sym; } +static inline DWORD symt_array_count(struct module* module, const struct symt_array* array) +{ + if (array->end < 0) + { + DWORD64 elem_size; + /* One could want to also set the array->end field in array, but we won't do it + * as long as all the get_type() helpers use const objects + */ + if (symt_get_info(module, array->base_type, TI_GET_LENGTH, &elem_size) && elem_size) + return -array->end / (DWORD)elem_size; + return 0; + } + return array->end - array->start + 1; +} + struct symt_function_signature* symt_new_function_signature(struct module* module, struct symt* ret_type, enum CV_call_e call_conv) @@ -400,9 +415,9 @@ BOOL WINAPI SymEnumTypes(HANDLE hProcess, ULONG64 BaseOfDll, for (i=0; ivtypes); i++) { type = *(struct symt**)vector_at(&pair.effective->vtypes, i); - sym_info->TypeIndex = (DWORD)type; + sym_info->TypeIndex = symt_ptr2index(pair.effective, type); sym_info->info = 0; /* FIXME */ - symt_get_info(type, TI_GET_LENGTH, &size); + symt_get_info(pair.effective, type, TI_GET_LENGTH, &size); sym_info->Size = size; sym_info->ModBase = pair.requested->module.BaseOfImage; sym_info->Flags = 0; /* FIXME */ @@ -462,8 +477,8 @@ BOOL WINAPI SymEnumTypesW(HANDLE hProcess, ULONG64 BaseOfDll, * * Retrieves information about a symt (either symbol or type) */ -BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req, - void* pInfo) +BOOL symt_get_info(struct module* module, const struct symt* type, + IMAGEHLP_SYMBOL_TYPE_INFO req, void* pInfo) { unsigned len; @@ -495,7 +510,7 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req, for (i = 0; i < tifp->Count; i++) { if (!(pt = vector_at(v, tifp->Start + i))) return FALSE; - tifp->ChildId[i] = (DWORD)*pt; + tifp->ChildId[i] = symt_ptr2index(module, *pt); } } break; @@ -522,7 +537,7 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req, case SymTagFuncDebugStart: case SymTagFuncDebugEnd: case SymTagLabel: - if (!symt_get_info(((const struct symt_hierarchy_point*)type)->parent, + if (!symt_get_info(module, ((const struct symt_hierarchy_point*)type)->parent, req, pInfo)) return FALSE; X(ULONG64) += ((const struct symt_hierarchy_point*)type)->loc.offset; @@ -597,8 +612,7 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req, switch (type->tag) { case SymTagArrayType: - X(DWORD) = ((const struct symt_array*)type)->end - - ((const struct symt_array*)type)->start + 1; + X(DWORD) = symt_array_count(module, (const struct symt_array*)type); break; case SymTagFunctionType: /* this seems to be wrong for (future) C++ methods, where 'this' parameter @@ -639,18 +653,17 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req, return FALSE; X(DWORD64) = ((const struct symt_data*)type)->u.member.length; break; - case SymTagArrayType: - if (!symt_get_info(((const struct symt_array*)type)->base_type, + case SymTagArrayType: + if (!symt_get_info(module, ((const struct symt_array*)type)->base_type, TI_GET_LENGTH, pInfo)) return FALSE; - X(DWORD64) *= ((const struct symt_array*)type)->end - - ((const struct symt_array*)type)->start + 1; + X(DWORD64) *= symt_array_count(module, (const struct symt_array*)type); break; case SymTagPublicSymbol: X(DWORD64) = ((const struct symt_public*)type)->size; break; case SymTagTypedef: - return symt_get_info(((const struct symt_typedef*)type)->type, TI_GET_LENGTH, pInfo); + return symt_get_info(module, ((const struct symt_typedef*)type)->type, TI_GET_LENGTH, pInfo); case SymTagThunk: X(DWORD64) = ((const struct symt_thunk*)type)->size; break; @@ -670,19 +683,19 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req, switch (type->tag) { case SymTagBlock: - X(DWORD) = (DWORD)((const struct symt_block*)type)->container; + X(DWORD) = symt_ptr2index(module, ((const struct symt_block*)type)->container); break; case SymTagData: - X(DWORD) = (DWORD)((const struct symt_data*)type)->container; + X(DWORD) = symt_ptr2index(module, ((const struct symt_data*)type)->container); break; case SymTagFunction: - X(DWORD) = (DWORD)((const struct symt_function*)type)->container; + X(DWORD) = symt_ptr2index(module, ((const struct symt_function*)type)->container); break; case SymTagThunk: - X(DWORD) = (DWORD)((const struct symt_thunk*)type)->container; + X(DWORD) = symt_ptr2index(module, ((const struct symt_thunk*)type)->container); break; case SymTagFunctionArgType: - X(DWORD) = (DWORD)((const struct symt_function_arg_type*)type)->container; + X(DWORD) = symt_ptr2index(module, ((const struct symt_function_arg_type*)type)->container); break; default: FIXME("Unsupported sym-tag %s for get-lexical-parent\n", @@ -750,29 +763,29 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req, { /* hierarchical => hierarchical */ case SymTagArrayType: - X(DWORD) = (DWORD)((const struct symt_array*)type)->base_type; + X(DWORD) = symt_ptr2index(module, ((const struct symt_array*)type)->base_type); break; case SymTagPointerType: - X(DWORD) = (DWORD)((const struct symt_pointer*)type)->pointsto; + X(DWORD) = symt_ptr2index(module, ((const struct symt_pointer*)type)->pointsto); break; case SymTagFunctionType: - X(DWORD) = (DWORD)((const struct symt_function_signature*)type)->rettype; + X(DWORD) = symt_ptr2index(module, ((const struct symt_function_signature*)type)->rettype); break; case SymTagTypedef: - X(DWORD) = (DWORD)((const struct symt_typedef*)type)->type; + X(DWORD) = symt_ptr2index(module, ((const struct symt_typedef*)type)->type); break; /* lexical => hierarchical */ case SymTagData: - X(DWORD) = (DWORD)((const struct symt_data*)type)->type; + X(DWORD) = symt_ptr2index(module, ((const struct symt_data*)type)->type); break; case SymTagFunction: - X(DWORD) = (DWORD)((const struct symt_function*)type)->type; + X(DWORD) = symt_ptr2index(module, ((const struct symt_function*)type)->type); break; case SymTagEnum: - X(DWORD) = (DWORD)((const struct symt_enum*)type)->base_type; + X(DWORD) = symt_ptr2index(module, ((const struct symt_enum*)type)->base_type); break; case SymTagFunctionArgType: - X(DWORD) = (DWORD)((const struct symt_function_arg_type*)type)->arg_type; + X(DWORD) = symt_ptr2index(module, ((const struct symt_function_arg_type*)type)->arg_type); break; default: FIXME("Unsupported sym-tag %s for get-type\n", @@ -806,7 +819,7 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req, break; case TI_GET_ARRAYINDEXTYPEID: if (type->tag != SymTagArrayType) return FALSE; - X(DWORD) = (DWORD)((const struct symt_array*)type)->index_type; + X(DWORD) = symt_ptr2index(module, ((const struct symt_array*)type)->index_type); break; case TI_GET_CLASSPARENTID: @@ -854,7 +867,7 @@ BOOL WINAPI SymGetTypeInfo(HANDLE hProcess, DWORD64 ModBase, return FALSE; } - return symt_get_info((struct symt*)TypeId, GetType, pInfo); + return symt_get_info(pair.effective, symt_index2ptr(pair.effective, TypeId), GetType, pInfo); } /****************************************************************** @@ -865,15 +878,15 @@ BOOL WINAPI SymGetTypeFromName(HANDLE hProcess, ULONG64 BaseOfDll, PCSTR Name, PSYMBOL_INFO Symbol) { struct process* pcs = process_find_by_handle(hProcess); - struct module* module; + struct module_pair pair; struct symt* type; if (!pcs) return FALSE; - module = module_find_by_addr(pcs, BaseOfDll, DMT_UNKNOWN); - if (!module) return FALSE; - type = symt_find_type_by_name(module, SymTagNull, Name); + pair.requested = module_find_by_addr(pcs, BaseOfDll, DMT_UNKNOWN); + if (!module_get_debug(&pair)) return FALSE; + type = symt_find_type_by_name(pair.effective, SymTagNull, Name); if (!type) return FALSE; - Symbol->TypeIndex = (DWORD)type; + Symbol->TypeIndex = symt_ptr2index(pair.effective, type); return TRUE; } diff --git a/dll/win32/dbghelp/version.rc b/dll/win32/dbghelp/version.rc new file mode 100644 index 00000000000..1818010180e --- /dev/null +++ b/dll/win32/dbghelp/version.rc @@ -0,0 +1,26 @@ +/* + * Copyright 2009 Louis Lenders + * + * 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 Image Helper" +#define WINE_FILENAME_STR "dbghelp.dll" +#define WINE_FILEVERSION 5,1,2600,3264 +#define WINE_FILEVERSION_STR "5.1.2600.3264" +#define WINE_PRODUCTVERSION 5,1,2600,3264 +#define WINE_PRODUCTVERSION_STR "5.1.2600.3264" + +#include "wine/wine_common_ver.rc" diff --git a/dll/win32/faultrep/faultrep.c b/dll/win32/faultrep/faultrep.c new file mode 100644 index 00000000000..d4bd7131bbb --- /dev/null +++ b/dll/win32/faultrep/faultrep.c @@ -0,0 +1,130 @@ +/* Fault report handling + * + * Copyright 2007 Peter Dons Tychsen + * + * 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 + +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "winreg.h" +#include "wine/debug.h" +#include "wine/unicode.h" + +#include "errorrep.h" + +WINE_DEFAULT_DEBUG_CHANNEL(faultrep); + +static const WCHAR SZ_EXCLUSIONLIST_KEY[] = { + 'S','o','f','t','w','a','r','e','\\', + 'M','i','c','r','o','s','o','f','t','\\', + 'P','C','H','e','a','l','t','h','\\', + 'E','r','r','o','r','R','e','p','o','r','t','i','n','g','\\', + 'E','x','c','l','u','s','i','o','n','L','i','s','t', 0}; + +/************************************************************************* + * AddERExcludedApplicationW [FAULTREP.@] + * + * Adds an application to a list of applications for which fault reports + * shouldn't be generated + * + * PARAMS + * lpAppFileName [I] The filename of the application executable + * + * RETURNS + * TRUE on success, FALSE of failure + * + * NOTES + * Wine doesn't use this data but stores it in the registry (in the same place + * as Windows would) in case it will be useful in a future version + * + * According to MSDN this function should succeed even if the user has no write + * access to HKLM. This probably means that there is no error checking. + */ +BOOL WINAPI AddERExcludedApplicationW(LPCWSTR lpAppFileName) +{ + WCHAR *bslash; + DWORD value = 1; + HKEY hkey; + + TRACE("(%s)\n", wine_dbgstr_w(lpAppFileName)); + bslash = strrchrW(lpAppFileName, '\\'); + if (bslash != NULL) + lpAppFileName = bslash + 1; + if (*lpAppFileName == '\0') + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (!RegCreateKeyW(HKEY_LOCAL_MACHINE, SZ_EXCLUSIONLIST_KEY, &hkey)) + { + RegSetValueExW(hkey, lpAppFileName, 0, REG_DWORD, (LPBYTE)&value, sizeof(value)); + RegCloseKey(hkey); + } + + return TRUE; +} + +/************************************************************************* + * AddERExcludedApplicationA [FAULTREP.@] + * + * See AddERExcludedApplicationW + */ +BOOL WINAPI AddERExcludedApplicationA(LPCSTR lpAppFileName) +{ + int len = MultiByteToWideChar(CP_ACP, 0, lpAppFileName, -1, NULL, 0); + WCHAR *wstr; + BOOL ret; + + TRACE("(%s)\n", wine_dbgstr_a(lpAppFileName)); + if (len == 0) + return FALSE; + wstr = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*len); + MultiByteToWideChar(CP_ACP, 0, lpAppFileName, -1, wstr, len); + ret = AddERExcludedApplicationW(wstr); + HeapFree(GetProcessHeap(), 0, wstr); + return ret; +} + +/************************************************************************* + * ReportFault [FAULTREP.@] + */ +EFaultRepRetVal WINAPI ReportFault(LPEXCEPTION_POINTERS pep, DWORD dwOpt) +{ + FIXME("%p 0x%x stub\n", pep, dwOpt); + return frrvOk; +} + +/*********************************************************************** + * DllMain. + */ +BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, LPVOID reserved) +{ + switch(reason) + { + case DLL_WINE_PREATTACH: + return FALSE; + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(inst); + break; + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} diff --git a/dll/win32/faultrep/faultrep.rbuild b/dll/win32/faultrep/faultrep.rbuild new file mode 100644 index 00000000000..aeeb3afeca5 --- /dev/null +++ b/dll/win32/faultrep/faultrep.rbuild @@ -0,0 +1,9 @@ + + + . + include/reactos/wine + + wine + advapi32 + faultrep.c + diff --git a/dll/win32/faultrep/faultrep.spec b/dll/win32/faultrep/faultrep.spec new file mode 100644 index 00000000000..77e543fa779 --- /dev/null +++ b/dll/win32/faultrep/faultrep.spec @@ -0,0 +1,14 @@ +@ stdcall AddERExcludedApplicationA(str) +@ stdcall AddERExcludedApplicationW(wstr) +@ stub CreateMinidumpA +@ stub CreateMinidumpW +@ stub ReportEREvent +@ stub ReportEREventDW +@ stdcall ReportFault(ptr long) +@ stub ReportFaultDWM +@ stub ReportFaultFromQueue +@ stub ReportFaultToQueue +@ stub ReportHang +@ stub ReportKernelFaultA +@ stub ReportKernelFaultDWW +@ stub ReportKernelFaultW diff --git a/dll/win32/kernel32/file/dir.c b/dll/win32/kernel32/file/dir.c index c89afb6e465..97c04470e75 100644 --- a/dll/win32/kernel32/file/dir.c +++ b/dll/win32/kernel32/file/dir.c @@ -837,6 +837,12 @@ SearchPathA ( DWORD RetValue = 0; NTSTATUS Status = STATUS_SUCCESS; + if (!lpFileName) + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + RtlInitAnsiString (&Path, (LPSTR)lpPath); RtlInitAnsiString (&FileName, @@ -985,6 +991,12 @@ SearchPathW(LPCWSTR lpPath, { DWORD ret = 0; + if (!lpFileName || !lpFileName[0]) + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + /* If the name contains an explicit path, ignore the path */ if (ContainsPath(lpFileName)) { diff --git a/dll/win32/kernel32/misc/profile.c b/dll/win32/kernel32/misc/profile.c index 09b7c76806a..e327029f378 100644 --- a/dll/win32/kernel32/misc/profile.c +++ b/dll/win32/kernel32/misc/profile.c @@ -993,7 +993,7 @@ static INT PROFILE_GetSectionNames( LPWSTR buffer, UINT len ) * */ static INT PROFILE_GetString( LPCWSTR section, LPCWSTR key_name, - LPCWSTR def_val, LPWSTR buffer, UINT len, BOOL win32 ) + LPCWSTR def_val, LPWSTR buffer, UINT len ) { PROFILEKEY *key = NULL; static const WCHAR empty_strW[] = { 0 }; @@ -1114,16 +1114,12 @@ UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val ) return GetPrivateProfileIntW( section, entry, def_val, L"win.ini" ); } -/* - * if win32, copy: - * - Section names if 'section' is NULL - * - Keys in a Section if 'entry' is NULL - * (see MSDN doc for GetPrivateProfileString) +/*********************************************************************** + * GetPrivateProfileStringW (KERNEL32.@) */ -static int PROFILE_GetPrivateProfileString( LPCWSTR section, LPCWSTR entry, - LPCWSTR def_val, LPWSTR buffer, - UINT len, LPCWSTR filename, - BOOL win32 ) +DWORD WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry, + LPCWSTR def_val, LPWSTR buffer, + DWORD len, LPCWSTR filename ) { int ret; LPWSTR defval_tmp = NULL; @@ -1141,30 +1137,30 @@ static int PROFILE_GetPrivateProfileString( LPCWSTR section, LPCWSTR entry, if (p >= def_val) { - int len = (int)(p - def_val) + 1; + int len = (int)(p - def_val) + 1; - defval_tmp = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)); - if (!defval_tmp) return 0; - memcpy(defval_tmp, def_val, len * sizeof(WCHAR)); - defval_tmp[len] = '\0'; - def_val = defval_tmp; + defval_tmp = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)); + if (!defval_tmp) return 0; + memcpy(defval_tmp, def_val, len * sizeof(WCHAR)); + defval_tmp[len] = '\0'; + def_val = defval_tmp; } } RtlEnterCriticalSection( &PROFILE_CritSect ); if (PROFILE_Open( filename, FALSE )) { - if (win32 && (section == NULL)) + if (section == NULL) ret = PROFILE_GetSectionNames(buffer, len); else /* PROFILE_GetString can handle the 'entry == NULL' case */ - ret = PROFILE_GetString( section, entry, def_val, buffer, len, win32 ); + ret = PROFILE_GetString( section, entry, def_val, buffer, len ); } else if (buffer && def_val) { lstrcpynW( buffer, def_val, len ); ret = wcslen( buffer ); } - else - ret = 0; + else + ret = 0; RtlLeaveCriticalSection( &PROFILE_CritSect ); @@ -1175,7 +1171,6 @@ static int PROFILE_GetPrivateProfileString( LPCWSTR section, LPCWSTR entry, return ret; } - /*********************************************************************** * GetPrivateProfileStringA (KERNEL32.@) */ @@ -1219,21 +1214,6 @@ DWORD WINAPI GetPrivateProfileStringA( LPCSTR section, LPCSTR entry, return ret; } -/*********************************************************************** - * GetPrivateProfileStringW (KERNEL32.@) - */ -DWORD WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry, - LPCWSTR def_val, LPWSTR buffer, - DWORD len, LPCWSTR filename ) -{ - DPRINT("(%S, %S, %S, %p, %d, %S)\n", - section, entry, def_val, buffer, len, filename); - - return PROFILE_GetPrivateProfileString( section, entry, def_val, - buffer, len, filename, TRUE ); -} - - /*********************************************************************** * GetProfileStringA (KERNEL32.@) */ @@ -1244,7 +1224,6 @@ DWORD WINAPI GetProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val, buffer, len, "win.ini" ); } - /*********************************************************************** * GetProfileStringW (KERNEL32.@) */ @@ -1853,10 +1832,19 @@ WritePrivateProfileStructA (LPCSTR section, LPCSTR key, /*********************************************************************** - * CloseProfileUserMapping + * OpenProfileUserMapping (KERNEL32.@) */ -BOOL WINAPI -CloseProfileUserMapping(VOID) +BOOL WINAPI OpenProfileUserMapping(VOID) +{ + DPRINT1("(), stub!\n"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +/*********************************************************************** + * CloseProfileUserMapping (KERNEL32.@) + */ +BOOL WINAPI CloseProfileUserMapping(VOID) { DPRINT1("(), stub!\n"); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); diff --git a/dll/win32/kernel32/misc/stubs.c b/dll/win32/kernel32/misc/stubs.c index ecc9010d57d..d22e9baed17 100644 --- a/dll/win32/kernel32/misc/stubs.c +++ b/dll/win32/kernel32/misc/stubs.c @@ -1156,14 +1156,6 @@ OpenDataFile(HANDLE hFile, DWORD dwUnused) return FALSE; } -BOOL -WINAPI -OpenProfileUserMapping(VOID) -{ - STUB; - return FALSE; -} - BOOL WINAPI PrivMoveFileIdentityW(DWORD Unknown1, DWORD Unknown2, DWORD Unknown3) diff --git a/dll/win32/shell32/shell32_main.c b/dll/win32/shell32/shell32_main.c index f4ae815ade4..2bf6502443f 100644 --- a/dll/win32/shell32/shell32_main.c +++ b/dll/win32/shell32/shell32_main.c @@ -495,7 +495,7 @@ DWORD_PTR WINAPI SHGetFileInfoW(LPCWSTR path,DWORD dwFileAttributes, static const WCHAR p1W[] = {'%','1',0}; WCHAR sTemp [MAX_PATH]; - szExt = (LPWSTR) PathFindExtensionW(szFullPath); + szExt = PathFindExtensionW(szFullPath); TRACE("szExt=%s\n", debugstr_w(szExt)); if ( szExt && HCR_MapTypeToValueW(szExt, sTemp, MAX_PATH, TRUE) && diff --git a/dll/win32/shell32/shellord.c b/dll/win32/shell32/shellord.c index ff9025c4e0e..c25ddff3803 100644 --- a/dll/win32/shell32/shellord.c +++ b/dll/win32/shell32/shellord.c @@ -1673,6 +1673,14 @@ UINT WINAPI SHAddFromPropSheetExtArray(HPSXA hpsxa, LPFNADDPROPSHEETPAGE lpfnAdd return 0; } +/************************************************************************* + * SHCreatePropSheetExtArray [SHELL32.168] + */ +HPSXA WINAPI SHCreatePropSheetExtArray(HKEY hKey, LPCWSTR pszSubKey, UINT max_iface) +{ + return SHCreatePropSheetExtArrayEx(hKey, pszSubKey, max_iface, NULL); +} + /************************************************************************* * SHCreatePropSheetExtArrayEx [SHELL32.194] */ @@ -1780,15 +1788,6 @@ HPSXA WINAPI SHCreatePropSheetExtArrayEx(HKEY hKey, LPCWSTR pszSubKey, UINT max_ return (HPSXA)psxa; } -/************************************************************************* - * SHCreatePropSheetExtArray [SHELL32.168] - */ -HPSXA WINAPI SHCreatePropSheetExtArray(HKEY hKey, LPCWSTR pszSubKey, UINT max_iface) -{ - return SHCreatePropSheetExtArrayEx(hKey, pszSubKey, max_iface, NULL); -} - - /************************************************************************* * SHReplaceFromPropSheetExtArray [SHELL32.170] */ diff --git a/dll/win32/shell32/shlfileop.c b/dll/win32/shell32/shlfileop.c index e3bdf6eac31..6992d187ee4 100644 --- a/dll/win32/shell32/shlfileop.c +++ b/dll/win32/shell32/shlfileop.c @@ -531,9 +531,15 @@ static DWORD SHNotifyMoveFileW(LPCWSTR src, LPCWSTR dest) static DWORD SHNotifyCopyFileW(LPCWSTR src, LPCWSTR dest, BOOL bFailIfExists) { BOOL ret; + DWORD attribs; TRACE("(%s %s %s)\n", debugstr_w(src), debugstr_w(dest), bFailIfExists ? "failIfExists" : ""); + /* Destination file may already exist with read only attribute */ + attribs = GetFileAttributesW(dest); + if (IsAttrib(attribs, FILE_ATTRIBUTE_READONLY)) + SetFileAttributesW(dest, attribs & ~FILE_ATTRIBUTE_READONLY); + ret = CopyFileW(src, dest, bFailIfExists); if (ret) { @@ -1479,7 +1485,7 @@ int WINAPI SHFileOperationW(LPSHFILEOPSTRUCTW lpFileOp) /************************************************************************* * SHFreeNameMappings [shell32.246] * - * Free the mapping handle returned by SHFileoperation if FOF_WANTSMAPPINGHANDLE + * Free the mapping handle returned by SHFileOperation if FOF_WANTSMAPPINGHANDLE * was specified. * * PARAMS @@ -1496,12 +1502,12 @@ void WINAPI SHFreeNameMappings(HANDLE hNameMapping) for (; i>= 0; i--) { - LPSHNAMEMAPPINGW lp = DSA_GetItemPtr((HDSA)hNameMapping, i); + LPSHNAMEMAPPINGW lp = DSA_GetItemPtr(hNameMapping, i); SHFree(lp->pszOldPath); SHFree(lp->pszNewPath); } - DSA_Destroy((HDSA)hNameMapping); + DSA_Destroy(hNameMapping); } } diff --git a/dll/win32/user32/windows/menu.c b/dll/win32/user32/windows/menu.c index 3f3916c6481..58c4a95243e 100644 --- a/dll/win32/user32/windows/menu.c +++ b/dll/win32/user32/windows/menu.c @@ -12,15 +12,25 @@ /* INCLUDES ******************************************************************/ #include - #include -WINE_DEFAULT_DEBUG_CHANNEL(user32); LRESULT DefWndNCPaint(HWND hWnd, HRGN hRgn, BOOL Active); +WINE_DEFAULT_DEBUG_CHANNEL(menu); + /* internal popup menu window messages */ -#define MM_SETMENUHANDLE (WM_USER + 0) -#define MM_GETMENUHANDLE (WM_USER + 1) + +#define MM_SETMENUHANDLE (WM_USER + 0) +#define MM_GETMENUHANDLE (WM_USER + 1) + +/* internal flags for menu tracking */ + +#define TF_ENDMENU 0x10000 +#define TF_SUSPENDPOPUP 0x20000 +#define TF_SKIPREMOVE 0x40000 + +#define ITEM_PREV -1 +#define ITEM_NEXT 1 /* Internal MenuTrackMenu() flags */ #define TPM_INTERNAL 0xF0000000 @@ -28,13 +38,14 @@ LRESULT DefWndNCPaint(HWND hWnd, HRGN hRgn, BOOL Active); #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */ #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */ -/* TYPES *********************************************************************/ #define MENU_TYPE_MASK (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR) #define MENU_ITEM_TYPE(flags) ((flags) & MENU_TYPE_MASK) + +/* macro to test that flags do not indicate bitmap, ownerdraw or separator */ #define IS_STRING_ITEM(flags) (MF_STRING == MENU_ITEM_TYPE(flags)) -#define IS_BITMAP_ITEM(flags) (MF_BITMAP == MENU_ITEM_TYPE(flags)) +#define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1)) #define IS_SYSTEM_MENU(MenuInfo) \ (0 == ((MenuInfo)->Flags & MF_POPUP) && 0 != ((MenuInfo)->Flags & MF_SYSMENU)) @@ -42,27 +53,25 @@ LRESULT DefWndNCPaint(HWND hWnd, HRGN hRgn, BOOL Active); #define IS_SYSTEM_POPUP(MenuInfo) \ (0 != ((MenuInfo)->Flags & MF_POPUP) && 0 != ((MenuInfo)->Flags & MF_SYSMENU)) -#define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1)) +#define IS_BITMAP_ITEM(flags) (MF_BITMAP == MENU_ITEM_TYPE(flags)) + +/* Use global popup window because there's no way 2 menus can + * be tracked at the same time. */ +static HWND top_popup; + +/* Flag set by EndMenu() to force an exit from menu tracking */ +static BOOL fEndMenu = FALSE; #define MENU_ITEM_HBMP_SPACE (5) #define MENU_BAR_ITEMS_SPACE (12) #define SEPARATOR_HEIGHT (5) #define MENU_TAB_SPACE (8) -#define ITEM_PREV -1 -#define ITEM_NEXT 1 - #define MAKEINTATOMA(atom) ((LPCSTR)((ULONG_PTR)((WORD)(atom)))) #define MAKEINTATOMW(atom) ((LPCWSTR)((ULONG_PTR)((WORD)(atom)))) #define POPUPMENU_CLASS_ATOMA MAKEINTATOMA(32768) /* PopupMenu */ #define POPUPMENU_CLASS_ATOMW MAKEINTATOMW(32768) /* PopupMenu */ -/* internal flags for menu tracking */ - -#define TF_ENDMENU 0x0001 -#define TF_SUSPENDPOPUP 0x0002 -#define TF_SKIPREMOVE 0x0004 - typedef struct { UINT TrackFlags; @@ -72,8 +81,6 @@ typedef struct POINT Pt; } MTRACKER; -//static LRESULT WINAPI PopupMenuWndProcA(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam); -//static LRESULT WINAPI PopupMenuWndProcW(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); /********************************************************************* * PopupMenu class descriptor @@ -89,14 +96,6 @@ const struct builtin_class_descr POPUPMENU_builtin_class = (HBRUSH)(COLOR_MENU + 1) /* brush */ }; - -/* INTERNAL FUNCTIONS ********************************************************/ - -/* Rip the fun and easy to use and fun WINE unicode string manipulation routines. - * Of course I didnt copy the ASM code because we want this to be portable - * and it needs to go away. - */ - #ifndef GET_WORD #define GET_WORD(ptr) (*(WORD *)(ptr)) #endif @@ -107,13 +106,6 @@ const struct builtin_class_descr POPUPMENU_builtin_class = HFONT hMenuFont = NULL; HFONT hMenuFontBold = NULL; -/* Flag set by EndMenu() to force an exit from menu tracking */ -static BOOL fEndMenu = FALSE; - -/* Use global popup window because there's no way 2 menus can - * be tracked at the same time. */ -static HWND TopPopup; - /* Dimension of the menu bitmaps */ static HBITMAP BmpSysMenu = NULL; @@ -276,6 +268,157 @@ MenuCleanupAllRosMenuItemInfo(PROSMENUITEMINFO ItemInfo) HeapFree(GetProcessHeap(), 0, ItemInfo); } +/*********************************************************************** + * MenuInitSysMenuPopup + * + * Grey the appropriate items in System menu. + */ +void FASTCALL MenuInitSysMenuPopup(HMENU hmenu, DWORD style, DWORD clsStyle, LONG HitTest ) +{ + BOOL gray; + UINT DefItem; + #if 0 + MENUITEMINFOW mii; + #endif + + gray = !(style & WS_THICKFRAME) || (style & (WS_MAXIMIZE | WS_MINIMIZE)); + EnableMenuItem( hmenu, SC_SIZE, (gray ? MF_GRAYED : MF_ENABLED) ); + gray = ((style & WS_MAXIMIZE) != 0); + EnableMenuItem( hmenu, SC_MOVE, (gray ? MF_GRAYED : MF_ENABLED) ); + gray = !(style & WS_MINIMIZEBOX) || (style & WS_MINIMIZE); + EnableMenuItem( hmenu, SC_MINIMIZE, (gray ? MF_GRAYED : MF_ENABLED) ); + gray = !(style & WS_MAXIMIZEBOX) || (style & WS_MAXIMIZE); + EnableMenuItem( hmenu, SC_MAXIMIZE, (gray ? MF_GRAYED : MF_ENABLED) ); + gray = !(style & (WS_MAXIMIZE | WS_MINIMIZE)); + EnableMenuItem( hmenu, SC_RESTORE, (gray ? MF_GRAYED : MF_ENABLED) ); + gray = (clsStyle & CS_NOCLOSE) != 0; + + /* The menu item must keep its state if it's disabled */ + if(gray) + EnableMenuItem( hmenu, SC_CLOSE, MF_GRAYED); + + /* Set default menu item */ + if(style & WS_MINIMIZE) DefItem = SC_RESTORE; + else if(HitTest == HTCAPTION) DefItem = ((style & (WS_MAXIMIZE | WS_MINIMIZE)) ? SC_RESTORE : SC_MAXIMIZE); + else DefItem = SC_CLOSE; +#if 0 + mii.cbSize = sizeof(MENUITEMINFOW); + mii.fMask |= MIIM_STATE; + if((DefItem != SC_CLOSE) && GetMenuItemInfoW(hmenu, DefItem, FALSE, &mii) && + (mii.fState & (MFS_GRAYED | MFS_DISABLED))) DefItem = SC_CLOSE; +#endif + SetMenuDefaultItem(hmenu, DefItem, MF_BYCOMMAND); +} + +/****************************************************************************** + * + * UINT MenuGetStartOfNextColumn( + * PROSMENUINFO MenuInfo) + * + *****************************************************************************/ +static UINT MenuGetStartOfNextColumn( + PROSMENUINFO MenuInfo) +{ + PROSMENUITEMINFO MenuItems; + UINT i; + + i = MenuInfo->FocusedItem; + if ( i == NO_SELECTED_ITEM ) + return i; + + if (MenuGetAllRosMenuItemInfo(MenuInfo->Self, &MenuItems) <= 0) + return NO_SELECTED_ITEM; + + for (i++ ; i < MenuInfo->MenuItemCount; i++) + if (0 != (MenuItems[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK))) + return i; + + return NO_SELECTED_ITEM; +} + +/****************************************************************************** + * + * UINT MenuGetStartOfPrevColumn( + * PROSMENUINFO MenuInfo) + * + *****************************************************************************/ + +static UINT FASTCALL MenuGetStartOfPrevColumn( + PROSMENUINFO MenuInfo) +{ + PROSMENUITEMINFO MenuItems; + UINT i; + + if (!MenuInfo->FocusedItem || MenuInfo->FocusedItem == NO_SELECTED_ITEM) + return NO_SELECTED_ITEM; + + if (MenuGetAllRosMenuItemInfo(MenuInfo->Self, &MenuItems) <= 0) + return NO_SELECTED_ITEM; + + /* Find the start of the column */ + for (i = MenuInfo->FocusedItem; + 0 != i && 0 == (MenuItems[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK)); + --i) + { + ; /* empty */ + } + + if (i == 0) + { + MenuCleanupAllRosMenuItemInfo(MenuItems); + return NO_SELECTED_ITEM; + } + + for (--i; 0 != i; --i) + if (MenuItems[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK)) + break; + + MenuCleanupAllRosMenuItemInfo(MenuItems); + TRACE("ret %d.\n", i ); + + return i; +} + +/*********************************************************************** + * MenuFindSubMenu + * + * Find a Sub menu. Return the position of the submenu, and modifies + * *hmenu in case it is found in another sub-menu. + * If the submenu cannot be found, NO_SELECTED_ITEM is returned. + */ +static UINT FASTCALL MenuFindSubMenu(HMENU *hmenu, HMENU hSubTarget ) +{ + ROSMENUINFO menu; + UINT i; + ROSMENUITEMINFO item; + if (((*hmenu)==(HMENU)0xffff) || + (!MenuGetRosMenuInfo(&menu, *hmenu))) + return NO_SELECTED_ITEM; + + MenuInitRosMenuItemInfo(&item); + for (i = 0; i < menu.MenuItemCount; i++) { + if (! MenuGetRosMenuItemInfo(menu.Self, i, &item)) + { + MenuCleanupRosMenuItemInfo(&item); + return NO_SELECTED_ITEM; + } + if (!(item.fType & MF_POPUP)) continue; + if (item.hSubMenu == hSubTarget) { + MenuCleanupRosMenuItemInfo(&item); + return i; + } + else { + HMENU hsubmenu = item.hSubMenu; + UINT pos = MenuFindSubMenu(&hsubmenu, hSubTarget ); + if (pos != NO_SELECTED_ITEM) { + *hmenu = hsubmenu; + return pos; + } + } + } + MenuCleanupRosMenuItemInfo(&item); + return NO_SELECTED_ITEM; +} /*********************************************************************** * MenuLoadBitmaps @@ -293,71 +436,6 @@ MenuLoadBitmaps(VOID) } } -/*********************************************************************** - * MenuGetBitmapItemSize - * - * Get the size of a bitmap item. - */ -static void FASTCALL -MenuGetBitmapItemSize(PROSMENUITEMINFO lpitem, SIZE *Size, HWND WndOwner) -{ - BITMAP Bm; - HBITMAP Bmp = lpitem->hbmpItem; - - Size->cx = Size->cy = 0; - - /* check if there is a magic menu item associated with this item */ - if (IS_MAGIC_BITMAP(Bmp)) - { - switch((INT_PTR) Bmp) - { - case (INT_PTR)HBMMENU_CALLBACK: - { - MEASUREITEMSTRUCT measItem; - measItem.CtlType = ODT_MENU; - measItem.CtlID = 0; - measItem.itemID = lpitem->wID; - measItem.itemWidth = lpitem->Rect.right - lpitem->Rect.left; - measItem.itemHeight = lpitem->Rect.bottom - lpitem->Rect.top; - measItem.itemData = lpitem->dwItemData; - SendMessageW( WndOwner, WM_MEASUREITEM, lpitem->wID, (LPARAM)&measItem); - Size->cx = measItem.itemWidth; - Size->cy = measItem.itemHeight; - return; - } - break; - - case (INT_PTR) HBMMENU_SYSTEM: - if (0 != lpitem->dwItemData) - { - Bmp = (HBITMAP) lpitem->dwItemData; - break; - } - /* fall through */ - case (INT_PTR) HBMMENU_MBAR_RESTORE: - case (INT_PTR) HBMMENU_MBAR_MINIMIZE: - case (INT_PTR) HBMMENU_MBAR_CLOSE: - case (INT_PTR) HBMMENU_MBAR_MINIMIZE_D: - case (INT_PTR) HBMMENU_MBAR_CLOSE_D: - case (INT_PTR) HBMMENU_POPUP_CLOSE: - case (INT_PTR) HBMMENU_POPUP_RESTORE: - case (INT_PTR) HBMMENU_POPUP_MAXIMIZE: - case (INT_PTR) HBMMENU_POPUP_MINIMIZE: - /* FIXME: Why we need to subtract these magic values? */ - /* to make them smaller than the menu bar? */ - Size->cx = GetSystemMetrics(SM_CXSIZE) - 2; - Size->cy = GetSystemMetrics(SM_CYSIZE) - 4; - return; - } - } - - if (GetObjectW(Bmp, sizeof(BITMAP), &Bm)) - { - Size->cx = Bm.bmWidth; - Size->cy = Bm.bmHeight; - } -} - /*********************************************************************** * MenuDrawPopupGlyph * @@ -422,96 +500,225 @@ MenuDrawPopupGlyph(HDC dc, LPRECT r, INT_PTR popupMagic, BOOL inactive, BOOL hil DeleteObject(hFont); } +/*********************************************************************** + * MenuFindItemByKey + * + * Find the menu item selected by a key press. + * Return item id, -1 if none, -2 if we should close the menu. + */ +static UINT FASTCALL MenuFindItemByKey(HWND WndOwner, PROSMENUINFO MenuInfo, + WCHAR Key, BOOL ForceMenuChar) +{ + ROSMENUINFO SysMenuInfo; + PROSMENUITEMINFO Items, ItemInfo; + LRESULT MenuChar; + UINT i; + + TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char) Key, Key, MenuInfo); + + if (NULL == MenuInfo || ! IsMenu(MenuInfo->Self)) + { + if (MenuGetRosMenuInfo(&SysMenuInfo, GetSystemMenu(WndOwner, FALSE))) + { + MenuInfo = &SysMenuInfo; + } + else + { + MenuInfo = NULL; + } + } + + if (NULL != MenuInfo) + { + if (MenuGetAllRosMenuItemInfo(MenuInfo->Self, &Items) <= 0) + { + return -1; + } + if (! ForceMenuChar) + { + Key = toupperW(Key); + ItemInfo = Items; + for (i = 0; i < MenuInfo->MenuItemCount; i++, ItemInfo++) + { + if ((ItemInfo->Text) && NULL != ItemInfo->dwTypeData) + { + WCHAR *p = (WCHAR *) ItemInfo->dwTypeData - 2; + do + { + p = strchrW(p + 2, '&'); + } + while (NULL != p && L'&' == p[1]); + if (NULL != p && (toupperW(p[1]) == Key)) + { + return i; + } + } + } + } + + MenuChar = SendMessageW(WndOwner, WM_MENUCHAR, + MAKEWPARAM(Key, MenuInfo->Flags), (LPARAM) MenuInfo->Self); + if (2 == HIWORD(MenuChar)) + { + return LOWORD(MenuChar); + } + if (1 == HIWORD(MenuChar)) + { + return (UINT) (-2); + } + } + + return (UINT)(-1); +} + +/*********************************************************************** + * MenuGetBitmapItemSize + * + * Get the size of a bitmap item. + */ +static void FASTCALL MenuGetBitmapItemSize(PROSMENUITEMINFO lpitem, SIZE *size, + HWND WndOwner) +{ + BITMAP bm; + HBITMAP bmp = lpitem->hbmpItem; + + size->cx = size->cy = 0; + + /* check if there is a magic menu item associated with this item */ + if (IS_MAGIC_BITMAP(bmp)) + { + switch((INT_PTR) bmp) + { + case (INT_PTR)HBMMENU_CALLBACK: + { + MEASUREITEMSTRUCT measItem; + measItem.CtlType = ODT_MENU; + measItem.CtlID = 0; + measItem.itemID = lpitem->wID; + measItem.itemWidth = lpitem->Rect.right - lpitem->Rect.left; + measItem.itemHeight = lpitem->Rect.bottom - lpitem->Rect.top; + measItem.itemData = lpitem->dwItemData; + SendMessageW( WndOwner, WM_MEASUREITEM, lpitem->wID, (LPARAM)&measItem); + size->cx = measItem.itemWidth; + size->cy = measItem.itemHeight; + return; + } + break; + + case (INT_PTR) HBMMENU_SYSTEM: + if (0 != lpitem->dwItemData) + { + bmp = (HBITMAP) lpitem->dwItemData; + break; + } + /* fall through */ + case (INT_PTR) HBMMENU_MBAR_RESTORE: + case (INT_PTR) HBMMENU_MBAR_MINIMIZE: + case (INT_PTR) HBMMENU_MBAR_CLOSE: + case (INT_PTR) HBMMENU_MBAR_MINIMIZE_D: + case (INT_PTR) HBMMENU_MBAR_CLOSE_D: + case (INT_PTR) HBMMENU_POPUP_CLOSE: + case (INT_PTR) HBMMENU_POPUP_RESTORE: + case (INT_PTR) HBMMENU_POPUP_MAXIMIZE: + case (INT_PTR) HBMMENU_POPUP_MINIMIZE: + /* FIXME: Why we need to subtract these magic values? */ + /* to make them smaller than the menu bar? */ + size->cx = GetSystemMetrics(SM_CXSIZE) - 2; + size->cy = GetSystemMetrics(SM_CYSIZE) - 4; + return; + } + } + + if (GetObjectW(bmp, sizeof(BITMAP), &bm)) + { + size->cx = bm.bmWidth; + size->cy = bm.bmHeight; + } +} + /*********************************************************************** * MenuDrawBitmapItem * * Draw a bitmap item. */ -static void FASTCALL -MenuDrawBitmapItem(HDC Dc, PROSMENUITEMINFO Item, const RECT *Rect, +static void FASTCALL MenuDrawBitmapItem(HDC hdc, PROSMENUITEMINFO lpitem, const RECT *rect, HMENU hmenu, HWND WndOwner, UINT odaction, BOOL MenuBar) { - BITMAP Bm; - DWORD Rop; - HDC DcMem; - HBITMAP Bmp; - int w = Rect->right - Rect->left; - int h = Rect->bottom - Rect->top; - int BmpXoffset = 0; - int Left, Top; - HBITMAP hbmpToDraw = (HBITMAP) Item->hbmpItem; - Bmp = hbmpToDraw; + BITMAP bm; + DWORD rop; + HDC hdcMem; + HBITMAP bmp; + int w = rect->right - rect->left; + int h = rect->bottom - rect->top; + int bmp_xoffset = 0; + int left, top; + HBITMAP hbmToDraw = lpitem->hbmpItem; + bmp = hbmToDraw; - /* Check if there is a magic menu item associated with this item */ - if (IS_MAGIC_BITMAP(hbmpToDraw)) + /* Check if there is a magic menu item associated with this item */ + if (IS_MAGIC_BITMAP(hbmToDraw)) { - UINT Flags = 0; - RECT r; + UINT flags = 0; + RECT r; - r = *Rect; - switch ((INT_PTR)hbmpToDraw) + r = *rect; + switch ((INT_PTR)hbmToDraw) { - case (INT_PTR) HBMMENU_SYSTEM: - if (NULL != Item->dwTypeData) - { - Bmp = (HBITMAP)Item->dwTypeData; - if (! GetObjectW(Bmp, sizeof(BITMAP), &Bm)) - { - return; - } - } + case (INT_PTR)HBMMENU_SYSTEM: + if (lpitem->dwTypeData) + { + bmp = (HBITMAP)lpitem->dwTypeData; + if (!GetObjectW( bmp, sizeof(bm), &bm )) return; + } else - { + { if (!BmpSysMenu) BmpSysMenu = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE)); - Bmp = BmpSysMenu; - if (! GetObjectW(Bmp, sizeof(BITMAP), &Bm)) - { - return; - } + bmp = BmpSysMenu; + if (! GetObjectW(bmp, sizeof(bm), &bm)) return; /* only use right half of the bitmap */ - BmpXoffset = Bm.bmWidth / 2; - Bm.bmWidth -= BmpXoffset; - } + bmp_xoffset = bm.bmWidth / 2; + bm.bmWidth -= bmp_xoffset; + } goto got_bitmap; - case (INT_PTR) HBMMENU_MBAR_RESTORE: - Flags = DFCS_CAPTIONRESTORE; + case (INT_PTR)HBMMENU_MBAR_RESTORE: + flags = DFCS_CAPTIONRESTORE; break; - case (INT_PTR) HBMMENU_MBAR_MINIMIZE: + case (INT_PTR)HBMMENU_MBAR_MINIMIZE: r.right += 1; - Flags = DFCS_CAPTIONMIN; + flags = DFCS_CAPTIONMIN; break; - case (INT_PTR) HBMMENU_MBAR_MINIMIZE_D: + case (INT_PTR)HBMMENU_MBAR_MINIMIZE_D: r.right += 1; - Flags = DFCS_CAPTIONMIN | DFCS_INACTIVE; + flags = DFCS_CAPTIONMIN | DFCS_INACTIVE; break; - case (INT_PTR) HBMMENU_MBAR_CLOSE: - Flags = DFCS_CAPTIONCLOSE; + case (INT_PTR)HBMMENU_MBAR_CLOSE: + flags = DFCS_CAPTIONCLOSE; break; - case (INT_PTR) HBMMENU_MBAR_CLOSE_D: - Flags = DFCS_CAPTIONCLOSE | DFCS_INACTIVE; + case (INT_PTR)HBMMENU_MBAR_CLOSE_D: + flags = DFCS_CAPTIONCLOSE | DFCS_INACTIVE; break; - case (INT_PTR) HBMMENU_CALLBACK: + case (INT_PTR)HBMMENU_CALLBACK: { DRAWITEMSTRUCT drawItem; POINT origorg; drawItem.CtlType = ODT_MENU; drawItem.CtlID = 0; - drawItem.itemID = Item->wID; + drawItem.itemID = lpitem->wID; drawItem.itemAction = odaction; - drawItem.itemState = (Item->fState & MF_CHECKED)?ODS_CHECKED:0; - drawItem.itemState |= (Item->fState & MF_DEFAULT)?ODS_DEFAULT:0; - drawItem.itemState |= (Item->fState & MF_DISABLED)?ODS_DISABLED:0; - drawItem.itemState |= (Item->fState & MF_GRAYED)?ODS_GRAYED|ODS_DISABLED:0; - drawItem.itemState |= (Item->fState & MF_HILITE)?ODS_SELECTED:0; + drawItem.itemState = (lpitem->fState & MF_CHECKED)?ODS_CHECKED:0; + drawItem.itemState |= (lpitem->fState & MF_DEFAULT)?ODS_DEFAULT:0; + drawItem.itemState |= (lpitem->fState & MF_DISABLED)?ODS_DISABLED:0; + drawItem.itemState |= (lpitem->fState & MF_GRAYED)?ODS_GRAYED|ODS_DISABLED:0; + drawItem.itemState |= (lpitem->fState & MF_HILITE)?ODS_SELECTED:0; drawItem.hwndItem = (HWND)hmenu; - drawItem.hDC = Dc; - drawItem.rcItem = *Rect; - drawItem.itemData = Item->dwItemData; + drawItem.hDC = hdc; + drawItem.rcItem = *rect; + drawItem.itemData = lpitem->dwItemData; /* some applications make this assumption on the DC's origin */ - SetViewportOrgEx( Dc, Item->Rect.left, Item->Rect.top, &origorg); - OffsetRect( &drawItem.rcItem, - Item->Rect.left, - Item->Rect.top); + SetViewportOrgEx( hdc, lpitem->Rect.left, lpitem->Rect.top, &origorg); + OffsetRect( &drawItem.rcItem, - lpitem->Rect.left, - lpitem->Rect.top); SendMessageW( WndOwner, WM_DRAWITEM, 0, (LPARAM)&drawItem); - SetViewportOrgEx( Dc, origorg.x, origorg.y, NULL); + SetViewportOrgEx( hdc, origorg.x, origorg.y, NULL); return; } break; @@ -520,37 +727,413 @@ MenuDrawBitmapItem(HDC Dc, PROSMENUITEMINFO Item, const RECT *Rect, case (INT_PTR) HBMMENU_POPUP_RESTORE: case (INT_PTR) HBMMENU_POPUP_MAXIMIZE: case (INT_PTR) HBMMENU_POPUP_MINIMIZE: - MenuDrawPopupGlyph(Dc, &r, (INT_PTR)hbmpToDraw, Item->fState & MF_GRAYED, Item->fState & MF_HILITE); + MenuDrawPopupGlyph(hdc, &r, (INT_PTR)hbmToDraw, lpitem->fState & MF_GRAYED, lpitem->fState & MF_HILITE); return; } InflateRect(&r, -1, -1); - if (0 != (Item->fState & MF_HILITE)) - { - Flags |= DFCS_PUSHED; + if (0 != (lpitem->fState & MF_HILITE)) + { + flags |= DFCS_PUSHED; + } + DrawFrameControl(hdc, &r, DFC_CAPTION, flags); + return; + } + + if (!bmp || !GetObjectW( bmp, sizeof(bm), &bm )) return; + + got_bitmap: + hdcMem = CreateCompatibleDC( hdc ); + SelectObject( hdcMem, bmp ); + + /* handle fontsize > bitmap_height */ + top = (h>bm.bmHeight) ? rect->top+(h-bm.bmHeight)/2 : rect->top; + left=rect->left; + rop=((lpitem->fState & MF_HILITE) && !IS_MAGIC_BITMAP(hbmToDraw)) ? NOTSRCCOPY : SRCCOPY; + if ((lpitem->fState & MF_HILITE) && lpitem->hbmpItem) + SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT)); + BitBlt( hdc, left, top, w, h, hdcMem, bmp_xoffset, 0, rop ); + DeleteDC( hdcMem ); +} + +/*********************************************************************** + * MenuCalcItemSize + * + * Calculate the size of the menu item and store it in lpitem->rect. + */ +static void FASTCALL MenuCalcItemSize( HDC hdc, PROSMENUITEMINFO lpitem, PROSMENUINFO MenuInfo, HWND hwndOwner, + INT orgX, INT orgY, BOOL menuBar) +{ + WCHAR *p; + UINT check_bitmap_width = GetSystemMetrics( SM_CXMENUCHECK ); + INT itemheight = 0; + + TRACE("dc=%x owner=%x (%d,%d)\n", hdc, hwndOwner, orgX, orgY); + + MenuCharSize.cx = GdiGetCharDimensions( hdc, NULL, &MenuCharSize.cy ); + + SetRect( &lpitem->Rect, orgX, orgY, orgX, orgY ); + + if (lpitem->fType & MF_OWNERDRAW) + { + MEASUREITEMSTRUCT mis; + mis.CtlType = ODT_MENU; + mis.CtlID = 0; + mis.itemID = lpitem->wID; + mis.itemData = lpitem->dwItemData; + mis.itemHeight = HIWORD( GetDialogBaseUnits()); + mis.itemWidth = 0; + SendMessageW( hwndOwner, WM_MEASUREITEM, 0, (LPARAM)&mis ); + /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average + * width of a menufont character to the width of an owner-drawn menu. + */ + lpitem->Rect.right += mis.itemWidth + 2 * MenuCharSize.cx; + + if (menuBar) { + /* under at least win95 you seem to be given a standard + height for the menu and the height value is ignored */ + lpitem->Rect.bottom += GetSystemMetrics(SM_CYMENUSIZE); + } else + lpitem->Rect.bottom += mis.itemHeight; + + TRACE("id=%04lx size=%dx%d\n", + lpitem->wID, mis.itemWidth, mis.itemHeight); + return; + } + + if (lpitem->fType & MF_SEPARATOR) + { + lpitem->Rect.bottom += SEPARATOR_HEIGHT; + if( !menuBar) + lpitem->Rect.right += check_bitmap_width + MenuCharSize.cx; + return; + } + + lpitem->XTab = 0; + + if (lpitem->hbmpItem) + { + SIZE size; + + if (!menuBar) { + MenuGetBitmapItemSize(lpitem, &size, hwndOwner ); + /* Keep the size of the bitmap in callback mode to be able + * to draw it correctly */ + lpitem->Rect.right = lpitem->Rect.left + size.cx; + if (MenuInfo->maxBmpSize.cx < abs(size.cx) + MENU_ITEM_HBMP_SPACE || + MenuInfo->maxBmpSize.cy < abs(size.cy)) + { + MenuInfo->maxBmpSize.cx = abs(size.cx) + MENU_ITEM_HBMP_SPACE; + MenuInfo->maxBmpSize.cy = abs(size.cy); + } + MenuSetRosMenuInfo(MenuInfo); + itemheight = size.cy + 2; + + if( !(MenuInfo->dwStyle & MNS_NOCHECK)) + lpitem->Rect.right += 2 * check_bitmap_width; + lpitem->Rect.right += 4 + MenuCharSize.cx; + lpitem->XTab = lpitem->Rect.right; + lpitem->Rect.right += check_bitmap_width; + } else /* hbmpItem & MenuBar */ { + MenuGetBitmapItemSize(lpitem, &size, hwndOwner ); + lpitem->Rect.right += size.cx; + if( lpitem->Text) lpitem->Rect.right += 2; + itemheight = size.cy; + + /* Special case: Minimize button doesn't have a space behind it. */ + if (lpitem->hbmpItem == (HBITMAP)HBMMENU_MBAR_MINIMIZE || + lpitem->hbmpItem == (HBITMAP)HBMMENU_MBAR_MINIMIZE_D) + lpitem->Rect.right -= 1; } - DrawFrameControl(Dc, &r, DFC_CAPTION, Flags); - return; + } + else if (!menuBar) { + if( !(MenuInfo->dwStyle & MNS_NOCHECK)) + lpitem->Rect.right += check_bitmap_width; + lpitem->Rect.right += 4 + MenuCharSize.cx; + lpitem->XTab = lpitem->Rect.right; + lpitem->Rect.right += check_bitmap_width; } - if (NULL == Bmp || ! GetObjectW(Bmp, sizeof(BITMAP), &Bm)) + /* it must be a text item - unless it's the system menu */ + if (!(lpitem->fType & MF_SYSMENU) && lpitem->Text) { + HFONT hfontOld = NULL; + RECT rc = lpitem->Rect; + LONG txtheight, txtwidth; + + if ( lpitem->fState & MFS_DEFAULT ) { + hfontOld = SelectObject( hdc, hMenuFontBold ); + } + if (menuBar) { + txtheight = DrawTextW( hdc, lpitem->dwTypeData, -1, &rc, + DT_SINGLELINE|DT_CALCRECT); + lpitem->Rect.right += rc.right - rc.left; + itemheight = max( max( itemheight, txtheight), + GetSystemMetrics( SM_CYMENU) - 1); + lpitem->Rect.right += 2 * MenuCharSize.cx; + } else { + if ((p = strchrW( lpitem->dwTypeData, '\t' )) != NULL) { + RECT tmprc = rc; + LONG tmpheight; + int n = (int)( p - lpitem->dwTypeData); + /* Item contains a tab (only meaningful in popup menus) */ + /* get text size before the tab */ + txtheight = DrawTextW( hdc, lpitem->dwTypeData, n, &rc, + DT_SINGLELINE|DT_CALCRECT); + txtwidth = rc.right - rc.left; + p += 1; /* advance past the Tab */ + /* get text size after the tab */ + tmpheight = DrawTextW( hdc, p, -1, &tmprc, + DT_SINGLELINE|DT_CALCRECT); + lpitem->XTab += txtwidth; + txtheight = max( txtheight, tmpheight); + txtwidth += MenuCharSize.cx + /* space for the tab */ + tmprc.right - tmprc.left; /* space for the short cut */ + } else { + txtheight = DrawTextW( hdc, lpitem->dwTypeData, -1, &rc, + DT_SINGLELINE|DT_CALCRECT); + txtwidth = rc.right - rc.left; + lpitem->XTab += txtwidth; + } + lpitem->Rect.right += 2 + txtwidth; + itemheight = max( itemheight, + max( txtheight + 2, MenuCharSize.cy + 4)); + } + if (hfontOld) SelectObject (hdc, hfontOld); + } else if( menuBar) { + itemheight = max( itemheight, GetSystemMetrics(SM_CYMENU)-1); + } + lpitem->Rect.bottom += itemheight; + TRACE("(%ld,%ld)-(%ld,%ld)\n", lpitem->Rect.left, lpitem->Rect.top, lpitem->Rect.right, lpitem->Rect.bottom); +} + +/*********************************************************************** + * MenuPopupMenuCalcSize + * + * Calculate the size of a popup menu. + */ +static void FASTCALL MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo, HWND WndOwner) +{ + ROSMENUITEMINFO lpitem; + HDC hdc; + int start, i; + int orgX, orgY, maxX, maxTab, maxTabWidth; + + MenuInfo->Width = MenuInfo->Height = 0; + if (MenuInfo->MenuItemCount == 0) { - return; + MenuSetRosMenuInfo(MenuInfo); + return; } -got_bitmap: - DcMem = CreateCompatibleDC(Dc); - SelectObject(DcMem, Bmp); + hdc = GetDC(NULL); + SelectObject( hdc, hMenuFont ); - /* handle fontsize > bitmap_height */ - Top = (Bm.bmHeight < h) ? Rect->top + (h - Bm.bmHeight) / 2 : Rect->top; - Left = Rect->left; - Rop= ((Item->fState & MF_HILITE) && !IS_MAGIC_BITMAP(hbmpToDraw)) ? NOTSRCCOPY : SRCCOPY; - if ((Item->fState & MF_HILITE) && Item->hbmpItem) + start = 0; + maxX = 2 + 1; + + MenuInfo->maxBmpSize.cx = 0; + MenuInfo->maxBmpSize.cy = 0; + + MenuInitRosMenuItemInfo(&lpitem); + while (start < MenuInfo->MenuItemCount) { - SetBkColor(Dc, GetSysColor(COLOR_HIGHLIGHT)); + orgX = maxX; + orgY = 2; + + maxTab = maxTabWidth = 0; + + /* Parse items until column break or end of menu */ + for (i = start; i < MenuInfo->MenuItemCount; i++) + { + if (! MenuGetRosMenuItemInfo(MenuInfo->Self, i, &lpitem)) + { + MenuCleanupRosMenuItemInfo(&lpitem); + MenuSetRosMenuInfo(MenuInfo); + return; + } + if (i != start && + (lpitem.fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break; + + MenuCalcItemSize(hdc, &lpitem, MenuInfo, WndOwner, orgX, orgY, FALSE); + if (! MenuSetRosMenuItemInfo(MenuInfo->Self, i, &lpitem)) + { + MenuCleanupRosMenuItemInfo(&lpitem); + MenuSetRosMenuInfo(MenuInfo); + return; + } +// Not sure here,, The patch from wine removes this. +// if ((lpitem.fType & MF_MENUBARBREAK) != 0) +// { +// OrgX++; +// } + maxX = max(maxX, lpitem.Rect.right); + orgY = lpitem.Rect.bottom; + if ((lpitem.Text) && lpitem.XTab ) + { + maxTab = max( maxTab, lpitem.XTab ); + maxTabWidth = max(maxTabWidth, lpitem.Rect.right - lpitem.XTab); + } + } + + /* Finish the column (set all items to the largest width found) */ + maxX = max( maxX, maxTab + maxTabWidth ); + while (start < i) + { + if (MenuGetRosMenuItemInfo(MenuInfo->Self, start, &lpitem)) + { + lpitem.Rect.right = maxX; + if ((lpitem.Text) && 0 != lpitem.XTab) + { + lpitem.XTab = maxTab; + } + MenuSetRosMenuItemInfo(MenuInfo->Self, start, &lpitem); + } + start++; + } + MenuInfo->Height = max(MenuInfo->Height, orgY); } - BitBlt(Dc, Left, Top, w, h, DcMem, BmpXoffset, 0, Rop); - DeleteDC(DcMem); + + MenuInfo->Width = maxX; + + /* space for 3d border */ + MenuInfo->Height += 2; + MenuInfo->Width += 2; + + MenuCleanupRosMenuItemInfo(&lpitem); + MenuSetRosMenuInfo(MenuInfo); + ReleaseDC( 0, hdc ); +} + +/*********************************************************************** + * MenuMenuBarCalcSize + * + * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap + * height is off by 1 pixel which causes lengthy window relocations when + * active document window is maximized/restored. + * + * Calculate the size of the menu bar. + */ +static void FASTCALL MenuMenuBarCalcSize( HDC hdc, LPRECT lprect, + PROSMENUINFO MenuInfo, HWND hwndOwner ) +{ + ROSMENUITEMINFO ItemInfo; + int start, i, orgX, orgY, maxY, helpPos; + + if ((lprect == NULL) || (MenuInfo == NULL)) return; + if (MenuInfo->MenuItemCount == 0) return; + TRACE("left=%ld top=%ld right=%ld bottom=%ld\n", lprect->left, lprect->top, lprect->right, lprect->bottom); + MenuInfo->Width = lprect->right - lprect->left; + MenuInfo->Height = 0; + maxY = lprect->top + 1; + start = 0; + helpPos = -1; + + MenuInfo->maxBmpSize.cx = 0; + MenuInfo->maxBmpSize.cy = 0; + + MenuInitRosMenuItemInfo(&ItemInfo); + while (start < MenuInfo->MenuItemCount) + { + if (! MenuGetRosMenuItemInfo(MenuInfo->Self, start, &ItemInfo)) + { + MenuCleanupRosMenuItemInfo(&ItemInfo); + return; + } + orgX = lprect->left; + orgY = maxY; + + /* Parse items until line break or end of menu */ + for (i = start; i < MenuInfo->MenuItemCount; i++) + { + if ((helpPos == -1) && (ItemInfo.fType & MF_RIGHTJUSTIFY)) helpPos = i; + if ((i != start) && + (ItemInfo.fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break; + + TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", orgX, orgY); + MenuCalcItemSize(hdc, &ItemInfo, MenuInfo, hwndOwner, orgX, orgY, TRUE); + if (! MenuSetRosMenuItemInfo(MenuInfo->Self, i, &ItemInfo)) + { + MenuCleanupRosMenuItemInfo(&ItemInfo); + return; + } + + if (ItemInfo.Rect.right > lprect->right) + { + if (i != start) break; + else ItemInfo.Rect.right = lprect->right; + } + maxY = max( maxY, ItemInfo.Rect.bottom ); + orgX = ItemInfo.Rect.right; + if (i + 1 < MenuInfo->MenuItemCount) + { + if (! MenuGetRosMenuItemInfo(MenuInfo->Self, i + 1, &ItemInfo)) + { + MenuCleanupRosMenuItemInfo(&ItemInfo); + return; + } + } + } + +/* FIXME: Is this really needed? */ /*NO! it is not needed, why make the +HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */ +#if 0 + /* Finish the line (set all items to the largest height found) */ + while (start < i) + { + if (MenuGetRosMenuItemInfo(MenuInfo->Self, start, &ItemInfo)) + { + ItemInfo.Rect.bottom = maxY; + MenuSetRosMenuItemInfo(MenuInfo->Self, start, &ItemInfo); + } + start++; + } +#else + start = i; /* This works! */ +#endif + } + + lprect->bottom = maxY; + MenuInfo->Height = lprect->bottom - lprect->top; + MenuSetRosMenuInfo(MenuInfo); + + if (helpPos != -1) + { + /* Flush right all items between the MF_RIGHTJUSTIFY and */ + /* the last item (if several lines, only move the last line) */ + if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->MenuItemCount - 1, &ItemInfo)) + { + MenuCleanupRosMenuItemInfo(&ItemInfo); + return; + } + orgY = ItemInfo.Rect.top; + orgX = lprect->right; + for (i = MenuInfo->MenuItemCount - 1; helpPos <= i; i--) + { + if (i < helpPos) + { + break; /* done */ + } + if (ItemInfo.Rect.top != orgY) + { + break; /* Other line */ + } + if (orgX <= ItemInfo.Rect.right) + { + break; /* Too far right already */ + } + ItemInfo.Rect.left += orgX - ItemInfo.Rect.right; + ItemInfo.Rect.right = orgX; + orgX = ItemInfo.Rect.left; + MenuSetRosMenuItemInfo(MenuInfo->Self, i, &ItemInfo); + if (helpPos + 1 <= i && + ! MenuGetRosMenuItemInfo(MenuInfo->Self, i - 1, &ItemInfo)) + { + MenuCleanupRosMenuItemInfo(&ItemInfo); + return; + } + } + } + + MenuCleanupRosMenuItemInfo(&ItemInfo); } /*********************************************************************** @@ -558,358 +1141,322 @@ got_bitmap: * * Draw a single menu item. */ -static void FASTCALL -MenuDrawMenuItem(HWND hWnd, PROSMENUINFO MenuInfo, HWND WndOwner, HDC Dc, - PROSMENUITEMINFO Item, UINT Height, BOOL MenuBar, UINT Action) +static void FASTCALL MenuDrawMenuItem(HWND hWnd, PROSMENUINFO MenuInfo, HWND WndOwner, HDC hdc, + PROSMENUITEMINFO lpitem, UINT Height, BOOL menuBar, UINT odaction) { - RECT Rect; - PWCHAR Text; - BOOL flat_menu = FALSE; - int bkgnd; - PWND Wnd = ValidateHwnd(hWnd); + RECT rect; + PWCHAR Text; + BOOL flat_menu = FALSE; + int bkgnd; + PWND Wnd = ValidateHwnd(hWnd); - if (!Wnd) + if (!Wnd) return; - if (0 != (Item->fType & MF_SYSMENU)) + if (lpitem->fType & MF_SYSMENU) { - if ( (Wnd->style & WS_MINIMIZE)) + if ( (Wnd->style & WS_MINIMIZE)) { - UserGetInsideRectNC(Wnd, &Rect); - UserDrawSysMenuButton(hWnd, Dc, &Rect, - Item->fState & (MF_HILITE | MF_MOUSESELECT)); - } - return; + UserGetInsideRectNC(Wnd, &rect); + UserDrawSysMenuButton(hWnd, hdc, &rect, + lpitem->fState & (MF_HILITE | MF_MOUSESELECT)); + } + return; } SystemParametersInfoW (SPI_GETFLATMENU, 0, &flat_menu, 0); - bkgnd = (MenuBar && flat_menu) ? COLOR_MENUBAR : COLOR_MENU; + bkgnd = (menuBar && flat_menu) ? COLOR_MENUBAR : COLOR_MENU; + + /* Setup colors */ - /* Setup colors */ - - if (0 != (Item->fState & MF_HILITE)) + if (lpitem->fState & MF_HILITE) { - if (MenuBar && !flat_menu) - { - SetTextColor(Dc, GetSysColor(COLOR_MENUTEXT)); - SetBkColor(Dc, GetSysColor(COLOR_MENU)); + if(menuBar && !flat_menu) { + SetTextColor(hdc, GetSysColor(COLOR_MENUTEXT)); + SetBkColor(hdc, GetSysColor(COLOR_MENU)); + } else { + if (lpitem->fState & MF_GRAYED) + SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT)); + else + SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); + SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT)); } - else - { - if (0 != (Item->fState & MF_GRAYED)) - { - SetTextColor(Dc, GetSysColor(COLOR_GRAYTEXT)); - } - else - { - SetTextColor(Dc, GetSysColor(COLOR_HIGHLIGHTTEXT)); - } - SetBkColor(Dc, GetSysColor(COLOR_HIGHLIGHT)); - } - } - else - { - if (0 != (Item->fState & MF_GRAYED)) - { - SetTextColor(Dc, GetSysColor(COLOR_GRAYTEXT)); - } - else - { - SetTextColor(Dc, GetSysColor(COLOR_MENUTEXT)); - } - SetBkColor(Dc, GetSysColor(bkgnd)); - } - - Rect = Item->Rect; - - if (Item->fType & MF_OWNERDRAW) - { - /* - ** Experimentation under Windows reveals that an owner-drawn - ** menu is given the rectangle which includes the space it requested - ** in its response to WM_MEASUREITEM _plus_ width for a checkmark - ** and a popup-menu arrow. This is the value of lpitem->rect. - ** Windows will leave all drawing to the application except for - ** the popup-menu arrow. Windows always draws that itself, after - ** the menu owner has finished drawing. - */ - DRAWITEMSTRUCT dis; - - dis.CtlType = ODT_MENU; - dis.CtlID = 0; - dis.itemID = Item->wID; - dis.itemData = (DWORD)Item->dwItemData; - dis.itemState = 0; - if (0 != (Item->fState & MF_CHECKED)) - { - dis.itemState |= ODS_CHECKED; - } - if (0 != (Item->fState & MF_GRAYED)) - { - dis.itemState |= ODS_GRAYED | ODS_DISABLED; - } - if (0 != (Item->fState & MF_HILITE)) - { - dis.itemState |= ODS_SELECTED; - } - dis.itemAction = Action; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */ - dis.hwndItem = (HWND) MenuInfo->Self; - dis.hDC = Dc; - dis.rcItem = Rect; - TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, " - "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", hWnd, - dis.itemID, dis.itemState, dis.itemAction, dis.hwndItem, - dis.hDC, dis.rcItem.left, dis.rcItem.top, dis.rcItem.right, - dis.rcItem.bottom); - SendMessageW(WndOwner, WM_DRAWITEM, 0, (LPARAM) &dis); - /* Draw the popup-menu arrow */ - if (0 != (Item->fType & MF_POPUP)) - { - RECT rectTemp; - CopyRect(&rectTemp, &Rect); - rectTemp.left = rectTemp.right - GetSystemMetrics(SM_CXMENUCHECK); - DrawFrameControl(Dc, &rectTemp, DFC_MENU, DFCS_MENUARROW); - } - return; - } - - TRACE("rect={%ld,%ld,%ld,%ld}\n", Item->Rect.left, Item->Rect.top, - Item->Rect.right, Item->Rect.bottom); - - if (MenuBar && 0 != (Item->fType & MF_SEPARATOR)) - { - return; - } - - if (Item->fState & MF_HILITE) - { - if (flat_menu) - { - InflateRect (&Rect, -1, -1); - FillRect(Dc, &Rect, GetSysColorBrush(COLOR_MENUHILIGHT)); - InflateRect (&Rect, 1, 1); - FrameRect(Dc, &Rect, GetSysColorBrush(COLOR_HIGHLIGHT)); } else { - if (MenuBar) - { - DrawEdge(Dc, &Rect, BDR_SUNKENOUTER, BF_RECT); - } - else - { - FillRect(Dc, &Rect, GetSysColorBrush(COLOR_HIGHLIGHT)); - } + if (lpitem->fState & MF_GRAYED) + SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) ); + else + SetTextColor( hdc, GetSysColor( COLOR_MENUTEXT ) ); + SetBkColor( hdc, GetSysColor( bkgnd ) ); } - } - else - { - FillRect(Dc, &Rect, GetSysColorBrush(bkgnd)); - } - SetBkMode(Dc, TRANSPARENT); + rect = lpitem->Rect; - /* vertical separator */ - if (! MenuBar && 0 != (Item->fType & MF_MENUBARBREAK)) - { - HPEN oldPen; - RECT rc = Rect; - rc.left -= 3; - rc.top = 3; - rc.bottom = Height - 3; - if (flat_menu) + if (lpitem->fType & MF_OWNERDRAW) { - oldPen = SelectObject( Dc, GetStockObject(DC_PEN) ); - SetDCPenColor(Dc, GetSysColor(COLOR_BTNSHADOW)); - MoveToEx( Dc, rc.left, rc.top, NULL ); - LineTo( Dc, rc.left, rc.bottom ); - SelectObject( Dc, oldPen ); + /* + ** Experimentation under Windows reveals that an owner-drawn + ** menu is given the rectangle which includes the space it requested + ** in its response to WM_MEASUREITEM _plus_ width for a checkmark + ** and a popup-menu arrow. This is the value of lpitem->rect. + ** Windows will leave all drawing to the application except for + ** the popup-menu arrow. Windows always draws that itself, after + ** the menu owner has finished drawing. + */ + DRAWITEMSTRUCT dis; + + dis.CtlType = ODT_MENU; + dis.CtlID = 0; + dis.itemID = lpitem->wID; + dis.itemData = (DWORD)lpitem->dwItemData; + dis.itemState = 0; + if (lpitem->fState & MF_CHECKED) dis.itemState |= ODS_CHECKED; + if (lpitem->fState & MF_GRAYED) dis.itemState |= ODS_GRAYED | ODS_DISABLED; + if (lpitem->fState & MF_HILITE) dis.itemState |= ODS_SELECTED; + dis.itemAction = odaction; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */ + dis.hwndItem = (HWND) MenuInfo->Self; + dis.hDC = hdc; + dis.rcItem = rect; + TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, " + "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", hWnd, + dis.itemID, dis.itemState, dis.itemAction, dis.hwndItem, + dis.hDC, dis.rcItem.left, dis.rcItem.top, dis.rcItem.right, + dis.rcItem.bottom); + SendMessageW(WndOwner, WM_DRAWITEM, 0, (LPARAM) &dis); + /* Draw the popup-menu arrow */ + if (lpitem->fType & MF_POPUP) + { + RECT rectTemp; + CopyRect(&rectTemp, &rect); + rectTemp.left = rectTemp.right - GetSystemMetrics(SM_CXMENUCHECK); + DrawFrameControl(hdc, &rectTemp, DFC_MENU, DFCS_MENUARROW); + } + return; + } + + if (menuBar && (lpitem->fType & MF_SEPARATOR)) return; + + if (lpitem->fState & MF_HILITE) + { + if (flat_menu) + { + InflateRect (&rect, -1, -1); + FillRect(hdc, &rect, GetSysColorBrush(COLOR_MENUHILIGHT)); + InflateRect (&rect, 1, 1); + FrameRect(hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT)); + } + else + { + if(menuBar) + DrawEdge(hdc, &rect, BDR_SUNKENOUTER, BF_RECT); + else + FillRect(hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT)); + } } else - DrawEdge(Dc, &rc, EDGE_ETCHED, BF_LEFT); - } + FillRect( hdc, &rect, GetSysColorBrush(bkgnd) ); - /* horizontal separator */ - if (0 != (Item->fType & MF_SEPARATOR)) - { - HPEN oldPen; - RECT rc = Rect; - rc.left++; - rc.right--; - rc.top += SEPARATOR_HEIGHT / 2; - if (flat_menu) + SetBkMode( hdc, TRANSPARENT ); + + /* vertical separator */ + if (!menuBar && (lpitem->fType & MF_MENUBARBREAK)) { - oldPen = SelectObject( Dc, GetStockObject(DC_PEN) ); - SetDCPenColor(Dc, GetSysColor(COLOR_BTNSHADOW)); - MoveToEx( Dc, rc.left, rc.top, NULL ); - LineTo( Dc, rc.right, rc.top ); - SelectObject( Dc, oldPen ); + HPEN oldPen; + RECT rc = rect; + + rc.left -= 3; + rc.top = 3; + rc.bottom = Height - 3; + if (flat_menu) + { + oldPen = SelectObject( hdc, GetStockObject(DC_PEN) ); + SetDCPenColor(hdc, GetSysColor(COLOR_BTNSHADOW)); + MoveToEx( hdc, rc.left, rc.top, NULL ); + LineTo( hdc, rc.left, rc.bottom ); + SelectObject( hdc, oldPen ); + } + else + DrawEdge (hdc, &rc, EDGE_ETCHED, BF_LEFT); + } + + /* horizontal separator */ + if (lpitem->fType & MF_SEPARATOR) + { + HPEN oldPen; + RECT rc = rect; + + rc.left++; + rc.right--; + rc.top += SEPARATOR_HEIGHT / 2; + if (flat_menu) + { + oldPen = SelectObject( hdc, GetStockObject(DC_PEN) ); + SetDCPenColor( hdc, GetSysColor(COLOR_BTNSHADOW)); + MoveToEx( hdc, rc.left, rc.top, NULL ); + LineTo( hdc, rc.right, rc.top ); + SelectObject( hdc, oldPen ); + } + else + DrawEdge (hdc, &rc, EDGE_ETCHED, BF_TOP); + return; } - else - DrawEdge(Dc, &rc, EDGE_ETCHED, BF_TOP); - return; - } #if 0 - /* helper lines for debugging */ - /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */ - FrameRect(Dc, &Rect, GetStockObject(BLACK_BRUSH)); - SelectObject(Dc, GetStockObject(DC_PEN)); - SetDCPenColor(Dc, GetSysColor(COLOR_WINDOWFRAME)); - MoveToEx(Dc, Rect.left, (Rect.top + Rect.bottom) / 2, NULL); - LineTo(Dc, Rect.right, (Rect.top + Rect.bottom) / 2); + /* helper lines for debugging */ + /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */ + FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH)); + SelectObject(hdc, GetStockObject(DC_PEN)); + SetDCPenColor(hdc, GetSysColor(COLOR_WINDOWFRAME)); + MoveToEx(hdc, rect.left, (rect.top + rect.bottom) / 2, NULL); + LineTo(hdc, rect.right, (rect.top + rect.bottom) / 2); #endif - if (! MenuBar) - { - INT y = Rect.top + Rect.bottom; - RECT Rc = Rect; - UINT CheckBitmapWidth = GetSystemMetrics(SM_CXMENUCHECK); - UINT CheckBitmapHeight = GetSystemMetrics(SM_CYMENUCHECK); - int checked = FALSE; - /* Draw the check mark - * - * FIXME: - * Custom checkmark bitmaps are monochrome but not always 1bpp. - */ - if( !(MenuInfo->dwStyle & MNS_NOCHECK)) - { - HBITMAP bm = 0 != (Item->fState & MF_CHECKED) ? Item->hbmpChecked : Item->hbmpUnchecked; - if (NULL != bm) /* we have a custom bitmap */ - { - HDC DcMem = CreateCompatibleDC(Dc); - SelectObject(DcMem, bm); - BitBlt(Dc, Rc.left, (y - CheckBitmapHeight) / 2, - CheckBitmapWidth, CheckBitmapHeight, - DcMem, 0, 0, SRCCOPY); - DeleteDC(DcMem); - checked = TRUE; - } - else if (0 != (Item->fState & MF_CHECKED)) /* standard bitmaps */ - { - RECT rectTemp; - CopyRect(&rectTemp, &Rect); - rectTemp.right = rectTemp.left + GetSystemMetrics(SM_CXMENUCHECK); - DrawFrameControl(Dc, &rectTemp, DFC_MENU, - 0 != (Item->fType & MFT_RADIOCHECK) ? + if (!menuBar) + { + HBITMAP bm; + INT y = rect.top + rect.bottom; + RECT rc = rect; + int checked = FALSE; + UINT check_bitmap_width = GetSystemMetrics( SM_CXMENUCHECK ); + UINT check_bitmap_height = GetSystemMetrics( SM_CYMENUCHECK ); + /* Draw the check mark + * + * FIXME: + * Custom checkmark bitmaps are monochrome but not always 1bpp. + */ + if( !(MenuInfo->dwStyle & MNS_NOCHECK)) { + bm = (lpitem->fState & MF_CHECKED) ? lpitem->hbmpChecked : + lpitem->hbmpUnchecked; + if (bm) /* we have a custom bitmap */ + { + HDC hdcMem = CreateCompatibleDC( hdc ); + + SelectObject( hdcMem, bm ); + BitBlt( hdc, rc.left, (y - check_bitmap_height) / 2, + check_bitmap_width, check_bitmap_height, + hdcMem, 0, 0, SRCCOPY ); + DeleteDC( hdcMem ); + checked = TRUE; + } + else if (lpitem->fState & MF_CHECKED) /* standard bitmaps */ + { + RECT r; + CopyRect(&r, &rect); + r.right = r.left + GetSystemMetrics(SM_CXMENUCHECK); + DrawFrameControl( hdc, &r, DFC_MENU, + (lpitem->fType & MFT_RADIOCHECK) ? DFCS_MENUBULLET : DFCS_MENUCHECK); - checked = TRUE; - } - } - if (Item->hbmpItem) - { - RECT bmpRect; - CopyRect(&bmpRect, &Rect); - if (!(MenuInfo->dwStyle & MNS_CHECKORBMP) && !(MenuInfo->dwStyle & MNS_NOCHECK)) - bmpRect.left += CheckBitmapWidth + 2; - if (!(checked && (MenuInfo->dwStyle & MNS_CHECKORBMP))) - { - bmpRect.right = bmpRect.left + MenuInfo->maxBmpSize.cx; - MenuDrawBitmapItem(Dc, Item, &bmpRect, MenuInfo->Self, WndOwner, Action, MenuBar); - } - } - /* Draw the popup-menu arrow */ - if (0 != (Item->fType & MF_POPUP)) - { - RECT rectTemp; - CopyRect(&rectTemp, &Rect); - rectTemp.left = rectTemp.right - GetSystemMetrics(SM_CXMENUCHECK); - DrawFrameControl(Dc, &rectTemp, DFC_MENU, DFCS_MENUARROW); - } - Rect.left += 4; - if( !(MenuInfo->dwStyle & MNS_NOCHECK)) - Rect.left += CheckBitmapWidth; - Rect.right -= CheckBitmapWidth; - } - else if (Item->hbmpItem) /* Draw the bitmap */ - { - MenuDrawBitmapItem(Dc, Item, &Rect, MenuInfo->Self, WndOwner, Action, MenuBar); - } - - /* No bitmap - process text if present */ - if (Item->Text) - { - register int i = 0; - HFONT FontOld = NULL; - - UINT uFormat = MenuBar ? DT_CENTER | DT_VCENTER | DT_SINGLELINE - : DT_LEFT | DT_VCENTER | DT_SINGLELINE; - - if(MenuInfo->dwStyle & MNS_CHECKORBMP) - Rect.left += max(0, MenuInfo->maxBmpSize.cx - GetSystemMetrics(SM_CXMENUCHECK)); - else - Rect.left += MenuInfo->maxBmpSize.cx; - - if (0 != (Item->fState & MFS_DEFAULT)) - { - FontOld = SelectObject(Dc, hMenuFontBold); - } - - if (MenuBar) - { - Rect.left += MENU_BAR_ITEMS_SPACE / 2; - Rect.right -= MENU_BAR_ITEMS_SPACE / 2; - } - - Text = (PWCHAR) Item->dwTypeData; - if(Text) - { - for (i = 0; L'\0' != Text[i]; i++) - { - if (L'\t' == Text[i] || L'\b' == Text[i]) - { - break; + checked = TRUE; } } - } + if ( lpitem->hbmpItem ) + { + RECT bmpRect; + CopyRect(&bmpRect, &rect); + if (!(MenuInfo->dwStyle & MNS_CHECKORBMP) && !(MenuInfo->dwStyle & MNS_NOCHECK)) + bmpRect.left += check_bitmap_width + 2; + if (!(checked && (MenuInfo->dwStyle & MNS_CHECKORBMP))) + { + bmpRect.right = bmpRect.left + MenuInfo->maxBmpSize.cx; + MenuDrawBitmapItem(hdc, lpitem, &bmpRect, MenuInfo->Self, WndOwner, odaction, menuBar); + } + } + /* Draw the popup-menu arrow */ + if (lpitem->fType & MF_POPUP) + { + RECT rectTemp; + CopyRect(&rectTemp, &rect); + rectTemp.left = rectTemp.right - GetSystemMetrics(SM_CXMENUCHECK); + DrawFrameControl(hdc, &rectTemp, DFC_MENU, DFCS_MENUARROW); + } + rect.left += 4; + if( !(MenuInfo->dwStyle & MNS_NOCHECK)) + rect.left += check_bitmap_width; + rect.right -= check_bitmap_width; + } + else if( lpitem->hbmpItem) + { /* Draw the bitmap */ + MenuDrawBitmapItem(hdc, lpitem, &rect, MenuInfo->Self, WndOwner, odaction, menuBar); + } - if (0 != (Item->fState & MF_GRAYED)) - { - if (0 == (Item->fState & MF_HILITE)) - { - ++Rect.left; ++Rect.top; ++Rect.right; ++Rect.bottom; - SetTextColor(Dc, RGB(0xff, 0xff, 0xff)); - DrawTextW(Dc, Text, i, &Rect, uFormat); - --Rect.left; --Rect.top; --Rect.right; --Rect.bottom; - } - SetTextColor(Dc, RGB(0x80, 0x80, 0x80)); + /* process text if present */ + if (lpitem->Text) + { + register int i = 0; + HFONT hfontOld = 0; + + UINT uFormat = menuBar ? DT_CENTER | DT_VCENTER | DT_SINGLELINE + : DT_LEFT | DT_VCENTER | DT_SINGLELINE; + + if(MenuInfo->dwStyle & MNS_CHECKORBMP) + rect.left += max(0, MenuInfo->maxBmpSize.cx - GetSystemMetrics(SM_CXMENUCHECK)); + else + rect.left += MenuInfo->maxBmpSize.cx; + + if ( lpitem->fState & MFS_DEFAULT ) + { + hfontOld = SelectObject(hdc, hMenuFontBold); } - DrawTextW(Dc, Text, i, &Rect, uFormat); + if (menuBar) { + rect.left += MENU_BAR_ITEMS_SPACE / 2; + rect.right -= MENU_BAR_ITEMS_SPACE / 2; + } - /* paint the shortcut text */ - if (! MenuBar && L'\0' != Text[i]) /* There's a tab or flush-right char */ + Text = (PWCHAR) lpitem->dwTypeData; + if(Text) { - if (L'\t' == Text[i]) + for (i = 0; L'\0' != Text[i]; i++) + if (Text[i] == L'\t' || Text[i] == L'\b') + break; + } + + if(lpitem->fState & MF_GRAYED) + { + if (!(lpitem->fState & MF_HILITE) ) { - Rect.left = Item->XTab; - uFormat = DT_LEFT | DT_VCENTER | DT_SINGLELINE; + ++rect.left; ++rect.top; ++rect.right; ++rect.bottom; + SetTextColor(hdc, RGB(0xff, 0xff, 0xff)); + DrawTextW( hdc, Text, i, &rect, uFormat ); + --rect.left; --rect.top; --rect.right; --rect.bottom; + } + SetTextColor(hdc, RGB(0x80, 0x80, 0x80)); + } + + DrawTextW( hdc, Text, i, &rect, uFormat); + + /* paint the shortcut text */ + if (!menuBar && L'\0' != Text[i]) /* There's a tab or flush-right char */ + { + if (L'\t' == Text[i]) + { + rect.left = lpitem->XTab; + uFormat = DT_LEFT | DT_VCENTER | DT_SINGLELINE; } - else + else { - Rect.right = Item->XTab; - uFormat = DT_RIGHT | DT_VCENTER | DT_SINGLELINE; + rect.right = lpitem->XTab; + uFormat = DT_RIGHT | DT_VCENTER | DT_SINGLELINE; } - if (0 != (Item->fState & MF_GRAYED)) + if (lpitem->fState & MF_GRAYED) { - if (0 == (Item->fState & MF_HILITE)) + if (!(lpitem->fState & MF_HILITE) ) { - ++Rect.left; ++Rect.top; ++Rect.right; ++Rect.bottom; - SetTextColor(Dc, RGB(0xff, 0xff, 0xff)); - DrawTextW(Dc, Text + i + 1, -1, &Rect, uFormat); - --Rect.left; --Rect.top; --Rect.right; --Rect.bottom; + ++rect.left; ++rect.top; ++rect.right; ++rect.bottom; + SetTextColor(hdc, RGB(0xff, 0xff, 0xff)); + DrawTextW( hdc, Text + i + 1, -1, &rect, uFormat); + --rect.left; --rect.top; --rect.right; --rect.bottom; } - SetTextColor(Dc, RGB(0x80, 0x80, 0x80)); - } - DrawTextW(Dc, Text + i + 1, -1, &Rect, uFormat); + SetTextColor(hdc, RGB(0x80, 0x80, 0x80)); + } + DrawTextW( hdc, Text + i + 1, -1, &rect, uFormat ); } - if (NULL != FontOld) - { - SelectObject(Dc, FontOld); - } - } + if (hfontOld) + SelectObject (hdc, hfontOld); + } } /*********************************************************************** @@ -917,63 +1464,337 @@ MenuDrawMenuItem(HWND hWnd, PROSMENUINFO MenuInfo, HWND WndOwner, HDC Dc, * * Paint a popup menu. */ -static void FASTCALL -MenuDrawPopupMenu(HWND Wnd, HDC Dc, HMENU Menu) +static void FASTCALL MenuDrawPopupMenu(HWND hwnd, HDC hdc, HMENU hmenu ) { - HBRUSH PrevBrush = NULL; - HPEN PrevPen; - RECT Rect; - ROSMENUINFO MenuInfo; - ROSMENUITEMINFO ItemInfo; - UINT u; + HBRUSH hPrevBrush = 0; + RECT rect; - TRACE("wnd=%x dc=%x menu=%x\n", Wnd, Dc, Menu); + TRACE("wnd=%p dc=%p menu=%p\n", hwnd, hdc, hmenu); - GetClientRect(Wnd, &Rect); + GetClientRect( hwnd, &rect ); - if (NULL != (PrevBrush = SelectObject(Dc, GetSysColorBrush(COLOR_MENU))) - && NULL != SelectObject(Dc, hMenuFont)) + if((hPrevBrush = SelectObject( hdc, GetSysColorBrush(COLOR_MENU) )) + && (SelectObject( hdc, hMenuFont))) { - Rectangle(Dc, Rect.left, Rect.top, Rect.right, Rect.bottom); + HPEN hPrevPen; - PrevPen = SelectObject(Dc, GetStockObject(NULL_PEN)); - if (NULL != PrevPen) + Rectangle( hdc, rect.left, rect.top, rect.right, rect.bottom ); + + hPrevPen = SelectObject( hdc, GetStockObject( NULL_PEN ) ); + if ( hPrevPen ) { - BOOL flat_menu = FALSE; + BOOL flat_menu = FALSE; + ROSMENUINFO MenuInfo; + ROSMENUITEMINFO ItemInfo; - SystemParametersInfoW (SPI_GETFLATMENU, 0, &flat_menu, 0); - if (flat_menu) - FrameRect(Dc, &Rect, GetSysColorBrush(COLOR_BTNSHADOW)); - else - DrawEdge(Dc, &Rect, EDGE_RAISED, BF_RECT); + SystemParametersInfoW (SPI_GETFLATMENU, 0, &flat_menu, 0); + if (flat_menu) + FrameRect(hdc, &rect, GetSysColorBrush(COLOR_BTNSHADOW)); + else + DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT); - /* draw menu items */ - - if (MenuGetRosMenuInfo(&MenuInfo, Menu) && 0 != MenuInfo.MenuItemCount) + /* draw menu items */ + if (MenuGetRosMenuInfo(&MenuInfo, hmenu) && MenuInfo.MenuItemCount) { - MenuInitRosMenuItemInfo(&ItemInfo); + UINT u; + + MenuInitRosMenuItemInfo(&ItemInfo); - for (u = 0; u < MenuInfo.MenuItemCount; u++) + for (u = 0; u < MenuInfo.MenuItemCount; u++) { - if (MenuGetRosMenuItemInfo(MenuInfo.Self, u, &ItemInfo)) + if (MenuGetRosMenuItemInfo(MenuInfo.Self, u, &ItemInfo)) { - MenuDrawMenuItem(Wnd, &MenuInfo, MenuInfo.WndOwner, Dc, &ItemInfo, - MenuInfo.Height, FALSE, ODA_DRAWENTIRE); + MenuDrawMenuItem(hwnd, &MenuInfo, MenuInfo.WndOwner, hdc, &ItemInfo, + MenuInfo.Height, FALSE, ODA_DRAWENTIRE); } } - MenuCleanupRosMenuItemInfo(&ItemInfo); - } - } - else - { - SelectObject(Dc, PrevBrush); - } + MenuCleanupRosMenuItemInfo(&ItemInfo); + } + } else + { + SelectObject( hdc, hPrevBrush ); + } } } -LRESULT WINAPI -PopupMenuWndProcA(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam) +/*********************************************************************** + * MenuDrawMenuBar + * + * Paint a menu bar. Returns the height of the menu bar. + * called from [windows/nonclient.c] + */ +UINT MenuDrawMenuBar( HDC hDC, LPRECT lprect, HWND hwnd, + BOOL suppress_draw) +{ + ROSMENUINFO lppop; + HFONT hfontOld = 0; + HMENU hMenu = GetMenu(hwnd); + + if (! MenuGetRosMenuInfo(&lppop, hMenu) || lprect == NULL) + { + return GetSystemMetrics(SM_CYMENU); + } + + if (suppress_draw) + { + hfontOld = SelectObject(hDC, hMenuFont); + + MenuMenuBarCalcSize(hDC, lprect, &lppop, hwnd); + + lprect->bottom = lprect->top + lppop.Height; + + if (hfontOld) SelectObject( hDC, hfontOld); + return lppop.Height; + } + else + return DrawMenuBarTemp(hwnd, hDC, lprect, hMenu, NULL); +} + +/*********************************************************************** + * MenuShowPopup + * + * Display a popup menu. + */ +static BOOL FASTCALL MenuShowPopup(HWND hwndOwner, HMENU hmenu, UINT id, UINT flags, + INT x, INT y, INT xanchor, INT yanchor ) +{ + ROSMENUINFO MenuInfo; + ROSMENUITEMINFO ItemInfo; + UINT width, height; + POINT pt; + HMONITOR monitor; + MONITORINFO info; + + TRACE("owner=%p hmenu=%p id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n", + hwndOwner, hmenu, id, x, y, xanchor, yanchor); + + if (! MenuGetRosMenuInfo(&MenuInfo, hmenu)) return FALSE; + if (MenuInfo.FocusedItem != NO_SELECTED_ITEM) + { + MenuInitRosMenuItemInfo(&ItemInfo); + if (MenuGetRosMenuItemInfo(MenuInfo.Self, MenuInfo.FocusedItem, &ItemInfo)) + { + ItemInfo.fMask |= MIIM_STATE; + ItemInfo.fState &= ~(MF_HILITE|MF_MOUSESELECT); + MenuSetRosMenuItemInfo(MenuInfo.Self, MenuInfo.FocusedItem, &ItemInfo); + } + MenuCleanupRosMenuItemInfo(&ItemInfo); + MenuInfo.FocusedItem = NO_SELECTED_ITEM; + } + + /* store the owner for DrawItem */ + MenuInfo.WndOwner = hwndOwner; + MenuSetRosMenuInfo(&MenuInfo); + + MenuPopupMenuCalcSize(&MenuInfo, hwndOwner); + + /* adjust popup menu pos so that it fits within the desktop */ + + width = MenuInfo.Width + GetSystemMetrics(SM_CXBORDER); + height = MenuInfo.Height + GetSystemMetrics(SM_CYBORDER); + + /* FIXME: should use item rect */ + pt.x = x; + pt.y = y; + monitor = MonitorFromPoint( pt, MONITOR_DEFAULTTONEAREST ); + info.cbSize = sizeof(info); + GetMonitorInfoW( monitor, &info ); + + if( flags & TPM_RIGHTALIGN ) x -= width; + if( flags & TPM_CENTERALIGN ) x -= width / 2; + + if( flags & TPM_BOTTOMALIGN ) y -= height; + if( flags & TPM_VCENTERALIGN ) y -= height / 2; + + if( x + width > info.rcWork.right) + { + if( xanchor && x >= width - xanchor ) + x -= width - xanchor; + + if( x + width > info.rcWork.right) + x = info.rcWork.right - width; + } + if( x < info.rcWork.left ) x = info.rcWork.left; + + if( y + height > info.rcWork.bottom) + { + if( yanchor && y >= height + yanchor ) + y -= height + yanchor; + + if( y + height > info.rcWork.bottom) + y = info.rcWork.bottom - height; + } + if( y < info.rcWork.top ) y = info.rcWork.top; + + /* NOTE: In Windows, top menu popup is not owned. */ + MenuInfo.Wnd = CreateWindowExW( 0, POPUPMENU_CLASS_ATOMW, NULL, + WS_POPUP, x, y, width, height, + hwndOwner, 0, (HINSTANCE) GetWindowLongPtrW(hwndOwner, GWLP_HINSTANCE), + (LPVOID) MenuInfo.Self); + if ( !MenuInfo.Wnd || ! MenuSetRosMenuInfo(&MenuInfo)) return FALSE; + if (!top_popup) { + top_popup = MenuInfo.Wnd; + } + + /* Display the window */ + + SetWindowPos( MenuInfo.Wnd, HWND_TOPMOST, 0, 0, 0, 0, + SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE); + UpdateWindow( MenuInfo.Wnd ); + return TRUE; +} + +/*********************************************************************** + * MenuSelectItem + */ +static void FASTCALL MenuSelectItem(HWND hwndOwner, PROSMENUINFO hmenu, UINT wIndex, + BOOL sendMenuSelect, HMENU topmenu) +{ + ROSMENUITEMINFO ItemInfo; + ROSMENUINFO TopMenuInfo; + HDC hdc; + + TRACE("owner=%p menu=%p index=0x%04x select=0x%04x\n", hwndOwner, hmenu, wIndex, sendMenuSelect); + + if (!hmenu || !hmenu->MenuItemCount || !hmenu->Wnd) return; + if (hmenu->FocusedItem == wIndex) return; + if (hmenu->Flags & MF_POPUP) hdc = GetDC(hmenu->Wnd); + else hdc = GetDCEx(hmenu->Wnd, 0, DCX_CACHE | DCX_WINDOW); + if (!top_popup) { + top_popup = hmenu->Wnd; + } + + SelectObject( hdc, hMenuFont ); + + MenuInitRosMenuItemInfo(&ItemInfo); + + /* Clear previous highlighted item */ + if (hmenu->FocusedItem != NO_SELECTED_ITEM) + { + if (MenuGetRosMenuItemInfo(hmenu->Self, hmenu->FocusedItem, &ItemInfo)) + { + ItemInfo.fMask |= MIIM_STATE; + ItemInfo.fState &= ~(MF_HILITE|MF_MOUSESELECT); + MenuSetRosMenuItemInfo(hmenu->Self, hmenu->FocusedItem, &ItemInfo); + } + MenuDrawMenuItem(hmenu->Wnd, hmenu, hwndOwner, hdc, &ItemInfo, + hmenu->Height, ! (hmenu->Flags & MF_POPUP), + ODA_SELECT); + } + + /* Highlight new item (if any) */ + hmenu->FocusedItem = wIndex; + MenuSetRosMenuInfo(hmenu); + if (hmenu->FocusedItem != NO_SELECTED_ITEM) + { + if (MenuGetRosMenuItemInfo(hmenu->Self, hmenu->FocusedItem, &ItemInfo)) + { + if (!(ItemInfo.fType & MF_SEPARATOR)) + { + ItemInfo.fMask |= MIIM_STATE; + ItemInfo.fState |= MF_HILITE; + MenuSetRosMenuItemInfo(hmenu->Self, hmenu->FocusedItem, &ItemInfo); + MenuDrawMenuItem(hmenu->Wnd, hmenu, hwndOwner, hdc, + &ItemInfo, hmenu->Height, ! (hmenu->Flags & MF_POPUP), + ODA_SELECT); + } + if (sendMenuSelect) + { + SendMessageW(hwndOwner, WM_MENUSELECT, + MAKELONG(ItemInfo.fType & MF_POPUP ? wIndex : ItemInfo.wID, + ItemInfo.fType | ItemInfo.fState | MF_MOUSESELECT | + (hmenu->Flags & MF_SYSMENU)), (LPARAM) hmenu->Self); + } + } + } + else if (sendMenuSelect) { + if(topmenu) { + int pos; + pos = MenuFindSubMenu(&topmenu, hmenu->Self); + if (pos != NO_SELECTED_ITEM) + { + if (MenuGetRosMenuInfo(&TopMenuInfo, topmenu) + && MenuGetRosMenuItemInfo(topmenu, pos, &ItemInfo)) + { + SendMessageW(hwndOwner, WM_MENUSELECT, + MAKELONG(Pos, ItemInfo.fType | ItemInfo.fState + | MF_MOUSESELECT + | (TopMenuInfo.Flags & MF_SYSMENU)), + (LPARAM) topmenu); + } + } + } + } + MenuCleanupRosMenuItemInfo(&ItemInfo); + ReleaseDC(hmenu->Wnd, hdc); +} + +/*********************************************************************** + * MenuMoveSelection + * + * Moves currently selected item according to the Offset parameter. + * If there is no selection then it should select the last item if + * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT. + */ +static void FASTCALL +MenuMoveSelection(HWND WndOwner, PROSMENUINFO MenuInfo, INT Offset) +{ + INT i; + ROSMENUITEMINFO ItemInfo; + INT OrigPos; + + TRACE("hwnd=%x menu=%x off=0x%04x\n", WndOwner, MenuInfo, Offset); + + /* Prevent looping */ + if (0 == MenuInfo->MenuItemCount || 0 == Offset) + return; + else if (Offset < -1) + Offset = -1; + else if (Offset > 1) + Offset = 1; + + MenuInitRosMenuItemInfo(&ItemInfo); + + OrigPos = MenuInfo->FocusedItem; + if (OrigPos == NO_SELECTED_ITEM) /* NO_SELECTED_ITEM is not -1 ! */ + { + OrigPos = 0; + i = -1; + } + else + { + i = MenuInfo->FocusedItem; + } + + do + { + /* Step */ + i += Offset; + /* Clip and wrap around */ + if (i < 0) + { + i = MenuInfo->MenuItemCount - 1; + } + else if (i >= MenuInfo->MenuItemCount) + { + i = 0; + } + /* If this is a good candidate; */ + if (MenuGetRosMenuItemInfo(MenuInfo->Self, i, &ItemInfo) && + 0 == (ItemInfo.fType & MF_SEPARATOR)) + { + MenuSelectItem(WndOwner, MenuInfo, i, TRUE, NULL); + MenuCleanupRosMenuItemInfo(&ItemInfo); + return; + } + } while (i != OrigPos); + + /* Not found */ + MenuCleanupRosMenuItemInfo(&ItemInfo); +} + +LRESULT WINAPI PopupMenuWndProcA(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam) { TRACE("YES! hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd, Message, wParam, lParam); @@ -1010,9 +1831,9 @@ PopupMenuWndProcA(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam) case WM_DESTROY: /* zero out global pointer in case resident popup window was destroyed. */ - if (Wnd == TopPopup) + if (Wnd == top_popup) { - TopPopup = NULL; + top_popup = NULL; } break; @@ -1082,9 +1903,9 @@ PopupMenuWndProcW(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam) case WM_DESTROY: /* zero out global pointer in case resident popup window was destroyed. */ - if (Wnd == TopPopup) + if (Wnd == top_popup) { - TopPopup = NULL; + top_popup = NULL; } break; @@ -1117,66 +1938,6 @@ PopupMenuWndProcW(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam) return 0; } -/********************************************************************** - * MENUEX_ParseResource - * - * Parse an extended menu resource and add items to the menu. - * Return a pointer to the end of the resource. - * - * FIXME - should we be passing an LPCSTR to a predominantly UNICODE function? - */ -static LPCSTR MENUEX_ParseResource( LPCSTR res, HMENU hMenu) -{ - WORD resinfo; - - do - { - MENUITEMINFOW mii; - - mii.cbSize = sizeof(mii); - mii.fMask = MIIM_STATE | MIIM_ID | MIIM_FTYPE; - mii.fType = GET_DWORD(res); - res += sizeof(DWORD); - mii.fState = GET_DWORD(res); - res += sizeof(DWORD); - mii.wID = GET_DWORD(res); - res += sizeof(DWORD); - resinfo = GET_WORD(res); - res += sizeof(WORD); - /* Align the text on a word boundary. */ - res += (~((int)res - 1)) & 1; - mii.dwTypeData = (LPWSTR) res; - res += (1 + strlenW(mii.dwTypeData)) * sizeof(WCHAR); - /* Align the following fields on a dword boundary. */ - res += (~((int)res - 1)) & 3; - - if (resinfo & 1) /* Pop-up? */ - { - /* DWORD helpid = GET_DWORD(res); FIXME: use this. */ - res += sizeof(DWORD); - mii.hSubMenu = CreatePopupMenu(); - if (!mii.hSubMenu) - return NULL; - if (!(res = MENUEX_ParseResource(res, mii.hSubMenu))) - { - DestroyMenu(mii.hSubMenu); - return NULL; - } - mii.fMask |= MIIM_SUBMENU; - mii.fType |= MF_POPUP; - mii.wID = (UINT) mii.hSubMenu; - } - else if(!*mii.dwTypeData && !(mii.fType & MF_SEPARATOR)) - { - mii.fType |= MF_SEPARATOR; - } - InsertMenuItemW(hMenu, -1, MF_BYPOSITION, &mii); - } - while (!(resinfo & MF_END)); - return res; -} - - /********************************************************************** * MENU_ParseResource * @@ -1187,72 +1948,126 @@ static LPCSTR MENUEX_ParseResource( LPCSTR res, HMENU hMenu) */ static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu, BOOL unicode ) { - WORD flags, id = 0; - HMENU hSubMenu; - LPCSTR str; - BOOL end = FALSE; + WORD flags, id = 0; + HMENU hSubMenu; + LPCSTR str; + BOOL end = FALSE; - do - { - flags = GET_WORD(res); - - /* remove MF_END flag before passing it to AppendMenu()! */ - end = (flags & MF_END); - if(end) flags ^= MF_END; - - res += sizeof(WORD); - if(!(flags & MF_POPUP)) + do { - id = GET_WORD(res); - res += sizeof(WORD); - } - str = res; - if(!unicode) - res += strlen(str) + 1; - else - res += (strlenW((LPCWSTR)str) + 1) * sizeof(WCHAR); - if (flags & MF_POPUP) - { - hSubMenu = CreatePopupMenu(); - if(!hSubMenu) return NULL; - if(!(res = MENU_ParseResource(res, hSubMenu, unicode))) - return NULL; - if(!unicode) - AppendMenuA(hMenu, flags, (UINT)hSubMenu, str); - else - AppendMenuW(hMenu, flags, (UINT)hSubMenu, (LPCWSTR)str); - } - else /* Not a popup */ - { - if(!unicode) - { - if (*str == 0) - flags = MF_SEPARATOR; - } - else - { - if (*(LPCWSTR)str == 0) - flags = MF_SEPARATOR; - } + flags = GET_WORD(res); - if (flags & MF_SEPARATOR) - { - if (!(flags & (MF_GRAYED | MF_DISABLED))) - flags |= MF_GRAYED | MF_DISABLED; - } + /* remove MF_END flag before passing it to AppendMenu()! */ + end = (flags & MF_END); + if(end) flags ^= MF_END; - if(!unicode) - AppendMenuA(hMenu, flags, id, *str ? str : NULL); - else - AppendMenuW(hMenu, flags, id, + res += sizeof(WORD); + if(!(flags & MF_POPUP)) + { + id = GET_WORD(res); + res += sizeof(WORD); + } + str = res; + if(!unicode) + res += strlen(str) + 1; + else + res += (strlenW((LPCWSTR)str) + 1) * sizeof(WCHAR); + if (flags & MF_POPUP) + { + hSubMenu = CreatePopupMenu(); + if(!hSubMenu) return NULL; + if(!(res = MENU_ParseResource(res, hSubMenu, unicode))) + return NULL; + if(!unicode) + AppendMenuA(hMenu, flags, (UINT)hSubMenu, str); + else + AppendMenuW(hMenu, flags, (UINT)hSubMenu, (LPCWSTR)str); + } + else /* Not a popup */ + { + if(!unicode) + { + if (*str == 0) + flags = MF_SEPARATOR; + } + else + { + if (*(LPCWSTR)str == 0) + flags = MF_SEPARATOR; + } + + if (flags & MF_SEPARATOR) + { + if (!(flags & (MF_GRAYED | MF_DISABLED))) + flags |= MF_GRAYED | MF_DISABLED; + } + + if(!unicode) + AppendMenuA(hMenu, flags, id, *str ? str : NULL); + else + AppendMenuW(hMenu, flags, id, *(LPCWSTR)str ? (LPCWSTR)str : NULL); - } - } while(!end); - - return res; + } + } while(!end); + return res; } +/********************************************************************** + * MENUEX_ParseResource + * + * Parse an extended menu resource and add items to the menu. + * Return a pointer to the end of the resource. + */ +static LPCSTR MENUEX_ParseResource( LPCSTR res, HMENU hMenu) +{ + WORD resinfo; + do { + MENUITEMINFOW mii; + + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_STATE | MIIM_ID | MIIM_FTYPE; + mii.fType = GET_DWORD(res); + res += sizeof(DWORD); + mii.fState = GET_DWORD(res); + res += sizeof(DWORD); + mii.wID = GET_DWORD(res); + res += sizeof(DWORD); + resinfo = GET_WORD(res); + res += sizeof(WORD); + /* Align the text on a word boundary. */ + res += (~((UINT_PTR)res - 1)) & 1; + mii.dwTypeData = (LPWSTR) res; + res += (1 + strlenW(mii.dwTypeData)) * sizeof(WCHAR); + /* Align the following fields on a dword boundary. */ + res += (~((UINT_PTR)res - 1)) & 3; + + TRACE("Menu item: [%08x,%08x,%04x,%04x,%S]\n", + mii.fType, mii.fState, mii.wID, resinfo, mii.dwTypeData); + + if (resinfo & 1) { /* Pop-up? */ + /* DWORD helpid = GET_DWORD(res); FIXME: use this. */ + res += sizeof(DWORD); + mii.hSubMenu = CreatePopupMenu(); + if (!mii.hSubMenu) + return NULL; + if (!(res = MENUEX_ParseResource(res, mii.hSubMenu))) { + DestroyMenu(mii.hSubMenu); + return NULL; + } + mii.fMask |= MIIM_SUBMENU; + mii.fType |= MF_POPUP; + mii.wID = (UINT) mii.hSubMenu; + } + else if(!*mii.dwTypeData && !(mii.fType & MF_SEPARATOR)) + { + mii.fType |= MF_SEPARATOR; + } + InsertMenuItemW(hMenu, -1, MF_BYPOSITION, &mii); + } while (!(resinfo & MF_END)); + return res; +} + NTSTATUS WINAPI User32LoadSysMenuTemplateForKernel(PVOID Arguments, ULONG ArgumentLength) { @@ -1320,7 +2135,6 @@ MenuInit(VOID) return TRUE; } - VOID MenuCleanup(VOID) { @@ -1337,435 +2151,6 @@ MenuCleanup(VOID) } } - - -/*********************************************************************** - * MenuCalcItemSize - * - * Calculate the size of the menu item and store it in ItemInfo->rect. - */ -static void FASTCALL -MenuCalcItemSize(HDC Dc, PROSMENUITEMINFO ItemInfo, PROSMENUINFO MenuInfo, HWND WndOwner, - INT OrgX, INT OrgY, BOOL MenuBar) -{ - PWCHAR p; - INT itemheight = 0; - UINT CheckBitmapWidth = GetSystemMetrics(SM_CXMENUCHECK); - - TRACE("dc=%x owner=%x (%d,%d)\n", Dc, WndOwner, OrgX, OrgY); - - MenuCharSize.cx = GdiGetCharDimensions( Dc, NULL, &MenuCharSize.cy ); - - SetRect(&ItemInfo->Rect, OrgX, OrgY, OrgX, OrgY); - - if (0 != (ItemInfo->fType & MF_OWNERDRAW)) - { - /* - ** Experimentation under Windows reveals that an owner-drawn - ** menu is expected to return the size of the content part of - ** the menu item, not including the checkmark nor the submenu - ** arrow. Windows adds those values itself and returns the - ** enlarged rectangle on subsequent WM_DRAWITEM messages. - */ - MEASUREITEMSTRUCT mis; - mis.CtlType = ODT_MENU; - mis.CtlID = 0; - mis.itemID = ItemInfo->wID; - mis.itemData = (DWORD)ItemInfo->dwItemData; - mis.itemHeight = HIWORD( GetDialogBaseUnits()); - mis.itemWidth = 0; - SendMessageW(WndOwner, WM_MEASUREITEM, 0, (LPARAM) &mis); - /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average - * width of a menufont character to the width of an owner-drawn menu. - */ - ItemInfo->Rect.right += mis.itemWidth + 2 * MenuCharSize.cx; - - if (MenuBar) - { - /* under at least win95 you seem to be given a standard - height for the menu and the height value is ignored */ - ItemInfo->Rect.bottom += GetSystemMetrics(SM_CYMENUSIZE); - } - else - { - ItemInfo->Rect.bottom += mis.itemHeight; - } - - TRACE("id=%04x size=%dx%d\n", ItemInfo->wID, mis.itemWidth, mis.itemHeight); - return; - } - - if (0 != (ItemInfo->fType & MF_SEPARATOR)) - { - ItemInfo->Rect.bottom += SEPARATOR_HEIGHT; - if( !MenuBar) - ItemInfo->Rect.right += CheckBitmapWidth + MenuCharSize.cx; - return; - } - - ItemInfo->XTab = 0; - - if (ItemInfo->hbmpItem) - { - SIZE Size; - - if (!MenuBar) /* hbmpItem */ - { - MenuGetBitmapItemSize(ItemInfo, &Size, WndOwner ); - /* Keep the size of the bitmap in callback mode to be able - * to draw it correctly */ - ItemInfo->Rect.right = ItemInfo->Rect.left + Size.cx; - if (MenuInfo->maxBmpSize.cx < abs(Size.cx) + MENU_ITEM_HBMP_SPACE || - MenuInfo->maxBmpSize.cy < abs(Size.cy)) - { - MenuInfo->maxBmpSize.cx = abs(Size.cx) + MENU_ITEM_HBMP_SPACE; - MenuInfo->maxBmpSize.cy = abs(Size.cy); - } - MenuSetRosMenuInfo(MenuInfo); - itemheight = Size.cy + 2; - - if( !(MenuInfo->dwStyle & MNS_NOCHECK)) - ItemInfo->Rect.right += 2 * CheckBitmapWidth; - ItemInfo->Rect.right += 4 + MenuCharSize.cx; - ItemInfo->XTab = ItemInfo->Rect.right; - ItemInfo->Rect.right += CheckBitmapWidth; - } - else /* hbmpItem & MenuBar */ - { - MenuGetBitmapItemSize(ItemInfo, &Size, WndOwner ); - ItemInfo->Rect.right += Size.cx; - if( ItemInfo->Text) ItemInfo->Rect.right += 2; - itemheight = Size.cy; - - /* Special case: Minimize button doesn't have a space behind it. */ - if (ItemInfo->hbmpItem == (HBITMAP)HBMMENU_MBAR_MINIMIZE || - ItemInfo->hbmpItem == (HBITMAP)HBMMENU_MBAR_MINIMIZE_D) - ItemInfo->Rect.right -= 1; - } - } - else if (!MenuBar) - { - if( !(MenuInfo->dwStyle & MNS_NOCHECK)) - ItemInfo->Rect.right += CheckBitmapWidth; - ItemInfo->Rect.right += 4 + MenuCharSize.cx; - ItemInfo->XTab = ItemInfo->Rect.right; - ItemInfo->Rect.right += CheckBitmapWidth; - } - - /* it must be a text item - unless it's the system menu */ - if (0 == (ItemInfo->fType & MF_SYSMENU) && ItemInfo->Text) - { - HFONT hfontOld = NULL; - RECT rc = ItemInfo->Rect; - LONG txtheight, txtwidth; - - if ( ItemInfo->fState & MFS_DEFAULT ) - { - hfontOld = SelectObject( Dc, hMenuFontBold ); - } - if (MenuBar) - { - txtheight = DrawTextW( Dc, ItemInfo->dwTypeData, -1, &rc, - DT_SINGLELINE|DT_CALCRECT); - ItemInfo->Rect.right += rc.right - rc.left; - itemheight = max( max( itemheight, txtheight), - GetSystemMetrics( SM_CYMENU) - 1); - ItemInfo->Rect.right += 2 * MenuCharSize.cx; - } - else - { - if ((p = strchrW( ItemInfo->dwTypeData, '\t' )) != NULL) - { - RECT tmprc = rc; - LONG tmpheight; - int n = (int)( p - ItemInfo->dwTypeData); - /* Item contains a tab (only meaningful in popup menus) */ - /* get text size before the tab */ - txtheight = DrawTextW( Dc, ItemInfo->dwTypeData, n, &rc, - DT_SINGLELINE|DT_CALCRECT); - txtwidth = rc.right - rc.left; - p += 1; /* advance past the Tab */ - /* get text size after the tab */ - tmpheight = DrawTextW( Dc, p, -1, &tmprc, DT_SINGLELINE|DT_CALCRECT); - ItemInfo->XTab += txtwidth; - txtheight = max( txtheight, tmpheight); - txtwidth += MenuCharSize.cx + /* space for the tab */ - tmprc.right - tmprc.left; /* space for the short cut */ - } - else - { - txtheight = DrawTextW( Dc, ItemInfo->dwTypeData, -1, &rc, - DT_SINGLELINE|DT_CALCRECT); - txtwidth = rc.right - rc.left; - ItemInfo->XTab += txtwidth; - } - ItemInfo->Rect.right += 2 + txtwidth; - itemheight = max( itemheight, max( txtheight + 2, MenuCharSize.cy + 4)); - } - if (hfontOld) SelectObject (Dc, hfontOld); - } - else if( MenuBar) - { - itemheight = max( itemheight, GetSystemMetrics(SM_CYMENU)-1); - } - ItemInfo->Rect.bottom += itemheight; - TRACE("(%ld,%ld)-(%ld,%ld)\n", ItemInfo->Rect.left, ItemInfo->Rect.top, ItemInfo->Rect.right, ItemInfo->Rect.bottom); -} - -/*********************************************************************** - * MenuPopupMenuCalcSize - * - * Calculate the size of a popup menu. - */ -static void FASTCALL -MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo, HWND WndOwner) -{ - ROSMENUITEMINFO ItemInfo; - HDC Dc; - int Start, i; - int OrgX, OrgY, MaxX, MaxTab, MaxTabWidth; - - MenuInfo->Width = MenuInfo->Height = 0; - if (0 == MenuInfo->MenuItemCount) - { - MenuSetRosMenuInfo(MenuInfo); - return; - } - - Dc = GetDC(NULL); - SelectObject(Dc, hMenuFont); - - Start = 0; - MaxX = 2 + 1; - - MenuInfo->maxBmpSize.cx = 0; - MenuInfo->maxBmpSize.cy = 0; - - MenuInitRosMenuItemInfo(&ItemInfo); - while (Start < MenuInfo->MenuItemCount) - { - OrgX = MaxX; - OrgY = 2; - - MaxTab = MaxTabWidth = 0; - - /* Parse items until column break or end of menu */ - for (i = Start; i < MenuInfo->MenuItemCount; i++) - { - if (! MenuGetRosMenuItemInfo(MenuInfo->Self, i, &ItemInfo)) - { - MenuCleanupRosMenuItemInfo(&ItemInfo); - MenuSetRosMenuInfo(MenuInfo); - return; - } - if (i != Start && - 0 != (ItemInfo.fType & (MF_MENUBREAK | MF_MENUBARBREAK))) - { - break; - } - MenuCalcItemSize(Dc, &ItemInfo, MenuInfo, WndOwner, OrgX, OrgY, FALSE); - if (! MenuSetRosMenuItemInfo(MenuInfo->Self, i, &ItemInfo)) - { - MenuCleanupRosMenuItemInfo(&ItemInfo); - MenuSetRosMenuInfo(MenuInfo); - return; - } -// Not sure here,, The patch from wine removes this. -// if (0 != (ItemInfo.fType & MF_MENUBARBREAK)) -// { -// OrgX++; -// } - MaxX = max(MaxX, ItemInfo.Rect.right); - OrgY = ItemInfo.Rect.bottom; - if ((ItemInfo.Text) && 0 != ItemInfo.XTab) - { - MaxTab = max(MaxTab, ItemInfo.XTab); - MaxTabWidth = max(MaxTabWidth, ItemInfo.Rect.right - ItemInfo.XTab); - } - } - - /* Finish the column (set all items to the largest width found) */ - MaxX = max(MaxX, MaxTab + MaxTabWidth); - while (Start < i) - { - if (MenuGetRosMenuItemInfo(MenuInfo->Self, Start, &ItemInfo)) - { - ItemInfo.Rect.right = MaxX; - if ((ItemInfo.Text) && 0 != ItemInfo.XTab) - { - ItemInfo.XTab = MaxTab; - } - MenuSetRosMenuItemInfo(MenuInfo->Self, Start, &ItemInfo); - } - Start++; - } - MenuInfo->Height = max(MenuInfo->Height, OrgY); - } - - MenuInfo->Width = MaxX; - - /* space for 3d border */ - MenuInfo->Height += 2; - MenuInfo->Width += 2; - - ReleaseDC(NULL, Dc); - MenuCleanupRosMenuItemInfo(&ItemInfo); - MenuSetRosMenuInfo(MenuInfo); -} - -/*********************************************************************** - * MenuMenuBarCalcSize - * - * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap - * height is off by 1 pixel which causes lengthy window relocations when - * active document window is maximized/restored. - * - * Calculate the size of the menu bar. - */ -static void FASTCALL -MenuMenuBarCalcSize(HDC Dc, LPRECT Rect, PROSMENUINFO MenuInfo, HWND WndOwner) -{ - ROSMENUITEMINFO ItemInfo; - int Start, i, OrgX, OrgY, MaxY, HelpPos; - - if (NULL == Rect || NULL == MenuInfo) - { - return; - } - if (0 == MenuInfo->MenuItemCount) - { - return; - } - - TRACE("left=%ld top=%ld right=%ld bottom=%ld\n", - Rect->left, Rect->top, Rect->right, Rect->bottom); - MenuInfo->Width = Rect->right - Rect->left; - MenuInfo->Height = 0; - MaxY = Rect->top + 1; - Start = 0; - HelpPos = -1; - - MenuInfo->maxBmpSize.cx = 0; - MenuInfo->maxBmpSize.cy = 0; - - MenuInitRosMenuItemInfo(&ItemInfo); - while (Start < MenuInfo->MenuItemCount) - { - if (! MenuGetRosMenuItemInfo(MenuInfo->Self, Start, &ItemInfo)) - { - MenuCleanupRosMenuItemInfo(&ItemInfo); - return; - } - OrgX = Rect->left; - OrgY = MaxY; - - /* Parse items until line break or end of menu */ - for (i = Start; i < MenuInfo->MenuItemCount; i++) - { - if (-1 == HelpPos && 0 != (ItemInfo.fType & MF_RIGHTJUSTIFY)) - { - HelpPos = i; - } - if (i != Start && - 0 != (ItemInfo.fType & (MF_MENUBREAK | MF_MENUBARBREAK))) - { - break; - } - - TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", OrgX, OrgY); - MenuCalcItemSize(Dc, &ItemInfo, MenuInfo, WndOwner, OrgX, OrgY, TRUE); - if (! MenuSetRosMenuItemInfo(MenuInfo->Self, i, &ItemInfo)) - { - MenuCleanupRosMenuItemInfo(&ItemInfo); - return; - } - - if (ItemInfo.Rect.right > Rect->right) - { - if (i != Start) - { - break; - } - else - { - ItemInfo.Rect.right = Rect->right; - } - } - MaxY = max(MaxY, ItemInfo.Rect.bottom ); - OrgX = ItemInfo.Rect.right; - if (i + 1 < MenuInfo->MenuItemCount) - { - if (! MenuGetRosMenuItemInfo(MenuInfo->Self, i + 1, &ItemInfo)) - { - MenuCleanupRosMenuItemInfo(&ItemInfo); - return; - } - } - } - -/* FIXME: Is this really needed? */ /*NO! it is not needed, why make the -HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */ -#if 0 - /* Finish the line (set all items to the largest height found) */ - while (Start < i) - { - if (MenuGetRosMenuItemInfo(MenuInfo->Self, Start, &ItemInfo)) - { - ItemInfo.Rect.bottom = MaxY; - MenuSetRosMenuItemInfo(MenuInfo->Self, Start, &ItemInfo); - } - Start++; - } -#else - Start = i; /* This works! */ -#endif - } - - Rect->bottom = MaxY; - MenuInfo->Height = Rect->bottom - Rect->top; - MenuSetRosMenuInfo(MenuInfo); - - if (-1 != HelpPos) - { - /* Flush right all items between the MF_RIGHTJUSTIFY and */ - /* the last item (if several lines, only move the last line) */ - if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->MenuItemCount - 1, &ItemInfo)) - { - MenuCleanupRosMenuItemInfo(&ItemInfo); - return; - } - OrgY = ItemInfo.Rect.top; - OrgX = Rect->right; - for (i = MenuInfo->MenuItemCount - 1; HelpPos <= i; i--) - { - if (i < HelpPos) - { - break; /* done */ - } - if (ItemInfo.Rect.top != OrgY) - { - break; /* Other line */ - } - if (OrgX <= ItemInfo.Rect.right) - { - break; /* Too far right already */ - } - ItemInfo.Rect.left += OrgX - ItemInfo.Rect.right; - ItemInfo.Rect.right = OrgX; - OrgX = ItemInfo.Rect.left; - MenuSetRosMenuItemInfo(MenuInfo->Self, i, &ItemInfo); - if (HelpPos + 1 <= i && - ! MenuGetRosMenuItemInfo(MenuInfo->Self, i - 1, &ItemInfo)) - { - MenuCleanupRosMenuItemInfo(&ItemInfo); - return; - } - } - } - - MenuCleanupRosMenuItemInfo(&ItemInfo); -} - /*********************************************************************** * DrawMenuBarTemp (USER32.@) * @@ -1843,476 +2228,6 @@ DrawMenuBarTemp(HWND Wnd, HDC DC, LPRECT Rect, HMENU Menu, HFONT Font) return MenuInfo.Height; } - -/*********************************************************************** - * MenuDrawMenuBar - * - * Paint a menu bar. Returns the height of the menu bar. - * called from [windows/nonclient.c] - */ -UINT MenuDrawMenuBar(HDC DC, LPRECT Rect, HWND Wnd, BOOL SuppressDraw) -{ - ROSMENUINFO MenuInfo; - HFONT FontOld = NULL; - HMENU Menu = GetMenu(Wnd); - - if (NULL == Rect || ! MenuGetRosMenuInfo(&MenuInfo, Menu)) - { - return GetSystemMetrics(SM_CYMENU); - } - - if (SuppressDraw) - { - FontOld = SelectObject(DC, hMenuFont); - - MenuMenuBarCalcSize(DC, Rect, &MenuInfo, Wnd); - - Rect->bottom = Rect->top + MenuInfo.Height; - - if (NULL != FontOld) - { - SelectObject(DC, FontOld); - } - return MenuInfo.Height; - } - else - { - return DrawMenuBarTemp(Wnd, DC, Rect, Menu, NULL); - } -} - -/*********************************************************************** - * MenuInitTracking - */ -static BOOL FASTCALL -MenuInitTracking(HWND Wnd, HMENU Menu, BOOL Popup, UINT Flags) -{ - TRACE("Wnd=%p Menu=%p\n", Wnd, Menu); - - HideCaret(0); - - /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */ - if (0 == (Flags & TPM_NONOTIFY)) - { - SendMessageW(Wnd, WM_ENTERMENULOOP, Popup, 0); - } - - SendMessageW(Wnd, WM_SETCURSOR, (WPARAM) Wnd, HTCAPTION); - - if (0 == (Flags & TPM_NONOTIFY)) - { - ROSMENUINFO MenuInfo; - - SendMessageW(Wnd, WM_INITMENU, (WPARAM)Menu, 0); - - MenuGetRosMenuInfo(&MenuInfo, Menu); - - if (0 == MenuInfo.Height) - { - /* app changed/recreated menu bar entries in WM_INITMENU - Recalculate menu sizes else clicks will not work */ - SetWindowPos(Wnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | - SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED ); - - } - /* This makes the menus of applications built with Delphi work. - * It also enables menus to be displayed in more than one window, - * but there are some bugs left that need to be fixed in this case. - */ - if(MenuInfo.Self == Menu) - { - MenuInfo.Wnd = Wnd; - MenuSetRosMenuInfo(&MenuInfo); - } - } - - return TRUE; -} - - -/*********************************************************************** - * MenuShowPopup - * - * Display a popup menu. - */ -static BOOL FASTCALL -MenuShowPopup(HWND WndOwner, HMENU Menu, UINT Id, UINT flags, - INT X, INT Y, INT XAnchor, INT YAnchor ) -{ - ROSMENUINFO MenuInfo; - ROSMENUITEMINFO ItemInfo; - UINT Width, Height; - POINT pt; - HMONITOR monitor; - MONITORINFO info; - - TRACE("owner=%x hmenu=%x id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n", - WndOwner, Menu, Id, X, Y, XAnchor, YAnchor); - - if (! MenuGetRosMenuInfo(&MenuInfo, Menu)) - { - return FALSE; - } - - if (NO_SELECTED_ITEM != MenuInfo.FocusedItem) - { - MenuInitRosMenuItemInfo(&ItemInfo); - if (MenuGetRosMenuItemInfo(MenuInfo.Self, MenuInfo.FocusedItem, &ItemInfo)) - { - ItemInfo.fMask |= MIIM_STATE; - ItemInfo.fState &= ~(MF_HILITE|MF_MOUSESELECT); - MenuSetRosMenuItemInfo(MenuInfo.Self, MenuInfo.FocusedItem, &ItemInfo); - } - MenuCleanupRosMenuItemInfo(&ItemInfo); - MenuInfo.FocusedItem = NO_SELECTED_ITEM; - } - - /* store the owner for DrawItem */ - MenuInfo.WndOwner = WndOwner; - MenuSetRosMenuInfo(&MenuInfo); - - MenuPopupMenuCalcSize(&MenuInfo, WndOwner); - - /* adjust popup menu pos so that it fits within the desktop */ - - Width = MenuInfo.Width + GetSystemMetrics(SM_CXBORDER); - Height = MenuInfo.Height + GetSystemMetrics(SM_CYBORDER); - - /* FIXME: should use item rect */ - pt.x = X; - pt.y = Y; - monitor = MonitorFromPoint( pt, MONITOR_DEFAULTTONEAREST ); - info.cbSize = sizeof(info); - GetMonitorInfoW( monitor, &info ); - - if( flags & TPM_RIGHTALIGN ) X -= Width; - if( flags & TPM_CENTERALIGN ) X -= Width / 2; - - if( flags & TPM_BOTTOMALIGN ) Y -= Height; - if( flags & TPM_VCENTERALIGN ) Y -= Height / 2; - - if (X + Width > info.rcWork.right) - { - if ( XAnchor && X >= Width - XAnchor) - X -= Width - XAnchor; - - if ( X + Width > info.rcWork.right) - X = info.rcWork.right - Width; - } - - if ( X < info.rcWork.left ) X = info.rcWork.left; - - if (Y + Height > info.rcWork.bottom) - { - if ( YAnchor && Y >= Height + YAnchor) - Y -= Height + YAnchor; - - if ( Y + Height > info.rcWork.bottom) - Y = info.rcWork.bottom - Height; - } - - if ( Y < info.rcWork.top ) Y = info.rcWork.top; - - /* NOTE: In Windows, top menu popup is not owned. */ - MenuInfo.Wnd = CreateWindowExW(0, POPUPMENU_CLASS_ATOMW, NULL, - WS_POPUP, X, Y, Width, Height, - WndOwner, 0, (HINSTANCE) GetWindowLongPtrW(WndOwner, GWLP_HINSTANCE), - (LPVOID) MenuInfo.Self); - if (NULL == MenuInfo.Wnd || ! MenuSetRosMenuInfo(&MenuInfo)) - { - return FALSE; - } - if (NULL == TopPopup) - { - TopPopup = MenuInfo.Wnd; - } - - /* Display the window */ - SetWindowPos(MenuInfo.Wnd, HWND_TOPMOST, 0, 0, 0, 0, - SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE); - UpdateWindow(MenuInfo.Wnd); - - return TRUE; -} - -/*********************************************************************** - * MenuFindSubMenu - * - * Find a Sub menu. Return the position of the submenu, and modifies - * *hmenu in case it is found in another sub-menu. - * If the submenu cannot be found, NO_SELECTED_ITEM is returned. - */ -static UINT FASTCALL -MenuFindSubMenu(HMENU *Menu, HMENU SubTarget) -{ - ROSMENUINFO MenuInfo; - ROSMENUITEMINFO ItemInfo; - UINT i; - HMENU SubMenu; - UINT Pos; - - if ((HMENU) 0xffff == *Menu - || ! MenuGetRosMenuInfo(&MenuInfo, *Menu)) - { - return NO_SELECTED_ITEM; - } - - MenuInitRosMenuItemInfo(&ItemInfo); - for (i = 0; i < MenuInfo.MenuItemCount; i++) - { - if (! MenuGetRosMenuItemInfo(MenuInfo.Self, i, &ItemInfo)) - { - MenuCleanupRosMenuItemInfo(&ItemInfo); - return NO_SELECTED_ITEM; - } - if (0 == (ItemInfo.fType & MF_POPUP)) - { - continue; - } - if (ItemInfo.hSubMenu == SubTarget) - { - MenuCleanupRosMenuItemInfo(&ItemInfo); - return i; - } - SubMenu = ItemInfo.hSubMenu; - Pos = MenuFindSubMenu(&SubMenu, SubTarget); - if (NO_SELECTED_ITEM != Pos) - { - *Menu = SubMenu; - return Pos; - } - } - MenuCleanupRosMenuItemInfo(&ItemInfo); - - return NO_SELECTED_ITEM; -} - -/*********************************************************************** - * MenuSelectItem - */ -static void FASTCALL -MenuSelectItem(HWND WndOwner, PROSMENUINFO MenuInfo, UINT Index, - BOOL SendMenuSelect, HMENU TopMenu) -{ - HDC Dc; - ROSMENUITEMINFO ItemInfo; - ROSMENUINFO TopMenuInfo; - int Pos; - - TRACE("owner=%x menu=%p index=0x%04x select=0x%04x\n", WndOwner, MenuInfo, Index, SendMenuSelect); - - if (NULL == MenuInfo || 0 == MenuInfo->MenuItemCount || NULL == MenuInfo->Wnd) - { - return; - } - - if (MenuInfo->FocusedItem == Index) - { - return; - } - - if (0 != (MenuInfo->Flags & MF_POPUP)) - { - Dc = GetDC(MenuInfo->Wnd); - } - else - { - Dc = GetDCEx(MenuInfo->Wnd, 0, DCX_CACHE | DCX_WINDOW); - } - - if (NULL == TopPopup) - { - TopPopup = MenuInfo->Wnd; - } - - SelectObject(Dc, hMenuFont); - MenuInitRosMenuItemInfo(&ItemInfo); - /* Clear previous highlighted item */ - if (NO_SELECTED_ITEM != MenuInfo->FocusedItem) - { - if (MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->FocusedItem, &ItemInfo)) - { - ItemInfo.fMask |= MIIM_STATE; - ItemInfo.fState &= ~(MF_HILITE|MF_MOUSESELECT); - MenuSetRosMenuItemInfo(MenuInfo->Self, MenuInfo->FocusedItem, &ItemInfo); - } - MenuDrawMenuItem(MenuInfo->Wnd, MenuInfo, WndOwner, Dc, &ItemInfo, - MenuInfo->Height, ! (MenuInfo->Flags & MF_POPUP), - ODA_SELECT); - } - - /* Highlight new item (if any) */ - MenuInfo->FocusedItem = Index; - MenuSetRosMenuInfo(MenuInfo); - if (NO_SELECTED_ITEM != MenuInfo->FocusedItem) - { - if (MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->FocusedItem, &ItemInfo)) - { - if (0 == (ItemInfo.fType & MF_SEPARATOR)) - { - ItemInfo.fMask |= MIIM_STATE; - ItemInfo.fState |= MF_HILITE; - MenuSetRosMenuItemInfo(MenuInfo->Self, MenuInfo->FocusedItem, &ItemInfo); - MenuDrawMenuItem(MenuInfo->Wnd, MenuInfo, WndOwner, Dc, - &ItemInfo, MenuInfo->Height, ! (MenuInfo->Flags & MF_POPUP), - ODA_SELECT); - } - if (SendMenuSelect) - { - SendMessageW(WndOwner, WM_MENUSELECT, - MAKELONG(ItemInfo.fType & MF_POPUP ? Index : ItemInfo.wID, - ItemInfo.fType | ItemInfo.fState | MF_MOUSESELECT | - (MenuInfo->Flags & MF_SYSMENU)), (LPARAM) MenuInfo->Self); - } - } - } - else if (SendMenuSelect) - { - if (NULL != TopMenu) - { - Pos = MenuFindSubMenu(&TopMenu, MenuInfo->Self); - if (NO_SELECTED_ITEM != Pos) - { - if (MenuGetRosMenuInfo(&TopMenuInfo, TopMenu) - && MenuGetRosMenuItemInfo(TopMenu, Pos, &ItemInfo)) - { - SendMessageW(WndOwner, WM_MENUSELECT, - MAKELONG(Pos, ItemInfo.fType | ItemInfo.fState - | MF_MOUSESELECT - | (TopMenuInfo.Flags & MF_SYSMENU)), - (LPARAM) TopMenu); - } - } - } - } - MenuCleanupRosMenuItemInfo(&ItemInfo); - ReleaseDC(MenuInfo->Wnd, Dc); -} - -/*********************************************************************** - * MenuMoveSelection - * - * Moves currently selected item according to the Offset parameter. - * If there is no selection then it should select the last item if - * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT. - */ -static void FASTCALL -MenuMoveSelection(HWND WndOwner, PROSMENUINFO MenuInfo, INT Offset) -{ - INT i; - ROSMENUITEMINFO ItemInfo; - INT OrigPos; - - TRACE("hwnd=%x menu=%x off=0x%04x\n", WndOwner, MenuInfo, Offset); - - /* Prevent looping */ - if (0 == MenuInfo->MenuItemCount || 0 == Offset) - return; - else if (Offset < -1) - Offset = -1; - else if (Offset > 1) - Offset = 1; - - MenuInitRosMenuItemInfo(&ItemInfo); - - OrigPos = MenuInfo->FocusedItem; - if (OrigPos == NO_SELECTED_ITEM) /* NO_SELECTED_ITEM is not -1 ! */ - { - OrigPos = 0; - i = -1; - } - else - { - i = MenuInfo->FocusedItem; - } - - do - { - /* Step */ - i += Offset; - /* Clip and wrap around */ - if (i < 0) - { - i = MenuInfo->MenuItemCount - 1; - } - else if (i >= MenuInfo->MenuItemCount) - { - i = 0; - } - /* If this is a good candidate; */ - if (MenuGetRosMenuItemInfo(MenuInfo->Self, i, &ItemInfo) && - 0 == (ItemInfo.fType & MF_SEPARATOR)) - { - MenuSelectItem(WndOwner, MenuInfo, i, TRUE, NULL); - MenuCleanupRosMenuItemInfo(&ItemInfo); - return; - } - } while (i != OrigPos); - - /* Not found */ - MenuCleanupRosMenuItemInfo(&ItemInfo); -} - -/*********************************************************************** - * MenuInitSysMenuPopup - * - * Grey the appropriate items in System menu. - */ -void FASTCALL -MenuInitSysMenuPopup(HMENU Menu, DWORD Style, DWORD ClsStyle, LONG HitTest ) -{ - BOOL Gray; - UINT DefItem; - #if 0 - MENUITEMINFOW mii; - #endif - - Gray = 0 == (Style & WS_THICKFRAME) || 0 != (Style & (WS_MAXIMIZE | WS_MINIMIZE)); - EnableMenuItem(Menu, SC_SIZE, (Gray ? MF_GRAYED : MF_ENABLED)); - Gray = 0 != (Style & WS_MAXIMIZE); - EnableMenuItem(Menu, SC_MOVE, (Gray ? MF_GRAYED : MF_ENABLED)); - Gray = 0 == (Style & WS_MINIMIZEBOX) || 0 != (Style & WS_MINIMIZE); - EnableMenuItem(Menu, SC_MINIMIZE, (Gray ? MF_GRAYED : MF_ENABLED)); - Gray = 0 == (Style & WS_MAXIMIZEBOX) || 0 != (Style & WS_MAXIMIZE); - EnableMenuItem(Menu, SC_MAXIMIZE, (Gray ? MF_GRAYED : MF_ENABLED)); - Gray = 0 == (Style & (WS_MAXIMIZE | WS_MINIMIZE)); - EnableMenuItem(Menu, SC_RESTORE, (Gray ? MF_GRAYED : MF_ENABLED)); - Gray = 0 != (ClsStyle & CS_NOCLOSE); - - /* The menu item must keep its state if it's disabled */ - if (Gray) - { - EnableMenuItem(Menu, SC_CLOSE, MF_GRAYED); - } - - /* Set default menu item */ - if(Style & WS_MINIMIZE) - { - DefItem = SC_RESTORE; - } - else - { - if(HitTest == HTCAPTION) - { - DefItem = ((Style & (WS_MAXIMIZE | WS_MINIMIZE)) ? SC_RESTORE : SC_MAXIMIZE); - } - else - { - DefItem = SC_CLOSE; - } - } - #if 0 - mii.cbSize = sizeof(MENUITEMINFOW); - mii.fMask |= MIIM_STATE; - if((DefItem != SC_CLOSE) && GetMenuItemInfoW(Menu, DefItem, FALSE, &mii) && - (mii.fState & (MFS_GRAYED | MFS_DISABLED))) - { - DefItem = SC_CLOSE; - } - #endif - SetMenuDefaultItem(Menu, DefItem, MF_BYCOMMAND); -} - /*********************************************************************** * MenuShowSubPopup * @@ -2452,7 +2367,7 @@ MenuHideSubPopups(HWND WndOwner, PROSMENUINFO MenuInfo, BOOL SendMenuSelect) TRACE("owner=%x menu=%x 0x%04x\n", WndOwner, MenuInfo, SendMenuSelect); - if (NULL != MenuInfo && NULL != TopPopup && NO_SELECTED_ITEM != MenuInfo->FocusedItem) + if (NULL != MenuInfo && NULL != top_popup && NO_SELECTED_ITEM != MenuInfo->FocusedItem) { MenuInitRosMenuItemInfo(&ItemInfo); ItemInfo.fMask |= MIIM_FTYPE | MIIM_STATE; @@ -2809,86 +2724,6 @@ MenuMouseMove(MTRACKER *Mt, HMENU PtMenu, UINT Flags) return TRUE; } -/****************************************************************************** - * - * UINT MenuGetStartOfNextColumn(PROSMENUINFO MenuInfo) - */ -static UINT MenuGetStartOfNextColumn(PROSMENUINFO MenuInfo) -{ - UINT i; - PROSMENUITEMINFO MenuItems; - - i = MenuInfo->FocusedItem; - if (NO_SELECTED_ITEM == i) - { - return i; - } - - if (MenuGetAllRosMenuItemInfo(MenuInfo->Self, &MenuItems) <= 0) - { - return NO_SELECTED_ITEM; - } - - for (i++ ; i < MenuInfo->MenuItemCount; i++) - { - if (0 != (MenuItems[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK))) - { - return i; - } - } - - return NO_SELECTED_ITEM; -} - -/****************************************************************************** - * - * UINT MenuGetStartOfPrevColumn(PROSMENUINFO MenuInfo) - */ -static UINT FASTCALL -MenuGetStartOfPrevColumn(PROSMENUINFO MenuInfo) -{ - UINT i; - PROSMENUITEMINFO MenuItems; - - if (0 == MenuInfo->FocusedItem || NO_SELECTED_ITEM == MenuInfo->FocusedItem) - { - return NO_SELECTED_ITEM; - } - - if (MenuGetAllRosMenuItemInfo(MenuInfo->Self, &MenuItems) <= 0) - { - return NO_SELECTED_ITEM; - } - - /* Find the start of the column */ - - for (i = MenuInfo->FocusedItem; - 0 != i && 0 == (MenuItems[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK)); - --i) - { - ; /* empty */ - } - - if (0 == i) - { - MenuCleanupAllRosMenuItemInfo(MenuItems); - return NO_SELECTED_ITEM; - } - - for (--i; 0 != i; --i) - { - if (MenuItems[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK)) - { - break; - } - } - - MenuCleanupAllRosMenuItemInfo(MenuItems); - TRACE("ret %d.\n", i ); - - return i; -} - /*********************************************************************** * MenuGetSubPopup * @@ -3202,36 +3037,29 @@ MenuKeyLeft(MTRACKER* Mt, UINT Flags) * * Handle a VK_RIGHT key event in a menu. */ -static void FASTCALL -MenuKeyRight(MTRACKER *Mt, UINT Flags) +static void FASTCALL MenuKeyRight(MTRACKER *Mt, UINT Flags) { - HMENU MenuTmp; - ROSMENUINFO MenuInfo; - ROSMENUINFO CurrentMenuInfo; - UINT NextCol; + HMENU hmenutmp; + ROSMENUINFO MenuInfo; + ROSMENUINFO CurrentMenuInfo; + UINT NextCol; - TRACE("MenuKeyRight called, cur %p, top %p.\n", + TRACE("MenuKeyRight called, cur %p, top %p.\n", Mt->CurrentMenu, Mt->TopMenu); - if (! MenuGetRosMenuInfo(&MenuInfo, Mt->TopMenu)) - { - return; - } - if (0 != (MenuInfo.Flags & MF_POPUP) || (Mt->CurrentMenu != Mt->TopMenu)) + if (! MenuGetRosMenuInfo(&MenuInfo, Mt->TopMenu)) return; + if ((MenuInfo.Flags & MF_POPUP) || (Mt->CurrentMenu != Mt->TopMenu)) { /* If already displaying a popup, try to display sub-popup */ - MenuTmp = Mt->CurrentMenu; + hmenutmp = Mt->CurrentMenu; if (MenuGetRosMenuInfo(&CurrentMenuInfo, Mt->CurrentMenu)) { Mt->CurrentMenu = MenuShowSubPopup(Mt->OwnerWnd, &CurrentMenuInfo, TRUE, Flags); } /* if subpopup was displayed then we are done */ - if (MenuTmp != Mt->CurrentMenu) - { - return; - } + if (hmenutmp != Mt->CurrentMenu) return; } if (! MenuGetRosMenuInfo(&CurrentMenuInfo, Mt->CurrentMenu)) @@ -3255,20 +3083,18 @@ MenuKeyRight(MTRACKER *Mt, UINT Flags) if (Mt->CurrentMenu != Mt->TopMenu) { MenuHideSubPopups(Mt->OwnerWnd, &MenuInfo, FALSE ); - MenuTmp = Mt->CurrentMenu = Mt->TopMenu; + hmenutmp = Mt->CurrentMenu = Mt->TopMenu; } else { - MenuTmp = NULL; + hmenutmp = NULL; } /* try to move to the next item */ - if (! MenuDoNextMenu(Mt, VK_RIGHT)) - { + if ( !MenuDoNextMenu(Mt, VK_RIGHT)) MenuMoveSelection(Mt->OwnerWnd, &MenuInfo, ITEM_NEXT); - } - if (NULL != MenuTmp || 0 != (Mt->TrackFlags & TF_SUSPENDPOPUP)) + if ( hmenutmp || Mt->TrackFlags & TF_SUSPENDPOPUP ) { if (! MenuSuspendPopup(Mt, WM_KEYDOWN) && MenuGetRosMenuInfo(&MenuInfo, Mt->TopMenu)) @@ -3280,525 +3106,466 @@ MenuKeyRight(MTRACKER *Mt, UINT Flags) } } -/*********************************************************************** - * MenuFindItemByKey - * - * Find the menu item selected by a key press. - * Return item id, -1 if none, -2 if we should close the menu. - */ -static UINT FASTCALL -MenuFindItemByKey(HWND WndOwner, PROSMENUINFO MenuInfo, - WCHAR Key, BOOL ForceMenuChar) -{ - ROSMENUINFO SysMenuInfo; - PROSMENUITEMINFO Items, ItemInfo; - LRESULT MenuChar; - UINT i; - - TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char) Key, Key, MenuInfo); - - if (NULL == MenuInfo || ! IsMenu(MenuInfo->Self)) - { - if (MenuGetRosMenuInfo(&SysMenuInfo, GetSystemMenu(WndOwner, FALSE))) - { - MenuInfo = &SysMenuInfo; - } - else - { - MenuInfo = NULL; - } - } - - if (NULL != MenuInfo) - { - if (MenuGetAllRosMenuItemInfo(MenuInfo->Self, &Items) <= 0) - { - return -1; - } - if (! ForceMenuChar) - { - Key = toupperW(Key); - ItemInfo = Items; - for (i = 0; i < MenuInfo->MenuItemCount; i++, ItemInfo++) - { - if ((ItemInfo->Text) && NULL != ItemInfo->dwTypeData) - { - WCHAR *p = (WCHAR *) ItemInfo->dwTypeData - 2; - do - { - p = strchrW(p + 2, '&'); - } - while (NULL != p && L'&' == p[1]); - if (NULL != p && (toupperW(p[1]) == Key)) - { - return i; - } - } - } - } - - MenuChar = SendMessageW(WndOwner, WM_MENUCHAR, - MAKEWPARAM(Key, MenuInfo->Flags), (LPARAM) MenuInfo->Self); - if (2 == HIWORD(MenuChar)) - { - return LOWORD(MenuChar); - } - if (1 == HIWORD(MenuChar)) - { - return (UINT) (-2); - } - } - - return (UINT)(-1); -} - /*********************************************************************** * MenuTrackMenu * * Menu tracking code. */ -static INT FASTCALL -MenuTrackMenu(HMENU Menu, UINT Flags, INT x, INT y, - HWND Wnd, const RECT *Rect ) +static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y, + HWND hwnd, const RECT *lprect ) { - MSG Msg; - ROSMENUINFO MenuInfo; - ROSMENUITEMINFO ItemInfo; - BOOL fRemove; - INT ExecutedMenuId = -1; - MTRACKER Mt; - BOOL EnterIdleSent = FALSE; + MSG msg; + ROSMENUINFO MenuInfo; + ROSMENUITEMINFO ItemInfo; + BOOL fRemove; + INT executedMenuId = -1; + MTRACKER mt; + BOOL enterIdleSent = FALSE; - Mt.TrackFlags = 0; - Mt.CurrentMenu = Menu; - Mt.TopMenu = Menu; - Mt.OwnerWnd = Wnd; - Mt.Pt.x = x; - Mt.Pt.y = y; + mt.TrackFlags = 0; + mt.CurrentMenu = hmenu; + mt.TopMenu = hmenu; + mt.OwnerWnd = hwnd; + mt.Pt.x = x; + mt.Pt.y = y; - TRACE("Menu=%x Flags=0x%08x (%d,%d) Wnd=%x (%ld,%ld)-(%ld,%ld)\n", - Menu, Flags, x, y, Wnd, Rect ? Rect->left : 0, Rect ? Rect->top : 0, - Rect ? Rect->right : 0, Rect ? Rect->bottom : 0); + TRACE("hmenu=%p flags=0x%08x (%d,%d) hwnd=%x (%ld,%ld)-(%ld,%ld)\n", + hmenu, wFlags, x, y, hwnd, lprect ? lprect->left : 0, lprect ? lprect->top : 0, + lprect ? lprect->right : 0, lprect ? lprect->bottom : 0); - if (!IsMenu(Menu)) - { - SetLastError( ERROR_INVALID_MENU_HANDLE ); - return FALSE; - } - - fEndMenu = FALSE; - if (! MenuGetRosMenuInfo(&MenuInfo, Menu)) + if (!IsMenu(hmenu)) { - return FALSE; + SetLastError( ERROR_INVALID_MENU_HANDLE ); + return FALSE; } - if (0 != (Flags & TPM_BUTTONDOWN)) + fEndMenu = FALSE; + if (! MenuGetRosMenuInfo(&MenuInfo, hmenu)) { - /* Get the result in order to start the tracking or not */ - fRemove = MenuButtonDown(&Mt, Menu, Flags); - fEndMenu = ! fRemove; + return FALSE; } - SetCapture(Mt.OwnerWnd); - (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER, Mt.OwnerWnd); - - ERR("MenuTrackMenu 1\n"); - while (! fEndMenu) + if (wFlags & TPM_BUTTONDOWN) { - PVOID menu = ValidateHandle(Mt.CurrentMenu, VALIDATE_TYPE_MENU); - if (!menu) /* sometimes happens if I do a window manager close */ - break; + /* Get the result in order to start the tracking or not */ + fRemove = MenuButtonDown( &mt, hmenu, wFlags ); + fEndMenu = !fRemove; + } - /* we have to keep the message in the queue until it's - * clear that menu loop is not over yet. */ + SetCapture(mt.OwnerWnd); + (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER, mt.OwnerWnd); - for (;;) + ERR("MenuTrackMenu 1\n"); + while (! fEndMenu) + { + PVOID menu = ValidateHandle(mt.CurrentMenu, VALIDATE_TYPE_MENU); + if (!menu) /* sometimes happens if I do a window manager close */ + break; + + /* we have to keep the message in the queue until it's + * clear that menu loop is not over yet. */ + + for (;;) { - if (PeekMessageW(&Msg, 0, 0, 0, PM_NOREMOVE)) + if (PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE )) { - if (! CallMsgFilterW(&Msg, MSGF_MENU)) - { - break; - } - /* remove the message from the queue */ - PeekMessageW(&Msg, 0, Msg.message, Msg.message, PM_REMOVE ); + if (!CallMsgFilterW( &msg, MSGF_MENU )) break; + /* remove the message from the queue */ + PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE ); } - else + else { - if (! EnterIdleSent) + if (!enterIdleSent) { - HWND Win = (0 != (Flags & TPM_ENTERIDLEEX) - && 0 != (MenuInfo.Flags & MF_POPUP)) ? MenuInfo.Wnd : NULL; - EnterIdleSent = TRUE; - SendMessageW(Mt.OwnerWnd, WM_ENTERIDLE, MSGF_MENU, (LPARAM) Win); + HWND win = (wFlags & TPM_ENTERIDLEEX) && (MenuInfo.Flags & MF_POPUP) ? MenuInfo.Wnd : NULL; + enterIdleSent = TRUE; + SendMessageW( mt.OwnerWnd, WM_ENTERIDLE, MSGF_MENU, (LPARAM) win); } - WaitMessage(); + WaitMessage(); } } - /* check if EndMenu() tried to cancel us, by posting this message */ - if (WM_CANCELMODE == Msg.message) + /* check if EndMenu() tried to cancel us, by posting this message */ + if (msg.message == WM_CANCELMODE) { - /* we are now out of the loop */ - fEndMenu = TRUE; + /* we are now out of the loop */ + fEndMenu = TRUE; - /* remove the message from the queue */ - PeekMessageW(&Msg, 0, Msg.message, Msg.message, PM_REMOVE); + /* remove the message from the queue */ + PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE ); - /* break out of internal loop, ala ESCAPE */ - break; + /* break out of internal loop, ala ESCAPE */ + break; } - TranslateMessage(&Msg); - Mt.Pt = Msg.pt; + TranslateMessage( &msg ); + mt.Pt = msg.pt; - if (Msg.hwnd == MenuInfo.Wnd || WM_TIMER != Msg.message) + if ( (msg.hwnd == MenuInfo.Wnd) || (msg.message!=WM_TIMER) ) + enterIdleSent=FALSE; + + fRemove = FALSE; + if ((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST)) { - EnterIdleSent = FALSE; - } + /* + * Use the mouse coordinates in lParam instead of those in the MSG + * struct to properly handle synthetic messages. They are already + * in screen coordinates. + */ + mt.Pt.x = (short)LOWORD(msg.lParam); + mt.Pt.y = (short)HIWORD(msg.lParam); - fRemove = FALSE; - if (WM_MOUSEFIRST <= Msg.message && Msg.message <= WM_MOUSELAST) - { - /* - * Use the mouse coordinates in lParam instead of those in the MSG - * struct to properly handle synthetic messages. They are already - * in screen coordinates. - */ - Mt.Pt.x = (short) LOWORD(Msg.lParam); - Mt.Pt.y = (short) HIWORD(Msg.lParam); + /* Find a menu for this mouse event */ + hmenu = MenuPtMenu(mt.TopMenu, mt.Pt); - /* Find a menu for this mouse event */ - Menu = MenuPtMenu(Mt.TopMenu, Mt.Pt); - - switch(Msg.message) + switch(msg.message) { - /* no WM_NC... messages in captured state */ + /* no WM_NC... messages in captured state */ - case WM_RBUTTONDBLCLK: - case WM_RBUTTONDOWN: - if (0 == (Flags & TPM_RIGHTBUTTON)) - { + case WM_RBUTTONDBLCLK: + case WM_RBUTTONDOWN: + if (!(wFlags & TPM_RIGHTBUTTON)) break; + /* fall through */ + case WM_LBUTTONDBLCLK: + case WM_LBUTTONDOWN: + /* If the message belongs to the menu, removes it from the queue */ + /* Else, end menu tracking */ + fRemove = MenuButtonDown(&mt, hmenu, wFlags); + fEndMenu = !fRemove; break; - } - /* fall through */ - case WM_LBUTTONDBLCLK: - case WM_LBUTTONDOWN: - /* If the message belongs to the menu, removes it from the queue */ - /* Else, end menu tracking */ - fRemove = MenuButtonDown(&Mt, Menu, Flags); - fEndMenu = ! fRemove; - break; - case WM_RBUTTONUP: - if (0 == (Flags & TPM_RIGHTBUTTON)) - { - break; - } - /* fall through */ - case WM_LBUTTONUP: - /* Check if a menu was selected by the mouse */ - if (NULL != Menu) - { - ExecutedMenuId = MenuButtonUp(&Mt, Menu, Flags); + case WM_RBUTTONUP: + if (!(wFlags & TPM_RIGHTBUTTON)) break; + /* fall through */ + case WM_LBUTTONUP: + /* Check if a menu was selected by the mouse */ + if (hmenu) + { + executedMenuId = MenuButtonUp( &mt, hmenu, wFlags); - /* End the loop if ExecutedMenuId is an item ID */ - /* or if the job was done (ExecutedMenuId = 0). */ - fEndMenu = fRemove = (-1 != ExecutedMenuId); - } - else - { + /* End the loop if executedMenuId is an item ID */ + /* or if the job was done (executedMenuId = 0). */ + fEndMenu = fRemove = (executedMenuId != -1); + } /* No menu was selected by the mouse */ /* if the function was called by TrackPopupMenu, continue with the menu tracking. If not, stop it */ - fEndMenu = (0 != (Flags & TPM_POPUPMENU) ? FALSE : TRUE); - } - break; + else + fEndMenu = ((wFlags & TPM_POPUPMENU) ? FALSE : TRUE); - case WM_MOUSEMOVE: - if (Menu) - { - fEndMenu |= ! MenuMouseMove(&Mt, Menu, Flags); - } - break; + break; - } /* switch(Msg.message) - mouse */ - } - else if (WM_KEYFIRST <= Msg.message && Msg.message <= WM_KEYLAST) - { - fRemove = TRUE; /* Keyboard messages are always removed */ - switch(Msg.message) + case WM_MOUSEMOVE: + /* the selected menu item must be changed every time */ + /* the mouse moves. */ + + if (hmenu) + fEndMenu |= !MenuMouseMove( &mt, hmenu, wFlags ); + break; + + } /* switch(msg.message) - mouse */ + } + else if ((msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST)) + { + fRemove = TRUE; /* Keyboard messages are always removed */ + switch(msg.message) { - case WM_SYSKEYDOWN: - case WM_KEYDOWN: - switch(Msg.wParam) - { + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + switch(msg.wParam) + { case VK_MENU: - fEndMenu = TRUE; - break; + case VK_F10: + fEndMenu = TRUE; + break; + case VK_HOME: case VK_END: - if (MenuGetRosMenuInfo(&MenuInfo, Mt.CurrentMenu)) + if (MenuGetRosMenuInfo(&MenuInfo, mt.CurrentMenu)) { - MenuSelectItem(Mt.OwnerWnd, &MenuInfo, NO_SELECTED_ITEM, - FALSE, 0 ); - MenuMoveSelection(Mt.OwnerWnd, &MenuInfo, - VK_HOME == Msg.wParam ? ITEM_NEXT : ITEM_PREV); + MenuSelectItem(mt.OwnerWnd, &MenuInfo, + NO_SELECTED_ITEM, FALSE, 0 ); + MenuMoveSelection(mt.OwnerWnd, &MenuInfo, + VK_HOME == msg.wParam ? ITEM_NEXT : ITEM_PREV); } - break; + break; case VK_UP: case VK_DOWN: /* If on menu bar, pull-down the menu */ - if (MenuGetRosMenuInfo(&MenuInfo, Mt.CurrentMenu)) + if (MenuGetRosMenuInfo(&MenuInfo, mt.CurrentMenu)) { - if (0 == (MenuInfo.Flags & MF_POPUP)) + if (!(MenuInfo.Flags & MF_POPUP)) { - if (MenuGetRosMenuInfo(&MenuInfo, Mt.TopMenu)) - { - Mt.CurrentMenu = MenuShowSubPopup(Mt.OwnerWnd, &MenuInfo, - TRUE, Flags); - } - } - else /* otherwise try to move selection */ - { - MenuMoveSelection(Mt.OwnerWnd, &MenuInfo, - VK_DOWN == Msg.wParam ? ITEM_NEXT : ITEM_PREV); + if (MenuGetRosMenuInfo(&MenuInfo, mt.TopMenu)) + mt.CurrentMenu = MenuShowSubPopup(mt.OwnerWnd, &MenuInfo, TRUE, wFlags); } + else /* otherwise try to move selection */ + MenuMoveSelection(mt.OwnerWnd, &MenuInfo, + (msg.wParam == VK_UP)? ITEM_PREV : ITEM_NEXT ); } - break; + break; case VK_LEFT: - MenuKeyLeft(&Mt, Flags); - break; + MenuKeyLeft( &mt, wFlags ); + break; case VK_RIGHT: - MenuKeyRight(&Mt, Flags); - break; + MenuKeyRight( &mt, wFlags ); + break; case VK_ESCAPE: - fEndMenu = MenuKeyEscape(&Mt, Flags); - break; + fEndMenu = MenuKeyEscape(&mt, wFlags); + break; case VK_F1: - { + { HELPINFO hi; hi.cbSize = sizeof(HELPINFO); hi.iContextType = HELPINFO_MENUITEM; - if (MenuGetRosMenuInfo(&MenuInfo, Mt.CurrentMenu)) - { - if (NO_SELECTED_ITEM == MenuInfo.FocusedItem) - { + if (MenuGetRosMenuInfo(&MenuInfo, mt.CurrentMenu)) + { + if (MenuInfo.FocusedItem == NO_SELECTED_ITEM) hi.iCtrlId = 0; - } else - { + { MenuInitRosMenuItemInfo(&ItemInfo); if (MenuGetRosMenuItemInfo(MenuInfo.Self, MenuInfo.FocusedItem, &ItemInfo)) - { + { hi.iCtrlId = ItemInfo.wID; - } + } else - { + { hi.iCtrlId = 0; - } + } MenuCleanupRosMenuItemInfo(&ItemInfo); - } - } - hi.hItemHandle = Menu; - hi.dwContextId = MenuInfo.dwContextHelpID; - hi.MousePos = Msg.pt; - SendMessageW(Wnd, WM_HELP, 0, (LPARAM) &hi); + } + } + hi.hItemHandle = hmenu; + hi.dwContextId = MenuInfo.dwContextHelpID; + hi.MousePos = msg.pt; + SendMessageW(hwnd, WM_HELP, 0, (LPARAM)&hi); break; - } + } default: - break; - } + break; + } break; /* WM_KEYDOWN */ - case WM_CHAR: - case WM_SYSCHAR: + case WM_CHAR: + case WM_SYSCHAR: { - UINT Pos; + UINT pos; - if (! MenuGetRosMenuInfo(&MenuInfo, Mt.CurrentMenu)) + if (! MenuGetRosMenuInfo(&MenuInfo, mt.CurrentMenu)) break; + if (msg.wParam == L'\r' || msg.wParam == L' ') { - break; - } - if (L'\r' == Msg.wParam || L' ' == Msg.wParam) - { - ExecutedMenuId = MenuExecFocusedItem(&Mt, &MenuInfo, Flags); - fEndMenu = (ExecutedMenuId != -2); - break; + executedMenuId = MenuExecFocusedItem(&mt, &MenuInfo, wFlags); + fEndMenu = (executedMenuId != -2); + break; } - /* Hack to avoid control chars. */ - /* We will find a better way real soon... */ - if (Msg.wParam < 32) - { - break; - } + /* Hack to avoid control chars. */ + /* We will find a better way real soon... */ + if (msg.wParam < 32) break; - Pos = MenuFindItemByKey(Mt.OwnerWnd, &MenuInfo, - LOWORD(Msg.wParam), FALSE); - if ((UINT) -2 == Pos) + pos = MenuFindItemByKey(mt.OwnerWnd, &MenuInfo, + LOWORD(msg.wParam), FALSE); + if (pos == (UINT)-2) fEndMenu = TRUE; + else if (pos == (UINT)-1) MessageBeep(0); + else { - fEndMenu = TRUE; + MenuSelectItem(mt.OwnerWnd, &MenuInfo, pos, + TRUE, 0); + executedMenuId = MenuExecFocusedItem(&mt, &MenuInfo, wFlags); + fEndMenu = (executedMenuId != -2); } - else if ((UINT) -1 == Pos) - { - MessageBeep(0); - } - else - { - MenuSelectItem(Mt.OwnerWnd, &MenuInfo, Pos, TRUE, 0); - ExecutedMenuId = MenuExecFocusedItem(&Mt, &MenuInfo, Flags); - fEndMenu = (-2 != ExecutedMenuId); - } - } - break; + } + break; } /* switch(msg.message) - kbd */ } - else + else { - PeekMessageW( &Msg, 0, Msg.message, Msg.message, PM_REMOVE ); - DispatchMessageW(&Msg); - continue; + PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE ); + DispatchMessageW( &msg ); + continue; } - if (! fEndMenu) - { - fRemove = TRUE; - } + if (!fEndMenu) fRemove = TRUE; - /* finally remove message from the queue */ + /* finally remove message from the queue */ - if (fRemove && 0 == (Mt.TrackFlags & TF_SKIPREMOVE)) - { - PeekMessageW(&Msg, 0, Msg.message, Msg.message, PM_REMOVE); - } - else - { - Mt.TrackFlags &= ~TF_SKIPREMOVE; - } + if (fRemove && !(mt.TrackFlags & TF_SKIPREMOVE) ) + PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE ); + else mt.TrackFlags &= ~TF_SKIPREMOVE; } - ERR("MenuTrackMenu 2\n"); - (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER, NULL); - SetCapture(NULL); /* release the capture */ + (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER, NULL); + SetCapture(NULL); /* release the capture */ - /* If dropdown is still painted and the close box is clicked on - then the menu will be destroyed as part of the DispatchMessage above. - This will then invalidate the menu handle in Mt.hTopMenu. We should - check for this first. */ - if (IsMenu(Mt.TopMenu)) + /* If dropdown is still painted and the close box is clicked on + then the menu will be destroyed as part of the DispatchMessage above. + This will then invalidate the menu handle in mt.hTopMenu. We should + check for this first. */ + if( IsMenu( mt.TopMenu ) ) { - if (IsWindow(Mt.OwnerWnd)) + if (IsWindow(mt.OwnerWnd)) { - if (MenuGetRosMenuInfo(&MenuInfo, Mt.TopMenu)) + if (MenuGetRosMenuInfo(&MenuInfo, mt.TopMenu)) { - MenuHideSubPopups(Mt.OwnerWnd, &MenuInfo, FALSE); + MenuHideSubPopups(mt.OwnerWnd, &MenuInfo, FALSE); - if (0 != (MenuInfo.Flags & MF_POPUP)) + if (MenuInfo.Flags & MF_POPUP) { - DestroyWindow(MenuInfo.Wnd); - MenuInfo.Wnd = NULL; + DestroyWindow(MenuInfo.Wnd); + MenuInfo.Wnd = NULL; - if (!(MenuInfo.Flags & TPM_NONOTIFY)) - SendMessageW( Mt.OwnerWnd, WM_UNINITMENUPOPUP, (WPARAM)Mt.TopMenu, + if (!(MenuInfo.Flags & TPM_NONOTIFY)) + SendMessageW( mt.OwnerWnd, WM_UNINITMENUPOPUP, (WPARAM)mt.TopMenu, MAKELPARAM(0, IS_SYSTEM_MENU(&MenuInfo)) ); } - MenuSelectItem(Mt.OwnerWnd, &MenuInfo, NO_SELECTED_ITEM, FALSE, NULL); + MenuSelectItem( mt.OwnerWnd, &MenuInfo, NO_SELECTED_ITEM, FALSE, 0 ); } - SendMessageW(Mt.OwnerWnd, WM_MENUSELECT, MAKELONG(0, 0xffff), 0); + SendMessageW( mt.OwnerWnd, WM_MENUSELECT, MAKEWPARAM(0, 0xffff), 0 ); } - if (MenuGetRosMenuInfo(&MenuInfo, Mt.TopMenu)) + /* Reset the variable for hiding menu */ + if (MenuGetRosMenuInfo(&MenuInfo, mt.TopMenu)) { - /* Reset the variable for hiding menu */ - MenuInfo.TimeToHide = FALSE; - MenuSetRosMenuInfo(&MenuInfo); + MenuInfo.TimeToHide = FALSE; + MenuSetRosMenuInfo(&MenuInfo); } } - /* The return value is only used by TrackPopupMenu */ - if (!(Flags & TPM_RETURNCMD)) return TRUE; - if (ExecutedMenuId < 0) ExecutedMenuId = 0; - return ExecutedMenuId; + /* The return value is only used by TrackPopupMenu */ + if (!(wFlags & TPM_RETURNCMD)) return TRUE; + if (executedMenuId == -1) executedMenuId = 0; + return executedMenuId; } +/*********************************************************************** + * MenuInitTracking + */ +static BOOL FASTCALL MenuInitTracking(HWND hWnd, HMENU hMenu, BOOL bPopup, UINT wFlags) +{ + ROSMENUINFO MenuInfo; + + TRACE("hwnd=%p hmenu=%p\n", hWnd, hMenu); + + HideCaret(0); + + /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */ + if (!(wFlags & TPM_NONOTIFY)) + SendMessageW( hWnd, WM_ENTERMENULOOP, bPopup, 0 ); + + SendMessageW( hWnd, WM_SETCURSOR, (WPARAM)hWnd, HTCAPTION ); + + if (!(wFlags & TPM_NONOTIFY)) + { + SendMessageW( hWnd, WM_INITMENU, (WPARAM)hMenu, 0 ); + + MenuGetRosMenuInfo(&MenuInfo, hMenu); + + if (!MenuInfo.Height) + { + /* app changed/recreated menu bar entries in WM_INITMENU + Recalculate menu sizes else clicks will not work */ + SetWindowPos(hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | + SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED ); + + } + /* This makes the menus of applications built with Delphi work. + * It also enables menus to be displayed in more than one window, + * but there are some bugs left that need to be fixed in this case. + */ + if(MenuInfo.Self == hMenu) + { + MenuInfo.Wnd = hWnd; + MenuSetRosMenuInfo(&MenuInfo); + } + } + + return TRUE; +} /*********************************************************************** * MenuExitTracking */ -static BOOL FASTCALL -MenuExitTracking(HWND Wnd) +static BOOL FASTCALL MenuExitTracking(HWND hWnd) { - TRACE("hwnd=%p\n", Wnd); + TRACE("hwnd=%p\n", hWnd); - SendMessageW(Wnd, WM_EXITMENULOOP, 0, 0); - ShowCaret(0); - return TRUE; + SendMessageW( hWnd, WM_EXITMENULOOP, 0, 0 ); + ShowCaret(0); + top_popup = 0; + return TRUE; } - -VOID -MenuTrackMouseMenuBar(HWND Wnd, ULONG Ht, POINT Pt) +/*********************************************************************** + * MenuTrackMouseMenuBar + * + * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand(). + */ +VOID MenuTrackMouseMenuBar( HWND hWnd, ULONG ht, POINT pt) { - HMENU Menu = (HTSYSMENU == Ht) ? NtUserGetSystemMenu(Wnd, FALSE) : GetMenu(Wnd); - UINT Flags = TPM_ENTERIDLEEX | TPM_BUTTONDOWN | TPM_LEFTALIGN | TPM_LEFTBUTTON; + HMENU hMenu = (ht == HTSYSMENU) ? NtUserGetSystemMenu( hWnd, FALSE) : GetMenu(hWnd); + UINT wFlags = TPM_ENTERIDLEEX | TPM_BUTTONDOWN | TPM_LEFTALIGN | TPM_LEFTBUTTON; - TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", Wnd, Ht, Pt.x, Pt.y); + TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", hWnd, ht, pt.x, pt.y); - if (IsMenu(Menu)) + if (IsMenu(hMenu)) { - /* map point to parent client coordinates */ - HWND Parent = GetAncestor(Wnd, GA_PARENT ); - if (Parent != GetDesktopWindow()) + /* map point to parent client coordinates */ + HWND Parent = GetAncestor(hWnd, GA_PARENT ); + if (Parent != GetDesktopWindow()) { - ScreenToClient(Parent, &Pt); + ScreenToClient(Parent, &pt); } - MenuInitTracking(Wnd, Menu, FALSE, Flags); - MenuTrackMenu(Menu, Flags, Pt.x, Pt.y, Wnd, NULL); - MenuExitTracking(Wnd); + MenuInitTracking(hWnd, hMenu, FALSE, wFlags); + MenuTrackMenu(hMenu, wFlags, pt.x, pt.y, hWnd, NULL); + MenuExitTracking(hWnd); } } -VOID -MenuTrackKbdMenuBar(HWND hWnd, UINT wParam, WCHAR wChar) +/*********************************************************************** + * MenuTrackKbdMenuBar + * + * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand(). + */ +VOID MenuTrackKbdMenuBar(HWND hwnd, UINT wParam, WCHAR wChar) { UINT uItem = NO_SELECTED_ITEM; HMENU hTrackMenu; ROSMENUINFO MenuInfo; UINT wFlags = TPM_ENTERIDLEEX | TPM_LEFTALIGN | TPM_LEFTBUTTON; - TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", hWnd, wParam, wChar); + TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", hwnd, wParam, wChar); /* find window that has a menu */ - while (!((GetWindowLongPtrW( hWnd, GWL_STYLE ) & + while (!((GetWindowLongPtrW( hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) != WS_CHILD)) - if (!(hWnd = GetAncestor( hWnd, GA_PARENT ))) return; + if (!(hwnd = GetAncestor( hwnd, GA_PARENT ))) return; /* check if we have to track a system menu */ - hTrackMenu = GetMenu( hWnd ); - if (!hTrackMenu || IsIconic(hWnd) || wChar == ' ' ) + hTrackMenu = GetMenu( hwnd ); + if (!hTrackMenu || IsIconic(hwnd) || wChar == ' ' ) { - if (!(GetWindowLongPtrW( hWnd, GWL_STYLE ) & WS_SYSMENU)) return; - hTrackMenu = NtUserGetSystemMenu(hWnd, FALSE); + if (!(GetWindowLongPtrW( hwnd, GWL_STYLE ) & WS_SYSMENU)) return; + hTrackMenu = NtUserGetSystemMenu(hwnd, FALSE); uItem = 0; wParam |= HTSYSMENU; /* prevent item lookup */ } if (!IsMenu( hTrackMenu )) return; - MenuInitTracking( hWnd, hTrackMenu, FALSE, wFlags ); + MenuInitTracking( hwnd, hTrackMenu, FALSE, wFlags ); if (! MenuGetRosMenuInfo(&MenuInfo, hTrackMenu)) { @@ -3807,7 +3574,7 @@ MenuTrackKbdMenuBar(HWND hWnd, UINT wParam, WCHAR wChar) if( wChar && wChar != ' ' ) { - uItem = MenuFindItemByKey( hWnd, &MenuInfo, wChar, (wParam & HTSYSMENU) ); + uItem = MenuFindItemByKey( hwnd, &MenuInfo, wChar, (wParam & HTSYSMENU) ); if ( uItem >= (UINT)(-2) ) { if( uItem == (UINT)(-1) ) MessageBeep(0); @@ -3817,7 +3584,7 @@ MenuTrackKbdMenuBar(HWND hWnd, UINT wParam, WCHAR wChar) } } - MenuSelectItem( hWnd, &MenuInfo, uItem, TRUE, 0 ); + MenuSelectItem( hwnd, &MenuInfo, uItem, TRUE, 0 ); if (wParam & HTSYSMENU) { @@ -3828,17 +3595,54 @@ MenuTrackKbdMenuBar(HWND hWnd, UINT wParam, WCHAR wChar) else { if( uItem == NO_SELECTED_ITEM ) - MenuMoveSelection( hWnd, &MenuInfo, ITEM_NEXT ); + MenuMoveSelection( hwnd, &MenuInfo, ITEM_NEXT ); else - PostMessageW( hWnd, WM_KEYDOWN, VK_DOWN, 0L ); + PostMessageW( hwnd, WM_KEYDOWN, VK_DOWN, 0L ); } track_menu: - MenuTrackMenu( hTrackMenu, wFlags, 0, 0, hWnd, NULL ); - MenuExitTracking( hWnd ); + MenuTrackMenu( hTrackMenu, wFlags, 0, 0, hwnd, NULL ); + MenuExitTracking( hwnd ); } +/********************************************************************** + * TrackPopupMenuEx (USER32.@) + */ +BOOL WINAPI TrackPopupMenuEx( HMENU Menu, UINT Flags, int x, int y, + HWND Wnd, LPTPMPARAMS Tpm) +{ + /* Not fully implemented */ + return TrackPopupMenu(Menu, Flags, x, y, 0, Wnd, + NULL != Tpm ? &Tpm->rcExclude : NULL); +} + +/********************************************************************** + * TrackPopupMenu (USER32.@) + */ +BOOL WINAPI TrackPopupMenu( HMENU Menu, UINT Flags, int x, int y, + int Reserved, HWND Wnd, CONST RECT *Rect) +{ + BOOL ret = FALSE; + + if (!IsMenu(Menu)) + { + SetLastError( ERROR_INVALID_MENU_HANDLE ); + return FALSE; + } + + MenuInitTracking(Wnd, Menu, TRUE, Flags); + + /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */ + if (!(Flags & TPM_NONOTIFY)) + SendMessageW(Wnd, WM_INITMENUPOPUP, (WPARAM) Menu, 0); + + if (MenuShowPopup(Wnd, Menu, 0, Flags, x, y, 0, 0 )) + ret = MenuTrackMenu(Menu, Flags | TPM_POPUPMENU, 0, 0, Wnd, Rect); + MenuExitTracking(Wnd); + return ret; +} + /* * From MSDN: * The MFT_BITMAP, MFT_SEPARATOR, and MFT_STRING values cannot be combined @@ -5193,64 +4997,6 @@ SetSystemMenu ( return NtUserSetSystemMenu(hwnd, hMenu); } - -/* - * @implemented - */ -BOOL -WINAPI -TrackPopupMenu( - HMENU Menu, - UINT Flags, - int x, - int y, - int Reserved, - HWND Wnd, - CONST RECT *Rect) -{ - BOOL ret = FALSE; - - if (!IsMenu(Menu)) - { - SetLastError( ERROR_INVALID_MENU_HANDLE ); - return FALSE; - } - - MenuInitTracking(Wnd, Menu, TRUE, Flags); - - /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */ - if (0 == (Flags & TPM_NONOTIFY)) - { - SendMessageW(Wnd, WM_INITMENUPOPUP, (WPARAM) Menu, 0); - } - - if (MenuShowPopup(Wnd, Menu, 0, Flags, x, y, 0, 0 )) - { - ret = MenuTrackMenu(Menu, Flags | TPM_POPUPMENU, 0, 0, Wnd, Rect); - } - MenuExitTracking(Wnd); - return ret; -} - - -/* - * @unimplemented - */ -BOOL -WINAPI -TrackPopupMenuEx( - HMENU Menu, - UINT Flags, - int x, - int y, - HWND Wnd, - LPTPMPARAMS Tpm) -{ - /* Not fully implemented */ - return TrackPopupMenu(Menu, Flags, x, y, 0, Wnd, - NULL != Tpm ? &Tpm->rcExclude : NULL); -} - // // Example for the Win32/User32 rewrite. // Def = TrackPopupMenuEx@24=NtUserTrackPopupMenuEx@24 diff --git a/dll/win32/win32.rbuild b/dll/win32/win32.rbuild index c68742612de..9ff3319d54f 100644 --- a/dll/win32/win32.rbuild +++ b/dll/win32/win32.rbuild @@ -103,6 +103,9 @@ + + + diff --git a/dll/win32/wininet/cookie.c b/dll/win32/wininet/cookie.c index 12d841bc7b9..75cf049308b 100644 --- a/dll/win32/wininet/cookie.c +++ b/dll/win32/wininet/cookie.c @@ -23,6 +23,10 @@ #include "config.h" #include "wine/port.h" +#if defined(__MINGW32__) || defined (_MSC_VER) +#include +#endif + #include #include #include @@ -48,7 +52,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(wininet); * Cookies are currently memory only. * Cookies are NOT THREAD SAFE * Cookies could use A LOT OF MEMORY. We need some kind of memory management here! - * Cookies should care about the expiry time */ typedef struct _cookie_domain cookie_domain; @@ -62,7 +65,7 @@ struct _cookie LPWSTR lpCookieName; LPWSTR lpCookieData; - time_t expiry; /* FIXME: not used */ + FILETIME expiry; }; struct _cookie_domain @@ -76,7 +79,7 @@ struct _cookie_domain static struct list domain_list = LIST_INIT(domain_list); -static cookie *COOKIE_addCookie(cookie_domain *domain, LPCWSTR name, LPCWSTR data); +static cookie *COOKIE_addCookie(cookie_domain *domain, LPCWSTR name, LPCWSTR data, FILETIME expiry); static cookie *COOKIE_findCookie(cookie_domain *domain, LPCWSTR lpszCookieName); static void COOKIE_deleteCookie(cookie *deadCookie, BOOL deleteDomain); static cookie_domain *COOKIE_addDomain(LPCWSTR domain, LPCWSTR path); @@ -84,24 +87,16 @@ static void COOKIE_deleteDomain(cookie_domain *deadDomain); /* adds a cookie to the domain */ -static cookie *COOKIE_addCookie(cookie_domain *domain, LPCWSTR name, LPCWSTR data) +static cookie *COOKIE_addCookie(cookie_domain *domain, LPCWSTR name, LPCWSTR data, FILETIME expiry) { cookie *newCookie = HeapAlloc(GetProcessHeap(), 0, sizeof(cookie)); list_init(&newCookie->entry); newCookie->lpCookieName = NULL; newCookie->lpCookieData = NULL; - - if (name) - { - newCookie->lpCookieName = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1)*sizeof(WCHAR)); - lstrcpyW(newCookie->lpCookieName, name); - } - if (data) - { - newCookie->lpCookieData = HeapAlloc(GetProcessHeap(), 0, (strlenW(data) + 1)*sizeof(WCHAR)); - lstrcpyW(newCookie->lpCookieData, data); - } + newCookie->expiry = expiry; + newCookie->lpCookieName = heap_strdupW(name); + newCookie->lpCookieData = heap_strdupW(data); TRACE("added cookie %p (data is %s)\n", newCookie, debugstr_w(data) ); @@ -156,17 +151,8 @@ static cookie_domain *COOKIE_addDomain(LPCWSTR domain, LPCWSTR path) list_init(&newDomain->cookie_list); newDomain->lpCookieDomain = NULL; newDomain->lpCookiePath = NULL; - - if (domain) - { - newDomain->lpCookieDomain = HeapAlloc(GetProcessHeap(), 0, (strlenW(domain) + 1)*sizeof(WCHAR)); - strcpyW(newDomain->lpCookieDomain, domain); - } - if (path) - { - newDomain->lpCookiePath = HeapAlloc(GetProcessHeap(), 0, (strlenW(path) + 1)*sizeof(WCHAR)); - lstrcpyW(newDomain->lpCookiePath, path); - } + newDomain->lpCookieDomain = heap_strdupW(domain); + newDomain->lpCookiePath = heap_strdupW(path); list_add_tail(&domain_list, &newDomain->entry); @@ -191,7 +177,28 @@ static BOOL COOKIE_crackUrlSimple(LPCWSTR lpszUrl, LPWSTR hostName, int hostName UrlComponents.dwHostNameLength = hostNameLen; UrlComponents.dwUrlPathLength = pathLen; - return InternetCrackUrlW(lpszUrl, 0, 0, &UrlComponents); + if (!InternetCrackUrlW(lpszUrl, 0, 0, &UrlComponents)) return FALSE; + + /* discard the webpage off the end of the path */ + if (UrlComponents.dwUrlPathLength) + { + if (path[UrlComponents.dwUrlPathLength - 1] != '/') + { + WCHAR *ptr; + if ((ptr = strrchrW(path, '/'))) *(++ptr) = 0; + else + { + path[0] = '/'; + path[1] = 0; + } + } + } + else if (pathLen >= 2) + { + path[0] = '/'; + path[1] = 0; + } + return TRUE; } /* match a domain. domain must match if the domain is not NULL. path must match if the path is not NULL */ @@ -215,11 +222,22 @@ static BOOL COOKIE_matchDomain(LPCWSTR lpszCookieDomain, LPCWSTR lpszCookiePath, } if (lpszCookiePath) { + INT len; TRACE("comparing paths: %s with %s\n", debugstr_w(lpszCookiePath), debugstr_w(searchDomain->lpCookiePath)); + /* paths match at the beginning. so a path of /foo would match + * /foobar and /foo/bar + */ if (!searchDomain->lpCookiePath) return FALSE; - if (strcmpW(lpszCookiePath, searchDomain->lpCookiePath)) + if (allow_partial) + { + len = lstrlenW(searchDomain->lpCookiePath); + if (strncmpiW(searchDomain->lpCookiePath, lpszCookiePath, len)!=0) + return FALSE; + } + else if (strcmpW(lpszCookiePath, searchDomain->lpCookiePath)) return FALSE; + } return TRUE; } @@ -262,6 +280,7 @@ BOOL WINAPI InternetGetCookieW(LPCWSTR lpszUrl, LPCWSTR lpszCookieName, struct list * cursor; unsigned int cnt = 0, domain_count = 0, cookie_count = 0; WCHAR hostName[2048], path[2048]; + FILETIME tm; TRACE("(%s, %s, %p, %p)\n", debugstr_w(lpszUrl),debugstr_w(lpszCookieName), lpCookieData, lpdwSize); @@ -276,10 +295,12 @@ BOOL WINAPI InternetGetCookieW(LPCWSTR lpszUrl, LPCWSTR lpszCookieName, ret = COOKIE_crackUrlSimple(lpszUrl, hostName, sizeof(hostName)/sizeof(hostName[0]), path, sizeof(path)/sizeof(path[0])); if (!ret || !hostName[0]) return FALSE; + GetSystemTimeAsFileTime(&tm); + LIST_FOR_EACH(cursor, &domain_list) { cookie_domain *cookiesDomain = LIST_ENTRY(cursor, cookie_domain, entry); - if (COOKIE_matchDomain(hostName, NULL /* FIXME: path */, cookiesDomain, TRUE)) + if (COOKIE_matchDomain(hostName, path, cookiesDomain, TRUE)) { struct list * cursor; domain_count++; @@ -288,6 +309,14 @@ BOOL WINAPI InternetGetCookieW(LPCWSTR lpszUrl, LPCWSTR lpszCookieName, LIST_FOR_EACH(cursor, &cookiesDomain->cookie_list) { cookie *thisCookie = LIST_ENTRY(cursor, cookie, entry); + /* check for expiry */ + if ((thisCookie->expiry.dwLowDateTime != 0 || thisCookie->expiry.dwHighDateTime != 0) && CompareFileTime(&tm,&thisCookie->expiry) > 0) + { + TRACE("Found expired cookie. deleting\n"); + COOKIE_deleteCookie(thisCookie, FALSE); + continue; + } + if (lpCookieData == NULL) /* return the size of the buffer required to lpdwSize */ { unsigned int len; @@ -356,27 +385,16 @@ BOOL WINAPI InternetGetCookieA(LPCSTR lpszUrl, LPCSTR lpszCookieName, LPSTR lpCookieData, LPDWORD lpdwSize) { DWORD len; - LPWSTR szCookieData = NULL, szUrl = NULL, szCookieName = NULL; + LPWSTR szCookieData = NULL, url, name; BOOL r; TRACE("(%s,%s,%p)\n", debugstr_a(lpszUrl), debugstr_a(lpszCookieName), lpCookieData); - if( lpszUrl ) - { - len = MultiByteToWideChar( CP_ACP, 0, lpszUrl, -1, NULL, 0 ); - szUrl = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, lpszUrl, -1, szUrl, len ); - } + url = heap_strdupAtoW(lpszUrl); + name = heap_strdupAtoW(lpszCookieName); - if( lpszCookieName ) - { - len = MultiByteToWideChar( CP_ACP, 0, lpszCookieName, -1, NULL, 0 ); - szCookieName = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, lpszCookieName, -1, szCookieName, len ); - } - - r = InternetGetCookieW( szUrl, szCookieName, NULL, &len ); + r = InternetGetCookieW( url, name, NULL, &len ); if( r ) { szCookieData = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); @@ -386,7 +404,7 @@ BOOL WINAPI InternetGetCookieA(LPCSTR lpszUrl, LPCSTR lpszCookieName, } else { - r = InternetGetCookieW( szUrl, szCookieName, szCookieData, &len ); + r = InternetGetCookieW( url, name, szCookieData, &len ); *lpdwSize = WideCharToMultiByte( CP_ACP, 0, szCookieData, len, lpCookieData, *lpdwSize, NULL, NULL ); @@ -394,8 +412,8 @@ BOOL WINAPI InternetGetCookieA(LPCSTR lpszUrl, LPCSTR lpszCookieName, } HeapFree( GetProcessHeap(), 0, szCookieData ); - HeapFree( GetProcessHeap(), 0, szCookieName ); - HeapFree( GetProcessHeap(), 0, szUrl ); + HeapFree( GetProcessHeap(), 0, name ); + HeapFree( GetProcessHeap(), 0, url ); return r; } @@ -405,27 +423,129 @@ static BOOL set_cookie(LPCWSTR domain, LPCWSTR path, LPCWSTR cookie_name, LPCWST cookie_domain *thisCookieDomain = NULL; cookie *thisCookie; struct list *cursor; + LPWSTR data, value; + WCHAR *ptr; + FILETIME expiry; + BOOL expired = FALSE; + + value = data = heap_strdupW(cookie_data); + if (!data) + { + ERR("could not allocate %zu bytes for the cookie data buffer\n", (strlenW(cookie_data) + 1) * sizeof(WCHAR)); + return FALSE; + } + + memset(&expiry,0,sizeof(expiry)); + + /* lots of information can be parsed out of the cookie value */ + + ptr = data; + for (;;) + { + static const WCHAR szDomain[] = {'d','o','m','a','i','n','=',0}; + static const WCHAR szPath[] = {'p','a','t','h','=',0}; + static const WCHAR szExpires[] = {'e','x','p','i','r','e','s','=',0}; + static const WCHAR szSecure[] = {'s','e','c','u','r','e',0}; + static const WCHAR szHttpOnly[] = {'h','t','t','p','o','n','l','y',0}; + + if (!(ptr = strchrW(ptr,';'))) break; + *ptr++ = 0; + + if (value != data) + HeapFree(GetProcessHeap(), 0, value); + value = HeapAlloc(GetProcessHeap(), 0, (ptr - data) * sizeof(WCHAR)); + if (value == NULL) + { + HeapFree(GetProcessHeap(), 0, data); + ERR("could not allocate %zu bytes for the cookie value buffer\n", (ptr - data) * sizeof(WCHAR)); + return FALSE; + } + strcpyW(value, data); + + while (*ptr == ' ') ptr++; /* whitespace */ + + if (strncmpiW(ptr, szDomain, 7) == 0) + { + ptr+=strlenW(szDomain); + domain = ptr; + TRACE("Parsing new domain %s\n",debugstr_w(domain)); + } + else if (strncmpiW(ptr, szPath, 5) == 0) + { + ptr+=strlenW(szPath); + path = ptr; + TRACE("Parsing new path %s\n",debugstr_w(path)); + } + else if (strncmpiW(ptr, szExpires, 8) == 0) + { + FILETIME ft; + SYSTEMTIME st; + FIXME("persistent cookies not handled (%s)\n",debugstr_w(ptr)); + ptr+=strlenW(szExpires); + if (InternetTimeToSystemTimeW(ptr, &st, 0)) + { + SystemTimeToFileTime(&st, &expiry); + GetSystemTimeAsFileTime(&ft); + + if (CompareFileTime(&ft,&expiry) > 0) + { + TRACE("Cookie already expired.\n"); + expired = TRUE; + } + } + } + else if (strncmpiW(ptr, szSecure, 6) == 0) + { + FIXME("secure not handled (%s)\n",debugstr_w(ptr)); + ptr += strlenW(szSecure); + } + else if (strncmpiW(ptr, szHttpOnly, 8) == 0) + { + FIXME("httponly not handled (%s)\n",debugstr_w(ptr)); + ptr += strlenW(szHttpOnly); + } + else if (*ptr) + { + FIXME("Unknown additional option %s\n",debugstr_w(ptr)); + break; + } + } LIST_FOR_EACH(cursor, &domain_list) { thisCookieDomain = LIST_ENTRY(cursor, cookie_domain, entry); - if (COOKIE_matchDomain(domain, NULL /* FIXME: path */, thisCookieDomain, FALSE)) + if (COOKIE_matchDomain(domain, path, thisCookieDomain, FALSE)) break; thisCookieDomain = NULL; } if (!thisCookieDomain) - thisCookieDomain = COOKIE_addDomain(domain, path); + { + if (!expired) + thisCookieDomain = COOKIE_addDomain(domain, path); + else + { + HeapFree(GetProcessHeap(),0,data); + if (value != data) HeapFree(GetProcessHeap(), 0, value); + return TRUE; + } + } if ((thisCookie = COOKIE_findCookie(thisCookieDomain, cookie_name))) COOKIE_deleteCookie(thisCookie, FALSE); - TRACE("setting cookie %s=%s for domain %s\n", debugstr_w(cookie_name), - debugstr_w(cookie_data), debugstr_w(thisCookieDomain->lpCookieDomain)); + TRACE("setting cookie %s=%s for domain %s path %s\n", debugstr_w(cookie_name), + debugstr_w(value), debugstr_w(thisCookieDomain->lpCookieDomain),debugstr_w(thisCookieDomain->lpCookiePath)); - if (!COOKIE_addCookie(thisCookieDomain, cookie_name, cookie_data)) + if (!expired && !COOKIE_addCookie(thisCookieDomain, cookie_name, value, expiry)) + { + HeapFree(GetProcessHeap(),0,data); + if (value != data) HeapFree(GetProcessHeap(), 0, value); return FALSE; + } + HeapFree(GetProcessHeap(),0,data); + if (value != data) HeapFree(GetProcessHeap(), 0, value); return TRUE; } @@ -454,28 +574,26 @@ BOOL WINAPI InternetSetCookieW(LPCWSTR lpszUrl, LPCWSTR lpszCookieName, return FALSE; } - hostName[0] = path[0] = 0; + hostName[0] = 0; ret = COOKIE_crackUrlSimple(lpszUrl, hostName, sizeof(hostName)/sizeof(hostName[0]), path, sizeof(path)/sizeof(path[0])); if (!ret || !hostName[0]) return FALSE; if (!lpszCookieName) { - unsigned int len; WCHAR *cookie, *data; - len = strlenW(lpCookieData); - if (!(cookie = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)))) + cookie = heap_strdupW(lpCookieData); + if (!cookie) { SetLastError(ERROR_OUTOFMEMORY); return FALSE; } - strcpyW(cookie, lpCookieData); /* some apps (or is it us??) try to add a cookie with no cookie name, but * the cookie data in the form of name[=data]. */ - if (!(data = strchrW(cookie, '='))) data = cookie + len; - else data++; + if (!(data = strchrW(cookie, '='))) data = cookie + strlenW(cookie); + else *data++ = 0; ret = set_cookie(hostName, path, cookie, data); @@ -499,39 +617,21 @@ BOOL WINAPI InternetSetCookieW(LPCWSTR lpszUrl, LPCWSTR lpszCookieName, BOOL WINAPI InternetSetCookieA(LPCSTR lpszUrl, LPCSTR lpszCookieName, LPCSTR lpCookieData) { - DWORD len; - LPWSTR szCookieData = NULL, szUrl = NULL, szCookieName = NULL; + LPWSTR data, url, name; BOOL r; TRACE("(%s,%s,%s)\n", debugstr_a(lpszUrl), debugstr_a(lpszCookieName), debugstr_a(lpCookieData)); - if( lpszUrl ) - { - len = MultiByteToWideChar( CP_ACP, 0, lpszUrl, -1, NULL, 0 ); - szUrl = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, lpszUrl, -1, szUrl, len ); - } + url = heap_strdupAtoW(lpszUrl); + name = heap_strdupAtoW(lpszCookieName); + data = heap_strdupAtoW(lpCookieData); - if( lpszCookieName ) - { - len = MultiByteToWideChar( CP_ACP, 0, lpszCookieName, -1, NULL, 0 ); - szCookieName = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, lpszCookieName, -1, szCookieName, len ); - } + r = InternetSetCookieW( url, name, data ); - if( lpCookieData ) - { - len = MultiByteToWideChar( CP_ACP, 0, lpCookieData, -1, NULL, 0 ); - szCookieData = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, lpCookieData, -1, szCookieData, len ); - } - - r = InternetSetCookieW( szUrl, szCookieName, szCookieData ); - - HeapFree( GetProcessHeap(), 0, szCookieData ); - HeapFree( GetProcessHeap(), 0, szCookieName ); - HeapFree( GetProcessHeap(), 0, szUrl ); + HeapFree( GetProcessHeap(), 0, data ); + HeapFree( GetProcessHeap(), 0, name ); + HeapFree( GetProcessHeap(), 0, url ); return r; } @@ -692,3 +792,28 @@ BOOL WINAPI InternetSetPerSiteCookieDecisionW( LPCWSTR pchHostName, DWORD dwDeci FIXME("(%s, 0x%08x) stub\n", debugstr_w(pchHostName), dwDecision); return FALSE; } + +/*********************************************************************** + * IsDomainLegalCookieDomainW (WININET.@) + */ +BOOL WINAPI IsDomainLegalCookieDomainW( LPCWSTR s1, LPCWSTR s2 ) +{ + const WCHAR *p; + + FIXME("(%s, %s)\n", debugstr_w(s1), debugstr_w(s2)); + + if (!s1 || !s2) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + if (s1[0] == '.' || !s1[0] || s2[0] == '.' || !s2[0]) + { + SetLastError(ERROR_INVALID_NAME); + return FALSE; + } + if (!(p = strchrW(s2, '.'))) return FALSE; + if (strchrW(p + 1, '.') && !strcmpW(p + 1, s1)) return TRUE; + else if (!strcmpW(s1, s2)) return TRUE; + return FALSE; +} diff --git a/dll/win32/wininet/dialogs.c b/dll/win32/wininet/dialogs.c index dd5aa315a63..2c4a5278569 100644 --- a/dll/win32/wininet/dialogs.c +++ b/dll/win32/wininet/dialogs.c @@ -21,6 +21,10 @@ #include "config.h" #include "wine/port.h" +#if defined(__MINGW32__) || defined (_MSC_VER) +#include +#endif + #include #include "windef.h" @@ -58,22 +62,23 @@ struct WININET_ErrorDlgParams */ static BOOL WININET_GetProxyServer( HINTERNET hRequest, LPWSTR szBuf, DWORD sz ) { - LPWININETHTTPREQW lpwhr; - LPWININETHTTPSESSIONW lpwhs = NULL; - LPWININETAPPINFOW hIC = NULL; + http_request_t *lpwhr; + http_session_t *lpwhs = NULL; + appinfo_t *hIC = NULL; + BOOL ret = FALSE; LPWSTR p; - lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hRequest ); + lpwhr = (http_request_t*) WININET_GetObject( hRequest ); if (NULL == lpwhr) - return FALSE; + return FALSE; lpwhs = lpwhr->lpHttpSession; if (NULL == lpwhs) - return FALSE; + goto done; hIC = lpwhs->lpAppInfo; if (NULL == hIC) - return FALSE; + goto done; lstrcpynW(szBuf, hIC->lpszProxy, sz); @@ -82,7 +87,39 @@ static BOOL WININET_GetProxyServer( HINTERNET hRequest, LPWSTR szBuf, DWORD sz ) if (p) *p = 0; - return TRUE; + ret = TRUE; + +done: + WININET_Release( &lpwhr->hdr ); + return ret; +} + +/*********************************************************************** + * WININET_GetServer + * + * Determine the name of the web server + */ +static BOOL WININET_GetServer( HINTERNET hRequest, LPWSTR szBuf, DWORD sz ) +{ + http_request_t *lpwhr; + http_session_t *lpwhs = NULL; + BOOL ret = FALSE; + + lpwhr = (http_request_t*) WININET_GetObject( hRequest ); + if (NULL == lpwhr) + return FALSE; + + lpwhs = lpwhr->lpHttpSession; + if (NULL == lpwhs) + goto done; + + lstrcpynW(szBuf, lpwhs->lpszHostName, sz); + + ret = TRUE; + +done: + WININET_Release( &lpwhr->hdr ); + return ret; } /*********************************************************************** @@ -90,16 +127,20 @@ static BOOL WININET_GetProxyServer( HINTERNET hRequest, LPWSTR szBuf, DWORD sz ) * * Determine the name of the (basic) Authentication realm */ -static BOOL WININET_GetAuthRealm( HINTERNET hRequest, LPWSTR szBuf, DWORD sz ) +static BOOL WININET_GetAuthRealm( HINTERNET hRequest, LPWSTR szBuf, DWORD sz, BOOL proxy ) { LPWSTR p, q; - DWORD index; + DWORD index, query; static const WCHAR szRealm[] = { 'r','e','a','l','m','=',0 }; - /* extract the Realm from the proxy response and show it */ + if (proxy) + query = HTTP_QUERY_PROXY_AUTHENTICATE; + else + query = HTTP_QUERY_WWW_AUTHENTICATE; + + /* extract the Realm from the response and show it */ index = 0; - if( !HttpQueryInfoW( hRequest, HTTP_QUERY_PROXY_AUTHENTICATE, - szBuf, &sz, &index) ) + if( !HttpQueryInfoW( hRequest, query, szBuf, &sz, &index) ) return FALSE; /* @@ -109,11 +150,10 @@ static BOOL WININET_GetAuthRealm( HINTERNET hRequest, LPWSTR szBuf, DWORD sz ) p = strchrW( szBuf, ' ' ); if( !p || strncmpW( p+1, szRealm, strlenW(szRealm) ) ) { - ERR("proxy response wrong? (%s)\n", debugstr_w(szBuf)); + ERR("response wrong? (%s)\n", debugstr_w(szBuf)); return FALSE; } - /* remove quotes */ p += 7; if( *p == '"' ) @@ -194,44 +234,62 @@ static BOOL WININET_GetSetPassword( HWND hdlg, LPCWSTR szServer, } /*********************************************************************** - * WININET_SetProxyAuthorization + * WININET_SetAuthorization */ -static BOOL WININET_SetProxyAuthorization( HINTERNET hRequest, - LPWSTR username, LPWSTR password ) +static BOOL WININET_SetAuthorization( HINTERNET hRequest, LPWSTR username, + LPWSTR password, BOOL proxy ) { - LPWININETHTTPREQW lpwhr; - LPWININETHTTPSESSIONW lpwhs; - LPWININETAPPINFOW hIC; - LPWSTR p; + http_request_t *lpwhr; + http_session_t *lpwhs; + BOOL ret = FALSE; + LPWSTR p, q; - lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hRequest ); + lpwhr = (http_request_t*) WININET_GetObject( hRequest ); if( !lpwhr ) - return FALSE; - + return FALSE; + lpwhs = lpwhr->lpHttpSession; if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION) { INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); - return FALSE; + goto done; } - hIC = lpwhs->lpAppInfo; - - p = HeapAlloc( GetProcessHeap(), 0, (strlenW( username ) + 1)*sizeof(WCHAR) ); + p = heap_strdupW(username); if( !p ) - return FALSE; - - lstrcpyW( p, username ); - hIC->lpszProxyUsername = p; + goto done; - p = HeapAlloc( GetProcessHeap(), 0, (strlenW( password ) + 1)*sizeof(WCHAR) ); - if( !p ) - return FALSE; - - lstrcpyW( p, password ); - hIC->lpszProxyPassword = p; + q = heap_strdupW(password); + if( !q ) + { + HeapFree(GetProcessHeap(), 0, username); + goto done; + } - return TRUE; + if (proxy) + { + appinfo_t *hIC = lpwhs->lpAppInfo; + + HeapFree(GetProcessHeap(), 0, hIC->lpszProxyUsername); + hIC->lpszProxyUsername = p; + + HeapFree(GetProcessHeap(), 0, hIC->lpszProxyPassword); + hIC->lpszProxyPassword = q; + } + else + { + HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName); + lpwhs->lpszUserName = p; + + HeapFree(GetProcessHeap(), 0, lpwhs->lpszPassword); + lpwhs->lpszPassword = q; + } + + ret = TRUE; + +done: + WININET_Release( &lpwhr->hdr ); + return ret; } /*********************************************************************** @@ -254,7 +312,7 @@ static INT_PTR WINAPI WININET_ProxyPasswordDialog( /* extract the Realm from the proxy response and show it */ if( WININET_GetAuthRealm( params->hRequest, - szRealm, sizeof szRealm/sizeof(WCHAR)) ) + szRealm, sizeof szRealm/sizeof(WCHAR), TRUE ) ) { hitem = GetDlgItem( hdlg, IDC_REALM ); SetWindowTextW( hitem, szRealm ); @@ -297,13 +355,97 @@ static INT_PTR WINAPI WININET_ProxyPasswordDialog( if( hitem && SendMessageW( hitem, BM_GETSTATE, 0, 0 ) && WININET_GetAuthRealm( params->hRequest, - szRealm, sizeof szRealm/sizeof(WCHAR)) && + szRealm, sizeof szRealm/sizeof(WCHAR), TRUE ) && WININET_GetProxyServer( params->hRequest, szServer, sizeof szServer/sizeof(WCHAR)) ) { WININET_GetSetPassword( hdlg, szServer, szRealm, TRUE ); } - WININET_SetProxyAuthorization( params->hRequest, username, password ); + WININET_SetAuthorization( params->hRequest, username, password, TRUE ); + + EndDialog( hdlg, ERROR_INTERNET_FORCE_RETRY ); + return TRUE; + } + if( wParam == IDCANCEL ) + { + EndDialog( hdlg, 0 ); + return TRUE; + } + break; + } + return FALSE; +} + +/*********************************************************************** + * WININET_PasswordDialog + */ +static INT_PTR WINAPI WININET_PasswordDialog( + HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) +{ + HWND hitem; + struct WININET_ErrorDlgParams *params; + WCHAR szRealm[0x80], szServer[0x80]; + + if( uMsg == WM_INITDIALOG ) + { + TRACE("WM_INITDIALOG (%08lx)\n", lParam); + + /* save the parameter list */ + params = (struct WININET_ErrorDlgParams*) lParam; + SetWindowLongPtrW( hdlg, GWLP_USERDATA, lParam ); + + /* extract the Realm from the response and show it */ + if( WININET_GetAuthRealm( params->hRequest, + szRealm, sizeof szRealm/sizeof(WCHAR), FALSE ) ) + { + hitem = GetDlgItem( hdlg, IDC_REALM ); + SetWindowTextW( hitem, szRealm ); + } + + /* extract the name of the server */ + if( WININET_GetServer( params->hRequest, + szServer, sizeof szServer/sizeof(WCHAR)) ) + { + hitem = GetDlgItem( hdlg, IDC_SERVER ); + SetWindowTextW( hitem, szServer ); + } + + WININET_GetSetPassword( hdlg, szServer, szRealm, FALSE ); + + return TRUE; + } + + params = (struct WININET_ErrorDlgParams*) + GetWindowLongPtrW( hdlg, GWLP_USERDATA ); + + switch( uMsg ) + { + case WM_COMMAND: + if( wParam == IDOK ) + { + WCHAR username[0x20], password[0x20]; + + username[0] = 0; + hitem = GetDlgItem( hdlg, IDC_USERNAME ); + if( hitem ) + GetWindowTextW( hitem, username, sizeof username/sizeof(WCHAR) ); + + password[0] = 0; + hitem = GetDlgItem( hdlg, IDC_PASSWORD ); + if( hitem ) + GetWindowTextW( hitem, password, sizeof password/sizeof(WCHAR) ); + + hitem = GetDlgItem( hdlg, IDC_SAVEPASSWORD ); + if( hitem && + SendMessageW( hitem, BM_GETSTATE, 0, 0 ) && + WININET_GetAuthRealm( params->hRequest, + szRealm, sizeof szRealm/sizeof(WCHAR), FALSE ) && + WININET_GetServer( params->hRequest, + szServer, sizeof szServer/sizeof(WCHAR)) ) + { + WININET_GetSetPassword( hdlg, szServer, szRealm, TRUE ); + } + WININET_SetAuthorization( params->hRequest, username, password, FALSE ); EndDialog( hdlg, ERROR_INTERNET_FORCE_RETRY ); return TRUE; @@ -362,17 +504,23 @@ DWORD WINAPI InternetErrorDlg(HWND hWnd, HINTERNET hRequest, switch( dwError ) { case ERROR_SUCCESS: - if( !(dwFlags & FLAGS_ERROR_UI_FILTER_FOR_ERRORS ) ) - return 0; - dwStatus = WININET_GetConnectionStatus( hRequest ); - if( HTTP_STATUS_PROXY_AUTH_REQ != dwStatus ) - return ERROR_SUCCESS; - return DialogBoxParamW( hwininet, MAKEINTRESOURCEW( IDD_PROXYDLG ), - hWnd, WININET_ProxyPasswordDialog, (LPARAM) ¶ms ); - case ERROR_INTERNET_INCORRECT_PASSWORD: - return DialogBoxParamW( hwininet, MAKEINTRESOURCEW( IDD_PROXYDLG ), - hWnd, WININET_ProxyPasswordDialog, (LPARAM) ¶ms ); + if( !dwError && !(dwFlags & FLAGS_ERROR_UI_FILTER_FOR_ERRORS ) ) + return 0; + + dwStatus = WININET_GetConnectionStatus( hRequest ); + switch (dwStatus) + { + case HTTP_STATUS_PROXY_AUTH_REQ: + return DialogBoxParamW( hwininet, MAKEINTRESOURCEW( IDD_PROXYDLG ), + hWnd, WININET_ProxyPasswordDialog, (LPARAM) ¶ms ); + case HTTP_STATUS_DENIED: + return DialogBoxParamW( hwininet, MAKEINTRESOURCEW( IDD_AUTHDLG ), + hWnd, WININET_PasswordDialog, (LPARAM) ¶ms ); + default: + WARN("unhandled status %u\n", dwStatus); + return 0; + } case ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR: case ERROR_INTERNET_INVALID_CA: diff --git a/dll/win32/wininet/ftp.c b/dll/win32/wininet/ftp.c index 770fef2886a..1f031996811 100644 --- a/dll/win32/wininet/ftp.c +++ b/dll/win32/wininet/ftp.c @@ -30,6 +30,10 @@ #include "config.h" #include "wine/port.h" +#if defined(__MINGW32__) || defined (_MSC_VER) +#include +#endif + #include #include #include @@ -39,9 +43,15 @@ #ifdef HAVE_SYS_SOCKET_H # include #endif +#ifdef HAVE_ARPA_INET_H +# include +#endif #ifdef HAVE_UNISTD_H # include #endif +#ifdef HAVE_SYS_IOCTL_H +# include +#endif #include #include @@ -61,43 +71,47 @@ WINE_DEFAULT_DEBUG_CHANNEL(wininet); -typedef struct _WININETFTPSESSIONW WININETFTPSESSIONW; +typedef struct _ftp_session_t ftp_session_t; typedef struct { - WININETHANDLEHEADER hdr; - WININETFTPSESSIONW *lpFtpSession; + object_header_t hdr; + ftp_session_t *lpFtpSession; BOOL session_deleted; int nDataSocket; -} WININETFTPFILE, *LPWININETFTPFILE; + WCHAR *cache_file; + HANDLE cache_file_handle; +} ftp_file_t; -typedef struct _WININETFTPSESSIONW +struct _ftp_session_t { - WININETHANDLEHEADER hdr; - WININETAPPINFOW *lpAppInfo; + object_header_t hdr; + appinfo_t *lpAppInfo; int sndSocket; int lstnSocket; int pasvSocket; /* data socket connected by us in case of passive FTP */ - LPWININETFTPFILE download_in_progress; + ftp_file_t *download_in_progress; struct sockaddr_in socketAddress; struct sockaddr_in lstnSocketAddress; + LPWSTR servername; + INTERNET_PORT serverport; LPWSTR lpszPassword; LPWSTR lpszUserName; -} *LPWININETFTPSESSIONW; +}; typedef struct { BOOL bIsDirectory; LPWSTR lpszName; DWORD nSize; - struct tm tmLastModified; + SYSTEMTIME tmLastModified; unsigned short permissions; } FILEPROPERTIESW, *LPFILEPROPERTIESW; typedef struct { - WININETHANDLEHEADER hdr; - WININETFTPSESSIONW *lpFtpSession; + object_header_t hdr; + ftp_session_t *lpFtpSession; DWORD index; DWORD size; LPFILEPROPERTIESW lpafp; @@ -165,46 +179,51 @@ static const CHAR szMonths[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC"; static const WCHAR szNoAccount[] = {'n','o','a','c','c','o','u','n','t','\0'}; static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam, - INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext); -static BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType); -static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket); -static BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile); -static INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD_PTR dwContext); -static BOOL FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType); -static BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile); -static BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs); -static BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs); -static BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs); -static BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs); -static BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType); -static BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs); -static BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs); -static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs); + INTERNET_STATUS_CALLBACK lpfnStatusCB, object_header_t *hdr, DWORD_PTR dwContext); +static BOOL FTP_SendStore(ftp_session_t*, LPCWSTR lpszRemoteFile, DWORD dwType); +static BOOL FTP_GetDataSocket(ftp_session_t*, LPINT nDataSocket); +static BOOL FTP_SendData(ftp_session_t*, INT nDataSocket, HANDLE hFile); +static INT FTP_ReceiveResponse(ftp_session_t*, DWORD_PTR dwContext); +static BOOL FTP_SendRetrieve(ftp_session_t*, LPCWSTR lpszRemoteFile, DWORD dwType); +static BOOL FTP_RetrieveFileData(ftp_session_t*, INT nDataSocket, HANDLE hFile); +static BOOL FTP_InitListenSocket(ftp_session_t*); +static BOOL FTP_ConnectToHost(ftp_session_t*); +static BOOL FTP_SendPassword(ftp_session_t*); +static BOOL FTP_SendAccount(ftp_session_t*); +static BOOL FTP_SendType(ftp_session_t*, DWORD dwType); +static BOOL FTP_SendPort(ftp_session_t*); +static BOOL FTP_DoPassive(ftp_session_t*); +static BOOL FTP_SendPortOrPasv(ftp_session_t*); static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp); static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW fileprop); -static BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile, +static BOOL FTP_ParseDirectory(ftp_session_t*, INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW *lpafp, LPDWORD dwfp); -static HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile, +static HINTERNET FTP_ReceiveFileList(ftp_session_t*, INT nSocket, LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD_PTR dwContext); static DWORD FTP_SetResponseError(DWORD dwResponse); static BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFindFileData); -static BOOL FTP_FtpPutFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszLocalFile, +static BOOL FTP_FtpPutFileW(ftp_session_t*, LPCWSTR lpszLocalFile, LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext); -static BOOL FTP_FtpSetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory); -static BOOL FTP_FtpCreateDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory); -static HINTERNET FTP_FtpFindFirstFileW(LPWININETFTPSESSIONW lpwfs, +static BOOL FTP_FtpSetCurrentDirectoryW(ftp_session_t*, LPCWSTR lpszDirectory); +static BOOL FTP_FtpCreateDirectoryW(ftp_session_t*, LPCWSTR lpszDirectory); +static HINTERNET FTP_FtpFindFirstFileW(ftp_session_t*, LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext); -static BOOL FTP_FtpGetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPWSTR lpszCurrentDirectory, +static BOOL FTP_FtpGetCurrentDirectoryW(ftp_session_t*, LPWSTR lpszCurrentDirectory, LPDWORD lpdwCurrentDirectory); -static BOOL FTP_FtpRenameFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszSrc, LPCWSTR lpszDest); -static BOOL FTP_FtpRemoveDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory); -static BOOL FTP_FtpDeleteFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszFileName); -static HINTERNET FTP_FtpOpenFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszFileName, - DWORD fdwAccess, DWORD dwFlags, DWORD_PTR dwContext); -static BOOL FTP_FtpGetFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile, +static BOOL FTP_FtpRenameFileW(ftp_session_t*, LPCWSTR lpszSrc, LPCWSTR lpszDest); +static BOOL FTP_FtpRemoveDirectoryW(ftp_session_t*, LPCWSTR lpszDirectory); +static BOOL FTP_FtpDeleteFileW(ftp_session_t*, LPCWSTR lpszFileName); +static BOOL FTP_FtpGetFileW(ftp_session_t*, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile, BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags, DWORD_PTR dwContext); +/* A temporary helper until we get rid of INTERNET_GetLastError calls */ +static BOOL res_to_le(DWORD res) +{ + if(res != ERROR_SUCCESS) + INTERNET_SetLastError(res); + return res == ERROR_SUCCESS; +} /*********************************************************************** * FtpPutFileA (WININET.@) @@ -223,8 +242,8 @@ BOOL WINAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile, LPWSTR lpwzNewRemoteFile; BOOL ret; - lpwzLocalFile = lpszLocalFile?WININET_strdup_AtoW(lpszLocalFile):NULL; - lpwzNewRemoteFile = lpszNewRemoteFile?WININET_strdup_AtoW(lpszNewRemoteFile):NULL; + lpwzLocalFile = heap_strdupAtoW(lpszLocalFile); + lpwzNewRemoteFile = heap_strdupAtoW(lpszNewRemoteFile); ret = FtpPutFileW(hConnect, lpwzLocalFile, lpwzNewRemoteFile, dwFlags, dwContext); HeapFree(GetProcessHeap(), 0, lpwzLocalFile); @@ -235,7 +254,7 @@ BOOL WINAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile, static void AsyncFtpPutFileProc(WORKREQUEST *workRequest) { struct WORKREQ_FTPPUTFILEW const *req = &workRequest->u.FtpPutFileW; - LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr; + ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr; TRACE("%p\n", lpwfs); @@ -259,8 +278,8 @@ static void AsyncFtpPutFileProc(WORKREQUEST *workRequest) BOOL WINAPI FtpPutFileW(HINTERNET hConnect, LPCWSTR lpszLocalFile, LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext) { - LPWININETFTPSESSIONW lpwfs; - LPWININETAPPINFOW hIC = NULL; + ftp_session_t *lpwfs; + appinfo_t *hIC = NULL; BOOL r = FALSE; if (!lpszLocalFile || !lpszNewRemoteFile) @@ -269,7 +288,7 @@ BOOL WINAPI FtpPutFileW(HINTERNET hConnect, LPCWSTR lpszLocalFile, return FALSE; } - lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect ); + lpwfs = (ftp_session_t*) WININET_GetObject( hConnect ); if (!lpwfs) { INTERNET_SetLastError(ERROR_INVALID_HANDLE); @@ -302,12 +321,12 @@ BOOL WINAPI FtpPutFileW(HINTERNET hConnect, LPCWSTR lpszLocalFile, workRequest.asyncproc = AsyncFtpPutFileProc; workRequest.hdr = WININET_AddRef( &lpwfs->hdr ); - req->lpszLocalFile = WININET_strdupW(lpszLocalFile); - req->lpszNewRemoteFile = WININET_strdupW(lpszNewRemoteFile); + req->lpszLocalFile = heap_strdupW(lpszLocalFile); + req->lpszNewRemoteFile = heap_strdupW(lpszNewRemoteFile); req->dwFlags = dwFlags; req->dwContext = dwContext; - r = INTERNET_AsyncCall(&workRequest); + r = res_to_le(INTERNET_AsyncCall(&workRequest)); } else { @@ -331,12 +350,12 @@ lend: * FALSE on failure * */ -static BOOL FTP_FtpPutFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszLocalFile, +static BOOL FTP_FtpPutFileW(ftp_session_t *lpwfs, LPCWSTR lpszLocalFile, LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext) { HANDLE hFile; BOOL bSuccess = FALSE; - LPWININETAPPINFOW hIC = NULL; + appinfo_t *hIC = NULL; INT nResCode; TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", debugstr_w(lpszLocalFile), debugstr_w(lpszNewRemoteFile)); @@ -375,7 +394,10 @@ static BOOL FTP_FtpPutFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszLocalFile, } if (lpwfs->lstnSocket != -1) + { closesocket(lpwfs->lstnSocket); + lpwfs->lstnSocket = -1; + } if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) { @@ -408,7 +430,7 @@ BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory) LPWSTR lpwzDirectory; BOOL ret; - lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL; + lpwzDirectory = heap_strdupAtoW(lpszDirectory); ret = FtpSetCurrentDirectoryW(hConnect, lpwzDirectory); HeapFree(GetProcessHeap(), 0, lpwzDirectory); return ret; @@ -418,7 +440,7 @@ BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory) static void AsyncFtpSetCurrentDirectoryProc(WORKREQUEST *workRequest) { struct WORKREQ_FTPSETCURRENTDIRECTORYW const *req = &workRequest->u.FtpSetCurrentDirectoryW; - LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr; + ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr; TRACE("%p\n", lpwfs); @@ -438,8 +460,8 @@ static void AsyncFtpSetCurrentDirectoryProc(WORKREQUEST *workRequest) */ BOOL WINAPI FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory) { - LPWININETFTPSESSIONW lpwfs = NULL; - LPWININETAPPINFOW hIC = NULL; + ftp_session_t *lpwfs = NULL; + appinfo_t *hIC = NULL; BOOL r = FALSE; if (!lpszDirectory) @@ -448,7 +470,7 @@ BOOL WINAPI FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory) goto lend; } - lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect ); + lpwfs = (ftp_session_t*) WININET_GetObject( hConnect ); if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype) { INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); @@ -472,9 +494,9 @@ BOOL WINAPI FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory) workRequest.asyncproc = AsyncFtpSetCurrentDirectoryProc; workRequest.hdr = WININET_AddRef( &lpwfs->hdr ); req = &workRequest.u.FtpSetCurrentDirectoryW; - req->lpszDirectory = WININET_strdupW(lpszDirectory); + req->lpszDirectory = heap_strdupW(lpszDirectory); - r = INTERNET_AsyncCall(&workRequest); + r = res_to_le(INTERNET_AsyncCall(&workRequest)); } else { @@ -499,10 +521,10 @@ lend: * FALSE on failure * */ -static BOOL FTP_FtpSetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory) +static BOOL FTP_FtpSetCurrentDirectoryW(ftp_session_t *lpwfs, LPCWSTR lpszDirectory) { INT nResCode; - LPWININETAPPINFOW hIC = NULL; + appinfo_t *hIC = NULL; DWORD bSuccess = FALSE; TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory)); @@ -554,7 +576,7 @@ BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory) LPWSTR lpwzDirectory; BOOL ret; - lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL; + lpwzDirectory = heap_strdupAtoW(lpszDirectory); ret = FtpCreateDirectoryW(hConnect, lpwzDirectory); HeapFree(GetProcessHeap(), 0, lpwzDirectory); return ret; @@ -564,7 +586,7 @@ BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory) static void AsyncFtpCreateDirectoryProc(WORKREQUEST *workRequest) { struct WORKREQ_FTPCREATEDIRECTORYW const *req = &workRequest->u.FtpCreateDirectoryW; - LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr; + ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr; TRACE(" %p\n", lpwfs); @@ -584,11 +606,11 @@ static void AsyncFtpCreateDirectoryProc(WORKREQUEST *workRequest) */ BOOL WINAPI FtpCreateDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory) { - LPWININETFTPSESSIONW lpwfs; - LPWININETAPPINFOW hIC = NULL; + ftp_session_t *lpwfs; + appinfo_t *hIC = NULL; BOOL r = FALSE; - lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect ); + lpwfs = (ftp_session_t*) WININET_GetObject( hConnect ); if (!lpwfs) { INTERNET_SetLastError(ERROR_INVALID_HANDLE); @@ -622,9 +644,9 @@ BOOL WINAPI FtpCreateDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory) workRequest.asyncproc = AsyncFtpCreateDirectoryProc; workRequest.hdr = WININET_AddRef( &lpwfs->hdr ); req = &workRequest.u.FtpCreateDirectoryW; - req->lpszDirectory = WININET_strdupW(lpszDirectory); + req->lpszDirectory = heap_strdupW(lpszDirectory); - r = INTERNET_AsyncCall(&workRequest); + r = res_to_le(INTERNET_AsyncCall(&workRequest)); } else { @@ -647,11 +669,11 @@ lend: * FALSE on failure * */ -static BOOL FTP_FtpCreateDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory) +static BOOL FTP_FtpCreateDirectoryW(ftp_session_t *lpwfs, LPCWSTR lpszDirectory) { INT nResCode; BOOL bSuccess = FALSE; - LPWININETAPPINFOW hIC = NULL; + appinfo_t *hIC = NULL; TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory)); @@ -703,14 +725,14 @@ HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect, LPWIN32_FIND_DATAW lpFindFileDataW; HINTERNET ret; - lpwzSearchFile = lpszSearchFile?WININET_strdup_AtoW(lpszSearchFile):NULL; + lpwzSearchFile = heap_strdupAtoW(lpszSearchFile); lpFindFileDataW = lpFindFileData?&wfd:NULL; ret = FtpFindFirstFileW(hConnect, lpwzSearchFile, lpFindFileDataW, dwFlags, dwContext); HeapFree(GetProcessHeap(), 0, lpwzSearchFile); if (ret && lpFindFileData) WININET_find_data_WtoA(lpFindFileDataW, lpFindFileData); - + return ret; } @@ -718,7 +740,7 @@ HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect, static void AsyncFtpFindFirstFileProc(WORKREQUEST *workRequest) { struct WORKREQ_FTPFINDFIRSTFILEW const *req = &workRequest->u.FtpFindFirstFileW; - LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr; + ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr; TRACE("%p\n", lpwfs); @@ -740,11 +762,11 @@ static void AsyncFtpFindFirstFileProc(WORKREQUEST *workRequest) HINTERNET WINAPI FtpFindFirstFileW(HINTERNET hConnect, LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext) { - LPWININETFTPSESSIONW lpwfs; - LPWININETAPPINFOW hIC = NULL; + ftp_session_t *lpwfs; + appinfo_t *hIC = NULL; HINTERNET r = NULL; - lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect ); + lpwfs = (ftp_session_t*) WININET_GetObject( hConnect ); if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype) { INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); @@ -766,7 +788,7 @@ HINTERNET WINAPI FtpFindFirstFileW(HINTERNET hConnect, workRequest.asyncproc = AsyncFtpFindFirstFileProc; workRequest.hdr = WININET_AddRef( &lpwfs->hdr ); req = &workRequest.u.FtpFindFirstFileW; - req->lpszSearchFile = (lpszSearchFile == NULL) ? NULL : WININET_strdupW(lpszSearchFile); + req->lpszSearchFile = (lpszSearchFile == NULL) ? NULL : heap_strdupW(lpszSearchFile); req->lpFindFileData = lpFindFileData; req->dwFlags = dwFlags; req->dwContext= dwContext; @@ -797,11 +819,11 @@ lend: * NULL on failure * */ -static HINTERNET FTP_FtpFindFirstFileW(LPWININETFTPSESSIONW lpwfs, +static HINTERNET FTP_FtpFindFirstFileW(ftp_session_t *lpwfs, LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext) { INT nResCode; - LPWININETAPPINFOW hIC = NULL; + appinfo_t *hIC = NULL; HINTERNET hFindNext = NULL; TRACE("\n"); @@ -845,7 +867,10 @@ static HINTERNET FTP_FtpFindFirstFileW(LPWININETFTPSESSIONW lpwfs, lend: if (lpwfs->lstnSocket != -1) + { closesocket(lpwfs->lstnSocket); + lpwfs->lstnSocket = -1; + } hIC = lpwfs->lpAppInfo; if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) @@ -854,13 +879,13 @@ lend: if (hFindNext) { - iar.dwResult = (DWORD)hFindNext; + iar.dwResult = (DWORD_PTR)hFindNext; iar.dwError = ERROR_SUCCESS; SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED, &iar, sizeof(INTERNET_ASYNC_RESULT)); } - iar.dwResult = (DWORD)hFindNext; + iar.dwResult = (DWORD_PTR)hFindNext; iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError(); SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, &iar, sizeof(INTERNET_ASYNC_RESULT)); @@ -913,7 +938,7 @@ BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDire static void AsyncFtpGetCurrentDirectoryProc(WORKREQUEST *workRequest) { struct WORKREQ_FTPGETCURRENTDIRECTORYW const *req = &workRequest->u.FtpGetCurrentDirectoryW; - LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr; + ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr; TRACE("%p\n", lpwfs); @@ -933,13 +958,13 @@ static void AsyncFtpGetCurrentDirectoryProc(WORKREQUEST *workRequest) BOOL WINAPI FtpGetCurrentDirectoryW(HINTERNET hFtpSession, LPWSTR lpszCurrentDirectory, LPDWORD lpdwCurrentDirectory) { - LPWININETFTPSESSIONW lpwfs; - LPWININETAPPINFOW hIC = NULL; + ftp_session_t *lpwfs; + appinfo_t *hIC = NULL; BOOL r = FALSE; TRACE("%p %p %p\n", hFtpSession, lpszCurrentDirectory, lpdwCurrentDirectory); - lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession ); + lpwfs = (ftp_session_t*) WININET_GetObject( hFtpSession ); if (NULL == lpwfs) { INTERNET_SetLastError(ERROR_INVALID_HANDLE); @@ -982,7 +1007,7 @@ BOOL WINAPI FtpGetCurrentDirectoryW(HINTERNET hFtpSession, LPWSTR lpszCurrentDir req->lpszDirectory = lpszCurrentDirectory; req->lpdwDirectory = lpdwCurrentDirectory; - r = INTERNET_AsyncCall(&workRequest); + r = res_to_le(INTERNET_AsyncCall(&workRequest)); } else { @@ -1008,11 +1033,11 @@ lend: * FALSE on failure * */ -static BOOL FTP_FtpGetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPWSTR lpszCurrentDirectory, +static BOOL FTP_FtpGetCurrentDirectoryW(ftp_session_t *lpwfs, LPWSTR lpszCurrentDirectory, LPDWORD lpdwCurrentDirectory) { INT nResCode; - LPWININETAPPINFOW hIC = NULL; + appinfo_t *hIC = NULL; DWORD bSuccess = FALSE; /* Clear any error information */ @@ -1029,7 +1054,7 @@ static BOOL FTP_FtpGetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPWSTR lpszC if (nResCode == 257) /* Extract directory name */ { DWORD firstpos, lastpos, len; - LPWSTR lpszResponseBuffer = WININET_strdup_AtoW(INTERNET_GetResponseBuffer()); + LPWSTR lpszResponseBuffer = heap_strdupAtoW(INTERNET_GetResponseBuffer()); for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++) { @@ -1071,6 +1096,354 @@ lend: return bSuccess; } + +/*********************************************************************** + * FTPFILE_Destroy(internal) + * + * Closes the file transfer handle. This also 'cleans' the data queue of + * the 'transfer complete' message (this is a bit of a hack though :-/ ) + * + */ +static void FTPFILE_Destroy(object_header_t *hdr) +{ + ftp_file_t *lpwh = (ftp_file_t*) hdr; + ftp_session_t *lpwfs = lpwh->lpFtpSession; + INT nResCode; + + TRACE("\n"); + + if (lpwh->cache_file_handle != INVALID_HANDLE_VALUE) + CloseHandle(lpwh->cache_file_handle); + + HeapFree(GetProcessHeap(), 0, lpwh->cache_file); + + if (!lpwh->session_deleted) + lpwfs->download_in_progress = NULL; + + if (lpwh->nDataSocket != -1) + closesocket(lpwh->nDataSocket); + + nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); + if (nResCode > 0 && nResCode != 226) WARN("server reports failed transfer\n"); + + WININET_Release(&lpwh->lpFtpSession->hdr); + + HeapFree(GetProcessHeap(), 0, lpwh); +} + +static DWORD FTPFILE_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) +{ + switch(option) { + case INTERNET_OPTION_HANDLE_TYPE: + TRACE("INTERNET_OPTION_HANDLE_TYPE\n"); + + if (*size < sizeof(ULONG)) + return ERROR_INSUFFICIENT_BUFFER; + + *size = sizeof(DWORD); + *(DWORD*)buffer = INTERNET_HANDLE_TYPE_FTP_FILE; + return ERROR_SUCCESS; + case INTERNET_OPTION_DATAFILE_NAME: + { + DWORD required; + ftp_file_t *file = (ftp_file_t *)hdr; + + TRACE("INTERNET_OPTION_DATAFILE_NAME\n"); + + if (!file->cache_file) + { + *size = 0; + return ERROR_INTERNET_ITEM_NOT_FOUND; + } + if (unicode) + { + required = (lstrlenW(file->cache_file) + 1) * sizeof(WCHAR); + if (*size < required) + return ERROR_INSUFFICIENT_BUFFER; + + *size = required; + memcpy(buffer, file->cache_file, *size); + return ERROR_SUCCESS; + } + else + { + required = WideCharToMultiByte(CP_ACP, 0, file->cache_file, -1, NULL, 0, NULL, NULL); + if (required > *size) + return ERROR_INSUFFICIENT_BUFFER; + + *size = WideCharToMultiByte(CP_ACP, 0, file->cache_file, -1, buffer, *size, NULL, NULL); + return ERROR_SUCCESS; + } + } + } + return INET_QueryOption(option, buffer, size, unicode); +} + +static DWORD FTPFILE_ReadFile(object_header_t *hdr, void *buffer, DWORD size, DWORD *read) +{ + ftp_file_t *file = (ftp_file_t*)hdr; + int res; + DWORD error; + + if (file->nDataSocket == -1) + return ERROR_INTERNET_DISCONNECTED; + + /* FIXME: FTP should use NETCON_ stuff */ + res = recv(file->nDataSocket, buffer, size, MSG_WAITALL); + *read = res>0 ? res : 0; + + error = res >= 0 ? ERROR_SUCCESS : INTERNET_ERROR_BASE; /* FIXME */ + if (error == ERROR_SUCCESS && file->cache_file) + { + DWORD bytes_written; + + if (!WriteFile(file->cache_file_handle, buffer, *read, &bytes_written, NULL)) + WARN("WriteFile failed: %u\n", GetLastError()); + } + return error; +} + +static DWORD FTPFILE_ReadFileExA(object_header_t *hdr, INTERNET_BUFFERSA *buffers, + DWORD flags, DWORD_PTR context) +{ + return FTPFILE_ReadFile(hdr, buffers->lpvBuffer, buffers->dwBufferLength, &buffers->dwBufferLength); +} + +static DWORD FTPFILE_ReadFileExW(object_header_t *hdr, INTERNET_BUFFERSW *buffers, + DWORD flags, DWORD_PTR context) +{ + return FTPFILE_ReadFile(hdr, buffers->lpvBuffer, buffers->dwBufferLength, &buffers->dwBufferLength); +} + +static DWORD FTPFILE_WriteFile(object_header_t *hdr, const void *buffer, DWORD size, DWORD *written) +{ + ftp_file_t *lpwh = (ftp_file_t*) hdr; + int res; + + res = send(lpwh->nDataSocket, buffer, size, 0); + + *written = res>0 ? res : 0; + return res >= 0 ? ERROR_SUCCESS : sock_get_error(errno); +} + +static void FTP_ReceiveRequestData(ftp_file_t *file, BOOL first_notif) +{ + INTERNET_ASYNC_RESULT iar; + BYTE buffer[4096]; + int available; + + TRACE("%p\n", file); + + available = recv(file->nDataSocket, buffer, sizeof(buffer), MSG_PEEK); + + if(available != -1) { + iar.dwResult = (DWORD_PTR)file->hdr.hInternet; + iar.dwError = first_notif ? 0 : available; + }else { + iar.dwResult = 0; + iar.dwError = INTERNET_GetLastError(); + } + + INTERNET_SendCallback(&file->hdr, file->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, &iar, + sizeof(INTERNET_ASYNC_RESULT)); +} + +static void FTPFILE_AsyncQueryDataAvailableProc(WORKREQUEST *workRequest) +{ + ftp_file_t *file = (ftp_file_t*)workRequest->hdr; + + FTP_ReceiveRequestData(file, FALSE); +} + +static DWORD FTPFILE_QueryDataAvailable(object_header_t *hdr, DWORD *available, DWORD flags, DWORD_PTR ctx) +{ + ftp_file_t *file = (ftp_file_t*) hdr; + int retval, unread = 0; + + TRACE("(%p %p %x %lx)\n", file, available, flags, ctx); + +#ifdef FIONREAD + retval = ioctlsocket(file->nDataSocket, FIONREAD, &unread); + if (!retval) + TRACE("%d bytes of queued, but unread data\n", unread); +#else + FIXME("FIONREAD not available\n"); +#endif + + *available = unread; + + if(!unread) { + BYTE byte; + + *available = 0; + + retval = recv(file->nDataSocket, &byte, 1, MSG_PEEK); + if(retval > 0) { + WORKREQUEST workRequest; + + *available = 0; + workRequest.asyncproc = FTPFILE_AsyncQueryDataAvailableProc; + workRequest.hdr = WININET_AddRef( &file->hdr ); + + INTERNET_AsyncCall(&workRequest); + + return ERROR_IO_PENDING; + } + } + + return ERROR_SUCCESS; +} + + +static const object_vtbl_t FTPFILEVtbl = { + FTPFILE_Destroy, + NULL, + FTPFILE_QueryOption, + NULL, + FTPFILE_ReadFile, + FTPFILE_ReadFileExA, + FTPFILE_ReadFileExW, + FTPFILE_WriteFile, + FTPFILE_QueryDataAvailable, + NULL +}; + +/*********************************************************************** + * FTP_FtpOpenFileW (Internal) + * + * Open a remote file for writing or reading + * + * RETURNS + * HINTERNET handle on success + * NULL on failure + * + */ +static HINTERNET FTP_FtpOpenFileW(ftp_session_t *lpwfs, + LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags, + DWORD_PTR dwContext) +{ + INT nDataSocket; + BOOL bSuccess = FALSE; + ftp_file_t *lpwh = NULL; + appinfo_t *hIC = NULL; + HINTERNET handle = NULL; + + TRACE("\n"); + + /* Clear any error information */ + INTERNET_SetLastError(0); + + if (GENERIC_READ == fdwAccess) + { + /* Set up socket to retrieve data */ + bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags); + } + else if (GENERIC_WRITE == fdwAccess) + { + /* Set up socket to send data */ + bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags); + } + + /* Get data socket to server */ + if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket)) + { + lpwh = HeapAlloc(GetProcessHeap(), 0, sizeof(ftp_file_t)); + lpwh->hdr.htype = WH_HFILE; + lpwh->hdr.vtbl = &FTPFILEVtbl; + lpwh->hdr.dwFlags = dwFlags; + lpwh->hdr.dwContext = dwContext; + lpwh->hdr.dwInternalFlags = 0; + lpwh->hdr.refs = 1; + lpwh->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB; + lpwh->nDataSocket = nDataSocket; + lpwh->cache_file = NULL; + lpwh->cache_file_handle = INVALID_HANDLE_VALUE; + lpwh->session_deleted = FALSE; + + WININET_AddRef( &lpwfs->hdr ); + lpwh->lpFtpSession = lpwfs; + list_add_head( &lpwfs->hdr.children, &lpwh->hdr.entry ); + + handle = WININET_AllocHandle( &lpwh->hdr ); + if( !handle ) + goto lend; + + /* Indicate that a download is currently in progress */ + lpwfs->download_in_progress = lpwh; + } + + if (lpwfs->lstnSocket != -1) + { + closesocket(lpwfs->lstnSocket); + lpwfs->lstnSocket = -1; + } + + if (bSuccess && fdwAccess == GENERIC_READ) + { + WCHAR filename[MAX_PATH + 1]; + URL_COMPONENTSW uc; + DWORD len; + + memset(&uc, 0, sizeof(uc)); + uc.dwStructSize = sizeof(uc); + uc.nScheme = INTERNET_SCHEME_FTP; + uc.lpszHostName = lpwfs->servername; + uc.nPort = lpwfs->serverport; + uc.lpszUserName = lpwfs->lpszUserName; + uc.lpszUrlPath = heap_strdupW(lpszFileName); + + if (!InternetCreateUrlW(&uc, 0, NULL, &len) && GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + WCHAR *url = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + + if (url && InternetCreateUrlW(&uc, 0, url, &len) && CreateUrlCacheEntryW(url, 0, NULL, filename, 0)) + { + lpwh->cache_file = heap_strdupW(filename); + lpwh->cache_file_handle = CreateFileW(filename, GENERIC_WRITE, FILE_SHARE_READ, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (lpwh->cache_file_handle == INVALID_HANDLE_VALUE) + { + WARN("Could not create cache file: %u\n", GetLastError()); + HeapFree(GetProcessHeap(), 0, lpwh->cache_file); + lpwh->cache_file = NULL; + } + } + HeapFree(GetProcessHeap(), 0, url); + } + HeapFree(GetProcessHeap(), 0, uc.lpszUrlPath); + } + + hIC = lpwfs->lpAppInfo; + if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) + { + INTERNET_ASYNC_RESULT iar; + + if (lpwh) + { + iar.dwResult = (DWORD_PTR)handle; + iar.dwError = ERROR_SUCCESS; + SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED, + &iar, sizeof(INTERNET_ASYNC_RESULT)); + } + + if(bSuccess) { + FTP_ReceiveRequestData(lpwh, TRUE); + }else { + iar.dwResult = 0; + iar.dwError = INTERNET_GetLastError(); + SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, + &iar, sizeof(INTERNET_ASYNC_RESULT)); + } + } + +lend: + if( lpwh ) + WININET_Release( &lpwh->hdr ); + + return handle; +} + + /*********************************************************************** * FtpOpenFileA (WININET.@) * @@ -1087,8 +1460,8 @@ HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession, { LPWSTR lpwzFileName; HINTERNET ret; - - lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL; + + lpwzFileName = heap_strdupAtoW(lpszFileName); ret = FtpOpenFileW(hFtpSession, lpwzFileName, fdwAccess, dwFlags, dwContext); HeapFree(GetProcessHeap(), 0, lpwzFileName); return ret; @@ -1098,7 +1471,7 @@ HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession, static void AsyncFtpOpenFileProc(WORKREQUEST *workRequest) { struct WORKREQ_FTPOPENFILEW const *req = &workRequest->u.FtpOpenFileW; - LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr; + ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr; TRACE("%p\n", lpwfs); @@ -1121,14 +1494,14 @@ HINTERNET WINAPI FtpOpenFileW(HINTERNET hFtpSession, LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags, DWORD_PTR dwContext) { - LPWININETFTPSESSIONW lpwfs; - LPWININETAPPINFOW hIC = NULL; + ftp_session_t *lpwfs; + appinfo_t *hIC = NULL; HINTERNET r = NULL; - + TRACE("(%p,%s,0x%08x,0x%08x,0x%08lx)\n", hFtpSession, debugstr_w(lpszFileName), fdwAccess, dwFlags, dwContext); - lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession ); + lpwfs = (ftp_session_t*) WININET_GetObject( hFtpSession ); if (!lpwfs) { INTERNET_SetLastError(ERROR_INVALID_HANDLE); @@ -1164,7 +1537,7 @@ HINTERNET WINAPI FtpOpenFileW(HINTERNET hFtpSession, workRequest.asyncproc = AsyncFtpOpenFileProc; workRequest.hdr = WININET_AddRef( &lpwfs->hdr ); req = &workRequest.u.FtpOpenFileW; - req->lpszFilename = WININET_strdupW(lpszFileName); + req->lpszFilename = heap_strdupW(lpszFileName); req->dwAccess = fdwAccess; req->dwFlags = dwFlags; req->dwContext = dwContext; @@ -1184,181 +1557,6 @@ lend: } -/*********************************************************************** - * FTPFILE_Destroy(internal) - * - * Closes the file transfer handle. This also 'cleans' the data queue of - * the 'transfer complete' message (this is a bit of a hack though :-/ ) - * - */ -static void FTPFILE_Destroy(WININETHANDLEHEADER *hdr) -{ - LPWININETFTPFILE lpwh = (LPWININETFTPFILE) hdr; - LPWININETFTPSESSIONW lpwfs = lpwh->lpFtpSession; - INT nResCode; - - TRACE("\n"); - - WININET_Release(&lpwh->lpFtpSession->hdr); - - if (!lpwh->session_deleted) - lpwfs->download_in_progress = NULL; - - if (lpwh->nDataSocket != -1) - closesocket(lpwh->nDataSocket); - - nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); - if (nResCode > 0 && nResCode != 226) WARN("server reports failed transfer\n"); - - HeapFree(GetProcessHeap(), 0, lpwh); -} - -static DWORD FTPFILE_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) -{ - switch(option) { - case INTERNET_OPTION_HANDLE_TYPE: - TRACE("INTERNET_OPTION_HANDLE_TYPE\n"); - - if (*size < sizeof(ULONG)) - return ERROR_INSUFFICIENT_BUFFER; - - *size = sizeof(DWORD); - *(DWORD*)buffer = INTERNET_HANDLE_TYPE_FTP_FILE; - return ERROR_SUCCESS; - } - - return INET_QueryOption(option, buffer, size, unicode); -} - -static DWORD FTPFILE_ReadFile(WININETHANDLEHEADER *hdr, void *buffer, DWORD size, DWORD *read) -{ - WININETFTPFILE *file = (WININETFTPFILE*)hdr; - int res; - - if (file->nDataSocket == -1) - return ERROR_INTERNET_DISCONNECTED; - - /* FIXME: FTP should use NETCON_ stuff */ - res = recv(file->nDataSocket, buffer, size, MSG_WAITALL); - *read = res>0 ? res : 0; - - return res>=0 ? ERROR_SUCCESS : INTERNET_ERROR_BASE; /* FIXME*/ -} - -static BOOL FTPFILE_WriteFile(WININETHANDLEHEADER *hdr, const void *buffer, DWORD size, DWORD *written) -{ - LPWININETFTPFILE lpwh = (LPWININETFTPFILE) hdr; - int res; - - res = send(lpwh->nDataSocket, buffer, size, 0); - - *written = res>0 ? res : 0; - return res >= 0; -} - -static const HANDLEHEADERVtbl FTPFILEVtbl = { - FTPFILE_Destroy, - NULL, - FTPFILE_QueryOption, - NULL, - FTPFILE_ReadFile, - NULL, - FTPFILE_WriteFile, - NULL, - NULL -}; - -/*********************************************************************** - * FTP_FtpOpenFileW (Internal) - * - * Open a remote file for writing or reading - * - * RETURNS - * HINTERNET handle on success - * NULL on failure - * - */ -HINTERNET FTP_FtpOpenFileW(LPWININETFTPSESSIONW lpwfs, - LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags, - DWORD_PTR dwContext) -{ - INT nDataSocket; - BOOL bSuccess = FALSE; - LPWININETFTPFILE lpwh = NULL; - LPWININETAPPINFOW hIC = NULL; - HINTERNET handle = NULL; - - TRACE("\n"); - - /* Clear any error information */ - INTERNET_SetLastError(0); - - if (GENERIC_READ == fdwAccess) - { - /* Set up socket to retrieve data */ - bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags); - } - else if (GENERIC_WRITE == fdwAccess) - { - /* Set up socket to send data */ - bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags); - } - - /* Get data socket to server */ - if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket)) - { - lpwh = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPFILE)); - lpwh->hdr.htype = WH_HFILE; - lpwh->hdr.vtbl = &FTPFILEVtbl; - lpwh->hdr.dwFlags = dwFlags; - lpwh->hdr.dwContext = dwContext; - lpwh->hdr.refs = 1; - lpwh->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB; - lpwh->nDataSocket = nDataSocket; - lpwh->session_deleted = FALSE; - - WININET_AddRef( &lpwfs->hdr ); - lpwh->lpFtpSession = lpwfs; - list_add_head( &lpwfs->hdr.children, &lpwh->hdr.entry ); - - handle = WININET_AllocHandle( &lpwh->hdr ); - if( !handle ) - goto lend; - - /* Indicate that a download is currently in progress */ - lpwfs->download_in_progress = lpwh; - } - - if (lpwfs->lstnSocket != -1) - closesocket(lpwfs->lstnSocket); - - hIC = lpwfs->lpAppInfo; - if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) - { - INTERNET_ASYNC_RESULT iar; - - if (lpwh) - { - iar.dwResult = (DWORD)handle; - iar.dwError = ERROR_SUCCESS; - SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED, - &iar, sizeof(INTERNET_ASYNC_RESULT)); - } - - iar.dwResult = (DWORD)bSuccess; - iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError(); - SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, - &iar, sizeof(INTERNET_ASYNC_RESULT)); - } - -lend: - if( lpwh ) - WININET_Release( &lpwh->hdr ); - - return handle; -} - - /*********************************************************************** * FtpGetFileA (WININET.@) * @@ -1377,8 +1575,8 @@ BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszN LPWSTR lpwzNewFile; BOOL ret; - lpwzRemoteFile = lpszRemoteFile?WININET_strdup_AtoW(lpszRemoteFile):NULL; - lpwzNewFile = lpszNewFile?WININET_strdup_AtoW(lpszNewFile):NULL; + lpwzRemoteFile = heap_strdupAtoW(lpszRemoteFile); + lpwzNewFile = heap_strdupAtoW(lpszNewFile); ret = FtpGetFileW(hInternet, lpwzRemoteFile, lpwzNewFile, fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext); HeapFree(GetProcessHeap(), 0, lpwzRemoteFile); @@ -1390,7 +1588,7 @@ BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszN static void AsyncFtpGetFileProc(WORKREQUEST *workRequest) { struct WORKREQ_FTPGETFILEW const *req = &workRequest->u.FtpGetFileW; - LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr; + ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr; TRACE("%p\n", lpwfs); @@ -1416,8 +1614,8 @@ BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lps BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags, DWORD_PTR dwContext) { - LPWININETFTPSESSIONW lpwfs; - LPWININETAPPINFOW hIC = NULL; + ftp_session_t *lpwfs; + appinfo_t *hIC = NULL; BOOL r = FALSE; if (!lpszRemoteFile || !lpszNewFile) @@ -1426,7 +1624,7 @@ BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lps return FALSE; } - lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hInternet ); + lpwfs = (ftp_session_t*) WININET_GetObject( hInternet ); if (!lpwfs) { INTERNET_SetLastError(ERROR_INVALID_HANDLE); @@ -1460,14 +1658,14 @@ BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lps workRequest.asyncproc = AsyncFtpGetFileProc; workRequest.hdr = WININET_AddRef( &lpwfs->hdr ); req = &workRequest.u.FtpGetFileW; - req->lpszRemoteFile = WININET_strdupW(lpszRemoteFile); - req->lpszNewFile = WININET_strdupW(lpszNewFile); + req->lpszRemoteFile = heap_strdupW(lpszRemoteFile); + req->lpszNewFile = heap_strdupW(lpszNewFile); req->dwLocalFlagsAttribute = dwLocalFlagsAttribute; req->fFailIfExists = fFailIfExists; req->dwFlags = dwInternetFlags; req->dwContext = dwContext; - r = INTERNET_AsyncCall(&workRequest); + r = res_to_le(INTERNET_AsyncCall(&workRequest)); } else { @@ -1492,13 +1690,13 @@ lend: * FALSE on failure * */ -static BOOL FTP_FtpGetFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile, +static BOOL FTP_FtpGetFileW(ftp_session_t *lpwfs, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile, BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags, DWORD_PTR dwContext) { BOOL bSuccess = FALSE; HANDLE hFile; - LPWININETAPPINFOW hIC = NULL; + appinfo_t *hIC = NULL; TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", debugstr_w(lpszRemoteFile), debugstr_w(lpszNewFile)); @@ -1537,7 +1735,10 @@ static BOOL FTP_FtpGetFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, } if (lpwfs->lstnSocket != -1) + { closesocket(lpwfs->lstnSocket); + lpwfs->lstnSocket = -1; + } CloseHandle(hFile); @@ -1584,7 +1785,7 @@ BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName) LPWSTR lpwzFileName; BOOL ret; - lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL; + lpwzFileName = heap_strdupAtoW(lpszFileName); ret = FtpDeleteFileW(hFtpSession, lpwzFileName); HeapFree(GetProcessHeap(), 0, lpwzFileName); return ret; @@ -1593,7 +1794,7 @@ BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName) static void AsyncFtpDeleteFileProc(WORKREQUEST *workRequest) { struct WORKREQ_FTPDELETEFILEW const *req = &workRequest->u.FtpDeleteFileW; - LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr; + ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr; TRACE("%p\n", lpwfs); @@ -1613,11 +1814,11 @@ static void AsyncFtpDeleteFileProc(WORKREQUEST *workRequest) */ BOOL WINAPI FtpDeleteFileW(HINTERNET hFtpSession, LPCWSTR lpszFileName) { - LPWININETFTPSESSIONW lpwfs; - LPWININETAPPINFOW hIC = NULL; + ftp_session_t *lpwfs; + appinfo_t *hIC = NULL; BOOL r = FALSE; - lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession ); + lpwfs = (ftp_session_t*) WININET_GetObject( hFtpSession ); if (!lpwfs) { INTERNET_SetLastError(ERROR_INVALID_HANDLE); @@ -1651,9 +1852,9 @@ BOOL WINAPI FtpDeleteFileW(HINTERNET hFtpSession, LPCWSTR lpszFileName) workRequest.asyncproc = AsyncFtpDeleteFileProc; workRequest.hdr = WININET_AddRef( &lpwfs->hdr ); req = &workRequest.u.FtpDeleteFileW; - req->lpszFilename = WININET_strdupW(lpszFileName); + req->lpszFilename = heap_strdupW(lpszFileName); - r = INTERNET_AsyncCall(&workRequest); + r = res_to_le(INTERNET_AsyncCall(&workRequest)); } else { @@ -1676,11 +1877,11 @@ lend: * FALSE on failure * */ -BOOL FTP_FtpDeleteFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszFileName) +BOOL FTP_FtpDeleteFileW(ftp_session_t *lpwfs, LPCWSTR lpszFileName) { INT nResCode; BOOL bSuccess = FALSE; - LPWININETAPPINFOW hIC = NULL; + appinfo_t *hIC = NULL; TRACE("%p\n", lpwfs); @@ -1729,7 +1930,7 @@ BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory) LPWSTR lpwzDirectory; BOOL ret; - lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL; + lpwzDirectory = heap_strdupAtoW(lpszDirectory); ret = FtpRemoveDirectoryW(hFtpSession, lpwzDirectory); HeapFree(GetProcessHeap(), 0, lpwzDirectory); return ret; @@ -1738,7 +1939,7 @@ BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory) static void AsyncFtpRemoveDirectoryProc(WORKREQUEST *workRequest) { struct WORKREQ_FTPREMOVEDIRECTORYW const *req = &workRequest->u.FtpRemoveDirectoryW; - LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr; + ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr; TRACE("%p\n", lpwfs); @@ -1758,11 +1959,11 @@ static void AsyncFtpRemoveDirectoryProc(WORKREQUEST *workRequest) */ BOOL WINAPI FtpRemoveDirectoryW(HINTERNET hFtpSession, LPCWSTR lpszDirectory) { - LPWININETFTPSESSIONW lpwfs; - LPWININETAPPINFOW hIC = NULL; + ftp_session_t *lpwfs; + appinfo_t *hIC = NULL; BOOL r = FALSE; - lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession ); + lpwfs = (ftp_session_t*) WININET_GetObject( hFtpSession ); if (!lpwfs) { INTERNET_SetLastError(ERROR_INVALID_HANDLE); @@ -1796,9 +1997,9 @@ BOOL WINAPI FtpRemoveDirectoryW(HINTERNET hFtpSession, LPCWSTR lpszDirectory) workRequest.asyncproc = AsyncFtpRemoveDirectoryProc; workRequest.hdr = WININET_AddRef( &lpwfs->hdr ); req = &workRequest.u.FtpRemoveDirectoryW; - req->lpszDirectory = WININET_strdupW(lpszDirectory); + req->lpszDirectory = heap_strdupW(lpszDirectory); - r = INTERNET_AsyncCall(&workRequest); + r = res_to_le(INTERNET_AsyncCall(&workRequest)); } else { @@ -1821,11 +2022,11 @@ lend: * FALSE on failure * */ -BOOL FTP_FtpRemoveDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory) +BOOL FTP_FtpRemoveDirectoryW(ftp_session_t *lpwfs, LPCWSTR lpszDirectory) { INT nResCode; BOOL bSuccess = FALSE; - LPWININETAPPINFOW hIC = NULL; + appinfo_t *hIC = NULL; TRACE("\n"); @@ -1876,8 +2077,8 @@ BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDes LPWSTR lpwzDest; BOOL ret; - lpwzSrc = lpszSrc?WININET_strdup_AtoW(lpszSrc):NULL; - lpwzDest = lpszDest?WININET_strdup_AtoW(lpszDest):NULL; + lpwzSrc = heap_strdupAtoW(lpszSrc); + lpwzDest = heap_strdupAtoW(lpszDest); ret = FtpRenameFileW(hFtpSession, lpwzSrc, lpwzDest); HeapFree(GetProcessHeap(), 0, lpwzSrc); HeapFree(GetProcessHeap(), 0, lpwzDest); @@ -1887,7 +2088,7 @@ BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDes static void AsyncFtpRenameFileProc(WORKREQUEST *workRequest) { struct WORKREQ_FTPRENAMEFILEW const *req = &workRequest->u.FtpRenameFileW; - LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr; + ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr; TRACE("%p\n", lpwfs); @@ -1908,11 +2109,11 @@ static void AsyncFtpRenameFileProc(WORKREQUEST *workRequest) */ BOOL WINAPI FtpRenameFileW(HINTERNET hFtpSession, LPCWSTR lpszSrc, LPCWSTR lpszDest) { - LPWININETFTPSESSIONW lpwfs; - LPWININETAPPINFOW hIC = NULL; + ftp_session_t *lpwfs; + appinfo_t *hIC = NULL; BOOL r = FALSE; - lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession ); + lpwfs = (ftp_session_t*) WININET_GetObject( hFtpSession ); if (!lpwfs) { INTERNET_SetLastError(ERROR_INVALID_HANDLE); @@ -1946,10 +2147,10 @@ BOOL WINAPI FtpRenameFileW(HINTERNET hFtpSession, LPCWSTR lpszSrc, LPCWSTR lpszD workRequest.asyncproc = AsyncFtpRenameFileProc; workRequest.hdr = WININET_AddRef( &lpwfs->hdr ); req = &workRequest.u.FtpRenameFileW; - req->lpszSrcFile = WININET_strdupW(lpszSrc); - req->lpszDestFile = WININET_strdupW(lpszDest); + req->lpszSrcFile = heap_strdupW(lpszSrc); + req->lpszDestFile = heap_strdupW(lpszDest); - r = INTERNET_AsyncCall(&workRequest); + r = res_to_le(INTERNET_AsyncCall(&workRequest)); } else { @@ -1972,12 +2173,11 @@ lend: * FALSE on failure * */ -BOOL FTP_FtpRenameFileW( LPWININETFTPSESSIONW lpwfs, - LPCWSTR lpszSrc, LPCWSTR lpszDest) +BOOL FTP_FtpRenameFileW(ftp_session_t *lpwfs, LPCWSTR lpszSrc, LPCWSTR lpszDest) { INT nResCode; BOOL bSuccess = FALSE; - LPWININETAPPINFOW hIC = NULL; + appinfo_t *hIC = NULL; TRACE("\n"); @@ -2040,7 +2240,7 @@ BOOL WINAPI FtpCommandA( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags return FALSE; } - if (!(cmdW = WININET_strdup_AtoW(lpszCommand))) + if (!(cmdW = heap_strdupAtoW(lpszCommand))) { INTERNET_SetLastError(ERROR_OUTOFMEMORY); return FALSE; @@ -2059,7 +2259,7 @@ BOOL WINAPI FtpCommandW( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags LPCWSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand ) { BOOL r = FALSE; - LPWININETFTPSESSIONW lpwfs; + ftp_session_t *lpwfs; LPSTR cmd = NULL; DWORD len, nBytesSent= 0; INT nResCode, nRC = 0; @@ -2079,7 +2279,7 @@ BOOL WINAPI FtpCommandW( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags return FALSE; } - lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect ); + lpwfs = (ftp_session_t*) WININET_GetObject( hConnect ); if (!lpwfs) { INTERNET_SetLastError(ERROR_INVALID_HANDLE); @@ -2142,9 +2342,9 @@ lend: * * Deallocate session handle */ -static void FTPSESSION_Destroy(WININETHANDLEHEADER *hdr) +static void FTPSESSION_Destroy(object_header_t *hdr) { - LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) hdr; + ftp_session_t *lpwfs = (ftp_session_t*) hdr; TRACE("\n"); @@ -2152,12 +2352,13 @@ static void FTPSESSION_Destroy(WININETHANDLEHEADER *hdr) HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword); HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName); + HeapFree(GetProcessHeap(), 0, lpwfs->servername); HeapFree(GetProcessHeap(), 0, lpwfs); } -static void FTPSESSION_CloseConnection(WININETHANDLEHEADER *hdr) +static void FTPSESSION_CloseConnection(object_header_t *hdr) { - LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) hdr; + ftp_session_t *lpwfs = (ftp_session_t*) hdr; TRACE("\n"); @@ -2180,7 +2381,7 @@ static void FTPSESSION_CloseConnection(WININETHANDLEHEADER *hdr) INTERNET_STATUS_CONNECTION_CLOSED, 0, 0); } -static DWORD FTPSESSION_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) +static DWORD FTPSESSION_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) { switch(option) { case INTERNET_OPTION_HANDLE_TYPE: @@ -2197,7 +2398,7 @@ static DWORD FTPSESSION_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void return INET_QueryOption(option, buffer, size, unicode); } -static const HANDLEHEADERVtbl FTPSESSIONVtbl = { +static const object_vtbl_t FTPSESSIONVtbl = { FTPSESSION_Destroy, FTPSESSION_CloseConnection, FTPSESSION_QueryOption, @@ -2230,7 +2431,7 @@ static const HANDLEHEADERVtbl FTPSESSIONVtbl = { * */ -HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, +HINTERNET FTP_Connect(appinfo_t *hIC, LPCWSTR lpszServerName, INTERNET_PORT nServerPort, LPCWSTR lpszUserName, LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext, DWORD dwInternalFlags) @@ -2247,8 +2448,9 @@ HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, INT nsocket = -1; UINT sock_namelen; BOOL bSuccess = FALSE; - LPWININETFTPSESSIONW lpwfs = NULL; + ftp_session_t *lpwfs = NULL; HINTERNET handle = NULL; + char szaddr[INET_ADDRSTRLEN]; TRACE("%p Server(%s) Port(%d) User(%s) Paswd(%s)\n", hIC, debugstr_w(lpszServerName), @@ -2256,13 +2458,13 @@ HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, assert( hIC->hdr.htype == WH_HINIT ); - if (NULL == lpszUserName && NULL != lpszPassword) + if ((!lpszUserName || !*lpszUserName) && lpszPassword && *lpszPassword) { INTERNET_SetLastError(ERROR_INVALID_PARAMETER); goto lerror; } - lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONW)); + lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(ftp_session_t)); if (NULL == lpwfs) { INTERNET_SetLastError(ERROR_OUTOFMEMORY); @@ -2270,7 +2472,9 @@ HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, } if (nServerPort == INTERNET_INVALID_PORT_NUMBER) - nServerPort = INTERNET_DEFAULT_FTP_PORT; + lpwfs->serverport = INTERNET_DEFAULT_FTP_PORT; + else + lpwfs->serverport = nServerPort; lpwfs->hdr.htype = WH_HFTPSESSION; lpwfs->hdr.vtbl = &FTPSESSIONVtbl; @@ -2302,12 +2506,12 @@ HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, if(hIC->lpszProxyBypass) FIXME("Proxy bypass is ignored.\n"); } - if ( !lpszUserName) { + if (!lpszUserName || !strlenW(lpszUserName)) { HKEY key; WCHAR szPassword[MAX_PATH]; DWORD len = sizeof(szPassword); - lpwfs->lpszUserName = WININET_strdupW(szDefaultUsername); + lpwfs->lpszUserName = heap_strdupW(szDefaultUsername); RegOpenKeyW(HKEY_CURRENT_USER, szKey, &key); if (RegQueryValueExW(key, szValue, NULL, NULL, (LPBYTE)szPassword, &len)) { @@ -2320,23 +2524,20 @@ HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, RegCloseKey(key); TRACE("Password used for anonymous ftp : (%s)\n", debugstr_w(szPassword)); - lpwfs->lpszPassword = WININET_strdupW(szPassword); + lpwfs->lpszPassword = heap_strdupW(szPassword); } else { - lpwfs->lpszUserName = WININET_strdupW(lpszUserName); - - if (lpszPassword) - lpwfs->lpszPassword = WININET_strdupW(lpszPassword); - else - lpwfs->lpszPassword = WININET_strdupW(szEmpty); + lpwfs->lpszUserName = heap_strdupW(lpszUserName); + lpwfs->lpszPassword = heap_strdupW(lpszPassword ? lpszPassword : szEmpty); } + lpwfs->servername = heap_strdupW(lpszServerName); /* Don't send a handle created callback if this handle was created with InternetOpenUrl */ if (!(lpwfs->hdr.dwInternalFlags & INET_OPENURL)) { INTERNET_ASYNC_RESULT iar; - iar.dwResult = (DWORD)handle; + iar.dwResult = (DWORD_PTR)handle; iar.dwError = ERROR_SUCCESS; SendAsyncCallback(&hIC->hdr, dwContext, @@ -2345,16 +2546,25 @@ HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, } SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_RESOLVING_NAME, - (LPWSTR) lpszServerName, strlenW(lpszServerName)); + (LPWSTR) lpszServerName, (strlenW(lpszServerName)+1) * sizeof(WCHAR)); - if (!GetAddress(lpszServerName, nServerPort, &socketAddr)) + sock_namelen = sizeof(socketAddr); + if (!GetAddress(lpszServerName, lpwfs->serverport, (struct sockaddr *)&socketAddr, &sock_namelen)) { INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED); goto lerror; } + if (socketAddr.sin_family != AF_INET) + { + WARN("unsupported address family %d\n", socketAddr.sin_family); + INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT); + goto lerror; + } + + inet_ntop(socketAddr.sin_family, &socketAddr.sin_addr, szaddr, sizeof(szaddr)); SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_NAME_RESOLVED, - (LPWSTR) lpszServerName, strlenW(lpszServerName)); + szaddr, strlen(szaddr)+1); nsocket = socket(AF_INET,SOCK_STREAM,0); if (nsocket == -1) @@ -2364,19 +2574,20 @@ HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, } SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER, - &socketAddr, sizeof(struct sockaddr_in)); + szaddr, strlen(szaddr)+1); - if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0) + if (connect(nsocket, (struct sockaddr *)&socketAddr, sock_namelen) < 0) { ERR("Unable to connect (%s)\n", strerror(errno)); INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT); + closesocket(nsocket); } else { TRACE("Connected to server\n"); lpwfs->sndSocket = nsocket; SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER, - &socketAddr, sizeof(struct sockaddr_in)); + szaddr, strlen(szaddr)+1); sock_namelen = sizeof(lpwfs->socketAddress); getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen); @@ -2397,16 +2608,6 @@ lerror: handle = NULL; } - if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) - { - INTERNET_ASYNC_RESULT iar; - - iar.dwResult = bSuccess ? (DWORD_PTR)lpwfs : 0; - iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError(); - SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_REQUEST_COMPLETE, - &iar, sizeof(INTERNET_ASYNC_RESULT)); - } - return handle; } @@ -2421,7 +2622,7 @@ lerror: * NULL on failure * */ -static BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs) +static BOOL FTP_ConnectToHost(ftp_session_t *lpwfs) { INT nResCode; BOOL bSuccess = FALSE; @@ -2465,7 +2666,7 @@ lend: * */ static BOOL FTP_SendCommandA(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam, - INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext) + INTERNET_STATUS_CALLBACK lpfnStatusCB, object_header_t *hdr, DWORD_PTR dwContext) { DWORD len; CHAR *buf; @@ -2520,10 +2721,10 @@ static BOOL FTP_SendCommandA(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam, * */ static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam, - INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext) + INTERNET_STATUS_CALLBACK lpfnStatusCB, object_header_t *hdr, DWORD_PTR dwContext) { BOOL ret; - LPSTR lpszParamA = lpszParam?WININET_strdup_WtoA(lpszParam):NULL; + LPSTR lpszParamA = heap_strdupWtoA(lpszParam); ret = FTP_SendCommandA(nSocket, ftpCmd, lpszParamA, lpfnStatusCB, hdr, dwContext); HeapFree(GetProcessHeap(), 0, lpszParamA); return ret; @@ -2539,7 +2740,7 @@ static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam, * 0 on failure * */ -INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD_PTR dwContext) +INT FTP_ReceiveResponse(ftp_session_t *lpwfs, DWORD_PTR dwContext) { LPSTR lpszResponse = INTERNET_GetResponseBuffer(); DWORD nRecv; @@ -2602,7 +2803,7 @@ lerror: * NULL on failure * */ -static BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs) +static BOOL FTP_SendPassword(ftp_session_t *lpwfs) { INT nResCode; BOOL bSuccess = FALSE; @@ -2642,7 +2843,7 @@ lend: * FALSE on failure * */ -static BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs) +static BOOL FTP_SendAccount(ftp_session_t *lpwfs) { INT nResCode; BOOL bSuccess = FALSE; @@ -2672,7 +2873,7 @@ lend: * FALSE on failure * */ -static BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType) +static BOOL FTP_SendStore(ftp_session_t *lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType) { INT nResCode; BOOL bSuccess = FALSE; @@ -2719,10 +2920,10 @@ lend: * FALSE on failure * */ -static BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs) +static BOOL FTP_InitListenSocket(ftp_session_t *lpwfs) { BOOL bSuccess = FALSE; - socklen_t namelen = sizeof(struct sockaddr_in); + socklen_t namelen = sizeof(lpwfs->lstnSocketAddress); TRACE("\n"); @@ -2737,9 +2938,9 @@ static BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs) lpwfs->lstnSocketAddress = lpwfs->socketAddress; /* and get the system to assign us a port */ - lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0); + lpwfs->lstnSocketAddress.sin_port = htons(0); - if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1) + if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(lpwfs->lstnSocketAddress)) == -1) { TRACE("Unable to bind socket\n"); goto lend; @@ -2778,7 +2979,7 @@ lend: * (i.e. it sends it always), * so we probably don't want to do that either. */ -static BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType) +static BOOL FTP_SendType(ftp_session_t *lpwfs, DWORD dwType) { INT nResCode; WCHAR type[] = { 'I','\0' }; @@ -2816,7 +3017,7 @@ lend: * FALSE on failure * */ -static BOOL FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize) +static BOOL FTP_GetFileSize(ftp_session_t *lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize) { INT nResCode; BOOL bSuccess = FALSE; @@ -2860,7 +3061,7 @@ lend: * FALSE on failure * */ -static BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs) +static BOOL FTP_SendPort(ftp_session_t *lpwfs) { static const WCHAR szIPFormat[] = {'%','d',',','%','d',',','%','d',',','%','d',',','%','d',',','%','d','\0'}; INT nResCode; @@ -2904,7 +3105,7 @@ lend: * FALSE on failure * */ -static BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs) +static BOOL FTP_DoPassive(ftp_session_t *lpwfs) { INT nResCode; BOOL bSuccess = FALSE; @@ -2976,7 +3177,7 @@ lend: } -static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs) +static BOOL FTP_SendPortOrPasv(ftp_session_t *lpwfs) { if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE) { @@ -3005,7 +3206,7 @@ static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs) * FALSE on failure * */ -static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket) +static BOOL FTP_GetDataSocket(ftp_session_t *lpwfs, LPINT nDataSocket) { struct sockaddr_in saddr; socklen_t addrlen = sizeof(struct sockaddr); @@ -3014,6 +3215,7 @@ static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket) if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE) { *nDataSocket = lpwfs->pasvSocket; + lpwfs->pasvSocket = -1; } else { @@ -3035,7 +3237,7 @@ static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket) * FALSE on failure * */ -static BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile) +static BOOL FTP_SendData(ftp_session_t *lpwfs, INT nDataSocket, HANDLE hFile) { BY_HANDLE_FILE_INFORMATION fi; DWORD nBytesRead = 0; @@ -3116,7 +3318,7 @@ static BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFi * 0 on failure * */ -static BOOL FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType) +static BOOL FTP_SendRetrieve(ftp_session_t *lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType) { INT nResCode; BOOL ret; @@ -3162,7 +3364,7 @@ lend: * FALSE on failure * */ -static BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile) +static BOOL FTP_RetrieveFileData(ftp_session_t *lpwfs, INT nDataSocket, HANDLE hFile) { DWORD nBytesWritten; INT nRC = 0; @@ -3202,7 +3404,7 @@ recv_end: * * Deallocate session handle */ -static void FTPFINDNEXT_Destroy(WININETHANDLEHEADER *hdr) +static void FTPFINDNEXT_Destroy(object_header_t *hdr) { LPWININETFTPFINDNEXTW lpwfn = (LPWININETFTPFINDNEXTW) hdr; DWORD i; @@ -3220,7 +3422,7 @@ static void FTPFINDNEXT_Destroy(WININETHANDLEHEADER *hdr) HeapFree(GetProcessHeap(), 0, lpwfn); } -static DWORD WINAPI FTPFINDNEXT_FindNextFileProc(WININETFTPFINDNEXTW *find, LPVOID data) +static DWORD FTPFINDNEXT_FindNextFileProc(WININETFTPFINDNEXTW *find, LPVOID data) { WIN32_FIND_DATAW *find_data = data; DWORD res = ERROR_SUCCESS; @@ -3260,7 +3462,7 @@ static void FTPFINDNEXT_AsyncFindNextFileProc(WORKREQUEST *workRequest) FTPFINDNEXT_FindNextFileProc((WININETFTPFINDNEXTW*)workRequest->hdr, req->lpFindFileData); } -static DWORD FTPFINDNEXT_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) +static DWORD FTPFINDNEXT_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) { switch(option) { case INTERNET_OPTION_HANDLE_TYPE: @@ -3277,7 +3479,7 @@ static DWORD FTPFINDNEXT_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, voi return INET_QueryOption(option, buffer, size, unicode); } -static DWORD FTPFINDNEXT_FindNextFileW(WININETHANDLEHEADER *hdr, void *data) +static DWORD FTPFINDNEXT_FindNextFileW(object_header_t *hdr, void *data) { WININETFTPFINDNEXTW *find = (WININETFTPFINDNEXTW*)hdr; @@ -3299,7 +3501,7 @@ static DWORD FTPFINDNEXT_FindNextFileW(WININETHANDLEHEADER *hdr, void *data) return FTPFINDNEXT_FindNextFileProc(find, data); } -static const HANDLEHEADERVtbl FTPFINDNEXTVtbl = { +static const object_vtbl_t FTPFINDNEXTVtbl = { FTPFINDNEXT_Destroy, NULL, FTPFINDNEXT_QueryOption, @@ -3308,6 +3510,7 @@ static const HANDLEHEADERVtbl FTPFINDNEXTVtbl = { NULL, NULL, NULL, + NULL, FTPFINDNEXT_FindNextFileW }; @@ -3321,7 +3524,7 @@ static const HANDLEHEADERVtbl FTPFINDNEXTVtbl = { * NULL on failure * */ -static HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile, +static HINTERNET FTP_ReceiveFileList(ftp_session_t *lpwfs, INT nSocket, LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD_PTR dwContext) { DWORD dwSize = 0; @@ -3382,9 +3585,7 @@ static BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFi if (lpafp) { - /* Convert 'Unix' time to Windows time */ - RtlSecondsSince1970ToTime(mktime(&lpafp->tmLastModified), - (LARGE_INTEGER *) &(lpFindFileData->ftLastAccessTime)); + SystemTimeToFileTime( &lpafp->tmLastModified, &lpFindFileData->ftLastAccessTime ); lpFindFileData->ftLastWriteTime = lpFindFileData->ftLastAccessTime; lpFindFileData->ftCreationTime = lpFindFileData->ftLastAccessTime; @@ -3452,12 +3653,12 @@ static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERT lpfp->nSize = atol(pszToken); } - lpfp->tmLastModified.tm_sec = 0; - lpfp->tmLastModified.tm_min = 0; - lpfp->tmLastModified.tm_hour = 0; - lpfp->tmLastModified.tm_mday = 0; - lpfp->tmLastModified.tm_mon = 0; - lpfp->tmLastModified.tm_year = 0; + lpfp->tmLastModified.wSecond = 0; + lpfp->tmLastModified.wMinute = 0; + lpfp->tmLastModified.wHour = 0; + lpfp->tmLastModified.wDay = 0; + lpfp->tmLastModified.wMonth = 0; + lpfp->tmLastModified.wYear = 0; /* Determine month */ pszToken = strtok(NULL, szSpace); @@ -3465,38 +3666,35 @@ static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERT if(strlen(pszToken) >= 3) { pszToken[3] = 0; if((pszTmp = StrStrIA(szMonths, pszToken))) - lpfp->tmLastModified.tm_mon = ((pszTmp - szMonths) / 3)+1; + lpfp->tmLastModified.wMonth = ((pszTmp - szMonths) / 3)+1; } /* Determine day */ pszToken = strtok(NULL, szSpace); if(!pszToken) continue; - lpfp->tmLastModified.tm_mday = atoi(pszToken); + lpfp->tmLastModified.wDay = atoi(pszToken); /* Determine time or year */ pszToken = strtok(NULL, szSpace); if(!pszToken) continue; if((pszTmp = strchr(pszToken, ':'))) { - struct tm* apTM; - time_t aTime; + SYSTEMTIME curr_time; *pszTmp = 0; pszTmp++; - lpfp->tmLastModified.tm_min = atoi(pszTmp); - lpfp->tmLastModified.tm_hour = atoi(pszToken); - time(&aTime); - apTM = localtime(&aTime); - lpfp->tmLastModified.tm_year = apTM->tm_year; + lpfp->tmLastModified.wMinute = atoi(pszTmp); + lpfp->tmLastModified.wHour = atoi(pszToken); + GetLocalTime( &curr_time ); + lpfp->tmLastModified.wYear = curr_time.wYear; } else { - lpfp->tmLastModified.tm_year = atoi(pszToken) - 1900; - lpfp->tmLastModified.tm_hour = 12; + lpfp->tmLastModified.wYear = atoi(pszToken); + lpfp->tmLastModified.wHour = 12; } - TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n", - lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec, - (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year, - lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday); + TRACE("Mod time: %02d:%02d:%02d %04d/%02d/%02d\n", + lpfp->tmLastModified.wHour, lpfp->tmLastModified.wMinute, lpfp->tmLastModified.wSecond, + lpfp->tmLastModified.wYear, lpfp->tmLastModified.wMonth, lpfp->tmLastModified.wDay); pszToken = strtok(NULL, szSpace); if(!pszToken) continue; - lpfp->lpszName = WININET_strdup_AtoW(pszToken); + lpfp->lpszName = heap_strdupAtoW(pszToken); TRACE("File: %s\n", debugstr_w(lpfp->lpszName)); } /* NT way of parsing ... : @@ -3505,32 +3703,31 @@ static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERT 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz */ else if(isdigit(pszToken[0]) && 8 == strlen(pszToken)) { + int mon, mday, year, hour, min; lpfp->permissions = 0xFFFF; /* No idea, put full permission :-) */ - sscanf(pszToken, "%d-%d-%d", - &lpfp->tmLastModified.tm_mon, - &lpfp->tmLastModified.tm_mday, - &lpfp->tmLastModified.tm_year); + sscanf(pszToken, "%d-%d-%d", &mon, &mday, &year); + lpfp->tmLastModified.wDay = mday; + lpfp->tmLastModified.wMonth = mon; + lpfp->tmLastModified.wYear = year; /* Hacky and bad Y2K protection :-) */ - if (lpfp->tmLastModified.tm_year < 70) - lpfp->tmLastModified.tm_year += 100; - + if (lpfp->tmLastModified.wYear < 70) lpfp->tmLastModified.wYear += 2000; + pszToken = strtok(NULL, szSpace); if(!pszToken) continue; - sscanf(pszToken, "%d:%d", - &lpfp->tmLastModified.tm_hour, - &lpfp->tmLastModified.tm_min); + sscanf(pszToken, "%d:%d", &hour, &min); + lpfp->tmLastModified.wHour = hour; + lpfp->tmLastModified.wMinute = min; if((pszToken[5] == 'P') && (pszToken[6] == 'M')) { - lpfp->tmLastModified.tm_hour += 12; + lpfp->tmLastModified.wHour += 12; } - lpfp->tmLastModified.tm_sec = 0; + lpfp->tmLastModified.wSecond = 0; + + TRACE("Mod time: %02d:%02d:%02d %04d/%02d/%02d\n", + lpfp->tmLastModified.wHour, lpfp->tmLastModified.wMinute, lpfp->tmLastModified.wSecond, + lpfp->tmLastModified.wYear, lpfp->tmLastModified.wMonth, lpfp->tmLastModified.wDay); - TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n", - lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec, - (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year, - lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday); - pszToken = strtok(NULL, szSpace); if(!pszToken) continue; if(!strcasecmp(pszToken, "")) { @@ -3546,7 +3743,7 @@ static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERT pszToken = strtok(NULL, szSpace); if(!pszToken) continue; - lpfp->lpszName = WININET_strdup_AtoW(pszToken); + lpfp->lpszName = heap_strdupAtoW(pszToken); TRACE("Name: %s\n", debugstr_w(lpfp->lpszName)); } /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */ @@ -3578,7 +3775,7 @@ static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERT * TRUE on success * FALSE on failure */ -static BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile, +static BOOL FTP_ParseDirectory(ftp_session_t *lpwfs, INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW *lpafp, LPDWORD dwfp) { BOOL bSuccess = TRUE; diff --git a/dll/win32/wininet/http.c b/dll/win32/wininet/http.c index f0ad6beddc1..5b7459db6f7 100644 --- a/dll/win32/wininet/http.c +++ b/dll/win32/wininet/http.c @@ -29,6 +29,10 @@ #include "config.h" #include "wine/port.h" +#if defined(__MINGW32__) || defined (_MSC_VER) +#include +#endif + #include #ifdef HAVE_SYS_SOCKET_H # include @@ -44,6 +48,9 @@ #endif #include #include +#ifdef HAVE_ZLIB +# include +#endif #include "windef.h" #include "winbase.h" @@ -59,6 +66,7 @@ #include "internet.h" #include "wine/debug.h" +#include "wine/exception.h" #include "wine/unicode.h" #include "inet_ntop.c" @@ -67,23 +75,77 @@ WINE_DEFAULT_DEBUG_CHANNEL(wininet); static const WCHAR g_szHttp1_0[] = {'H','T','T','P','/','1','.','0',0}; static const WCHAR g_szHttp1_1[] = {'H','T','T','P','/','1','.','1',0}; -static const WCHAR g_szReferer[] = {'R','e','f','e','r','e','r',0}; -static const WCHAR g_szAccept[] = {'A','c','c','e','p','t',0}; -static const WCHAR g_szUserAgent[] = {'U','s','e','r','-','A','g','e','n','t',0}; -static const WCHAR szHost[] = { 'H','o','s','t',0 }; +static const WCHAR szOK[] = {'O','K',0}; +static const WCHAR szDefaultHeader[] = {'H','T','T','P','/','1','.','0',' ','2','0','0',' ','O','K',0}; +static const WCHAR hostW[] = { 'H','o','s','t',0 }; static const WCHAR szAuthorization[] = { 'A','u','t','h','o','r','i','z','a','t','i','o','n',0 }; static const WCHAR szProxy_Authorization[] = { 'P','r','o','x','y','-','A','u','t','h','o','r','i','z','a','t','i','o','n',0 }; static const WCHAR szStatus[] = { 'S','t','a','t','u','s',0 }; static const WCHAR szKeepAlive[] = {'K','e','e','p','-','A','l','i','v','e',0}; static const WCHAR szGET[] = { 'G','E','T', 0 }; +static const WCHAR szHEAD[] = { 'H','E','A','D', 0 }; +static const WCHAR szCrLf[] = {'\r','\n', 0}; + +static const WCHAR szAccept[] = { 'A','c','c','e','p','t',0 }; +static const WCHAR szAccept_Charset[] = { 'A','c','c','e','p','t','-','C','h','a','r','s','e','t', 0 }; +static const WCHAR szAccept_Encoding[] = { 'A','c','c','e','p','t','-','E','n','c','o','d','i','n','g',0 }; +static const WCHAR szAccept_Language[] = { 'A','c','c','e','p','t','-','L','a','n','g','u','a','g','e',0 }; +static const WCHAR szAccept_Ranges[] = { 'A','c','c','e','p','t','-','R','a','n','g','e','s',0 }; +static const WCHAR szAge[] = { 'A','g','e',0 }; +static const WCHAR szAllow[] = { 'A','l','l','o','w',0 }; +static const WCHAR szCache_Control[] = { 'C','a','c','h','e','-','C','o','n','t','r','o','l',0 }; +static const WCHAR szConnection[] = { 'C','o','n','n','e','c','t','i','o','n',0 }; +static const WCHAR szContent_Base[] = { 'C','o','n','t','e','n','t','-','B','a','s','e',0 }; +static const WCHAR szContent_Encoding[] = { 'C','o','n','t','e','n','t','-','E','n','c','o','d','i','n','g',0 }; +static const WCHAR szContent_ID[] = { 'C','o','n','t','e','n','t','-','I','D',0 }; +static const WCHAR szContent_Language[] = { 'C','o','n','t','e','n','t','-','L','a','n','g','u','a','g','e',0 }; +static const WCHAR szContent_Length[] = { 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',0 }; +static const WCHAR szContent_Location[] = { 'C','o','n','t','e','n','t','-','L','o','c','a','t','i','o','n',0 }; +static const WCHAR szContent_MD5[] = { 'C','o','n','t','e','n','t','-','M','D','5',0 }; +static const WCHAR szContent_Range[] = { 'C','o','n','t','e','n','t','-','R','a','n','g','e',0 }; +static const WCHAR szContent_Transfer_Encoding[] = { 'C','o','n','t','e','n','t','-','T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0 }; +static const WCHAR szContent_Type[] = { 'C','o','n','t','e','n','t','-','T','y','p','e',0 }; +static const WCHAR szCookie[] = { 'C','o','o','k','i','e',0 }; +static const WCHAR szDate[] = { 'D','a','t','e',0 }; +static const WCHAR szFrom[] = { 'F','r','o','m',0 }; +static const WCHAR szETag[] = { 'E','T','a','g',0 }; +static const WCHAR szExpect[] = { 'E','x','p','e','c','t',0 }; +static const WCHAR szExpires[] = { 'E','x','p','i','r','e','s',0 }; +static const WCHAR szIf_Match[] = { 'I','f','-','M','a','t','c','h',0 }; +static const WCHAR szIf_Modified_Since[] = { 'I','f','-','M','o','d','i','f','i','e','d','-','S','i','n','c','e',0 }; +static const WCHAR szIf_None_Match[] = { 'I','f','-','N','o','n','e','-','M','a','t','c','h',0 }; +static const WCHAR szIf_Range[] = { 'I','f','-','R','a','n','g','e',0 }; +static const WCHAR szIf_Unmodified_Since[] = { 'I','f','-','U','n','m','o','d','i','f','i','e','d','-','S','i','n','c','e',0 }; +static const WCHAR szLast_Modified[] = { 'L','a','s','t','-','M','o','d','i','f','i','e','d',0 }; +static const WCHAR szLocation[] = { 'L','o','c','a','t','i','o','n',0 }; +static const WCHAR szMax_Forwards[] = { 'M','a','x','-','F','o','r','w','a','r','d','s',0 }; +static const WCHAR szMime_Version[] = { 'M','i','m','e','-','V','e','r','s','i','o','n',0 }; +static const WCHAR szPragma[] = { 'P','r','a','g','m','a',0 }; +static const WCHAR szProxy_Authenticate[] = { 'P','r','o','x','y','-','A','u','t','h','e','n','t','i','c','a','t','e',0 }; +static const WCHAR szProxy_Connection[] = { 'P','r','o','x','y','-','C','o','n','n','e','c','t','i','o','n',0 }; +static const WCHAR szPublic[] = { 'P','u','b','l','i','c',0 }; +static const WCHAR szRange[] = { 'R','a','n','g','e',0 }; +static const WCHAR szReferer[] = { 'R','e','f','e','r','e','r',0 }; +static const WCHAR szRetry_After[] = { 'R','e','t','r','y','-','A','f','t','e','r',0 }; +static const WCHAR szServer[] = { 'S','e','r','v','e','r',0 }; +static const WCHAR szSet_Cookie[] = { 'S','e','t','-','C','o','o','k','i','e',0 }; +static const WCHAR szTransfer_Encoding[] = { 'T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0 }; +static const WCHAR szUnless_Modified_Since[] = { 'U','n','l','e','s','s','-','M','o','d','i','f','i','e','d','-','S','i','n','c','e',0 }; +static const WCHAR szUpgrade[] = { 'U','p','g','r','a','d','e',0 }; +static const WCHAR szURI[] = { 'U','R','I',0 }; +static const WCHAR szUser_Agent[] = { 'U','s','e','r','-','A','g','e','n','t',0 }; +static const WCHAR szVary[] = { 'V','a','r','y',0 }; +static const WCHAR szVia[] = { 'V','i','a',0 }; +static const WCHAR szWarning[] = { 'W','a','r','n','i','n','g',0 }; +static const WCHAR szWWW_Authenticate[] = { 'W','W','W','-','A','u','t','h','e','n','t','i','c','a','t','e',0 }; #define MAXHOSTNAME 100 #define MAX_FIELD_VALUE_LEN 256 #define MAX_FIELD_LEN 256 -#define HTTP_REFERER g_szReferer -#define HTTP_ACCEPT g_szAccept -#define HTTP_USERAGENT g_szUserAgent +#define HTTP_REFERER szReferer +#define HTTP_ACCEPT szAccept +#define HTTP_USERAGENT szUser_Agent #define HTTP_ADDHDR_FLAG_ADD 0x20000000 #define HTTP_ADDHDR_FLAG_ADD_IF_NEW 0x10000000 @@ -108,23 +170,54 @@ struct HttpAuthInfo BOOL finished; /* finished authenticating */ }; -static BOOL HTTP_OpenConnection(LPWININETHTTPREQW lpwhr); -static BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr, BOOL clear); -static BOOL HTTP_ProcessHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field, LPCWSTR value, DWORD dwModifier); -static LPWSTR * HTTP_InterpretHttpHeader(LPCWSTR buffer); -static BOOL HTTP_InsertCustomHeader(LPWININETHTTPREQW lpwhr, LPHTTPHEADERW lpHdr); -static INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQW lpwhr, LPCWSTR lpszField, INT index, BOOL Request); -static BOOL HTTP_DeleteCustomHeader(LPWININETHTTPREQW lpwhr, DWORD index); -static LPWSTR HTTP_build_req( LPCWSTR *list, int len ); -static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD - dwInfoLevel, LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD - lpdwIndex); -static BOOL HTTP_HandleRedirect(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl); -static UINT HTTP_DecodeBase64(LPCWSTR base64, LPSTR bin); -static BOOL HTTP_VerifyValidHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field); -static void HTTP_DrainContent(WININETHTTPREQW *req); -LPHTTPHEADERW HTTP_GetHeader(LPWININETHTTPREQW req, LPCWSTR head) +struct gzip_stream_t { +#ifdef HAVE_ZLIB + z_stream zstream; +#endif + BYTE buf[8192]; + DWORD buf_size; + DWORD buf_pos; + BOOL end_of_data; +}; + +typedef struct _authorizationData +{ + struct list entry; + + LPWSTR lpszwHost; + LPWSTR lpszwRealm; + LPSTR lpszAuthorization; + UINT AuthorizationLen; +} authorizationData; + +static struct list basicAuthorizationCache = LIST_INIT(basicAuthorizationCache); + +static CRITICAL_SECTION authcache_cs; +static CRITICAL_SECTION_DEBUG critsect_debug = +{ + 0, 0, &authcache_cs, + { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": authcache_cs") } +}; +static CRITICAL_SECTION authcache_cs = { &critsect_debug, -1, 0, 0, 0, 0 }; + +static DWORD HTTP_OpenConnection(http_request_t *req); +static BOOL HTTP_GetResponseHeaders(http_request_t *req, BOOL clear); +static DWORD HTTP_ProcessHeader(http_request_t *req, LPCWSTR field, LPCWSTR value, DWORD dwModifier); +static LPWSTR * HTTP_InterpretHttpHeader(LPCWSTR buffer); +static DWORD HTTP_InsertCustomHeader(http_request_t *req, LPHTTPHEADERW lpHdr); +static INT HTTP_GetCustomHeaderIndex(http_request_t *req, LPCWSTR lpszField, INT index, BOOL Request); +static BOOL HTTP_DeleteCustomHeader(http_request_t *req, DWORD index); +static LPWSTR HTTP_build_req( LPCWSTR *list, int len ); +static DWORD HTTP_HttpQueryInfoW(http_request_t*, DWORD, LPVOID, LPDWORD, LPDWORD); +static LPWSTR HTTP_GetRedirectURL(http_request_t *req, LPCWSTR lpszUrl); +static UINT HTTP_DecodeBase64(LPCWSTR base64, LPSTR bin); +static BOOL HTTP_VerifyValidHeader(http_request_t *req, LPCWSTR field); +static void HTTP_DrainContent(http_request_t *req); +static BOOL HTTP_FinishedReading(http_request_t *req); + +static LPHTTPHEADERW HTTP_GetHeader(http_request_t *req, LPCWSTR head) { int HeaderIndex = 0; HeaderIndex = HTTP_GetCustomHeaderIndex(req, head, 0, TRUE); @@ -134,6 +227,91 @@ LPHTTPHEADERW HTTP_GetHeader(LPWININETHTTPREQW req, LPCWSTR head) return &req->pCustHeaders[HeaderIndex]; } +#ifdef HAVE_ZLIB + +static voidpf wininet_zalloc(voidpf opaque, uInt items, uInt size) +{ + return HeapAlloc(GetProcessHeap(), 0, items*size); +} + +static void wininet_zfree(voidpf opaque, voidpf address) +{ + HeapFree(GetProcessHeap(), 0, address); +} + +static void init_gzip_stream(http_request_t *req) +{ + gzip_stream_t *gzip_stream; + int index, zres; + + gzip_stream = HeapAlloc(GetProcessHeap(), 0, sizeof(gzip_stream_t)); + gzip_stream->zstream.zalloc = wininet_zalloc; + gzip_stream->zstream.zfree = wininet_zfree; + gzip_stream->zstream.opaque = NULL; + gzip_stream->zstream.next_in = NULL; + gzip_stream->zstream.avail_in = 0; + gzip_stream->zstream.next_out = NULL; + gzip_stream->zstream.avail_out = 0; + gzip_stream->buf_pos = 0; + gzip_stream->buf_size = 0; + gzip_stream->end_of_data = FALSE; + + zres = inflateInit2(&gzip_stream->zstream, 0x1f); + if(zres != Z_OK) { + ERR("inflateInit failed: %d\n", zres); + HeapFree(GetProcessHeap(), 0, gzip_stream); + return; + } + + req->gzip_stream = gzip_stream; + + index = HTTP_GetCustomHeaderIndex(req, szContent_Length, 0, FALSE); + if(index != -1) + HTTP_DeleteCustomHeader(req, index); +} + +#else + +static void init_gzip_stream(http_request_t *req) +{ + ERR("gzip stream not supported, missing zlib.\n"); +} + +#endif + +/* set the request content length based on the headers */ +static DWORD set_content_length( http_request_t *lpwhr ) +{ + static const WCHAR szChunked[] = {'c','h','u','n','k','e','d',0}; + WCHAR encoding[20]; + DWORD size; + + size = sizeof(lpwhr->dwContentLength); + if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_CONTENT_LENGTH, + &lpwhr->dwContentLength, &size, NULL) != ERROR_SUCCESS) + lpwhr->dwContentLength = ~0u; + + size = sizeof(encoding); + if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_TRANSFER_ENCODING, encoding, &size, NULL) == ERROR_SUCCESS && + !strcmpiW(encoding, szChunked)) + { + lpwhr->dwContentLength = ~0u; + lpwhr->read_chunked = TRUE; + } + + if(lpwhr->decoding) { + int encoding_idx; + + static const WCHAR gzipW[] = {'g','z','i','p',0}; + + encoding_idx = HTTP_GetCustomHeaderIndex(lpwhr, szContent_Encoding, 0, FALSE); + if(encoding_idx != -1 && !strcmpiW(lpwhr->pCustHeaders[encoding_idx].lpszValue, gzipW)) + init_gzip_stream(lpwhr); + } + + return lpwhr->dwContentLength; +} + /*********************************************************************** * HTTP_Tokenize (internal) * @@ -146,21 +324,26 @@ static LPWSTR * HTTP_Tokenize(LPCWSTR string, LPCWSTR token_string) int i; LPCWSTR next_token; - /* empty string has no tokens */ - if (*string) - tokens++; - /* count tokens */ - for (i = 0; string[i]; i++) - if (!strncmpW(string+i, token_string, strlenW(token_string))) - { - DWORD j; + if (string) + { + /* empty string has no tokens */ + if (*string) tokens++; - /* we want to skip over separators, but not the null terminator */ - for (j = 0; j < strlenW(token_string) - 1; j++) - if (!string[i+j]) - break; - i += j; + /* count tokens */ + for (i = 0; string[i]; i++) + { + if (!strncmpW(string+i, token_string, strlenW(token_string))) + { + DWORD j; + tokens++; + /* we want to skip over separators, but not the null terminator */ + for (j = 0; j < strlenW(token_string) - 1; j++) + if (!string[i+j]) + break; + i += j; + } } + } /* add 1 for terminating NULL */ token_array = HeapAlloc(GetProcessHeap(), 0, (tokens+1) * sizeof(*token_array)); @@ -194,33 +377,14 @@ static void HTTP_FreeTokens(LPWSTR * token_array) HeapFree(GetProcessHeap(), 0, token_array); } -/* ********************************************************************** - * - * Helper functions for the HttpSendRequest(Ex) functions - * - */ -static void AsyncHttpSendRequestProc(WORKREQUEST *workRequest) -{ - struct WORKREQ_HTTPSENDREQUESTW const *req = &workRequest->u.HttpSendRequestW; - LPWININETHTTPREQW lpwhr = (LPWININETHTTPREQW) workRequest->hdr; - - TRACE("%p\n", lpwhr); - - HTTP_HttpSendRequestW(lpwhr, req->lpszHeader, - req->dwHeaderLength, req->lpOptional, req->dwOptionalLength, - req->dwContentLength, req->bEndRequest); - - HeapFree(GetProcessHeap(), 0, req->lpszHeader); -} - -static void HTTP_FixURL( LPWININETHTTPREQW lpwhr) +static void HTTP_FixURL(http_request_t *lpwhr) { static const WCHAR szSlash[] = { '/',0 }; static const WCHAR szHttp[] = { 'h','t','t','p',':','/','/', 0 }; /* If we don't have a path we set it to root */ if (NULL == lpwhr->lpszPath) - lpwhr->lpszPath = WININET_strdupW(szSlash); + lpwhr->lpszPath = heap_strdupW(szSlash); else /* remove \r and \n*/ { int nLen = strlenW(lpwhr->lpszPath); @@ -249,7 +413,7 @@ static void HTTP_FixURL( LPWININETHTTPREQW lpwhr) } } -static LPWSTR HTTP_BuildHeaderRequestString( LPWININETHTTPREQW lpwhr, LPCWSTR verb, LPCWSTR path, LPCWSTR version ) +static LPWSTR HTTP_BuildHeaderRequestString( http_request_t *lpwhr, LPCWSTR verb, LPCWSTR path, LPCWSTR version ) { LPWSTR requestString; DWORD len, n; @@ -258,7 +422,6 @@ static LPWSTR HTTP_BuildHeaderRequestString( LPWININETHTTPREQW lpwhr, LPCWSTR ve LPWSTR p; static const WCHAR szSpace[] = { ' ',0 }; - static const WCHAR szcrlf[] = {'\r','\n', 0}; static const WCHAR szColon[] = { ':',' ',0 }; static const WCHAR sztwocrlf[] = {'\r','\n','\r','\n', 0}; @@ -279,7 +442,7 @@ static LPWSTR HTTP_BuildHeaderRequestString( LPWININETHTTPREQW lpwhr, LPCWSTR ve { if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST) { - req[n++] = szcrlf; + req[n++] = szCrLf; req[n++] = lpwhr->pCustHeaders[i].lpszField; req[n++] = szColon; req[n++] = lpwhr->pCustHeaders[i].lpszValue; @@ -309,103 +472,176 @@ static LPWSTR HTTP_BuildHeaderRequestString( LPWININETHTTPREQW lpwhr, LPCWSTR ve return requestString; } -static void HTTP_ProcessCookies( LPWININETHTTPREQW lpwhr ) +static void HTTP_ProcessCookies( http_request_t *lpwhr ) { - static const WCHAR szSet_Cookie[] = { 'S','e','t','-','C','o','o','k','i','e',0 }; int HeaderIndex; + int numCookies = 0; LPHTTPHEADERW setCookieHeader; - HeaderIndex = HTTP_GetCustomHeaderIndex(lpwhr, szSet_Cookie, 0, FALSE); - if (HeaderIndex == -1) - return; - setCookieHeader = &lpwhr->pCustHeaders[HeaderIndex]; - - if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_COOKIES) && setCookieHeader->lpszValue) + while((HeaderIndex = HTTP_GetCustomHeaderIndex(lpwhr, szSet_Cookie, numCookies, FALSE)) != -1) { - int nPosStart = 0, nPosEnd = 0, len; - static const WCHAR szFmt[] = { 'h','t','t','p',':','/','/','%','s','/',0}; + setCookieHeader = &lpwhr->pCustHeaders[HeaderIndex]; - while (setCookieHeader->lpszValue[nPosEnd] != '\0') + if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_COOKIES) && setCookieHeader->lpszValue) { - LPWSTR buf_cookie, cookie_name, cookie_data; + int len; + static const WCHAR szFmt[] = { 'h','t','t','p',':','/','/','%','s','%','s',0}; LPWSTR buf_url; - LPWSTR domain = NULL; LPHTTPHEADERW Host; - int nEqualPos = 0; - while (setCookieHeader->lpszValue[nPosEnd] != ';' && setCookieHeader->lpszValue[nPosEnd] != ',' && - setCookieHeader->lpszValue[nPosEnd] != '\0') - { - nPosEnd++; - } - if (setCookieHeader->lpszValue[nPosEnd] == ';') - { - /* fixme: not case sensitive, strcasestr is gnu only */ - int nDomainPosEnd = 0; - int nDomainPosStart = 0, nDomainLength = 0; - static const WCHAR szDomain[] = {'d','o','m','a','i','n','=',0}; - LPWSTR lpszDomain = strstrW(&setCookieHeader->lpszValue[nPosEnd], szDomain); - if (lpszDomain) - { /* they have specified their own domain, lets use it */ - while (lpszDomain[nDomainPosEnd] != ';' && lpszDomain[nDomainPosEnd] != ',' && - lpszDomain[nDomainPosEnd] != '\0') - { - nDomainPosEnd++; - } - nDomainPosStart = strlenW(szDomain); - nDomainLength = (nDomainPosEnd - nDomainPosStart) + 1; - domain = HeapAlloc(GetProcessHeap(), 0, (nDomainLength + 1)*sizeof(WCHAR)); - lstrcpynW(domain, &lpszDomain[nDomainPosStart], nDomainLength + 1); - } - } - if (setCookieHeader->lpszValue[nPosEnd] == '\0') break; - buf_cookie = HeapAlloc(GetProcessHeap(), 0, ((nPosEnd - nPosStart) + 1)*sizeof(WCHAR)); - lstrcpynW(buf_cookie, &setCookieHeader->lpszValue[nPosStart], (nPosEnd - nPosStart) + 1); - TRACE("%s\n", debugstr_w(buf_cookie)); - while (buf_cookie[nEqualPos] != '=' && buf_cookie[nEqualPos] != '\0') - { - nEqualPos++; - } - if (buf_cookie[nEqualPos] == '\0' || buf_cookie[nEqualPos + 1] == '\0') - { - HeapFree(GetProcessHeap(), 0, buf_cookie); - break; - } - - cookie_name = HeapAlloc(GetProcessHeap(), 0, (nEqualPos + 1)*sizeof(WCHAR)); - lstrcpynW(cookie_name, buf_cookie, nEqualPos + 1); - cookie_data = &buf_cookie[nEqualPos + 1]; - - Host = HTTP_GetHeader(lpwhr,szHost); - len = lstrlenW((domain ? domain : (Host?Host->lpszValue:NULL))) + - strlenW(lpwhr->lpszPath) + 9; + Host = HTTP_GetHeader(lpwhr, hostW); + len = lstrlenW(Host->lpszValue) + 9 + lstrlenW(lpwhr->lpszPath); buf_url = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); - sprintfW(buf_url, szFmt, (domain ? domain : (Host?Host->lpszValue:NULL))); /* FIXME PATH!!! */ - InternetSetCookieW(buf_url, cookie_name, cookie_data); + sprintfW(buf_url, szFmt, Host->lpszValue, lpwhr->lpszPath); + InternetSetCookieW(buf_url, NULL, setCookieHeader->lpszValue); HeapFree(GetProcessHeap(), 0, buf_url); - HeapFree(GetProcessHeap(), 0, buf_cookie); - HeapFree(GetProcessHeap(), 0, cookie_name); - HeapFree(GetProcessHeap(), 0, domain); - nPosStart = nPosEnd; } + numCookies++; } } -static inline BOOL is_basic_auth_value( LPCWSTR pszAuthValue ) +static void strip_spaces(LPWSTR start) { - static const WCHAR szBasic[] = {'B','a','s','i','c'}; /* Note: not nul-terminated */ - return !strncmpiW(pszAuthValue, szBasic, ARRAYSIZE(szBasic)) && - ((pszAuthValue[ARRAYSIZE(szBasic)] == ' ') || !pszAuthValue[ARRAYSIZE(szBasic)]); + LPWSTR str = start; + LPWSTR end; + + while (*str == ' ' && *str != '\0') + str++; + + if (str != start) + memmove(start, str, sizeof(WCHAR) * (strlenW(str) + 1)); + + end = start + strlenW(start) - 1; + while (end >= start && *end == ' ') + { + *end = '\0'; + end--; + } } -static BOOL HTTP_DoAuthorization( LPWININETHTTPREQW lpwhr, LPCWSTR pszAuthValue, +static inline BOOL is_basic_auth_value( LPCWSTR pszAuthValue, LPWSTR *pszRealm ) +{ + static const WCHAR szBasic[] = {'B','a','s','i','c'}; /* Note: not nul-terminated */ + static const WCHAR szRealm[] = {'r','e','a','l','m'}; /* Note: not nul-terminated */ + BOOL is_basic; + is_basic = !strncmpiW(pszAuthValue, szBasic, ARRAYSIZE(szBasic)) && + ((pszAuthValue[ARRAYSIZE(szBasic)] == ' ') || !pszAuthValue[ARRAYSIZE(szBasic)]); + if (is_basic && pszRealm) + { + LPCWSTR token; + LPCWSTR ptr = &pszAuthValue[ARRAYSIZE(szBasic)]; + LPCWSTR realm; + ptr++; + *pszRealm=NULL; + token = strchrW(ptr,'='); + if (!token) + return TRUE; + realm = ptr; + while (*realm == ' ' && *realm != '\0') + realm++; + if(!strncmpiW(realm, szRealm, ARRAYSIZE(szRealm)) && + (realm[ARRAYSIZE(szRealm)] == ' ' || realm[ARRAYSIZE(szRealm)] == '=')) + { + token++; + while (*token == ' ' && *token != '\0') + token++; + if (*token == '\0') + return TRUE; + *pszRealm = heap_strdupW(token); + strip_spaces(*pszRealm); + } + } + + return is_basic; +} + +static void destroy_authinfo( struct HttpAuthInfo *authinfo ) +{ + if (!authinfo) return; + + if (SecIsValidHandle(&authinfo->ctx)) + DeleteSecurityContext(&authinfo->ctx); + if (SecIsValidHandle(&authinfo->cred)) + FreeCredentialsHandle(&authinfo->cred); + + HeapFree(GetProcessHeap(), 0, authinfo->auth_data); + HeapFree(GetProcessHeap(), 0, authinfo->scheme); + HeapFree(GetProcessHeap(), 0, authinfo); +} + +static UINT retrieve_cached_basic_authorization(LPWSTR host, LPWSTR realm, LPSTR *auth_data) +{ + authorizationData *ad; + UINT rc = 0; + + TRACE("Looking for authorization for %s:%s\n",debugstr_w(host),debugstr_w(realm)); + + EnterCriticalSection(&authcache_cs); + LIST_FOR_EACH_ENTRY(ad, &basicAuthorizationCache, authorizationData, entry) + { + if (!strcmpiW(host,ad->lpszwHost) && !strcmpW(realm,ad->lpszwRealm)) + { + TRACE("Authorization found in cache\n"); + *auth_data = HeapAlloc(GetProcessHeap(),0,ad->AuthorizationLen); + memcpy(*auth_data,ad->lpszAuthorization,ad->AuthorizationLen); + rc = ad->AuthorizationLen; + break; + } + } + LeaveCriticalSection(&authcache_cs); + return rc; +} + +static void cache_basic_authorization(LPWSTR host, LPWSTR realm, LPSTR auth_data, UINT auth_data_len) +{ + struct list *cursor; + authorizationData* ad = NULL; + + TRACE("caching authorization for %s:%s = %s\n",debugstr_w(host),debugstr_w(realm),debugstr_an(auth_data,auth_data_len)); + + EnterCriticalSection(&authcache_cs); + LIST_FOR_EACH(cursor, &basicAuthorizationCache) + { + authorizationData *check = LIST_ENTRY(cursor,authorizationData,entry); + if (!strcmpiW(host,check->lpszwHost) && !strcmpW(realm,check->lpszwRealm)) + { + ad = check; + break; + } + } + + if (ad) + { + TRACE("Found match in cache, replacing\n"); + HeapFree(GetProcessHeap(),0,ad->lpszAuthorization); + ad->lpszAuthorization = HeapAlloc(GetProcessHeap(),0,auth_data_len); + memcpy(ad->lpszAuthorization, auth_data, auth_data_len); + ad->AuthorizationLen = auth_data_len; + } + else + { + ad = HeapAlloc(GetProcessHeap(),0,sizeof(authorizationData)); + ad->lpszwHost = heap_strdupW(host); + ad->lpszwRealm = heap_strdupW(realm); + ad->lpszAuthorization = HeapAlloc(GetProcessHeap(),0,auth_data_len); + memcpy(ad->lpszAuthorization, auth_data, auth_data_len); + ad->AuthorizationLen = auth_data_len; + list_add_head(&basicAuthorizationCache,&ad->entry); + TRACE("authorization cached\n"); + } + LeaveCriticalSection(&authcache_cs); +} + +static BOOL HTTP_DoAuthorization( http_request_t *lpwhr, LPCWSTR pszAuthValue, struct HttpAuthInfo **ppAuthInfo, - LPWSTR domain_and_username, LPWSTR password ) + LPWSTR domain_and_username, LPWSTR password, + LPWSTR host ) { SECURITY_STATUS sec_status; struct HttpAuthInfo *pAuthInfo = *ppAuthInfo; BOOL first = FALSE; + LPWSTR szRealm = NULL; TRACE("%s\n", debugstr_w(pszAuthValue)); @@ -426,10 +662,10 @@ static BOOL HTTP_DoAuthorization( LPWININETHTTPREQW lpwhr, LPCWSTR pszAuthValue, pAuthInfo->auth_data_len = 0; pAuthInfo->finished = FALSE; - if (is_basic_auth_value(pszAuthValue)) + if (is_basic_auth_value(pszAuthValue,NULL)) { static const WCHAR szBasic[] = {'B','a','s','i','c',0}; - pAuthInfo->scheme = WININET_strdupW(szBasic); + pAuthInfo->scheme = heap_strdupW(szBasic); if (!pAuthInfo->scheme) { HeapFree(GetProcessHeap(), 0, pAuthInfo); @@ -441,7 +677,7 @@ static BOOL HTTP_DoAuthorization( LPWININETHTTPREQW lpwhr, LPCWSTR pszAuthValue, PVOID pAuthData; SEC_WINNT_AUTH_IDENTITY_W nt_auth_identity; - pAuthInfo->scheme = WININET_strdupW(pszAuthValue); + pAuthInfo->scheme = heap_strdupW(pszAuthValue); if (!pAuthInfo->scheme) { HeapFree(GetProcessHeap(), 0, pAuthInfo); @@ -513,33 +749,50 @@ static BOOL HTTP_DoAuthorization( LPWININETHTTPREQW lpwhr, LPCWSTR pszAuthValue, return FALSE; } - if (is_basic_auth_value(pszAuthValue)) + if (is_basic_auth_value(pszAuthValue,&szRealm)) { int userlen; int passlen; - char *auth_data; + char *auth_data = NULL; + UINT auth_data_len = 0; - TRACE("basic authentication\n"); + TRACE("basic authentication realm %s\n",debugstr_w(szRealm)); - /* we don't cache credentials for basic authentication, so we can't - * retrieve them if the application didn't pass us any credentials */ - if (!domain_and_username) return FALSE; + if (!domain_and_username) + { + if (host && szRealm) + auth_data_len = retrieve_cached_basic_authorization(host, szRealm,&auth_data); + if (auth_data_len == 0) + { + HeapFree(GetProcessHeap(),0,szRealm); + return FALSE; + } + } + else + { + userlen = WideCharToMultiByte(CP_UTF8, 0, domain_and_username, lstrlenW(domain_and_username), NULL, 0, NULL, NULL); + passlen = WideCharToMultiByte(CP_UTF8, 0, password, lstrlenW(password), NULL, 0, NULL, NULL); - userlen = WideCharToMultiByte(CP_UTF8, 0, domain_and_username, lstrlenW(domain_and_username), NULL, 0, NULL, NULL); - passlen = WideCharToMultiByte(CP_UTF8, 0, password, lstrlenW(password), NULL, 0, NULL, NULL); + /* length includes a nul terminator, which will be re-used for the ':' */ + auth_data = HeapAlloc(GetProcessHeap(), 0, userlen + 1 + passlen); + if (!auth_data) + { + HeapFree(GetProcessHeap(),0,szRealm); + return FALSE; + } - /* length includes a nul terminator, which will be re-used for the ':' */ - auth_data = HeapAlloc(GetProcessHeap(), 0, userlen + 1 + passlen); - if (!auth_data) - return FALSE; - - WideCharToMultiByte(CP_UTF8, 0, domain_and_username, -1, auth_data, userlen, NULL, NULL); - auth_data[userlen] = ':'; - WideCharToMultiByte(CP_UTF8, 0, password, -1, &auth_data[userlen+1], passlen, NULL, NULL); + WideCharToMultiByte(CP_UTF8, 0, domain_and_username, -1, auth_data, userlen, NULL, NULL); + auth_data[userlen] = ':'; + WideCharToMultiByte(CP_UTF8, 0, password, -1, &auth_data[userlen+1], passlen, NULL, NULL); + auth_data_len = userlen + 1 + passlen; + if (host && szRealm) + cache_basic_authorization(host, szRealm, auth_data, auth_data_len); + } pAuthInfo->auth_data = auth_data; - pAuthInfo->auth_data_len = userlen + 1 + passlen; + pAuthInfo->auth_data_len = auth_data_len; pAuthInfo->finished = TRUE; + HeapFree(GetProcessHeap(),0,szRealm); return TRUE; } @@ -602,8 +855,9 @@ static BOOL HTTP_DoAuthorization( LPWININETHTTPREQW lpwhr, LPCWSTR pszAuthValue, else { ERR("InitializeSecurityContextW returned error 0x%08x\n", sec_status); - pAuthInfo->finished = TRUE; HeapFree(GetProcessHeap(), 0, out.pvBuffer); + destroy_authinfo(pAuthInfo); + *ppAuthInfo = NULL; return FALSE; } } @@ -614,14 +868,13 @@ static BOOL HTTP_DoAuthorization( LPWININETHTTPREQW lpwhr, LPCWSTR pszAuthValue, /*********************************************************************** * HTTP_HttpAddRequestHeadersW (internal) */ -static BOOL WINAPI HTTP_HttpAddRequestHeadersW(LPWININETHTTPREQW lpwhr, +static DWORD HTTP_HttpAddRequestHeadersW(http_request_t *lpwhr, LPCWSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier) { LPWSTR lpszStart; LPWSTR lpszEnd; LPWSTR buffer; - BOOL bSuccess = FALSE; - DWORD len; + DWORD len, res = ERROR_HTTP_INVALID_HEADER; TRACE("copying header: %s\n", debugstr_wn(lpszHeader, dwHeaderLength)); @@ -642,7 +895,7 @@ static BOOL WINAPI HTTP_HttpAddRequestHeadersW(LPWININETHTTPREQW lpwhr, while (*lpszEnd != '\0') { - if (*lpszEnd == '\r' && *(lpszEnd + 1) == '\n') + if (*lpszEnd == '\r' || *lpszEnd == '\n') break; lpszEnd++; } @@ -650,28 +903,35 @@ static BOOL WINAPI HTTP_HttpAddRequestHeadersW(LPWININETHTTPREQW lpwhr, if (*lpszStart == '\0') break; - if (*lpszEnd == '\r') + if (*lpszEnd == '\r' || *lpszEnd == '\n') { *lpszEnd = '\0'; - lpszEnd += 2; /* Jump over \r\n */ + lpszEnd++; /* Jump over newline */ } TRACE("interpreting header %s\n", debugstr_w(lpszStart)); + if (*lpszStart == '\0') + { + /* Skip 0-length headers */ + lpszStart = lpszEnd; + res = ERROR_SUCCESS; + continue; + } pFieldAndValue = HTTP_InterpretHttpHeader(lpszStart); if (pFieldAndValue) { - bSuccess = HTTP_VerifyValidHeader(lpwhr, pFieldAndValue[0]); - if (bSuccess) - bSuccess = HTTP_ProcessHeader(lpwhr, pFieldAndValue[0], + res = HTTP_VerifyValidHeader(lpwhr, pFieldAndValue[0]); + if (res == ERROR_SUCCESS) + res = HTTP_ProcessHeader(lpwhr, pFieldAndValue[0], pFieldAndValue[1], dwModifier | HTTP_ADDHDR_FLAG_REQ); HTTP_FreeTokens(pFieldAndValue); } lpszStart = lpszEnd; - } while (bSuccess); + } while (res == ERROR_SUCCESS); HeapFree(GetProcessHeap(), 0, buffer); - return bSuccess; + return res; } /*********************************************************************** @@ -693,26 +953,23 @@ static BOOL WINAPI HTTP_HttpAddRequestHeadersW(LPWININETHTTPREQW lpwhr, BOOL WINAPI HttpAddRequestHeadersW(HINTERNET hHttpRequest, LPCWSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier) { - BOOL bSuccess = FALSE; - LPWININETHTTPREQW lpwhr; + http_request_t *lpwhr; + DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE; TRACE("%p, %s, %i, %i\n", hHttpRequest, debugstr_wn(lpszHeader, dwHeaderLength), dwHeaderLength, dwModifier); if (!lpszHeader) return TRUE; - lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hHttpRequest ); - if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ) - { - INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); - goto lend; - } - bSuccess = HTTP_HttpAddRequestHeadersW( lpwhr, lpszHeader, dwHeaderLength, dwModifier ); -lend: + lpwhr = (http_request_t*) WININET_GetObject( hHttpRequest ); + if (lpwhr && lpwhr->hdr.htype == WH_HHTTPREQ) + res = HTTP_HttpAddRequestHeadersW( lpwhr, lpszHeader, dwHeaderLength, dwModifier ); if( lpwhr ) WININET_Release( &lpwhr->hdr ); - return bSuccess; + if(res != ERROR_SUCCESS) + SetLastError(res); + return res == ERROR_SUCCESS; } /*********************************************************************** @@ -747,208 +1004,6 @@ BOOL WINAPI HttpAddRequestHeadersA(HINTERNET hHttpRequest, return r; } -/*********************************************************************** - * HttpEndRequestA (WININET.@) - * - * Ends an HTTP request that was started by HttpSendRequestEx - * - * RETURNS - * TRUE if successful - * FALSE on failure - * - */ -BOOL WINAPI HttpEndRequestA(HINTERNET hRequest, - LPINTERNET_BUFFERSA lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext) -{ - LPINTERNET_BUFFERSA ptr; - LPINTERNET_BUFFERSW lpBuffersOutW,ptrW; - BOOL rc = FALSE; - - TRACE("(%p, %p, %08x, %08lx): stub\n", hRequest, lpBuffersOut, dwFlags, - dwContext); - - ptr = lpBuffersOut; - if (ptr) - lpBuffersOutW = (LPINTERNET_BUFFERSW)HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, sizeof(INTERNET_BUFFERSW)); - else - lpBuffersOutW = NULL; - - ptrW = lpBuffersOutW; - while (ptr) - { - if (ptr->lpvBuffer && ptr->dwBufferLength) - ptrW->lpvBuffer = HeapAlloc(GetProcessHeap(),0,ptr->dwBufferLength); - ptrW->dwBufferLength = ptr->dwBufferLength; - ptrW->dwBufferTotal= ptr->dwBufferTotal; - - if (ptr->Next) - ptrW->Next = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, - sizeof(INTERNET_BUFFERSW)); - - ptr = ptr->Next; - ptrW = ptrW->Next; - } - - rc = HttpEndRequestW(hRequest, lpBuffersOutW, dwFlags, dwContext); - - if (lpBuffersOutW) - { - ptrW = lpBuffersOutW; - while (ptrW) - { - LPINTERNET_BUFFERSW ptrW2; - - FIXME("Do we need to translate info out of these buffer?\n"); - - HeapFree(GetProcessHeap(),0,ptrW->lpvBuffer); - ptrW2 = ptrW->Next; - HeapFree(GetProcessHeap(),0,ptrW); - ptrW = ptrW2; - } - } - - return rc; -} - -/*********************************************************************** - * HttpEndRequestW (WININET.@) - * - * Ends an HTTP request that was started by HttpSendRequestEx - * - * RETURNS - * TRUE if successful - * FALSE on failure - * - */ -BOOL WINAPI HttpEndRequestW(HINTERNET hRequest, - LPINTERNET_BUFFERSW lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext) -{ - BOOL rc = FALSE; - LPWININETHTTPREQW lpwhr; - INT responseLen; - DWORD dwBufferSize; - - TRACE("-->\n"); - lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hRequest ); - - if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ) - { - INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); - if (lpwhr) - WININET_Release( &lpwhr->hdr ); - return FALSE; - } - - lpwhr->hdr.dwFlags |= dwFlags; - lpwhr->hdr.dwContext = dwContext; - - /* We appear to do nothing with lpBuffersOut.. is that correct? */ - - SendAsyncCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, - INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0); - - responseLen = HTTP_GetResponseHeaders(lpwhr, TRUE); - if (responseLen) - rc = TRUE; - - SendAsyncCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, - INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen, sizeof(DWORD)); - - /* process cookies here. Is this right? */ - HTTP_ProcessCookies(lpwhr); - - dwBufferSize = sizeof(lpwhr->dwContentLength); - if (!HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_CONTENT_LENGTH, - &lpwhr->dwContentLength,&dwBufferSize,NULL)) - lpwhr->dwContentLength = -1; - - if (lpwhr->dwContentLength == 0) - HTTP_FinishedReading(lpwhr); - - if(!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT)) - { - DWORD dwCode,dwCodeLength=sizeof(DWORD); - if(HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE,&dwCode,&dwCodeLength,NULL) && - (dwCode==302 || dwCode==301)) - { - WCHAR szNewLocation[INTERNET_MAX_URL_LENGTH]; - dwBufferSize=sizeof(szNewLocation); - if(HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_LOCATION,szNewLocation,&dwBufferSize,NULL)) - { - /* redirects are always GETs */ - HeapFree(GetProcessHeap(),0,lpwhr->lpszVerb); - lpwhr->lpszVerb = WININET_strdupW(szGET); - HTTP_DrainContent(lpwhr); - INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, - INTERNET_STATUS_REDIRECT, szNewLocation, - dwBufferSize); - rc = HTTP_HandleRedirect(lpwhr, szNewLocation); - if (rc) - rc = HTTP_HttpSendRequestW(lpwhr, NULL, 0, NULL, 0, 0, TRUE); - } - } - } - - WININET_Release( &lpwhr->hdr ); - TRACE("%i <--\n",rc); - return rc; -} - -/*********************************************************************** - * HttpOpenRequestW (WININET.@) - * - * Open a HTTP request handle - * - * RETURNS - * HINTERNET a HTTP request handle on success - * NULL on failure - * - */ -HINTERNET WINAPI HttpOpenRequestW(HINTERNET hHttpSession, - LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion, - LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes, - DWORD dwFlags, DWORD_PTR dwContext) -{ - LPWININETHTTPSESSIONW lpwhs; - HINTERNET handle = NULL; - - TRACE("(%p, %s, %s, %s, %s, %p, %08x, %08lx)\n", hHttpSession, - debugstr_w(lpszVerb), debugstr_w(lpszObjectName), - debugstr_w(lpszVersion), debugstr_w(lpszReferrer), lpszAcceptTypes, - dwFlags, dwContext); - if(lpszAcceptTypes!=NULL) - { - int i; - for(i=0;lpszAcceptTypes[i]!=NULL;i++) - TRACE("\taccept type: %s\n",debugstr_w(lpszAcceptTypes[i])); - } - - lpwhs = (LPWININETHTTPSESSIONW) WININET_GetObject( hHttpSession ); - if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION) - { - INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); - goto lend; - } - - /* - * My tests seem to show that the windows version does not - * become asynchronous until after this point. And anyhow - * if this call was asynchronous then how would you get the - * necessary HINTERNET pointer returned by this function. - * - */ - handle = HTTP_HttpOpenRequestW(lpwhs, lpszVerb, lpszObjectName, - lpszVersion, lpszReferrer, lpszAcceptTypes, - dwFlags, dwContext); -lend: - if( lpwhs ) - WININET_Release( &lpwhs->hdr ); - TRACE("returning %p\n", handle); - return handle; -} - - /*********************************************************************** * HttpOpenRequestA (WININET.@) * @@ -966,7 +1021,7 @@ HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession, { LPWSTR szVerb = NULL, szObjectName = NULL; LPWSTR szVersion = NULL, szReferrer = NULL, *szAcceptTypes = NULL; - INT len, acceptTypesCount; + INT acceptTypesCount; HINTERNET rc = FALSE; LPCSTR *types; @@ -977,38 +1032,30 @@ HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession, if (lpszVerb) { - len = MultiByteToWideChar(CP_ACP, 0, lpszVerb, -1, NULL, 0 ); - szVerb = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR) ); + szVerb = heap_strdupAtoW(lpszVerb); if ( !szVerb ) goto end; - MultiByteToWideChar(CP_ACP, 0, lpszVerb, -1, szVerb, len); } if (lpszObjectName) { - len = MultiByteToWideChar(CP_ACP, 0, lpszObjectName, -1, NULL, 0 ); - szObjectName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR) ); + szObjectName = heap_strdupAtoW(lpszObjectName); if ( !szObjectName ) goto end; - MultiByteToWideChar(CP_ACP, 0, lpszObjectName, -1, szObjectName, len ); } if (lpszVersion) { - len = MultiByteToWideChar(CP_ACP, 0, lpszVersion, -1, NULL, 0 ); - szVersion = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + szVersion = heap_strdupAtoW(lpszVersion); if ( !szVersion ) goto end; - MultiByteToWideChar(CP_ACP, 0, lpszVersion, -1, szVersion, len ); } if (lpszReferrer) { - len = MultiByteToWideChar(CP_ACP, 0, lpszReferrer, -1, NULL, 0 ); - szReferrer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + szReferrer = heap_strdupAtoW(lpszReferrer); if ( !szReferrer ) goto end; - MultiByteToWideChar(CP_ACP, 0, lpszReferrer, -1, szReferrer, len ); } if (lpszAcceptTypes) @@ -1017,12 +1064,20 @@ HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession, types = lpszAcceptTypes; while (*types) { - /* find out how many there are */ - if (((ULONG_PTR)*types >> 16) && **types) + __TRY { - TRACE("accept type: %s\n", debugstr_a(*types)); - acceptTypesCount++; + /* find out how many there are */ + if (*types && **types) + { + TRACE("accept type: %s\n", debugstr_a(*types)); + acceptTypesCount++; + } } + __EXCEPT_PAGE_FAULT + { + WARN("invalid accept type pointer\n"); + } + __ENDTRY; types++; } szAcceptTypes = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR *) * (acceptTypesCount+1)); @@ -1032,20 +1087,20 @@ HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession, types = lpszAcceptTypes; while (*types) { - if (((ULONG_PTR)*types >> 16) && **types) + __TRY { - len = MultiByteToWideChar(CP_ACP, 0, *types, -1, NULL, 0 ); - szAcceptTypes[acceptTypesCount] = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); - if (!szAcceptTypes[acceptTypesCount]) goto end; - - MultiByteToWideChar(CP_ACP, 0, *types, -1, szAcceptTypes[acceptTypesCount], len); - acceptTypesCount++; + if (*types && **types) + szAcceptTypes[acceptTypesCount++] = heap_strdupAtoW(*types); } + __EXCEPT_PAGE_FAULT + { + /* ignore invalid pointer */ + } + __ENDTRY; types++; } szAcceptTypes[acceptTypesCount] = NULL; } - else szAcceptTypes = 0; rc = HttpOpenRequestW(hHttpSession, szVerb, szObjectName, szVersion, szReferrer, @@ -1207,7 +1262,7 @@ static UINT HTTP_DecodeBase64( LPCWSTR base64, LPSTR bin ) * * Insert or delete the authorization field in the request header. */ -static BOOL HTTP_InsertAuthorization( LPWININETHTTPREQW lpwhr, struct HttpAuthInfo *pAuthInfo, LPCWSTR header ) +static BOOL HTTP_InsertAuthorization( http_request_t *lpwhr, struct HttpAuthInfo *pAuthInfo, LPCWSTR header ) { if (pAuthInfo) { @@ -1250,13 +1305,13 @@ static BOOL HTTP_InsertAuthorization( LPWININETHTTPREQW lpwhr, struct HttpAuthIn return TRUE; } -static WCHAR *HTTP_BuildProxyRequestUrl(WININETHTTPREQW *req) +static WCHAR *HTTP_BuildProxyRequestUrl(http_request_t *req) { WCHAR new_location[INTERNET_MAX_URL_LENGTH], *url; DWORD size; size = sizeof(new_location); - if (HTTP_HttpQueryInfoW(req, HTTP_QUERY_LOCATION, new_location, &size, NULL)) + if (HTTP_HttpQueryInfoW(req, HTTP_QUERY_LOCATION, new_location, &size, NULL) == ERROR_SUCCESS) { if (!(url = HeapAlloc( GetProcessHeap(), 0, size + sizeof(WCHAR) ))) return NULL; strcpyW( url, new_location ); @@ -1266,7 +1321,7 @@ static WCHAR *HTTP_BuildProxyRequestUrl(WININETHTTPREQW *req) static const WCHAR slash[] = { '/',0 }; static const WCHAR format[] = { 'h','t','t','p',':','/','/','%','s',':','%','d',0 }; static const WCHAR formatSSL[] = { 'h','t','t','p','s',':','/','/','%','s',':','%','d',0 }; - WININETHTTPSESSIONW *session = req->lpHttpSession; + http_session_t *session = req->lpHttpSession; size = 16; /* "https://" + sizeof(port#) + ":/\0" */ size += strlenW( session->lpszHostName ) + strlenW( req->lpszPath ); @@ -1287,8 +1342,7 @@ static WCHAR *HTTP_BuildProxyRequestUrl(WININETHTTPREQW *req) /*********************************************************************** * HTTP_DealWithProxy */ -static BOOL HTTP_DealWithProxy( LPWININETAPPINFOW hIC, - LPWININETHTTPSESSIONW lpwhs, LPWININETHTTPREQW lpwhr) +static BOOL HTTP_DealWithProxy(appinfo_t *hIC, http_session_t *lpwhs, http_request_t *lpwhr) { WCHAR buf[MAXHOSTNAME]; WCHAR proxy[MAXHOSTNAME + 15]; /* 15 == "http://" + sizeof(port#) + ":/\0" */ @@ -1319,38 +1373,52 @@ static BOOL HTTP_DealWithProxy( LPWININETAPPINFOW hIC, UrlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT; HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName); - lpwhs->lpszServerName = WININET_strdupW(UrlComponents.lpszHostName); + lpwhs->lpszServerName = heap_strdupW(UrlComponents.lpszHostName); lpwhs->nServerPort = UrlComponents.nPort; TRACE("proxy server=%s port=%d\n", debugstr_w(lpwhs->lpszServerName), lpwhs->nServerPort); return TRUE; } -static BOOL HTTP_ResolveName(LPWININETHTTPREQW lpwhr) +#ifndef INET6_ADDRSTRLEN +#define INET6_ADDRSTRLEN 46 +#endif + +static DWORD HTTP_ResolveName(http_request_t *lpwhr) { - char szaddr[32]; - LPWININETHTTPSESSIONW lpwhs = lpwhr->lpHttpSession; + char szaddr[INET6_ADDRSTRLEN]; + http_session_t *lpwhs = lpwhr->lpHttpSession; + const void *addr; INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_RESOLVING_NAME, lpwhs->lpszServerName, - strlenW(lpwhs->lpszServerName)+1); + (strlenW(lpwhs->lpszServerName)+1) * sizeof(WCHAR)); + lpwhs->sa_len = sizeof(lpwhs->socketAddress); if (!GetAddress(lpwhs->lpszServerName, lpwhs->nServerPort, - &lpwhs->socketAddress)) - { - INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED); - return FALSE; - } + (struct sockaddr *)&lpwhs->socketAddress, &lpwhs->sa_len)) + return ERROR_INTERNET_NAME_NOT_RESOLVED; - inet_ntop(lpwhs->socketAddress.sin_family, &lpwhs->socketAddress.sin_addr, - szaddr, sizeof(szaddr)); + switch (lpwhs->socketAddress.ss_family) + { + case AF_INET: + addr = &((struct sockaddr_in *)&lpwhs->socketAddress)->sin_addr; + break; + case AF_INET6: + addr = &((struct sockaddr_in6 *)&lpwhs->socketAddress)->sin6_addr; + break; + default: + WARN("unsupported family %d\n", lpwhs->socketAddress.ss_family); + return ERROR_INTERNET_NAME_NOT_RESOLVED; + } + inet_ntop(lpwhs->socketAddress.ss_family, addr, szaddr, sizeof(szaddr)); INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_NAME_RESOLVED, szaddr, strlen(szaddr)+1); TRACE("resolved %s to %s\n", debugstr_w(lpwhs->lpszServerName), szaddr); - return TRUE; + return ERROR_SUCCESS; } @@ -1360,9 +1428,9 @@ static BOOL HTTP_ResolveName(LPWININETHTTPREQW lpwhr) * Deallocate request handle * */ -static void HTTPREQ_Destroy(WININETHANDLEHEADER *hdr) +static void HTTPREQ_Destroy(object_header_t *hdr) { - LPWININETHTTPREQW lpwhr = (LPWININETHTTPREQW) hdr; + http_request_t *lpwhr = (http_request_t*) hdr; DWORD i; TRACE("\n"); @@ -1370,13 +1438,14 @@ static void HTTPREQ_Destroy(WININETHANDLEHEADER *hdr) if(lpwhr->hCacheFile) CloseHandle(lpwhr->hCacheFile); - if(lpwhr->lpszCacheFile) { - DeleteFileW(lpwhr->lpszCacheFile); /* FIXME */ - HeapFree(GetProcessHeap(), 0, lpwhr->lpszCacheFile); - } + HeapFree(GetProcessHeap(), 0, lpwhr->lpszCacheFile); + DeleteCriticalSection( &lpwhr->read_section ); WININET_Release(&lpwhr->lpHttpSession->hdr); + destroy_authinfo(lpwhr->pAuthInfo); + destroy_authinfo(lpwhr->pProxyAuthInfo); + HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath); HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb); HeapFree(GetProcessHeap(), 0, lpwhr->lpszRawHeaders); @@ -1389,44 +1458,27 @@ static void HTTPREQ_Destroy(WININETHANDLEHEADER *hdr) HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszValue); } +#ifdef HAVE_ZLIB + if(lpwhr->gzip_stream) { + if(!lpwhr->gzip_stream->end_of_data) + inflateEnd(&lpwhr->gzip_stream->zstream); + HeapFree(GetProcessHeap(), 0, lpwhr->gzip_stream); + } +#endif + HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders); HeapFree(GetProcessHeap(), 0, lpwhr); } -static void HTTPREQ_CloseConnection(WININETHANDLEHEADER *hdr) +static void HTTPREQ_CloseConnection(object_header_t *hdr) { - LPWININETHTTPREQW lpwhr = (LPWININETHTTPREQW) hdr; + http_request_t *lpwhr = (http_request_t*) hdr; TRACE("%p\n",lpwhr); if (!NETCON_connected(&lpwhr->netConnection)) return; - if (lpwhr->pAuthInfo) - { - if (SecIsValidHandle(&lpwhr->pAuthInfo->ctx)) - DeleteSecurityContext(&lpwhr->pAuthInfo->ctx); - if (SecIsValidHandle(&lpwhr->pAuthInfo->cred)) - FreeCredentialsHandle(&lpwhr->pAuthInfo->cred); - - HeapFree(GetProcessHeap(), 0, lpwhr->pAuthInfo->auth_data); - HeapFree(GetProcessHeap(), 0, lpwhr->pAuthInfo->scheme); - HeapFree(GetProcessHeap(), 0, lpwhr->pAuthInfo); - lpwhr->pAuthInfo = NULL; - } - if (lpwhr->pProxyAuthInfo) - { - if (SecIsValidHandle(&lpwhr->pProxyAuthInfo->ctx)) - DeleteSecurityContext(&lpwhr->pProxyAuthInfo->ctx); - if (SecIsValidHandle(&lpwhr->pProxyAuthInfo->cred)) - FreeCredentialsHandle(&lpwhr->pProxyAuthInfo->cred); - - HeapFree(GetProcessHeap(), 0, lpwhr->pProxyAuthInfo->auth_data); - HeapFree(GetProcessHeap(), 0, lpwhr->pProxyAuthInfo->scheme); - HeapFree(GetProcessHeap(), 0, lpwhr->pProxyAuthInfo); - lpwhr->pProxyAuthInfo = NULL; - } - INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_CLOSING_CONNECTION, 0, 0); @@ -1436,11 +1488,95 @@ static void HTTPREQ_CloseConnection(WININETHANDLEHEADER *hdr) INTERNET_STATUS_CONNECTION_CLOSED, 0, 0); } -static DWORD HTTPREQ_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) +static BOOL HTTP_GetRequestURL(http_request_t *req, LPWSTR buf) { - WININETHTTPREQW *req = (WININETHTTPREQW*)hdr; + LPHTTPHEADERW host_header; + + static const WCHAR formatW[] = {'h','t','t','p',':','/','/','%','s','%','s',0}; + + host_header = HTTP_GetHeader(req, hostW); + if(!host_header) + return FALSE; + + sprintfW(buf, formatW, host_header->lpszValue, req->lpszPath); /* FIXME */ + return TRUE; +} + +static BOOL HTTP_KeepAlive(http_request_t *lpwhr) +{ + WCHAR szVersion[10]; + WCHAR szConnectionResponse[20]; + DWORD dwBufferSize = sizeof(szVersion); + BOOL keepalive = FALSE; + + /* as per RFC 2068, S8.1.2.1, if the client is HTTP/1.1 then assume that + * the connection is keep-alive by default */ + if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_VERSION, szVersion, &dwBufferSize, NULL) == ERROR_SUCCESS + && !strcmpiW(szVersion, g_szHttp1_1)) + { + keepalive = TRUE; + } + + dwBufferSize = sizeof(szConnectionResponse); + if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_PROXY_CONNECTION, szConnectionResponse, &dwBufferSize, NULL) == ERROR_SUCCESS + || HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_CONNECTION, szConnectionResponse, &dwBufferSize, NULL) == ERROR_SUCCESS) + { + keepalive = !strcmpiW(szConnectionResponse, szKeepAlive); + } + + return keepalive; +} + +static DWORD HTTPREQ_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) +{ + http_request_t *req = (http_request_t*)hdr; switch(option) { + case INTERNET_OPTION_DIAGNOSTIC_SOCKET_INFO: + { + http_session_t *lpwhs = req->lpHttpSession; + INTERNET_DIAGNOSTIC_SOCKET_INFO *info = buffer; + + FIXME("INTERNET_DIAGNOSTIC_SOCKET_INFO stub\n"); + + if (*size < sizeof(INTERNET_DIAGNOSTIC_SOCKET_INFO)) + return ERROR_INSUFFICIENT_BUFFER; + *size = sizeof(INTERNET_DIAGNOSTIC_SOCKET_INFO); + /* FIXME: can't get a SOCKET from our connection since we don't use + * winsock + */ + info->Socket = 0; + /* FIXME: get source port from req->netConnection */ + info->SourcePort = 0; + info->DestPort = lpwhs->nHostPort; + info->Flags = 0; + if (HTTP_KeepAlive(req)) + info->Flags |= IDSI_FLAG_KEEP_ALIVE; + if (lpwhs->lpAppInfo->lpszProxy && lpwhs->lpAppInfo->lpszProxy[0] != 0) + info->Flags |= IDSI_FLAG_PROXY; + if (req->netConnection.useSSL) + info->Flags |= IDSI_FLAG_SECURE; + + return ERROR_SUCCESS; + } + + case INTERNET_OPTION_SECURITY_FLAGS: + { + http_session_t *lpwhs; + lpwhs = req->lpHttpSession; + + if (*size < sizeof(ULONG)) + return ERROR_INSUFFICIENT_BUFFER; + + *size = sizeof(DWORD); + if (lpwhs->hdr.dwFlags & INTERNET_FLAG_SECURE) + *(DWORD*)buffer = SECURITY_FLAG_SECURE; + else + *(DWORD*)buffer = 0; + FIXME("Semi-STUB INTERNET_OPTION_SECURITY_FLAGS: %x\n",*(DWORD*)buffer); + return ERROR_SUCCESS; + } + case INTERNET_OPTION_HANDLE_TYPE: TRACE("INTERNET_OPTION_HANDLE_TYPE\n"); @@ -1458,7 +1594,6 @@ static DWORD HTTPREQ_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *b WCHAR *pch; static const WCHAR httpW[] = {'h','t','t','p',':','/','/',0}; - static const WCHAR hostW[] = {'H','o','s','t',0}; TRACE("INTERNET_OPTION_URL\n"); @@ -1489,6 +1624,41 @@ static DWORD HTTPREQ_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *b } } + case INTERNET_OPTION_CACHE_TIMESTAMPS: { + INTERNET_CACHE_ENTRY_INFOW *info; + INTERNET_CACHE_TIMESTAMPS *ts = buffer; + WCHAR url[INTERNET_MAX_URL_LENGTH]; + DWORD nbytes, error; + BOOL ret; + + TRACE("INTERNET_OPTION_CACHE_TIMESTAMPS\n"); + + if (*size < sizeof(*ts)) + { + *size = sizeof(*ts); + return ERROR_INSUFFICIENT_BUFFER; + } + nbytes = 0; + HTTP_GetRequestURL(req, url); + ret = GetUrlCacheEntryInfoW(url, NULL, &nbytes); + error = GetLastError(); + if (!ret && error == ERROR_INSUFFICIENT_BUFFER) + { + if (!(info = HeapAlloc(GetProcessHeap(), 0, nbytes))) + return ERROR_OUTOFMEMORY; + + GetUrlCacheEntryInfoW(url, info, &nbytes); + + ts->ftExpires = info->ExpireTime; + ts->ftLastModified = info->LastModifiedTime; + + HeapFree(GetProcessHeap(), 0, info); + *size = sizeof(*ts); + return ERROR_SUCCESS; + } + return error; + } + case INTERNET_OPTION_DATAFILE_NAME: { DWORD req_size; @@ -1584,9 +1754,9 @@ static DWORD HTTPREQ_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *b return INET_QueryOption(option, buffer, size, unicode); } -static DWORD HTTPREQ_SetOption(WININETHANDLEHEADER *hdr, DWORD option, void *buffer, DWORD size) +static DWORD HTTPREQ_SetOption(object_header_t *hdr, DWORD option, void *buffer, DWORD size) { - WININETHTTPREQW *req = (WININETHTTPREQW*)hdr; + http_request_t *req = (http_request_t*)hdr; switch(option) { case INTERNET_OPTION_SEND_TIMEOUT: @@ -1598,30 +1768,340 @@ static DWORD HTTPREQ_SetOption(WININETHANDLEHEADER *hdr, DWORD option, void *buf return NETCON_set_timeout(&req->netConnection, option == INTERNET_OPTION_SEND_TIMEOUT, *(DWORD*)buffer); + + case INTERNET_OPTION_USERNAME: + HeapFree(GetProcessHeap(), 0, req->lpHttpSession->lpszUserName); + if (!(req->lpHttpSession->lpszUserName = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY; + return ERROR_SUCCESS; + + case INTERNET_OPTION_PASSWORD: + HeapFree(GetProcessHeap(), 0, req->lpHttpSession->lpszPassword); + if (!(req->lpHttpSession->lpszPassword = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY; + return ERROR_SUCCESS; + case INTERNET_OPTION_HTTP_DECODING: + if(size != sizeof(BOOL)) + return ERROR_INVALID_PARAMETER; + req->decoding = *(BOOL*)buffer; + return ERROR_SUCCESS; } return ERROR_INTERNET_INVALID_OPTION; } -static DWORD HTTP_Read(WININETHTTPREQW *req, void *buffer, DWORD size, DWORD *read, BOOL sync) +/* read some more data into the read buffer (the read section must be held) */ +static DWORD read_more_data( http_request_t *req, int maxlen ) { - int bytes_read; + DWORD res; + int len; - if(!NETCON_recv(&req->netConnection, buffer, min(size, req->dwContentLength - req->dwContentRead), - sync ? MSG_WAITALL : 0, &bytes_read)) { - if(req->dwContentLength != -1 && req->dwContentRead != req->dwContentLength) - ERR("not all data received %d/%d\n", req->dwContentRead, req->dwContentLength); - - /* always return success, even if the network layer returns an error */ - *read = 0; - HTTP_FinishedReading(req); - return ERROR_SUCCESS; + if (req->read_pos) + { + /* move existing data to the start of the buffer */ + if(req->read_size) + memmove( req->read_buf, req->read_buf + req->read_pos, req->read_size ); + req->read_pos = 0; } - req->dwContentRead += bytes_read; + if (maxlen == -1) maxlen = sizeof(req->read_buf); + + res = NETCON_recv( &req->netConnection, req->read_buf + req->read_size, + maxlen - req->read_size, 0, &len ); + if(res == ERROR_SUCCESS) + req->read_size += len; + + return res; +} + +/* remove some amount of data from the read buffer (the read section must be held) */ +static void remove_data( http_request_t *req, int count ) +{ + if (!(req->read_size -= count)) req->read_pos = 0; + else req->read_pos += count; +} + +static BOOL read_line( http_request_t *req, LPSTR buffer, DWORD *len ) +{ + int count, bytes_read, pos = 0; + DWORD res; + + EnterCriticalSection( &req->read_section ); + for (;;) + { + BYTE *eol = memchr( req->read_buf + req->read_pos, '\n', req->read_size ); + + if (eol) + { + count = eol - (req->read_buf + req->read_pos); + bytes_read = count + 1; + } + else count = bytes_read = req->read_size; + + count = min( count, *len - pos ); + memcpy( buffer + pos, req->read_buf + req->read_pos, count ); + pos += count; + remove_data( req, bytes_read ); + if (eol) break; + + if ((res = read_more_data( req, -1 )) != ERROR_SUCCESS || !req->read_size) + { + *len = 0; + TRACE( "returning empty string\n" ); + LeaveCriticalSection( &req->read_section ); + INTERNET_SetLastError(res); + return FALSE; + } + } + LeaveCriticalSection( &req->read_section ); + + if (pos < *len) + { + if (pos && buffer[pos - 1] == '\r') pos--; + *len = pos + 1; + } + buffer[*len - 1] = 0; + TRACE( "returning %s\n", debugstr_a(buffer)); + return TRUE; +} + +/* discard data contents until we reach end of line (the read section must be held) */ +static DWORD discard_eol( http_request_t *req ) +{ + DWORD res; + + do + { + BYTE *eol = memchr( req->read_buf + req->read_pos, '\n', req->read_size ); + if (eol) + { + remove_data( req, (eol + 1) - (req->read_buf + req->read_pos) ); + break; + } + req->read_pos = req->read_size = 0; /* discard everything */ + if ((res = read_more_data( req, -1 )) != ERROR_SUCCESS) return res; + } while (req->read_size); + return ERROR_SUCCESS; +} + +/* read the size of the next chunk (the read section must be held) */ +static DWORD start_next_chunk( http_request_t *req ) +{ + DWORD chunk_size = 0, res; + + if (!req->dwContentLength) return ERROR_SUCCESS; + if (req->dwContentLength == req->dwContentRead) + { + /* read terminator for the previous chunk */ + if ((res = discard_eol( req )) != ERROR_SUCCESS) return res; + req->dwContentLength = ~0u; + req->dwContentRead = 0; + } + for (;;) + { + while (req->read_size) + { + char ch = req->read_buf[req->read_pos]; + if (ch >= '0' && ch <= '9') chunk_size = chunk_size * 16 + ch - '0'; + else if (ch >= 'a' && ch <= 'f') chunk_size = chunk_size * 16 + ch - 'a' + 10; + else if (ch >= 'A' && ch <= 'F') chunk_size = chunk_size * 16 + ch - 'A' + 10; + else if (ch == ';' || ch == '\r' || ch == '\n') + { + TRACE( "reading %u byte chunk\n", chunk_size ); + req->dwContentLength = chunk_size; + req->dwContentRead = 0; + return discard_eol( req ); + } + remove_data( req, 1 ); + } + if ((res = read_more_data( req, -1 )) != ERROR_SUCCESS) return res; + if (!req->read_size) + { + req->dwContentLength = req->dwContentRead = 0; + return ERROR_SUCCESS; + } + } +} + +/* check if we have reached the end of the data to read (the read section must be held) */ +static BOOL end_of_read_data( http_request_t *req ) +{ + if (req->gzip_stream) return req->gzip_stream->end_of_data && !req->gzip_stream->buf_size; + if (req->read_chunked) return (req->dwContentLength == 0); + if (req->dwContentLength == ~0u) return FALSE; + return (req->dwContentLength == req->dwContentRead); +} + +/* fetch some more data into the read buffer (the read section must be held) */ +static DWORD refill_buffer( http_request_t *req ) +{ + int len = sizeof(req->read_buf); + DWORD res; + + if (req->read_chunked && (req->dwContentLength == ~0u || req->dwContentLength == req->dwContentRead)) + { + if ((res = start_next_chunk( req )) != ERROR_SUCCESS) return res; + } + + if (req->dwContentLength != ~0u) len = min( len, req->dwContentLength - req->dwContentRead ); + if (len <= req->read_size) return ERROR_SUCCESS; + + if ((res = read_more_data( req, len )) != ERROR_SUCCESS) return res; + if (!req->read_size) req->dwContentLength = req->dwContentRead = 0; + return ERROR_SUCCESS; +} + +static DWORD read_gzip_data(http_request_t *req, BYTE *buf, int size, BOOL sync, int *read_ret) +{ + DWORD ret = ERROR_SUCCESS; + int read = 0; + +#ifdef HAVE_ZLIB + z_stream *zstream = &req->gzip_stream->zstream; + DWORD buf_avail; + int zres; + + while(read < size && !req->gzip_stream->end_of_data) { + if(!req->read_size) { + if(!sync || refill_buffer(req) != ERROR_SUCCESS) + break; + } + + buf_avail = req->dwContentLength == ~0 ? req->read_size : min(req->read_size, req->dwContentLength-req->dwContentRead); + + zstream->next_in = req->read_buf+req->read_pos; + zstream->avail_in = buf_avail; + zstream->next_out = buf+read; + zstream->avail_out = size-read; + zres = inflate(zstream, Z_FULL_FLUSH); + read = size - zstream->avail_out; + req->dwContentRead += buf_avail-zstream->avail_in; + remove_data(req, buf_avail-zstream->avail_in); + if(zres == Z_STREAM_END) { + TRACE("end of data\n"); + req->gzip_stream->end_of_data = TRUE; + inflateEnd(&req->gzip_stream->zstream); + }else if(zres != Z_OK) { + WARN("inflate failed %d\n", zres); + if(!read) + ret = ERROR_INTERNET_DECODING_FAILED; + break; + } + } +#endif + + *read_ret = read; + return ret; +} + +static void refill_gzip_buffer(http_request_t *req) +{ + DWORD res; + int len; + + if(!req->gzip_stream || !req->read_size || req->gzip_stream->buf_size == sizeof(req->gzip_stream->buf)) + return; + + if(req->gzip_stream->buf_pos) { + if(req->gzip_stream->buf_size) + memmove(req->gzip_stream->buf, req->gzip_stream->buf + req->gzip_stream->buf_pos, req->gzip_stream->buf_size); + req->gzip_stream->buf_pos = 0; + } + + res = read_gzip_data(req, req->gzip_stream->buf + req->gzip_stream->buf_size, + sizeof(req->gzip_stream->buf) - req->gzip_stream->buf_size, FALSE, &len); + if(res == ERROR_SUCCESS) + req->gzip_stream->buf_size += len; +} + +/* return the size of data available to be read immediately (the read section must be held) */ +static DWORD get_avail_data( http_request_t *req ) +{ + if (req->gzip_stream) { + refill_gzip_buffer(req); + return req->gzip_stream->buf_size; + } + if (req->read_chunked && (req->dwContentLength == ~0u || req->dwContentLength == req->dwContentRead)) + return 0; + return min( req->read_size, req->dwContentLength - req->dwContentRead ); +} + +static void HTTP_ReceiveRequestData(http_request_t *req, BOOL first_notif) +{ + INTERNET_ASYNC_RESULT iar; + DWORD res; + + TRACE("%p\n", req); + + EnterCriticalSection( &req->read_section ); + if ((res = refill_buffer( req )) == ERROR_SUCCESS) { + iar.dwResult = (DWORD_PTR)req->hdr.hInternet; + iar.dwError = first_notif ? 0 : get_avail_data(req); + }else { + iar.dwResult = 0; + iar.dwError = res; + } + LeaveCriticalSection( &req->read_section ); + + INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, &iar, + sizeof(INTERNET_ASYNC_RESULT)); +} + +/* read data from the http connection (the read section must be held) */ +static DWORD HTTPREQ_Read(http_request_t *req, void *buffer, DWORD size, DWORD *read, BOOL sync) +{ + BOOL finished_reading = FALSE; + int len, bytes_read = 0; + DWORD ret = ERROR_SUCCESS; + + EnterCriticalSection( &req->read_section ); + + if (req->read_chunked && (req->dwContentLength == ~0u || req->dwContentLength == req->dwContentRead)) + { + if (start_next_chunk( req ) != ERROR_SUCCESS) goto done; + } + + if(req->gzip_stream) { + if(req->gzip_stream->buf_size) { + bytes_read = min(req->gzip_stream->buf_size, size); + memcpy(buffer, req->gzip_stream->buf + req->gzip_stream->buf_pos, bytes_read); + req->gzip_stream->buf_pos += bytes_read; + req->gzip_stream->buf_size -= bytes_read; + }else if(!req->read_size && !req->gzip_stream->end_of_data) { + refill_buffer(req); + } + + if(size > bytes_read) { + ret = read_gzip_data(req, (BYTE*)buffer+bytes_read, size-bytes_read, sync, &len); + if(ret == ERROR_SUCCESS) + bytes_read += len; + } + + finished_reading = req->gzip_stream->end_of_data && !req->gzip_stream->buf_size; + }else { + if (req->dwContentLength != ~0u) size = min( size, req->dwContentLength - req->dwContentRead ); + + if (req->read_size) { + bytes_read = min( req->read_size, size ); + memcpy( buffer, req->read_buf + req->read_pos, bytes_read ); + remove_data( req, bytes_read ); + } + + if (size > bytes_read && (!bytes_read || sync)) { + if (NETCON_recv( &req->netConnection, (char *)buffer + bytes_read, size - bytes_read, + sync ? MSG_WAITALL : 0, &len) == ERROR_SUCCESS) + bytes_read += len; + /* always return success, even if the network layer returns an error */ + } + + finished_reading = !bytes_read && req->dwContentRead == req->dwContentLength; + req->dwContentRead += bytes_read; + } +done: *read = bytes_read; - if(req->lpszCacheFile) { + TRACE( "retrieved %u bytes (%u/%u)\n", bytes_read, req->dwContentRead, req->dwContentLength ); + LeaveCriticalSection( &req->read_section ); + + if(ret == ERROR_SUCCESS && req->lpszCacheFile) { BOOL res; DWORD dwBytesWritten; @@ -1630,119 +2110,23 @@ static DWORD HTTP_Read(WININETHTTPREQW *req, void *buffer, DWORD size, DWORD *re WARN("WriteFile failed: %u\n", GetLastError()); } - if(!bytes_read && (req->dwContentRead == req->dwContentLength)) + if(finished_reading) HTTP_FinishedReading(req); - return ERROR_SUCCESS; + return ret; } -static DWORD get_chunk_size(const char *buffer) + +static DWORD HTTPREQ_ReadFile(object_header_t *hdr, void *buffer, DWORD size, DWORD *read) { - const char *p; - DWORD size = 0; - - for (p = buffer; *p; p++) - { - if (*p >= '0' && *p <= '9') size = size * 16 + *p - '0'; - else if (*p >= 'a' && *p <= 'f') size = size * 16 + *p - 'a' + 10; - else if (*p >= 'A' && *p <= 'F') size = size * 16 + *p - 'A' + 10; - else if (*p == ';') break; - } - return size; -} - -static DWORD HTTP_ReadChunked(WININETHTTPREQW *req, void *buffer, DWORD size, DWORD *read, BOOL sync) -{ - char reply[MAX_REPLY_LEN], *p = buffer; - DWORD buflen, to_read, to_write = size; - int bytes_read; - - *read = 0; - for (;;) - { - if (*read == size) break; - - if (req->dwContentLength == ~0UL) /* new chunk */ - { - buflen = sizeof(reply); - if (!NETCON_getNextLine(&req->netConnection, reply, &buflen)) break; - - if (!(req->dwContentLength = get_chunk_size(reply))) - { - /* zero sized chunk marks end of transfer; read any trailing headers and return */ - HTTP_GetResponseHeaders(req, FALSE); - break; - } - } - to_read = min(to_write, req->dwContentLength - req->dwContentRead); - - if (!NETCON_recv(&req->netConnection, p, to_read, sync ? MSG_WAITALL : 0, &bytes_read)) - { - if (bytes_read != to_read) - ERR("Not all data received %d/%d\n", bytes_read, to_read); - - /* always return success, even if the network layer returns an error */ - *read = 0; - break; - } - if (!bytes_read) break; - - req->dwContentRead += bytes_read; - to_write -= bytes_read; - *read += bytes_read; - - if (req->lpszCacheFile) - { - DWORD dwBytesWritten; - - if (!WriteFile(req->hCacheFile, p, bytes_read, &dwBytesWritten, NULL)) - WARN("WriteFile failed: %u\n", GetLastError()); - } - p += bytes_read; - - if (req->dwContentRead == req->dwContentLength) /* chunk complete */ - { - req->dwContentRead = 0; - req->dwContentLength = ~0UL; - - buflen = sizeof(reply); - if (!NETCON_getNextLine(&req->netConnection, reply, &buflen)) - { - ERR("Malformed chunk\n"); - *read = 0; - break; - } - } - } - if (!*read) HTTP_FinishedReading(req); - return ERROR_SUCCESS; -} - -static DWORD HTTPREQ_Read(WININETHTTPREQW *req, void *buffer, DWORD size, DWORD *read, BOOL sync) -{ - WCHAR encoding[20]; - DWORD buflen = sizeof(encoding); - static const WCHAR szChunked[] = {'c','h','u','n','k','e','d',0}; - - if (HTTP_HttpQueryInfoW(req, HTTP_QUERY_TRANSFER_ENCODING, encoding, &buflen, NULL) && - !strcmpiW(encoding, szChunked)) - { - return HTTP_ReadChunked(req, buffer, size, read, sync); - } - else - return HTTP_Read(req, buffer, size, read, sync); -} - -static DWORD HTTPREQ_ReadFile(WININETHANDLEHEADER *hdr, void *buffer, DWORD size, DWORD *read) -{ - WININETHTTPREQW *req = (WININETHTTPREQW*)hdr; + http_request_t *req = (http_request_t*)hdr; return HTTPREQ_Read(req, buffer, size, read, TRUE); } -static void HTTPREQ_AsyncReadFileExProc(WORKREQUEST *workRequest) +static void HTTPREQ_AsyncReadFileExAProc(WORKREQUEST *workRequest) { struct WORKREQ_INTERNETREADFILEEXA const *data = &workRequest->u.InternetReadFileExA; - WININETHTTPREQW *req = (WININETHTTPREQW*)workRequest->hdr; + http_request_t *req = (http_request_t*)workRequest->hdr; INTERNET_ASYNC_RESULT iar; DWORD res; @@ -1759,11 +2143,10 @@ static void HTTPREQ_AsyncReadFileExProc(WORKREQUEST *workRequest) sizeof(INTERNET_ASYNC_RESULT)); } -static DWORD HTTPREQ_ReadFileExA(WININETHANDLEHEADER *hdr, INTERNET_BUFFERSA *buffers, +static DWORD HTTPREQ_ReadFileExA(object_header_t *hdr, INTERNET_BUFFERSA *buffers, DWORD flags, DWORD_PTR context) { - - WININETHTTPREQW *req = (WININETHTTPREQW*)hdr; + http_request_t *req = (http_request_t*)hdr; DWORD res; if (flags & ~(IRF_ASYNC|IRF_NO_WAIT)) @@ -1774,27 +2157,35 @@ static DWORD HTTPREQ_ReadFileExA(WININETHANDLEHEADER *hdr, INTERNET_BUFFERSA *bu INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0); - if (hdr->dwFlags & INTERNET_FLAG_ASYNC) { - DWORD available = 0; + if ((hdr->dwFlags & INTERNET_FLAG_ASYNC) && !get_avail_data(req)) + { + WORKREQUEST workRequest; - NETCON_query_data_available(&req->netConnection, &available); - if (!available) + if (TryEnterCriticalSection( &req->read_section )) { - WORKREQUEST workRequest; - - workRequest.asyncproc = HTTPREQ_AsyncReadFileExProc; - workRequest.hdr = WININET_AddRef(&req->hdr); - workRequest.u.InternetReadFileExA.lpBuffersOut = buffers; - - INTERNET_AsyncCall(&workRequest); - - return ERROR_IO_PENDING; + if (get_avail_data(req)) + { + res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength, + &buffers->dwBufferLength, FALSE); + LeaveCriticalSection( &req->read_section ); + goto done; + } + LeaveCriticalSection( &req->read_section ); } + + workRequest.asyncproc = HTTPREQ_AsyncReadFileExAProc; + workRequest.hdr = WININET_AddRef(&req->hdr); + workRequest.u.InternetReadFileExA.lpBuffersOut = buffers; + + INTERNET_AsyncCall(&workRequest); + + return ERROR_IO_PENDING; } res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength, &buffers->dwBufferLength, !(flags & IRF_NO_WAIT)); +done: if (res == ERROR_SUCCESS) { DWORD size = buffers->dwBufferLength; INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED, @@ -1804,52 +2195,120 @@ static DWORD HTTPREQ_ReadFileExA(WININETHANDLEHEADER *hdr, INTERNET_BUFFERSA *bu return res; } -static BOOL HTTPREQ_WriteFile(WININETHANDLEHEADER *hdr, const void *buffer, DWORD size, DWORD *written) +static void HTTPREQ_AsyncReadFileExWProc(WORKREQUEST *workRequest) { - LPWININETHTTPREQW lpwhr = (LPWININETHTTPREQW)hdr; + struct WORKREQ_INTERNETREADFILEEXW const *data = &workRequest->u.InternetReadFileExW; + http_request_t *req = (http_request_t*)workRequest->hdr; + INTERNET_ASYNC_RESULT iar; + DWORD res; - return NETCON_send(&lpwhr->netConnection, buffer, size, 0, (LPINT)written); + TRACE("INTERNETREADFILEEXW %p\n", workRequest->hdr); + + res = HTTPREQ_Read(req, data->lpBuffersOut->lpvBuffer, + data->lpBuffersOut->dwBufferLength, &data->lpBuffersOut->dwBufferLength, TRUE); + + iar.dwResult = res == ERROR_SUCCESS; + iar.dwError = res; + + INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, + INTERNET_STATUS_REQUEST_COMPLETE, &iar, + sizeof(INTERNET_ASYNC_RESULT)); +} + +static DWORD HTTPREQ_ReadFileExW(object_header_t *hdr, INTERNET_BUFFERSW *buffers, + DWORD flags, DWORD_PTR context) +{ + + http_request_t *req = (http_request_t*)hdr; + DWORD res; + + if (flags & ~(IRF_ASYNC|IRF_NO_WAIT)) + FIXME("these dwFlags aren't implemented: 0x%x\n", flags & ~(IRF_ASYNC|IRF_NO_WAIT)); + + if (buffers->dwStructSize != sizeof(*buffers)) + return ERROR_INVALID_PARAMETER; + + INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0); + + if (hdr->dwFlags & INTERNET_FLAG_ASYNC) + { + WORKREQUEST workRequest; + + if (TryEnterCriticalSection( &req->read_section )) + { + if (get_avail_data(req)) + { + res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength, + &buffers->dwBufferLength, FALSE); + LeaveCriticalSection( &req->read_section ); + goto done; + } + LeaveCriticalSection( &req->read_section ); + } + + workRequest.asyncproc = HTTPREQ_AsyncReadFileExWProc; + workRequest.hdr = WININET_AddRef(&req->hdr); + workRequest.u.InternetReadFileExW.lpBuffersOut = buffers; + + INTERNET_AsyncCall(&workRequest); + + return ERROR_IO_PENDING; + } + + res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength, &buffers->dwBufferLength, + !(flags & IRF_NO_WAIT)); + +done: + if (res == ERROR_SUCCESS) { + DWORD size = buffers->dwBufferLength; + INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED, + &size, sizeof(size)); + } + + return res; +} + +static DWORD HTTPREQ_WriteFile(object_header_t *hdr, const void *buffer, DWORD size, DWORD *written) +{ + DWORD res; + http_request_t *lpwhr = (http_request_t*)hdr; + + INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0); + + *written = 0; + res = NETCON_send(&lpwhr->netConnection, buffer, size, 0, (LPINT)written); + if (res == ERROR_SUCCESS) + lpwhr->dwBytesWritten += *written; + + INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_REQUEST_SENT, written, sizeof(DWORD)); + return res; } static void HTTPREQ_AsyncQueryDataAvailableProc(WORKREQUEST *workRequest) { - WININETHTTPREQW *req = (WININETHTTPREQW*)workRequest->hdr; - INTERNET_ASYNC_RESULT iar; - char buffer[4048]; + http_request_t *req = (http_request_t*)workRequest->hdr; - TRACE("%p\n", workRequest->hdr); - - iar.dwResult = NETCON_recv(&req->netConnection, buffer, - min(sizeof(buffer), req->dwContentLength - req->dwContentRead), - MSG_PEEK, (int *)&iar.dwError); - - INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, &iar, - sizeof(INTERNET_ASYNC_RESULT)); + HTTP_ReceiveRequestData(req, FALSE); } -static DWORD HTTPREQ_QueryDataAvailable(WININETHANDLEHEADER *hdr, DWORD *available, DWORD flags, DWORD_PTR ctx) +static DWORD HTTPREQ_QueryDataAvailable(object_header_t *hdr, DWORD *available, DWORD flags, DWORD_PTR ctx) { - WININETHTTPREQW *req = (WININETHTTPREQW*)hdr; - BYTE buffer[4048]; - BOOL async; + http_request_t *req = (http_request_t*)hdr; TRACE("(%p %p %x %lx)\n", req, available, flags, ctx); - if(!NETCON_query_data_available(&req->netConnection, available) || *available) - return ERROR_SUCCESS; - - /* Even if we are in async mode, we need to determine whether - * there is actually more data available. We do this by trying - * to peek only a single byte in async mode. */ - async = (req->lpHttpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC) != 0; - - if (NETCON_recv(&req->netConnection, buffer, - min(async ? 1 : sizeof(buffer), req->dwContentLength - req->dwContentRead), - MSG_PEEK, (int *)available) && async && *available) + if (req->lpHttpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC) { WORKREQUEST workRequest; - *available = 0; + /* never wait, if we can't enter the section we queue an async request right away */ + if (TryEnterCriticalSection( &req->read_section )) + { + if ((*available = get_avail_data( req ))) goto done; + if (end_of_read_data( req )) goto done; + LeaveCriticalSection( &req->read_section ); + } + workRequest.asyncproc = HTTPREQ_AsyncQueryDataAvailableProc; workRequest.hdr = WININET_AddRef( &req->hdr ); @@ -1858,16 +2317,35 @@ static DWORD HTTPREQ_QueryDataAvailable(WININETHANDLEHEADER *hdr, DWORD *availab return ERROR_IO_PENDING; } + EnterCriticalSection( &req->read_section ); + + if (!(*available = get_avail_data( req )) && !end_of_read_data( req )) + { + refill_buffer( req ); + *available = get_avail_data( req ); + } + +done: + if (*available == sizeof(req->read_buf) && !req->gzip_stream) /* check if we have even more pending in the socket */ + { + DWORD extra; + if (NETCON_query_data_available(&req->netConnection, &extra)) + *available = min( *available + extra, req->dwContentLength - req->dwContentRead ); + } + LeaveCriticalSection( &req->read_section ); + + TRACE( "returning %u\n", *available ); return ERROR_SUCCESS; } -static const HANDLEHEADERVtbl HTTPREQVtbl = { +static const object_vtbl_t HTTPREQVtbl = { HTTPREQ_Destroy, HTTPREQ_CloseConnection, HTTPREQ_QueryOption, HTTPREQ_SetOption, HTTPREQ_ReadFile, HTTPREQ_ReadFileExA, + HTTPREQ_ReadFileExW, HTTPREQ_WriteFile, HTTPREQ_QueryDataAvailable, NULL @@ -1883,27 +2361,27 @@ static const HANDLEHEADERVtbl HTTPREQVtbl = { * NULL on failure * */ -HINTERNET WINAPI HTTP_HttpOpenRequestW(LPWININETHTTPSESSIONW lpwhs, - LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion, - LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes, - DWORD dwFlags, DWORD_PTR dwContext) +static DWORD HTTP_HttpOpenRequestW(http_session_t *lpwhs, + LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion, + LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes, + DWORD dwFlags, DWORD_PTR dwContext, HINTERNET *ret) { - LPWININETAPPINFOW hIC = NULL; - LPWININETHTTPREQW lpwhr; + appinfo_t *hIC = NULL; + http_request_t *lpwhr; LPWSTR lpszHostName = NULL; HINTERNET handle = NULL; static const WCHAR szHostForm[] = {'%','s',':','%','u',0}; - DWORD len; + DWORD len, res; TRACE("-->\n"); assert( lpwhs->hdr.htype == WH_HHTTPSESSION ); hIC = lpwhs->lpAppInfo; - lpwhr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPREQW)); + lpwhr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(http_request_t)); if (NULL == lpwhr) { - INTERNET_SetLastError(ERROR_OUTOFMEMORY); + res = ERROR_OUTOFMEMORY; goto lend; } lpwhr->hdr.htype = WH_HHTTPREQ; @@ -1913,6 +2391,8 @@ HINTERNET WINAPI HTTP_HttpOpenRequestW(LPWININETHTTPSESSIONW lpwhs, lpwhr->hdr.refs = 1; lpwhr->hdr.lpfnStatusCB = lpwhs->hdr.lpfnStatusCB; lpwhr->hdr.dwInternalFlags = lpwhs->hdr.dwInternalFlags & INET_CALLBACKW; + lpwhr->dwContentLength = ~0u; + InitializeCriticalSection( &lpwhr->read_section ); WININET_AddRef( &lpwhs->hdr ); lpwhr->lpHttpSession = lpwhs; @@ -1922,18 +2402,18 @@ HINTERNET WINAPI HTTP_HttpOpenRequestW(LPWININETHTTPSESSIONW lpwhs, (strlenW(lpwhs->lpszHostName) + 7 /* length of ":65535" + 1 */)); if (NULL == lpszHostName) { - INTERNET_SetLastError(ERROR_OUTOFMEMORY); + res = ERROR_OUTOFMEMORY; goto lend; } handle = WININET_AllocHandle( &lpwhr->hdr ); if (NULL == handle) { - INTERNET_SetLastError(ERROR_OUTOFMEMORY); + res = ERROR_OUTOFMEMORY; goto lend; } - if (!NETCON_init(&lpwhr->netConnection, dwFlags & INTERNET_FLAG_SECURE)) + if ((res = NETCON_init(&lpwhr->netConnection, dwFlags & INTERNET_FLAG_SECURE)) != ERROR_SUCCESS) { InternetCloseHandle( handle ); handle = NULL; @@ -1950,11 +2430,15 @@ HINTERNET WINAPI HTTP_HttpOpenRequestW(LPWININETHTTPSESSIONW lpwhs, lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); rc = UrlEscapeW(lpszObjectName, lpwhr->lpszPath, &len, URL_ESCAPE_SPACES_ONLY); - if (rc) + if (rc != S_OK) { ERR("Unable to escape string!(%s) (%d)\n",debugstr_w(lpszObjectName),rc); strcpyW(lpwhr->lpszPath,lpszObjectName); } + }else { + static const WCHAR slashW[] = {'/',0}; + + lpwhr->lpszPath = heap_strdupW(slashW); } if (lpszReferrer && *lpszReferrer) @@ -1973,23 +2457,19 @@ HINTERNET WINAPI HTTP_HttpOpenRequestW(LPWININETHTTPSESSIONW lpwhs, } } - lpwhr->lpszVerb = WININET_strdupW(lpszVerb && *lpszVerb ? lpszVerb : szGET); - - if (lpszVersion) - lpwhr->lpszVersion = WININET_strdupW(lpszVersion); - else - lpwhr->lpszVersion = WININET_strdupW(g_szHttp1_1); + lpwhr->lpszVerb = heap_strdupW(lpszVerb && *lpszVerb ? lpszVerb : szGET); + lpwhr->lpszVersion = heap_strdupW(lpszVersion ? lpszVersion : g_szHttp1_1); if (lpwhs->nHostPort != INTERNET_INVALID_PORT_NUMBER && lpwhs->nHostPort != INTERNET_DEFAULT_HTTP_PORT && lpwhs->nHostPort != INTERNET_DEFAULT_HTTPS_PORT) { sprintfW(lpszHostName, szHostForm, lpwhs->lpszHostName, lpwhs->nHostPort); - HTTP_ProcessHeader(lpwhr, szHost, lpszHostName, + HTTP_ProcessHeader(lpwhr, hostW, lpszHostName, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ); } else - HTTP_ProcessHeader(lpwhr, szHost, lpwhs->lpszHostName, + HTTP_ProcessHeader(lpwhr, hostW, lpwhs->lpszHostName, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ); if (lpwhs->nServerPort == INTERNET_INVALID_PORT_NUMBER) @@ -2015,81 +2495,89 @@ lend: WININET_Release( &lpwhr->hdr ); TRACE("<-- %p (%p)\n", handle, lpwhr); + *ret = handle; + return res; +} + +/*********************************************************************** + * HttpOpenRequestW (WININET.@) + * + * Open a HTTP request handle + * + * RETURNS + * HINTERNET a HTTP request handle on success + * NULL on failure + * + */ +HINTERNET WINAPI HttpOpenRequestW(HINTERNET hHttpSession, + LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion, + LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes, + DWORD dwFlags, DWORD_PTR dwContext) +{ + http_session_t *lpwhs; + HINTERNET handle = NULL; + DWORD res; + + TRACE("(%p, %s, %s, %s, %s, %p, %08x, %08lx)\n", hHttpSession, + debugstr_w(lpszVerb), debugstr_w(lpszObjectName), + debugstr_w(lpszVersion), debugstr_w(lpszReferrer), lpszAcceptTypes, + dwFlags, dwContext); + if(lpszAcceptTypes!=NULL) + { + int i; + for(i=0;lpszAcceptTypes[i]!=NULL;i++) + TRACE("\taccept type: %s\n",debugstr_w(lpszAcceptTypes[i])); + } + + lpwhs = (http_session_t*) WININET_GetObject( hHttpSession ); + if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION) + { + res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE; + goto lend; + } + + /* + * My tests seem to show that the windows version does not + * become asynchronous until after this point. And anyhow + * if this call was asynchronous then how would you get the + * necessary HINTERNET pointer returned by this function. + * + */ + res = HTTP_HttpOpenRequestW(lpwhs, lpszVerb, lpszObjectName, + lpszVersion, lpszReferrer, lpszAcceptTypes, + dwFlags, dwContext, &handle); +lend: + if( lpwhs ) + WININET_Release( &lpwhs->hdr ); + TRACE("returning %p\n", handle); + if(res != ERROR_SUCCESS) + SetLastError(res); return handle; } /* read any content returned by the server so that the connection can be * reused */ -static void HTTP_DrainContent(WININETHTTPREQW *req) +static void HTTP_DrainContent(http_request_t *req) { DWORD bytes_read; if (!NETCON_connected(&req->netConnection)) return; if (req->dwContentLength == -1) + { NETCON_close(&req->netConnection); + return; + } + if (!strcmpW(req->lpszVerb, szHEAD)) return; do { char buffer[2048]; - if (HTTP_Read(req, buffer, sizeof(buffer), &bytes_read, TRUE) != ERROR_SUCCESS) + if (HTTPREQ_Read(req, buffer, sizeof(buffer), &bytes_read, TRUE) != ERROR_SUCCESS) return; } while (bytes_read); } -static const WCHAR szAccept[] = { 'A','c','c','e','p','t',0 }; -static const WCHAR szAccept_Charset[] = { 'A','c','c','e','p','t','-','C','h','a','r','s','e','t', 0 }; -static const WCHAR szAccept_Encoding[] = { 'A','c','c','e','p','t','-','E','n','c','o','d','i','n','g',0 }; -static const WCHAR szAccept_Language[] = { 'A','c','c','e','p','t','-','L','a','n','g','u','a','g','e',0 }; -static const WCHAR szAccept_Ranges[] = { 'A','c','c','e','p','t','-','R','a','n','g','e','s',0 }; -static const WCHAR szAge[] = { 'A','g','e',0 }; -static const WCHAR szAllow[] = { 'A','l','l','o','w',0 }; -static const WCHAR szCache_Control[] = { 'C','a','c','h','e','-','C','o','n','t','r','o','l',0 }; -static const WCHAR szConnection[] = { 'C','o','n','n','e','c','t','i','o','n',0 }; -static const WCHAR szContent_Base[] = { 'C','o','n','t','e','n','t','-','B','a','s','e',0 }; -static const WCHAR szContent_Encoding[] = { 'C','o','n','t','e','n','t','-','E','n','c','o','d','i','n','g',0 }; -static const WCHAR szContent_ID[] = { 'C','o','n','t','e','n','t','-','I','D',0 }; -static const WCHAR szContent_Language[] = { 'C','o','n','t','e','n','t','-','L','a','n','g','u','a','g','e',0 }; -static const WCHAR szContent_Length[] = { 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',0 }; -static const WCHAR szContent_Location[] = { 'C','o','n','t','e','n','t','-','L','o','c','a','t','i','o','n',0 }; -static const WCHAR szContent_MD5[] = { 'C','o','n','t','e','n','t','-','M','D','5',0 }; -static const WCHAR szContent_Range[] = { 'C','o','n','t','e','n','t','-','R','a','n','g','e',0 }; -static const WCHAR szContent_Transfer_Encoding[] = { 'C','o','n','t','e','n','t','-','T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0 }; -static const WCHAR szContent_Type[] = { 'C','o','n','t','e','n','t','-','T','y','p','e',0 }; -static const WCHAR szCookie[] = { 'C','o','o','k','i','e',0 }; -static const WCHAR szDate[] = { 'D','a','t','e',0 }; -static const WCHAR szFrom[] = { 'F','r','o','m',0 }; -static const WCHAR szETag[] = { 'E','T','a','g',0 }; -static const WCHAR szExpect[] = { 'E','x','p','e','c','t',0 }; -static const WCHAR szExpires[] = { 'E','x','p','i','r','e','s',0 }; -static const WCHAR szIf_Match[] = { 'I','f','-','M','a','t','c','h',0 }; -static const WCHAR szIf_Modified_Since[] = { 'I','f','-','M','o','d','i','f','i','e','d','-','S','i','n','c','e',0 }; -static const WCHAR szIf_None_Match[] = { 'I','f','-','N','o','n','e','-','M','a','t','c','h',0 }; -static const WCHAR szIf_Range[] = { 'I','f','-','R','a','n','g','e',0 }; -static const WCHAR szIf_Unmodified_Since[] = { 'I','f','-','U','n','m','o','d','i','f','i','e','d','-','S','i','n','c','e',0 }; -static const WCHAR szLast_Modified[] = { 'L','a','s','t','-','M','o','d','i','f','i','e','d',0 }; -static const WCHAR szLocation[] = { 'L','o','c','a','t','i','o','n',0 }; -static const WCHAR szMax_Forwards[] = { 'M','a','x','-','F','o','r','w','a','r','d','s',0 }; -static const WCHAR szMime_Version[] = { 'M','i','m','e','-','V','e','r','s','i','o','n',0 }; -static const WCHAR szPragma[] = { 'P','r','a','g','m','a',0 }; -static const WCHAR szProxy_Authenticate[] = { 'P','r','o','x','y','-','A','u','t','h','e','n','t','i','c','a','t','e',0 }; -static const WCHAR szProxy_Connection[] = { 'P','r','o','x','y','-','C','o','n','n','e','c','t','i','o','n',0 }; -static const WCHAR szPublic[] = { 'P','u','b','l','i','c',0 }; -static const WCHAR szRange[] = { 'R','a','n','g','e',0 }; -static const WCHAR szReferer[] = { 'R','e','f','e','r','e','r',0 }; -static const WCHAR szRetry_After[] = { 'R','e','t','r','y','-','A','f','t','e','r',0 }; -static const WCHAR szServer[] = { 'S','e','r','v','e','r',0 }; -static const WCHAR szSet_Cookie[] = { 'S','e','t','-','C','o','o','k','i','e',0 }; -static const WCHAR szTransfer_Encoding[] = { 'T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0 }; -static const WCHAR szUnless_Modified_Since[] = { 'U','n','l','e','s','s','-','M','o','d','i','f','i','e','d','-','S','i','n','c','e',0 }; -static const WCHAR szUpgrade[] = { 'U','p','g','r','a','d','e',0 }; -static const WCHAR szURI[] = { 'U','R','I',0 }; -static const WCHAR szUser_Agent[] = { 'U','s','e','r','-','A','g','e','n','t',0 }; -static const WCHAR szVary[] = { 'V','a','r','y',0 }; -static const WCHAR szVia[] = { 'V','i','a',0 }; -static const WCHAR szWarning[] = { 'W','a','r','n','i','n','g',0 }; -static const WCHAR szWWW_Authenticate[] = { 'W','W','W','-','A','u','t','h','e','n','t','i','c','a','t','e',0 }; - static const LPCWSTR header_lookup[] = { szMime_Version, /* HTTP_QUERY_MIME_VERSION = 0 */ szContent_Type, /* HTTP_QUERY_CONTENT_TYPE = 1 */ @@ -2146,7 +2634,7 @@ static const LPCWSTR header_lookup[] = { szContent_MD5, /* HTTP_QUERY_CONTENT_MD5 = 52 */ szContent_Range, /* HTTP_QUERY_CONTENT_RANGE = 53 */ szETag, /* HTTP_QUERY_ETAG = 54 */ - szHost, /* HTTP_QUERY_HOST = 55 */ + hostW, /* HTTP_QUERY_HOST = 55 */ szIf_Match, /* HTTP_QUERY_IF_MATCH = 56 */ szIf_None_Match, /* HTTP_QUERY_IF_NONE_MATCH = 57 */ szIf_Range, /* HTTP_QUERY_IF_RANGE = 58 */ @@ -2169,58 +2657,64 @@ static const LPCWSTR header_lookup[] = { /*********************************************************************** * HTTP_HttpQueryInfoW (internal) */ -static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD dwInfoLevel, - LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex) +static DWORD HTTP_HttpQueryInfoW(http_request_t *lpwhr, DWORD dwInfoLevel, + LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex) { LPHTTPHEADERW lphttpHdr = NULL; - BOOL bSuccess = FALSE; BOOL request_only = dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS; INT requested_index = lpdwIndex ? *lpdwIndex : 0; - INT level = (dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK); + DWORD level = (dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK); INT index = -1; /* Find requested header structure */ switch (level) { case HTTP_QUERY_CUSTOM: + if (!lpBuffer) return ERROR_INVALID_PARAMETER; index = HTTP_GetCustomHeaderIndex(lpwhr, lpBuffer, requested_index, request_only); break; - case HTTP_QUERY_RAW_HEADERS_CRLF: { LPWSTR headers; - DWORD len; - BOOL ret = FALSE; + DWORD len = 0; + DWORD res = ERROR_INVALID_PARAMETER; if (request_only) headers = HTTP_BuildHeaderRequestString(lpwhr, lpwhr->lpszVerb, lpwhr->lpszPath, lpwhr->lpszVersion); else headers = lpwhr->lpszRawHeaders; - len = (strlenW(headers) + 1) * sizeof(WCHAR); - if (len > *lpdwBufferLength) + if (headers) + len = strlenW(headers) * sizeof(WCHAR); + + if (len + sizeof(WCHAR) > *lpdwBufferLength) { - INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER); - ret = FALSE; + len += sizeof(WCHAR); + res = ERROR_INSUFFICIENT_BUFFER; } else if (lpBuffer) { - memcpy(lpBuffer, headers, len); + if (headers) + memcpy(lpBuffer, headers, len + sizeof(WCHAR)); + else + { + len = strlenW(szCrLf) * sizeof(WCHAR); + memcpy(lpBuffer, szCrLf, sizeof(szCrLf)); + } TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len / sizeof(WCHAR))); - ret = TRUE; + res = ERROR_SUCCESS; } *lpdwBufferLength = len; if (request_only) HeapFree(GetProcessHeap(), 0, headers); - return ret; + return res; } case HTTP_QUERY_RAW_HEADERS: { - static const WCHAR szCrLf[] = {'\r','\n',0}; LPWSTR * ppszRawHeaderLines = HTTP_Tokenize(lpwhr->lpszRawHeaders, szCrLf); DWORD i, size = 0; - LPWSTR pszString = (WCHAR*)lpBuffer; + LPWSTR pszString = lpBuffer; for (i = 0; ppszRawHeaderLines[i]; i++) size += strlenW(ppszRawHeaderLines[i]) + 1; @@ -2229,24 +2723,23 @@ static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD dwInfoLev { HTTP_FreeTokens(ppszRawHeaderLines); *lpdwBufferLength = (size + 1) * sizeof(WCHAR); - INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER); - return FALSE; + return ERROR_INSUFFICIENT_BUFFER; } - - for (i = 0; ppszRawHeaderLines[i]; i++) + if (pszString) { - DWORD len = strlenW(ppszRawHeaderLines[i]); - memcpy(pszString, ppszRawHeaderLines[i], (len+1)*sizeof(WCHAR)); - pszString += len+1; + for (i = 0; ppszRawHeaderLines[i]; i++) + { + DWORD len = strlenW(ppszRawHeaderLines[i]); + memcpy(pszString, ppszRawHeaderLines[i], (len+1)*sizeof(WCHAR)); + pszString += len+1; + } + *pszString = '\0'; + TRACE("returning data: %s\n", debugstr_wn(lpBuffer, size)); } - *pszString = '\0'; - - TRACE("returning data: %s\n", debugstr_wn((WCHAR*)lpBuffer, size)); - *lpdwBufferLength = size * sizeof(WCHAR); HTTP_FreeTokens(ppszRawHeaderLines); - return TRUE; + return ERROR_SUCCESS; } case HTTP_QUERY_STATUS_TEXT: if (lpwhr->lpszStatusText) @@ -2255,15 +2748,15 @@ static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD dwInfoLev if (len + 1 > *lpdwBufferLength/sizeof(WCHAR)) { *lpdwBufferLength = (len + 1) * sizeof(WCHAR); - INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER); - return FALSE; + return ERROR_INSUFFICIENT_BUFFER; + } + if (lpBuffer) + { + memcpy(lpBuffer, lpwhr->lpszStatusText, (len + 1) * sizeof(WCHAR)); + TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len)); } - memcpy(lpBuffer, lpwhr->lpszStatusText, (len+1)*sizeof(WCHAR)); *lpdwBufferLength = len * sizeof(WCHAR); - - TRACE("returning data: %s\n", debugstr_wn((WCHAR*)lpBuffer, len)); - - return TRUE; + return ERROR_SUCCESS; } break; case HTTP_QUERY_VERSION: @@ -2273,21 +2766,25 @@ static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD dwInfoLev if (len + 1 > *lpdwBufferLength/sizeof(WCHAR)) { *lpdwBufferLength = (len + 1) * sizeof(WCHAR); - INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER); - return FALSE; + return ERROR_INSUFFICIENT_BUFFER; + } + if (lpBuffer) + { + memcpy(lpBuffer, lpwhr->lpszVersion, (len + 1) * sizeof(WCHAR)); + TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len)); } - memcpy(lpBuffer, lpwhr->lpszVersion, (len+1)*sizeof(WCHAR)); *lpdwBufferLength = len * sizeof(WCHAR); - - TRACE("returning data: %s\n", debugstr_wn((WCHAR*)lpBuffer, len)); - - return TRUE; + return ERROR_SUCCESS; } break; + case HTTP_QUERY_CONTENT_ENCODING: + index = HTTP_GetCustomHeaderIndex(lpwhr, header_lookup[lpwhr->gzip_stream ? HTTP_QUERY_CONTENT_TYPE : level], + requested_index,request_only); + break; default: assert (LAST_TABLE_HEADER == (HTTP_QUERY_UNLESS_MODIFIED_SINCE + 1)); - if (level >= 0 && level < LAST_TABLE_HEADER && header_lookup[level]) + if (level < LAST_TABLE_HEADER && header_lookup[level]) index = HTTP_GetCustomHeaderIndex(lpwhr, header_lookup[level], requested_index,request_only); } @@ -2300,22 +2797,18 @@ static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD dwInfoLev ((dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS) && (~lphttpHdr->wFlags & HDR_ISREQUEST))) { - INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND); - return bSuccess; + return ERROR_HTTP_HEADER_NOT_FOUND; } - if (lpdwIndex) - (*lpdwIndex)++; + if (lpdwIndex && level != HTTP_QUERY_STATUS_CODE) (*lpdwIndex)++; /* coalesce value to requested type */ - if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER) + if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER && lpBuffer) { - *(int *)lpBuffer = atoiW(lphttpHdr->lpszValue); - bSuccess = TRUE; - - TRACE(" returning number : %d\n", *(int *)lpBuffer); - } - else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME) + *(int *)lpBuffer = atoiW(lphttpHdr->lpszValue); + TRACE(" returning number: %d\n", *(int *)lpBuffer); + } + else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME && lpBuffer) { time_t tmpTime; struct tm tmpTM; @@ -2324,24 +2817,19 @@ static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD dwInfoLev tmpTime = ConvertTimeString(lphttpHdr->lpszValue); tmpTM = *gmtime(&tmpTime); - STHook = (SYSTEMTIME *) lpBuffer; - if(STHook==NULL) - return bSuccess; + STHook = (SYSTEMTIME *)lpBuffer; + STHook->wDay = tmpTM.tm_mday; + STHook->wHour = tmpTM.tm_hour; + STHook->wMilliseconds = 0; + STHook->wMinute = tmpTM.tm_min; + STHook->wDayOfWeek = tmpTM.tm_wday; + STHook->wMonth = tmpTM.tm_mon + 1; + STHook->wSecond = tmpTM.tm_sec; + STHook->wYear = tmpTM.tm_year; - STHook->wDay = tmpTM.tm_mday; - STHook->wHour = tmpTM.tm_hour; - STHook->wMilliseconds = 0; - STHook->wMinute = tmpTM.tm_min; - STHook->wDayOfWeek = tmpTM.tm_wday; - STHook->wMonth = tmpTM.tm_mon + 1; - STHook->wSecond = tmpTM.tm_sec; - STHook->wYear = tmpTM.tm_year; - - bSuccess = TRUE; - - TRACE(" returning time : %04d/%02d/%02d - %d - %02d:%02d:%02d.%02d\n", - STHook->wYear, STHook->wMonth, STHook->wDay, STHook->wDayOfWeek, - STHook->wHour, STHook->wMinute, STHook->wSecond, STHook->wMilliseconds); + TRACE(" returning time: %04d/%02d/%02d - %d - %02d:%02d:%02d.%02d\n", + STHook->wYear, STHook->wMonth, STHook->wDay, STHook->wDayOfWeek, + STHook->wHour, STHook->wMinute, STHook->wSecond, STHook->wMilliseconds); } else if (lphttpHdr->lpszValue) { @@ -2350,17 +2838,16 @@ static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD dwInfoLev if (len > *lpdwBufferLength) { *lpdwBufferLength = len; - INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER); - return bSuccess; + return ERROR_INSUFFICIENT_BUFFER; + } + if (lpBuffer) + { + memcpy(lpBuffer, lphttpHdr->lpszValue, len); + TRACE("! returning string: %s\n", debugstr_w(lpBuffer)); } - - memcpy(lpBuffer, lphttpHdr->lpszValue, len); *lpdwBufferLength = len - sizeof(WCHAR); - bSuccess = TRUE; - - TRACE(" returning string : %s\n", debugstr_w(lpBuffer)); } - return bSuccess; + return ERROR_SUCCESS; } /*********************************************************************** @@ -2374,10 +2861,10 @@ static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD dwInfoLev * */ BOOL WINAPI HttpQueryInfoW(HINTERNET hHttpRequest, DWORD dwInfoLevel, - LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex) + LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex) { - BOOL bSuccess = FALSE; - LPWININETHTTPREQW lpwhr; + http_request_t *lpwhr; + DWORD res; if (TRACE_ON(wininet)) { #define FE(x) { x, #x } @@ -2463,7 +2950,7 @@ BOOL WINAPI HttpQueryInfoW(HINTERNET hHttpRequest, DWORD dwInfoLevel, DWORD info = dwInfoLevel & HTTP_QUERY_HEADER_MASK; DWORD i; - TRACE("(%p, 0x%08x)--> %d\n", hHttpRequest, dwInfoLevel, dwInfoLevel); + TRACE("(%p, 0x%08x)--> %d\n", hHttpRequest, dwInfoLevel, info); TRACE(" Attribute:"); for (i = 0; i < (sizeof(query_flags) / sizeof(query_flags[0])); i++) { if (query_flags[i].val == info) { @@ -2489,24 +2976,26 @@ BOOL WINAPI HttpQueryInfoW(HINTERNET hHttpRequest, DWORD dwInfoLevel, TRACE("\n"); } - lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hHttpRequest ); + lpwhr = (http_request_t*) WININET_GetObject( hHttpRequest ); if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ) { - INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); - goto lend; + res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE; + goto lend; } if (lpBuffer == NULL) *lpdwBufferLength = 0; - bSuccess = HTTP_HttpQueryInfoW( lpwhr, dwInfoLevel, - lpBuffer, lpdwBufferLength, lpdwIndex); + res = HTTP_HttpQueryInfoW( lpwhr, dwInfoLevel, + lpBuffer, lpdwBufferLength, lpdwIndex); lend: if( lpwhr ) WININET_Release( &lpwhr->hdr ); - TRACE("%d <--\n", bSuccess); - return bSuccess; + TRACE("%u <--\n", res); + if(res != ERROR_SUCCESS) + SetLastError(res); + return res == ERROR_SUCCESS; } /*********************************************************************** @@ -2577,287 +3066,74 @@ BOOL WINAPI HttpQueryInfoA(HINTERNET hHttpRequest, DWORD dwInfoLevel, } /*********************************************************************** - * HttpSendRequestExA (WININET.@) - * - * Sends the specified request to the HTTP server and allows chunked - * transfers. - * - * RETURNS - * Success: TRUE - * Failure: FALSE, call GetLastError() for more information. + * HTTP_GetRedirectURL (internal) */ -BOOL WINAPI HttpSendRequestExA(HINTERNET hRequest, - LPINTERNET_BUFFERSA lpBuffersIn, - LPINTERNET_BUFFERSA lpBuffersOut, - DWORD dwFlags, DWORD_PTR dwContext) +static LPWSTR HTTP_GetRedirectURL(http_request_t *lpwhr, LPCWSTR lpszUrl) { - INTERNET_BUFFERSW BuffersInW; - BOOL rc = FALSE; - DWORD headerlen; - LPWSTR header = NULL; + static WCHAR szHttp[] = {'h','t','t','p',0}; + static WCHAR szHttps[] = {'h','t','t','p','s',0}; + http_session_t *lpwhs = lpwhr->lpHttpSession; + URL_COMPONENTSW urlComponents; + DWORD url_length = 0; + LPWSTR orig_url; + LPWSTR combined_url; - TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn, - lpBuffersOut, dwFlags, dwContext); + urlComponents.dwStructSize = sizeof(URL_COMPONENTSW); + urlComponents.lpszScheme = (lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE) ? szHttps : szHttp; + urlComponents.dwSchemeLength = 0; + urlComponents.lpszHostName = lpwhs->lpszHostName; + urlComponents.dwHostNameLength = 0; + urlComponents.nPort = lpwhs->nHostPort; + urlComponents.lpszUserName = lpwhs->lpszUserName; + urlComponents.dwUserNameLength = 0; + urlComponents.lpszPassword = NULL; + urlComponents.dwPasswordLength = 0; + urlComponents.lpszUrlPath = lpwhr->lpszPath; + urlComponents.dwUrlPathLength = 0; + urlComponents.lpszExtraInfo = NULL; + urlComponents.dwExtraInfoLength = 0; - if (lpBuffersIn) + if (!InternetCreateUrlW(&urlComponents, 0, NULL, &url_length) && + (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) + return NULL; + + orig_url = HeapAlloc(GetProcessHeap(), 0, url_length); + + /* convert from bytes to characters */ + url_length = url_length / sizeof(WCHAR) - 1; + if (!InternetCreateUrlW(&urlComponents, 0, orig_url, &url_length)) { - BuffersInW.dwStructSize = sizeof(LPINTERNET_BUFFERSW); - if (lpBuffersIn->lpcszHeader) - { - headerlen = MultiByteToWideChar(CP_ACP,0,lpBuffersIn->lpcszHeader, - lpBuffersIn->dwHeadersLength,0,0); - header = HeapAlloc(GetProcessHeap(),0,headerlen*sizeof(WCHAR)); - if (!(BuffersInW.lpcszHeader = header)) - { - INTERNET_SetLastError(ERROR_OUTOFMEMORY); - return FALSE; - } - BuffersInW.dwHeadersLength = MultiByteToWideChar(CP_ACP, 0, - lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength, - header, headerlen); - } - else - BuffersInW.lpcszHeader = NULL; - BuffersInW.dwHeadersTotal = lpBuffersIn->dwHeadersTotal; - BuffersInW.lpvBuffer = lpBuffersIn->lpvBuffer; - BuffersInW.dwBufferLength = lpBuffersIn->dwBufferLength; - BuffersInW.dwBufferTotal = lpBuffersIn->dwBufferTotal; - BuffersInW.Next = NULL; + HeapFree(GetProcessHeap(), 0, orig_url); + return NULL; } - rc = HttpSendRequestExW(hRequest, lpBuffersIn ? &BuffersInW : NULL, NULL, dwFlags, dwContext); + url_length = 0; + if (!InternetCombineUrlW(orig_url, lpszUrl, NULL, &url_length, ICU_ENCODE_SPACES_ONLY) && + (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) + { + HeapFree(GetProcessHeap(), 0, orig_url); + return NULL; + } + combined_url = HeapAlloc(GetProcessHeap(), 0, url_length * sizeof(WCHAR)); - HeapFree(GetProcessHeap(),0,header); - - return rc; + if (!InternetCombineUrlW(orig_url, lpszUrl, combined_url, &url_length, ICU_ENCODE_SPACES_ONLY)) + { + HeapFree(GetProcessHeap(), 0, orig_url); + HeapFree(GetProcessHeap(), 0, combined_url); + return NULL; + } + HeapFree(GetProcessHeap(), 0, orig_url); + return combined_url; } -/*********************************************************************** - * HttpSendRequestExW (WININET.@) - * - * Sends the specified request to the HTTP server and allows chunked - * transfers - * - * RETURNS - * Success: TRUE - * Failure: FALSE, call GetLastError() for more information. - */ -BOOL WINAPI HttpSendRequestExW(HINTERNET hRequest, - LPINTERNET_BUFFERSW lpBuffersIn, - LPINTERNET_BUFFERSW lpBuffersOut, - DWORD dwFlags, DWORD_PTR dwContext) -{ - BOOL ret = FALSE; - LPWININETHTTPREQW lpwhr; - LPWININETHTTPSESSIONW lpwhs; - LPWININETAPPINFOW hIC; - - TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn, - lpBuffersOut, dwFlags, dwContext); - - lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hRequest ); - - if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ) - { - INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); - goto lend; - } - - lpwhs = lpwhr->lpHttpSession; - assert(lpwhs->hdr.htype == WH_HHTTPSESSION); - hIC = lpwhs->lpAppInfo; - assert(hIC->hdr.htype == WH_HINIT); - - if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) - { - WORKREQUEST workRequest; - struct WORKREQ_HTTPSENDREQUESTW *req; - - workRequest.asyncproc = AsyncHttpSendRequestProc; - workRequest.hdr = WININET_AddRef( &lpwhr->hdr ); - req = &workRequest.u.HttpSendRequestW; - if (lpBuffersIn) - { - if (lpBuffersIn->lpcszHeader) - /* FIXME: this should use dwHeadersLength or may not be necessary at all */ - req->lpszHeader = WININET_strdupW(lpBuffersIn->lpcszHeader); - else - req->lpszHeader = NULL; - req->dwHeaderLength = lpBuffersIn->dwHeadersLength; - req->lpOptional = lpBuffersIn->lpvBuffer; - req->dwOptionalLength = lpBuffersIn->dwBufferLength; - req->dwContentLength = lpBuffersIn->dwBufferTotal; - } - else - { - req->lpszHeader = NULL; - req->dwHeaderLength = 0; - req->lpOptional = NULL; - req->dwOptionalLength = 0; - req->dwContentLength = 0; - } - - req->bEndRequest = FALSE; - - INTERNET_AsyncCall(&workRequest); - /* - * This is from windows. - */ - INTERNET_SetLastError(ERROR_IO_PENDING); - } - else - { - if (lpBuffersIn) - ret = HTTP_HttpSendRequestW(lpwhr, lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength, - lpBuffersIn->lpvBuffer, lpBuffersIn->dwBufferLength, - lpBuffersIn->dwBufferTotal, FALSE); - else - ret = HTTP_HttpSendRequestW(lpwhr, NULL, 0, NULL, 0, 0, FALSE); - } - -lend: - if ( lpwhr ) - WININET_Release( &lpwhr->hdr ); - - TRACE("<---\n"); - return ret; -} - -/*********************************************************************** - * HttpSendRequestW (WININET.@) - * - * Sends the specified request to the HTTP server - * - * RETURNS - * TRUE on success - * FALSE on failure - * - */ -BOOL WINAPI HttpSendRequestW(HINTERNET hHttpRequest, LPCWSTR lpszHeaders, - DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength) -{ - LPWININETHTTPREQW lpwhr; - LPWININETHTTPSESSIONW lpwhs = NULL; - LPWININETAPPINFOW hIC = NULL; - BOOL r; - - TRACE("%p, %s, %i, %p, %i)\n", hHttpRequest, - debugstr_wn(lpszHeaders, dwHeaderLength), dwHeaderLength, lpOptional, dwOptionalLength); - - lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hHttpRequest ); - if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ) - { - INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); - r = FALSE; - goto lend; - } - - lpwhs = lpwhr->lpHttpSession; - if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION) - { - INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); - r = FALSE; - goto lend; - } - - hIC = lpwhs->lpAppInfo; - if (NULL == hIC || hIC->hdr.htype != WH_HINIT) - { - INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); - r = FALSE; - goto lend; - } - - if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) - { - WORKREQUEST workRequest; - struct WORKREQ_HTTPSENDREQUESTW *req; - - workRequest.asyncproc = AsyncHttpSendRequestProc; - workRequest.hdr = WININET_AddRef( &lpwhr->hdr ); - req = &workRequest.u.HttpSendRequestW; - if (lpszHeaders) - { - req->lpszHeader = HeapAlloc(GetProcessHeap(), 0, dwHeaderLength * sizeof(WCHAR)); - memcpy(req->lpszHeader, lpszHeaders, dwHeaderLength * sizeof(WCHAR)); - } - else - req->lpszHeader = 0; - req->dwHeaderLength = dwHeaderLength; - req->lpOptional = lpOptional; - req->dwOptionalLength = dwOptionalLength; - req->dwContentLength = dwOptionalLength; - req->bEndRequest = TRUE; - - INTERNET_AsyncCall(&workRequest); - /* - * This is from windows. - */ - INTERNET_SetLastError(ERROR_IO_PENDING); - r = FALSE; - } - else - { - r = HTTP_HttpSendRequestW(lpwhr, lpszHeaders, - dwHeaderLength, lpOptional, dwOptionalLength, - dwOptionalLength, TRUE); - } -lend: - if( lpwhr ) - WININET_Release( &lpwhr->hdr ); - return r; -} - -/*********************************************************************** - * HttpSendRequestA (WININET.@) - * - * Sends the specified request to the HTTP server - * - * RETURNS - * TRUE on success - * FALSE on failure - * - */ -BOOL WINAPI HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders, - DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength) -{ - BOOL result; - LPWSTR szHeaders=NULL; - DWORD nLen=dwHeaderLength; - if(lpszHeaders!=NULL) - { - nLen=MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,NULL,0); - szHeaders=HeapAlloc(GetProcessHeap(),0,nLen*sizeof(WCHAR)); - MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,szHeaders,nLen); - } - result=HttpSendRequestW(hHttpRequest, szHeaders, nLen, lpOptional, dwOptionalLength); - HeapFree(GetProcessHeap(),0,szHeaders); - return result; -} - -static BOOL HTTP_GetRequestURL(WININETHTTPREQW *req, LPWSTR buf) -{ - LPHTTPHEADERW host_header; - - static const WCHAR formatW[] = {'h','t','t','p',':','/','/','%','s','%','s',0}; - - host_header = HTTP_GetHeader(req, szHost); - if(!host_header) - return FALSE; - - sprintfW(buf, formatW, host_header->lpszValue, req->lpszPath); /* FIXME */ - return TRUE; -} /*********************************************************************** * HTTP_HandleRedirect (internal) */ -static BOOL HTTP_HandleRedirect(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl) +static DWORD HTTP_HandleRedirect(http_request_t *lpwhr, LPCWSTR lpszUrl) { - static const WCHAR szContentType[] = {'C','o','n','t','e','n','t','-','T','y','p','e',0}; - static const WCHAR szContentLength[] = {'C','o','n','t','e','n','t','-','L','e','n','g','t','h',0}; - LPWININETHTTPSESSIONW lpwhs = lpwhr->lpHttpSession; - LPWININETAPPINFOW hIC = lpwhs->lpAppInfo; + http_session_t *lpwhs = lpwhr->lpHttpSession; + appinfo_t *hIC = lpwhs->lpAppInfo; BOOL using_proxy = hIC->lpszProxy && hIC->lpszProxy[0]; WCHAR path[INTERNET_MAX_URL_LENGTH]; int index; @@ -2873,55 +3149,6 @@ static BOOL HTTP_HandleRedirect(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl) WCHAR protocol[32], hostName[MAXHOSTNAME], userName[1024]; static WCHAR szHttp[] = {'h','t','t','p',0}; static WCHAR szHttps[] = {'h','t','t','p','s',0}; - DWORD url_length = 0; - LPWSTR orig_url; - LPWSTR combined_url; - - urlComponents.dwStructSize = sizeof(URL_COMPONENTSW); - urlComponents.lpszScheme = (lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE) ? szHttps : szHttp; - urlComponents.dwSchemeLength = 0; - urlComponents.lpszHostName = lpwhs->lpszHostName; - urlComponents.dwHostNameLength = 0; - urlComponents.nPort = lpwhs->nHostPort; - urlComponents.lpszUserName = lpwhs->lpszUserName; - urlComponents.dwUserNameLength = 0; - urlComponents.lpszPassword = NULL; - urlComponents.dwPasswordLength = 0; - urlComponents.lpszUrlPath = lpwhr->lpszPath; - urlComponents.dwUrlPathLength = 0; - urlComponents.lpszExtraInfo = NULL; - urlComponents.dwExtraInfoLength = 0; - - if (!InternetCreateUrlW(&urlComponents, 0, NULL, &url_length) && - (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) - return FALSE; - - orig_url = HeapAlloc(GetProcessHeap(), 0, url_length); - - /* convert from bytes to characters */ - url_length = url_length / sizeof(WCHAR) - 1; - if (!InternetCreateUrlW(&urlComponents, 0, orig_url, &url_length)) - { - HeapFree(GetProcessHeap(), 0, orig_url); - return FALSE; - } - - url_length = 0; - if (!InternetCombineUrlW(orig_url, lpszUrl, NULL, &url_length, ICU_ENCODE_SPACES_ONLY) && - (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) - { - HeapFree(GetProcessHeap(), 0, orig_url); - return FALSE; - } - combined_url = HeapAlloc(GetProcessHeap(), 0, url_length * sizeof(WCHAR)); - - if (!InternetCombineUrlW(orig_url, lpszUrl, combined_url, &url_length, ICU_ENCODE_SPACES_ONLY)) - { - HeapFree(GetProcessHeap(), 0, orig_url); - HeapFree(GetProcessHeap(), 0, combined_url); - return FALSE; - } - HeapFree(GetProcessHeap(), 0, orig_url); userName[0] = 0; hostName[0] = 0; @@ -2940,13 +3167,8 @@ static BOOL HTTP_HandleRedirect(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl) urlComponents.dwUrlPathLength = 2048; urlComponents.lpszExtraInfo = NULL; urlComponents.dwExtraInfoLength = 0; - if(!InternetCrackUrlW(combined_url, strlenW(combined_url), 0, &urlComponents)) - { - HeapFree(GetProcessHeap(), 0, combined_url); - return FALSE; - } - - HeapFree(GetProcessHeap(), 0, combined_url); + if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents)) + return INTERNET_GetLastError(); if (!strncmpW(szHttp, urlComponents.lpszScheme, strlenW(szHttp)) && (lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE)) @@ -3000,26 +3222,35 @@ static BOOL HTTP_HandleRedirect(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl) sprintfW(lpwhs->lpszHostName, fmt, hostName, urlComponents.nPort); } else - lpwhs->lpszHostName = WININET_strdupW(hostName); + lpwhs->lpszHostName = heap_strdupW(hostName); - HTTP_ProcessHeader(lpwhr, szHost, lpwhs->lpszHostName, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDHDR_FLAG_REQ); + HTTP_ProcessHeader(lpwhr, hostW, lpwhs->lpszHostName, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDHDR_FLAG_REQ); HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName); lpwhs->lpszUserName = NULL; if (userName[0]) - lpwhs->lpszUserName = WININET_strdupW(userName); + lpwhs->lpszUserName = heap_strdupW(userName); if (!using_proxy) { if (strcmpiW(lpwhs->lpszServerName, hostName) || lpwhs->nServerPort != urlComponents.nPort) { + DWORD res; + HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName); - lpwhs->lpszServerName = WININET_strdupW(hostName); + lpwhs->lpszServerName = heap_strdupW(hostName); lpwhs->nServerPort = urlComponents.nPort; NETCON_close(&lpwhr->netConnection); - if (!HTTP_ResolveName(lpwhr)) return FALSE; - if (!NETCON_init(&lpwhr->netConnection, lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE)) return FALSE; + if ((res = HTTP_ResolveName(lpwhr)) != ERROR_SUCCESS) + return res; + + res = NETCON_init(&lpwhr->netConnection, lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE); + if (res != ERROR_SUCCESS) + return res; + + lpwhr->read_pos = lpwhr->read_size = 0; + lpwhr->read_chunked = FALSE; } } else @@ -3039,7 +3270,7 @@ static BOOL HTTP_HandleRedirect(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl) lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, needed*sizeof(WCHAR)); rc = UrlEscapeW(path, lpwhr->lpszPath, &needed, URL_ESCAPE_SPACES_ONLY); - if (rc) + if (rc != S_OK) { ERR("Unable to escape string!(%s) (%d)\n",debugstr_w(path),rc); strcpyW(lpwhr->lpszPath,path); @@ -3047,14 +3278,14 @@ static BOOL HTTP_HandleRedirect(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl) } /* Remove custom content-type/length headers on redirects. */ - index = HTTP_GetCustomHeaderIndex(lpwhr, szContentType, 0, TRUE); + index = HTTP_GetCustomHeaderIndex(lpwhr, szContent_Type, 0, TRUE); if (0 <= index) HTTP_DeleteCustomHeader(lpwhr, index); - index = HTTP_GetCustomHeaderIndex(lpwhr, szContentLength, 0, TRUE); + index = HTTP_GetCustomHeaderIndex(lpwhr, szContent_Length, 0, TRUE); if (0 <= index) HTTP_DeleteCustomHeader(lpwhr, index); - return TRUE; + return ERROR_SUCCESS; } /*********************************************************************** @@ -3080,7 +3311,7 @@ static LPWSTR HTTP_build_req( LPCWSTR *list, int len ) return str; } -static BOOL HTTP_SecureProxyConnect(LPWININETHTTPREQW lpwhr) +static DWORD HTTP_SecureProxyConnect(http_request_t *lpwhr) { LPWSTR lpszPath; LPWSTR requestString; @@ -3088,10 +3319,10 @@ static BOOL HTTP_SecureProxyConnect(LPWININETHTTPREQW lpwhr) INT cnt; INT responseLen; char *ascii_req; - BOOL ret; + DWORD res; static const WCHAR szConnect[] = {'C','O','N','N','E','C','T',0}; static const WCHAR szFormat[] = {'%','s',':','%','d',0}; - LPWININETHTTPSESSIONW lpwhs = lpwhr->lpHttpSession; + http_session_t *lpwhs = lpwhr->lpHttpSession; TRACE("\n"); @@ -3110,43 +3341,42 @@ static BOOL HTTP_SecureProxyConnect(LPWININETHTTPREQW lpwhr) TRACE("full request -> %s\n", debugstr_an( ascii_req, len ) ); - ret = NETCON_send( &lpwhr->netConnection, ascii_req, len, 0, &cnt ); + res = NETCON_send( &lpwhr->netConnection, ascii_req, len, 0, &cnt ); HeapFree( GetProcessHeap(), 0, ascii_req ); - if (!ret || cnt < 0) - return FALSE; + if (res != ERROR_SUCCESS) + return res; responseLen = HTTP_GetResponseHeaders( lpwhr, TRUE ); if (!responseLen) - return FALSE; + return ERROR_HTTP_INVALID_HEADER; - return TRUE; + return ERROR_SUCCESS; } -static void HTTP_InsertCookies(LPWININETHTTPREQW lpwhr) +static void HTTP_InsertCookies(http_request_t *lpwhr) { - static const WCHAR szUrlForm[] = {'h','t','t','p',':','/','/','%','s',0}; + static const WCHAR szUrlForm[] = {'h','t','t','p',':','/','/','%','s','%','s',0}; LPWSTR lpszCookies, lpszUrl = NULL; DWORD nCookieSize, size; - LPHTTPHEADERW Host = HTTP_GetHeader(lpwhr,szHost); + LPHTTPHEADERW Host = HTTP_GetHeader(lpwhr, hostW); - size = (strlenW(Host->lpszValue) + strlenW(szUrlForm)) * sizeof(WCHAR); + size = (strlenW(Host->lpszValue) + strlenW(szUrlForm) + strlenW(lpwhr->lpszPath)) * sizeof(WCHAR); if (!(lpszUrl = HeapAlloc(GetProcessHeap(), 0, size))) return; - sprintfW( lpszUrl, szUrlForm, Host->lpszValue ); + sprintfW( lpszUrl, szUrlForm, Host->lpszValue, lpwhr->lpszPath); if (InternetGetCookieW(lpszUrl, NULL, NULL, &nCookieSize)) { int cnt = 0; static const WCHAR szCookie[] = {'C','o','o','k','i','e',':',' ',0}; - static const WCHAR szcrlf[] = {'\r','\n',0}; - size = sizeof(szCookie) + nCookieSize * sizeof(WCHAR) + sizeof(szcrlf); + size = sizeof(szCookie) + nCookieSize * sizeof(WCHAR) + sizeof(szCrLf); if ((lpszCookies = HeapAlloc(GetProcessHeap(), 0, size))) { cnt += sprintfW(lpszCookies, szCookie); InternetGetCookieW(lpszUrl, NULL, lpszCookies + cnt, &nCookieSize); - strcatW(lpszCookies, szcrlf); + strcatW(lpszCookies, szCrLf); - HTTP_HttpAddRequestHeadersW(lpwhr, lpszCookies, strlenW(lpszCookies), HTTP_ADDREQ_FLAG_ADD); + HTTP_HttpAddRequestHeadersW(lpwhr, lpszCookies, strlenW(lpszCookies), HTTP_ADDREQ_FLAG_REPLACE); HeapFree(GetProcessHeap(), 0, lpszCookies); } } @@ -3163,12 +3393,12 @@ static void HTTP_InsertCookies(LPWININETHTTPREQW lpwhr) * FALSE on failure * */ -BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, +static DWORD HTTP_HttpSendRequestW(http_request_t *lpwhr, LPCWSTR lpszHeaders, DWORD dwHeaderLength, LPVOID lpOptional, DWORD dwOptionalLength, DWORD dwContentLength, BOOL bEndRequest) { INT cnt; - BOOL bSuccess = FALSE; + BOOL redirected = FALSE; LPWSTR requestString = NULL; INT responseLen; BOOL loop_next; @@ -3177,6 +3407,7 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, static const WCHAR szContentLength[] = { 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',':',' ','%','l','i','\r','\n',0 }; WCHAR contentLengthStr[sizeof szContentLength/2 /* includes \r\n */ + 20 /* int */ ]; + DWORD res; TRACE("--> %p\n", lpwhr); @@ -3184,12 +3415,13 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, /* if the verb is NULL default to GET */ if (!lpwhr->lpszVerb) - lpwhr->lpszVerb = WININET_strdupW(szGET); + lpwhr->lpszVerb = heap_strdupW(szGET); - if (dwContentLength || !strcmpW(lpwhr->lpszVerb, szPost)) + if (dwContentLength || strcmpW(lpwhr->lpszVerb, szGET)) { sprintfW(contentLengthStr, szContentLength, dwContentLength); - HTTP_HttpAddRequestHeadersW(lpwhr, contentLengthStr, -1L, HTTP_ADDREQ_FLAG_ADD_IF_NEW); + HTTP_HttpAddRequestHeadersW(lpwhr, contentLengthStr, -1L, HTTP_ADDREQ_FLAG_REPLACE); + lpwhr->dwBytesToWrite = dwContentLength; } if (lpwhr->lpHttpSession->lpAppInfo->lpszAgent) { @@ -3230,7 +3462,7 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, if (TRACE_ON(wininet)) { - LPHTTPHEADERW Host = HTTP_GetHeader(lpwhr,szHost); + LPHTTPHEADERW Host = HTTP_GetHeader(lpwhr, hostW); TRACE("Going to url %s %s\n", debugstr_w(Host->lpszValue), debugstr_w(lpwhr->lpszPath)); } @@ -3265,11 +3497,11 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, TRACE("Request header -> %s\n", debugstr_w(requestString) ); /* Send the request and store the results */ - if (!HTTP_OpenConnection(lpwhr)) + if ((res = HTTP_OpenConnection(lpwhr)) != ERROR_SUCCESS) goto lend; /* send the request as ASCII, tack on the optional data */ - if( !lpOptional ) + if (!lpOptional || redirected) dwOptionalLength = 0; len = WideCharToMultiByte( CP_ACP, 0, requestString, -1, NULL, 0, NULL, NULL ); @@ -3285,9 +3517,11 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0); - NETCON_send(&lpwhr->netConnection, ascii_req, len, 0, &cnt); + res = NETCON_send(&lpwhr->netConnection, ascii_req, len, 0, &cnt); HeapFree( GetProcessHeap(), 0, ascii_req ); + lpwhr->dwBytesWritten = dwOptionalLength; + INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_REQUEST_SENT, &len, sizeof(DWORD)); @@ -3296,18 +3530,14 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, { DWORD dwBufferSize; DWORD dwStatusCode; - WCHAR encoding[20]; - static const WCHAR szChunked[] = {'c','h','u','n','k','e','d',0}; INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0); - if (cnt < 0) + if (res != ERROR_SUCCESS) goto lend; responseLen = HTTP_GetResponseHeaders(lpwhr, TRUE); - if (responseLen) - bSuccess = TRUE; INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen, @@ -3315,61 +3545,58 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, HTTP_ProcessCookies(lpwhr); - dwBufferSize = sizeof(lpwhr->dwContentLength); - if (!HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_CONTENT_LENGTH, - &lpwhr->dwContentLength,&dwBufferSize,NULL)) - lpwhr->dwContentLength = -1; - - if (lpwhr->dwContentLength == 0) - HTTP_FinishedReading(lpwhr); - - /* Correct the case where both a Content-Length and Transfer-encoding = chunked are set */ - - dwBufferSize = sizeof(encoding); - if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_TRANSFER_ENCODING, encoding, &dwBufferSize, NULL) && - !strcmpiW(encoding, szChunked)) - { - lpwhr->dwContentLength = -1; - } + if (!set_content_length( lpwhr )) HTTP_FinishedReading(lpwhr); dwBufferSize = sizeof(dwStatusCode); - if (!HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE, - &dwStatusCode,&dwBufferSize,NULL)) + if (HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE, + &dwStatusCode,&dwBufferSize,NULL) != ERROR_SUCCESS) dwStatusCode = 0; - if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT) && bSuccess) + if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT) && responseLen) { - WCHAR szNewLocation[INTERNET_MAX_URL_LENGTH]; + WCHAR *new_url, szNewLocation[INTERNET_MAX_URL_LENGTH]; dwBufferSize=sizeof(szNewLocation); if ((dwStatusCode==HTTP_STATUS_REDIRECT || dwStatusCode==HTTP_STATUS_MOVED) && - HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_LOCATION,szNewLocation,&dwBufferSize,NULL)) + HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_LOCATION,szNewLocation,&dwBufferSize,NULL) == ERROR_SUCCESS) { - HTTP_DrainContent(lpwhr); - INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, - INTERNET_STATUS_REDIRECT, szNewLocation, - dwBufferSize); - bSuccess = HTTP_HandleRedirect(lpwhr, szNewLocation); - if (bSuccess) + if (strcmpW(lpwhr->lpszVerb, szGET) && strcmpW(lpwhr->lpszVerb, szHEAD)) { - HeapFree(GetProcessHeap(), 0, requestString); - loop_next = TRUE; + HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb); + lpwhr->lpszVerb = heap_strdupW(szGET); } + HTTP_DrainContent(lpwhr); + if ((new_url = HTTP_GetRedirectURL( lpwhr, szNewLocation ))) + { + INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_REDIRECT, + new_url, (strlenW(new_url) + 1) * sizeof(WCHAR)); + res = HTTP_HandleRedirect(lpwhr, new_url); + if (res == ERROR_SUCCESS) + { + HeapFree(GetProcessHeap(), 0, requestString); + loop_next = TRUE; + } + HeapFree( GetProcessHeap(), 0, new_url ); + } + redirected = TRUE; } } - if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTH) && bSuccess) + if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTH) && res == ERROR_SUCCESS) { WCHAR szAuthValue[2048]; dwBufferSize=2048; if (dwStatusCode == HTTP_STATUS_DENIED) { + LPHTTPHEADERW Host = HTTP_GetHeader(lpwhr, hostW); DWORD dwIndex = 0; - while (HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_WWW_AUTHENTICATE,szAuthValue,&dwBufferSize,&dwIndex)) + while (HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_WWW_AUTHENTICATE,szAuthValue,&dwBufferSize,&dwIndex) == ERROR_SUCCESS) { if (HTTP_DoAuthorization(lpwhr, szAuthValue, &lpwhr->pAuthInfo, lpwhr->lpHttpSession->lpszUserName, - lpwhr->lpHttpSession->lpszPassword)) + lpwhr->lpHttpSession->lpszPassword, + Host->lpszValue)) { + HeapFree(GetProcessHeap(), 0, requestString); loop_next = TRUE; break; } @@ -3378,12 +3605,13 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, if (dwStatusCode == HTTP_STATUS_PROXY_AUTH_REQ) { DWORD dwIndex = 0; - while (HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_PROXY_AUTHENTICATE,szAuthValue,&dwBufferSize,&dwIndex)) + while (HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_PROXY_AUTHENTICATE,szAuthValue,&dwBufferSize,&dwIndex) == ERROR_SUCCESS) { if (HTTP_DoAuthorization(lpwhr, szAuthValue, &lpwhr->pProxyAuthInfo, lpwhr->lpHttpSession->lpAppInfo->lpszProxyUsername, - lpwhr->lpHttpSession->lpAppInfo->lpszProxyPassword)) + lpwhr->lpHttpSession->lpAppInfo->lpszProxyPassword, + NULL)) { loop_next = TRUE; break; @@ -3393,12 +3621,11 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, } } else - bSuccess = TRUE; + res = ERROR_SUCCESS; } while (loop_next); - /* FIXME: Better check, when we have to create the cache file */ - if(bSuccess && (lpwhr->hdr.dwFlags & INTERNET_FLAG_NEED_FILE)) { + if(res == ERROR_SUCCESS) { WCHAR url[INTERNET_MAX_URL_LENGTH]; WCHAR cacheFileName[MAX_PATH+1]; BOOL b; @@ -3411,7 +3638,10 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, b = CreateUrlCacheEntryW(url, lpwhr->dwContentLength > 0 ? lpwhr->dwContentLength : 0, NULL, cacheFileName, 0); if(b) { - lpwhr->lpszCacheFile = WININET_strdupW(cacheFileName); + HeapFree(GetProcessHeap(), 0, lpwhr->lpszCacheFile); + CloseHandle(lpwhr->hCacheFile); + + lpwhr->lpszCacheFile = heap_strdupW(cacheFileName); lpwhr->hCacheFile = CreateFileW(lpwhr->lpszCacheFile, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if(lpwhr->hCacheFile == INVALID_HANDLE_VALUE) { @@ -3429,16 +3659,469 @@ lend: /* TODO: send notification for P3P header */ + if (lpwhr->lpHttpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC) + { + if (res == ERROR_SUCCESS && lpwhr->dwBytesWritten == lpwhr->dwBytesToWrite) + HTTP_ReceiveRequestData(lpwhr, TRUE); + else + { + iar.dwResult = (DWORD_PTR)lpwhr->hdr.hInternet; + iar.dwError = res; + + INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, + INTERNET_STATUS_REQUEST_COMPLETE, &iar, + sizeof(INTERNET_ASYNC_RESULT)); + } + } + + TRACE("<--\n"); + return res; +} + +/*********************************************************************** + * + * Helper functions for the HttpSendRequest(Ex) functions + * + */ +static void AsyncHttpSendRequestProc(WORKREQUEST *workRequest) +{ + struct WORKREQ_HTTPSENDREQUESTW const *req = &workRequest->u.HttpSendRequestW; + http_request_t *lpwhr = (http_request_t*) workRequest->hdr; + + TRACE("%p\n", lpwhr); + + HTTP_HttpSendRequestW(lpwhr, req->lpszHeader, + req->dwHeaderLength, req->lpOptional, req->dwOptionalLength, + req->dwContentLength, req->bEndRequest); + + HeapFree(GetProcessHeap(), 0, req->lpszHeader); +} + + +static DWORD HTTP_HttpEndRequestW(http_request_t *lpwhr, DWORD dwFlags, DWORD_PTR dwContext) +{ + INT responseLen; + DWORD dwBufferSize; + INTERNET_ASYNC_RESULT iar; + DWORD res = ERROR_SUCCESS; + + INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, + INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0); + + responseLen = HTTP_GetResponseHeaders(lpwhr, TRUE); + if (!responseLen) + res = ERROR_HTTP_HEADER_NOT_FOUND; + + INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, + INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen, sizeof(DWORD)); + + /* process cookies here. Is this right? */ + HTTP_ProcessCookies(lpwhr); + + if (!set_content_length( lpwhr )) HTTP_FinishedReading(lpwhr); + + if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT)) + { + DWORD dwCode,dwCodeLength = sizeof(DWORD); + if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE, &dwCode, &dwCodeLength, NULL) == ERROR_SUCCESS + && (dwCode == 302 || dwCode == 301 || dwCode == 303)) + { + WCHAR *new_url, szNewLocation[INTERNET_MAX_URL_LENGTH]; + dwBufferSize=sizeof(szNewLocation); + if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_LOCATION, szNewLocation, &dwBufferSize, NULL) == ERROR_SUCCESS) + { + if (strcmpW(lpwhr->lpszVerb, szGET) && strcmpW(lpwhr->lpszVerb, szHEAD)) + { + HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb); + lpwhr->lpszVerb = heap_strdupW(szGET); + } + HTTP_DrainContent(lpwhr); + if ((new_url = HTTP_GetRedirectURL( lpwhr, szNewLocation ))) + { + INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_REDIRECT, + new_url, (strlenW(new_url) + 1) * sizeof(WCHAR)); + res = HTTP_HandleRedirect(lpwhr, new_url); + if (res == ERROR_SUCCESS) + res = HTTP_HttpSendRequestW(lpwhr, NULL, 0, NULL, 0, 0, TRUE); + HeapFree( GetProcessHeap(), 0, new_url ); + } + } + } + } + iar.dwResult = (DWORD_PTR)lpwhr->hdr.hInternet; - iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError(); + iar.dwError = res; INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, &iar, sizeof(INTERNET_ASYNC_RESULT)); + return res; +} - TRACE("<--\n"); - if (bSuccess) INTERNET_SetLastError(ERROR_SUCCESS); - return bSuccess; +/*********************************************************************** + * HttpEndRequestA (WININET.@) + * + * Ends an HTTP request that was started by HttpSendRequestEx + * + * RETURNS + * TRUE if successful + * FALSE on failure + * + */ +BOOL WINAPI HttpEndRequestA(HINTERNET hRequest, + LPINTERNET_BUFFERSA lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext) +{ + TRACE("(%p, %p, %08x, %08lx)\n", hRequest, lpBuffersOut, dwFlags, dwContext); + + if (lpBuffersOut) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + return HttpEndRequestW(hRequest, NULL, dwFlags, dwContext); +} + +static void AsyncHttpEndRequestProc(WORKREQUEST *work) +{ + struct WORKREQ_HTTPENDREQUESTW const *req = &work->u.HttpEndRequestW; + http_request_t *lpwhr = (http_request_t*)work->hdr; + + TRACE("%p\n", lpwhr); + + HTTP_HttpEndRequestW(lpwhr, req->dwFlags, req->dwContext); +} + +/*********************************************************************** + * HttpEndRequestW (WININET.@) + * + * Ends an HTTP request that was started by HttpSendRequestEx + * + * RETURNS + * TRUE if successful + * FALSE on failure + * + */ +BOOL WINAPI HttpEndRequestW(HINTERNET hRequest, + LPINTERNET_BUFFERSW lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext) +{ + http_request_t *lpwhr; + DWORD res; + + TRACE("-->\n"); + + if (lpBuffersOut) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + lpwhr = (http_request_t*) WININET_GetObject( hRequest ); + + if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ) + { + SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); + if (lpwhr) + WININET_Release( &lpwhr->hdr ); + return FALSE; + } + lpwhr->hdr.dwFlags |= dwFlags; + + if (lpwhr->lpHttpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC) + { + WORKREQUEST work; + struct WORKREQ_HTTPENDREQUESTW *request; + + work.asyncproc = AsyncHttpEndRequestProc; + work.hdr = WININET_AddRef( &lpwhr->hdr ); + + request = &work.u.HttpEndRequestW; + request->dwFlags = dwFlags; + request->dwContext = dwContext; + + INTERNET_AsyncCall(&work); + res = ERROR_IO_PENDING; + } + else + res = HTTP_HttpEndRequestW(lpwhr, dwFlags, dwContext); + + WININET_Release( &lpwhr->hdr ); + TRACE("%u <--\n", res); + if(res != ERROR_SUCCESS) + SetLastError(res); + return res == ERROR_SUCCESS; +} + +/*********************************************************************** + * HttpSendRequestExA (WININET.@) + * + * Sends the specified request to the HTTP server and allows chunked + * transfers. + * + * RETURNS + * Success: TRUE + * Failure: FALSE, call GetLastError() for more information. + */ +BOOL WINAPI HttpSendRequestExA(HINTERNET hRequest, + LPINTERNET_BUFFERSA lpBuffersIn, + LPINTERNET_BUFFERSA lpBuffersOut, + DWORD dwFlags, DWORD_PTR dwContext) +{ + INTERNET_BUFFERSW BuffersInW; + BOOL rc = FALSE; + DWORD headerlen; + LPWSTR header = NULL; + + TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn, + lpBuffersOut, dwFlags, dwContext); + + if (lpBuffersIn) + { + BuffersInW.dwStructSize = sizeof(LPINTERNET_BUFFERSW); + if (lpBuffersIn->lpcszHeader) + { + headerlen = MultiByteToWideChar(CP_ACP,0,lpBuffersIn->lpcszHeader, + lpBuffersIn->dwHeadersLength,0,0); + header = HeapAlloc(GetProcessHeap(),0,headerlen*sizeof(WCHAR)); + if (!(BuffersInW.lpcszHeader = header)) + { + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } + BuffersInW.dwHeadersLength = MultiByteToWideChar(CP_ACP, 0, + lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength, + header, headerlen); + } + else + BuffersInW.lpcszHeader = NULL; + BuffersInW.dwHeadersTotal = lpBuffersIn->dwHeadersTotal; + BuffersInW.lpvBuffer = lpBuffersIn->lpvBuffer; + BuffersInW.dwBufferLength = lpBuffersIn->dwBufferLength; + BuffersInW.dwBufferTotal = lpBuffersIn->dwBufferTotal; + BuffersInW.Next = NULL; + } + + rc = HttpSendRequestExW(hRequest, lpBuffersIn ? &BuffersInW : NULL, NULL, dwFlags, dwContext); + + HeapFree(GetProcessHeap(),0,header); + + return rc; +} + +/*********************************************************************** + * HttpSendRequestExW (WININET.@) + * + * Sends the specified request to the HTTP server and allows chunked + * transfers + * + * RETURNS + * Success: TRUE + * Failure: FALSE, call GetLastError() for more information. + */ +BOOL WINAPI HttpSendRequestExW(HINTERNET hRequest, + LPINTERNET_BUFFERSW lpBuffersIn, + LPINTERNET_BUFFERSW lpBuffersOut, + DWORD dwFlags, DWORD_PTR dwContext) +{ + http_request_t *lpwhr; + http_session_t *lpwhs; + appinfo_t *hIC; + DWORD res; + + TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn, + lpBuffersOut, dwFlags, dwContext); + + lpwhr = (http_request_t*) WININET_GetObject( hRequest ); + + if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ) + { + res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE; + goto lend; + } + + lpwhs = lpwhr->lpHttpSession; + assert(lpwhs->hdr.htype == WH_HHTTPSESSION); + hIC = lpwhs->lpAppInfo; + assert(hIC->hdr.htype == WH_HINIT); + + if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) + { + WORKREQUEST workRequest; + struct WORKREQ_HTTPSENDREQUESTW *req; + + workRequest.asyncproc = AsyncHttpSendRequestProc; + workRequest.hdr = WININET_AddRef( &lpwhr->hdr ); + req = &workRequest.u.HttpSendRequestW; + if (lpBuffersIn) + { + DWORD size = 0; + + if (lpBuffersIn->lpcszHeader) + { + if (lpBuffersIn->dwHeadersLength == ~0u) + size = (strlenW( lpBuffersIn->lpcszHeader ) + 1) * sizeof(WCHAR); + else + size = lpBuffersIn->dwHeadersLength * sizeof(WCHAR); + + req->lpszHeader = HeapAlloc( GetProcessHeap(), 0, size ); + memcpy( req->lpszHeader, lpBuffersIn->lpcszHeader, size ); + } + else req->lpszHeader = NULL; + + req->dwHeaderLength = size / sizeof(WCHAR); + req->lpOptional = lpBuffersIn->lpvBuffer; + req->dwOptionalLength = lpBuffersIn->dwBufferLength; + req->dwContentLength = lpBuffersIn->dwBufferTotal; + } + else + { + req->lpszHeader = NULL; + req->dwHeaderLength = 0; + req->lpOptional = NULL; + req->dwOptionalLength = 0; + req->dwContentLength = 0; + } + + req->bEndRequest = FALSE; + + INTERNET_AsyncCall(&workRequest); + /* + * This is from windows. + */ + res = ERROR_IO_PENDING; + } + else + { + if (lpBuffersIn) + res = HTTP_HttpSendRequestW(lpwhr, lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength, + lpBuffersIn->lpvBuffer, lpBuffersIn->dwBufferLength, + lpBuffersIn->dwBufferTotal, FALSE); + else + res = HTTP_HttpSendRequestW(lpwhr, NULL, 0, NULL, 0, 0, FALSE); + } + +lend: + if ( lpwhr ) + WININET_Release( &lpwhr->hdr ); + + TRACE("<---\n"); + SetLastError(res); + return res == ERROR_SUCCESS; +} + +/*********************************************************************** + * HttpSendRequestW (WININET.@) + * + * Sends the specified request to the HTTP server + * + * RETURNS + * TRUE on success + * FALSE on failure + * + */ +BOOL WINAPI HttpSendRequestW(HINTERNET hHttpRequest, LPCWSTR lpszHeaders, + DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength) +{ + http_request_t *lpwhr; + http_session_t *lpwhs = NULL; + appinfo_t *hIC = NULL; + DWORD res = ERROR_SUCCESS; + + TRACE("%p, %s, %i, %p, %i)\n", hHttpRequest, + debugstr_wn(lpszHeaders, dwHeaderLength), dwHeaderLength, lpOptional, dwOptionalLength); + + lpwhr = (http_request_t*) WININET_GetObject( hHttpRequest ); + if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ) + { + res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE; + goto lend; + } + + lpwhs = lpwhr->lpHttpSession; + if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION) + { + res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE; + goto lend; + } + + hIC = lpwhs->lpAppInfo; + if (NULL == hIC || hIC->hdr.htype != WH_HINIT) + { + res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE; + goto lend; + } + + if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) + { + WORKREQUEST workRequest; + struct WORKREQ_HTTPSENDREQUESTW *req; + + workRequest.asyncproc = AsyncHttpSendRequestProc; + workRequest.hdr = WININET_AddRef( &lpwhr->hdr ); + req = &workRequest.u.HttpSendRequestW; + if (lpszHeaders) + { + DWORD size; + + if (dwHeaderLength == ~0u) size = (strlenW(lpszHeaders) + 1) * sizeof(WCHAR); + else size = dwHeaderLength * sizeof(WCHAR); + + req->lpszHeader = HeapAlloc(GetProcessHeap(), 0, size); + memcpy(req->lpszHeader, lpszHeaders, size); + } + else + req->lpszHeader = 0; + req->dwHeaderLength = dwHeaderLength; + req->lpOptional = lpOptional; + req->dwOptionalLength = dwOptionalLength; + req->dwContentLength = dwOptionalLength; + req->bEndRequest = TRUE; + + INTERNET_AsyncCall(&workRequest); + /* + * This is from windows. + */ + res = ERROR_IO_PENDING; + } + else + { + res = HTTP_HttpSendRequestW(lpwhr, lpszHeaders, + dwHeaderLength, lpOptional, dwOptionalLength, + dwOptionalLength, TRUE); + } +lend: + if( lpwhr ) + WININET_Release( &lpwhr->hdr ); + + SetLastError(res); + return res == ERROR_SUCCESS; +} + +/*********************************************************************** + * HttpSendRequestA (WININET.@) + * + * Sends the specified request to the HTTP server + * + * RETURNS + * TRUE on success + * FALSE on failure + * + */ +BOOL WINAPI HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders, + DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength) +{ + BOOL result; + LPWSTR szHeaders=NULL; + DWORD nLen=dwHeaderLength; + if(lpszHeaders!=NULL) + { + nLen=MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,NULL,0); + szHeaders=HeapAlloc(GetProcessHeap(),0,nLen*sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,szHeaders,nLen); + } + result=HttpSendRequestW(hHttpRequest, szHeaders, nLen, lpOptional, dwOptionalLength); + HeapFree(GetProcessHeap(),0,szHeaders); + return result; } /*********************************************************************** @@ -3447,9 +4130,9 @@ lend: * Deallocate session handle * */ -static void HTTPSESSION_Destroy(WININETHANDLEHEADER *hdr) +static void HTTPSESSION_Destroy(object_header_t *hdr) { - LPWININETHTTPSESSIONW lpwhs = (LPWININETHTTPSESSIONW) hdr; + http_session_t *lpwhs = (http_session_t*) hdr; TRACE("%p\n", lpwhs); @@ -3462,7 +4145,7 @@ static void HTTPSESSION_Destroy(WININETHANDLEHEADER *hdr) HeapFree(GetProcessHeap(), 0, lpwhs); } -static DWORD HTTPSESSION_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) +static DWORD HTTPSESSION_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) { switch(option) { case INTERNET_OPTION_HANDLE_TYPE: @@ -3479,11 +4162,34 @@ static DWORD HTTPSESSION_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, voi return INET_QueryOption(option, buffer, size, unicode); } -static const HANDLEHEADERVtbl HTTPSESSIONVtbl = { +static DWORD HTTPSESSION_SetOption(object_header_t *hdr, DWORD option, void *buffer, DWORD size) +{ + http_session_t *ses = (http_session_t*)hdr; + + switch(option) { + case INTERNET_OPTION_USERNAME: + { + HeapFree(GetProcessHeap(), 0, ses->lpszUserName); + if (!(ses->lpszUserName = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY; + return ERROR_SUCCESS; + } + case INTERNET_OPTION_PASSWORD: + { + HeapFree(GetProcessHeap(), 0, ses->lpszPassword); + if (!(ses->lpszPassword = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY; + return ERROR_SUCCESS; + } + default: break; + } + + return ERROR_INTERNET_INVALID_OPTION; +} + +static const object_vtbl_t HTTPSESSIONVtbl = { HTTPSESSION_Destroy, NULL, HTTPSESSION_QueryOption, - NULL, + HTTPSESSION_SetOption, NULL, NULL, NULL, @@ -3502,30 +4208,25 @@ static const HANDLEHEADERVtbl HTTPSESSIONVtbl = { * NULL on failure * */ -HINTERNET HTTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, - INTERNET_PORT nServerPort, LPCWSTR lpszUserName, - LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext, - DWORD dwInternalFlags) +DWORD HTTP_Connect(appinfo_t *hIC, LPCWSTR lpszServerName, + INTERNET_PORT nServerPort, LPCWSTR lpszUserName, + LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext, + DWORD dwInternalFlags, HINTERNET *ret) { - LPWININETHTTPSESSIONW lpwhs = NULL; + http_session_t *lpwhs = NULL; HINTERNET handle = NULL; + DWORD res = ERROR_SUCCESS; TRACE("-->\n"); if (!lpszServerName || !lpszServerName[0]) - { - INTERNET_SetLastError(ERROR_INVALID_PARAMETER); - goto lerror; - } + return ERROR_INVALID_PARAMETER; assert( hIC->hdr.htype == WH_HINIT ); - lpwhs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPSESSIONW)); - if (NULL == lpwhs) - { - INTERNET_SetLastError(ERROR_OUTOFMEMORY); - goto lerror; - } + lpwhs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(http_session_t)); + if (!lpwhs) + return ERROR_OUTOFMEMORY; /* * According to my tests. The name is not resolved until a request is sent @@ -3547,8 +4248,8 @@ HINTERNET HTTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, if (NULL == handle) { ERR("Failed to alloc handle\n"); - INTERNET_SetLastError(ERROR_OUTOFMEMORY); - goto lerror; + res = ERROR_OUTOFMEMORY; + goto lerror; } if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) { @@ -3559,13 +4260,13 @@ HINTERNET HTTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, } if (lpszServerName && lpszServerName[0]) { - lpwhs->lpszServerName = WININET_strdupW(lpszServerName); - lpwhs->lpszHostName = WININET_strdupW(lpszServerName); + lpwhs->lpszServerName = heap_strdupW(lpszServerName); + lpwhs->lpszHostName = heap_strdupW(lpszServerName); } if (lpszUserName && lpszUserName[0]) - lpwhs->lpszUserName = WININET_strdupW(lpszUserName); + lpwhs->lpszUserName = heap_strdupW(lpszUserName); if (lpszPassword && lpszPassword[0]) - lpwhs->lpszPassword = WININET_strdupW(lpszPassword); + lpwhs->lpszPassword = heap_strdupW(lpszPassword); lpwhs->nServerPort = nServerPort; lpwhs->nHostPort = nServerPort; @@ -3587,7 +4288,10 @@ lerror: */ TRACE("%p --> %p (%p)\n", hIC, handle, lpwhs); - return handle; + + if(res == ERROR_SUCCESS) + *ret = handle; + return res; } @@ -3601,48 +4305,58 @@ lerror: * TRUE on success * FALSE on failure */ -static BOOL HTTP_OpenConnection(LPWININETHTTPREQW lpwhr) +static DWORD HTTP_OpenConnection(http_request_t *lpwhr) { - BOOL bSuccess = FALSE; - LPWININETHTTPSESSIONW lpwhs; - LPWININETAPPINFOW hIC = NULL; - char szaddr[32]; + http_session_t *lpwhs; + appinfo_t *hIC = NULL; + char szaddr[INET6_ADDRSTRLEN]; + const void *addr; + DWORD res = ERROR_SUCCESS; TRACE("-->\n"); - if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ) + if (lpwhr->hdr.htype != WH_HHTTPREQ) { - INTERNET_SetLastError(ERROR_INVALID_PARAMETER); + res = ERROR_INVALID_PARAMETER; goto lend; } if (NETCON_connected(&lpwhr->netConnection)) - { - bSuccess = TRUE; goto lend; - } - if (!HTTP_ResolveName(lpwhr)) goto lend; + if ((res = HTTP_ResolveName(lpwhr)) != ERROR_SUCCESS) goto lend; lpwhs = lpwhr->lpHttpSession; hIC = lpwhs->lpAppInfo; - inet_ntop(lpwhs->socketAddress.sin_family, &lpwhs->socketAddress.sin_addr, - szaddr, sizeof(szaddr)); + switch (lpwhs->socketAddress.ss_family) + { + case AF_INET: + addr = &((struct sockaddr_in *)&lpwhs->socketAddress)->sin_addr; + break; + case AF_INET6: + addr = &((struct sockaddr_in6 *)&lpwhs->socketAddress)->sin6_addr; + break; + default: + WARN("unsupported family %d\n", lpwhs->socketAddress.ss_family); + return ERROR_INTERNET_NAME_NOT_RESOLVED; + } + inet_ntop(lpwhs->socketAddress.ss_family, addr, szaddr, sizeof(szaddr)); INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER, szaddr, strlen(szaddr)+1); - if (!NETCON_create(&lpwhr->netConnection, lpwhs->socketAddress.sin_family, - SOCK_STREAM, 0)) + res = NETCON_create(&lpwhr->netConnection, lpwhs->socketAddress.ss_family, SOCK_STREAM, 0); + if (res != ERROR_SUCCESS) { - WARN("Socket creation failed: %u\n", INTERNET_GetLastError()); + WARN("Socket creation failed: %u\n", res); goto lend; } - if (!NETCON_connect(&lpwhr->netConnection, (struct sockaddr *)&lpwhs->socketAddress, - sizeof(lpwhs->socketAddress))) + res = NETCON_connect(&lpwhr->netConnection, (struct sockaddr *)&lpwhs->socketAddress, + lpwhs->sa_len); + if(res != ERROR_SUCCESS) goto lend; if (lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE) @@ -3653,10 +4367,11 @@ static BOOL HTTP_OpenConnection(LPWININETHTTPREQW lpwhr) * behaviour to be more correct and to not cause any incompatibilities * because using a secure connection through a proxy server is a rare * case that would be hard for anyone to depend on */ - if (hIC->lpszProxy && !HTTP_SecureProxyConnect(lpwhr)) + if (hIC->lpszProxy && (res = HTTP_SecureProxyConnect(lpwhr)) != ERROR_SUCCESS) goto lend; - if (!NETCON_secure_connect(&lpwhr->netConnection, lpwhs->lpszHostName)) + res = NETCON_secure_connect(&lpwhr->netConnection, lpwhs->lpszHostName); + if(res != ERROR_SUCCESS) { WARN("Couldn't connect securely to host\n"); goto lend; @@ -3667,11 +4382,12 @@ static BOOL HTTP_OpenConnection(LPWININETHTTPREQW lpwhr) INTERNET_STATUS_CONNECTED_TO_SERVER, szaddr, strlen(szaddr)+1); - bSuccess = TRUE; - lend: - TRACE("%d <--\n", bSuccess); - return bSuccess; + lpwhr->read_pos = lpwhr->read_size = 0; + lpwhr->read_chunked = FALSE; + + TRACE("%d <--\n", res); + return res; } @@ -3680,7 +4396,7 @@ lend: * * clear out any old response headers */ -static void HTTP_clear_response_headers( LPWININETHTTPREQW lpwhr ) +static void HTTP_clear_response_headers( http_request_t *lpwhr ) { DWORD i; @@ -3707,20 +4423,20 @@ static void HTTP_clear_response_headers( LPWININETHTTPREQW lpwhr ) * TRUE on success * FALSE on error */ -static INT HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr, BOOL clear) +static INT HTTP_GetResponseHeaders(http_request_t *lpwhr, BOOL clear) { INT cbreaks = 0; WCHAR buffer[MAX_REPLY_LEN]; DWORD buflen = MAX_REPLY_LEN; BOOL bSuccess = FALSE; INT rc = 0; - static const WCHAR szCrLf[] = {'\r','\n',0}; - static const WCHAR szHundred[] = {'1','0','0',0}; char bufferA[MAX_REPLY_LEN]; - LPWSTR status_code, status_text; + LPWSTR status_code = NULL, status_text = NULL; DWORD cchMaxRawHeaders = 1024; - LPWSTR lpszRawHeaders = HeapAlloc(GetProcessHeap(), 0, (cchMaxRawHeaders+1)*sizeof(WCHAR)); + LPWSTR lpszRawHeaders = NULL; + LPWSTR temp; DWORD cchRawHeaders = 0; + BOOL codeHundred = FALSE; TRACE("-->\n"); @@ -3731,36 +4447,52 @@ static INT HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr, BOOL clear) goto lend; do { - /* - * HACK peek at the buffer - */ - buflen = MAX_REPLY_LEN; - NETCON_recv(&lpwhr->netConnection, buffer, buflen, MSG_PEEK, &rc); - + static const WCHAR szHundred[] = {'1','0','0',0}; /* * We should first receive 'HTTP/1.x nnn OK' where nnn is the status code. */ - memset(buffer, 0, MAX_REPLY_LEN); - if (!NETCON_getNextLine(&lpwhr->netConnection, bufferA, &buflen)) + buflen = MAX_REPLY_LEN; + if (!read_line(lpwhr, bufferA, &buflen)) goto lend; + rc += buflen; MultiByteToWideChar( CP_ACP, 0, bufferA, buflen, buffer, MAX_REPLY_LEN ); + /* check is this a status code line? */ + if (!strncmpW(buffer, g_szHttp1_0, 4)) + { + /* split the version from the status code */ + status_code = strchrW( buffer, ' ' ); + if( !status_code ) + goto lend; + *status_code++=0; - /* split the version from the status code */ - status_code = strchrW( buffer, ' ' ); - if( !status_code ) + /* split the status code from the status text */ + status_text = strchrW( status_code, ' ' ); + if( !status_text ) + goto lend; + *status_text++=0; + + TRACE("version [%s] status code [%s] status text [%s]\n", + debugstr_w(buffer), debugstr_w(status_code), debugstr_w(status_text) ); + + codeHundred = (!strcmpW(status_code, szHundred)); + } + else if (!codeHundred) + { + WARN("No status line at head of response (%s)\n", debugstr_w(buffer)); + + HeapFree(GetProcessHeap(), 0, lpwhr->lpszVersion); + HeapFree(GetProcessHeap(), 0, lpwhr->lpszStatusText); + + lpwhr->lpszVersion = heap_strdupW(g_szHttp1_0); + lpwhr->lpszStatusText = heap_strdupW(szOK); + + HeapFree(GetProcessHeap(), 0, lpwhr->lpszRawHeaders); + lpwhr->lpszRawHeaders = heap_strdupW(szDefaultHeader); + + bSuccess = TRUE; goto lend; - *status_code++=0; - - /* split the status code from the status text */ - status_text = strchrW( status_code, ' ' ); - if( !status_text ) - goto lend; - *status_text++=0; - - TRACE("version [%s] status code [%s] status text [%s]\n", - debugstr_w(buffer), debugstr_w(status_code), debugstr_w(status_text) ); - - } while (!strcmpW(status_code, szHundred)); /* ignore "100 Continue" responses */ + } + } while (codeHundred); /* Add status code */ HTTP_ProcessHeader(lpwhr, szStatus, status_code, @@ -3769,19 +4501,22 @@ static INT HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr, BOOL clear) HeapFree(GetProcessHeap(),0,lpwhr->lpszVersion); HeapFree(GetProcessHeap(),0,lpwhr->lpszStatusText); - lpwhr->lpszVersion= WININET_strdupW(buffer); - lpwhr->lpszStatusText = WININET_strdupW(status_text); + lpwhr->lpszVersion = heap_strdupW(buffer); + lpwhr->lpszStatusText = heap_strdupW(status_text); /* Restore the spaces */ *(status_code-1) = ' '; *(status_text-1) = ' '; /* regenerate raw headers */ + lpszRawHeaders = HeapAlloc(GetProcessHeap(), 0, (cchMaxRawHeaders + 1) * sizeof(WCHAR)); + if (!lpszRawHeaders) goto lend; + while (cchRawHeaders + buflen + strlenW(szCrLf) > cchMaxRawHeaders) - { cchMaxRawHeaders *= 2; - lpszRawHeaders = HeapReAlloc(GetProcessHeap(), 0, lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR)); - } + temp = HeapReAlloc(GetProcessHeap(), 0, lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR)); + if (temp == NULL) goto lend; + lpszRawHeaders = temp; memcpy(lpszRawHeaders+cchRawHeaders, buffer, (buflen-1)*sizeof(WCHAR)); cchRawHeaders += (buflen-1); memcpy(lpszRawHeaders+cchRawHeaders, szCrLf, sizeof(szCrLf)); @@ -3792,33 +4527,35 @@ static INT HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr, BOOL clear) do { buflen = MAX_REPLY_LEN; - if (NETCON_getNextLine(&lpwhr->netConnection, bufferA, &buflen)) + if (read_line(lpwhr, bufferA, &buflen)) { LPWSTR * pFieldAndValue; TRACE("got line %s, now interpreting\n", debugstr_a(bufferA)); + + if (!bufferA[0]) break; MultiByteToWideChar( CP_ACP, 0, bufferA, buflen, buffer, MAX_REPLY_LEN ); - while (cchRawHeaders + buflen + strlenW(szCrLf) > cchMaxRawHeaders) - { - cchMaxRawHeaders *= 2; - lpszRawHeaders = HeapReAlloc(GetProcessHeap(), 0, lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR)); - } - memcpy(lpszRawHeaders+cchRawHeaders, buffer, (buflen-1)*sizeof(WCHAR)); - cchRawHeaders += (buflen-1); - memcpy(lpszRawHeaders+cchRawHeaders, szCrLf, sizeof(szCrLf)); - cchRawHeaders += sizeof(szCrLf)/sizeof(szCrLf[0])-1; - lpszRawHeaders[cchRawHeaders] = '\0'; - pFieldAndValue = HTTP_InterpretHttpHeader(buffer); - if (!pFieldAndValue) - break; + if (pFieldAndValue) + { + while (cchRawHeaders + buflen + strlenW(szCrLf) > cchMaxRawHeaders) + cchMaxRawHeaders *= 2; + temp = HeapReAlloc(GetProcessHeap(), 0, lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR)); + if (temp == NULL) goto lend; + lpszRawHeaders = temp; + memcpy(lpszRawHeaders+cchRawHeaders, buffer, (buflen-1)*sizeof(WCHAR)); + cchRawHeaders += (buflen-1); + memcpy(lpszRawHeaders+cchRawHeaders, szCrLf, sizeof(szCrLf)); + cchRawHeaders += sizeof(szCrLf)/sizeof(szCrLf[0])-1; + lpszRawHeaders[cchRawHeaders] = '\0'; - HTTP_ProcessHeader(lpwhr, pFieldAndValue[0], pFieldAndValue[1], - HTTP_ADDREQ_FLAG_ADD ); + HTTP_ProcessHeader(lpwhr, pFieldAndValue[0], pFieldAndValue[1], + HTTP_ADDREQ_FLAG_ADD ); - HTTP_FreeTokens(pFieldAndValue); - } + HTTP_FreeTokens(pFieldAndValue); + } + } else { cbreaks++; @@ -3827,6 +4564,19 @@ static INT HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr, BOOL clear) } }while(1); + /* make sure the response header is terminated with an empty line. Some apps really + truly care about that empty line being there for some reason. Just add it to the + header. */ + if (cchRawHeaders + strlenW(szCrLf) > cchMaxRawHeaders) + { + cchMaxRawHeaders = cchRawHeaders + strlenW(szCrLf); + temp = HeapReAlloc(GetProcessHeap(), 0, lpszRawHeaders, (cchMaxRawHeaders + 1) * sizeof(WCHAR)); + if (temp == NULL) goto lend; + lpszRawHeaders = temp; + } + + memcpy(&lpszRawHeaders[cchRawHeaders], szCrLf, sizeof(szCrLf)); + HeapFree(GetProcessHeap(), 0, lpwhr->lpszRawHeaders); lpwhr->lpszRawHeaders = lpszRawHeaders; TRACE("raw headers: %s\n", debugstr_w(lpszRawHeaders)); @@ -3844,27 +4594,6 @@ lend: } } - -static void strip_spaces(LPWSTR start) -{ - LPWSTR str = start; - LPWSTR end; - - while (*str == ' ' && *str != '\0') - str++; - - if (str != start) - memmove(start, str, sizeof(WCHAR) * (strlenW(str) + 1)); - - end = start + strlenW(start) - 1; - while (end >= start && *end == ' ') - { - *end = '\0'; - end--; - } -} - - /*********************************************************************** * HTTP_InterpretHttpHeader (internal) * @@ -3929,12 +4658,12 @@ static LPWSTR * HTTP_InterpretHttpHeader(LPCWSTR buffer) #define COALESCEFLAGS (HTTP_ADDHDR_FLAG_COALESCE|HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON) -static BOOL HTTP_ProcessHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field, LPCWSTR value, DWORD dwModifier) +static DWORD HTTP_ProcessHeader(http_request_t *lpwhr, LPCWSTR field, LPCWSTR value, DWORD dwModifier) { LPHTTPHEADERW lphttpHdr = NULL; - BOOL bSuccess = FALSE; INT index = -1; BOOL request_only = dwModifier & HTTP_ADDHDR_FLAG_REQ; + DWORD res = ERROR_HTTP_INVALID_HEADER; TRACE("--> %s: %s - 0x%08x\n", debugstr_w(field), debugstr_w(value), dwModifier); @@ -3950,9 +4679,7 @@ static BOOL HTTP_ProcessHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field, LPCWSTR v if (index >= 0) { if (dwModifier & HTTP_ADDHDR_FLAG_ADD_IF_NEW) - { - return FALSE; - } + return ERROR_HTTP_INVALID_HEADER; lphttpHdr = &lpwhr->pCustHeaders[index]; } else if (value) @@ -3969,7 +4696,7 @@ static BOOL HTTP_ProcessHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field, LPCWSTR v return HTTP_InsertCustomHeader(lpwhr, &hdr); } /* no value to delete */ - else return TRUE; + else return ERROR_SUCCESS; if (dwModifier & HTTP_ADDHDR_FLAG_REQ) lphttpHdr->wFlags |= HDR_ISREQUEST; @@ -3994,7 +4721,7 @@ static BOOL HTTP_ProcessHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field, LPCWSTR v return HTTP_InsertCustomHeader(lpwhr, &hdr); } - return TRUE; + return ERROR_SUCCESS; } else if (dwModifier & COALESCEFLAGS) { @@ -4032,16 +4759,16 @@ static BOOL HTTP_ProcessHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field, LPCWSTR v memcpy(&lphttpHdr->lpszValue[origlen], value, valuelen*sizeof(WCHAR)); lphttpHdr->lpszValue[len] = '\0'; - bSuccess = TRUE; + res = ERROR_SUCCESS; } else { WARN("HeapReAlloc (%d bytes) failed\n",len+1); - INTERNET_SetLastError(ERROR_OUTOFMEMORY); + res = ERROR_OUTOFMEMORY; } } - TRACE("<-- %d\n",bSuccess); - return bSuccess; + TRACE("<-- %d\n", res); + return res; } @@ -4051,30 +4778,12 @@ static BOOL HTTP_ProcessHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field, LPCWSTR v * Called when all content from server has been read by client. * */ -BOOL HTTP_FinishedReading(LPWININETHTTPREQW lpwhr) +static BOOL HTTP_FinishedReading(http_request_t *lpwhr) { - WCHAR szVersion[10]; - WCHAR szConnectionResponse[20]; - DWORD dwBufferSize = sizeof(szVersion); - BOOL keepalive = FALSE; + BOOL keepalive = HTTP_KeepAlive(lpwhr); TRACE("\n"); - /* as per RFC 2068, S8.1.2.1, if the client is HTTP/1.1 then assume that - * the connection is keep-alive by default */ - if (!HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_VERSION, szVersion, - &dwBufferSize, NULL) || - strcmpiW(szVersion, g_szHttp1_1)) - { - keepalive = TRUE; - } - - dwBufferSize = sizeof(szConnectionResponse); - if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_PROXY_CONNECTION, szConnectionResponse, &dwBufferSize, NULL) || - HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_CONNECTION, szConnectionResponse, &dwBufferSize, NULL)) - { - keepalive = !strcmpiW(szConnectionResponse, szKeepAlive); - } if (!keepalive) { @@ -4093,12 +4802,12 @@ BOOL HTTP_FinishedReading(LPWININETHTTPREQW lpwhr) * Return index of custom header from header array * */ -static INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQW lpwhr, LPCWSTR lpszField, +static INT HTTP_GetCustomHeaderIndex(http_request_t *lpwhr, LPCWSTR lpszField, int requested_index, BOOL request_only) { DWORD index; - TRACE("%s\n", debugstr_w(lpszField)); + TRACE("%s, %d, %d\n", debugstr_w(lpszField), requested_index, request_only); for (index = 0; index < lpwhr->nCustHeaders; index++) { @@ -4130,11 +4839,10 @@ static INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQW lpwhr, LPCWSTR lpszField, * Insert header into array * */ -static BOOL HTTP_InsertCustomHeader(LPWININETHTTPREQW lpwhr, LPHTTPHEADERW lpHdr) +static DWORD HTTP_InsertCustomHeader(http_request_t *lpwhr, LPHTTPHEADERW lpHdr) { INT count; LPHTTPHEADERW lph = NULL; - BOOL r = FALSE; TRACE("--> %s: %s\n", debugstr_w(lpHdr->lpszField), debugstr_w(lpHdr->lpszValue)); count = lpwhr->nCustHeaders + 1; @@ -4143,22 +4851,17 @@ static BOOL HTTP_InsertCustomHeader(LPWININETHTTPREQW lpwhr, LPHTTPHEADERW lpHdr else lph = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HTTPHEADERW) * count); - if (NULL != lph) - { - lpwhr->pCustHeaders = lph; - lpwhr->pCustHeaders[count-1].lpszField = WININET_strdupW(lpHdr->lpszField); - lpwhr->pCustHeaders[count-1].lpszValue = WININET_strdupW(lpHdr->lpszValue); - lpwhr->pCustHeaders[count-1].wFlags = lpHdr->wFlags; - lpwhr->pCustHeaders[count-1].wCount= lpHdr->wCount; - lpwhr->nCustHeaders++; - r = TRUE; - } - else - { - INTERNET_SetLastError(ERROR_OUTOFMEMORY); - } + if (!lph) + return ERROR_OUTOFMEMORY; - return r; + lpwhr->pCustHeaders = lph; + lpwhr->pCustHeaders[count-1].lpszField = heap_strdupW(lpHdr->lpszField); + lpwhr->pCustHeaders[count-1].lpszValue = heap_strdupW(lpHdr->lpszValue); + lpwhr->pCustHeaders[count-1].wFlags = lpHdr->wFlags; + lpwhr->pCustHeaders[count-1].wCount= lpHdr->wCount; + lpwhr->nCustHeaders++; + + return ERROR_SUCCESS; } @@ -4168,7 +4871,7 @@ static BOOL HTTP_InsertCustomHeader(LPWININETHTTPREQW lpwhr, LPHTTPHEADERW lpHdr * Delete header from array * If this function is called, the indexs may change. */ -static BOOL HTTP_DeleteCustomHeader(LPWININETHTTPREQW lpwhr, DWORD index) +static BOOL HTTP_DeleteCustomHeader(http_request_t *lpwhr, DWORD index) { if( lpwhr->nCustHeaders <= 0 ) return FALSE; @@ -4193,13 +4896,13 @@ static BOOL HTTP_DeleteCustomHeader(LPWININETHTTPREQW lpwhr, DWORD index) * Verify the given header is not invalid for the given http request * */ -static BOOL HTTP_VerifyValidHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field) +static BOOL HTTP_VerifyValidHeader(http_request_t *lpwhr, LPCWSTR field) { /* Accept-Encoding is stripped from HTTP/1.0 requests. It is invalid */ if (!strcmpW(lpwhr->lpszVersion, g_szHttp1_0) && !strcmpiW(field, szAccept_Encoding)) - return FALSE; + return ERROR_HTTP_INVALID_HEADER; - return TRUE; + return ERROR_SUCCESS; } /*********************************************************************** diff --git a/dll/win32/wininet/internet.c b/dll/win32/wininet/internet.c index bad795ddbd4..45b6aa791f3 100644 --- a/dll/win32/wininet/internet.c +++ b/dll/win32/wininet/internet.c @@ -31,6 +31,10 @@ #define MAXHOSTNAME 100 /* from http.c */ +#if defined(__MINGW32__) || defined (_MSC_VER) +#include +#endif + #include #include #include @@ -97,13 +101,27 @@ static CRITICAL_SECTION_DEBUG WININET_cs_debug = }; static CRITICAL_SECTION WININET_cs = { &WININET_cs_debug, -1, 0, 0, 0, 0 }; -static LPWININETHANDLEHEADER *WININET_Handles; +static object_header_t **WININET_Handles; static UINT WININET_dwNextHandle; static UINT WININET_dwMaxHandles; -HINTERNET WININET_AllocHandle( LPWININETHANDLEHEADER info ) +typedef struct { - LPWININETHANDLEHEADER *p; + DWORD dwProxyEnabled; + LPWSTR lpszProxyServer; + LPWSTR lpszProxyBypass; +} proxyinfo_t; + +static const WCHAR szInternetSettings[] = + { 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\', + 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', + 'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0 }; +static const WCHAR szProxyServer[] = { 'P','r','o','x','y','S','e','r','v','e','r', 0 }; +static const WCHAR szProxyEnable[] = { 'P','r','o','x','y','E','n','a','b','l','e', 0 }; + +HINTERNET WININET_AllocHandle( object_header_t *info ) +{ + object_header_t **p; UINT handle = 0, num; list_init( &info->children ); @@ -113,7 +131,7 @@ HINTERNET WININET_AllocHandle( LPWININETHANDLEHEADER info ) { num = HANDLE_CHUNK_SIZE; p = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof (UINT)* num); + sizeof (*WININET_Handles)* num); if( !p ) goto end; WININET_Handles = p; @@ -123,7 +141,7 @@ HINTERNET WININET_AllocHandle( LPWININETHANDLEHEADER info ) { num = WININET_dwMaxHandles + HANDLE_CHUNK_SIZE; p = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - WININET_Handles, sizeof (UINT)* num); + WININET_Handles, sizeof (*WININET_Handles)* num); if( !p ) goto end; WININET_Handles = p; @@ -145,16 +163,16 @@ end: return info->hInternet = (HINTERNET) (handle+1); } -LPWININETHANDLEHEADER WININET_AddRef( LPWININETHANDLEHEADER info ) +object_header_t *WININET_AddRef( object_header_t *info ) { ULONG refs = InterlockedIncrement(&info->refs); TRACE("%p -> refcount = %d\n", info, refs ); return info; } -LPWININETHANDLEHEADER WININET_GetObject( HINTERNET hinternet ) +object_header_t *WININET_GetObject( HINTERNET hinternet ) { - LPWININETHANDLEHEADER info = NULL; + object_header_t *info = NULL; UINT handle = (UINT) hinternet; EnterCriticalSection( &WININET_cs ); @@ -170,7 +188,7 @@ LPWININETHANDLEHEADER WININET_GetObject( HINTERNET hinternet ) return info; } -BOOL WININET_Release( LPWININETHANDLEHEADER info ) +BOOL WININET_Release( object_header_t *info ) { ULONG refs = InterlockedDecrement(&info->refs); TRACE( "object %p refcount = %d\n", info, refs ); @@ -182,7 +200,8 @@ BOOL WININET_Release( LPWININETHANDLEHEADER info ) info->vtbl->CloseConnection( info ); } /* Don't send a callback if this is a session handle created with InternetOpenUrl */ - if (info->htype != WH_HHTTPSESSION || !(info->dwInternalFlags & INET_OPENURL)) + if ((info->htype != WH_HHTTPSESSION && info->htype != WH_HFTPSESSION) + || !(info->dwInternalFlags & INET_OPENURL)) { INTERNET_SendCallback(info, info->dwContext, INTERNET_STATUS_HANDLE_CLOSING, &info->hInternet, @@ -200,7 +219,7 @@ BOOL WININET_FreeHandle( HINTERNET hinternet ) { BOOL ret = FALSE; UINT handle = (UINT) hinternet; - LPWININETHANDLEHEADER info = NULL, child, next; + object_header_t *info = NULL, *child, *next; EnterCriticalSection( &WININET_cs ); @@ -224,7 +243,7 @@ BOOL WININET_FreeHandle( HINTERNET hinternet ) if( info ) { /* Free all children as native does */ - LIST_FOR_EACH_ENTRY_SAFE( child, next, &info->children, WININETHANDLEHEADER, entry ) + LIST_FOR_EACH_ENTRY_SAFE( child, next, &info->children, object_header_t, entry ) { TRACE( "freeing child handle %d for parent handle %d\n", (UINT)child->hInternet, handle+1); @@ -285,6 +304,8 @@ BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) case DLL_PROCESS_DETACH: + NETCON_unload(); + URLCacheContainers_DeleteAll(); if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES) @@ -298,6 +319,48 @@ BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) return TRUE; } +/*********************************************************************** + * INTERNET_SaveProxySettings + * + * Stores the proxy settings given by lpwai into the registry + * + * RETURNS + * ERROR_SUCCESS if no error, or error code on fail + */ +static LONG INTERNET_SaveProxySettings( proxyinfo_t *lpwpi ) +{ + HKEY key; + LONG ret; + + if ((ret = RegOpenKeyW( HKEY_CURRENT_USER, szInternetSettings, &key ))) + return ret; + + if ((ret = RegSetValueExW( key, szProxyEnable, 0, REG_DWORD, (BYTE*)&lpwpi->dwProxyEnabled, sizeof(DWORD)))) + { + RegCloseKey( key ); + return ret; + } + + if (lpwpi->lpszProxyServer) + { + if ((ret = RegSetValueExW( key, szProxyServer, 0, REG_SZ, (BYTE*)lpwpi->lpszProxyServer, sizeof(WCHAR) * (lstrlenW(lpwpi->lpszProxyServer) + 1)))) + { + RegCloseKey( key ); + return ret; + } + } + else + { + if ((ret = RegDeleteValueW( key, szProxyServer ))) + { + RegCloseKey( key ); + return ret; + } + } + + RegCloseKey(key); + return ERROR_SUCCESS; +} /*********************************************************************** * InternetInitializeAutoProxyDll (WININET.@) @@ -314,7 +377,7 @@ BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) BOOL WINAPI InternetInitializeAutoProxyDll(DWORD dwReserved) { FIXME("STUB\n"); - INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } @@ -331,37 +394,49 @@ BOOL WINAPI DetectAutoProxyUrl(LPSTR lpszAutoProxyUrl, DWORD dwAutoProxyUrlLength, DWORD dwDetectFlags) { FIXME("STUB\n"); - INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } +static void FreeProxyInfo( proxyinfo_t *lpwpi ) +{ + HeapFree(GetProcessHeap(), 0, lpwpi->lpszProxyServer); + HeapFree(GetProcessHeap(), 0, lpwpi->lpszProxyBypass); +} /*********************************************************************** - * INTERNET_ConfigureProxy + * INTERNET_LoadProxySettings + * + * Loads proxy information from the registry or environment into lpwpi. + * + * The caller should call FreeProxyInfo when done with lpwpi. * * FIXME: * The proxy may be specified in the form 'http=proxy.my.org' * Presumably that means there can be ftp=ftpproxy.my.org too. */ -static BOOL INTERNET_ConfigureProxy( LPWININETAPPINFOW lpwai ) +static LONG INTERNET_LoadProxySettings( proxyinfo_t *lpwpi ) { HKEY key; - DWORD type, len, enabled = 0; + DWORD type, len; LPCSTR envproxy; - static const WCHAR szInternetSettings[] = - { 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\', - 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', - 'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0 }; - static const WCHAR szProxyServer[] = { 'P','r','o','x','y','S','e','r','v','e','r', 0 }; - static const WCHAR szProxyEnable[] = { 'P','r','o','x','y','E','n','a','b','l','e', 0 }; + LONG ret; - if (RegOpenKeyW( HKEY_CURRENT_USER, szInternetSettings, &key )) return FALSE; + if ((ret = RegOpenKeyW( HKEY_CURRENT_USER, szInternetSettings, &key ))) + return ret; - len = sizeof enabled; - if (RegQueryValueExW( key, szProxyEnable, NULL, &type, (BYTE *)&enabled, &len ) || type != REG_DWORD) - RegSetValueExW( key, szProxyEnable, 0, REG_DWORD, (BYTE *)&enabled, sizeof(REG_DWORD) ); + len = sizeof(DWORD); + if (RegQueryValueExW( key, szProxyEnable, NULL, &type, (BYTE *)&lpwpi->dwProxyEnabled, &len ) || type != REG_DWORD) + { + lpwpi->dwProxyEnabled = 0; + if((ret = RegSetValueExW( key, szProxyEnable, 0, REG_DWORD, (BYTE *)&lpwpi->dwProxyEnabled, sizeof(DWORD) ))) + { + RegCloseKey( key ); + return ret; + } + } - if (enabled) + if (!(envproxy = getenv( "http_proxy" )) || lpwpi->dwProxyEnabled) { TRACE("Proxy is enabled.\n"); @@ -374,7 +449,7 @@ static BOOL INTERNET_ConfigureProxy( LPWININETAPPINFOW lpwai ) if (!(szProxy = HeapAlloc( GetProcessHeap(), 0, len ))) { RegCloseKey( key ); - return FALSE; + return ERROR_OUTOFMEMORY; } RegQueryValueExW( key, szProxyServer, NULL, &type, (BYTE*)szProxy, &len ); @@ -388,32 +463,56 @@ static BOOL INTERNET_ConfigureProxy( LPWININETAPPINFOW lpwai ) p = strchrW( szProxy, ' ' ); if (p) *p = 0; - lpwai->dwAccessType = INTERNET_OPEN_TYPE_PROXY; - lpwai->lpszProxy = szProxy; + lpwpi->lpszProxyServer = szProxy; - TRACE("http proxy = %s\n", debugstr_w(lpwai->lpszProxy)); + TRACE("http proxy = %s\n", debugstr_w(lpwpi->lpszProxyServer)); } else - ERR("Couldn't read proxy server settings from registry.\n"); + { + TRACE("No proxy server settings in registry.\n"); + lpwpi->lpszProxyServer = NULL; + } } - else if ((envproxy = getenv( "http_proxy" ))) + else if (envproxy) { WCHAR *envproxyW; len = MultiByteToWideChar( CP_UNIXCP, 0, envproxy, -1, NULL, 0 ); - if (!(envproxyW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR)))) return FALSE; + if (!(envproxyW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR)))) + return ERROR_OUTOFMEMORY; MultiByteToWideChar( CP_UNIXCP, 0, envproxy, -1, envproxyW, len ); - lpwai->dwAccessType = INTERNET_OPEN_TYPE_PROXY; - lpwai->lpszProxy = envproxyW; + lpwpi->dwProxyEnabled = 1; + lpwpi->lpszProxyServer = envproxyW; - TRACE("http proxy (from environment) = %s\n", debugstr_w(lpwai->lpszProxy)); - enabled = 1; + TRACE("http proxy (from environment) = %s\n", debugstr_w(lpwpi->lpszProxyServer)); } - if (!enabled) TRACE("Proxy is not enabled.\n"); - RegCloseKey( key ); - return (enabled > 0); + + lpwpi->lpszProxyBypass = NULL; + + return ERROR_SUCCESS; +} + +/*********************************************************************** + * INTERNET_ConfigureProxy + */ +static BOOL INTERNET_ConfigureProxy( appinfo_t *lpwai ) +{ + proxyinfo_t wpi; + + if (INTERNET_LoadProxySettings( &wpi )) + return FALSE; + + if (wpi.dwProxyEnabled) + { + lpwai->dwAccessType = INTERNET_OPEN_TYPE_PROXY; + lpwai->lpszProxy = wpi.lpszProxyServer; + return TRUE; + } + + lpwai->dwAccessType = INTERNET_OPEN_TYPE_DIRECT; + return FALSE; } /*********************************************************************** @@ -459,8 +558,8 @@ static void dump_INTERNET_FLAGS(DWORD dwFlags) FE(INTERNET_FLAG_TRANSFER_BINARY) }; #undef FE - int i; - + unsigned int i; + for (i = 0; i < (sizeof(flag) / sizeof(flag[0])); i++) { if (flag[i].val & dwFlags) { TRACE(" %s", flag[i].name); @@ -479,9 +578,9 @@ static void dump_INTERNET_FLAGS(DWORD dwFlags) * Close internet handle * */ -static VOID APPINFO_Destroy(WININETHANDLEHEADER *hdr) +static VOID APPINFO_Destroy(object_header_t *hdr) { - LPWININETAPPINFOW lpwai = (LPWININETAPPINFOW) hdr; + appinfo_t *lpwai = (appinfo_t*)hdr; TRACE("%p\n",lpwai); @@ -493,9 +592,9 @@ static VOID APPINFO_Destroy(WININETHANDLEHEADER *hdr) HeapFree(GetProcessHeap(), 0, lpwai); } -static DWORD APPINFO_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) +static DWORD APPINFO_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) { - LPWININETAPPINFOW ai = (LPWININETAPPINFOW)hdr; + appinfo_t *ai = (appinfo_t*)hdr; switch(option) { case INTERNET_OPTION_HANDLE_TYPE: @@ -516,17 +615,36 @@ static DWORD APPINFO_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *b bufsize = *size; if (unicode) { - *size = (strlenW(ai->lpszAgent) + 1) * sizeof(WCHAR); + DWORD len = ai->lpszAgent ? strlenW(ai->lpszAgent) : 0; + + *size = (len + 1) * sizeof(WCHAR); if(!buffer || bufsize < *size) return ERROR_INSUFFICIENT_BUFFER; - strcpyW(buffer, ai->lpszAgent); + if (ai->lpszAgent) + strcpyW(buffer, ai->lpszAgent); + else + *(WCHAR *)buffer = 0; + /* If the buffer is copied, the returned length doesn't include + * the NULL terminator. + */ + *size = len * sizeof(WCHAR); }else { - *size = WideCharToMultiByte(CP_ACP, 0, ai->lpszAgent, -1, NULL, 0, NULL, NULL); + if (ai->lpszAgent) + *size = WideCharToMultiByte(CP_ACP, 0, ai->lpszAgent, -1, NULL, 0, NULL, NULL); + else + *size = 1; if(!buffer || bufsize < *size) return ERROR_INSUFFICIENT_BUFFER; - WideCharToMultiByte(CP_ACP, 0, ai->lpszAgent, -1, buffer, *size, NULL, NULL); + if (ai->lpszAgent) + WideCharToMultiByte(CP_ACP, 0, ai->lpszAgent, -1, buffer, *size, NULL, NULL); + else + *(char *)buffer = 0; + /* If the buffer is copied, the returned length doesn't include + * the NULL terminator. + */ + *size -= 1; } return ERROR_SUCCESS; @@ -543,8 +661,10 @@ static DWORD APPINFO_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *b if (ai->lpszProxyBypass) proxyBypassBytesRequired = (lstrlenW(ai->lpszProxyBypass) + 1) * sizeof(WCHAR); if (*size < sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired + proxyBypassBytesRequired) - return ERROR_INSUFFICIENT_BUFFER; - + { + *size = sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired + proxyBypassBytesRequired; + return ERROR_INSUFFICIENT_BUFFER; + } proxy = (LPWSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOW)); proxy_bypass = (LPWSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired); @@ -574,8 +694,10 @@ static DWORD APPINFO_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *b proxyBypassBytesRequired = WideCharToMultiByte(CP_ACP, 0, ai->lpszProxyBypass, -1, NULL, 0, NULL, NULL); if (*size < sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired + proxyBypassBytesRequired) + { + *size = sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired + proxyBypassBytesRequired; return ERROR_INSUFFICIENT_BUFFER; - + } proxy = (LPSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOA)); proxy_bypass = (LPSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired); @@ -601,7 +723,7 @@ static DWORD APPINFO_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *b return INET_QueryOption(option, buffer, size, unicode); } -static const HANDLEHEADERVtbl APPINFOVtbl = { +static const object_vtbl_t APPINFOVtbl = { APPINFO_Destroy, NULL, APPINFO_QueryOption, @@ -627,7 +749,7 @@ static const HANDLEHEADERVtbl APPINFOVtbl = { HINTERNET WINAPI InternetOpenW(LPCWSTR lpszAgent, DWORD dwAccessType, LPCWSTR lpszProxy, LPCWSTR lpszProxyBypass, DWORD dwFlags) { - LPWININETAPPINFOW lpwai = NULL; + appinfo_t *lpwai = NULL; HINTERNET handle = NULL; if (TRACE_ON(wininet)) { @@ -658,7 +780,7 @@ HINTERNET WINAPI InternetOpenW(LPCWSTR lpszAgent, DWORD dwAccessType, /* Clear any error information */ INTERNET_SetLastError(0); - lpwai = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETAPPINFOW)); + lpwai = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(appinfo_t)); if (NULL == lpwai) { INTERNET_SetLastError(ERROR_OUTOFMEMORY); @@ -681,30 +803,12 @@ HINTERNET WINAPI InternetOpenW(LPCWSTR lpszAgent, DWORD dwAccessType, goto lend; } - if (NULL != lpszAgent) - { - lpwai->lpszAgent = HeapAlloc( GetProcessHeap(),0, - (strlenW(lpszAgent)+1)*sizeof(WCHAR)); - if (lpwai->lpszAgent) - lstrcpyW( lpwai->lpszAgent, lpszAgent ); - } + lpwai->lpszAgent = heap_strdupW(lpszAgent); if(dwAccessType == INTERNET_OPEN_TYPE_PRECONFIG) INTERNET_ConfigureProxy( lpwai ); - else if (NULL != lpszProxy) - { - lpwai->lpszProxy = HeapAlloc( GetProcessHeap(), 0, - (strlenW(lpszProxy)+1)*sizeof(WCHAR)); - if (lpwai->lpszProxy) - lstrcpyW( lpwai->lpszProxy, lpszProxy ); - } - - if (NULL != lpszProxyBypass) - { - lpwai->lpszProxyBypass = HeapAlloc( GetProcessHeap(), 0, - (strlenW(lpszProxyBypass)+1)*sizeof(WCHAR)); - if (lpwai->lpszProxyBypass) - lstrcpyW( lpwai->lpszProxyBypass, lpszProxyBypass ); - } + else + lpwai->lpszProxy = heap_strdupW(lpszProxy); + lpwai->lpszProxyBypass = heap_strdupW(lpszProxyBypass); lend: if( lpwai ) @@ -729,33 +833,15 @@ lend: HINTERNET WINAPI InternetOpenA(LPCSTR lpszAgent, DWORD dwAccessType, LPCSTR lpszProxy, LPCSTR lpszProxyBypass, DWORD dwFlags) { - HINTERNET rc = NULL; - INT len; - WCHAR *szAgent = NULL, *szProxy = NULL, *szBypass = NULL; + WCHAR *szAgent, *szProxy, *szBypass; + HINTERNET rc; TRACE("(%s, 0x%08x, %s, %s, 0x%08x)\n", debugstr_a(lpszAgent), dwAccessType, debugstr_a(lpszProxy), debugstr_a(lpszProxyBypass), dwFlags); - if( lpszAgent ) - { - len = MultiByteToWideChar(CP_ACP, 0, lpszAgent, -1, NULL, 0); - szAgent = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); - MultiByteToWideChar(CP_ACP, 0, lpszAgent, -1, szAgent, len); - } - - if( lpszProxy ) - { - len = MultiByteToWideChar(CP_ACP, 0, lpszProxy, -1, NULL, 0); - szProxy = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); - MultiByteToWideChar(CP_ACP, 0, lpszProxy, -1, szProxy, len); - } - - if( lpszProxyBypass ) - { - len = MultiByteToWideChar(CP_ACP, 0, lpszProxyBypass, -1, NULL, 0); - szBypass = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); - MultiByteToWideChar(CP_ACP, 0, lpszProxyBypass, -1, szBypass, len); - } + szAgent = heap_strdupAtoW(lpszAgent); + szProxy = heap_strdupAtoW(lpszProxy); + szBypass = heap_strdupAtoW(lpszProxyBypass); rc = InternetOpenW(szAgent, dwAccessType, szProxy, szBypass, dwFlags); @@ -779,7 +865,7 @@ HINTERNET WINAPI InternetOpenA(LPCSTR lpszAgent, DWORD dwAccessType, BOOL WINAPI InternetGetLastResponseInfoA(LPDWORD lpdwError, LPSTR lpszBuffer, LPDWORD lpdwBufferLength) { - LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex); + LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex); TRACE("\n"); @@ -816,7 +902,7 @@ BOOL WINAPI InternetGetLastResponseInfoA(LPDWORD lpdwError, BOOL WINAPI InternetGetLastResponseInfoW(LPDWORD lpdwError, LPWSTR lpszBuffer, LPDWORD lpdwBufferLength) { - LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex); + LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex); TRACE("\n"); @@ -856,7 +942,7 @@ BOOL WINAPI InternetGetConnectedState(LPDWORD lpdwStatus, DWORD dwReserved) TRACE("(%p, 0x%08x)\n", lpdwStatus, dwReserved); if (lpdwStatus) { - FIXME("always returning LAN connection.\n"); + WARN("always returning LAN connection.\n"); *lpdwStatus = INTERNET_CONNECTION_LAN; } return TRUE; @@ -900,7 +986,7 @@ BOOL WINAPI InternetGetConnectedStateExW(LPDWORD lpdwStatus, LPWSTR lpszConnecti return FALSE; if (lpdwStatus) { - FIXME("always returning LAN connection.\n"); + WARN("always returning LAN connection.\n"); *lpdwStatus = INTERNET_CONNECTION_LAN; } return LoadStringW(WININET_hModule, IDS_LANCONNECTION, lpszConnectionName, dwNameLen); @@ -950,8 +1036,9 @@ HINTERNET WINAPI InternetConnectW(HINTERNET hInternet, LPCWSTR lpszUserName, LPCWSTR lpszPassword, DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext) { - LPWININETAPPINFOW hIC; + appinfo_t *hIC; HINTERNET rc = NULL; + DWORD res = ERROR_SUCCESS; TRACE("(%p, %s, %i, %s, %s, %i, %i, %lx)\n", hInternet, debugstr_w(lpszServerName), nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword), @@ -959,16 +1046,14 @@ HINTERNET WINAPI InternetConnectW(HINTERNET hInternet, if (!lpszServerName) { - INTERNET_SetLastError(ERROR_INVALID_PARAMETER); + SetLastError(ERROR_INVALID_PARAMETER); return NULL; } - /* Clear any error information */ - INTERNET_SetLastError(0); - hIC = (LPWININETAPPINFOW) WININET_GetObject( hInternet ); + hIC = (appinfo_t*)WININET_GetObject( hInternet ); if ( (hIC == NULL) || (hIC->hdr.htype != WH_HINIT) ) { - INTERNET_SetLastError(ERROR_INVALID_HANDLE); + res = ERROR_INVALID_HANDLE; goto lend; } @@ -977,11 +1062,13 @@ HINTERNET WINAPI InternetConnectW(HINTERNET hInternet, case INTERNET_SERVICE_FTP: rc = FTP_Connect(hIC, lpszServerName, nServerPort, lpszUserName, lpszPassword, dwFlags, dwContext, 0); + if(!rc) + res = INTERNET_GetLastError(); break; case INTERNET_SERVICE_HTTP: - rc = HTTP_Connect(hIC, lpszServerName, nServerPort, - lpszUserName, lpszPassword, dwFlags, dwContext, 0); + res = HTTP_Connect(hIC, lpszServerName, nServerPort, + lpszUserName, lpszPassword, dwFlags, dwContext, 0, &rc); break; case INTERNET_SERVICE_GOPHER: @@ -993,6 +1080,7 @@ lend: WININET_Release( &hIC->hdr ); TRACE("returning %p\n", rc); + SetLastError(res); return rc; } @@ -1013,30 +1101,13 @@ HINTERNET WINAPI InternetConnectA(HINTERNET hInternet, DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext) { HINTERNET rc = NULL; - INT len = 0; - LPWSTR szServerName = NULL; - LPWSTR szUserName = NULL; - LPWSTR szPassword = NULL; - - if (lpszServerName) - { - len = MultiByteToWideChar(CP_ACP, 0, lpszServerName, -1, NULL, 0); - szServerName = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); - MultiByteToWideChar(CP_ACP, 0, lpszServerName, -1, szServerName, len); - } - if (lpszUserName) - { - len = MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, NULL, 0); - szUserName = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); - MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, szUserName, len); - } - if (lpszPassword) - { - len = MultiByteToWideChar(CP_ACP, 0, lpszPassword, -1, NULL, 0); - szPassword = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); - MultiByteToWideChar(CP_ACP, 0, lpszPassword, -1, szPassword, len); - } + LPWSTR szServerName; + LPWSTR szUserName; + LPWSTR szPassword; + szServerName = heap_strdupAtoW(lpszServerName); + szUserName = heap_strdupAtoW(lpszUserName); + szPassword = heap_strdupAtoW(lpszPassword); rc = InternetConnectW(hInternet, szServerName, nServerPort, szUserName, szPassword, dwService, dwFlags, dwContext); @@ -1081,7 +1152,7 @@ BOOL WINAPI InternetFindNextFileA(HINTERNET hFind, LPVOID lpvFindData) */ BOOL WINAPI InternetFindNextFileW(HINTERNET hFind, LPVOID lpvFindData) { - WININETHANDLEHEADER *hdr; + object_header_t *hdr; DWORD res; TRACE("\n"); @@ -1119,7 +1190,7 @@ BOOL WINAPI InternetFindNextFileW(HINTERNET hFind, LPVOID lpvFindData) */ BOOL WINAPI InternetCloseHandle(HINTERNET hInternet) { - LPWININETHANDLEHEADER lpwh; + object_header_t *lpwh; TRACE("%p\n",hInternet); @@ -1153,11 +1224,14 @@ static void ConvertUrlComponentValue(LPSTR* lppszComponent, LPDWORD dwComponentL DWORD nASCIILength=WideCharToMultiByte(CP_ACP,0,lpwszComponent,dwwComponentLen,NULL,0,NULL,NULL); if (*lppszComponent == NULL) { - int nASCIIOffset=WideCharToMultiByte(CP_ACP,0,lpwszStart,lpwszComponent-lpwszStart,NULL,0,NULL,NULL); if (lpwszComponent) - *lppszComponent = (LPSTR)lpszStart+nASCIIOffset; + { + int offset = WideCharToMultiByte(CP_ACP, 0, lpwszStart, lpwszComponent-lpwszStart, NULL, 0, NULL, NULL); + *lppszComponent = (LPSTR)lpszStart + offset; + } else *lppszComponent = NULL; + *dwComponentLen = nASCIILength; } else @@ -1204,7 +1278,7 @@ BOOL WINAPI InternetCrackUrlA(LPCSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags, InternetCrackUrlW should not include it */ if (dwUrlLength == -1) nLength--; - lpwszUrl=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WCHAR)*nLength); + lpwszUrl = HeapAlloc(GetProcessHeap(), 0, nLength * sizeof(WCHAR)); MultiByteToWideChar(CP_ACP,0,lpszUrl,dwUrlLength,lpwszUrl,nLength); memset(&UCW,0,sizeof(UCW)); @@ -1443,7 +1517,7 @@ BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWOR /* Determine if the URI is absolute. */ while (lpszap - lpszUrl < dwUrlLength) { - if (isalnumW(*lpszap)) + if (isalnumW(*lpszap) || *lpszap == '+' || *lpszap == '.' || *lpszap == '-') { lpszap++; continue; @@ -1465,8 +1539,11 @@ BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWOR lpUC->nPort = INTERNET_INVALID_PORT_NUMBER; /* Parse */ - if (!(lpszParam = memchrW(lpszap, ';', dwUrlLength - (lpszap - lpszUrl)))) + lpszParam = memchrW(lpszap, ';', dwUrlLength - (lpszap - lpszUrl)); + if(!lpszParam) lpszParam = memchrW(lpszap, '?', dwUrlLength - (lpszap - lpszUrl)); + if(!lpszParam) + lpszParam = memchrW(lpszap, '#', dwUrlLength - (lpszap - lpszUrl)); SetUrlComponentValueW(&lpUC->lpszExtraInfo, &lpUC->dwExtraInfoLength, lpszParam, lpszParam ? dwUrlLength-(lpszParam-lpszUrl) : 0); @@ -1564,7 +1641,7 @@ BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWOR } /* If the scheme is "file" and the host is just one letter, it's not a host */ - if(lpUC->nScheme==INTERNET_SCHEME_FILE && (lpszPort-lpszHost)==1) + if(lpUC->nScheme==INTERNET_SCHEME_FILE && lpszPort <= lpszHost+1) { lpszcp=lpszHost; SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength, @@ -1617,7 +1694,7 @@ BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWOR * :[//][/path][;][?][#] * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */ - if (lpszcp != 0 && lpszcp - lpszUrl < dwUrlLength && (!lpszParam || lpszcp < lpszParam)) + if (lpszcp != 0 && lpszcp - lpszUrl < dwUrlLength && (!lpszParam || lpszcp <= lpszParam)) { INT len; @@ -1783,7 +1860,7 @@ BOOL WINAPI InternetCanonicalizeUrlW(LPCWSTR lpszUrl, LPWSTR lpszBuffer, /* #################################################### */ static INTERNET_STATUS_CALLBACK set_status_callback( - LPWININETHANDLEHEADER lpwh, INTERNET_STATUS_CALLBACK callback, BOOL unicode) + object_header_t *lpwh, INTERNET_STATUS_CALLBACK callback, BOOL unicode) { INTERNET_STATUS_CALLBACK ret; @@ -1811,10 +1888,10 @@ INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackA( HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB) { INTERNET_STATUS_CALLBACK retVal; - LPWININETHANDLEHEADER lpwh; + object_header_t *lpwh; + + TRACE("%p\n", hInternet); - TRACE("0x%08x\n", (ULONG)hInternet); - if (!(lpwh = WININET_GetObject(hInternet))) return INTERNET_INVALID_STATUS_CALLBACK; @@ -1839,9 +1916,9 @@ INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackW( HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB) { INTERNET_STATUS_CALLBACK retVal; - LPWININETHANDLEHEADER lpwh; + object_header_t *lpwh; - TRACE("0x%08x\n", (ULONG)hInternet); + TRACE("%p\n", hInternet); if (!(lpwh = WININET_GetObject(hInternet))) return INTERNET_INVALID_STATUS_CALLBACK; @@ -1875,8 +1952,8 @@ DWORD WINAPI InternetSetFilePointer(HINTERNET hFile, LONG lDistanceToMove, BOOL WINAPI InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer, DWORD dwNumOfBytesToWrite, LPDWORD lpdwNumOfBytesWritten) { - LPWININETHANDLEHEADER lpwh; - BOOL retval = FALSE; + object_header_t *lpwh; + BOOL res; TRACE("(%p %p %d %p)\n", hFile, lpBuffer, dwNumOfBytesToWrite, lpdwNumOfBytesWritten); @@ -1888,16 +1965,17 @@ BOOL WINAPI InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer, } if(lpwh->vtbl->WriteFile) { - retval = lpwh->vtbl->WriteFile(lpwh, lpBuffer, dwNumOfBytesToWrite, lpdwNumOfBytesWritten); + res = lpwh->vtbl->WriteFile(lpwh, lpBuffer, dwNumOfBytesToWrite, lpdwNumOfBytesWritten); }else { WARN("No Writefile method.\n"); - SetLastError(ERROR_INVALID_HANDLE); - retval = FALSE; + res = ERROR_INVALID_HANDLE; } WININET_Release( lpwh ); - return retval; + if(res != ERROR_SUCCESS) + SetLastError(res); + return res == ERROR_SUCCESS; } @@ -1914,7 +1992,7 @@ BOOL WINAPI InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer, BOOL WINAPI InternetReadFile(HINTERNET hFile, LPVOID lpBuffer, DWORD dwNumOfBytesToRead, LPDWORD pdwNumOfBytesRead) { - LPWININETHANDLEHEADER hdr; + object_header_t *hdr; DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE; TRACE("%p %p %d %p\n", hFile, lpBuffer, dwNumOfBytesToRead, pdwNumOfBytesRead); @@ -1968,7 +2046,7 @@ BOOL WINAPI InternetReadFile(HINTERNET hFile, LPVOID lpBuffer, BOOL WINAPI InternetReadFileExA(HINTERNET hFile, LPINTERNET_BUFFERSA lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext) { - LPWININETHANDLEHEADER hdr; + object_header_t *hdr; DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE; TRACE("(%p %p 0x%x 0x%lx)\n", hFile, lpBuffersOut, dwFlags, dwContext); @@ -1994,33 +2072,40 @@ BOOL WINAPI InternetReadFileExA(HINTERNET hFile, LPINTERNET_BUFFERSA lpBuffersOu /*********************************************************************** * InternetReadFileExW (WININET.@) - * - * Read data from an open internet file. - * - * PARAMS - * hFile [I] Handle returned by InternetOpenUrl() or HttpOpenRequest(). - * lpBuffersOut [I/O] Buffer. - * dwFlags [I] Flags. - * dwContext [I] Context for callbacks. - * - * RETURNS - * FALSE, last error is set to ERROR_CALL_NOT_IMPLEMENTED - * - * NOTES - * Not implemented in Wine or native either (as of IE6 SP2). - * + * SEE + * InternetReadFileExA() */ BOOL WINAPI InternetReadFileExW(HINTERNET hFile, LPINTERNET_BUFFERSW lpBuffer, DWORD dwFlags, DWORD_PTR dwContext) { - ERR("(%p, %p, 0x%x, 0x%lx): not implemented in native\n", hFile, lpBuffer, dwFlags, dwContext); + object_header_t *hdr; + DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE; - INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; + TRACE("(%p %p 0x%x 0x%lx)\n", hFile, lpBuffer, dwFlags, dwContext); + + hdr = WININET_GetObject(hFile); + if (!hdr) { + INTERNET_SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + if(hdr->vtbl->ReadFileExW) + res = hdr->vtbl->ReadFileExW(hdr, lpBuffer, dwFlags, dwContext); + + WININET_Release(hdr); + + TRACE("-- %s (%u, bytes read: %d)\n", res == ERROR_SUCCESS ? "TRUE": "FALSE", + res, lpBuffer->dwBufferLength); + + if(res != ERROR_SUCCESS) + SetLastError(res); + return res == ERROR_SUCCESS; } DWORD INET_QueryOption(DWORD option, void *buffer, DWORD *size, BOOL unicode) { + static BOOL warn = TRUE; + switch(option) { case INTERNET_OPTION_REQUEST_FLAGS: TRACE("INTERNET_OPTION_REQUEST_FLAGS\n"); @@ -2047,8 +2132,10 @@ DWORD INET_QueryOption(DWORD option, void *buffer, DWORD *size, BOOL unicode) return ERROR_SUCCESS; case INTERNET_OPTION_CONNECTED_STATE: - FIXME("INTERNET_OPTION_CONNECTED_STATE: semi-stub\n"); - + if (warn) { + FIXME("INTERNET_OPTION_CONNECTED_STATE: semi-stub\n"); + warn = FALSE; + } if (*size < sizeof(ULONG)) return ERROR_INSUFFICIENT_BUFFER; @@ -2058,13 +2145,16 @@ DWORD INET_QueryOption(DWORD option, void *buffer, DWORD *size, BOOL unicode) return ERROR_SUCCESS; case INTERNET_OPTION_PROXY: { - WININETAPPINFOW ai; + appinfo_t ai; + BOOL ret; TRACE("Getting global proxy info\n"); - memset(&ai, 0, sizeof(WININETAPPINFOW)); + memset(&ai, 0, sizeof(appinfo_t)); INTERNET_ConfigureProxy(&ai); - return APPINFO_QueryOption(&ai.hdr, INTERNET_OPTION_PROXY, buffer, size, unicode); /* FIXME */ + ret = APPINFO_QueryOption(&ai.hdr, INTERNET_OPTION_PROXY, buffer, size, unicode); /* FIXME */ + APPINFO_Destroy(&ai.hdr); + return ret; } case INTERNET_OPTION_MAX_CONNS_PER_SERVER: @@ -2109,23 +2199,48 @@ DWORD INET_QueryOption(DWORD option, void *buffer, DWORD *size, BOOL unicode) case INTERNET_OPTION_PER_CONNECTION_OPTION: { INTERNET_PER_CONN_OPTION_LISTW *con = buffer; + INTERNET_PER_CONN_OPTION_LISTA *conA = buffer; DWORD res = ERROR_SUCCESS, i; + proxyinfo_t pi; + LONG ret; + + TRACE("Getting global proxy info\n"); + if((ret = INTERNET_LoadProxySettings(&pi))) + return ret; FIXME("INTERNET_OPTION_PER_CONNECTION_OPTION stub\n"); - if (*size < sizeof(INTERNET_PER_CONN_OPTION_LISTW)) + if (*size < sizeof(INTERNET_PER_CONN_OPTION_LISTW)) { + FreeProxyInfo(&pi); return ERROR_INSUFFICIENT_BUFFER; + } for (i = 0; i < con->dwOptionCount; i++) { INTERNET_PER_CONN_OPTIONW *option = con->pOptions + i; + INTERNET_PER_CONN_OPTIONA *optionA = conA->pOptions + i; switch (option->dwOption) { case INTERNET_PER_CONN_FLAGS: - option->Value.dwValue = PROXY_TYPE_DIRECT; + if(pi.dwProxyEnabled) + option->Value.dwValue = PROXY_TYPE_PROXY; + else + option->Value.dwValue = PROXY_TYPE_DIRECT; break; case INTERNET_PER_CONN_PROXY_SERVER: + if (unicode) + option->Value.pszValue = heap_strdupW(pi.lpszProxyServer); + else + optionA->Value.pszValue = heap_strdupWtoA(pi.lpszProxyServer); + break; + case INTERNET_PER_CONN_PROXY_BYPASS: + if (unicode) + option->Value.pszValue = heap_strdupW(pi.lpszProxyBypass); + else + optionA->Value.pszValue = heap_strdupWtoA(pi.lpszProxyBypass); + break; + case INTERNET_PER_CONN_AUTOCONFIG_URL: case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS: case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL: @@ -2133,8 +2248,7 @@ DWORD INET_QueryOption(DWORD option, void *buffer, DWORD *size, BOOL unicode) case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME: case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL: FIXME("Unhandled dwOption %d\n", option->dwOption); - option->Value.dwValue = 0; - res = ERROR_INVALID_PARAMETER; + memset(&option->Value, 0, sizeof(option->Value)); break; default: @@ -2143,9 +2257,14 @@ DWORD INET_QueryOption(DWORD option, void *buffer, DWORD *size, BOOL unicode) break; } } + FreeProxyInfo(&pi); return res; } + case INTERNET_OPTION_USER_AGENT: + return ERROR_INTERNET_INCORRECT_HANDLE_TYPE; + case INTERNET_OPTION_POLICY: + return ERROR_INVALID_PARAMETER; } FIXME("Stub for %d\n", option); @@ -2165,7 +2284,7 @@ DWORD INET_QueryOption(DWORD option, void *buffer, DWORD *size, BOOL unicode) BOOL WINAPI InternetQueryOptionW(HINTERNET hInternet, DWORD dwOption, LPVOID lpBuffer, LPDWORD lpdwBufferLength) { - LPWININETHANDLEHEADER hdr; + object_header_t *hdr; DWORD res = ERROR_INVALID_HANDLE; TRACE("%p %d %p %p\n", hInternet, dwOption, lpBuffer, lpdwBufferLength); @@ -2198,7 +2317,7 @@ BOOL WINAPI InternetQueryOptionW(HINTERNET hInternet, DWORD dwOption, BOOL WINAPI InternetQueryOptionA(HINTERNET hInternet, DWORD dwOption, LPVOID lpBuffer, LPDWORD lpdwBufferLength) { - LPWININETHANDLEHEADER hdr; + object_header_t *hdr; DWORD res = ERROR_INVALID_HANDLE; TRACE("%p %d %p %p\n", hInternet, dwOption, lpBuffer, lpdwBufferLength); @@ -2232,12 +2351,12 @@ BOOL WINAPI InternetQueryOptionA(HINTERNET hInternet, DWORD dwOption, BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption, LPVOID lpBuffer, DWORD dwBufferLength) { - LPWININETHANDLEHEADER lpwhh; + object_header_t *lpwhh; BOOL ret = TRUE; TRACE("(%p %d %p %d)\n", hInternet, dwOption, lpBuffer, dwBufferLength); - lpwhh = (LPWININETHANDLEHEADER) WININET_GetObject( hInternet ); + lpwhh = (object_header_t*) WININET_GetObject( hInternet ); if(lpwhh && lpwhh->vtbl->SetOption) { DWORD res; @@ -2256,9 +2375,14 @@ BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption, { case INTERNET_OPTION_CALLBACK: { - INTERNET_STATUS_CALLBACK callback = *(INTERNET_STATUS_CALLBACK *)lpBuffer; - ret = (set_status_callback(lpwhh, callback, TRUE) != INTERNET_INVALID_STATUS_CALLBACK); - break; + if (!lpwhh) + { + SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); + return FALSE; + } + WININET_Release(lpwhh); + SetLastError(ERROR_INTERNET_OPTION_NOT_SETTABLE); + return FALSE; } case INTERNET_OPTION_HTTP_VERSION: { @@ -2342,12 +2466,96 @@ BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption, case INTERNET_OPTION_DISABLE_AUTODIAL: FIXME("Option INTERNET_OPTION_DISABLE_AUTODIAL; STUB\n"); break; - case 86: - FIXME("86\n"); + case INTERNET_OPTION_HTTP_DECODING: + FIXME("INTERNET_OPTION_HTTP_DECODING; STUB\n"); + SetLastError(ERROR_INTERNET_INVALID_OPTION); + ret = FALSE; break; + case INTERNET_OPTION_COOKIES_3RD_PARTY: + FIXME("INTERNET_OPTION_COOKIES_3RD_PARTY; STUB\n"); + SetLastError(ERROR_INTERNET_INVALID_OPTION); + ret = FALSE; + break; + case INTERNET_OPTION_SEND_UTF8_SERVERNAME_TO_PROXY: + FIXME("INTERNET_OPTION_SEND_UTF8_SERVERNAME_TO_PROXY; STUB\n"); + SetLastError(ERROR_INTERNET_INVALID_OPTION); + ret = FALSE; + break; + case INTERNET_OPTION_CODEPAGE_PATH: + FIXME("INTERNET_OPTION_CODEPAGE_PATH; STUB\n"); + SetLastError(ERROR_INTERNET_INVALID_OPTION); + ret = FALSE; + break; + case INTERNET_OPTION_CODEPAGE_EXTRA: + FIXME("INTERNET_OPTION_CODEPAGE_EXTRA; STUB\n"); + SetLastError(ERROR_INTERNET_INVALID_OPTION); + ret = FALSE; + break; + case INTERNET_OPTION_IDN: + FIXME("INTERNET_OPTION_IDN; STUB\n"); + SetLastError(ERROR_INTERNET_INVALID_OPTION); + ret = FALSE; + break; + case INTERNET_OPTION_POLICY: + SetLastError(ERROR_INVALID_PARAMETER); + ret = FALSE; + break; + case INTERNET_OPTION_PER_CONNECTION_OPTION: { + INTERNET_PER_CONN_OPTION_LISTW *con = lpBuffer; + LONG res; + int i; + proxyinfo_t pi; + + INTERNET_LoadProxySettings(&pi); + + for (i = 0; i < con->dwOptionCount; i++) { + INTERNET_PER_CONN_OPTIONW *option = con->pOptions + i; + + switch (option->dwOption) { + case INTERNET_PER_CONN_PROXY_SERVER: + HeapFree(GetProcessHeap(), 0, pi.lpszProxyServer); + pi.lpszProxyServer = heap_strdupW(option->Value.pszValue); + break; + + case INTERNET_PER_CONN_FLAGS: + if(option->Value.dwValue & PROXY_TYPE_PROXY) + pi.dwProxyEnabled = 1; + else + { + if(option->Value.dwValue != PROXY_TYPE_DIRECT) + FIXME("Unhandled flags: 0x%x\n", option->Value.dwValue); + pi.dwProxyEnabled = 0; + } + break; + + case INTERNET_PER_CONN_AUTOCONFIG_URL: + case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS: + case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL: + case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS: + case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME: + case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL: + case INTERNET_PER_CONN_PROXY_BYPASS: + FIXME("Unhandled dwOption %d\n", option->dwOption); + break; + + default: + FIXME("Unknown dwOption %d\n", option->dwOption); + SetLastError(ERROR_INVALID_PARAMETER); + break; + } + } + + if ((res = INTERNET_SaveProxySettings(&pi))) + SetLastError(res); + + FreeProxyInfo(&pi); + + ret = (res == ERROR_SUCCESS); + break; + } default: FIXME("Option %d STUB\n",dwOption); - INTERNET_SetLastError(ERROR_INTERNET_INVALID_OPTION); + SetLastError(ERROR_INTERNET_INVALID_OPTION); ret = FALSE; break; } @@ -2380,13 +2588,16 @@ BOOL WINAPI InternetSetOptionA(HINTERNET hInternet, DWORD dwOption, { case INTERNET_OPTION_CALLBACK: { - LPWININETHANDLEHEADER lpwh; - INTERNET_STATUS_CALLBACK callback = *(INTERNET_STATUS_CALLBACK *)lpBuffer; + object_header_t *lpwh; - if (!(lpwh = WININET_GetObject(hInternet))) return FALSE; - r = (set_status_callback(lpwh, callback, FALSE) != INTERNET_INVALID_STATUS_CALLBACK); + if (!(lpwh = WININET_GetObject(hInternet))) + { + INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); + return FALSE; + } WININET_Release(lpwh); - return r; + INTERNET_SetLastError(ERROR_INTERNET_OPTION_NOT_SETTABLE); + return FALSE; } case INTERNET_OPTION_PROXY: { @@ -2418,6 +2629,63 @@ BOOL WINAPI InternetSetOptionA(HINTERNET hInternet, DWORD dwOption, MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength, wbuffer, wlen ); break; + case INTERNET_OPTION_PER_CONNECTION_OPTION: { + int i; + INTERNET_PER_CONN_OPTION_LISTW *listW; + INTERNET_PER_CONN_OPTION_LISTA *listA = lpBuffer; + wlen = sizeof(INTERNET_PER_CONN_OPTION_LISTW); + wbuffer = HeapAlloc( GetProcessHeap(), 0, wlen ); + listW = wbuffer; + + listW->dwSize = sizeof(INTERNET_PER_CONN_OPTION_LISTW); + if (listA->pszConnection) + { + wlen = MultiByteToWideChar( CP_ACP, 0, listA->pszConnection, -1, NULL, 0 ); + listW->pszConnection = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, listA->pszConnection, -1, listW->pszConnection, wlen ); + } + else + listW->pszConnection = NULL; + listW->dwOptionCount = listA->dwOptionCount; + listW->dwOptionError = listA->dwOptionError; + listW->pOptions = HeapAlloc( GetProcessHeap(), 0, sizeof(INTERNET_PER_CONN_OPTIONW) * listA->dwOptionCount ); + + for (i = 0; i < listA->dwOptionCount; ++i) { + INTERNET_PER_CONN_OPTIONA *optA = listA->pOptions + i; + INTERNET_PER_CONN_OPTIONW *optW = listW->pOptions + i; + + optW->dwOption = optA->dwOption; + + switch (optA->dwOption) { + case INTERNET_PER_CONN_AUTOCONFIG_URL: + case INTERNET_PER_CONN_PROXY_BYPASS: + case INTERNET_PER_CONN_PROXY_SERVER: + case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL: + case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL: + if (optA->Value.pszValue) + { + wlen = MultiByteToWideChar( CP_ACP, 0, optA->Value.pszValue, -1, NULL, 0 ); + optW->Value.pszValue = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, optA->Value.pszValue, -1, optW->Value.pszValue, wlen ); + } + else + optW->Value.pszValue = NULL; + break; + case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS: + case INTERNET_PER_CONN_FLAGS: + case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS: + optW->Value.dwValue = optA->Value.dwValue; + break; + case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME: + optW->Value.ftValue = optA->Value.ftValue; + default: + WARN("Unknown PER_CONN dwOption: %d, guessing at conversion to Wide\n", optA->dwOption); + optW->Value.dwValue = optA->Value.dwValue; + break; + } + } + } + break; default: wbuffer = lpBuffer; wlen = dwBufferLength; @@ -2426,7 +2694,29 @@ BOOL WINAPI InternetSetOptionA(HINTERNET hInternet, DWORD dwOption, r = InternetSetOptionW(hInternet,dwOption, wbuffer, wlen); if( lpBuffer != wbuffer ) + { + if (dwOption == INTERNET_OPTION_PER_CONNECTION_OPTION) + { + INTERNET_PER_CONN_OPTION_LISTW *list = wbuffer; + int i; + for (i = 0; i < list->dwOptionCount; ++i) { + INTERNET_PER_CONN_OPTIONW *opt = list->pOptions + i; + switch (opt->dwOption) { + case INTERNET_PER_CONN_AUTOCONFIG_URL: + case INTERNET_PER_CONN_PROXY_BYPASS: + case INTERNET_PER_CONN_PROXY_SERVER: + case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL: + case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL: + HeapFree( GetProcessHeap(), 0, opt->Value.pszValue ); + break; + default: + break; + } + } + HeapFree( GetProcessHeap(), 0, list->pOptions ); + } HeapFree( GetProcessHeap(), 0, wbuffer ); + } return r; } @@ -2451,7 +2741,7 @@ BOOL WINAPI InternetSetOptionExW(HINTERNET hInternet, DWORD dwOption, FIXME("Flags %08x ignored\n", dwFlags); if( dwFlags & ~ISO_VALID_FLAGS ) { - INTERNET_SetLastError( ERROR_INVALID_PARAMETER ); + SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } return InternetSetOptionW( hInternet, dwOption, lpBuffer, dwBufferLength ); @@ -2475,6 +2765,18 @@ BOOL WINAPI InternetTimeFromSystemTimeA( const SYSTEMTIME* time, DWORD format, L TRACE( "%p 0x%08x %p 0x%08x\n", time, format, string, size ); + if (!time || !string || format != INTERNET_RFC1123_FORMAT) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (size < INTERNET_RFC1123_BUFSIZE * sizeof(*string)) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + ret = InternetTimeFromSystemTimeW( time, format, stringW, sizeof(stringW) ); if (ret) WideCharToMultiByte( CP_ACP, 0, stringW, -1, string, size, NULL, NULL ); @@ -2492,10 +2794,17 @@ BOOL WINAPI InternetTimeFromSystemTimeW( const SYSTEMTIME* time, DWORD format, L TRACE( "%p 0x%08x %p 0x%08x\n", time, format, string, size ); - if (!time || !string) return FALSE; - - if (format != INTERNET_RFC1123_FORMAT || size < INTERNET_RFC1123_BUFSIZE * sizeof(WCHAR)) + if (!time || !string || format != INTERNET_RFC1123_FORMAT) + { + SetLastError(ERROR_INVALID_PARAMETER); return FALSE; + } + + if (size < INTERNET_RFC1123_BUFSIZE * sizeof(*string)) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } sprintfW( string, date, WININET_wkday[time->wDayOfWeek], @@ -2516,16 +2825,12 @@ BOOL WINAPI InternetTimeToSystemTimeA( LPCSTR string, SYSTEMTIME* time, DWORD re { BOOL ret = FALSE; WCHAR *stringW; - int len; TRACE( "%s %p 0x%08x\n", debugstr_a(string), time, reserved ); - len = MultiByteToWideChar( CP_ACP, 0, string, -1, NULL, 0 ); - stringW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); - + stringW = heap_strdupAtoW(string); if (stringW) { - MultiByteToWideChar( CP_ACP, 0, string, -1, stringW, len ); ret = InternetTimeToSystemTimeW( stringW, time, reserved ); HeapFree( GetProcessHeap(), 0, stringW ); } @@ -2674,15 +2979,16 @@ BOOL WINAPI InternetCheckConnectionW( LPCWSTR lpszUrl, DWORD dwFlags, DWORD dwRe if (dwFlags & FLAG_ICC_FORCE_CONNECTION) { - struct sockaddr_in sin; + struct sockaddr_storage saddr; + socklen_t sa_len = sizeof(saddr); int fd; - if (!GetAddress(hostW, port, &sin)) + if (!GetAddress(hostW, port, (struct sockaddr *)&saddr, &sa_len)) goto End; - fd = socket(sin.sin_family, SOCK_STREAM, 0); + fd = socket(saddr.ss_family, SOCK_STREAM, 0); if (fd != -1) { - if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) == 0) + if (connect(fd, (struct sockaddr *)&saddr, sa_len) == 0) rc = TRUE; close(fd); } @@ -2731,17 +3037,18 @@ End: */ BOOL WINAPI InternetCheckConnectionA(LPCSTR lpszUrl, DWORD dwFlags, DWORD dwReserved) { - WCHAR *szUrl; - INT len; + WCHAR *url = NULL; BOOL rc; - len = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0); - if (!(szUrl = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)))) - return FALSE; - MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, szUrl, len); - rc = InternetCheckConnectionW(szUrl, dwFlags, dwReserved); - HeapFree(GetProcessHeap(), 0, szUrl); - + if(lpszUrl) { + url = heap_strdupAtoW(lpszUrl); + if(!url) + return FALSE; + } + + rc = InternetCheckConnectionW(url, dwFlags, dwReserved); + + HeapFree(GetProcessHeap(), 0, url); return rc; } @@ -2754,13 +3061,14 @@ BOOL WINAPI InternetCheckConnectionA(LPCSTR lpszUrl, DWORD dwFlags, DWORD dwRese * RETURNS * handle of connection or NULL on failure */ -static HINTERNET INTERNET_InternetOpenUrlW(LPWININETAPPINFOW hIC, LPCWSTR lpszUrl, +static HINTERNET INTERNET_InternetOpenUrlW(appinfo_t *hIC, LPCWSTR lpszUrl, LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext) { URL_COMPONENTSW urlComponents; WCHAR protocol[32], hostName[MAXHOSTNAME], userName[1024]; WCHAR password[1024], path[2048], extra[1024]; HINTERNET client = NULL, client1 = NULL; + DWORD res; TRACE("(%p, %s, %s, %08x, %08x, %08lx)\n", hIC, debugstr_w(lpszUrl), debugstr_w(lpszHeaders), dwHeadersLength, dwFlags, dwContext); @@ -2805,11 +3113,15 @@ static HINTERNET INTERNET_InternetOpenUrlW(LPWININETAPPINFOW hIC, LPCWSTR lpszUr else urlComponents.nPort = INTERNET_DEFAULT_HTTPS_PORT; } + if (urlComponents.nScheme == INTERNET_SCHEME_HTTPS) dwFlags |= INTERNET_FLAG_SECURE; + /* FIXME: should use pointers, not handles, as handles are not thread-safe */ - client = HTTP_Connect(hIC, hostName, urlComponents.nPort, - userName, password, dwFlags, dwContext, INET_OPENURL); - if(client == NULL) + res = HTTP_Connect(hIC, hostName, urlComponents.nPort, + userName, password, dwFlags, dwContext, INET_OPENURL, &client); + if(res != ERROR_SUCCESS) { + INTERNET_SetLastError(res); break; + } if (urlComponents.dwExtraInfoLength) { WCHAR *path_extra; @@ -2844,7 +3156,7 @@ static HINTERNET INTERNET_InternetOpenUrlW(LPWININETAPPINFOW hIC, LPCWSTR lpszUr /* gopher doesn't seem to be implemented in wine, but it's supposed * to be supported by InternetOpenUrlA. */ default: - INTERNET_SetLastError(ERROR_INTERNET_UNRECOGNIZED_SCHEME); + SetLastError(ERROR_INTERNET_UNRECOGNIZED_SCHEME); break; } @@ -2864,7 +3176,7 @@ static HINTERNET INTERNET_InternetOpenUrlW(LPWININETAPPINFOW hIC, LPCWSTR lpszUr static void AsyncInternetOpenUrlProc(WORKREQUEST *workRequest) { struct WORKREQ_INTERNETOPENURLW const *req = &workRequest->u.InternetOpenUrlW; - LPWININETAPPINFOW hIC = (LPWININETAPPINFOW) workRequest->hdr; + appinfo_t *hIC = (appinfo_t*) workRequest->hdr; TRACE("%p\n", hIC); @@ -2878,7 +3190,7 @@ HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl, LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext) { HINTERNET ret = NULL; - LPWININETAPPINFOW hIC = NULL; + appinfo_t *hIC = NULL; if (TRACE_ON(wininet)) { TRACE("(%p, %s, %s, %08x, %08x, %08lx)\n", hInternet, debugstr_w(lpszUrl), debugstr_w(lpszHeaders), @@ -2889,13 +3201,13 @@ HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl, if (!lpszUrl) { - INTERNET_SetLastError(ERROR_INVALID_PARAMETER); + SetLastError(ERROR_INVALID_PARAMETER); goto lend; } - hIC = (LPWININETAPPINFOW) WININET_GetObject( hInternet ); + hIC = (appinfo_t*)WININET_GetObject( hInternet ); if (NULL == hIC || hIC->hdr.htype != WH_HINIT) { - INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); + SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); goto lend; } @@ -2905,12 +3217,9 @@ HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl, workRequest.asyncproc = AsyncInternetOpenUrlProc; workRequest.hdr = WININET_AddRef( &hIC->hdr ); - req = &workRequest.u.InternetOpenUrlW; - req->lpszUrl = WININET_strdupW(lpszUrl); - if (lpszHeaders) - req->lpszHeaders = WININET_strdupW(lpszHeaders); - else - req->lpszHeaders = 0; + req = &workRequest.u.InternetOpenUrlW; + req->lpszUrl = heap_strdupW(lpszUrl); + req->lpszHeaders = heap_strdupW(lpszHeaders); req->dwHeadersLength = dwHeadersLength; req->dwFlags = dwFlags; req->dwContext = dwContext; @@ -2919,7 +3228,7 @@ HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl, /* * This is from windows. */ - INTERNET_SetLastError(ERROR_IO_PENDING); + SetLastError(ERROR_IO_PENDING); } else { ret = INTERNET_InternetOpenUrlW(hIC, lpszUrl, lpszHeaders, dwHeadersLength, dwFlags, dwContext); } @@ -2944,20 +3253,16 @@ HINTERNET WINAPI InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl, LPCSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext) { HINTERNET rc = NULL; - - INT lenUrl; - INT lenHeaders = 0; + DWORD lenHeaders = 0; LPWSTR szUrl = NULL; LPWSTR szHeaders = NULL; TRACE("\n"); if(lpszUrl) { - lenUrl = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0 ); - szUrl = HeapAlloc(GetProcessHeap(), 0, lenUrl*sizeof(WCHAR)); + szUrl = heap_strdupAtoW(lpszUrl); if(!szUrl) return NULL; - MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, szUrl, lenUrl); } if(lpszHeaders) { @@ -3010,7 +3315,7 @@ static LPWITHREADERROR INTERNET_AllocThreadError(void) */ void INTERNET_SetLastError(DWORD dwError) { - LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex); + LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex); if (!lpwite) lpwite = INTERNET_AllocThreadError(); @@ -3031,7 +3336,7 @@ void INTERNET_SetLastError(DWORD dwError) */ DWORD INTERNET_GetLastError(void) { - LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex); + LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex); if (!lpwite) return 0; /* TlsGetValue clears last error, so set it again here */ SetLastError(lpwite->dwError); @@ -3058,8 +3363,13 @@ static DWORD CALLBACK INTERNET_WorkerThreadFunc(LPVOID lpvParam) HeapFree(GetProcessHeap(), 0, lpRequest); workRequest.asyncproc(&workRequest); - WININET_Release( workRequest.hdr ); + + if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES) + { + HeapFree(GetProcessHeap(), 0, TlsGetValue(g_dwTlsErrIndex)); + TlsSetValue(g_dwTlsErrIndex, NULL); + } return TRUE; } @@ -3072,7 +3382,7 @@ static DWORD CALLBACK INTERNET_WorkerThreadFunc(LPVOID lpvParam) * RETURNS * */ -BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest) +DWORD INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest) { BOOL bSuccess; LPWORKREQUEST lpNewRequest; @@ -3081,7 +3391,7 @@ BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest) lpNewRequest = HeapAlloc(GetProcessHeap(), 0, sizeof(WORKREQUEST)); if (!lpNewRequest) - return FALSE; + return ERROR_OUTOFMEMORY; *lpNewRequest = *lpWorkRequest; @@ -3089,10 +3399,10 @@ BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest) if (!bSuccess) { HeapFree(GetProcessHeap(), 0, lpNewRequest); - INTERNET_SetLastError(ERROR_INTERNET_ASYNC_THREAD_FAILED); + return ERROR_INTERNET_ASYNC_THREAD_FAILED; } - return bSuccess; + return ERROR_SUCCESS; } @@ -3104,7 +3414,7 @@ BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest) */ LPSTR INTERNET_GetResponseBuffer(void) { - LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex); + LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex); if (!lpwite) lpwite = INTERNET_AllocThreadError(); TRACE("\n"); @@ -3193,14 +3503,14 @@ BOOL WINAPI InternetQueryDataAvailable( HINTERNET hFile, LPDWORD lpdwNumberOfBytesAvailble, DWORD dwFlags, DWORD_PTR dwContext) { - WININETHANDLEHEADER *hdr; + object_header_t *hdr; DWORD res; TRACE("(%p %p %x %lx)\n", hFile, lpdwNumberOfBytesAvailble, dwFlags, dwContext); hdr = WININET_GetObject( hFile ); if (!hdr) { - INTERNET_SetLastError(ERROR_INVALID_HANDLE); + SetLastError(ERROR_INVALID_HANDLE); return FALSE; } @@ -3451,6 +3761,9 @@ static BOOL calc_url_length(LPURL_COMPONENTSW lpUrlComponents, if (lpUrlComponents->lpszUrlPath) *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, UrlPath); + if (lpUrlComponents->lpszExtraInfo) + *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, ExtraInfo); + return TRUE; } @@ -3535,7 +3848,7 @@ BOOL WINAPI InternetCreateUrlA(LPURL_COMPONENTSA lpUrlComponents, DWORD dwFlags, if (!lpUrlComponents || lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSW) || !lpdwUrlLength) { - INTERNET_SetLastError(ERROR_INVALID_PARAMETER); + SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } @@ -3699,7 +4012,6 @@ BOOL WINAPI InternetCreateUrlW(LPURL_COMPONENTSW lpUrlComponents, DWORD dwFlags, } } - if (lpUrlComponents->lpszUrlPath) { dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, UrlPath); @@ -3707,6 +4019,13 @@ BOOL WINAPI InternetCreateUrlW(LPURL_COMPONENTSW lpUrlComponents, DWORD dwFlags, lpszUrl += dwLen; } + if (lpUrlComponents->lpszExtraInfo) + { + dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, ExtraInfo); + memcpy(lpszUrl, lpUrlComponents->lpszExtraInfo, dwLen * sizeof(WCHAR)); + lpszUrl += dwLen; + } + *lpszUrl = '\0'; return TRUE; @@ -3732,6 +4051,31 @@ DWORD WINAPI InternetConfirmZoneCrossingW( HWND hWnd, LPWSTR szUrlPrev, LPWSTR s return ERROR_SUCCESS; } +static DWORD zone_preference = 3; + +/*********************************************************************** + * PrivacySetZonePreferenceW (WININET.@) + */ +DWORD WINAPI PrivacySetZonePreferenceW( DWORD zone, DWORD type, DWORD template, LPCWSTR preference ) +{ + FIXME( "%x %x %x %s: stub\n", zone, type, template, debugstr_w(preference) ); + + zone_preference = template; + return 0; +} + +/*********************************************************************** + * PrivacyGetZonePreferenceW (WININET.@) + */ +DWORD WINAPI PrivacyGetZonePreferenceW( DWORD zone, DWORD type, LPDWORD template, + LPWSTR preference, LPDWORD length ) +{ + FIXME( "%x %x %p %p %p: stub\n", zone, type, template, preference, length ); + + if (template) *template = zone_preference; + return 0; +} + DWORD WINAPI InternetDialA( HWND hwndParent, LPSTR lpszConnectoid, DWORD dwFlags, DWORD_PTR* lpdwConnection, DWORD dwReserved ) { diff --git a/dll/win32/wininet/internet.h b/dll/win32/wininet/internet.h index 0dcf5a22ce6..e45176bb2c0 100644 --- a/dll/win32/wininet/internet.h +++ b/dll/win32/wininet/internet.h @@ -42,12 +42,7 @@ # include #endif -#if defined(__MINGW32__) || defined (_MSC_VER) -#include "ws2tcpip.h" -#ifndef MSG_WAITALL -#define MSG_WAITALL 0 -#endif -#else +#if !defined(__MINGW32__) && !defined(_MSC_VER) #define closesocket close #define ioctlsocket ioctl #endif /* __MINGW32__ */ @@ -62,33 +57,51 @@ typedef struct BOOL useSSL; int socketFD; void *ssl_s; - char *peek_msg; - char *peek_msg_mem; - size_t peek_len; } WININET_NETCONNECTION; -static inline LPWSTR WININET_strdupW( LPCWSTR str ) +static inline LPWSTR heap_strdupW(LPCWSTR str) { - LPWSTR ret = HeapAlloc( GetProcessHeap(), 0, (strlenW(str) + 1)*sizeof(WCHAR) ); - if (ret) strcpyW( ret, str ); + LPWSTR ret = NULL; + + if(str) { + DWORD size; + + size = (strlenW(str)+1)*sizeof(WCHAR); + ret = HeapAlloc(GetProcessHeap(), 0, size); + if(ret) + memcpy(ret, str, size); + } + return ret; } -static inline LPWSTR WININET_strdup_AtoW( LPCSTR str ) +static inline WCHAR *heap_strdupAtoW(const char *str) { - int len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0); - LPWSTR ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); - if (ret) - MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len); + LPWSTR ret = NULL; + + if(str) { + DWORD len; + + len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); + ret = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); + if(ret) + MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len); + } + return ret; } -static inline LPSTR WININET_strdup_WtoA( LPCWSTR str ) +static inline char *heap_strdupWtoA(LPCWSTR str) { - int len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL); - LPSTR ret = HeapAlloc( GetProcessHeap(), 0, len ); - if (ret) - WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL); + char *ret = NULL; + + if(str) { + DWORD size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL); + ret = HeapAlloc(GetProcessHeap(), 0, size); + if(ret) + WideCharToMultiByte(CP_ACP, 0, str, -1, ret, size, NULL, NULL); + } + return ret; } @@ -124,24 +137,25 @@ typedef enum #define INET_OPENURL 0x0001 #define INET_CALLBACKW 0x0002 -typedef struct _WININETHANDLEHEADER WININETHANDLEHEADER, *LPWININETHANDLEHEADER; +typedef struct _object_header_t object_header_t; typedef struct { - void (*Destroy)(WININETHANDLEHEADER*); - void (*CloseConnection)(WININETHANDLEHEADER*); - DWORD (*QueryOption)(WININETHANDLEHEADER*,DWORD,void*,DWORD*,BOOL); - DWORD (*SetOption)(WININETHANDLEHEADER*,DWORD,void*,DWORD); - DWORD (*ReadFile)(WININETHANDLEHEADER*,void*,DWORD,DWORD*); - DWORD (*ReadFileExA)(WININETHANDLEHEADER*,INTERNET_BUFFERSA*,DWORD,DWORD_PTR); - BOOL (*WriteFile)(WININETHANDLEHEADER*,const void*,DWORD,DWORD*); - DWORD (*QueryDataAvailable)(WININETHANDLEHEADER*,DWORD*,DWORD,DWORD_PTR); - DWORD (*FindNextFileW)(WININETHANDLEHEADER*,void*); -} HANDLEHEADERVtbl; + void (*Destroy)(object_header_t*); + void (*CloseConnection)(object_header_t*); + DWORD (*QueryOption)(object_header_t*,DWORD,void*,DWORD*,BOOL); + DWORD (*SetOption)(object_header_t*,DWORD,void*,DWORD); + DWORD (*ReadFile)(object_header_t*,void*,DWORD,DWORD*); + DWORD (*ReadFileExA)(object_header_t*,INTERNET_BUFFERSA*,DWORD,DWORD_PTR); + DWORD (*ReadFileExW)(object_header_t*,INTERNET_BUFFERSW*,DWORD,DWORD_PTR); + DWORD (*WriteFile)(object_header_t*,const void*,DWORD,DWORD*); + DWORD (*QueryDataAvailable)(object_header_t*,DWORD*,DWORD,DWORD_PTR); + DWORD (*FindNextFileW)(object_header_t*,void*); +} object_vtbl_t; -struct _WININETHANDLEHEADER +struct _object_header_t { WH_TYPE htype; - const HANDLEHEADERVtbl *vtbl; + const object_vtbl_t *vtbl; HINTERNET hInternet; DWORD dwFlags; DWORD_PTR dwContext; @@ -156,28 +170,29 @@ struct _WININETHANDLEHEADER typedef struct { - WININETHANDLEHEADER hdr; + object_header_t hdr; LPWSTR lpszAgent; LPWSTR lpszProxy; LPWSTR lpszProxyBypass; LPWSTR lpszProxyUsername; LPWSTR lpszProxyPassword; DWORD dwAccessType; -} WININETAPPINFOW, *LPWININETAPPINFOW; +} appinfo_t; typedef struct { - WININETHANDLEHEADER hdr; - WININETAPPINFOW *lpAppInfo; + object_header_t hdr; + appinfo_t *lpAppInfo; LPWSTR lpszHostName; /* the final destination of the request */ LPWSTR lpszServerName; /* the name of the server we directly connect to */ LPWSTR lpszUserName; LPWSTR lpszPassword; INTERNET_PORT nHostPort; /* the final destination port of the request */ INTERNET_PORT nServerPort; /* the port of the server we directly connect to */ - struct sockaddr_in socketAddress; -} WININETHTTPSESSIONW, *LPWININETHTTPSESSIONW; + struct sockaddr_storage socketAddress; + socklen_t sa_len; +} http_session_t; #define HDR_ISREQUEST 0x0001 #define HDR_COMMADELIMITED 0x0002 @@ -194,25 +209,38 @@ typedef struct struct HttpAuthInfo; +typedef struct gzip_stream_t gzip_stream_t; + typedef struct { - WININETHANDLEHEADER hdr; - WININETHTTPSESSIONW *lpHttpSession; + object_header_t hdr; + http_session_t *lpHttpSession; LPWSTR lpszPath; LPWSTR lpszVerb; LPWSTR lpszRawHeaders; WININET_NETCONNECTION netConnection; LPWSTR lpszVersion; LPWSTR lpszStatusText; - DWORD dwContentLength; /* total number of bytes to be read */ - DWORD dwContentRead; /* bytes of the content read so far */ + DWORD dwBytesToWrite; + DWORD dwBytesWritten; HTTPHEADERW *pCustHeaders; DWORD nCustHeaders; HANDLE hCacheFile; LPWSTR lpszCacheFile; struct HttpAuthInfo *pAuthInfo; struct HttpAuthInfo *pProxyAuthInfo; -} WININETHTTPREQW, *LPWININETHTTPREQW; + + CRITICAL_SECTION read_section; /* section to protect the following fields */ + DWORD dwContentLength; /* total number of bytes to be read */ + DWORD dwContentRead; /* bytes of the content read so far */ + BOOL read_chunked; /* are we reading in chunked mode? */ + DWORD read_pos; /* current read position in read_buf */ + DWORD read_size; /* valid data size in read_buf */ + BYTE read_buf[4096]; /* buffer for already read but not returned data */ + + BOOL decoding; + gzip_stream_t *gzip_stream; +} http_request_t; @@ -297,6 +325,12 @@ struct WORKREQ_HTTPSENDREQUESTW BOOL bEndRequest; }; +struct WORKREQ_HTTPENDREQUESTW +{ + DWORD dwFlags; + DWORD_PTR dwContext; +}; + struct WORKREQ_SENDCALLBACK { DWORD_PTR dwContext; @@ -320,10 +354,15 @@ struct WORKREQ_INTERNETREADFILEEXA LPINTERNET_BUFFERSA lpBuffersOut; }; +struct WORKREQ_INTERNETREADFILEEXW +{ + LPINTERNET_BUFFERSW lpBuffersOut; +}; + typedef struct WORKREQ { void (*asyncproc)(struct WORKREQ*); - WININETHANDLEHEADER *hdr; + object_header_t *hdr; union { struct WORKREQ_FTPPUTFILEW FtpPutFileW; @@ -338,77 +377,69 @@ typedef struct WORKREQ struct WORKREQ_FTPRENAMEFILEW FtpRenameFileW; struct WORKREQ_FTPFINDNEXTW FtpFindNextW; struct WORKREQ_HTTPSENDREQUESTW HttpSendRequestW; + struct WORKREQ_HTTPENDREQUESTW HttpEndRequestW; struct WORKREQ_SENDCALLBACK SendCallback; - struct WORKREQ_INTERNETOPENURLW InternetOpenUrlW; + struct WORKREQ_INTERNETOPENURLW InternetOpenUrlW; struct WORKREQ_INTERNETREADFILEEXA InternetReadFileExA; + struct WORKREQ_INTERNETREADFILEEXW InternetReadFileExW; } u; } WORKREQUEST, *LPWORKREQUEST; -HINTERNET WININET_AllocHandle( LPWININETHANDLEHEADER info ); -LPWININETHANDLEHEADER WININET_GetObject( HINTERNET hinternet ); -LPWININETHANDLEHEADER WININET_AddRef( LPWININETHANDLEHEADER info ); -BOOL WININET_Release( LPWININETHANDLEHEADER info ); +HINTERNET WININET_AllocHandle( object_header_t *info ); +object_header_t *WININET_GetObject( HINTERNET hinternet ); +object_header_t *WININET_AddRef( object_header_t *info ); +BOOL WININET_Release( object_header_t *info ); BOOL WININET_FreeHandle( HINTERNET hinternet ); DWORD INET_QueryOption(DWORD,void*,DWORD*,BOOL); time_t ConvertTimeString(LPCWSTR asctime); -HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, +HINTERNET FTP_Connect(appinfo_t *hIC, LPCWSTR lpszServerName, INTERNET_PORT nServerPort, LPCWSTR lpszUserName, LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext, DWORD dwInternalFlags); -HINTERNET HTTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, - INTERNET_PORT nServerPort, LPCWSTR lpszUserName, - LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext, - DWORD dwInternalFlags); +DWORD HTTP_Connect(appinfo_t*,LPCWSTR, + INTERNET_PORT nServerPort, LPCWSTR lpszUserName, + LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext, + DWORD dwInternalFlags, HINTERNET*); BOOL GetAddress(LPCWSTR lpszServerName, INTERNET_PORT nServerPort, - struct sockaddr_in *psa); + struct sockaddr *psa, socklen_t *sa_len); void INTERNET_SetLastError(DWORD dwError); DWORD INTERNET_GetLastError(void); -BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest); +DWORD INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest); LPSTR INTERNET_GetResponseBuffer(void); LPSTR INTERNET_GetNextLine(INT nSocket, LPDWORD dwLen); -BOOLAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, - DWORD dwHeaderLength, LPVOID lpOptional, DWORD dwOptionalLength, - DWORD dwContentLength, BOOL bEndRequest); -INTERNETAPI HINTERNET WINAPI HTTP_HttpOpenRequestW(LPWININETHTTPSESSIONW lpwhs, - LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion, - LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes, - DWORD dwFlags, DWORD_PTR dwContext); -BOOL HTTP_FinishedReading(LPWININETHTTPREQW lpwhr); - -VOID SendAsyncCallback(LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext, +VOID SendAsyncCallback(object_header_t *hdr, DWORD_PTR dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInfo, DWORD dwStatusInfoLength); -VOID INTERNET_SendCallback(LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext, +VOID INTERNET_SendCallback(object_header_t *hdr, DWORD_PTR dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInfo, DWORD dwStatusInfoLength); -LPHTTPHEADERW HTTP_GetHeader(LPWININETHTTPREQW lpwhr, LPCWSTR header); - BOOL NETCON_connected(WININET_NETCONNECTION *connection); -BOOL NETCON_init(WININET_NETCONNECTION *connnection, BOOL useSSL); -BOOL NETCON_create(WININET_NETCONNECTION *connection, int domain, +DWORD NETCON_init(WININET_NETCONNECTION *connnection, BOOL useSSL); +void NETCON_unload(void); +DWORD NETCON_create(WININET_NETCONNECTION *connection, int domain, int type, int protocol); -BOOL NETCON_close(WININET_NETCONNECTION *connection); -BOOL NETCON_connect(WININET_NETCONNECTION *connection, const struct sockaddr *serv_addr, +DWORD NETCON_close(WININET_NETCONNECTION *connection); +DWORD NETCON_connect(WININET_NETCONNECTION *connection, const struct sockaddr *serv_addr, unsigned int addrlen); -BOOL NETCON_secure_connect(WININET_NETCONNECTION *connection, LPCWSTR hostname); -BOOL NETCON_send(WININET_NETCONNECTION *connection, const void *msg, size_t len, int flags, +DWORD NETCON_secure_connect(WININET_NETCONNECTION *connection, LPWSTR hostname); +DWORD NETCON_send(WININET_NETCONNECTION *connection, const void *msg, size_t len, int flags, int *sent /* out */); -BOOL NETCON_recv(WININET_NETCONNECTION *connection, void *buf, size_t len, int flags, +DWORD NETCON_recv(WININET_NETCONNECTION *connection, void *buf, size_t len, int flags, int *recvd /* out */); BOOL NETCON_query_data_available(WININET_NETCONNECTION *connection, DWORD *available); -BOOL NETCON_getNextLine(WININET_NETCONNECTION *connection, LPSTR lpszBuffer, LPDWORD dwBuffer); LPCVOID NETCON_GetCert(WININET_NETCONNECTION *connection); DWORD NETCON_set_timeout(WININET_NETCONNECTION *connection, BOOL send, int value); +int sock_get_error(int); extern void URLCacheContainers_CreateDefaults(void); extern void URLCacheContainers_DeleteAll(void); diff --git a/dll/win32/wininet/netconnection.c b/dll/win32/wininet/netconnection.c index 5d8b4d75534..c2560b5da37 100644 --- a/dll/win32/wininet/netconnection.c +++ b/dll/win32/wininet/netconnection.c @@ -23,6 +23,12 @@ #include "config.h" #include "wine/port.h" +#define NONAMELESSUNION + +#if defined(__MINGW32__) || defined (_MSC_VER) +#include +#endif + #include #ifdef HAVE_POLL_H #include @@ -33,10 +39,12 @@ #ifdef HAVE_SYS_TIME_H # include #endif -#include #ifdef HAVE_SYS_SOCKET_H # include #endif +#ifdef HAVE_SYS_FILIO_H +# include +#endif #ifdef HAVE_UNISTD_H # include #endif @@ -55,9 +63,6 @@ #undef FAR #undef DSA #endif -#ifdef HAVE_SYS_SOCKET_H -# include -#endif #include #include @@ -81,7 +86,7 @@ #include "winsock2.h" #define RESPONSE_TIMEOUT 30 /* FROM internet.c */ -#define sock_get_error(x) WSAGetLastError() + WINE_DEFAULT_DEBUG_CHANNEL(wininet); @@ -95,11 +100,23 @@ WINE_DEFAULT_DEBUG_CHANNEL(wininet); #include +static CRITICAL_SECTION init_ssl_cs; +static CRITICAL_SECTION_DEBUG init_ssl_cs_debug = +{ + 0, 0, &init_ssl_cs, + { &init_ssl_cs_debug.ProcessLocksList, + &init_ssl_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": init_ssl_cs") } +}; +static CRITICAL_SECTION init_ssl_cs = { &init_ssl_cs_debug, -1, 0, 0, 0, 0 }; + static void *OpenSSL_ssl_handle; static void *OpenSSL_crypto_handle; static SSL_METHOD *meth; static SSL_CTX *ctx; +static int hostname_idx; +static int error_idx; #define MAKE_FUNCPTR(f) static typeof(f) * p##f @@ -107,6 +124,7 @@ static SSL_CTX *ctx; MAKE_FUNCPTR(SSL_library_init); MAKE_FUNCPTR(SSL_load_error_strings); MAKE_FUNCPTR(SSLv23_method); +MAKE_FUNCPTR(SSL_CTX_free); MAKE_FUNCPTR(SSL_CTX_new); MAKE_FUNCPTR(SSL_new); MAKE_FUNCPTR(SSL_free); @@ -115,46 +133,240 @@ MAKE_FUNCPTR(SSL_connect); MAKE_FUNCPTR(SSL_shutdown); MAKE_FUNCPTR(SSL_write); MAKE_FUNCPTR(SSL_read); +MAKE_FUNCPTR(SSL_pending); +MAKE_FUNCPTR(SSL_get_ex_new_index); +MAKE_FUNCPTR(SSL_get_ex_data); +MAKE_FUNCPTR(SSL_set_ex_data); +MAKE_FUNCPTR(SSL_get_ex_data_X509_STORE_CTX_idx); MAKE_FUNCPTR(SSL_get_verify_result); MAKE_FUNCPTR(SSL_get_peer_certificate); MAKE_FUNCPTR(SSL_CTX_get_timeout); MAKE_FUNCPTR(SSL_CTX_set_timeout); MAKE_FUNCPTR(SSL_CTX_set_default_verify_paths); -MAKE_FUNCPTR(i2d_X509); +MAKE_FUNCPTR(SSL_CTX_set_verify); +MAKE_FUNCPTR(X509_STORE_CTX_get_ex_data); /* OpenSSL's libcrypto functions that we use */ MAKE_FUNCPTR(BIO_new_fp); +MAKE_FUNCPTR(CRYPTO_num_locks); +MAKE_FUNCPTR(CRYPTO_set_id_callback); +MAKE_FUNCPTR(CRYPTO_set_locking_callback); +MAKE_FUNCPTR(ERR_free_strings); MAKE_FUNCPTR(ERR_get_error); MAKE_FUNCPTR(ERR_error_string); +MAKE_FUNCPTR(i2d_X509); +MAKE_FUNCPTR(sk_num); +MAKE_FUNCPTR(sk_value); #undef MAKE_FUNCPTR +static CRITICAL_SECTION *ssl_locks; +static unsigned int num_ssl_locks; + +static unsigned long ssl_thread_id(void) +{ + return GetCurrentThreadId(); +} + +static void ssl_lock_callback(int mode, int type, const char *file, int line) +{ + if (mode & CRYPTO_LOCK) + EnterCriticalSection(&ssl_locks[type]); + else + LeaveCriticalSection(&ssl_locks[type]); +} + +static PCCERT_CONTEXT X509_to_cert_context(X509 *cert) +{ + unsigned char* buffer,*p; + INT len; + BOOL malloced = FALSE; + PCCERT_CONTEXT ret; + + p = NULL; + len = pi2d_X509(cert,&p); + /* + * SSL 0.9.7 and above malloc the buffer if it is null. + * however earlier version do not and so we would need to alloc the buffer. + * + * see the i2d_X509 man page for more details. + */ + if (!p) + { + buffer = HeapAlloc(GetProcessHeap(),0,len); + p = buffer; + len = pi2d_X509(cert,&p); + } + else + { + buffer = p; + malloced = TRUE; + } + + ret = CertCreateCertificateContext(X509_ASN_ENCODING,buffer,len); + + if (malloced) + free(buffer); + else + HeapFree(GetProcessHeap(),0,buffer); + + return ret; +} + +static DWORD netconn_verify_cert(PCCERT_CONTEXT cert, HCERTSTORE store, + WCHAR *server) +{ + BOOL ret; + CERT_CHAIN_PARA chainPara = { sizeof(chainPara), { 0 } }; + PCCERT_CHAIN_CONTEXT chain; + char oid_server_auth[] = szOID_PKIX_KP_SERVER_AUTH; + char *server_auth[] = { oid_server_auth }; + DWORD err = ERROR_SUCCESS; + + TRACE("verifying %s\n", debugstr_w(server)); + chainPara.RequestedUsage.Usage.cUsageIdentifier = 1; + chainPara.RequestedUsage.Usage.rgpszUsageIdentifier = server_auth; + if ((ret = CertGetCertificateChain(NULL, cert, NULL, store, &chainPara, 0, + NULL, &chain))) + { + if (chain->TrustStatus.dwErrorStatus) + { + if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_TIME_VALID) + err = ERROR_INTERNET_SEC_CERT_DATE_INVALID; + else if (chain->TrustStatus.dwErrorStatus & + CERT_TRUST_IS_UNTRUSTED_ROOT) + err = ERROR_INTERNET_INVALID_CA; + else if ((chain->TrustStatus.dwErrorStatus & + CERT_TRUST_IS_OFFLINE_REVOCATION) || + (chain->TrustStatus.dwErrorStatus & + CERT_TRUST_REVOCATION_STATUS_UNKNOWN)) + err = ERROR_INTERNET_SEC_CERT_NO_REV; + else if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_REVOKED) + err = ERROR_INTERNET_SEC_CERT_REVOKED; + else if (chain->TrustStatus.dwErrorStatus & + CERT_TRUST_IS_NOT_VALID_FOR_USAGE) + err = ERROR_INTERNET_SEC_INVALID_CERT; + else + err = ERROR_INTERNET_SEC_INVALID_CERT; + } + else + { + CERT_CHAIN_POLICY_PARA policyPara; + SSL_EXTRA_CERT_CHAIN_POLICY_PARA sslExtraPolicyPara; + CERT_CHAIN_POLICY_STATUS policyStatus; + + sslExtraPolicyPara.u.cbSize = sizeof(sslExtraPolicyPara); + sslExtraPolicyPara.dwAuthType = AUTHTYPE_SERVER; + sslExtraPolicyPara.pwszServerName = server; + policyPara.cbSize = sizeof(policyPara); + policyPara.dwFlags = 0; + policyPara.pvExtraPolicyPara = &sslExtraPolicyPara; + ret = CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, + chain, &policyPara, &policyStatus); + /* Any error in the policy status indicates that the + * policy couldn't be verified. + */ + if (ret && policyStatus.dwError) + { + if (policyStatus.dwError == CERT_E_CN_NO_MATCH) + err = ERROR_INTERNET_SEC_CERT_CN_INVALID; + else + err = ERROR_INTERNET_SEC_INVALID_CERT; + } + } + CertFreeCertificateChain(chain); + } + TRACE("returning %08x\n", err); + return err; +} + +static int netconn_secure_verify(int preverify_ok, X509_STORE_CTX *ctx) +{ + SSL *ssl; + WCHAR *server; + BOOL ret = FALSE; + + ssl = pX509_STORE_CTX_get_ex_data(ctx, + pSSL_get_ex_data_X509_STORE_CTX_idx()); + server = pSSL_get_ex_data(ssl, hostname_idx); + if (preverify_ok) + { + HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + + if (store) + { + X509 *cert; + int i; + PCCERT_CONTEXT endCert = NULL; + + ret = TRUE; + for (i = 0; ret && i < psk_num((struct stack_st *)ctx->chain); i++) + { + PCCERT_CONTEXT context; + + cert = (X509 *)psk_value((struct stack_st *)ctx->chain, i); + if ((context = X509_to_cert_context(cert))) + { + if (i == 0) + ret = CertAddCertificateContextToStore(store, context, + CERT_STORE_ADD_ALWAYS, &endCert); + else + ret = CertAddCertificateContextToStore(store, context, + CERT_STORE_ADD_ALWAYS, NULL); + CertFreeCertificateContext(context); + } + } + if (!endCert) ret = FALSE; + if (ret) + { + DWORD_PTR err = netconn_verify_cert(endCert, store, server); + + if (err) + { + pSSL_set_ex_data(ssl, error_idx, (void *)err); + ret = FALSE; + } + } + CertFreeCertificateContext(endCert); + CertCloseStore(store, 0); + } + } + return ret; +} + #endif -BOOL NETCON_init(WININET_NETCONNECTION *connection, BOOL useSSL) +DWORD NETCON_init(WININET_NETCONNECTION *connection, BOOL useSSL) { connection->useSSL = FALSE; connection->socketFD = -1; if (useSSL) { #if defined(SONAME_LIBSSL) && defined(SONAME_LIBCRYPTO) + int i; + TRACE("using SSL connection\n"); + EnterCriticalSection(&init_ssl_cs); if (OpenSSL_ssl_handle) /* already initialized everything */ - return TRUE; + { + LeaveCriticalSection(&init_ssl_cs); + return ERROR_SUCCESS; + } OpenSSL_ssl_handle = wine_dlopen(SONAME_LIBSSL, RTLD_NOW, NULL, 0); if (!OpenSSL_ssl_handle) { ERR("trying to use a SSL connection, but couldn't load %s. Expect trouble.\n", SONAME_LIBSSL); - INTERNET_SetLastError(ERROR_INTERNET_SECURITY_CHANNEL_ERROR); - return FALSE; + LeaveCriticalSection(&init_ssl_cs); + return ERROR_INTERNET_SECURITY_CHANNEL_ERROR; } OpenSSL_crypto_handle = wine_dlopen(SONAME_LIBCRYPTO, RTLD_NOW, NULL, 0); if (!OpenSSL_crypto_handle) { ERR("trying to use a SSL connection, but couldn't load %s. Expect trouble.\n", SONAME_LIBCRYPTO); - INTERNET_SetLastError(ERROR_INTERNET_SECURITY_CHANNEL_ERROR); - return FALSE; + LeaveCriticalSection(&init_ssl_cs); + return ERROR_INTERNET_SECURITY_CHANNEL_ERROR; } /* mmm nice ugly macroness */ @@ -163,13 +375,14 @@ BOOL NETCON_init(WININET_NETCONNECTION *connection, BOOL useSSL) if (!p##x) \ { \ ERR("failed to load symbol %s\n", #x); \ - INTERNET_SetLastError(ERROR_INTERNET_SECURITY_CHANNEL_ERROR); \ - return FALSE; \ + LeaveCriticalSection(&init_ssl_cs); \ + return ERROR_INTERNET_SECURITY_CHANNEL_ERROR; \ } DYNSSL(SSL_library_init); DYNSSL(SSL_load_error_strings); DYNSSL(SSLv23_method); + DYNSSL(SSL_CTX_free); DYNSSL(SSL_CTX_new); DYNSSL(SSL_new); DYNSSL(SSL_free); @@ -178,12 +391,18 @@ BOOL NETCON_init(WININET_NETCONNECTION *connection, BOOL useSSL) DYNSSL(SSL_shutdown); DYNSSL(SSL_write); DYNSSL(SSL_read); + DYNSSL(SSL_pending); + DYNSSL(SSL_get_ex_new_index); + DYNSSL(SSL_get_ex_data); + DYNSSL(SSL_set_ex_data); + DYNSSL(SSL_get_ex_data_X509_STORE_CTX_idx); DYNSSL(SSL_get_verify_result); DYNSSL(SSL_get_peer_certificate); DYNSSL(SSL_CTX_get_timeout); DYNSSL(SSL_CTX_set_timeout); DYNSSL(SSL_CTX_set_default_verify_paths); - DYNSSL(i2d_X509); + DYNSSL(SSL_CTX_set_verify); + DYNSSL(X509_STORE_CTX_get_ex_data); #undef DYNSSL #define DYNCRYPTO(x) \ @@ -191,12 +410,19 @@ BOOL NETCON_init(WININET_NETCONNECTION *connection, BOOL useSSL) if (!p##x) \ { \ ERR("failed to load symbol %s\n", #x); \ - INTERNET_SetLastError(ERROR_INTERNET_SECURITY_CHANNEL_ERROR); \ - return FALSE; \ + LeaveCriticalSection(&init_ssl_cs); \ + return ERROR_INTERNET_SECURITY_CHANNEL_ERROR; \ } DYNCRYPTO(BIO_new_fp); + DYNCRYPTO(CRYPTO_num_locks); + DYNCRYPTO(CRYPTO_set_id_callback); + DYNCRYPTO(CRYPTO_set_locking_callback); + DYNCRYPTO(ERR_free_strings); DYNCRYPTO(ERR_get_error); DYNCRYPTO(ERR_error_string); + DYNCRYPTO(i2d_X509); + DYNCRYPTO(sk_num); + DYNCRYPTO(sk_value); #undef DYNCRYPTO pSSL_library_init(); @@ -204,15 +430,75 @@ BOOL NETCON_init(WININET_NETCONNECTION *connection, BOOL useSSL) pBIO_new_fp(stderr, BIO_NOCLOSE); /* FIXME: should use winedebug stuff */ meth = pSSLv23_method(); - connection->peek_msg = NULL; - connection->peek_msg_mem = NULL; + ctx = pSSL_CTX_new(meth); + if (!pSSL_CTX_set_default_verify_paths(ctx)) + { + ERR("SSL_CTX_set_default_verify_paths failed: %s\n", + pERR_error_string(pERR_get_error(), 0)); + LeaveCriticalSection(&init_ssl_cs); + return ERROR_OUTOFMEMORY; + } + hostname_idx = pSSL_get_ex_new_index(0, (void *)"hostname index", + NULL, NULL, NULL); + if (hostname_idx == -1) + { + ERR("SSL_get_ex_new_index failed; %s\n", + pERR_error_string(pERR_get_error(), 0)); + LeaveCriticalSection(&init_ssl_cs); + return ERROR_OUTOFMEMORY; + } + error_idx = pSSL_get_ex_new_index(0, (void *)"error index", + NULL, NULL, NULL); + if (error_idx == -1) + { + ERR("SSL_get_ex_new_index failed; %s\n", + pERR_error_string(pERR_get_error(), 0)); + LeaveCriticalSection(&init_ssl_cs); + return ERROR_OUTOFMEMORY; + } + pSSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, netconn_secure_verify); + + pCRYPTO_set_id_callback(ssl_thread_id); + num_ssl_locks = pCRYPTO_num_locks(); + ssl_locks = HeapAlloc(GetProcessHeap(), 0, num_ssl_locks * sizeof(CRITICAL_SECTION)); + if (!ssl_locks) + { + LeaveCriticalSection(&init_ssl_cs); + return ERROR_OUTOFMEMORY; + } + for (i = 0; i < num_ssl_locks; i++) + InitializeCriticalSection(&ssl_locks[i]); + pCRYPTO_set_locking_callback(ssl_lock_callback); + LeaveCriticalSection(&init_ssl_cs); #else FIXME("can't use SSL, not compiled in.\n"); - INTERNET_SetLastError(ERROR_INTERNET_SECURITY_CHANNEL_ERROR); - return FALSE; + return ERROR_INTERNET_SECURITY_CHANNEL_ERROR; #endif } - return TRUE; + return ERROR_SUCCESS; +} + +void NETCON_unload(void) +{ +#if defined(SONAME_LIBSSL) && defined(SONAME_LIBCRYPTO) + if (OpenSSL_crypto_handle) + { + pERR_free_strings(); + wine_dlclose(OpenSSL_crypto_handle, NULL, 0); + } + if (OpenSSL_ssl_handle) + { + if (ctx) + pSSL_CTX_free(ctx); + wine_dlclose(OpenSSL_ssl_handle, NULL, 0); + } + if (ssl_locks) + { + int i; + for (i = 0; i < num_ssl_locks; i++) DeleteCriticalSection(&ssl_locks[i]); + HeapFree(GetProcessHeap(), 0, ssl_locks); + } +#endif } BOOL NETCON_connected(WININET_NETCONNECTION *connection) @@ -223,9 +509,8 @@ BOOL NETCON_connected(WININET_NETCONNECTION *connection) return TRUE; } -#if 0 /* translate a unix error code into a winsock one */ -static int sock_get_error( int err ) +int sock_get_error( int err ) { #if !defined(__MINGW32__) && !defined (_MSC_VER) switch (err) @@ -290,47 +575,39 @@ static int sock_get_error( int err ) #endif return err; } -#endif /****************************************************************************** * NETCON_create * Basically calls 'socket()' */ -BOOL NETCON_create(WININET_NETCONNECTION *connection, int domain, +DWORD NETCON_create(WININET_NETCONNECTION *connection, int domain, int type, int protocol) { #ifdef SONAME_LIBSSL if (connection->useSSL) - return FALSE; + return ERROR_NOT_SUPPORTED; #endif connection->socketFD = socket(domain, type, protocol); if (connection->socketFD == -1) - { - INTERNET_SetLastError(sock_get_error(errno)); - return FALSE; - } - return TRUE; + return sock_get_error(errno); + + return ERROR_SUCCESS; } /****************************************************************************** * NETCON_close * Basically calls 'close()' unless we should use SSL */ -BOOL NETCON_close(WININET_NETCONNECTION *connection) +DWORD NETCON_close(WININET_NETCONNECTION *connection) { int result; - if (!NETCON_connected(connection)) return FALSE; + if (!NETCON_connected(connection)) return ERROR_SUCCESS; #ifdef SONAME_LIBSSL if (connection->useSSL) { - HeapFree(GetProcessHeap(),0,connection->peek_msg_mem); - connection->peek_msg = NULL; - connection->peek_msg_mem = NULL; - connection->peek_len = 0; - pSSL_shutdown(connection->ssl_s); pSSL_free(connection->ssl_s); connection->ssl_s = NULL; @@ -343,52 +620,34 @@ BOOL NETCON_close(WININET_NETCONNECTION *connection) connection->socketFD = -1; if (result == -1) - { - INTERNET_SetLastError(sock_get_error(errno)); - return FALSE; - } - return TRUE; + return sock_get_error(errno); + return ERROR_SUCCESS; } -#ifdef SONAME_LIBSSL -static BOOL check_hostname(X509 *cert, char *hostname) -{ - /* FIXME: implement */ - return TRUE; -} -#endif + /****************************************************************************** * NETCON_secure_connect * Initiates a secure connection over an existing plaintext connection. */ -BOOL NETCON_secure_connect(WININET_NETCONNECTION *connection, LPCWSTR hostname) +DWORD NETCON_secure_connect(WININET_NETCONNECTION *connection, LPWSTR hostname) { + DWORD res = ERROR_NOT_SUPPORTED; #ifdef SONAME_LIBSSL long verify_res; X509 *cert; - int len; - char *hostname_unix; /* can't connect if we are already connected */ if (connection->useSSL) { ERR("already connected\n"); - return FALSE; + return ERROR_INTERNET_CANNOT_CONNECT; } - ctx = pSSL_CTX_new(meth); - if (!pSSL_CTX_set_default_verify_paths(ctx)) - { - ERR("SSL_CTX_set_default_verify_paths failed: %s\n", - pERR_error_string(pERR_get_error(), 0)); - INTERNET_SetLastError(ERROR_OUTOFMEMORY); - return FALSE; - } connection->ssl_s = pSSL_new(ctx); if (!connection->ssl_s) { ERR("SSL_new failed: %s\n", pERR_error_string(pERR_get_error(), 0)); - INTERNET_SetLastError(ERROR_OUTOFMEMORY); + res = ERROR_OUTOFMEMORY; goto fail; } @@ -396,23 +655,25 @@ BOOL NETCON_secure_connect(WININET_NETCONNECTION *connection, LPCWSTR hostname) { ERR("SSL_set_fd failed: %s\n", pERR_error_string(pERR_get_error(), 0)); - INTERNET_SetLastError(ERROR_INTERNET_SECURITY_CHANNEL_ERROR); + res = ERROR_INTERNET_SECURITY_CHANNEL_ERROR; goto fail; } if (pSSL_connect(connection->ssl_s) <= 0) { - ERR("SSL_connect failed: %s\n", - pERR_error_string(pERR_get_error(), 0)); - INTERNET_SetLastError(ERROR_INTERNET_SECURITY_CHANNEL_ERROR); + res = (DWORD_PTR)pSSL_get_ex_data(connection->ssl_s, error_idx); + if (!res) + res = ERROR_INTERNET_SECURITY_CHANNEL_ERROR; + ERR("SSL_connect failed: %d\n", res); goto fail; } + pSSL_set_ex_data(connection->ssl_s, hostname_idx, hostname); cert = pSSL_get_peer_certificate(connection->ssl_s); if (!cert) { ERR("no certificate for server %s\n", debugstr_w(hostname)); /* FIXME: is this the best error? */ - INTERNET_SetLastError(ERROR_INTERNET_INVALID_CA); + res = ERROR_INTERNET_INVALID_CA; goto fail; } verify_res = pSSL_get_verify_result(connection->ssl_s); @@ -423,25 +684,8 @@ BOOL NETCON_secure_connect(WININET_NETCONNECTION *connection, LPCWSTR hostname) * the moment */ } - len = WideCharToMultiByte(CP_UNIXCP, 0, hostname, -1, NULL, 0, NULL, NULL); - hostname_unix = HeapAlloc(GetProcessHeap(), 0, len); - if (!hostname_unix) - { - INTERNET_SetLastError(ERROR_OUTOFMEMORY); - goto fail; - } - WideCharToMultiByte(CP_UNIXCP, 0, hostname, -1, hostname_unix, len, NULL, NULL); - - if (!check_hostname(cert, hostname_unix)) - { - HeapFree(GetProcessHeap(), 0, hostname_unix); - INTERNET_SetLastError(ERROR_INTERNET_SEC_CERT_CN_INVALID); - goto fail; - } - - HeapFree(GetProcessHeap(), 0, hostname_unix); connection->useSSL = TRUE; - return TRUE; + return ERROR_SUCCESS; fail: if (connection->ssl_s) @@ -451,32 +695,29 @@ fail: connection->ssl_s = NULL; } #endif - return FALSE; + return res; } /****************************************************************************** * NETCON_connect * Connects to the specified address. */ -BOOL NETCON_connect(WININET_NETCONNECTION *connection, const struct sockaddr *serv_addr, +DWORD NETCON_connect(WININET_NETCONNECTION *connection, const struct sockaddr *serv_addr, unsigned int addrlen) { int result; - if (!NETCON_connected(connection)) return FALSE; - result = connect(connection->socketFD, serv_addr, addrlen); if (result == -1) { WARN("Unable to connect to host (%s)\n", strerror(errno)); - INTERNET_SetLastError(sock_get_error(errno)); closesocket(connection->socketFD); connection->socketFD = -1; - return FALSE; + return sock_get_error(errno); } - return TRUE; + return ERROR_SUCCESS; } /****************************************************************************** @@ -484,19 +725,16 @@ BOOL NETCON_connect(WININET_NETCONNECTION *connection, const struct sockaddr *se * Basically calls 'send()' unless we should use SSL * number of chars send is put in *sent */ -BOOL NETCON_send(WININET_NETCONNECTION *connection, const void *msg, size_t len, int flags, +DWORD NETCON_send(WININET_NETCONNECTION *connection, const void *msg, size_t len, int flags, int *sent /* out */) { - if (!NETCON_connected(connection)) return FALSE; + if (!NETCON_connected(connection)) return ERROR_INTERNET_CONNECTION_ABORTED; if (!connection->useSSL) { *sent = send(connection->socketFD, msg, len, flags); if (*sent == -1) - { - INTERNET_SetLastError(sock_get_error(errno)); - return FALSE; - } - return TRUE; + return sock_get_error(errno); + return ERROR_SUCCESS; } else { @@ -505,10 +743,10 @@ BOOL NETCON_send(WININET_NETCONNECTION *connection, const void *msg, size_t len, FIXME("SSL_write doesn't support any flags (%08x)\n", flags); *sent = pSSL_write(connection->ssl_s, msg, len); if (*sent < 1 && len) - return FALSE; - return TRUE; + return ERROR_INTERNET_CONNECTION_ABORTED; + return ERROR_SUCCESS; #else - return FALSE; + return ERROR_NOT_SUPPORTED; #endif } } @@ -518,77 +756,25 @@ BOOL NETCON_send(WININET_NETCONNECTION *connection, const void *msg, size_t len, * Basically calls 'recv()' unless we should use SSL * number of chars received is put in *recvd */ -BOOL NETCON_recv(WININET_NETCONNECTION *connection, void *buf, size_t len, int flags, +DWORD NETCON_recv(WININET_NETCONNECTION *connection, void *buf, size_t len, int flags, int *recvd /* out */) { *recvd = 0; - if (!NETCON_connected(connection)) return FALSE; + if (!NETCON_connected(connection)) return ERROR_INTERNET_CONNECTION_ABORTED; if (!len) - return TRUE; + return ERROR_SUCCESS; if (!connection->useSSL) { *recvd = recv(connection->socketFD, buf, len, flags); - if (*recvd == -1) - { - INTERNET_SetLastError(sock_get_error(errno)); - return FALSE; - } - return TRUE; + return *recvd == -1 ? sock_get_error(errno) : ERROR_SUCCESS; } else { #ifdef SONAME_LIBSSL - if (flags & ~(MSG_PEEK|MSG_WAITALL)) - FIXME("SSL_read does not support the following flag: %08x\n", flags); - - /* this ugly hack is all for MSG_PEEK. eww gross */ - if (flags & MSG_PEEK && !connection->peek_msg) - { - connection->peek_msg = connection->peek_msg_mem = HeapAlloc(GetProcessHeap(), 0, (sizeof(char) * len) + 1); - } - else if (flags & MSG_PEEK && connection->peek_msg) - { - if (len < connection->peek_len) - FIXME("buffer isn't big enough. Do the expect us to wrap?\n"); - *recvd = min(len, connection->peek_len); - memcpy(buf, connection->peek_msg, *recvd); - return TRUE; - } - else if (connection->peek_msg) - { - *recvd = min(len, connection->peek_len); - memcpy(buf, connection->peek_msg, *recvd); - connection->peek_len -= *recvd; - connection->peek_msg += *recvd; - if (connection->peek_len == 0) - { - HeapFree(GetProcessHeap(), 0, connection->peek_msg_mem); - connection->peek_msg_mem = NULL; - connection->peek_msg = NULL; - } - /* check if we got enough data from the peek buffer */ - if (!(flags & MSG_WAITALL) || (*recvd == len)) - return TRUE; - /* otherwise, fall through */ - } - *recvd += pSSL_read(connection->ssl_s, (char*)buf + *recvd, len - *recvd); - if (flags & MSG_PEEK) /* must copy stuff into buffer */ - { - connection->peek_len = *recvd; - if (!*recvd) - { - HeapFree(GetProcessHeap(), 0, connection->peek_msg_mem); - connection->peek_msg_mem = NULL; - connection->peek_msg = NULL; - } - else - memcpy(connection->peek_msg, buf, *recvd); - } - if (*recvd < 1 && len) - return FALSE; - return TRUE; + *recvd = pSSL_read(connection->ssl_s, buf, len); + return *recvd > 0 ? ERROR_SUCCESS : ERROR_INTERNET_CONNECTION_ABORTED; #else - return FALSE; + return ERROR_NOT_SUPPORTED; #endif } } @@ -604,13 +790,9 @@ BOOL NETCON_query_data_available(WININET_NETCONNECTION *connection, DWORD *avail if (!NETCON_connected(connection)) return FALSE; -#ifdef SONAME_LIBSSL - if (connection->peek_msg) *available = connection->peek_len; -#endif - -#ifdef FIONREAD if (!connection->useSSL) { +#ifdef FIONREAD int unread; int retval = ioctlsocket(connection->socketFD, FIONREAD, &unread); if (!retval) @@ -618,155 +800,28 @@ BOOL NETCON_query_data_available(WININET_NETCONNECTION *connection, DWORD *avail TRACE("%d bytes of queued, but unread data\n", unread); *available += unread; } - } #endif - return TRUE; -} - -/****************************************************************************** - * NETCON_getNextLine - */ -BOOL NETCON_getNextLine(WININET_NETCONNECTION *connection, LPSTR lpszBuffer, LPDWORD dwBuffer) -{ - - TRACE("\n"); - - if (!NETCON_connected(connection)) return FALSE; - - if (!connection->useSSL) - { - struct timeval tv; - fd_set infd; - BOOL bSuccess = FALSE; - DWORD nRecv = 0; - - FD_ZERO(&infd); - FD_SET(connection->socketFD, &infd); - tv.tv_sec=RESPONSE_TIMEOUT; - tv.tv_usec=0; - - while (nRecv < *dwBuffer) - { - if (select(connection->socketFD+1,&infd,NULL,NULL,&tv) > 0) - { - if (recv(connection->socketFD, &lpszBuffer[nRecv], 1, 0) <= 0) - { - INTERNET_SetLastError(sock_get_error(errno)); - goto lend; - } - - if (lpszBuffer[nRecv] == '\n') - { - bSuccess = TRUE; - break; - } - if (lpszBuffer[nRecv] != '\r') - nRecv++; - } - else - { - INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT); - goto lend; - } - } - - lend: /* FIXME: don't use labels */ - if (bSuccess) - { - lpszBuffer[nRecv++] = '\0'; - *dwBuffer = nRecv; - TRACE(":%u %s\n", nRecv, lpszBuffer); - return TRUE; - } - else - { - return FALSE; - } } else { #ifdef SONAME_LIBSSL - long prev_timeout; - DWORD nRecv = 0; - BOOL success = TRUE; - - prev_timeout = pSSL_CTX_get_timeout(ctx); - pSSL_CTX_set_timeout(ctx, RESPONSE_TIMEOUT); - - while (nRecv < *dwBuffer) - { - int recv = 1; - if (!NETCON_recv(connection, &lpszBuffer[nRecv], 1, 0, &recv)) - { - INTERNET_SetLastError(ERROR_CONNECTION_ABORTED); - success = FALSE; - } - - if (lpszBuffer[nRecv] == '\n') - { - success = TRUE; - break; - } - if (lpszBuffer[nRecv] != '\r') - nRecv++; - } - - pSSL_CTX_set_timeout(ctx, prev_timeout); - if (success) - { - lpszBuffer[nRecv++] = '\0'; - *dwBuffer = nRecv; - TRACE("_SSL:%u %s\n", nRecv, lpszBuffer); - return TRUE; - } - return FALSE; -#else - return FALSE; + *available = pSSL_pending(connection->ssl_s); #endif } + return TRUE; } - LPCVOID NETCON_GetCert(WININET_NETCONNECTION *connection) { #ifdef SONAME_LIBSSL X509* cert; - unsigned char* buffer,*p; - INT len; - BOOL malloced = FALSE; LPCVOID r = NULL; if (!connection->useSSL) return NULL; cert = pSSL_get_peer_certificate(connection->ssl_s); - p = NULL; - len = pi2d_X509(cert,&p); - /* - * SSL 0.9.7 and above malloc the buffer if it is null. - * however earlier version do not and so we would need to alloc the buffer. - * - * see the i2d_X509 man page for more details. - */ - if (!p) - { - buffer = HeapAlloc(GetProcessHeap(),0,len); - p = buffer; - len = pi2d_X509(cert,&p); - } - else - { - buffer = p; - malloced = TRUE; - } - - r = CertCreateCertificateContext(X509_ASN_ENCODING,buffer,len); - - if (malloced) - free(buffer); - else - HeapFree(GetProcessHeap(),0,buffer); - + r = X509_to_cert_context(cert); return r; #else return NULL; @@ -788,7 +843,7 @@ DWORD NETCON_set_timeout(WININET_NETCONNECTION *connection, BOOL send, int value tv.tv_usec = (value % 1000) * 1000; result = setsockopt(connection->socketFD, SOL_SOCKET, - send ? SO_SNDTIMEO : SO_RCVTIMEO, &tv, + send ? SO_SNDTIMEO : SO_RCVTIMEO, (void*)&tv, sizeof(tv)); if (result == -1) diff --git a/dll/win32/wininet/resource.h b/dll/win32/wininet/resource.h index 8a6e4d152e2..279c1123db8 100644 --- a/dll/win32/wininet/resource.h +++ b/dll/win32/wininet/resource.h @@ -18,6 +18,10 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include +#include + +#define IDD_AUTHDLG 0x399 #define IDD_PROXYDLG 0x400 #define IDC_PROXY 0x401 @@ -25,5 +29,6 @@ #define IDC_USERNAME 0x403 #define IDC_PASSWORD 0x404 #define IDC_SAVEPASSWORD 0x405 +#define IDC_SERVER 0x406 #define IDS_LANCONNECTION 0x500 diff --git a/dll/win32/wininet/rsrc.rc b/dll/win32/wininet/rsrc.rc index 5a815116b03..52ea8d4e8d2 100644 --- a/dll/win32/wininet/rsrc.rc +++ b/dll/win32/wininet/rsrc.rc @@ -43,24 +43,28 @@ #include "wininet_Bg.rc" #include "wininet_Cs.rc" #include "wininet_Da.rc" -#include "wininet_De.rc" #include "wininet_En.rc" #include "wininet_Eo.rc" #include "wininet_Es.rc" #include "wininet_Fi.rc" -#include "wininet_Fr.rc" #include "wininet_Hu.rc" #include "wininet_It.rc" -#include "wininet_Ja.rc" #include "wininet_Ko.rc" #include "wininet_Nl.rc" -#include "wininet_No.rc" #include "wininet_Pl.rc" +#include "wininet_Sv.rc" +#include "wininet_Uk.rc" +#include "wininet_Tr.rc" + +/* UTF-8 */ +#include "wininet_De.rc" +#include "wininet_Fr.rc" +#include "wininet_Ja.rc" +#include "wininet_Lt.rc" +#include "wininet_No.rc" #include "wininet_Pt.rc" #include "wininet_Ro.rc" #include "wininet_Ru.rc" #include "wininet_Si.rc" -#include "wininet_Sv.rc" -#include "wininet_Uk.rc" -#include "wininet_Tr.rc" #include "wininet_Zh.rc" + diff --git a/dll/win32/wininet/urlcache.c b/dll/win32/wininet/urlcache.c index c839419f136..29d26ab0b6b 100644 --- a/dll/win32/wininet/urlcache.c +++ b/dll/win32/wininet/urlcache.c @@ -465,7 +465,6 @@ static void URLCacheContainer_CloseIndex(URLCACHECONTAINER * pContainer) static BOOL URLCacheContainers_AddContainer(LPCWSTR cache_prefix, LPCWSTR path, LPWSTR mutex_name) { URLCACHECONTAINER * pContainer = HeapAlloc(GetProcessHeap(), 0, sizeof(URLCACHECONTAINER)); - int path_len = strlenW(path); int cache_prefix_len = strlenW(cache_prefix); if (!pContainer) @@ -476,15 +475,13 @@ static BOOL URLCacheContainers_AddContainer(LPCWSTR cache_prefix, LPCWSTR path, pContainer->hMapping = NULL; pContainer->file_size = 0; - pContainer->path = HeapAlloc(GetProcessHeap(), 0, (path_len + 1) * sizeof(WCHAR)); + pContainer->path = heap_strdupW(path); if (!pContainer->path) { HeapFree(GetProcessHeap(), 0, pContainer); return FALSE; } - memcpy(pContainer->path, path, (path_len + 1) * sizeof(WCHAR)); - pContainer->cache_prefix = HeapAlloc(GetProcessHeap(), 0, (cache_prefix_len + 1) * sizeof(WCHAR)); if (!pContainer->cache_prefix) { @@ -593,6 +590,9 @@ static DWORD URLCacheContainers_FindContainerW(LPCWSTR lpwszUrl, URLCACHECONTAIN TRACE("searching for prefix for URL: %s\n", debugstr_w(lpwszUrl)); + if(!lpwszUrl) + return ERROR_INVALID_PARAMETER; + LIST_FOR_EACH_ENTRY(pContainer, &UrlContainers, URLCACHECONTAINER, entry) { int prefix_len = strlenW(pContainer->cache_prefix); @@ -609,17 +609,15 @@ static DWORD URLCacheContainers_FindContainerW(LPCWSTR lpwszUrl, URLCACHECONTAIN static DWORD URLCacheContainers_FindContainerA(LPCSTR lpszUrl, URLCACHECONTAINER ** ppContainer) { + LPWSTR url = NULL; DWORD ret; - LPWSTR lpwszUrl; - int url_len = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0); - if (url_len && (lpwszUrl = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(WCHAR)))) - { - MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, lpwszUrl, url_len); - ret = URLCacheContainers_FindContainerW(lpwszUrl, ppContainer); - HeapFree(GetProcessHeap(), 0, lpwszUrl); - return ret; - } - return GetLastError(); + + if (lpszUrl && !(url = heap_strdupAtoW(lpszUrl))) + return ERROR_OUTOFMEMORY; + + ret = URLCacheContainers_FindContainerW(url, ppContainer); + HeapFree(GetProcessHeap(), 0, url); + return ret; } static BOOL URLCacheContainers_Enum(LPCWSTR lpwszSearchPattern, DWORD dwIndex, URLCACHECONTAINER ** ppContainer) @@ -692,6 +690,7 @@ static LPURLCACHE_HEADER URLCacheContainer_LockIndex(URLCACHECONTAINER * pContai * of the memory mapped file */ if (pHeader->dwFileSize != pContainer->file_size) { + UnmapViewOfFile( pHeader ); URLCacheContainer_CloseIndex(pContainer); error = URLCacheContainer_OpenIndex(pContainer); if (error != ERROR_SUCCESS) @@ -1240,17 +1239,15 @@ static BOOL URLCache_FindHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, struct static BOOL URLCache_FindHashW(LPCURLCACHE_HEADER pHeader, LPCWSTR lpszUrl, struct _HASH_ENTRY ** ppHashEntry) { LPSTR urlA; - int url_len; BOOL ret; - url_len = WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, NULL, 0, NULL, NULL); - urlA = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(CHAR)); + urlA = heap_strdupWtoA(lpszUrl); if (!urlA) { SetLastError(ERROR_OUTOFMEMORY); return FALSE; } - WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, urlA, url_len, NULL, NULL); + ret = URLCache_FindHash(pHeader, urlA, ppHashEntry); HeapFree(GetProcessHeap(), 0, urlA); return ret; @@ -1451,6 +1448,28 @@ static BOOL URLCache_EnumHashTableEntries(LPCURLCACHE_HEADER pHeader, const HASH return FALSE; } +/*********************************************************************** + * FreeUrlCacheSpaceA (WININET.@) + * + */ +BOOL WINAPI FreeUrlCacheSpaceA(LPCSTR lpszCachePath, DWORD dwSize, DWORD dwFilter) +{ + FIXME("stub!\n"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + + /*********************************************************************** + * FreeUrlCacheSpaceW (WININET.@) + * + */ +BOOL WINAPI FreeUrlCacheSpaceW(LPCWSTR lpszCachePath, DWORD dwSize, DWORD dwFilter) +{ + FIXME("stub!\n"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + /*********************************************************************** * GetUrlCacheEntryInfoExA (WININET.@) * @@ -1482,7 +1501,11 @@ BOOL WINAPI GetUrlCacheEntryInfoExA( return FALSE; } if (dwFlags != 0) + { FIXME("Undocumented flag(s): %x\n", dwFlags); + SetLastError(ERROR_FILE_NOT_FOUND); + return FALSE; + } return GetUrlCacheEntryInfoA(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize); } @@ -1682,7 +1705,11 @@ BOOL WINAPI GetUrlCacheEntryInfoExW( return FALSE; } if (dwFlags != 0) + { FIXME("Undocumented flag(s): %x\n", dwFlags); + SetLastError(ERROR_FILE_NOT_FOUND); + return FALSE; + } return GetUrlCacheEntryInfoW(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize); } @@ -1869,6 +1896,13 @@ BOOL WINAPI RetrieveUrlCacheEntryFileA( } pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry; + if (!pUrlEntry->dwOffsetLocalName) + { + URLCacheContainer_UnlockIndex(pContainer, pHeader); + SetLastError(ERROR_INVALID_DATA); + return FALSE; + } + TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl); TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo); @@ -1958,6 +1992,13 @@ BOOL WINAPI RetrieveUrlCacheEntryFileW( } pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry; + if (!pUrlEntry->dwOffsetLocalName) + { + URLCacheContainer_UnlockIndex(pContainer, pHeader); + SetLastError(ERROR_INVALID_DATA); + return FALSE; + } + TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl); TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo); @@ -2142,21 +2183,16 @@ BOOL WINAPI CreateUrlCacheEntryA( IN DWORD dwReserved ) { - DWORD len; WCHAR *url_name; WCHAR *file_extension; WCHAR file_name[MAX_PATH]; BOOL bSuccess = FALSE; DWORD dwError = 0; - if ((len = MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, NULL, 0)) != 0 && - (url_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0) + if (lpszUrlName && (url_name = heap_strdupAtoW(lpszUrlName))) { - MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, url_name, len); - if ((len = MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, NULL, 0)) != 0 && - (file_extension = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0) + if (lpszFileExtension && (file_extension = heap_strdupAtoW(lpszFileExtension))) { - MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, file_extension, len); if (CreateUrlCacheEntryW(url_name, dwExpectedFileSize, file_extension, file_name, dwReserved)) { if (WideCharToMultiByte(CP_ACP, 0, file_name, -1, lpszFileName, MAX_PATH, NULL, NULL) < MAX_PATH) @@ -2211,7 +2247,11 @@ BOOL WINAPI CreateUrlCacheEntryW( BOOL bFound = FALSE; int count; DWORD error; + HANDLE hFile; + FILETIME ft; + static const WCHAR szWWW[] = {'w','w','w',0}; + static const WCHAR fmt[] = {'%','0','8','X','%','s',0}; TRACE("(%s, 0x%08x, %s, %p, 0x%08x)\n", debugstr_w(lpszUrlName), @@ -2221,11 +2261,7 @@ BOOL WINAPI CreateUrlCacheEntryW( dwReserved); if (dwReserved) - { - ERR("dwReserved != 0\n"); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } + FIXME("dwReserved 0x%08x\n", dwReserved); lpszUrlEnd = lpszUrlName + strlenW(lpszUrlName); @@ -2318,7 +2354,6 @@ BOOL WINAPI CreateUrlCacheEntryW( for (i = 0; i < 255; i++) { static const WCHAR szFormat[] = {'[','%','u',']','%','s',0}; - HANDLE hFile; WCHAR *p; wsprintfW(lpszFileNameNoPath + countnoextension, szFormat, i, szExtension); @@ -2346,6 +2381,18 @@ BOOL WINAPI CreateUrlCacheEntryW( } } + GetSystemTimeAsFileTime(&ft); + wsprintfW(lpszFileNameNoPath + countnoextension, fmt, ft.dwLowDateTime, szExtension); + + TRACE("Trying: %s\n", debugstr_w(lpszFileName)); + hFile = CreateFileW(lpszFileName, GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL); + if (hFile != INVALID_HANDLE_VALUE) + { + CloseHandle(hFile); + return TRUE; + } + + WARN("Could not find a unique filename\n"); return FALSE; } @@ -2447,25 +2494,17 @@ static BOOL CommitUrlCacheEntryInternal( if (!(pHeader = URLCacheContainer_LockIndex(pContainer))) return FALSE; - len = WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, NULL, 0, NULL, NULL); - lpszUrlNameA = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char)); + lpszUrlNameA = heap_strdupWtoA(lpszUrlName); if (!lpszUrlNameA) { error = GetLastError(); goto cleanup; } - WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, lpszUrlNameA, len, NULL, NULL); - if (lpszFileExtension) + if (lpszFileExtension && !(lpszFileExtensionA = heap_strdupWtoA(lpszFileExtension))) { - len = WideCharToMultiByte(CP_ACP, 0, lpszFileExtension, -1, NULL, 0, NULL, NULL); - lpszFileExtensionA = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char)); - if (!lpszFileExtensionA) - { - error = GetLastError(); - goto cleanup; - } - WideCharToMultiByte(CP_ACP, 0, lpszFileExtension, -1, lpszFileExtensionA, len, NULL, NULL); + error = GetLastError(); + goto cleanup; } if (URLCache_FindHash(pHeader, lpszUrlNameA, &pHashEntry)) @@ -2622,7 +2661,6 @@ BOOL WINAPI CommitUrlCacheEntryA( IN LPCSTR lpszOriginalUrl ) { - DWORD len; WCHAR *url_name = NULL; WCHAR *local_file_name = NULL; WCHAR *original_url = NULL; @@ -2638,35 +2676,27 @@ BOOL WINAPI CommitUrlCacheEntryA( debugstr_a(lpszFileExtension), debugstr_a(lpszOriginalUrl)); - len = MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, NULL, 0); - url_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + url_name = heap_strdupAtoW(lpszUrlName); if (!url_name) goto cleanup; - MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, url_name, len); if (lpszLocalFileName) { - len = MultiByteToWideChar(CP_ACP, 0, lpszLocalFileName, -1, NULL, 0); - local_file_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + local_file_name = heap_strdupAtoW(lpszLocalFileName); if (!local_file_name) goto cleanup; - MultiByteToWideChar(CP_ACP, 0, lpszLocalFileName, -1, local_file_name, len); } if (lpszFileExtension) { - len = MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, NULL, 0); - file_extension = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + file_extension = heap_strdupAtoW(lpszFileExtension); if (!file_extension) goto cleanup; - MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, file_extension, len); } if (lpszOriginalUrl) { - len = MultiByteToWideChar(CP_ACP, 0, lpszOriginalUrl, -1, NULL, 0); - original_url = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + original_url = heap_strdupAtoW(lpszOriginalUrl); if (!original_url) goto cleanup; - MultiByteToWideChar(CP_ACP, 0, lpszOriginalUrl, -1, original_url, len); } bSuccess = CommitUrlCacheEntryInternal(url_name, local_file_name, ExpireTime, LastModifiedTime, @@ -2712,12 +2742,8 @@ BOOL WINAPI CommitUrlCacheEntryW( debugstr_w(lpszFileExtension), debugstr_w(lpszOriginalUrl)); - if (!lpHeaderInfo || - ((len = WideCharToMultiByte(CP_ACP, 0, lpHeaderInfo, -1, NULL, 0, NULL, NULL)) != 0 && - (header_info = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR) * len)) != 0)) + if (!lpHeaderInfo || (header_info = heap_strdupWtoA(lpHeaderInfo))) { - if (header_info) - WideCharToMultiByte(CP_ACP, 0, lpHeaderInfo, -1, header_info, len, NULL, NULL); if (CommitUrlCacheEntryInternal(lpszUrlName, lpszLocalFileName, ExpireTime, LastModifiedTime, CacheEntryType, (LPBYTE)header_info, len, lpszFileExtension, lpszOriginalUrl)) { @@ -2940,19 +2966,16 @@ BOOL WINAPI DeleteUrlCacheEntryW(LPCWSTR lpszUrlName) struct _HASH_ENTRY * pHashEntry; CACHEFILE_ENTRY * pEntry; LPSTR urlA; - int url_len; DWORD error; TRACE("(%s)\n", debugstr_w(lpszUrlName)); - url_len = WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, NULL, 0, NULL, NULL); - urlA = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(CHAR)); + urlA = heap_strdupWtoA(lpszUrlName); if (!urlA) { SetLastError(ERROR_OUTOFMEMORY); return FALSE; } - WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, urlA, url_len, NULL, NULL); error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer); if (error != ERROR_SUCCESS) @@ -3133,14 +3156,12 @@ INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryA(LPCSTR lpszUrlSearchPattern, pEntryHandle->dwMagic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC; if (lpszUrlSearchPattern) { - int len = MultiByteToWideChar(CP_ACP, 0, lpszUrlSearchPattern, -1, NULL, 0); - pEntryHandle->lpszUrlSearchPattern = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + pEntryHandle->lpszUrlSearchPattern = heap_strdupAtoW(lpszUrlSearchPattern); if (!pEntryHandle->lpszUrlSearchPattern) { HeapFree(GetProcessHeap(), 0, pEntryHandle); return NULL; } - MultiByteToWideChar(CP_ACP, 0, lpszUrlSearchPattern, -1, pEntryHandle->lpszUrlSearchPattern, len); } else pEntryHandle->lpszUrlSearchPattern = NULL; @@ -3174,14 +3195,12 @@ INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryW(LPCWSTR lpszUrlSearchPattern, pEntryHandle->dwMagic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC; if (lpszUrlSearchPattern) { - int len = strlenW(lpszUrlSearchPattern); - pEntryHandle->lpszUrlSearchPattern = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)); + pEntryHandle->lpszUrlSearchPattern = heap_strdupW(lpszUrlSearchPattern); if (!pEntryHandle->lpszUrlSearchPattern) { HeapFree(GetProcessHeap(), 0, pEntryHandle); return NULL; } - memcpy(pEntryHandle->lpszUrlSearchPattern, lpszUrlSearchPattern, (len + 1) * sizeof(WCHAR)); } else pEntryHandle->lpszUrlSearchPattern = NULL; @@ -3623,10 +3642,26 @@ BOOL WINAPI IsUrlCacheEntryExpiredW( LPCWSTR url, DWORD dwFlags, FILETIME* pftLa /*********************************************************************** * GetDiskInfoA (WININET.@) */ -BOOL WINAPI GetDiskInfoA(PCSTR p0, PDWORD p1, PDWORDLONG p2, PDWORDLONG p3) +BOOL WINAPI GetDiskInfoA(PCSTR path, PDWORD cluster_size, PDWORDLONG free, PDWORDLONG total) { - FIXME("(%p, %p, %p, %p)\n", p0, p1, p2, p3); - return FALSE; + BOOL ret; + ULARGE_INTEGER bytes_free, bytes_total; + + TRACE("(%s, %p, %p, %p)\n", debugstr_a(path), cluster_size, free, total); + + if (!path) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if ((ret = GetDiskFreeSpaceExA(path, NULL, &bytes_total, &bytes_free))) + { + if (cluster_size) *cluster_size = 1; + if (free) *free = bytes_free.QuadPart; + if (total) *total = bytes_total.QuadPart; + } + return ret; } /*********************************************************************** @@ -3637,3 +3672,12 @@ DWORD WINAPI RegisterUrlCacheNotification(LPVOID a, DWORD b, DWORD c, DWORD d, D FIXME("(%p %x %x %x %x %x)\n", a, b, c, d, e, f); return 0; } + +/*********************************************************************** + * IncrementUrlCacheHeaderData (WININET.@) + */ +BOOL WINAPI IncrementUrlCacheHeaderData(DWORD index, LPDWORD data) +{ + FIXME("(%u, %p)\n", index, data); + return FALSE; +} diff --git a/dll/win32/wininet/utility.c b/dll/win32/wininet/utility.c index b0d9c9c91c6..66fbecdd653 100644 --- a/dll/win32/wininet/utility.c +++ b/dll/win32/wininet/utility.c @@ -25,6 +25,10 @@ #include "config.h" #include "wine/port.h" +#if defined(__MINGW32__) || defined (_MSC_VER) +#include +#endif + #include #include #include @@ -40,6 +44,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(wininet); +#ifndef HAVE_GETADDRINFO + /* critical section to protect non-reentrant gethostbyname() */ static CRITICAL_SECTION cs_gethostbyname; static CRITICAL_SECTION_DEBUG critsect_debug = @@ -50,6 +56,8 @@ static CRITICAL_SECTION_DEBUG critsect_debug = }; static CRITICAL_SECTION cs_gethostbyname = { &critsect_debug, -1, 0, 0, 0, 0 }; +#endif + #define TIME_STRING_LEN 30 time_t ConvertTimeString(LPCWSTR asctime) @@ -137,12 +145,18 @@ time_t ConvertTimeString(LPCWSTR asctime) BOOL GetAddress(LPCWSTR lpszServerName, INTERNET_PORT nServerPort, - struct sockaddr_in *psa) + struct sockaddr *psa, socklen_t *sa_len) { WCHAR *found; char *name; int len, sz; +#ifdef HAVE_GETADDRINFO + struct addrinfo *res, hints; + int ret; +#else struct hostent *phe; + struct sockaddr_in *sin = (struct sockaddr_in *)psa; +#endif TRACE("%s\n", debugstr_w(lpszServerName)); @@ -158,27 +172,75 @@ BOOL GetAddress(LPCWSTR lpszServerName, INTERNET_PORT nServerPort, len = strlenW(lpszServerName); sz = WideCharToMultiByte( CP_UNIXCP, 0, lpszServerName, len, NULL, 0, NULL, NULL ); - name = HeapAlloc(GetProcessHeap(), 0, sz+1); + if (!(name = HeapAlloc( GetProcessHeap(), 0, sz + 1 ))) return FALSE; WideCharToMultiByte( CP_UNIXCP, 0, lpszServerName, len, name, sz, NULL, NULL ); name[sz] = 0; +#ifdef HAVE_GETADDRINFO + memset( &hints, 0, sizeof(struct addrinfo) ); + /* Prefer IPv4 to IPv6 addresses, since some servers do not listen on + * their IPv6 addresses even though they have IPv6 addresses in the DNS. + */ + hints.ai_family = AF_INET; + + ret = getaddrinfo( name, NULL, &hints, &res ); + HeapFree( GetProcessHeap(), 0, name ); + if (ret != 0) + { + TRACE("failed to get IPv4 address of %s (%s), retrying with IPv6\n", debugstr_w(lpszServerName), gai_strerror(ret)); + hints.ai_family = AF_INET6; + ret = getaddrinfo( name, NULL, &hints, &res ); + if (ret != 0) + { + TRACE("failed to get address of %s (%s)\n", debugstr_w(lpszServerName), gai_strerror(ret)); + return FALSE; + } + } + if (*sa_len < res->ai_addrlen) + { + WARN("address too small\n"); + freeaddrinfo( res ); + return FALSE; + } + *sa_len = res->ai_addrlen; + memcpy( psa, res->ai_addr, res->ai_addrlen ); + /* Copy port */ + switch (res->ai_family) + { + case AF_INET: + ((struct sockaddr_in *)psa)->sin_port = htons(nServerPort); + break; + case AF_INET6: + ((struct sockaddr_in6 *)psa)->sin6_port = htons(nServerPort); + break; + } + + freeaddrinfo( res ); +#else EnterCriticalSection( &cs_gethostbyname ); phe = gethostbyname(name); HeapFree( GetProcessHeap(), 0, name ); if (NULL == phe) { - TRACE("Failed to get hostname: (%s)\n", debugstr_w(lpszServerName) ); + TRACE("failed to get address of %s (%d)\n", debugstr_w(lpszServerName), h_errno); LeaveCriticalSection( &cs_gethostbyname ); return FALSE; } - - memset(psa,0,sizeof(struct sockaddr_in)); - memcpy((char *)&psa->sin_addr, phe->h_addr, phe->h_length); - psa->sin_family = phe->h_addrtype; - psa->sin_port = htons(nServerPort); + if (*sa_len < sizeof(struct sockaddr_in)) + { + WARN("address too small\n"); + LeaveCriticalSection( &cs_gethostbyname ); + return FALSE; + } + *sa_len = sizeof(struct sockaddr_in); + memset(sin,0,sizeof(struct sockaddr_in)); + memcpy((char *)&sin->sin_addr, phe->h_addr, phe->h_length); + sin->sin_family = phe->h_addrtype; + sin->sin_port = htons(nServerPort); LeaveCriticalSection( &cs_gethostbyname ); +#endif return TRUE; } @@ -224,7 +286,7 @@ static const char *get_callback_name(DWORD dwInternetStatus) { return "Unknown"; } -VOID INTERNET_SendCallback(LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext, +VOID INTERNET_SendCallback(object_header_t *hdr, DWORD_PTR dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInfo, DWORD dwStatusInfoLength) { @@ -244,11 +306,11 @@ VOID INTERNET_SendCallback(LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext, case INTERNET_STATUS_NAME_RESOLVED: case INTERNET_STATUS_CONNECTING_TO_SERVER: case INTERNET_STATUS_CONNECTED_TO_SERVER: - lpvNewInfo = WININET_strdup_AtoW(lpvStatusInfo); + lpvNewInfo = heap_strdupAtoW(lpvStatusInfo); break; case INTERNET_STATUS_RESOLVING_NAME: case INTERNET_STATUS_REDIRECT: - lpvNewInfo = WININET_strdupW(lpvStatusInfo); + lpvNewInfo = heap_strdupW(lpvStatusInfo); break; } }else { @@ -262,7 +324,7 @@ VOID INTERNET_SendCallback(LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext, break; case INTERNET_STATUS_RESOLVING_NAME: case INTERNET_STATUS_REDIRECT: - lpvNewInfo = WININET_strdup_WtoA(lpvStatusInfo); + lpvNewInfo = heap_strdupWtoA(lpvStatusInfo); break; } } @@ -294,7 +356,7 @@ static void SendAsyncCallbackProc(WORKREQUEST *workRequest) HeapFree(GetProcessHeap(), 0, req->lpvStatusInfo); } -VOID SendAsyncCallback(LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext, +void SendAsyncCallback(object_header_t *hdr, DWORD_PTR dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInfo, DWORD dwStatusInfoLength) { diff --git a/dll/win32/wininet/wininet.rbuild b/dll/win32/wininet/wininet.rbuild index 4a83d0b0ac4..45b87b18665 100644 --- a/dll/win32/wininet/wininet.rbuild +++ b/dll/win32/wininet/wininet.rbuild @@ -22,6 +22,7 @@ secur32 crypt32 ws2_32 + pseh cookie.c dialogs.c ftp.c diff --git a/dll/win32/wininet/wininet.spec b/dll/win32/wininet/wininet.spec index dfbc38c02fc..46dd04334e6 100644 --- a/dll/win32/wininet/wininet.spec +++ b/dll/win32/wininet/wininet.spec @@ -1,5 +1,5 @@ 101 stub -noname DoConnectoidsExist -102 stub -noname GetDiskInfoA +102 stdcall -noname GetDiskInfoA(str ptr ptr ptr) 103 stub -noname PerformOperationOverUrlCacheA 104 stub -noname HttpCheckDavComplianceA 105 stub -noname HttpCheckDavComplianceW @@ -9,7 +9,7 @@ 111 stub -noname ExportCookieFileW 112 stub -noname IsProfilesEnabled 116 stub -noname IsDomainlegalCookieDomainA -117 stub -noname IsDomainLegalCookieDomainW +117 stdcall -noname IsDomainLegalCookieDomainW(wstr wstr) 118 stub -noname FindP3PPolicySymbol 120 stub -noname MapResourceToPolicy 121 stub -noname GetP3PPolicy @@ -50,8 +50,8 @@ @ stdcall FindNextUrlCacheGroup(long ptr ptr) @ stub ForceNexusLookup @ stub ForceNexusLookupExW -@ stub FreeUrlCacheSpaceA -@ stub FreeUrlCacheSpaceW +@ stdcall FreeUrlCacheSpaceA(str long long) +@ stdcall FreeUrlCacheSpaceW(wstr long long) @ stdcall FtpCommandA(long long long str ptr ptr) @ stdcall FtpCommandW(long long long wstr ptr ptr) @ stdcall FtpCreateDirectoryA(ptr str) @@ -109,7 +109,7 @@ @ stdcall HttpSendRequestExA(long ptr ptr long long) @ stdcall HttpSendRequestExW(long ptr ptr long long) @ stdcall HttpSendRequestW(ptr wstr long ptr long) -@ stub IncrementUrlCacheHeaderData +@ stdcall IncrementUrlCacheHeaderData(long ptr) @ stub InternetAlgIdToStringA @ stub InternetAlgIdToStringW @ stdcall InternetAttemptConnect(long) @@ -213,10 +213,10 @@ @ stdcall IsUrlCacheEntryExpiredW(wstr long ptr) @ stub LoadUrlCacheContent @ stub ParseX509EncodedCertificateForListBoxEntry -@ stub PrivacyGetZonePreferenceW # (long long ptr ptr ptr) -@ stub PrivacySetZonePreferenceW # (long long long wstr) +@ stdcall PrivacyGetZonePreferenceW(long long ptr ptr ptr) +@ stdcall PrivacySetZonePreferenceW(long long long wstr) @ stdcall ReadUrlCacheEntryStream(ptr long ptr ptr long) -@ stub RegisterUrlCacheNotification +@ stdcall RegisterUrlCacheNotification(ptr long long long long long) @ stdcall ResumeSuspendedDownload(long long) @ stdcall RetrieveUrlCacheEntryFileA(str ptr ptr long) @ stdcall RetrieveUrlCacheEntryFileW(wstr ptr ptr long) diff --git a/dll/win32/wininet/wininet_Bg.rc b/dll/win32/wininet/wininet_Bg.rc index 52d797ed751..b25356e074e 100644 --- a/dll/win32/wininet/wininet_Bg.rc +++ b/dll/win32/wininet/wininet_Bg.rc @@ -16,6 +16,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_BULGARIAN, SUBLANG_DEFAULT IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 diff --git a/dll/win32/wininet/wininet_Cs.rc b/dll/win32/wininet/wininet_Cs.rc index 9ca75397c4f..443c0175190 100644 --- a/dll/win32/wininet/wininet_Cs.rc +++ b/dll/win32/wininet/wininet_Cs.rc @@ -19,6 +19,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_CZECH, SUBLANG_DEFAULT /* Czech strings in CP1250 */ diff --git a/dll/win32/wininet/wininet_Da.rc b/dll/win32/wininet/wininet_Da.rc index 515dcabd8b3..6b37857ed54 100644 --- a/dll/win32/wininet/wininet_Da.rc +++ b/dll/win32/wininet/wininet_Da.rc @@ -16,6 +16,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_DANISH, SUBLANG_DEFAULT IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 diff --git a/dll/win32/wininet/wininet_De.rc b/dll/win32/wininet/wininet_De.rc index 9fb6be58c8d..f602a97a97d 100644 --- a/dll/win32/wininet/wininet_De.rc +++ b/dll/win32/wininet/wininet_De.rc @@ -1,5 +1,6 @@ /* * Copyright 2004 Henning Gerhardt + * Copyright 2009 André Hentschel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -16,6 +17,10 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + +#pragma code_page(65001) + LANGUAGE LANG_GERMAN, SUBLANG_NEUTRAL IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 @@ -25,8 +30,8 @@ FONT 8, "MS Shell Dlg" { LTEXT "Geben Sie Benutzernamen und Kennwort ein:", -1, 40, 6, 150, 15 LTEXT "Proxy", -1, 40, 26, 50, 10 - LTEXT "Realm", -1, 40, 46, 50, 10 - LTEXT "Ben&utzername", -1, 40, 66, 50, 10 + LTEXT "Bereich", -1, 40, 46, 50, 10 + LTEXT "Ben&utzer", -1, 40, 66, 50, 10 LTEXT "Kenn&wort", -1, 40, 86, 50, 10 LTEXT "" IDC_PROXY, 80, 26, 150, 14, 0 LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 @@ -38,6 +43,26 @@ FONT 8, "MS Shell Dlg" PUSHBUTTON "Abbrechen", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP } +IDD_AUTHDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Benutzeranmeldung" +FONT 8, "MS Shell Dlg" +{ + LTEXT "Geben Sie Benutzernamen und Kennwort ein:", -1, 40, 6, 150, 15 + LTEXT "Server", -1, 40, 26, 50, 10 + LTEXT "Bereich", -1, 40, 46, 50, 10 + LTEXT "Benutzer", -1, 40, 66, 50, 10 + LTEXT "Kennwort", -1, 40, 86, 50, 10 + LTEXT "" IDC_SERVER, 80, 26, 150, 14, 0 + LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 + EDITTEXT IDC_USERNAME, 80, 66, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP + EDITTEXT IDC_PASSWORD, 80, 86, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD + CHECKBOX "Dieses &Kennwort speichern (unsicher)", IDC_SAVEPASSWORD, + 80, 106, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP + PUSHBUTTON "OK", IDOK, 98, 126, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON + PUSHBUTTON "Abbrechen", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP +} + STRINGTABLE DISCARDABLE { IDS_LANCONNECTION "LAN Verbindung" diff --git a/dll/win32/wininet/wininet_En.rc b/dll/win32/wininet/wininet_En.rc index 66837dabc8e..d22d249f1cd 100644 --- a/dll/win32/wininet/wininet_En.rc +++ b/dll/win32/wininet/wininet_En.rc @@ -16,6 +16,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 @@ -38,6 +40,26 @@ FONT 8, "MS Shell Dlg" PUSHBUTTON "Cancel", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP } +IDD_AUTHDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Authentication Required" +FONT 8, "MS Shell Dlg" +{ + LTEXT "Please enter your username and password:", -1, 40, 6, 150, 15 + LTEXT "Server", -1, 40, 26, 50, 10 + LTEXT "Realm", -1, 40, 46, 50, 10 + LTEXT "User", -1, 40, 66, 50, 10 + LTEXT "Password", -1, 40, 86, 50, 10 + LTEXT "" IDC_SERVER, 80, 26, 150, 14, 0 + LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 + EDITTEXT IDC_USERNAME, 80, 66, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP + EDITTEXT IDC_PASSWORD, 80, 86, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD + CHECKBOX "&Save this password (insecure)", IDC_SAVEPASSWORD, + 80, 106, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP + PUSHBUTTON "OK", IDOK, 98, 126, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON + PUSHBUTTON "Cancel", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP +} + STRINGTABLE DISCARDABLE { IDS_LANCONNECTION "LAN Connection" diff --git a/dll/win32/wininet/wininet_Eo.rc b/dll/win32/wininet/wininet_Eo.rc index a145e263621..3fa19f37897 100644 --- a/dll/win32/wininet/wininet_Eo.rc +++ b/dll/win32/wininet/wininet_Eo.rc @@ -18,6 +18,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_ESPERANTO, SUBLANG_DEFAULT IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 diff --git a/dll/win32/wininet/wininet_Es.rc b/dll/win32/wininet/wininet_Es.rc index bbf08aeb2f6..c9ce2cebbe2 100644 --- a/dll/win32/wininet/wininet_Es.rc +++ b/dll/win32/wininet/wininet_Es.rc @@ -16,6 +16,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_SPANISH, SUBLANG_NEUTRAL IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 diff --git a/dll/win32/wininet/wininet_Fi.rc b/dll/win32/wininet/wininet_Fi.rc index 176a00337ce..df5ca723044 100644 --- a/dll/win32/wininet/wininet_Fi.rc +++ b/dll/win32/wininet/wininet_Fi.rc @@ -16,6 +16,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_FINNISH, SUBLANG_DEFAULT IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 diff --git a/dll/win32/wininet/wininet_Fr.rc b/dll/win32/wininet/wininet_Fr.rc index 0435b8eb711..74ee208a7ee 100644 --- a/dll/win32/wininet/wininet_Fr.rc +++ b/dll/win32/wininet/wininet_Fr.rc @@ -3,8 +3,9 @@ * French language support * * Copyright 2003 Mike McCormack for CodeWeavers - * Copyright 2003 Vincent Bron + * Copyright 2003 Vincent Béron * Copyright 2005 Jonathan Ernst + * Copyright 2009 Frédéric Delanoy * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -21,29 +22,54 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + +/* UTF-8 */ +#pragma code_page(65001) + LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL -IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 +IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 218, 150 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Entrez le mot de passe rseau" +CAPTION "Entrez le mot de passe réseau" FONT 8, "MS Shell Dlg" { - LTEXT "Entrez votre nom d'utilisateur et votre mot de passe :", -1, 40, 6, 150, 15 - LTEXT "Mandataire", -1, 40, 26, 50, 10 - LTEXT "Domaine", -1, 40, 46, 50, 10 - LTEXT "Utilisateur", -1, 40, 66, 50, 10 - LTEXT "Mot de passe", -1, 40, 86, 50, 10 - LTEXT "" IDC_PROXY, 80, 26, 150, 14, 0 - LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 - EDITTEXT IDC_USERNAME, 80, 66, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP - EDITTEXT IDC_PASSWORD, 80, 86, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD - CHECKBOX "&Enregistrer ce mot de passe (risqu)", IDC_SAVEPASSWORD, - 80, 106, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP - PUSHBUTTON "OK", IDOK, 98, 126, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON - PUSHBUTTON "Annuler", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP + LTEXT "Entrez votre nom d'utilisateur et votre mot de passe :", -1, 10, 8, 173, 12 + LTEXT "Serveur mandataire", -1, 10, 28, 50, 17 + LTEXT "Domaine", -1, 10, 50, 50, 10 + LTEXT "Utilisateur", -1, 10, 71, 50, 10 + LTEXT "Mot de passe", -1, 10, 90, 50, 10 + LTEXT "" IDC_PROXY, 58, 28, 150, 14, 0 + LTEXT "" IDC_REALM, 58, 48, 150, 14, 0 + EDITTEXT IDC_USERNAME, 58, 68, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP + EDITTEXT IDC_PASSWORD, 58, 88, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD + CHECKBOX "&Enregistrer ce mot de passe (risqué)", IDC_SAVEPASSWORD, + 58, 108, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP + PUSHBUTTON "OK", IDOK, 87, 128, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON + PUSHBUTTON "Annuler", IDCANCEL, 147, 128, 56, 14, WS_GROUP | WS_TABSTOP +} + +IDD_AUTHDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 218, 150 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Authentification requise" +FONT 8, "MS Shell Dlg" +{ + LTEXT "Entrez votre nom d'utilisateur et votre mot de passe :", -1, 10, 8, 173, 12 + LTEXT "Serveur", -1, 10, 28, 50, 17 + LTEXT "Domaine", -1, 10, 50, 50, 10 + LTEXT "Utilisateur", -1, 10, 71, 50, 10 + LTEXT "Mot de passe", -1, 10, 90, 50, 10 + LTEXT "" IDC_SERVER, 58, 28, 150, 14, 0 + LTEXT "" IDC_REALM, 58, 48, 150, 14, 0 + EDITTEXT IDC_USERNAME, 58, 68, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP + EDITTEXT IDC_PASSWORD, 58, 88, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD + CHECKBOX "&Enregistrer ce mot de passe (risqué)", IDC_SAVEPASSWORD, + 58, 108, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP + PUSHBUTTON "OK", IDOK, 87, 128, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON + PUSHBUTTON "Annuler", IDCANCEL, 147, 128, 56, 14, WS_GROUP | WS_TABSTOP } STRINGTABLE DISCARDABLE { - IDS_LANCONNECTION "Connexion LAN" + IDS_LANCONNECTION "Connexion réseau local (LAN)" } diff --git a/dll/win32/wininet/wininet_Hu.rc b/dll/win32/wininet/wininet_Hu.rc index c9704f9080b..b19e03dc007 100644 --- a/dll/win32/wininet/wininet_Hu.rc +++ b/dll/win32/wininet/wininet_Hu.rc @@ -16,6 +16,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_HUNGARIAN, SUBLANG_DEFAULT IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 diff --git a/dll/win32/wininet/wininet_It.rc b/dll/win32/wininet/wininet_It.rc index 45045460c33..04f71c5f177 100644 --- a/dll/win32/wininet/wininet_It.rc +++ b/dll/win32/wininet/wininet_It.rc @@ -18,6 +18,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_ITALIAN, SUBLANG_NEUTRAL IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 @@ -40,6 +42,26 @@ FONT 8, "MS Shell Dlg" PUSHBUTTON "Annulla", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP } +IDD_AUTHDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Autenticazione richiesta" +FONT 8, "MS Shell Dlg" +{ + LTEXT "Inserire il nome utente e la password:", -1, 40, 6, 150, 15 + LTEXT "Server", -1, 40, 26, 50, 10 + LTEXT "Realm", -1, 40, 46, 50, 10 + LTEXT "Utente", -1, 40, 66, 50, 10 + LTEXT "Password", -1, 40, 86, 50, 10 + LTEXT "" IDC_SERVER, 80, 26, 150, 14, 0 + LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 + EDITTEXT IDC_USERNAME, 80, 66, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP + EDITTEXT IDC_PASSWORD, 80, 86, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD + CHECKBOX "&Memorizza la password (RISCHIOSO)", IDC_SAVEPASSWORD, + 80, 106, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP + PUSHBUTTON "OK", IDOK, 98, 126, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON + PUSHBUTTON "Annulla", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP +} + STRINGTABLE DISCARDABLE { IDS_LANCONNECTION "Connessione LAN" diff --git a/dll/win32/wininet/wininet_Ja.rc b/dll/win32/wininet/wininet_Ja.rc index 615d7be1c86..e179b849254 100644 --- a/dll/win32/wininet/wininet_Ja.rc +++ b/dll/win32/wininet/wininet_Ja.rc @@ -16,6 +16,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + /* UTF-8 */ #pragma code_page(65001) @@ -45,5 +47,3 @@ STRINGTABLE DISCARDABLE { IDS_LANCONNECTION "LAN 接続" } - -#pragma code_page(default) diff --git a/dll/win32/wininet/wininet_Ko.rc b/dll/win32/wininet/wininet_Ko.rc index 26ed4a2fad2..5c2595a9b37 100644 --- a/dll/win32/wininet/wininet_Ko.rc +++ b/dll/win32/wininet/wininet_Ko.rc @@ -16,6 +16,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_KOREAN, SUBLANG_DEFAULT IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 diff --git a/dll/win32/wininet/wininet_Lt.rc b/dll/win32/wininet/wininet_Lt.rc new file mode 100644 index 00000000000..cd4bf482e35 --- /dev/null +++ b/dll/win32/wininet/wininet_Lt.rc @@ -0,0 +1,69 @@ +/* + * Copyright 2009 Aurimas Fišeras + * + * 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 "resource.h" + +/* UTF-8 */ +#pragma code_page(65001) + +LANGUAGE LANG_LITHUANIAN, SUBLANG_NEUTRAL + +IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Įveskite tinklo slaptažodį" +FONT 8, "MS Shell Dlg" +{ + LTEXT "Įveskite savo naudotojo vardą ir slaptažodį:", -1, 40, 6, 150, 15 + LTEXT "Įgaliot. serv.", -1, 40, 26, 50, 10 + LTEXT "Sritis", -1, 40, 46, 50, 10 + LTEXT "Naudotojas", -1, 40, 66, 50, 10 + LTEXT "Slaptažodis", -1, 40, 86, 50, 10 + LTEXT "" IDC_PROXY, 80, 26, 150, 14, 0 + LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 + EDITTEXT IDC_USERNAME, 80, 66, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP + EDITTEXT IDC_PASSWORD, 80, 86, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD + CHECKBOX "Į&rašyti šį slaptažodį (nesaugu)", IDC_SAVEPASSWORD, + 80, 106, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP + PUSHBUTTON "Gerai", IDOK, 98, 126, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON + PUSHBUTTON "Atsisakyti", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP +} + +IDD_AUTHDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Reikalingas tapatumo nustatymas" +FONT 8, "MS Shell Dlg" +{ + LTEXT "Įveskite savo naudotojo vardą ir slaptažodį:", -1, 40, 6, 150, 15 + LTEXT "Serveris", -1, 40, 26, 50, 10 + LTEXT "Sritis", -1, 40, 46, 50, 10 + LTEXT "Naudotojas", -1, 40, 66, 50, 10 + LTEXT "Slaptažodis", -1, 40, 86, 50, 10 + LTEXT "" IDC_SERVER, 80, 26, 150, 14, 0 + LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 + EDITTEXT IDC_USERNAME, 80, 66, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP + EDITTEXT IDC_PASSWORD, 80, 86, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD + CHECKBOX "Į&rašyti šį slaptažodį (nesaugu)", IDC_SAVEPASSWORD, + 80, 106, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP + PUSHBUTTON "Gerai", IDOK, 98, 126, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON + PUSHBUTTON "Atsisakyti", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP +} + +STRINGTABLE DISCARDABLE +{ + IDS_LANCONNECTION "Vietinio tinklo ryšys" +} diff --git a/dll/win32/wininet/wininet_Nl.rc b/dll/win32/wininet/wininet_Nl.rc index 16c80ccaad8..f0e891c7e19 100644 --- a/dll/win32/wininet/wininet_Nl.rc +++ b/dll/win32/wininet/wininet_Nl.rc @@ -18,6 +18,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_DUTCH, SUBLANG_NEUTRAL IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 @@ -40,6 +42,26 @@ FONT 8, "MS Shell Dlg" PUSHBUTTON "Annuleren", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP } +IDD_AUTHDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Authenticatie vereist" +FONT 8, "MS Shell Dlg" +{ + LTEXT "Voer uw gebruikersnaam en wachtwoord in:", -1, 40, 6, 150, 15 + LTEXT "Server", -1, 40, 26, 50, 10 + LTEXT "Realm", -1, 40, 46, 50, 10 + LTEXT "Gebruikersnaam", -1, 40, 66, 50, 10 + LTEXT "Wachtwoord", -1, 40, 86, 50, 10 + LTEXT "" IDC_SERVER, 80, 26, 150, 14, 0 + LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 + EDITTEXT IDC_USERNAME, 80, 66, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP + EDITTEXT IDC_PASSWORD, 80, 86, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD + CHECKBOX "&Wachtwoord opslaan (onveilig)", IDC_SAVEPASSWORD, + 80, 106, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP + PUSHBUTTON "OK", IDOK, 98, 126, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON + PUSHBUTTON "Annuleren", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP +} + STRINGTABLE DISCARDABLE { IDS_LANCONNECTION "LAN Verbinding" diff --git a/dll/win32/wininet/wininet_No.rc b/dll/win32/wininet/wininet_No.rc index fb885e9030d..1dfa544e4aa 100644 --- a/dll/win32/wininet/wininet_No.rc +++ b/dll/win32/wininet/wininet_No.rc @@ -1,5 +1,5 @@ /* - * Copyright 2005 Alexander N. Srnes + * Copyright 2005-2009 Alexander N. Sørnes * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -16,6 +16,10 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + +#pragma code_page(65001) + LANGUAGE LANG_NORWEGIAN, SUBLANG_NORWEGIAN_BOKMAL IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 @@ -25,7 +29,7 @@ FONT 8, "MS Shell Dlg" { LTEXT "Skriv inn brukernavnet og passordet ditt:", -1, 40, 6, 150, 15 LTEXT "Mellomtjener", -1, 40, 26, 50, 10 - LTEXT "Omrde", -1, 40, 46, 50, 10 + LTEXT "Område", -1, 40, 46, 50, 10 LTEXT "Bruker", -1, 40, 66, 50, 10 LTEXT "Passord", -1, 40, 86, 50, 10 LTEXT "" IDC_PROXY, 80, 26, 150, 14, 0 @@ -38,6 +42,26 @@ FONT 8, "MS Shell Dlg" PUSHBUTTON "Avbryt", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP } +IDD_AUTHDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Pålogging" +FONT 8, "MS Shell Dlg" +{ + LTEXT "Oppgi brukernavn og passord:", -1, 40, 6, 150, 15 + LTEXT "Tjener", -1, 40, 26, 50, 10 + LTEXT "Område", -1, 40, 46, 50, 10 + LTEXT "Bruker", -1, 40, 66, 50, 10 + LTEXT "Passord", -1, 40, 86, 50, 10 + LTEXT "" IDC_SERVER, 80, 26, 150, 14, 0 + LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 + EDITTEXT IDC_USERNAME, 80, 66, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP + EDITTEXT IDC_PASSWORD, 80, 86, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD + CHECKBOX "Lagre pa&ssordet (sikkerhetsrisiko)", IDC_SAVEPASSWORD, + 80, 106, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP + PUSHBUTTON "OK", IDOK, 98, 126, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON + PUSHBUTTON "Avbryt", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP +} + STRINGTABLE DISCARDABLE { IDS_LANCONNECTION "Lokal nettverksforbindelse" diff --git a/dll/win32/wininet/wininet_Pl.rc b/dll/win32/wininet/wininet_Pl.rc index 7ddb399a584..0c76d5335aa 100644 --- a/dll/win32/wininet/wininet_Pl.rc +++ b/dll/win32/wininet/wininet_Pl.rc @@ -17,6 +17,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_POLISH, SUBLANG_DEFAULT IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 diff --git a/dll/win32/wininet/wininet_Pt.rc b/dll/win32/wininet/wininet_Pt.rc index 57dd625a740..95e06e6d6e8 100644 --- a/dll/win32/wininet/wininet_Pt.rc +++ b/dll/win32/wininet/wininet_Pt.rc @@ -1,6 +1,7 @@ /* * Copyright 2003 Marcelo Duarte - * Copyright 2006-2007 Amrico Jos Melo + * Copyright 2006-2007 Américo José Melo + * Copyright 2009 Ricardo Filipe * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -17,6 +18,10 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + +#pragma code_page(65001) + LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 @@ -24,10 +29,10 @@ STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Entrar Senha da Rede" FONT 8, "MS Shell Dlg" { - LTEXT "Por favor, entre com o nome de usurio e a senha:", -1, 40, 6, 150, 15 + LTEXT "Por favor, entre com o nome de usuário e a senha:", -1, 40, 6, 150, 15 LTEXT "Proxy", -1, 40, 26, 50, 10 LTEXT "Realm", -1, 40, 46, 50, 10 - LTEXT "Usurio", -1, 40, 66, 50, 10 + LTEXT "Usuário", -1, 40, 66, 50, 10 LTEXT "Senha", -1, 40, 86, 50, 10 LTEXT "" IDC_PROXY, 80, 26, 150, 14, 0 LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 @@ -61,17 +66,36 @@ FONT 8, "MS Shell Dlg" PUSHBUTTON "Cancelar", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP } +IDD_AUTHDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Autenticação necessária" +FONT 8, "MS Shell Dlg" +{ + LTEXT "Por favor insira o seu nome de utilizador e palavra-passe:", -1, 40, 6, 150, 15 + LTEXT "Servidor", -1, 40, 26, 50, 10 + LTEXT "Reino", -1, 40, 46, 50, 10 + LTEXT "Utilizador", -1, 40, 66, 50, 10 + LTEXT "Palavra-passe", -1, 40, 86, 50, 10 + LTEXT "" IDC_SERVER, 80, 26, 150, 14, 0 + LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 + EDITTEXT IDC_USERNAME, 80, 66, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP + EDITTEXT IDC_PASSWORD, 80, 86, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD + CHECKBOX "&Guardar esta palavra-passe (inseguro)", IDC_SAVEPASSWORD, + 80, 106, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP + PUSHBUTTON "OK", IDOK, 98, 126, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON + PUSHBUTTON "Cancelar", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP +} LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN STRINGTABLE DISCARDABLE { - IDS_LANCONNECTION "Conexo LAN" + IDS_LANCONNECTION "Conexão LAN" } LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE STRINGTABLE DISCARDABLE { - IDS_LANCONNECTION "Ligao LAN" + IDS_LANCONNECTION "Ligação LAN" } diff --git a/dll/win32/wininet/wininet_Ro.rc b/dll/win32/wininet/wininet_Ro.rc index 367bbb5955a..13403eec1a6 100644 --- a/dll/win32/wininet/wininet_Ro.rc +++ b/dll/win32/wininet/wininet_Ro.rc @@ -17,6 +17,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_ROMANIAN, SUBLANG_NEUTRAL #pragma code_page(65001) @@ -28,7 +30,7 @@ FONT 8, "MS Shell Dlg" { LTEXT "Introduceți numele de utilizator și parola:", -1, 40, 6, 150, 15 LTEXT "Proxy", -1, 40, 26, 50, 10 - LTEXT "Realm", -1, 40, 46, 50, 10 + LTEXT "Domeniu", -1, 40, 46, 50, 10 LTEXT "Utilizator", -1, 40, 66, 50, 10 LTEXT "Parolă", -1, 40, 86, 50, 10 LTEXT "" IDC_PROXY, 80, 26, 150, 14, 0 @@ -41,9 +43,27 @@ FONT 8, "MS Shell Dlg" PUSHBUTTON "Renunță", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP } +IDD_AUTHDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Autentificare necesară" +FONT 8, "MS Shell Dlg" +{ + LTEXT "Introduceți numele de utilizator și parola:", -1, 40, 6, 150, 15 + LTEXT "Server", -1, 40, 26, 50, 10 + LTEXT "Domeniu", -1, 40, 46, 50, 10 + LTEXT "Utilizator", -1, 40, 66, 50, 10 + LTEXT "Parolă", -1, 40, 86, 50, 10 + LTEXT "" IDC_SERVER, 80, 26, 150, 14, 0 + LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 + EDITTEXT IDC_USERNAME, 80, 66, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP + EDITTEXT IDC_PASSWORD, 80, 86, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD + CHECKBOX "&Salvează această parolă (nesigur)", IDC_SAVEPASSWORD, + 80, 106, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP + PUSHBUTTON "OK", IDOK, 98, 126, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON + PUSHBUTTON "Renunță", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP +} + STRINGTABLE DISCARDABLE { IDS_LANCONNECTION "Conexiune LAN" } - -#pragma code_page(default) diff --git a/dll/win32/wininet/wininet_Ru.rc b/dll/win32/wininet/wininet_Ru.rc index d75985ba1b7..8d35fe40aab 100644 --- a/dll/win32/wininet/wininet_Ru.rc +++ b/dll/win32/wininet/wininet_Ru.rc @@ -18,29 +18,54 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + +/* UTF-8 */ +#pragma code_page(65001) + LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION " " +CAPTION "Ввод сетевого пароля" FONT 8, "MS Shell Dlg" { - LTEXT " :", -1, 40, 6, 150, 15 - LTEXT "", -1, 40, 26, 50, 10 - LTEXT "", -1, 40, 46, 50, 10 - LTEXT "", -1, 40, 66, 50, 10 - LTEXT "", -1, 40, 86, 50, 10 + LTEXT "Введите имя пользователя и пароль:", -1, 40, 6, 150, 15 + LTEXT "Прокси", -1, 40, 26, 50, 10 + LTEXT "Домен", -1, 40, 46, 50, 10 + LTEXT "Пользователь", -1, 40, 66, 50, 10 + LTEXT "Пароль", -1, 40, 86, 50, 10 LTEXT "" IDC_PROXY, 80, 26, 150, 14, 0 LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 EDITTEXT IDC_USERNAME, 80, 66, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP EDITTEXT IDC_PASSWORD, 80, 86, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD - CHECKBOX "& ()", IDC_SAVEPASSWORD, + CHECKBOX "&Сохранить этот пароль (небезопасно)", IDC_SAVEPASSWORD, 80, 106, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP PUSHBUTTON "OK", IDOK, 98, 126, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON - PUSHBUTTON "", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP + PUSHBUTTON "Отмена", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP +} + +IDD_AUTHDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Требуется идентификация" +FONT 8, "MS Shell Dlg" +{ + LTEXT "Введите имя пользователя и пароль:", -1, 40, 6, 150, 15 + LTEXT "Сервер", -1, 40, 26, 50, 10 + LTEXT "Домен", -1, 40, 46, 50, 10 + LTEXT "Пользователь", -1, 40, 66, 50, 10 + LTEXT "Пароль", -1, 40, 86, 50, 10 + LTEXT "" IDC_SERVER, 80, 26, 150, 14, 0 + LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 + EDITTEXT IDC_USERNAME, 80, 66, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP + EDITTEXT IDC_PASSWORD, 80, 86, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD + CHECKBOX "&Сохранить этот пароль (небезопасно)", IDC_SAVEPASSWORD, + 80, 106, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP + PUSHBUTTON "OK", IDOK, 98, 126, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON + PUSHBUTTON "Отмена", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP } STRINGTABLE DISCARDABLE { - IDS_LANCONNECTION " " + IDS_LANCONNECTION "Сетевое подключение" } diff --git a/dll/win32/wininet/wininet_Si.rc b/dll/win32/wininet/wininet_Si.rc index 93ac9e1f33b..b5bf2914328 100644 --- a/dll/win32/wininet/wininet_Si.rc +++ b/dll/win32/wininet/wininet_Si.rc @@ -16,6 +16,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + #pragma code_page(65001) LANGUAGE LANG_SLOVENIAN, SUBLANG_DEFAULT @@ -44,5 +46,3 @@ STRINGTABLE DISCARDABLE { IDS_LANCONNECTION "LAN povezava" } - -#pragma code_page(default) diff --git a/dll/win32/wininet/wininet_Sv.rc b/dll/win32/wininet/wininet_Sv.rc index 6d71f2ef842..8d3291ec750 100644 --- a/dll/win32/wininet/wininet_Sv.rc +++ b/dll/win32/wininet/wininet_Sv.rc @@ -16,6 +16,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_SWEDISH, SUBLANG_NEUTRAL IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 diff --git a/dll/win32/wininet/wininet_Tr.rc b/dll/win32/wininet/wininet_Tr.rc index dd796777236..8d26cf21694 100644 --- a/dll/win32/wininet/wininet_Tr.rc +++ b/dll/win32/wininet/wininet_Tr.rc @@ -18,6 +18,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_TURKISH, SUBLANG_DEFAULT IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 diff --git a/dll/win32/wininet/wininet_Uk.rc b/dll/win32/wininet/wininet_Uk.rc index be58bb621f2..94a9611888b 100644 --- a/dll/win32/wininet/wininet_Uk.rc +++ b/dll/win32/wininet/wininet_Uk.rc @@ -18,6 +18,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_UKRAINIAN, SUBLANG_DEFAULT IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 diff --git a/dll/win32/wininet/wininet_Zh.rc b/dll/win32/wininet/wininet_Zh.rc index 4406bd87c1a..e2e36ded277 100644 --- a/dll/win32/wininet/wininet_Zh.rc +++ b/dll/win32/wininet/wininet_Zh.rc @@ -18,6 +18,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + /* Chinese text is encoded in UTF-8 */ #pragma code_page(65001) @@ -74,5 +76,3 @@ STRINGTABLE DISCARDABLE { IDS_LANCONNECTION "局域網連接" } - -#pragma code_page(default) diff --git a/drivers/bus/acpi/acpi.rbuild b/drivers/bus/acpi/acpi.rbuild index f2b6a13cbca..cbc124a26f5 100644 --- a/drivers/bus/acpi/acpi.rbuild +++ b/drivers/bus/acpi/acpi.rbuild @@ -4,6 +4,9 @@ + + + diff --git a/drivers/bus/acpi/acpica/acpica.rbuild b/drivers/bus/acpi/acpica/acpica.rbuild index b23eed8d5b2..ce6fee8791f 100644 --- a/drivers/bus/acpi/acpica/acpica.rbuild +++ b/drivers/bus/acpi/acpica/acpica.rbuild @@ -83,9 +83,6 @@ nsxfname.c nsxfobj.c - psargs.c psloop.c diff --git a/drivers/bus/acpi/acpica/events/evgpe.c b/drivers/bus/acpi/acpica/events/evgpe.c index 17738b38404..00d72e54722 100644 --- a/drivers/bus/acpi/acpica/events/evgpe.c +++ b/drivers/bus/acpi/acpica/events/evgpe.c @@ -505,7 +505,7 @@ AcpiEvGpeDetect ( UINT8 EnabledStatusByte; UINT32 StatusReg; UINT32 EnableReg; - ACPI_CPU_FLAGS Flags; + //ACPI_CPU_FLAGS Flags; UINT32 i; UINT32 j; @@ -524,7 +524,7 @@ AcpiEvGpeDetect ( * Note: Not necessary to obtain the hardware lock, since the GPE * registers are owned by the GpeLock. */ - Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); + //Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); /* Examine all GPE blocks attached to this interrupt level */ @@ -596,7 +596,7 @@ AcpiEvGpeDetect ( UnlockAndExit: - AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); + //AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); return (IntStatus); } diff --git a/drivers/bus/acpi/acpica/osl/osl.c b/drivers/bus/acpi/acpica/osl/osl.c deleted file mode 100644 index a8c240a77d2..00000000000 --- a/drivers/bus/acpi/acpica/osl/osl.c +++ /dev/null @@ -1,751 +0,0 @@ -/******************************************************************************* -* * -* ACPI Component Architecture Operating System Layer (OSL) for ReactOS * -* * -*******************************************************************************/ - -#include - -#define NDEBUG -#include - -#define NUM_SEMAPHORES 128 - -static PKINTERRUPT AcpiInterrupt; -static BOOLEAN AcpiInterruptHandlerRegistered = FALSE; -static ACPI_OSD_HANDLER AcpiIrqHandler = NULL; -static PVOID AcpiIrqContext = NULL; -static ULONG AcpiIrqNumber = 0; -static KDPC AcpiDpc; -static PVOID IVTVirtualAddress = NULL; - - -typedef struct semaphore_entry -{ - UINT16 MaxUnits; - UINT16 CurrentUnits; - void *OsHandle; -} SEMAPHORE_ENTRY; - -static SEMAPHORE_ENTRY AcpiGbl_Semaphores[NUM_SEMAPHORES]; - -VOID NTAPI -OslDpcStub( - IN PKDPC Dpc, - IN PVOID DeferredContext, - IN PVOID SystemArgument1, - IN PVOID SystemArgument2) -{ - ACPI_OSD_EXEC_CALLBACK Routine = (ACPI_OSD_EXEC_CALLBACK)SystemArgument1; - - DPRINT("OslDpcStub()\n"); - DPRINT("Calling [%p]([%p])\n", Routine, SystemArgument2); - (*Routine)(SystemArgument2); -} - -BOOLEAN NTAPI -OslIsrStub( - PKINTERRUPT Interrupt, - PVOID ServiceContext) -{ - INT32 Status; - - Status = (*AcpiIrqHandler)(AcpiIrqContext); - - if (ACPI_SUCCESS(Status)) - return TRUE; - else - return FALSE; -} - -ACPI_STATUS -AcpiOsRemoveInterruptHandler ( - UINT32 InterruptNumber, - ACPI_OSD_HANDLER ServiceRoutine); - -ACPI_STATUS -AcpiOsInitialize (void) -{ - DPRINT("AcpiOsInitialize called\n"); - -#ifndef NDEBUG - /* Verboseness level of the acpica core */ - AcpiDbgLevel = 0x00FFFFFF; - AcpiDbgLayer = 0xFFFFFFFF; -#endif - - UINT32 i; - - for (i = 0; i < NUM_SEMAPHORES; i++) - { - AcpiGbl_Semaphores[i].OsHandle = NULL; - } - - KeInitializeDpc(&AcpiDpc, OslDpcStub, NULL); - - return AE_OK; -} - -ACPI_STATUS -AcpiOsTerminate(void) -{ - DPRINT1("AcpiOsTerminate() called\n"); - - if (AcpiInterruptHandlerRegistered) - AcpiOsRemoveInterruptHandler(AcpiIrqNumber, AcpiIrqHandler); - - return AE_OK; -} - -void ACPI_INTERNAL_VAR_XFACE -AcpiOsPrintf ( - const char *Fmt, - ...) -{ - va_list Args; - va_start (Args, Fmt); - - AcpiOsVprintf (Fmt, Args); - - va_end (Args); - return; -} - -void -AcpiOsVprintf ( - const char *Fmt, - va_list Args) -{ - vDbgPrintEx (-1, DPFLTR_ERROR_LEVEL, Fmt, Args); - return; -} - -void * -AcpiOsAllocate (ACPI_SIZE size) -{ - DPRINT("AcpiOsAllocate size %d\n",size); - return ExAllocatePool(NonPagedPool, size); -} - -void * -AcpiOsCallocate(ACPI_SIZE size) -{ - PVOID ptr = ExAllocatePool(NonPagedPool, size); - if (ptr) - memset(ptr, 0, size); - return ptr; -} - -void -AcpiOsFree(void *ptr) -{ - if (!ptr) - DPRINT1("Attempt to free null pointer!!!\n"); - ExFreePool(ptr); -} - -#ifndef ACPI_USE_LOCAL_CACHE - -void* -AcpiOsAcquireObjectHelper ( - POOL_TYPE PoolType, - SIZE_T NumberOfBytes, - ULONG Tag) -{ - void* Alloc = ExAllocatePool(PoolType, NumberOfBytes); - - /* acpica expects memory allocated from cache to be zeroed */ - RtlZeroMemory(Alloc,NumberOfBytes); - return Alloc; -} - -ACPI_STATUS -AcpiOsCreateCache ( - char *CacheName, - UINT16 ObjectSize, - UINT16 MaxDepth, - ACPI_CACHE_T **ReturnCache) -{ - PNPAGED_LOOKASIDE_LIST Lookaside = - ExAllocatePool(NonPagedPool,sizeof(NPAGED_LOOKASIDE_LIST)); - - ExInitializeNPagedLookasideList(Lookaside, - (PALLOCATE_FUNCTION)AcpiOsAcquireObjectHelper,// custom memory allocator - NULL, - 0, - ObjectSize, - 'IPCA', - 0); - *ReturnCache = (ACPI_CACHE_T *)Lookaside; - - DPRINT("AcpiOsCreateCache %p\n", Lookaside); - return (AE_OK); -} - -ACPI_STATUS -AcpiOsDeleteCache ( - ACPI_CACHE_T *Cache) -{ - DPRINT("AcpiOsDeleteCache %p\n", Cache); - ExDeleteNPagedLookasideList( - (PNPAGED_LOOKASIDE_LIST) Cache); - ExFreePool(Cache); - return (AE_OK); -} - -ACPI_STATUS -AcpiOsPurgeCache ( - ACPI_CACHE_T *Cache) -{ - DPRINT("AcpiOsPurgeCache\n"); - /* No such functionality for LookAside lists */ - return (AE_OK); -} - -void * -AcpiOsAcquireObject ( - ACPI_CACHE_T *Cache) -{ - PNPAGED_LOOKASIDE_LIST List = (PNPAGED_LOOKASIDE_LIST)Cache; - DPRINT("AcpiOsAcquireObject from %p\n", Cache); - void* ptr = - ExAllocateFromNPagedLookasideList(List); - ASSERT(ptr); - - RtlZeroMemory(ptr,List->L.Size); - return ptr; -} - -ACPI_STATUS -AcpiOsReleaseObject ( - ACPI_CACHE_T *Cache, - void *Object) -{ - DPRINT("AcpiOsReleaseObject %p from %p\n",Object, Cache); - ExFreeToNPagedLookasideList( - (PNPAGED_LOOKASIDE_LIST)Cache, - Object); - return (AE_OK); -} - -#endif - -void * -AcpiOsMapMemory ( - ACPI_PHYSICAL_ADDRESS phys, - ACPI_SIZE length) -{ - PHYSICAL_ADDRESS Address; - - DPRINT("AcpiOsMapMemory(phys 0x%X size 0x%X)\n", (ULONG)phys, length); - if (phys == 0x0) - { - IVTVirtualAddress = ExAllocatePool(NonPagedPool, length); - return IVTVirtualAddress; - } - - Address.QuadPart = (ULONG)phys; - return MmMapIoSpace(Address, length, MmNonCached); -} - -void -AcpiOsUnmapMemory ( - void *virt, - ACPI_SIZE length) -{ - DPRINT("AcpiOsUnmapMemory()\n"); - - if (virt == 0x0) - { - ExFreePool(IVTVirtualAddress); - return; - } - MmUnmapIoSpace(virt, length); -} - -UINT32 -AcpiOsInstallInterruptHandler ( - UINT32 InterruptNumber, - ACPI_OSD_HANDLER ServiceRoutine, - void *Context) -{ - ULONG Vector; - KIRQL DIrql; - KAFFINITY Affinity; - NTSTATUS Status; - - DPRINT("AcpiOsInstallInterruptHandler()\n"); - Vector = HalGetInterruptVector( - Internal, - 0, - InterruptNumber, - 0, - &DIrql, - &Affinity); - - AcpiIrqNumber = InterruptNumber; - AcpiIrqHandler = ServiceRoutine; - AcpiIrqContext = Context; - AcpiInterruptHandlerRegistered = TRUE; - - Status = IoConnectInterrupt( - &AcpiInterrupt, - OslIsrStub, - NULL, - NULL, - Vector, - DIrql, - DIrql, - LevelSensitive, /* FIXME: LevelSensitive or Latched? */ - TRUE, - Affinity, - FALSE); - - if (!NT_SUCCESS(Status)) - { - DPRINT("Could not connect to interrupt %d\n", Vector); - return AE_ERROR; - } - return AE_OK; -} - -ACPI_STATUS -AcpiOsRemoveInterruptHandler ( - UINT32 InterruptNumber, - ACPI_OSD_HANDLER ServiceRoutine) -{ - DPRINT("AcpiOsRemoveInterruptHandler()\n"); - if (AcpiInterruptHandlerRegistered) - { - IoDisconnectInterrupt(AcpiInterrupt); - AcpiInterrupt = NULL; - AcpiInterruptHandlerRegistered = FALSE; - } - - return AE_OK; -} - -void -AcpiOsStall (UINT32 microseconds) -{ - DPRINT1("AcpiOsStall %d\n",microseconds); - KeStallExecutionProcessor(microseconds); - return; -} - -void -AcpiOsSleep (ACPI_INTEGER milliseconds) -{ - DPRINT1("AcpiOsSleep %d\n", milliseconds); - KeStallExecutionProcessor(milliseconds*1000); - return; -} - -ACPI_STATUS -AcpiOsReadPort ( - ACPI_IO_ADDRESS Address, - UINT32 *Value, - UINT32 Width) -{ - DPRINT("AcpiOsReadPort %p, width %d\n",Address,Width); - - switch (Width) - { - case 8: - *Value = READ_PORT_UCHAR((PUCHAR)Address); - break; - - case 16: - *Value = READ_PORT_USHORT((PUSHORT)Address); - break; - - case 32: - *Value = READ_PORT_ULONG((PULONG)Address); - break; - default: - DPRINT1("AcpiOsReadPort got bad width: %d\n",Width); - return (AE_BAD_PARAMETER); - break; - } - return (AE_OK); -} - -ACPI_STATUS -AcpiOsWritePort ( - ACPI_IO_ADDRESS Address, - UINT32 Value, - UINT32 Width) -{ - DPRINT("AcpiOsWritePort %p, width %d\n",Address,Width); - switch (Width) - { - case 8: - WRITE_PORT_UCHAR((PUCHAR)Address, Value); - break; - - case 16: - WRITE_PORT_USHORT((PUSHORT)Address, Value); - break; - - case 32: - WRITE_PORT_ULONG((PULONG)Address, Value); - break; - - default: - DPRINT1("AcpiOsWritePort got bad width: %d\n",Width); - return (AE_BAD_PARAMETER); - break; - } - return (AE_OK); -} - -ACPI_STATUS -AcpiOsReadMemory ( - ACPI_PHYSICAL_ADDRESS Address, - UINT32 *Value, - UINT32 Width) -{ - DPRINT("AcpiOsReadMemory %p\n", Address); - switch (Width) - { - case 8: - *Value = (*(PUCHAR)(ULONG)Address); - break; - case 16: - *Value = (*(PUSHORT)(ULONG)Address); - break; - case 32: - *Value = (*(PULONG)(ULONG)Address); - break; - - default: - DPRINT1("AcpiOsReadMemory got bad width: %d\n",Width); - return (AE_BAD_PARAMETER); - break; - } - return (AE_OK); -} - - -ACPI_STATUS -AcpiOsWriteMemory ( - ACPI_PHYSICAL_ADDRESS Address, - UINT32 Value, - UINT32 Width) -{ - DPRINT("AcpiOsWriteMemory %p\n", Address); - switch (Width) - { - case 8: - *(PUCHAR)(ULONG)Address = Value; - break; - case 16: - *(PUSHORT)(ULONG)Address = Value; - break; - case 32: - *(PULONG)(ULONG)Address = Value; - break; - - default: - DPRINT1("AcpiOsWriteMemory got bad width: %d\n",Width); - return (AE_BAD_PARAMETER); - break; - } - - return (AE_OK); -} - -ACPI_STATUS -AcpiOsReadPciConfiguration ( - ACPI_PCI_ID *PciId, - UINT32 Register, - void *Value, - UINT32 Width) -{ - NTSTATUS Status; - PCI_SLOT_NUMBER slot; - - if (Register == 0) - return AE_ERROR; - - slot.u.AsULONG = 0; - slot.u.bits.DeviceNumber = PciId->Bus; - slot.u.bits.FunctionNumber = PciId->Function; - - DPRINT("AcpiOsReadPciConfiguration, slot=0x%X, func=0x%X\n", slot.u.AsULONG, Register); - Status = HalGetBusDataByOffset(PCIConfiguration, - PciId->Bus, - slot.u.AsULONG, - Value, - Register, - Width); - - if (NT_SUCCESS(Status)) - return AE_OK; - else - return AE_ERROR; -} - -ACPI_STATUS -AcpiOsWritePciConfiguration ( - ACPI_PCI_ID *PciId, - UINT32 Register, - ACPI_INTEGER Value, - UINT32 Width) -{ - NTSTATUS Status; - ULONG buf = Value; - PCI_SLOT_NUMBER slot; - - if (Register == 0) - return AE_ERROR; - - slot.u.AsULONG = 0; - slot.u.bits.DeviceNumber = PciId->Bus; - slot.u.bits.FunctionNumber = PciId->Function; - - DPRINT("AcpiOsWritePciConfiguration, slot=0x%x\n", slot.u.AsULONG); - Status = HalSetBusDataByOffset(PCIConfiguration, - PciId->Bus, - slot.u.AsULONG, - &buf, - Register, - Width); - - if (NT_SUCCESS(Status)) - return AE_OK; - else - return AE_ERROR; -} - -ACPI_STATUS -AcpiOsCreateSemaphore ( - UINT32 MaxUnits, - UINT32 InitialUnits, - ACPI_SEMAPHORE *OutHandle) -{ - PFAST_MUTEX Mutex; - - Mutex = ExAllocatePool(NonPagedPool, sizeof(FAST_MUTEX)); - if (!Mutex) - return AE_NO_MEMORY; - - DPRINT("AcpiOsCreateSemaphore() at 0x%X\n", Mutex); - - ExInitializeFastMutex(Mutex); - - *OutHandle = Mutex; - return AE_OK; -} - -ACPI_STATUS -AcpiOsDeleteSemaphore ( - ACPI_SEMAPHORE Handle) -{ - PFAST_MUTEX Mutex = (PFAST_MUTEX)Handle; - - DPRINT("AcpiOsDeleteSemaphore(handle 0x%X)\n", Handle); - - if (!Mutex) - return AE_BAD_PARAMETER; - - ExFreePool(Mutex); - return AE_OK; -} - -ACPI_STATUS -AcpiOsWaitSemaphore( - ACPI_SEMAPHORE Handle, - UINT32 units, - UINT16 timeout) -{ - PFAST_MUTEX Mutex = (PFAST_MUTEX)Handle; - - if (!Mutex || (units < 1)) - { - DPRINT("AcpiOsWaitSemaphore(handle 0x%X, units %d) Bad parameters\n", - Mutex, units); - return AE_BAD_PARAMETER; - } - - DPRINT("Waiting for semaphore %p\n", Handle); - ASSERT(Mutex); - - ExAcquireFastMutex(Mutex); - return AE_OK; -} - -ACPI_STATUS -AcpiOsSignalSemaphore ( - ACPI_HANDLE Handle, - UINT32 Units) -{ - PFAST_MUTEX Mutex = (PFAST_MUTEX)Handle; - - DPRINT("AcpiOsSignalSemaphore %p\n",Handle); - ASSERT(Mutex); - - ExReleaseFastMutex(Mutex); - return AE_OK; -} - -ACPI_STATUS -AcpiOsCreateLock ( - ACPI_SPINLOCK *OutHandle) -{ - DPRINT("AcpiOsCreateLock\n"); - return (AcpiOsCreateSemaphore (1, 1, OutHandle)); -} - -void -AcpiOsDeleteLock ( - ACPI_SPINLOCK Handle) -{ - DPRINT("AcpiOsDeleteLock %p\n", Handle); - AcpiOsDeleteSemaphore (Handle); -} - - -ACPI_CPU_FLAGS -AcpiOsAcquireLock ( - ACPI_HANDLE Handle) -{ - DPRINT("AcpiOsAcquireLock, %p\n", Handle); - AcpiOsWaitSemaphore (Handle, 1, 0xFFFF); - return (0); -} - - -void -AcpiOsReleaseLock ( - ACPI_SPINLOCK Handle, - ACPI_CPU_FLAGS Flags) -{ - DPRINT("AcpiOsReleaseLock %p\n",Handle); - AcpiOsSignalSemaphore (Handle, 1); -} - -ACPI_STATUS -AcpiOsSignal ( - UINT32 Function, - void *Info) -{ - - switch (Function) - { - case ACPI_SIGNAL_FATAL: - if (Info) - AcpiOsPrintf ("AcpiOsBreakpoint: %s ****\n", Info); - else - AcpiOsPrintf ("AcpiOsBreakpoint ****\n"); - break; - case ACPI_SIGNAL_BREAKPOINT: - if (Info) - AcpiOsPrintf ("AcpiOsBreakpoint: %s ****\n", Info); - else - AcpiOsPrintf ("AcpiOsBreakpoint ****\n"); - break; - } - - return (AE_OK); -} - - -ACPI_THREAD_ID -AcpiOsGetThreadId (void) -{ - return (ULONG)PsGetCurrentThreadId(); -} - -ACPI_STATUS -AcpiOsExecute ( - ACPI_EXECUTE_TYPE Type, - ACPI_OSD_EXEC_CALLBACK Function, - void *Context) -{ - DPRINT1("AcpiOsExecute\n"); - - KeInsertQueueDpc(&AcpiDpc, (PVOID)Function, (PVOID)Context); - -#ifdef _MULTI_THREADED - //_beginthread (Function, (unsigned) 0, Context); -#endif - - return 0; -} - -UINT64 -AcpiOsGetTimer (void) -{ - DPRINT("AcpiOsGetTimer\n"); - LARGE_INTEGER Timer; - KeQueryTickCount(&Timer); - - return Timer.QuadPart; -} - -void -AcpiOsDerivePciId( - ACPI_HANDLE rhandle, - ACPI_HANDLE chandle, - ACPI_PCI_ID **PciId) -{ - DPRINT("AcpiOsDerivePciId\n"); - return; -} - -ACPI_STATUS -AcpiOsPredefinedOverride ( - const ACPI_PREDEFINED_NAMES *InitVal, - ACPI_STRING *NewVal) -{ - if (!InitVal || !NewVal) - return AE_BAD_PARAMETER; - - *NewVal = ACPI_OS_NAME; - DPRINT("AcpiOsPredefinedOverride\n"); - return AE_OK; -} - -ACPI_PHYSICAL_ADDRESS -AcpiOsGetRootPointer ( - void); - -ACPI_STATUS -AcpiOsTableOverride ( - ACPI_TABLE_HEADER *ExistingTable, - ACPI_TABLE_HEADER **NewTable) -{ - DPRINT("AcpiOsTableOverride\n"); - *NewTable = NULL; - return (AE_OK); -} - -ACPI_STATUS -AcpiOsValidateInterface ( - char *Interface) -{ - DPRINT("AcpiOsValidateInterface\n"); - return (AE_OK); -} - -ACPI_STATUS -AcpiOsValidateAddress ( - UINT8 SpaceId, - ACPI_PHYSICAL_ADDRESS Address, - ACPI_SIZE Length) -{ - DPRINT("AcpiOsValidateAddress\n"); - return (AE_OK); -} - -ACPI_PHYSICAL_ADDRESS -AcpiOsGetRootPointer ( - void) -{ - DPRINT("AcpiOsGetRootPointer\n"); - ACPI_PHYSICAL_ADDRESS pa = 0; - - AcpiFindRootPointer(&pa); - return pa; -} diff --git a/drivers/bus/acpi/acpienum.c b/drivers/bus/acpi/acpienum.c index 50ab9eeee4b..c011dbadd63 100644 --- a/drivers/bus/acpi/acpienum.c +++ b/drivers/bus/acpi/acpienum.c @@ -13,7 +13,7 @@ #include #include -//#define NDEBUG +#define NDEBUG #include #define HAS_CHILDREN(d) ((d)->children.next != &((d)->children)) @@ -37,6 +37,10 @@ Bus_PlugInDevice ( PAGED_CODE (); + //Don't enumerate the root device + if (Device->handle == ACPI_ROOT_OBJECT) + return STATUS_SUCCESS; + /* Check we didnt add this already */ for (entry = FdoData->ListOfPDOs.Flink; entry != &FdoData->ListOfPDOs; entry = entry->Flink) diff --git a/drivers/bus/acpi/busmgr/bus.c b/drivers/bus/acpi/busmgr/bus.c index 949cfd2bd65..34aa0766c04 100644 --- a/drivers/bus/acpi/busmgr/bus.c +++ b/drivers/bus/acpi/busmgr/bus.c @@ -34,7 +34,7 @@ #include #include -//#define NDEBUG +#define NDEBUG #include #define _COMPONENT ACPI_BUS_COMPONENT diff --git a/drivers/bus/acpi/busmgr/power.c b/drivers/bus/acpi/busmgr/power.c index 6c6bc0814bf..77a37198ed7 100644 --- a/drivers/bus/acpi/busmgr/power.c +++ b/drivers/bus/acpi/busmgr/power.c @@ -46,7 +46,7 @@ #include #include -//#define NDEBUG +#define NDEBUG #include diff --git a/drivers/bus/acpi/busmgr/system.c b/drivers/bus/acpi/busmgr/system.c index d0f0503f366..ca5a0852bf9 100644 --- a/drivers/bus/acpi/busmgr/system.c +++ b/drivers/bus/acpi/busmgr/system.c @@ -32,7 +32,7 @@ #include #include "list.h" -//#define NDEBUG +#define NDEBUG #include ACPI_STATUS acpi_system_save_state(UINT32); diff --git a/drivers/bus/acpi/busmgr/utils.c b/drivers/bus/acpi/busmgr/utils.c index 67eaed017ca..2a82e49604c 100644 --- a/drivers/bus/acpi/busmgr/utils.c +++ b/drivers/bus/acpi/busmgr/utils.c @@ -30,7 +30,7 @@ #include #include -//#define NDEBUG +#define NDEBUG #include /* Modified for ReactOS and latest ACPICA diff --git a/drivers/bus/acpi/buspdo.c b/drivers/bus/acpi/buspdo.c index eb8f6686086..4a9498e7ad4 100644 --- a/drivers/bus/acpi/buspdo.c +++ b/drivers/bus/acpi/buspdo.c @@ -8,7 +8,7 @@ #include #include -//#define NDEBUG +#define NDEBUG #include #ifdef ALLOC_PRAGMA @@ -325,6 +325,7 @@ Bus_PDO_QueryDeviceCaps( deviceCapabilities->UniqueID = device->flags.unique_id; deviceCapabilities->NoDisplayInUI = !device->status.show_in_ui; deviceCapabilities->Address = device->pnp.bus_address; + deviceCapabilities->RawDeviceOK = FALSE; } else { @@ -335,6 +336,9 @@ Bus_PDO_QueryDeviceCaps( deviceCapabilities->UniqueID = FALSE; deviceCapabilities->NoDisplayInUI = FALSE; deviceCapabilities->Address = 0; + + /* The ACPI driver will run fixed buttons */ + deviceCapabilities->RawDeviceOK = TRUE; } deviceCapabilities->SilentInstall = FALSE; @@ -548,8 +552,6 @@ Bus_PDO_QueryDeviceText( Buffer = L"ACPI Power Resource"; else if (wcsstr(DeviceData->HardwareIDs, L"Processor") != 0) Buffer = L"Processor"; - else if (wcsstr(DeviceData->HardwareIDs, L"ACPI_SYS") != 0) - Buffer = L"ACPI System"; else if (wcsstr(DeviceData->HardwareIDs, L"ThermalZone") != 0) Buffer = L"ACPI Thermal Zone"; else if (wcsstr(DeviceData->HardwareIDs, L"ACPI0002") != 0) @@ -621,6 +623,12 @@ Bus_PDO_QueryResources( { switch (resource->Type) { + case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: + { + ACPI_RESOURCE_EXTENDED_IRQ *irq_data = (ACPI_RESOURCE_EXTENDED_IRQ*) &resource->Data; + NumberOfResources += irq_data->InterruptCount; + break; + } case ACPI_RESOURCE_TYPE_IRQ: { ACPI_RESOURCE_IRQ *irq_data = (ACPI_RESOURCE_IRQ*) &resource->Data; @@ -633,6 +641,12 @@ Bus_PDO_QueryResources( NumberOfResources += dma_data->ChannelCount; break; } + case ACPI_RESOURCE_TYPE_ADDRESS16: + case ACPI_RESOURCE_TYPE_ADDRESS32: + case ACPI_RESOURCE_TYPE_ADDRESS64: + case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: + case ACPI_RESOURCE_TYPE_MEMORY24: + case ACPI_RESOURCE_TYPE_MEMORY32: case ACPI_RESOURCE_TYPE_IO: { NumberOfResources++; @@ -665,10 +679,30 @@ Bus_PDO_QueryResources( ResourceDescriptor = ResourceList->List[0].PartialResourceList.PartialDescriptors; /* Fill resources list structure */ + resource = Buffer.Pointer; while (resource->Type != ACPI_RESOURCE_TYPE_END_TAG) { switch (resource->Type) { + case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: + { + ACPI_RESOURCE_EXTENDED_IRQ *irq_data = (ACPI_RESOURCE_EXTENDED_IRQ*) &resource->Data; + for (i = 0; i < irq_data->InterruptCount; i++) + { + ResourceDescriptor->Type = CmResourceTypeInterrupt; + + ResourceDescriptor->ShareDisposition = + (irq_data->Sharable == ACPI_SHARED ? CmResourceShareShared : CmResourceShareDeviceExclusive); + ResourceDescriptor->Flags = + (irq_data->Triggering == ACPI_LEVEL_SENSITIVE ? CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE : CM_RESOURCE_INTERRUPT_LATCHED); + ResourceDescriptor->u.Interrupt.Level = irq_data->Interrupts[i]; + ResourceDescriptor->u.Interrupt.Vector = 0; + ResourceDescriptor->u.Interrupt.Affinity = (KAFFINITY)(-1); + + ResourceDescriptor++; + } + break; + } case ACPI_RESOURCE_TYPE_IRQ: { ACPI_RESOURCE_IRQ *irq_data = (ACPI_RESOURCE_IRQ*) &resource->Data; @@ -725,13 +759,214 @@ Bus_PDO_QueryResources( ResourceDescriptor->Flags |= CM_RESOURCE_PORT_16_BIT_DECODE; else ResourceDescriptor->Flags |= CM_RESOURCE_PORT_10_BIT_DECODE; - ResourceDescriptor->u.Port.Start.u.HighPart = 0; - ResourceDescriptor->u.Port.Start.u.LowPart = io_data->Minimum; + ResourceDescriptor->u.Port.Start.QuadPart = io_data->Minimum; ResourceDescriptor->u.Port.Length = io_data->AddressLength; ResourceDescriptor++; break; } + case ACPI_RESOURCE_TYPE_ADDRESS16: + { + ACPI_RESOURCE_ADDRESS16 *addr16_data = (ACPI_RESOURCE_ADDRESS16*) &resource->Data; + if (addr16_data->ResourceType == ACPI_BUS_NUMBER_RANGE) + { + ResourceDescriptor->Type = CmResourceTypeBusNumber; + ResourceDescriptor->ShareDisposition = CmResourceShareShared; + ResourceDescriptor->Flags = 0; + ResourceDescriptor->u.BusNumber.Start = addr16_data->Minimum; + ResourceDescriptor->u.BusNumber.Length = addr16_data->AddressLength; + } + else if (addr16_data->ResourceType == ACPI_IO_RANGE) + { + ResourceDescriptor->Type = CmResourceTypePort; + ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO; + if (addr16_data->Decode == ACPI_POS_DECODE) + ResourceDescriptor->Flags |= CM_RESOURCE_PORT_POSITIVE_DECODE; + ResourceDescriptor->u.Port.Start.QuadPart = addr16_data->Minimum; + ResourceDescriptor->u.Port.Length = addr16_data->AddressLength; + } + else + { + ResourceDescriptor->Type = CmResourceTypeMemory; + ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + ResourceDescriptor->Flags = 0; + if (addr16_data->Info.Mem.WriteProtect == ACPI_READ_ONLY_MEMORY) + ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY; + else + ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE; + switch (addr16_data->Info.Mem.Caching) + { + case ACPI_CACHABLE_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_CACHEABLE; break; + case ACPI_WRITE_COMBINING_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_COMBINEDWRITE; break; + case ACPI_PREFETCHABLE_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE; break; + } + ResourceDescriptor->u.Memory.Start.QuadPart = addr16_data->Minimum; + ResourceDescriptor->u.Memory.Length = addr16_data->AddressLength; + } + ResourceDescriptor++; + break; + } + case ACPI_RESOURCE_TYPE_ADDRESS32: + { + ACPI_RESOURCE_ADDRESS32 *addr32_data = (ACPI_RESOURCE_ADDRESS32*) &resource->Data; + if (addr32_data->ResourceType == ACPI_BUS_NUMBER_RANGE) + { + ResourceDescriptor->Type = CmResourceTypeBusNumber; + ResourceDescriptor->ShareDisposition = CmResourceShareShared; + ResourceDescriptor->Flags = 0; + ResourceDescriptor->u.BusNumber.Start = addr32_data->Minimum; + ResourceDescriptor->u.BusNumber.Length = addr32_data->AddressLength; + } + else if (addr32_data->ResourceType == ACPI_IO_RANGE) + { + ResourceDescriptor->Type = CmResourceTypePort; + ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO; + if (addr32_data->Decode == ACPI_POS_DECODE) + ResourceDescriptor->Flags |= CM_RESOURCE_PORT_POSITIVE_DECODE; + ResourceDescriptor->u.Port.Start.QuadPart = addr32_data->Minimum; + ResourceDescriptor->u.Port.Length = addr32_data->AddressLength; + } + else + { + ResourceDescriptor->Type = CmResourceTypeMemory; + ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + ResourceDescriptor->Flags = 0; + if (addr32_data->Info.Mem.WriteProtect == ACPI_READ_ONLY_MEMORY) + ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY; + else + ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE; + switch (addr32_data->Info.Mem.Caching) + { + case ACPI_CACHABLE_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_CACHEABLE; break; + case ACPI_WRITE_COMBINING_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_COMBINEDWRITE; break; + case ACPI_PREFETCHABLE_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE; break; + } + ResourceDescriptor->u.Memory.Start.QuadPart = addr32_data->Minimum; + ResourceDescriptor->u.Memory.Length = addr32_data->AddressLength; + } + ResourceDescriptor++; + break; + } + case ACPI_RESOURCE_TYPE_ADDRESS64: + { + ACPI_RESOURCE_ADDRESS64 *addr64_data = (ACPI_RESOURCE_ADDRESS64*) &resource->Data; + if (addr64_data->ResourceType == ACPI_BUS_NUMBER_RANGE) + { + DPRINT1("64-bit bus address is not supported!\n"); + ResourceDescriptor->Type = CmResourceTypeBusNumber; + ResourceDescriptor->ShareDisposition = CmResourceShareShared; + ResourceDescriptor->Flags = 0; + ResourceDescriptor->u.BusNumber.Start = (ULONG)addr64_data->Minimum; + ResourceDescriptor->u.BusNumber.Length = addr64_data->AddressLength; + } + else if (addr64_data->ResourceType == ACPI_IO_RANGE) + { + ResourceDescriptor->Type = CmResourceTypePort; + ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO; + if (addr64_data->Decode == ACPI_POS_DECODE) + ResourceDescriptor->Flags |= CM_RESOURCE_PORT_POSITIVE_DECODE; + ResourceDescriptor->u.Port.Start.QuadPart = addr64_data->Minimum; + ResourceDescriptor->u.Port.Length = addr64_data->AddressLength; + } + else + { + ResourceDescriptor->Type = CmResourceTypeMemory; + ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + ResourceDescriptor->Flags = 0; + if (addr64_data->Info.Mem.WriteProtect == ACPI_READ_ONLY_MEMORY) + ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY; + else + ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE; + switch (addr64_data->Info.Mem.Caching) + { + case ACPI_CACHABLE_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_CACHEABLE; break; + case ACPI_WRITE_COMBINING_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_COMBINEDWRITE; break; + case ACPI_PREFETCHABLE_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE; break; + } + ResourceDescriptor->u.Memory.Start.QuadPart = addr64_data->Minimum; + ResourceDescriptor->u.Memory.Length = addr64_data->AddressLength; + } + ResourceDescriptor++; + break; + } + case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: + { + ACPI_RESOURCE_EXTENDED_ADDRESS64 *addr64_data = (ACPI_RESOURCE_EXTENDED_ADDRESS64*) &resource->Data; + if (addr64_data->ResourceType == ACPI_BUS_NUMBER_RANGE) + { + DPRINT1("64-bit bus address is not supported!\n"); + ResourceDescriptor->Type = CmResourceTypeBusNumber; + ResourceDescriptor->ShareDisposition = CmResourceShareShared; + ResourceDescriptor->Flags = 0; + ResourceDescriptor->u.BusNumber.Start = (ULONG)addr64_data->Minimum; + ResourceDescriptor->u.BusNumber.Length = addr64_data->AddressLength; + } + else if (addr64_data->ResourceType == ACPI_IO_RANGE) + { + ResourceDescriptor->Type = CmResourceTypePort; + ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO; + if (addr64_data->Decode == ACPI_POS_DECODE) + ResourceDescriptor->Flags |= CM_RESOURCE_PORT_POSITIVE_DECODE; + ResourceDescriptor->u.Port.Start.QuadPart = addr64_data->Minimum; + ResourceDescriptor->u.Port.Length = addr64_data->AddressLength; + } + else + { + ResourceDescriptor->Type = CmResourceTypeMemory; + ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + ResourceDescriptor->Flags = 0; + if (addr64_data->Info.Mem.WriteProtect == ACPI_READ_ONLY_MEMORY) + ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY; + else + ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE; + switch (addr64_data->Info.Mem.Caching) + { + case ACPI_CACHABLE_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_CACHEABLE; break; + case ACPI_WRITE_COMBINING_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_COMBINEDWRITE; break; + case ACPI_PREFETCHABLE_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE; break; + } + ResourceDescriptor->u.Memory.Start.QuadPart = addr64_data->Minimum; + ResourceDescriptor->u.Memory.Length = addr64_data->AddressLength; + } + ResourceDescriptor++; + break; + } + case ACPI_RESOURCE_TYPE_MEMORY24: + { + ACPI_RESOURCE_MEMORY24 *mem24_data = (ACPI_RESOURCE_MEMORY24*) &resource->Data; + ResourceDescriptor->Type = CmResourceTypeMemory; + ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + ResourceDescriptor->Flags = CM_RESOURCE_MEMORY_24; + if (mem24_data->WriteProtect == ACPI_READ_ONLY_MEMORY) + ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY; + else + ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE; + ResourceDescriptor->u.Memory.Start.QuadPart = mem24_data->Minimum; + ResourceDescriptor->u.Memory.Length = mem24_data->AddressLength; + + ResourceDescriptor++; + break; + } + case ACPI_RESOURCE_TYPE_MEMORY32: + { + ACPI_RESOURCE_MEMORY32 *mem32_data = (ACPI_RESOURCE_MEMORY32*) &resource->Data; + ResourceDescriptor->Type = CmResourceTypeMemory; + ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + ResourceDescriptor->Flags = 0; + if (mem32_data->WriteProtect == ACPI_READ_ONLY_MEMORY) + ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY; + else + ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE; + ResourceDescriptor->u.Memory.Start.QuadPart = mem32_data->Minimum; + ResourceDescriptor->u.Memory.Length = mem32_data->AddressLength; + + ResourceDescriptor++; + break; + } default: { break; @@ -803,6 +1038,12 @@ Bus_PDO_QueryResourceRequirements( { switch (resource->Type) { + case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: + { + ACPI_RESOURCE_EXTENDED_IRQ *irq_data = (ACPI_RESOURCE_EXTENDED_IRQ*) &resource->Data; + NumberOfResources += irq_data->InterruptCount; + break; + } case ACPI_RESOURCE_TYPE_IRQ: { ACPI_RESOURCE_IRQ *irq_data = (ACPI_RESOURCE_IRQ*) &resource->Data; @@ -815,6 +1056,12 @@ Bus_PDO_QueryResourceRequirements( NumberOfResources += dma_data->ChannelCount; break; } + case ACPI_RESOURCE_TYPE_ADDRESS16: + case ACPI_RESOURCE_TYPE_ADDRESS32: + case ACPI_RESOURCE_TYPE_ADDRESS64: + case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: + case ACPI_RESOURCE_TYPE_MEMORY24: + case ACPI_RESOURCE_TYPE_MEMORY32: case ACPI_RESOURCE_TYPE_IO: { NumberOfResources++; @@ -847,10 +1094,27 @@ Bus_PDO_QueryResourceRequirements( RequirementDescriptor = RequirementsList->List[0].Descriptors; /* Fill resources list structure */ + resource = Buffer.Pointer; while (resource->Type != ACPI_RESOURCE_TYPE_END_TAG) { switch (resource->Type) { + case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: + { + ACPI_RESOURCE_EXTENDED_IRQ *irq_data = (ACPI_RESOURCE_EXTENDED_IRQ*) &resource->Data; + for (i = 0; i < irq_data->InterruptCount; i++) + { + RequirementDescriptor->Option = CurrentRes ? 0 : IO_RESOURCE_PREFERRED; + RequirementDescriptor->Type = CmResourceTypeInterrupt; + RequirementDescriptor->ShareDisposition = (irq_data->Sharable == ACPI_SHARED ? CmResourceShareShared : CmResourceShareDeviceExclusive); + RequirementDescriptor->Flags =(irq_data->Triggering == ACPI_LEVEL_SENSITIVE ? CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE : CM_RESOURCE_INTERRUPT_LATCHED); + RequirementDescriptor->u.Interrupt.MinimumVector = + RequirementDescriptor->u.Interrupt.MaximumVector = irq_data->Interrupts[i]; + + RequirementDescriptor++; + } + break; + } case ACPI_RESOURCE_TYPE_IRQ: { ACPI_RESOURCE_IRQ *irq_data = (ACPI_RESOURCE_IRQ*) &resource->Data; @@ -905,9 +1169,7 @@ Bus_PDO_QueryResourceRequirements( RequirementDescriptor->Flags |= CM_RESOURCE_PORT_16_BIT_DECODE; else RequirementDescriptor->Flags |= CM_RESOURCE_PORT_10_BIT_DECODE; - RequirementDescriptor->u.Port.Length = io_data->AddressLength; - RequirementDescriptor->Option = CurrentRes ? 0 : IO_RESOURCE_PREFERRED; RequirementDescriptor->Type = CmResourceTypePort; RequirementDescriptor->ShareDisposition = CmResourceShareDriverExclusive; @@ -918,6 +1180,228 @@ Bus_PDO_QueryResourceRequirements( RequirementDescriptor++; break; } + case ACPI_RESOURCE_TYPE_ADDRESS16: + { + ACPI_RESOURCE_ADDRESS16 *addr16_data = (ACPI_RESOURCE_ADDRESS16*) &resource->Data; + RequirementDescriptor->Option = CurrentRes ? 0 : IO_RESOURCE_PREFERRED; + if (addr16_data->ResourceType == ACPI_BUS_NUMBER_RANGE) + { + RequirementDescriptor->Type = CmResourceTypeBusNumber; + RequirementDescriptor->ShareDisposition = CmResourceShareShared; + RequirementDescriptor->Flags = 0; + RequirementDescriptor->u.BusNumber.MinBusNumber = addr16_data->Minimum; + RequirementDescriptor->u.BusNumber.MaxBusNumber = addr16_data->Maximum; + RequirementDescriptor->u.BusNumber.Length = addr16_data->AddressLength; + } + else if (addr16_data->ResourceType == ACPI_IO_RANGE) + { + RequirementDescriptor->Type = CmResourceTypePort; + RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + RequirementDescriptor->Flags = CM_RESOURCE_PORT_IO; + if (addr16_data->Decode == ACPI_POS_DECODE) + RequirementDescriptor->Flags |= CM_RESOURCE_PORT_POSITIVE_DECODE; + RequirementDescriptor->u.Port.MinimumAddress.QuadPart = addr16_data->Minimum; + RequirementDescriptor->u.Port.MaximumAddress.QuadPart = addr16_data->Maximum; + RequirementDescriptor->u.Port.Length = addr16_data->AddressLength; + } + else + { + RequirementDescriptor->Type = CmResourceTypeMemory; + RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + RequirementDescriptor->Flags = 0; + if (addr16_data->Info.Mem.WriteProtect == ACPI_READ_ONLY_MEMORY) + RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY; + else + RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE; + switch (addr16_data->Info.Mem.Caching) + { + case ACPI_CACHABLE_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_CACHEABLE; break; + case ACPI_WRITE_COMBINING_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_COMBINEDWRITE; break; + case ACPI_PREFETCHABLE_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE; break; + } + RequirementDescriptor->u.Memory.MinimumAddress.QuadPart = addr16_data->Minimum; + RequirementDescriptor->u.Memory.MaximumAddress.QuadPart = addr16_data->Maximum; + RequirementDescriptor->u.Memory.Length = addr16_data->AddressLength; + } + RequirementDescriptor++; + break; + } + case ACPI_RESOURCE_TYPE_ADDRESS32: + { + ACPI_RESOURCE_ADDRESS32 *addr32_data = (ACPI_RESOURCE_ADDRESS32*) &resource->Data; + RequirementDescriptor->Option = CurrentRes ? 0 : IO_RESOURCE_PREFERRED; + if (addr32_data->ResourceType == ACPI_BUS_NUMBER_RANGE) + { + RequirementDescriptor->Type = CmResourceTypeBusNumber; + RequirementDescriptor->ShareDisposition = CmResourceShareShared; + RequirementDescriptor->Flags = 0; + RequirementDescriptor->u.BusNumber.MinBusNumber = addr32_data->Minimum; + RequirementDescriptor->u.BusNumber.MaxBusNumber = addr32_data->Maximum; + RequirementDescriptor->u.BusNumber.Length = addr32_data->AddressLength; + } + else if (addr32_data->ResourceType == ACPI_IO_RANGE) + { + RequirementDescriptor->Type = CmResourceTypePort; + RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + RequirementDescriptor->Flags = CM_RESOURCE_PORT_IO; + if (addr32_data->Decode == ACPI_POS_DECODE) + RequirementDescriptor->Flags |= CM_RESOURCE_PORT_POSITIVE_DECODE; + RequirementDescriptor->u.Port.MinimumAddress.QuadPart = addr32_data->Minimum; + RequirementDescriptor->u.Port.MaximumAddress.QuadPart = addr32_data->Maximum; + RequirementDescriptor->u.Port.Length = addr32_data->AddressLength; + } + else + { + RequirementDescriptor->Type = CmResourceTypeMemory; + RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + RequirementDescriptor->Flags = 0; + if (addr32_data->Info.Mem.WriteProtect == ACPI_READ_ONLY_MEMORY) + RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY; + else + RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE; + switch (addr32_data->Info.Mem.Caching) + { + case ACPI_CACHABLE_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_CACHEABLE; break; + case ACPI_WRITE_COMBINING_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_COMBINEDWRITE; break; + case ACPI_PREFETCHABLE_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE; break; + } + RequirementDescriptor->u.Memory.MinimumAddress.QuadPart = addr32_data->Minimum; + RequirementDescriptor->u.Memory.MaximumAddress.QuadPart = addr32_data->Maximum; + RequirementDescriptor->u.Memory.Length = addr32_data->AddressLength; + } + RequirementDescriptor++; + break; + } + case ACPI_RESOURCE_TYPE_ADDRESS64: + { + ACPI_RESOURCE_ADDRESS64 *addr64_data = (ACPI_RESOURCE_ADDRESS64*) &resource->Data; + RequirementDescriptor->Option = CurrentRes ? 0 : IO_RESOURCE_PREFERRED; + if (addr64_data->ResourceType == ACPI_BUS_NUMBER_RANGE) + { + DPRINT1("64-bit bus address is not supported!\n"); + RequirementDescriptor->Type = CmResourceTypeBusNumber; + RequirementDescriptor->ShareDisposition = CmResourceShareShared; + RequirementDescriptor->Flags = 0; + RequirementDescriptor->u.BusNumber.MinBusNumber = (ULONG)addr64_data->Minimum; + RequirementDescriptor->u.BusNumber.MaxBusNumber = (ULONG)addr64_data->Maximum; + RequirementDescriptor->u.BusNumber.Length = addr64_data->AddressLength; + } + else if (addr64_data->ResourceType == ACPI_IO_RANGE) + { + RequirementDescriptor->Type = CmResourceTypePort; + RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + RequirementDescriptor->Flags = CM_RESOURCE_PORT_IO; + if (addr64_data->Decode == ACPI_POS_DECODE) + RequirementDescriptor->Flags |= CM_RESOURCE_PORT_POSITIVE_DECODE; + RequirementDescriptor->u.Port.MinimumAddress.QuadPart = addr64_data->Minimum; + RequirementDescriptor->u.Port.MaximumAddress.QuadPart = addr64_data->Maximum; + RequirementDescriptor->u.Port.Length = addr64_data->AddressLength; + } + else + { + RequirementDescriptor->Type = CmResourceTypeMemory; + RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + RequirementDescriptor->Flags = 0; + if (addr64_data->Info.Mem.WriteProtect == ACPI_READ_ONLY_MEMORY) + RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY; + else + RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE; + switch (addr64_data->Info.Mem.Caching) + { + case ACPI_CACHABLE_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_CACHEABLE; break; + case ACPI_WRITE_COMBINING_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_COMBINEDWRITE; break; + case ACPI_PREFETCHABLE_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE; break; + } + RequirementDescriptor->u.Memory.MinimumAddress.QuadPart = addr64_data->Minimum; + RequirementDescriptor->u.Memory.MaximumAddress.QuadPart = addr64_data->Maximum; + RequirementDescriptor->u.Memory.Length = addr64_data->AddressLength; + } + RequirementDescriptor++; + break; + } + case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: + { + ACPI_RESOURCE_EXTENDED_ADDRESS64 *addr64_data = (ACPI_RESOURCE_EXTENDED_ADDRESS64*) &resource->Data; + RequirementDescriptor->Option = CurrentRes ? 0 : IO_RESOURCE_PREFERRED; + if (addr64_data->ResourceType == ACPI_BUS_NUMBER_RANGE) + { + DPRINT1("64-bit bus address is not supported!\n"); + RequirementDescriptor->Type = CmResourceTypeBusNumber; + RequirementDescriptor->ShareDisposition = CmResourceShareShared; + RequirementDescriptor->Flags = 0; + RequirementDescriptor->u.BusNumber.MinBusNumber = (ULONG)addr64_data->Minimum; + RequirementDescriptor->u.BusNumber.MaxBusNumber = (ULONG)addr64_data->Maximum; + RequirementDescriptor->u.BusNumber.Length = addr64_data->AddressLength; + } + else if (addr64_data->ResourceType == ACPI_IO_RANGE) + { + RequirementDescriptor->Type = CmResourceTypePort; + RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + RequirementDescriptor->Flags = CM_RESOURCE_PORT_IO; + if (addr64_data->Decode == ACPI_POS_DECODE) + RequirementDescriptor->Flags |= CM_RESOURCE_PORT_POSITIVE_DECODE; + RequirementDescriptor->u.Port.MinimumAddress.QuadPart = addr64_data->Minimum; + RequirementDescriptor->u.Port.MaximumAddress.QuadPart = addr64_data->Maximum; + RequirementDescriptor->u.Port.Length = addr64_data->AddressLength; + } + else + { + RequirementDescriptor->Type = CmResourceTypeMemory; + RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + RequirementDescriptor->Flags = 0; + if (addr64_data->Info.Mem.WriteProtect == ACPI_READ_ONLY_MEMORY) + RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY; + else + RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE; + switch (addr64_data->Info.Mem.Caching) + { + case ACPI_CACHABLE_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_CACHEABLE; break; + case ACPI_WRITE_COMBINING_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_COMBINEDWRITE; break; + case ACPI_PREFETCHABLE_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE; break; + } + RequirementDescriptor->u.Memory.MinimumAddress.QuadPart = addr64_data->Minimum; + RequirementDescriptor->u.Memory.MaximumAddress.QuadPart = addr64_data->Maximum; + RequirementDescriptor->u.Memory.Length = addr64_data->AddressLength; + } + RequirementDescriptor++; + break; + } + case ACPI_RESOURCE_TYPE_MEMORY24: + { + ACPI_RESOURCE_MEMORY24 *mem24_data = (ACPI_RESOURCE_MEMORY24*) &resource->Data; + RequirementDescriptor->Option = CurrentRes ? 0 : IO_RESOURCE_PREFERRED; + RequirementDescriptor->Type = CmResourceTypeMemory; + RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + RequirementDescriptor->Flags = CM_RESOURCE_MEMORY_24; + if (mem24_data->WriteProtect == ACPI_READ_ONLY_MEMORY) + RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY; + else + RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE; + RequirementDescriptor->u.Memory.MinimumAddress.QuadPart = mem24_data->Minimum; + RequirementDescriptor->u.Memory.MaximumAddress.QuadPart = mem24_data->Maximum; + RequirementDescriptor->u.Memory.Length = mem24_data->AddressLength; + + RequirementDescriptor++; + break; + } + case ACPI_RESOURCE_TYPE_MEMORY32: + { + ACPI_RESOURCE_MEMORY32 *mem32_data = (ACPI_RESOURCE_MEMORY32*) &resource->Data; + RequirementDescriptor->Option = CurrentRes ? 0 : IO_RESOURCE_PREFERRED; + RequirementDescriptor->Type = CmResourceTypeMemory; + RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + RequirementDescriptor->Flags = 0; + if (mem32_data->WriteProtect == ACPI_READ_ONLY_MEMORY) + RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY; + else + RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE; + RequirementDescriptor->u.Memory.MinimumAddress.QuadPart = mem32_data->Minimum; + RequirementDescriptor->u.Memory.MaximumAddress.QuadPart = mem32_data->Maximum; + RequirementDescriptor->u.Memory.Length = mem32_data->AddressLength; + + RequirementDescriptor++; + break; + } default: { break; diff --git a/drivers/bus/acpi/cmbatt/cmbatt.c b/drivers/bus/acpi/cmbatt/cmbatt.c new file mode 100644 index 00000000000..1957597a678 --- /dev/null +++ b/drivers/bus/acpi/cmbatt/cmbatt.c @@ -0,0 +1,149 @@ +/* + * PROJECT: ReactOS ACPI-Compliant Control Method Battery + * LICENSE: BSD - See COPYING.ARM in the top level directory + * FILE: boot/drivers/bus/acpi/cmbatt/cmbatt.c + * PURPOSE: Main Initialization Code and IRP Handling + * PROGRAMMERS: ReactOS Portable Systems Group + */ + +/* INCLUDES *******************************************************************/ + +#include "cmbatt.h" + +/* GLOBALS ********************************************************************/ + +ULONG CmBattDebug; + +/* FUNCTIONS ******************************************************************/ + +VOID +NTAPI +CmBattPowerCallBack(PCMBATT_DEVICE_EXTENSION DeviceExtension, + PVOID Argument1, + PVOID Argument2) +{ + UNIMPLEMENTED; +} + +VOID +NTAPI +CmBattWakeDpc(PKDPC Dpc, + PCMBATT_DEVICE_EXTENSION FdoExtension, + PVOID SystemArgument1, + PVOID SystemArgument2) +{ + UNIMPLEMENTED; +} + +VOID +NTAPI +CmBattNotifyHandler(PCMBATT_DEVICE_EXTENSION DeviceExtension, + ULONG NotifyValue) +{ + UNIMPLEMENTED; +} + +VOID +NTAPI +CmBattUnload(PDEVICE_OBJECT DeviceObject) +{ + UNIMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattVerifyStaticInfo(ULONG StaData, + ULONG BatteryTag) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattOpenClose(PDEVICE_OBJECT DeviceObject, + PIRP Irp) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattIoctl(PDEVICE_OBJECT DeviceObject, + PIRP Irp) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattQueryTag(PCMBATT_DEVICE_EXTENSION DeviceExtension, + PULONG BatteryTag) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattDisableStatusNotify(PCMBATT_DEVICE_EXTENSION DeviceExtension) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattSetStatusNotify(PCMBATT_DEVICE_EXTENSION DeviceExtension, + ULONG BatteryTag, + PBATTERY_NOTIFY BatteryNotify) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattGetBatteryStatus(PCMBATT_DEVICE_EXTENSION DeviceExtension, + ULONG BatteryTag) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattQueryInformation(PCMBATT_DEVICE_EXTENSION DeviceExtension, + ULONG BatteryTag, + BATTERY_QUERY_INFORMATION_LEVEL Level, + OPTIONAL LONG AtRate, + PVOID Buffer, + ULONG BufferLength, + PULONG ReturnedLength) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattQueryStatus(PCMBATT_DEVICE_EXTENSION DeviceExtension, + ULONG BatteryTag, + PBATTERY_STATUS BatteryStatus) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +DriverEntry(PDRIVER_OBJECT DriverObject, + PUNICODE_STRING RegistryPath) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +/* EOF */ diff --git a/drivers/bus/acpi/cmbatt/cmbatt.h b/drivers/bus/acpi/cmbatt/cmbatt.h new file mode 100644 index 00000000000..0443c4c86bb --- /dev/null +++ b/drivers/bus/acpi/cmbatt/cmbatt.h @@ -0,0 +1,105 @@ +/* + * PROJECT: ReactOS ACPI-Compliant Control Method Battery + * LICENSE: BSD - See COPYING.ARM in the top level directory + * FILE: boot/drivers/bus/acpi/cmbatt/cmbatt.h + * PURPOSE: Main Header File + * PROGRAMMERS: ReactOS Portable Systems Group + */ + +#include +#include +#include +#include +#include +#include + +#define CMBATT_GENERIC_STATUS 0x01 +#define CMBATT_GENERIC_INFO 0x02 +#define CMBATT_GENERIC_WARNING 0x04 +#define CMBATT_ACPI_WARNING 0x08 +#define CMBATT_POWER_INFO 0x10 +#define CMBATT_PNP_INFO 0x20 +#define CMBATT_ACPI_ENTRY_EXIT 0x40 +#define CMBATT_PNP_ENTRY_EXIT 0x200 +#define CMBATT_ACPI_ASSERT 0x400 + +typedef enum _CMBATT_EXTENSION_TYPE +{ + CmBattAcAdapter, + CmBattBattery +} CMBATT_EXTENSION_TYPE; + +typedef struct _ACPI_BST_DATA +{ + ULONG State; + ULONG PresentRate; + ULONG RemainingCapacity; + ULONG PresentVoltage; +} ACPI_BST_DATA, *PACPI_BST_DATA; + +typedef struct _ACPI_BIF_DATA +{ + ULONG PowerUnit; + ULONG DesignCapacity; + ULONG LastFullCapacity; + ULONG BatteryTechnology; + ULONG DesignVoltage; + ULONG DesignCapacityWarning; + ULONG DesignCapacityLow; + ULONG BatteryCapacityGranularity1; + ULONG BatteryCapacityGranularity2; + CHAR ModelNumber[256]; + CHAR SerialNubmer[256]; + CHAR BatteryType[256]; + CHAR OemInfo[256]; +} ACPI_BIF_DATA, *PACPI_BIF_DATA; + +typedef struct _CMBATT_DEVICE_EXTENSION +{ + CMBATT_EXTENSION_TYPE FdoType; + PDEVICE_OBJECT DeviceObject; + PDEVICE_OBJECT FdoDeviceObject; + PDEVICE_OBJECT PdoDeviceObject; + PDEVICE_OBJECT AttachedDevice; + FAST_MUTEX FastMutex; + ULONG HandleCount; + PIRP PowerIrp; + POWER_STATE PowerState; + WMILIB_CONTEXT WmiLibInfo; + ULONG WaitWakeEnable; + ULONG WmiCount; + KEVENT WmiEvent; + ULONG DeviceId; + PUNICODE_STRING DeviceName; + ACPI_INTERFACE_STANDARD2 AcpiInterface; + BOOLEAN DelayAr; + BOOLEAN DelayedArFlag; + PVOID ClassData; + BOOLEAN Started; + BOOLEAN NotifySent; + ULONG ArLock; + ULONG TagData; + ULONG Tag; + ULONG ModelNumberLength; + PCHAR ModelNumber; + ULONG SerialNumberLength; + PCHAR SerialNumber; + ULONG OemInfoLength; + PCHAR OemInfo; + ACPI_BST_DATA BstData; + ACPI_BIF_DATA BifData; + ULONG Id; + ULONG State; + ULONG RemainingCapacity; + ULONG PresentVoltage; + ULONG Rate; + BATTERY_INFORMATION StaticBatteryInformation; + ULONG BatteryCapacityGranularity1; + ULONG BatteryCapacityGranularity2; + BOOLEAN TripPointSet; + ULONG TripPointValue; + ULONG TripPointOld; + ULONGLONG InterruptTime; +} CMBATT_DEVICE_EXTENSION, *PCMBATT_DEVICE_EXTENSION; + +/* EOF */ diff --git a/drivers/bus/acpi/cmbatt/cmbatt.rbuild b/drivers/bus/acpi/cmbatt/cmbatt.rbuild new file mode 100644 index 00000000000..c8a09e31b44 --- /dev/null +++ b/drivers/bus/acpi/cmbatt/cmbatt.rbuild @@ -0,0 +1,13 @@ + + + + ntoskrnl + hal + battc + . + cmbatt.c + cmexec.c + cmbpnp.c + cmbwmi.c + cmbatt.rc + diff --git a/drivers/bus/acpi/cmbatt/cmbatt.rc b/drivers/bus/acpi/cmbatt/cmbatt.rc new file mode 100644 index 00000000000..d1542f9019e --- /dev/null +++ b/drivers/bus/acpi/cmbatt/cmbatt.rc @@ -0,0 +1,5 @@ +#define REACTOS_VERSION_DLL +#define REACTOS_STR_FILE_DESCRIPTION "Control Method Battery Miniclass Driver\0" +#define REACTOS_STR_INTERNAL_NAME "cmbatt\0" +#define REACTOS_STR_ORIGINAL_FILENAME "cmbatt.sys\0" +#include diff --git a/drivers/bus/acpi/cmbatt/cmbpnp.c b/drivers/bus/acpi/cmbatt/cmbpnp.c new file mode 100644 index 00000000000..fee3ec80b47 --- /dev/null +++ b/drivers/bus/acpi/cmbatt/cmbpnp.c @@ -0,0 +1,104 @@ +/* + * PROJECT: ReactOS ACPI-Compliant Control Method Battery + * LICENSE: BSD - See COPYING.ARM in the top level directory + * FILE: boot/drivers/bus/acpi/cmbatt/cmbpnp.c + * PURPOSE: Plug-and-Play IOCTL/IRP Handling + * PROGRAMMERS: ReactOS Portable Systems Group + */ + +/* INCLUDES *******************************************************************/ + +#include "cmbatt.h" + +/* FUNCTIONS ******************************************************************/ + +NTSTATUS +NTAPI +CmBattIoCompletion(PDEVICE_OBJECT DeviceObject, + PIRP Irp, + PKEVENT Event) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattGetAcpiInterfaces(PDEVICE_OBJECT DeviceObject, + PACPI_INTERFACE_STANDARD2 *AcpiInterface) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +VOID +NTAPI +CmBattDestroyFdo(PDEVICE_OBJECT DeviceObject) +{ + UNIMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattRemoveDevice(PDEVICE_OBJECT DeviceObject, + PIRP Irp) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattPowerDispatch(PDEVICE_OBJECT DeviceObject, + PIRP Irp) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattCreateFdo(PDRIVER_OBJECT DriverObject, + PDEVICE_OBJECT DeviceObject, + ULONG DeviceExtensionSize, + PDEVICE_OBJECT *NewDeviceObject) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattPnpDispatch(PDEVICE_OBJECT DeviceObject, + PIRP Irp) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattAddBattery(PDRIVER_OBJECT DriverObject, + PDEVICE_OBJECT DeviceObject) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattAddAcAdapter(PDRIVER_OBJECT DriverObject, + PDEVICE_OBJECT DeviceObject) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS NTAPI CmBattAddDevice(PDRIVER_OBJECT DriverObject, + PDEVICE_OBJECT DeviceObject) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +/* EOF */ diff --git a/drivers/bus/acpi/cmbatt/cmbwmi.c b/drivers/bus/acpi/cmbatt/cmbwmi.c new file mode 100644 index 00000000000..848c920dd0b --- /dev/null +++ b/drivers/bus/acpi/cmbatt/cmbwmi.c @@ -0,0 +1,94 @@ +/* + * PROJECT: ReactOS ACPI-Compliant Control Method Battery + * LICENSE: BSD - See COPYING.ARM in the top level directory + * FILE: boot/drivers/bus/acpi/cmbatt/cmbwmi.c + * PURPOSE: WMI Interface + * PROGRAMMERS: ReactOS Portable Systems Group + */ + +/* INCLUDES *******************************************************************/ + +#include "cmbatt.h" + +/* FUNCTIONS ******************************************************************/ + +NTSTATUS +NTAPI +CmBattQueryWmiRegInfo(PDEVICE_OBJECT DeviceObject, + PULONG RegFlags, + PUNICODE_STRING InstanceName, + PUNICODE_STRING *RegistryPath, + PUNICODE_STRING MofResourceName, + PDEVICE_OBJECT *Pdo) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattQueryWmiDataBlock(PDEVICE_OBJECT DeviceObject, + PIRP Irp, + ULONG GuidIndex, + ULONG InstanceIndex, + ULONG InstanceCount, + PULONG InstanceLengthArray, + ULONG BufferAvail, + PUCHAR Buffer) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattSetWmiDataBlock(PDEVICE_OBJECT DeviceObject, + PIRP Irp, + ULONG GuidIndex, + ULONG InstanceIndex, + ULONG BufferSize, + PUCHAR Buffer) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattSetWmiDataItem(PDEVICE_OBJECT DeviceObject, + PIRP Irp, + ULONG GuidIndex, + ULONG InstanceIndex, + ULONG DataItemId, + ULONG BufferSize, + PUCHAR Buffer) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattWmiDeRegistration(PCMBATT_DEVICE_EXTENSION DeviceExtension) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattWmiRegistration(PCMBATT_DEVICE_EXTENSION DeviceExtension) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattSystemControl(PDEVICE_OBJECT DeviceObject, PIRP Irp) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +/* EOF */ diff --git a/drivers/bus/acpi/cmbatt/cmexec.c b/drivers/bus/acpi/cmbatt/cmexec.c new file mode 100644 index 00000000000..a41865c5e4c --- /dev/null +++ b/drivers/bus/acpi/cmbatt/cmexec.c @@ -0,0 +1,100 @@ +/* + * PROJECT: ReactOS ACPI-Compliant Control Method Battery + * LICENSE: BSD - See COPYING.ARM in the top level directory + * FILE: boot/drivers/bus/acpi/cmbatt/cmexec.c + * PURPOSE: ACPI Method Execution/Evaluation Glue + * PROGRAMMERS: ReactOS Portable Systems Group + */ + +/* INCLUDES *******************************************************************/ + +#include "cmbatt.h" + +/* FUNCTIONS ******************************************************************/ + +NTSTATUS +NTAPI +GetDwordElement(PACPI_METHOD_ARGUMENT Argument, + PULONG Value) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +GetStringElement(PACPI_METHOD_ARGUMENT Argument, + PCHAR Value) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattGetPsrData(PDEVICE_OBJECT DeviceObject, + PULONG PsrData) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattGetBifData(PCMBATT_DEVICE_EXTENSION DeviceExtension, + PACPI_BIF_DATA BifData) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattGetBstData(PCMBATT_DEVICE_EXTENSION DeviceExtension, + PACPI_BST_DATA BstData) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattGetStaData(PDEVICE_OBJECT DeviceObject, + PULONG StaData) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattGetUniqueId(PDEVICE_OBJECT DeviceObject, + PULONG UniqueId) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattSetTripPpoint(PCMBATT_DEVICE_EXTENSION DeviceExtension, + ULONG AlarmValue) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattSendDownStreamIrp(PDEVICE_OBJECT DeviceObject, + ULONG IoControlCode, + PVOID InputBuffer, + ULONG InputBufferLength, + PACPI_EVAL_OUTPUT_BUFFER OutputBuffer, + ULONG OutputBufferLength) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +/* EOF */ diff --git a/drivers/bus/acpi/main.c b/drivers/bus/acpi/main.c index d8d8b3e7dad..3d1170eefd6 100644 --- a/drivers/bus/acpi/main.c +++ b/drivers/bus/acpi/main.c @@ -6,7 +6,7 @@ #include #include -//#define NDEBUG +#define NDEBUG #include #ifdef ALLOC_PRAGMA @@ -35,7 +35,7 @@ Bus_AddDevice( DPRINT("Add Device: 0x%p\n", PhysicalDeviceObject); - DPRINT1("#################### Bus_CreateClose Creating FDO Device ####################\n"); + DPRINT("#################### Bus_CreateClose Creating FDO Device ####################\n"); status = IoCreateDevice(DriverObject, sizeof(FDO_DEVICE_DATA), NULL, @@ -134,7 +134,7 @@ Bus_AddDevice( goto End; } - DPRINT1("AddDevice: %p to %p->%p (%ws) \n", + DPRINT("AddDevice: %p to %p->%p (%ws) \n", deviceObject, deviceData->NextLowerDriver, PhysicalDeviceObject, diff --git a/drivers/bus/acpi/osl.c b/drivers/bus/acpi/osl.c index be26a0811f9..f2549951e7e 100644 --- a/drivers/bus/acpi/osl.c +++ b/drivers/bus/acpi/osl.c @@ -90,7 +90,7 @@ AcpiOsInitialize (void) ACPI_STATUS AcpiOsTerminate(void) { - DPRINT1("AcpiOsTerminate() called\n"); + DPRINT("AcpiOsTerminate() called\n"); if (AcpiInterruptHandlerRegistered) AcpiOsRemoveInterruptHandler(AcpiIrqNumber, AcpiIrqHandler); @@ -117,7 +117,9 @@ AcpiOsVprintf ( const char *Fmt, va_list Args) { +#ifndef NDEBUG vDbgPrintEx (-1, DPFLTR_ERROR_LEVEL, Fmt, Args); +#endif return; } @@ -329,7 +331,7 @@ AcpiOsRemoveInterruptHandler ( void AcpiOsStall (UINT32 microseconds) { - DPRINT1("AcpiOsStall %d\n",microseconds); + DPRINT("AcpiOsStall %d\n",microseconds); KeStallExecutionProcessor(microseconds); return; } @@ -337,7 +339,7 @@ AcpiOsStall (UINT32 microseconds) void AcpiOsSleep (ACPI_INTEGER milliseconds) { - DPRINT1("AcpiOsSleep %d\n", milliseconds); + DPRINT("AcpiOsSleep %d\n", milliseconds); KeStallExecutionProcessor(milliseconds*1000); return; } @@ -466,11 +468,12 @@ AcpiOsReadPciConfiguration ( NTSTATUS Status; PCI_SLOT_NUMBER slot; - if (Register == 0) + if (Register == 0 || PciId->Device == 0 || + Register + Width > PCI_COMMON_HDR_LENGTH) return AE_ERROR; slot.u.AsULONG = 0; - slot.u.bits.DeviceNumber = PciId->Bus; + slot.u.bits.DeviceNumber = PciId->Device; slot.u.bits.FunctionNumber = PciId->Function; DPRINT("AcpiOsReadPciConfiguration, slot=0x%X, func=0x%X\n", slot.u.AsULONG, Register); @@ -498,11 +501,12 @@ AcpiOsWritePciConfiguration ( ULONG buf = Value; PCI_SLOT_NUMBER slot; - if (Register == 0) + if (Register == 0 || PciId->Device == 0 || + Register + Width > PCI_COMMON_HDR_LENGTH) return AE_ERROR; slot.u.AsULONG = 0; - slot.u.bits.DeviceNumber = PciId->Bus; + slot.u.bits.DeviceNumber = PciId->Device; slot.u.bits.FunctionNumber = PciId->Function; DPRINT("AcpiOsWritePciConfiguration, slot=0x%x\n", slot.u.AsULONG); @@ -664,7 +668,7 @@ AcpiOsExecute ( ACPI_OSD_EXEC_CALLBACK Function, void *Context) { - DPRINT1("AcpiOsExecute\n"); + DPRINT("AcpiOsExecute\n"); KeInsertQueueDpc(&AcpiDpc, (PVOID)Function, (PVOID)Context); diff --git a/drivers/bus/acpi/pnp.c b/drivers/bus/acpi/pnp.c index 4778dc66c2e..c82a3905023 100644 --- a/drivers/bus/acpi/pnp.c +++ b/drivers/bus/acpi/pnp.c @@ -7,7 +7,7 @@ #include #include -//#define NDEBUG +#define NDEBUG #include #ifdef ALLOC_PRAGMA diff --git a/drivers/bus/acpi/power.c b/drivers/bus/acpi/power.c index 3af99c96402..2f7175c74ad 100644 --- a/drivers/bus/acpi/power.c +++ b/drivers/bus/acpi/power.c @@ -6,7 +6,7 @@ #include #include -//#define NDEBUG +#define NDEBUG #include NTSTATUS diff --git a/drivers/storage/port/buslogic/BusLogic958.c b/drivers/storage/port/buslogic/BusLogic958.c index 22c5838b99b..0bf439e06b9 100644 --- a/drivers/storage/port/buslogic/BusLogic958.c +++ b/drivers/storage/port/buslogic/BusLogic958.c @@ -79,40 +79,6 @@ v1.2.0.2 // Fix PR 40284 correctly, disable interrupts in the initialization ro #include "BusLogic958.h" -int strcmp(const char* s1, const char* s2) -{ - while(*s1 == *s2) - { - if(*s1 == 0) return 0; - - s1 ++; - s2 ++; - } - - return *s1 - *s2; -} - -char * strcat(char * s, const char * append) -{ - char * save = s; - - for(; *s; ++s); - - while((*s++ = *append++)); - - return save; -} - -char * strcpy(char * to, const char * from) -{ - char *save = to; - - for (; (*to = *from); ++from, ++to); - - return save; -} - - ULONG NTAPI DriverEntry(IN PVOID DriverObject, diff --git a/drivers/storage/port/buslogic/buslogic.rbuild b/drivers/storage/port/buslogic/buslogic.rbuild index 3a197ce05de..3347f10b98d 100644 --- a/drivers/storage/port/buslogic/buslogic.rbuild +++ b/drivers/storage/port/buslogic/buslogic.rbuild @@ -1,6 +1,6 @@ - + . scsiport diff --git a/drivers/video/font/ftfd/freetype.def b/drivers/video/font/ftfd/freetype.def index 78f842588ee..883a977f464 100644 --- a/drivers/video/font/ftfd/freetype.def +++ b/drivers/video/font/ftfd/freetype.def @@ -1,5 +1,8 @@ LIBRARY ftfd.dll EXPORTS + FT_Bitmap_Convert + FT_Bitmap_Done + FT_Bitmap_New FT_Done_Face FT_Done_Glyph FT_Get_Char_Index diff --git a/include/ddk/wdm.h b/include/ddk/wdm.h index 36ff1c3fb34..0a75b5ec14d 100644 --- a/include/ddk/wdm.h +++ b/include/ddk/wdm.h @@ -4763,6 +4763,71 @@ typedef enum _WORK_QUEUE_TYPE { MaximumWorkQueue } WORK_QUEUE_TYPE; +typedef BOOLEAN +(*PGPE_SERVICE_ROUTINE2)( + PVOID ObjectContext, + PVOID ServiceContext); + +typedef NTSTATUS +(*PGPE_CONNECT_VECTOR2)( + PVOID Context, + ULONG GpeNumber, + KINTERRUPT_MODE Mode, + BOOLEAN Shareable, + PGPE_SERVICE_ROUTINE2 ServiceRoutine, + PVOID ServiceContext, + PVOID *ObjectContext); + +typedef NTSTATUS +(*PGPE_DISCONNECT_VECTOR2)( + PVOID Context, + PVOID ObjectContext); + +typedef NTSTATUS +(*PGPE_ENABLE_EVENT2)( + PVOID Context, + PVOID ObjectContext); + +typedef NTSTATUS +(*PGPE_DISABLE_EVENT2)( + PVOID Context, + PVOID ObjectContext); + +typedef NTSTATUS +(*PGPE_CLEAR_STATUS2)( + PVOID Context, + PVOID ObjectContext); + +typedef VOID +(*PDEVICE_NOTIFY_CALLBACK2)( + PVOID NotificationContext, + ULONG NotifyCode); + +typedef NTSTATUS +(*PREGISTER_FOR_DEVICE_NOTIFICATIONS2)( + PVOID Context, + PDEVICE_NOTIFY_CALLBACK2 NotificationHandler, + PVOID NotificationContext); + +typedef VOID +(*PUNREGISTER_FOR_DEVICE_NOTIFICATIONS2)( + PVOID Context); + +typedef struct _ACPI_INTERFACE_STANDARD2 { + USHORT Size; + USHORT Version; + PVOID Context; + PINTERFACE_REFERENCE InterfaceReference; + PINTERFACE_DEREFERENCE InterfaceDereference; + PGPE_CONNECT_VECTOR2 GpeConnectVector; + PGPE_DISCONNECT_VECTOR2 GpeDisconnectVector; + PGPE_ENABLE_EVENT2 GpeEnableEvent; + PGPE_DISABLE_EVENT2 GpeDisableEvent; + PGPE_CLEAR_STATUS2 GpeClearStatus; + PREGISTER_FOR_DEVICE_NOTIFICATIONS2 RegisterForDeviceNotifications; + PUNREGISTER_FOR_DEVICE_NOTIFICATIONS2 UnregisterForDeviceNotifications; +} ACPI_INTERFACE_STANDARD2, *PACPI_INTERFACE_STANDARD2; + #if !defined(_AMD64_) && !defined(_IA64_) #include #endif diff --git a/include/dxsdk/axextend.idl b/include/dxsdk/axextend.idl index 66e43f151ca..72e37ce47c7 100644 --- a/include/dxsdk/axextend.idl +++ b/include/dxsdk/axextend.idl @@ -1070,6 +1070,22 @@ interface IAMFilterMiscFlags : IUnknown ULONG GetMiscFlags(); }; +[ + local, + object, + uuid(56ED71A0-AF5F-11D0-B3F0-00AA003761C5), + pointer_default(unique) +] +interface IAMBufferNegotiation : IUnknown +{ + HRESULT SuggestAllocatorProperties ( + [in] const ALLOCATOR_PROPERTIES *pprop); + + HRESULT GetAllocatorProperties ( + [out] ALLOCATOR_PROPERTIES *pprop); + +} + #include [ diff --git a/include/psdk/ks.h b/include/psdk/ks.h index a86d4a87c1a..2249af3711a 100644 --- a/include/psdk/ks.h +++ b/include/psdk/ks.h @@ -336,22 +336,28 @@ DEFINE_GUIDSTRUCT("4747B320-62CE-11CF-A5D6-28DB04C10000", KSMEDIUMSETID_Standard Clock Properties/Methods/Events */ -#define KSPROPSETID_Clock \ +#define STATIC_KSPROPSETID_Clock \ 0xDF12A4C0L, 0xAC17, 0x11CF, 0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00 +DEFINE_GUIDSTRUCT("DF12A4C0-AC17-11CF-A5D6-28DB04C10000", KSPROPSETID_Clock); +#define KSPROPSETID_Clock DEFINE_GUIDNAMED(KSPROPSETID_Clock) typedef enum { KSPROPERTY_CLOCK_TIME, KSPROPERTY_CLOCK_PHYSICALTIME, - KSPROPERTY_CORRELATEDTIME, - KSPROPERTY_CORRELATEDPHYSICALTIME, + KSPROPERTY_CLOCK_CORRELATEDTIME, + KSPROPERTY_CLOCK_CORRELATEDPHYSICALTIME, KSPROPERTY_CLOCK_RESOLUTION, KSPROPERTY_CLOCK_STATE, +#if defined(_NTDDK_) KSPROPERTY_CLOCK_FUNCTIONTABLE +#endif // defined(_NTDDK_) } KSPROPERTY_CLOCK; -#define KSEVENTSETID_Clock \ +#define STATIC_KSEVENTSETID_Clock \ 0x364D8E20L, 0x62C7, 0x11CF, 0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00 +DEFINE_GUIDSTRUCT("364D8E20-62C7-11CF-A5D6-28DB04C10000", KSEVENTSETID_Clock); +#define KSEVENTSETID_Clock DEFINE_GUIDNAMED(KSEVENTSETID_Clock) typedef enum { @@ -718,8 +724,10 @@ typedef enum Properties/Methods/Events */ -#define KSPROPSETID_Stream \ +#define STATIC_KSPROPSETID_Stream\ 0x65aaba60L, 0x98ae, 0x11cf, 0xa1, 0x0d, 0x00, 0x20, 0xaf, 0xd1, 0x56, 0xe4 +DEFINE_GUIDSTRUCT("65aaba60-98ae-11cf-a10d-0020afd156e4", KSPROPSETID_Stream); +#define KSPROPSETID_Stream DEFINE_GUIDNAMED(KSPROPSETID_Stream) typedef enum { @@ -1838,11 +1846,32 @@ typedef struct KSEVENTDATA EventData; } KSRELATIVEEVENT, *PKSRELATIVEEVENT; +#define KSRELATIVEEVENT_FLAG_HANDLE 0x00000001 +#define KSRELATIVEEVENT_FLAG_POINTER 0x00000002 /* =============================================================== Timing */ + +typedef struct { + KSEVENTDATA EventData; + LONGLONG MarkTime; +} KSEVENT_TIME_MARK, *PKSEVENT_TIME_MARK; + +typedef struct { + KSEVENTDATA EventData; + LONGLONG TimeBase; + LONGLONG Interval; +} KSEVENT_TIME_INTERVAL, *PKSEVENT_TIME_INTERVAL; + +typedef struct { + LONGLONG TimeBase; + LONGLONG Interval; +} KSINTERVAL, *PKSINTERVAL; + + + typedef struct { LONGLONG Time; @@ -1856,12 +1885,6 @@ typedef struct LONGLONG SystemTime; } KSCORRELATED_TIME, *PKSCORRELATED_TIME; -typedef struct -{ - LONGLONG TimeBase; - LONGLONG Interval; -} KSINTERVAL, *PKSINTERVAL; - typedef struct { LONGLONG Duration; @@ -2070,19 +2093,7 @@ typedef struct { typedef struct _KSEVENT_ENTRY KSEVENT_ENTRY, *PKSEVENT_ENTRY; #if defined(_NTDDK_) -typedef struct -{ - KSEVENTDATA EventData; - LONGLONG MarkTime; -} KSEVENT_TIME_MARK, *PKSEVENT_TIME_MARK; - -typedef struct -{ - KSEVENTDATA EventData; - LONGLONG TimeBase; - LONGLONG Interval; -} KSEVENT_TIME_INTERVAL, *PKSEVENT_TIME_INTERVAL; - + typedef NTSTATUS (NTAPI *PFNKSADDEVENT)( IN PIRP Irp, IN PKSEVENTDATA EventData, @@ -3867,6 +3878,26 @@ KsPinGetConnectedPinFileObject( #else +#if !defined( KS_NO_CREATE_FUNCTIONS ) + +KSDDKAPI +DWORD +WINAPI +KsCreateAllocator( + IN HANDLE ConnectionHandle, + IN PKSALLOCATOR_FRAMING AllocatorFraming, + OUT PHANDLE AllocatorHandle + ); + +KSDDKAPI +DWORD +NTAPI +KsCreateClock( + IN HANDLE ConnectionHandle, + IN PKSCLOCK_CREATE ClockCreate, + OUT PHANDLE ClockHandle + ); + KSDDKAPI DWORD WINAPI @@ -3877,6 +3908,17 @@ KsCreatePin( OUT PHANDLE ConnectionHandle ); +KSDDKAPI +DWORD +WINAPI +KsCreateTopologyNode( + IN HANDLE ParentHandle, + IN PKSNODE_CREATE NodeCreate, + IN ACCESS_MASK DesiredAccess, + OUT PHANDLE NodeHandle + ); + +#endif #endif diff --git a/include/psdk/winternl.h b/include/psdk/winternl.h index f101f04bc74..7f1a739b53d 100644 --- a/include/psdk/winternl.h +++ b/include/psdk/winternl.h @@ -871,20 +871,20 @@ typedef struct _UNWIND_HISTORY_TABLE { */ /* This is used by NtQuerySystemInformation */ -typedef struct _SYSTEM_THREAD_INFORMATION{ - FILETIME ftKernelTime; - FILETIME ftUserTime; - FILETIME ftCreateTime; - DWORD dwTickCount; - DWORD dwStartAddress; - DWORD dwOwningPID; - DWORD dwThreadID; - DWORD dwCurrentPriority; - DWORD dwBasePriority; - DWORD dwContextSwitches; - DWORD dwThreadState; - DWORD dwWaitReason; - DWORD dwUnknown; +typedef struct _SYSTEM_THREAD_INFORMATION +{ /* win32/win64 */ + LARGE_INTEGER KernelTime; /* 00/00 */ + LARGE_INTEGER UserTime; /* 08/08 */ + LARGE_INTEGER CreateTime; /* 10/10 */ + DWORD dwTickCount; /* 18/18 */ + LPVOID StartAddress; /* 1c/20 */ + CLIENT_ID ClientId; /* 20/28 */ + DWORD dwCurrentPriority; /* 28/38 */ + DWORD dwBasePriority; /* 2c/3c */ + DWORD dwContextSwitches; /* 30/40 */ + DWORD dwThreadState; /* 34/44 */ + DWORD dwWaitReason; /* 38/48 */ + DWORD dwUnknown; /* 3c/4c */ } SYSTEM_THREAD_INFORMATION, *PSYSTEM_THREAD_INFORMATION; typedef struct _IO_STATUS_BLOCK { @@ -1195,38 +1195,39 @@ typedef struct _VM_COUNTERS_ { SIZE_T QuotaNonPagedPoolUsage; SIZE_T PagefileUsage; SIZE_T PeakPagefileUsage; + SIZE_T PrivatePageCount; } VM_COUNTERS, *PVM_COUNTERS; typedef struct _SYSTEM_PROCESS_INFORMATION { -#ifdef __WINESRC__ - DWORD dwOffset; - DWORD dwThreadCount; - DWORD dwUnknown1[6]; - FILETIME ftCreationTime; - FILETIME ftUserTime; - FILETIME ftKernelTime; - UNICODE_STRING ProcessName; - DWORD dwBasePriority; - DWORD dwProcessID; - DWORD dwParentProcessID; - DWORD dwHandleCount; - DWORD dwUnknown3; - DWORD dwUnknown4; - VM_COUNTERS vmCounters; - IO_COUNTERS ioCounters; - SYSTEM_THREAD_INFORMATION ti[1]; +#ifdef __WINESRC__ /* win32/win64 */ + ULONG NextEntryOffset; /* 00/00 */ + DWORD dwThreadCount; /* 04/04 */ + DWORD dwUnknown1[6]; /* 08/08 */ + LARGE_INTEGER CreationTime; /* 20/20 */ + LARGE_INTEGER UserTime; /* 28/28 */ + LARGE_INTEGER KernelTime; /* 30/30 */ + UNICODE_STRING ProcessName; /* 38/38 */ + DWORD dwBasePriority; /* 40/48 */ + HANDLE UniqueProcessId; /* 44/50 */ + HANDLE ParentProcessId; /* 48/58 */ + ULONG HandleCount; /* 4c/60 */ + DWORD dwUnknown3; /* 50/64 */ + DWORD dwUnknown4; /* 54/68 */ + VM_COUNTERS vmCounters; /* 58/70 */ + IO_COUNTERS ioCounters; /* 88/d0 */ + SYSTEM_THREAD_INFORMATION ti[1]; /* b8/100 */ #else - ULONG NextEntryOffset; - BYTE Reserved1[52]; - PVOID Reserved2[3]; - HANDLE UniqueProcessId; - PVOID Reserved3; - ULONG HandleCount; - BYTE Reserved4[4]; - PVOID Reserved5[11]; - SIZE_T PeakPagefileUsage; - SIZE_T PrivatePageCount; - LARGE_INTEGER Reserved6[6]; + ULONG NextEntryOffset; /* 00/00 */ + BYTE Reserved1[52]; /* 04/04 */ + PVOID Reserved2[3]; /* 38/38 */ + HANDLE UniqueProcessId; /* 44/50 */ + PVOID Reserved3; /* 48/58 */ + ULONG HandleCount; /* 4c/60 */ + BYTE Reserved4[4]; /* 50/64 */ + PVOID Reserved5[11]; /* 54/68 */ + SIZE_T PeakPagefileUsage; /* 80/c0 */ + SIZE_T PrivatePageCount; /* 84/c8 */ + LARGE_INTEGER Reserved6[6]; /* 88/d0 */ #endif } SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION; @@ -1553,7 +1554,7 @@ typedef struct _KEY_MULTIPLE_VALUE_INFORMATION ULONG Type; } KEY_MULTIPLE_VALUE_INFORMATION, *PKEY_MULTIPLE_VALUE_INFORMATION; -typedef VOID (*PTIMER_APC_ROUTINE) ( PVOID, ULONG, LONG ); +typedef VOID (CALLBACK *PTIMER_APC_ROUTINE) ( PVOID, ULONG, LONG ); typedef enum _EVENT_TYPE { NotificationEvent, diff --git a/include/reactos/wine/mscvpdb.h b/include/reactos/wine/mscvpdb.h index 9d52a655b56..2aefa879a90 100644 --- a/include/reactos/wine/mscvpdb.h +++ b/include/reactos/wine/mscvpdb.h @@ -1642,14 +1642,28 @@ struct startend unsigned int end; }; +#define LT2_LINES_BLOCK 0x000000f2 +#define LT2_FILES_BLOCK 0x000000f4 + /* there's a new line tab structure from MS Studio 2005 and after - * it's made of: - * DWORD 000000f4 - * DWORD lineblk_offset (counting bytes after this field) - * an array of codeview_linetab2_file structures - * an array (starting at ) of codeview_linetab2_block structures + * it's made of a list of codeview_linetab2 blocks. + * We've only seen (so far) list with a single LT2_FILES_BLOCK and several + * LT2_LINES_BLOCK. The LT2_FILES block has been encountered either as first + * or last block of the list. + * A LT2_FILES contains one or several codeview_linetab2_file:s */ +struct codeview_linetab2 +{ + DWORD header; + DWORD size_of_block; +}; + +static inline const struct codeview_linetab2* codeview_linetab2_next_block(const struct codeview_linetab2* lt2) +{ + return (const struct codeview_linetab2*)((const char*)(lt2 + 1) + lt2->size_of_block); +} + struct codeview_linetab2_file { DWORD offset; /* offset in string table for filename */ @@ -1658,16 +1672,21 @@ struct codeview_linetab2_file WORD pad0; /* always 0 */ }; -struct codeview_linetab2_block +struct codeview_lt2blk_files { - DWORD header; /* 0x000000f2 */ - DWORD size_of_block; /* next block is at # bytes after this field */ - DWORD start; /* start address of function with line numbers */ - DWORD seg; /* segment of function with line numbers */ - DWORD size; /* size of function with line numbers */ - DWORD file_offset; /* offset for accessing corresponding codeview_linetab2_file */ - DWORD nlines; /* number of lines in this block */ - DWORD size_lines; /* number of bytes following for line number information */ + struct codeview_linetab2 lt2; /* LT2_FILES */ + struct codeview_linetab2_file file[1]; +}; + +struct codeview_lt2blk_lines +{ + struct codeview_linetab2 lt2; /* LT2_LINE_BLOCK */ + DWORD start; /* start address of function with line numbers */ + DWORD seg; /* segment of function with line numbers */ + DWORD size; /* size of function with line numbers */ + DWORD file_offset; /* offset for accessing corresponding codeview_linetab2_file */ + DWORD nlines; /* number of lines in this block */ + DWORD size_lines; /* number of bytes following for line number information */ struct { DWORD offset; /* offset (from :) for line number */ DWORD lineno; /* the line number (OR:ed with 0x80000000 why ???) */ diff --git a/include/xdk/iotypes.h b/include/xdk/iotypes.h index a2bce0be3f9..4bdc140512a 100644 --- a/include/xdk/iotypes.h +++ b/include/xdk/iotypes.h @@ -2151,6 +2151,71 @@ typedef enum _WORK_QUEUE_TYPE { MaximumWorkQueue } WORK_QUEUE_TYPE; +typedef BOOLEAN +(*PGPE_SERVICE_ROUTINE2)( + PVOID ObjectContext, + PVOID ServiceContext); + +typedef NTSTATUS +(*PGPE_CONNECT_VECTOR2)( + PVOID Context, + ULONG GpeNumber, + KINTERRUPT_MODE Mode, + BOOLEAN Shareable, + PGPE_SERVICE_ROUTINE2 ServiceRoutine, + PVOID ServiceContext, + PVOID *ObjectContext); + +typedef NTSTATUS +(*PGPE_DISCONNECT_VECTOR2)( + PVOID Context, + PVOID ObjectContext); + +typedef NTSTATUS +(*PGPE_ENABLE_EVENT2)( + PVOID Context, + PVOID ObjectContext); + +typedef NTSTATUS +(*PGPE_DISABLE_EVENT2)( + PVOID Context, + PVOID ObjectContext); + +typedef NTSTATUS +(*PGPE_CLEAR_STATUS2)( + PVOID Context, + PVOID ObjectContext); + +typedef VOID +(*PDEVICE_NOTIFY_CALLBACK2)( + PVOID NotificationContext, + ULONG NotifyCode); + +typedef NTSTATUS +(*PREGISTER_FOR_DEVICE_NOTIFICATIONS2)( + PVOID Context, + PDEVICE_NOTIFY_CALLBACK2 NotificationHandler, + PVOID NotificationContext); + +typedef VOID +(*PUNREGISTER_FOR_DEVICE_NOTIFICATIONS2)( + PVOID Context); + +typedef struct _ACPI_INTERFACE_STANDARD2 { + USHORT Size; + USHORT Version; + PVOID Context; + PINTERFACE_REFERENCE InterfaceReference; + PINTERFACE_DEREFERENCE InterfaceDereference; + PGPE_CONNECT_VECTOR2 GpeConnectVector; + PGPE_DISCONNECT_VECTOR2 GpeDisconnectVector; + PGPE_ENABLE_EVENT2 GpeEnableEvent; + PGPE_DISABLE_EVENT2 GpeDisableEvent; + PGPE_CLEAR_STATUS2 GpeClearStatus; + PREGISTER_FOR_DEVICE_NOTIFICATIONS2 RegisterForDeviceNotifications; + PUNREGISTER_FOR_DEVICE_NOTIFICATIONS2 UnregisterForDeviceNotifications; +} ACPI_INTERFACE_STANDARD2, *PACPI_INTERFACE_STANDARD2; + #if !defined(_AMD64_) && !defined(_IA64_) #include #endif diff --git a/lib/3rdparty/freetype/src/base/ftbitmap.c b/lib/3rdparty/freetype/src/base/ftbitmap.c index 4c1cdf21888..c847eb00d24 100644 --- a/lib/3rdparty/freetype/src/base/ftbitmap.c +++ b/lib/3rdparty/freetype/src/base/ftbitmap.c @@ -445,15 +445,15 @@ { FT_Int val = ss[0]; /* avoid a byte->int cast on each line */ + tt[0] = (FT_Byte)( ( val & 0x80 ) ? 0xff : 0); + tt[1] = (FT_Byte)( ( val & 0x40 ) ? 0xff : 0); + tt[2] = (FT_Byte)( ( val & 0x20 ) ? 0xff : 0); + tt[3] = (FT_Byte)( ( val & 0x10 ) ? 0xff : 0); + tt[4] = (FT_Byte)( ( val & 0x08 ) ? 0xff : 0); + tt[5] = (FT_Byte)( ( val & 0x04 ) ? 0xff : 0); + tt[6] = (FT_Byte)( ( val & 0x02 ) ? 0xff : 0); + tt[7] = (FT_Byte)( ( val & 0x01 ) ? 0xff : 0); - tt[0] = (FT_Byte)( ( val & 0x80 ) >> 7 ); - tt[1] = (FT_Byte)( ( val & 0x40 ) >> 6 ); - tt[2] = (FT_Byte)( ( val & 0x20 ) >> 5 ); - tt[3] = (FT_Byte)( ( val & 0x10 ) >> 4 ); - tt[4] = (FT_Byte)( ( val & 0x08 ) >> 3 ); - tt[5] = (FT_Byte)( ( val & 0x04 ) >> 2 ); - tt[6] = (FT_Byte)( ( val & 0x02 ) >> 1 ); - tt[7] = (FT_Byte)( val & 0x01 ); tt += 8; ss += 1; @@ -468,7 +468,7 @@ for ( ; j > 0; j-- ) { - tt[0] = (FT_Byte)( ( val & 0x80 ) >> 7); + tt[0] = (FT_Byte)( ( val & 0x80 ) ? 0xff : 0); val <<= 1; tt += 1; } diff --git a/ntoskrnl/include/internal/i386/asmmacro.S b/ntoskrnl/include/internal/i386/asmmacro.S index d8ca99da594..6ddb9d015ad 100644 --- a/ntoskrnl/include/internal/i386/asmmacro.S +++ b/ntoskrnl/include/internal/i386/asmmacro.S @@ -179,6 +179,14 @@ set_sane_segs: mov fs, ax endif +#if DBG + /* Keep the frame chain intact */ + mov eax, [esp + KTRAP_FRAME_EIP] + mov [esp + KTRAP_FRAME_DEBUGEIP], eax + mov [esp + KTRAP_FRAME_DEBUGEBP], ebp + mov ebp, esp +#endif + /* Set parameter 1 (ECX) to point to the frame */ mov ecx, esp @@ -187,11 +195,157 @@ set_sane_segs: ENDM +MACRO(KiCallHandler, Handler) +#if DBG + /* Use a call to get the return address for back traces */ + call Handler +#else + /* Use the faster jmp */ + jmp Handler +#endif + nop +ENDM + MACRO(TRAP_ENTRY, Trap, Flags) EXTERN @&Trap&Handler@4 :PROC PUBLIC _&Trap _&Trap: KiEnterTrap Flags - jmp @&Trap&Handler@4 + KiCallHandler @&Trap&Handler@4 +ENDM + +#define KI_RESTORE_EAX HEX(001) +#define KI_RESTORE_ECX_EDX HEX(002) +#define KI_RESTORE_FS HEX(004) +#define KI_RESTORE_SEGMENTS HEX(008) +#define KI_RESTORE_EFLAGS HEX(010) +#define KI_EXIT_SYSCALL HEX(020) +#define KI_EXIT_JMP HEX(040) +#define KI_EXIT_RET HEX(080) +#define KI_EXIT_IRET HEX(100) +#define KI_EDITED_FRAME HEX(200) +#define KI_RESTORE_VOLATILES (KI_RESTORE_EAX OR KI_RESTORE_ECX_EDX) + +MACRO(KiTrapExitStub, Name, Flags) + +PUBLIC @&Name&@4 +@&Name&@4: + + if (Flags AND KI_RESTORE_EFLAGS) + + /* We will pop EFlags off the stack */ + OffsetEsp = KTRAP_FRAME_EFLAGS + + elseif (Flags AND KI_EXIT_IRET) + + /* This is the IRET frame */ + OffsetEsp = KTRAP_FRAME_EIP + + else + + OffsetEsp = 0 + + endif + + if (Flags AND KI_EDITED_FRAME) + + /* Load the requested ESP */ + mov esp, [ecx + KTRAP_FRAME_TEMPESP] + + /* Put return address on the new stack */ + push [ecx + KTRAP_FRAME_EIP] + + /* Put EFLAGS on the new stack */ + push [ecx + KTRAP_FRAME_EFLAGS] + + else + + /* Point esp to an appropriate member of the frame */ + lea esp, [ecx + OffsetEsp] + + endif + + /* Restore non volatiles */ + mov ebx, [ecx + KTRAP_FRAME_EBX] + mov esi, [ecx + KTRAP_FRAME_ESI] + mov edi, [ecx + KTRAP_FRAME_EDI] + mov ebp, [ecx + KTRAP_FRAME_EBP] + + if (Flags AND KI_RESTORE_EAX) + + /* Restore eax */ + mov eax, [ecx + KTRAP_FRAME_EAX] + + endif + + if (Flags AND KI_RESTORE_ECX_EDX) + + /* Restore volatiles */ + mov edx, [ecx + KTRAP_FRAME_EDX] + mov ecx, [ecx + KTRAP_FRAME_ECX] + + elseif (Flags AND KI_EXIT_JMP) + + /* Load return address into edx */ + mov edx, [esp - OffsetEsp + KTRAP_FRAME_EIP] + + elseif (Flags AND KI_EXIT_SYSCALL) + + /* Set sysexit parameters */ + mov edx, [esp - OffsetEsp + KTRAP_FRAME_EIP] + mov ecx, [esp - OffsetEsp + KTRAP_FRAME_ESP] + + /* Keep interrupts disabled until the sti / sysexit */ + and byte ptr [esp - OffsetEsp + KTRAP_FRAME_EFLAGS + 1], ~(EFLAGS_INTERRUPT_MASK >> 8) + + endif + + if (Flags AND KI_RESTORE_SEGMENTS) + + /* Restore segments for user mode */ + mov ds, [esp - OffsetEsp + KTRAP_FRAME_DS] + mov es, [esp - OffsetEsp + KTRAP_FRAME_ES] + mov gs, [esp - OffsetEsp + KTRAP_FRAME_GS] + + endif + + if ((Flags AND KI_RESTORE_FS) OR (Flags AND KI_RESTORE_SEGMENTS)) + + /* Restore user mode FS */ + mov fs, [esp - OffsetEsp + KTRAP_FRAME_FS] + + endif + + if (Flags AND KI_RESTORE_EFLAGS) + + /* Restore EFLAGS */ + popf + + endif + + if (Flags AND KI_EXIT_SYSCALL) + + /* Enable interrupts and return to user mode. + Both must follow directly after another to be "atomic". */ + sti + sysexit + + elseif (Flags AND KI_EXIT_IRET) + + /* Return with iret */ + iret + + elseif (Flags AND KI_EXIT_JMP) + + /* Return to kernel mode with a jmp */ + jmp edx + + elseif (Flags AND KI_EXIT_RET) + + /* Return to kernel mode with a ret */ + ret + + endif + ENDM diff --git a/ntoskrnl/include/internal/trap_x.h b/ntoskrnl/include/internal/trap_x.h index 26e39e4484b..93c5d1fc6c0 100644 --- a/ntoskrnl/include/internal/trap_x.h +++ b/ntoskrnl/include/internal/trap_x.h @@ -8,6 +8,8 @@ #pragma once +//#define TRAP_DEBUG 1 + // // Unreachable code hint for GCC 4.5.x, older GCC versions, and MSVC // @@ -23,6 +25,17 @@ #define UNREACHABLE #endif +// +// Helper Code +// +BOOLEAN +FORCEINLINE +KiUserTrap(IN PKTRAP_FRAME TrapFrame) +{ + /* Anything else but Ring 0 is Ring 3 */ + return (TrapFrame->SegCs & MODE_MASK); +} + // // Debug Macros // @@ -78,18 +91,19 @@ KiFillTrapFrameDebug(IN PKTRAP_FRAME TrapFrame) TrapFrame->DbgArgMark = 0xBADB0D00; TrapFrame->DbgEip = TrapFrame->Eip; TrapFrame->DbgEbp = TrapFrame->Ebp; + TrapFrame->PreviousPreviousMode = -1; } VOID FORCEINLINE KiExitTrapDebugChecks(IN PKTRAP_FRAME TrapFrame, - IN KTRAP_STATE_BITS SkipBits) + IN KTRAP_EXIT_SKIP_BITS SkipBits) { /* Make sure interrupts are disabled */ if (__readeflags() & EFLAGS_INTERRUPT_MASK) { DbgPrint("Exiting with interrupts enabled: %lx\n", __readeflags()); - while (TRUE); + __debugbreak(); } /* Make sure this is a real trap frame */ @@ -97,35 +111,35 @@ KiExitTrapDebugChecks(IN PKTRAP_FRAME TrapFrame, { DbgPrint("Exiting with an invalid trap frame? (No MAGIC in trap frame)\n"); KiDumpTrapFrame(TrapFrame); - while (TRUE); + __debugbreak(); } /* Make sure we're not in user-mode or something */ if (Ke386GetFs() != KGDT_R0_PCR) { DbgPrint("Exiting with an invalid FS: %lx\n", Ke386GetFs()); - while (TRUE); + __debugbreak(); } /* Make sure we have a valid SEH chain */ if (KeGetPcr()->NtTib.ExceptionList == 0) { DbgPrint("Exiting with NULL exception chain: %p\n", KeGetPcr()->NtTib.ExceptionList); - while (TRUE); + __debugbreak(); } /* Make sure we're restoring a valid SEH chain */ if (TrapFrame->ExceptionList == 0) { DbgPrint("Entered a trap with a NULL exception chain: %p\n", TrapFrame->ExceptionList); - while (TRUE); + __debugbreak(); } /* If we're ignoring previous mode, make sure caller doesn't actually want it */ if ((SkipBits.SkipPreviousMode) && (TrapFrame->PreviousPreviousMode != -1)) { - DbgPrint("Exiting a trap witout restoring previous mode, yet previous mode seems valid: %lx", TrapFrame->PreviousPreviousMode); - while (TRUE); + DbgPrint("Exiting a trap witout restoring previous mode, yet previous mode seems valid: %lx\n", TrapFrame->PreviousPreviousMode); + __debugbreak(); } } @@ -137,14 +151,14 @@ KiExitSystemCallDebugChecks(IN ULONG SystemCall, KIRQL OldIrql; /* Check if this was a user call */ - if (KiUserMode(TrapFrame)) + if (KiUserTrap(TrapFrame)) { /* Make sure we are not returning with elevated IRQL */ OldIrql = KeGetCurrentIrql(); if (OldIrql != PASSIVE_LEVEL) { /* Forcibly put us in a sane state */ - KeGetPcr()->CurrentIrql = PASSIVE_LEVEL; + KeGetPcr()->Irql = PASSIVE_LEVEL; _disable(); /* Fail */ @@ -154,7 +168,7 @@ KiExitSystemCallDebugChecks(IN ULONG SystemCall, 0, 0); } - +#if 0 /* Make sure we're not attached and that APCs are not disabled */ if ((KeGetCurrentThread()->ApcStateIndex != CurrentApcEnvironment) || (KeGetCurrentThread()->CombinedApcDisable != 0)) @@ -166,6 +180,7 @@ KiExitSystemCallDebugChecks(IN ULONG SystemCall, KeGetCurrentThread()->CombinedApcDisable, 0); } +#endif } } #else @@ -174,340 +189,29 @@ KiExitSystemCallDebugChecks(IN ULONG SystemCall, #define KiExitSystemCallDebugChecks(x, y) #endif -// -// Helper Code -// -BOOLEAN -FORCEINLINE -KiUserTrap(IN PKTRAP_FRAME TrapFrame) -{ - /* Anything else but Ring 0 is Ring 3 */ - return (TrapFrame->SegCs & MODE_MASK); -} - -// -// "BOP" code used by VDM and V8086 Mode -// -VOID -FORCEINLINE -KiIssueBop(VOID) -{ - /* Invalid instruction that an invalid opcode handler must trap and handle */ - asm volatile(".byte 0xC4\n.byte 0xC4\n"); -} - -VOID -FORCEINLINE -KiUserSystemCall(IN PKTRAP_FRAME TrapFrame) -{ - /* - * Kernel call or user call? - * - * This decision is made in inlined assembly because we need to patch - * the relative offset of the user-mode jump to point to the SYSEXIT - * routine if the CPU supports it. The only way to guarantee that a - * relative jnz/jz instruction is generated is to force it with the - * inline assembler. - */ - asm volatile - ( - "test $1, %0\n" /* MODE_MASK */ - ".globl _KiSystemCallExitBranch\n_KiSystemCallExitBranch:\n" - "jnz _KiSystemCallExit\n" - : - : "r"(TrapFrame->SegCs) - ); -} - -// -// Generates an Exit Epilog Stub for the given name -// -#define KI_FUNCTION_CALL 0x1 -#define KI_EDITED_FRAME 0x2 -#define KI_DIRECT_EXIT 0x4 -#define KI_FAST_SYSTEM_CALL_EXIT 0x8 -#define KI_SYSTEM_CALL_EXIT 0x10 -#define KI_SYSTEM_CALL_JUMP 0x20 -#define KiTrapExitStub(x, y) VOID FORCEINLINE DECLSPEC_NORETURN x(IN PKTRAP_FRAME TrapFrame) { KiTrapExit(TrapFrame, y); UNREACHABLE; } -#define KiTrapExitStub2(x, y) VOID FORCEINLINE x(IN PKTRAP_FRAME TrapFrame) { KiTrapExit(TrapFrame, y); } - -// -// How volatiles will be restored -// -#define KI_EAX_NO_VOLATILES 0x0 -#define KI_EAX_ONLY 0x1 -#define KI_ALL_VOLATILES 0x2 - -// -// Exit mechanism to use -// -#define KI_EXIT_IRET 0x0 -#define KI_EXIT_SYSEXIT 0x1 -#define KI_EXIT_JMP 0x2 -#define KI_EXIT_RET 0x3 - -// -// Master Trap Epilog -// -VOID -FORCEINLINE -KiTrapExit(IN PKTRAP_FRAME TrapFrame, - IN ULONG Flags) -{ - ULONG FrameSize = FIELD_OFFSET(KTRAP_FRAME, Eip); - ULONG ExitMechanism = KI_EXIT_IRET, Volatiles = KI_ALL_VOLATILES, NonVolatiles = TRUE; - ULONG EcxField = FIELD_OFFSET(KTRAP_FRAME, Ecx), EdxField = FIELD_OFFSET(KTRAP_FRAME, Edx); - - /* System call exit needs a special label */ - if (Flags & KI_SYSTEM_CALL_EXIT) __asm__ __volatile__ - ( - ".globl _KiSystemCallExit\n_KiSystemCallExit:\n" - ); - - /* Start by making the trap frame equal to the stack */ - __asm__ __volatile__ - ( - "movl %0, %%esp\n" - : - : "r"(TrapFrame) - : "%esp" - ); - - /* Check what kind of trap frame this trap requires */ - if (Flags & KI_FUNCTION_CALL) - { - /* These calls have an EIP on the stack they need */ - ExitMechanism = KI_EXIT_RET; - Volatiles = FALSE; - } - else if (Flags & KI_EDITED_FRAME) - { - /* Edited frames store a new ESP in the error code field */ - FrameSize = FIELD_OFFSET(KTRAP_FRAME, ErrCode); - } - else if (Flags & KI_DIRECT_EXIT) - { - /* Exits directly without restoring anything, interrupt frame on stack */ - NonVolatiles = Volatiles = FALSE; - } - else if (Flags & KI_FAST_SYSTEM_CALL_EXIT) - { - /* We have a fake interrupt stack with a ring transition */ - FrameSize = FIELD_OFFSET(KTRAP_FRAME, V86Es); - ExitMechanism = KI_EXIT_SYSEXIT; - - /* SYSEXIT wants EIP in EDX and ESP in ECX */ - EcxField = FIELD_OFFSET(KTRAP_FRAME, HardwareEsp); - EdxField = FIELD_OFFSET(KTRAP_FRAME, Eip); - } - else if (Flags & KI_SYSTEM_CALL_EXIT) - { - /* Only restore EAX */ - NonVolatiles = KI_EAX_ONLY; - } - else if (Flags & KI_SYSTEM_CALL_JUMP) - { - /* We have a fake interrupt stack with no ring transition */ - FrameSize = FIELD_OFFSET(KTRAP_FRAME, HardwareEsp); - NonVolatiles = KI_EAX_ONLY; - ExitMechanism = KI_EXIT_JMP; - } - - /* Restore the non volatiles */ - if (NonVolatiles) __asm__ __volatile__ - ( - "movl %c[b](%%esp), %%ebx\n" - "movl %c[s](%%esp), %%esi\n" - "movl %c[i](%%esp), %%edi\n" - "movl %c[p](%%esp), %%ebp\n" - : - : [b] "i"(FIELD_OFFSET(KTRAP_FRAME, Ebx)), - [s] "i"(FIELD_OFFSET(KTRAP_FRAME, Esi)), - [i] "i"(FIELD_OFFSET(KTRAP_FRAME, Edi)), - [p] "i"(FIELD_OFFSET(KTRAP_FRAME, Ebp)) - : "%esp" - ); - - /* Restore EAX if volatiles must be restored */ - if (Volatiles) __asm__ __volatile__ - ( - "movl %c[a](%%esp), %%eax\n":: [a] "i"(FIELD_OFFSET(KTRAP_FRAME, Eax)) : "%esp" - ); - - /* Restore the other volatiles if needed */ - if (Volatiles == KI_ALL_VOLATILES) __asm__ __volatile__ - ( - "movl %c[c](%%esp), %%ecx\n" - "movl %c[d](%%esp), %%edx\n" - : - : [c] "i"(EcxField), - [d] "i"(EdxField) - : "%esp" - ); - - /* Ring 0 system calls jump back to EDX */ - if (Flags & KI_SYSTEM_CALL_JUMP) __asm__ __volatile__ - ( - "movl %c[d](%%esp), %%edx\n":: [d] "i"(FIELD_OFFSET(KTRAP_FRAME, Eip)) : "%esp" - ); - - /* Now destroy the trap frame on the stack */ - __asm__ __volatile__ ("addl $%c[e],%%esp\n":: [e] "i"(FrameSize) : "%esp"); - - /* Edited traps need to change to a new ESP */ - if (Flags & KI_EDITED_FRAME) __asm__ __volatile__ ("movl (%%esp), %%esp\n":::"%esp"); - - /* Check the exit mechanism and apply it */ - if (ExitMechanism == KI_EXIT_RET) __asm__ __volatile__("ret\n"::: "%esp"); - else if (ExitMechanism == KI_EXIT_IRET) __asm__ __volatile__("iret\n"::: "%esp"); - else if (ExitMechanism == KI_EXIT_JMP) __asm__ __volatile__("jmp *%%edx\n.globl _KiSystemCallExit2\n_KiSystemCallExit2:\n"::: "%esp"); - else if (ExitMechanism == KI_EXIT_SYSEXIT) __asm__ __volatile__("sti\nsysexit\n"::: "%esp"); -} - -// -// All the specific trap epilog stubs -// -KiTrapExitStub (KiTrapReturn, 0); -KiTrapExitStub (KiDirectTrapReturn, KI_DIRECT_EXIT); -KiTrapExitStub (KiCallReturn, KI_FUNCTION_CALL); -KiTrapExitStub (KiEditedTrapReturn, KI_EDITED_FRAME); -KiTrapExitStub2(KiSystemCallReturn, KI_SYSTEM_CALL_JUMP); -KiTrapExitStub (KiSystemCallSysExitReturn, KI_FAST_SYSTEM_CALL_EXIT); -KiTrapExitStub (KiSystemCallTrapReturn, KI_SYSTEM_CALL_EXIT); - // // Generic Exit Routine // +VOID FASTCALL DECLSPEC_NORETURN KiSystemCallReturn(IN PKTRAP_FRAME TrapFrame); +VOID FASTCALL DECLSPEC_NORETURN KiSystemCallSysExitReturn(IN PKTRAP_FRAME TrapFrame); +VOID FASTCALL DECLSPEC_NORETURN KiSystemCallTrapReturn(IN PKTRAP_FRAME TrapFrame); +VOID FASTCALL DECLSPEC_NORETURN KiEditedTrapReturn(IN PKTRAP_FRAME TrapFrame); +VOID FASTCALL DECLSPEC_NORETURN KiTrapReturn(IN PKTRAP_FRAME TrapFrame); +VOID FASTCALL DECLSPEC_NORETURN KiTrapReturnNoSegments(IN PKTRAP_FRAME TrapFrame); + +typedef VOID -FORCEINLINE -DECLSPEC_NORETURN -KiExitTrap(IN PKTRAP_FRAME TrapFrame, - IN UCHAR Skip) -{ - KTRAP_EXIT_SKIP_BITS SkipBits = { .Bits = Skip }; - PULONG ReturnStack; - - /* Debugging checks */ - KiExitTrapDebugChecks(TrapFrame, SkipBits); +(FASTCALL +*PFAST_SYSTEM_CALL_EXIT)(IN PKTRAP_FRAME TrapFrame) DECLSPEC_NORETURN; - /* Restore the SEH handler chain */ - KeGetPcr()->NtTib.ExceptionList = TrapFrame->ExceptionList; - - /* Check if the previous mode must be restored */ - if (__builtin_expect(!SkipBits.SkipPreviousMode, 0)) /* More INTS than SYSCALLs */ - { - /* Restore it */ - KeGetCurrentThread()->PreviousMode = TrapFrame->PreviousPreviousMode; - } - - /* Check if there are active debug registers */ - if (__builtin_expect(TrapFrame->Dr7 & ~DR7_RESERVED_MASK, 0)) - { - /* Not handled yet */ - DbgPrint("Need Hardware Breakpoint Support!\n"); - DbgBreakPoint(); - while (TRUE); - } - - /* Check if this was a V8086 trap */ - if (__builtin_expect(TrapFrame->EFlags & EFLAGS_V86_MASK, 0)) KiTrapReturn(TrapFrame); - - /* Check if the trap frame was edited */ - if (__builtin_expect(!(TrapFrame->SegCs & FRAME_EDITED), 0)) - { - /* - * An edited trap frame happens when we need to modify CS and/or ESP but - * don't actually have a ring transition. This happens when a kernelmode - * caller wants to perform an NtContinue to another kernel address, such - * as in the case of SEH (basically, a longjmp), or to a user address. - * - * Therefore, the CPU never saved CS/ESP on the stack because we did not - * get a trap frame due to a ring transition (there was no interrupt). - * Even if we didn't want to restore CS to a new value, a problem occurs - * due to the fact a normal RET would not work if we restored ESP since - * RET would then try to read the result off the stack. - * - * The NT kernel solves this by adding 12 bytes of stack to the exiting - * trap frame, in which EFLAGS, CS, and EIP are stored, and then saving - * the ESP that's being requested into the ErrorCode field. It will then - * exit with an IRET. This fixes both issues, because it gives the stack - * some space where to hold the return address and then end up with the - * wanted stack, and it uses IRET which allows a new CS to be inputted. - * - */ - - /* Set CS that is requested */ - TrapFrame->SegCs = TrapFrame->TempSegCs; - - /* First make space on requested stack */ - ReturnStack = (PULONG)(TrapFrame->TempEsp - 12); - TrapFrame->ErrCode = (ULONG_PTR)ReturnStack; - - /* Now copy IRET frame */ - ReturnStack[0] = TrapFrame->Eip; - ReturnStack[1] = TrapFrame->SegCs; - ReturnStack[2] = TrapFrame->EFlags; - - /* Do special edited return */ - KiEditedTrapReturn(TrapFrame); - } - - /* Check if this is a user trap */ - if (__builtin_expect(KiUserTrap(TrapFrame), 1)) /* Ring 3 is where we spend time */ - { - /* Check if segments should be restored */ - if (!SkipBits.SkipSegments) - { - /* Restore segments */ - Ke386SetGs(TrapFrame->SegGs); - Ke386SetEs(TrapFrame->SegEs); - Ke386SetDs(TrapFrame->SegDs); - Ke386SetFs(TrapFrame->SegFs); - } - - /* Always restore FS since it goes from KPCR to TEB */ - Ke386SetFs(TrapFrame->SegFs); - } - - /* Check for system call -- a system call skips volatiles! */ - if (__builtin_expect(SkipBits.SkipVolatiles, 0)) /* More INTs than SYSCALLs */ - { - /* User or kernel call? */ - KiUserSystemCall(TrapFrame); - - /* Restore EFLags */ - __writeeflags(TrapFrame->EFlags); - - /* Call is kernel, so do a jump back since this wasn't a real INT */ - KiSystemCallReturn(TrapFrame); - - /* If we got here, this is SYSEXIT: are we stepping code? */ - if (!(TrapFrame->EFlags & EFLAGS_TF)) - { - /* Restore user FS */ - Ke386SetFs(KGDT_R3_TEB | RPL_MASK); - - /* Remove interrupt flag */ - TrapFrame->EFlags &= ~EFLAGS_INTERRUPT_MASK; - __writeeflags(TrapFrame->EFlags); - - /* Exit through SYSEXIT */ - KiSystemCallSysExitReturn(TrapFrame); - } - - /* Exit through IRETD, either due to debugging or due to lack of SYSEXIT */ - KiSystemCallTrapReturn(TrapFrame); - } - - /* Return from interrupt */ - KiTrapReturn(TrapFrame); -} +extern PFAST_SYSTEM_CALL_EXIT KiFastCallExitHandler; // // Virtual 8086 Mode Optimized Trap Exit // VOID FORCEINLINE +DECLSPEC_NORETURN KiExitV86Trap(IN PKTRAP_FRAME TrapFrame) { PKTHREAD Thread; @@ -517,6 +221,9 @@ KiExitV86Trap(IN PKTRAP_FRAME TrapFrame) Thread = KeGetCurrentThread(); while (TRUE) { + /* Return if this isn't V86 mode anymore */ + if (!(TrapFrame->EFlags & EFLAGS_V86_MASK)) KiEoiHelper(TrapFrame);; + /* Turn off the alerted state for kernel mode */ Thread->Alerted[KernelMode] = FALSE; @@ -533,9 +240,6 @@ KiExitV86Trap(IN PKTRAP_FRAME TrapFrame) /* Restore IRQL and disable interrupts once again */ KfLowerIrql(OldIrql); _disable(); - - /* Return if this isn't V86 mode anymore */ - if (__builtin_expect(TrapFrame->EFlags & EFLAGS_V86_MASK, 0)) return; } /* If we got here, we're still in a valid V8086 context, so quit it */ @@ -547,7 +251,7 @@ KiExitV86Trap(IN PKTRAP_FRAME TrapFrame) } /* Return from interrupt */ - KiTrapReturn(TrapFrame); + KiTrapReturnNoSegments(TrapFrame); } // diff --git a/ntoskrnl/io/iomgr/driver.c b/ntoskrnl/io/iomgr/driver.c index c9925d5eb28..ef1b78969fb 100644 --- a/ntoskrnl/io/iomgr/driver.c +++ b/ntoskrnl/io/iomgr/driver.c @@ -149,6 +149,39 @@ IopGetDriverObject( return STATUS_SUCCESS; } +/* + * RETURNS + * TRUE if String2 contains String1 as a suffix. + */ +BOOLEAN +NTAPI +IopSuffixUnicodeString( + IN PCUNICODE_STRING String1, + IN PCUNICODE_STRING String2) +{ + PWCHAR pc1; + PWCHAR pc2; + ULONG Length; + + if (String2->Length < String1->Length) + return FALSE; + + Length = String1->Length / 2; + pc1 = String1->Buffer; + pc2 = &String2->Buffer[String2->Length / sizeof(WCHAR) - Length]; + + if (pc1 && pc2) + { + while (Length--) + { + if( *pc1++ != *pc2++ ) + return FALSE; + } + return TRUE; + } + return FALSE; +} + /* * IopDisplayLoadingMessage * @@ -158,35 +191,19 @@ IopGetDriverObject( VOID FASTCALL INIT_FUNCTION -IopDisplayLoadingMessage(PVOID ServiceName, - BOOLEAN Unicode) +IopDisplayLoadingMessage(PUNICODE_STRING ServiceName) { CHAR TextBuffer[256]; - PCHAR Extra = ".sys"; + UNICODE_STRING DotSys = RTL_CONSTANT_STRING(L".SYS"); if (ExpInTextModeSetup) return; - if (Unicode) - { - if (wcsstr(_wcsupr(ServiceName), L".SYS")) Extra = ""; - sprintf(TextBuffer, - "%s%s%s\\%S%s\n", - KeLoaderBlock->ArcBootDeviceName, - KeLoaderBlock->NtBootPathName, - "System32\\Drivers", - (PWCHAR)ServiceName, - Extra); - } - else - { - if (strstr(_strupr(ServiceName), ".SYS")) Extra = ""; - sprintf(TextBuffer, - "%s%s%s\\%s%s\n", - KeLoaderBlock->ArcBootDeviceName, - KeLoaderBlock->NtBootPathName, - "System32\\Drivers", - (PCHAR)ServiceName, - Extra); - } + RtlUpcaseUnicodeString(ServiceName, ServiceName, FALSE); + snprintf(TextBuffer, sizeof(TextBuffer), + "%s%sSystem32\\Drivers\\%wZ%s\n", + KeLoaderBlock->ArcBootDeviceName, + KeLoaderBlock->NtBootPathName, + ServiceName, + IopSuffixUnicodeString(&DotSys, ServiceName) ? "" : ".SYS"); HalDisplayString(TextBuffer); } @@ -788,7 +805,7 @@ IopInitializeBuiltinDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry) /* * Display 'Loading XXX...' message */ - IopDisplayLoadingMessage(ModuleName->Buffer, TRUE); + IopDisplayLoadingMessage(ModuleName); InbvIndicateProgress(); /* diff --git a/ntoskrnl/io/iomgr/drvrlist.c b/ntoskrnl/io/iomgr/drvrlist.c index 42b69c6e2bd..ecc9980db46 100644 --- a/ntoskrnl/io/iomgr/drvrlist.c +++ b/ntoskrnl/io/iomgr/drvrlist.c @@ -48,8 +48,7 @@ extern BOOLEAN NoGuiBoot; VOID FASTCALL INIT_FUNCTION -IopDisplayLoadingMessage(PVOID ServiceName, - BOOLEAN Unicode); +IopDisplayLoadingMessage(PUNICODE_STRING ServiceName); /* PRIVATE FUNCTIONS **********************************************************/ @@ -416,7 +415,7 @@ IopLoadDriver(PSERVICE Service) { NTSTATUS Status = STATUS_UNSUCCESSFUL; - IopDisplayLoadingMessage(Service->ServiceName.Buffer, TRUE); + IopDisplayLoadingMessage(&Service->ServiceName); Status = ZwLoadDriver(&Service->RegistryPath); IopBootLog(&Service->ImagePath, NT_SUCCESS(Status) ? TRUE : FALSE); if (!NT_SUCCESS(Status)) diff --git a/ntoskrnl/io/pnpmgr/pnpmgr.c b/ntoskrnl/io/pnpmgr/pnpmgr.c index 890fd60d12a..e6346378566 100644 --- a/ntoskrnl/io/pnpmgr/pnpmgr.c +++ b/ntoskrnl/io/pnpmgr/pnpmgr.c @@ -13,7 +13,7 @@ #define NDEBUG #include -//#define ENABLE_ACPI +#define ENABLE_ACPI /* GLOBALS *******************************************************************/ @@ -1893,7 +1893,7 @@ IopActionConfigureChildServices(PDEVICE_NODE DeviceNode, RtlInitUnicodeString(&ClassGUID, NULL); QueryTable[0].Name = L"Service"; - QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; + QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT; QueryTable[0].EntryContext = Service; QueryTable[1].Name = L"ClassGUID"; diff --git a/ntoskrnl/ke/i386/cpu.c b/ntoskrnl/ke/i386/cpu.c index 21d49c90123..e05a8960470 100644 --- a/ntoskrnl/ke/i386/cpu.c +++ b/ntoskrnl/ke/i386/cpu.c @@ -995,56 +995,6 @@ KiLoadFastSyscallMachineSpecificRegisters(IN ULONG_PTR Context) return 0; } -VOID -NTAPI -KiDisableFastSyscallReturn(VOID) -{ - /* Was it applied? */ - if (KiSystemCallExitAdjusted) - { - /* Restore the original value */ - KiSystemCallExitBranch[1] = KiSystemCallExitBranch[1] - KiSystemCallExitAdjusted; - - /* It's not adjusted anymore */ - KiSystemCallExitAdjusted = FALSE; - } -} - -VOID -NTAPI -KiEnableFastSyscallReturn(VOID) -{ - /* Check if the patch has already been done */ - if ((KiSystemCallExitAdjusted == KiSystemCallExitAdjust) && - (KiFastCallCopyDoneOnce)) - { - return; - } - - /* Make sure the offset is within the distance of a Jxx SHORT */ - if ((KiSystemCallExitBranch[1] - KiSystemCallExitAdjust) < 0x80) - { - /* Remove any existing code patch */ - KiDisableFastSyscallReturn(); - - /* We should have a JNZ there */ - ASSERT(KiSystemCallExitBranch[0] == 0x75); - - /* Do the patch */ - KiSystemCallExitAdjusted = KiSystemCallExitAdjust; - KiSystemCallExitBranch[1] -= KiSystemCallExitAdjusted; - - /* Remember that we've done it */ - KiFastCallCopyDoneOnce = TRUE; - } - else - { - /* This shouldn't happen unless we've messed the macros up */ - DPRINT1("Your compiled kernel is broken!\n"); - DbgBreakPoint(); - } -} - VOID NTAPI KiRestoreFastSyscallReturnState(VOID) @@ -1055,28 +1005,27 @@ KiRestoreFastSyscallReturnState(VOID) /* Check if it has been disabled */ if (!KiFastSystemCallDisable) { - /* KiSystemCallExit2 should come BEFORE KiSystemCallExit */ - ASSERT(KiSystemCallExit2 < KiSystemCallExit); - - /* It's enabled, so we'll have to do a code patch */ - KiSystemCallExitAdjust = KiSystemCallExit - KiSystemCallExit2; + /* Do an IPI to enable it */ + KeIpiGenericCall(KiLoadFastSyscallMachineSpecificRegisters, 0); + + /* It's enabled, so use the proper exit stub */ + KiFastCallExitHandler = KiSystemCallSysExitReturn; + DPRINT1("Support for SYSENTER detected.\n"); } else { /* Disable fast system call */ KeFeatureBits &= ~KF_FAST_SYSCALL; + KiFastCallExitHandler = KiSystemCallTrapReturn; + DPRINT1("Support for SYSENTER disabled.\n"); } } - - /* Now check if all CPUs support fast system call, and the registry allows it */ - if (KeFeatureBits & KF_FAST_SYSCALL) + else { - /* Do an IPI to enable it */ - KeIpiGenericCall(KiLoadFastSyscallMachineSpecificRegisters, 0); + /* Use the IRET handler */ + KiFastCallExitHandler = KiSystemCallTrapReturn; + DPRINT1("No support for SYSENTER detected.\n"); } - - /* Perform the code patch that is required */ - KiEnableFastSyscallReturn(); } ULONG_PTR diff --git a/ntoskrnl/ke/i386/trap.s b/ntoskrnl/ke/i386/trap.s index 5f24877eeac..adfcd322dd9 100644 --- a/ntoskrnl/ke/i386/trap.s +++ b/ntoskrnl/ke/i386/trap.s @@ -124,13 +124,13 @@ EXTERN @KiSystemServiceHandler@8:PROC PUBLIC _KiSystemService _KiSystemService: KiEnterTrap (KI_PUSH_FAKE_ERROR_CODE OR KI_NONVOLATILES_ONLY OR KI_DONT_SAVE_SEGS) - jmp @KiSystemServiceHandler@8 + KiCallHandler @KiSystemServiceHandler@8 EXTERN @KiFastCallEntryHandler@8:PROC PUBLIC _KiFastCallEntry _KiFastCallEntry: KiEnterTrap (KI_FAST_SYSTEM_CALL OR KI_NONVOLATILES_ONLY OR KI_DONT_SAVE_SEGS) - jmp @KiFastCallEntryHandler@8 + KiCallHandler @KiFastCallEntryHandler@8 PUBLIC _KiStartUnexpectedRange@0 _KiStartUnexpectedRange@0: @@ -143,4 +143,15 @@ PUBLIC _KiEndUnexpectedRange@0 _KiEndUnexpectedRange@0: jmp _KiUnexpectedInterruptTail + +/* EXIT CODE *****************************************************************/ + +KiTrapExitStub KiSystemCallReturn, (KI_RESTORE_EAX OR KI_RESTORE_EFLAGS OR KI_EXIT_JMP) +KiTrapExitStub KiSystemCallSysExitReturn, (KI_RESTORE_EAX OR KI_RESTORE_FS OR KI_RESTORE_EFLAGS OR KI_EXIT_SYSCALL) +KiTrapExitStub KiSystemCallTrapReturn, (KI_RESTORE_EAX OR KI_RESTORE_FS OR KI_EXIT_IRET) + +KiTrapExitStub KiEditedTrapReturn, (KI_RESTORE_VOLATILES OR KI_RESTORE_EFLAGS OR KI_EDITED_FRAME OR KI_EXIT_RET) +KiTrapExitStub KiTrapReturn, (KI_RESTORE_VOLATILES OR KI_RESTORE_SEGMENTS OR KI_EXIT_IRET) +KiTrapExitStub KiTrapReturnNoSegments, (KI_RESTORE_VOLATILES OR KI_EXIT_IRET) + END diff --git a/ntoskrnl/ke/i386/traphdlr.c b/ntoskrnl/ke/i386/traphdlr.c index f85eb7f878c..f9a954ec298 100644 --- a/ntoskrnl/ke/i386/traphdlr.c +++ b/ntoskrnl/ke/i386/traphdlr.c @@ -45,6 +45,11 @@ UCHAR KiTrapIoTable[] = 0x6F, /* OUTS */ }; +PFAST_SYSTEM_CALL_EXIT KiFastCallExitHandler; + + +/* TRAP EXIT CODE *************************************************************/ + BOOLEAN FORCEINLINE KiVdmTrap(IN PKTRAP_FRAME TrapFrame) @@ -62,12 +67,18 @@ KiV86Trap(IN PKTRAP_FRAME TrapFrame) return ((TrapFrame->EFlags & EFLAGS_V86_MASK) != 0); } -/* TRAP EXIT CODE *************************************************************/ +BOOLEAN +FORCEINLINE +KiIsFrameEdited(IN PKTRAP_FRAME TrapFrame) +{ + /* An edited frame changes esp. It is marked by clearing the bits + defined by FRAME_EDITED in the SegCs field of the trap frame */ + return ((TrapFrame->SegCs & FRAME_EDITED) == 0); +} VOID -FASTCALL -DECLSPEC_NORETURN -KiEoiHelper(IN PKTRAP_FRAME TrapFrame) +FORCEINLINE +KiCommonExit(IN PKTRAP_FRAME TrapFrame, const ULONG Flags) { /* Disable interrupts until we return */ _disable(); @@ -75,8 +86,41 @@ KiEoiHelper(IN PKTRAP_FRAME TrapFrame) /* Check for APC delivery */ KiCheckForApcDelivery(TrapFrame); - /* Now exit the trap for real */ - KiExitTrap(TrapFrame, KTE_SKIP_PM_BIT); + /* Debugging checks */ + KiExitTrapDebugChecks(TrapFrame, Flags); + + /* Restore the SEH handler chain */ + KeGetPcr()->NtTib.ExceptionList = TrapFrame->ExceptionList; + + /* Check if there are active debug registers */ + if (__builtin_expect(TrapFrame->Dr7 & ~DR7_RESERVED_MASK, 0)) + { + /* Not handled yet */ + DbgPrint("Need Hardware Breakpoint Support!\n"); + DbgBreakPoint(); + while (TRUE); + } +} + +VOID +FASTCALL +DECLSPEC_NORETURN +KiEoiHelper(IN PKTRAP_FRAME TrapFrame) +{ + /* Common trap exit code */ + KiCommonExit(TrapFrame, 0); + + /* Check if this was a V8086 trap */ + if (TrapFrame->EFlags & EFLAGS_V86_MASK) KiTrapReturnNoSegments(TrapFrame); + + /* Check for user mode exit */ + if (TrapFrame->SegCs & MODE_MASK) KiTrapReturn(TrapFrame); + + /* Check for edited frame */ + if (KiIsFrameEdited(TrapFrame)) KiEditedTrapReturn(TrapFrame); + + /* Exit the trap to kernel mode */ + KiTrapReturnNoSegments(TrapFrame); } VOID @@ -85,17 +129,36 @@ DECLSPEC_NORETURN KiServiceExit(IN PKTRAP_FRAME TrapFrame, IN NTSTATUS Status) { - /* Disable interrupts until we return */ - _disable(); - - /* Check for APC delivery */ - KiCheckForApcDelivery(TrapFrame); + ASSERT((TrapFrame->EFlags & EFLAGS_V86_MASK) == 0); + ASSERT(!KiIsFrameEdited(TrapFrame)); /* Copy the status into EAX */ TrapFrame->Eax = Status; - /* Now exit the trap for real */ - KiExitTrap(TrapFrame, KTE_SKIP_SEG_BIT | KTE_SKIP_VOL_BIT); + /* Common trap exit code */ + KiCommonExit(TrapFrame, 0); + + /* Restore previous mode */ + KeGetCurrentThread()->PreviousMode = TrapFrame->PreviousPreviousMode; + + /* Check for user mode exit */ + if (TrapFrame->SegCs & MODE_MASK) + { + /* Check if we were single stepping */ + if (TrapFrame->EFlags & EFLAGS_TF) + { + /* Must use the IRET handler */ + KiSystemCallTrapReturn(TrapFrame); + } + else + { + /* We can use the sysexit handler */ + KiFastCallExitHandler(TrapFrame); + } + } + + /* Exit to kernel mode */ + KiSystemCallReturn(TrapFrame); } VOID @@ -103,16 +166,26 @@ FASTCALL DECLSPEC_NORETURN KiServiceExit2(IN PKTRAP_FRAME TrapFrame) { - /* Disable interrupts until we return */ - _disable(); + /* Common trap exit code */ + KiCommonExit(TrapFrame, 0); - /* Check for APC delivery */ - KiCheckForApcDelivery(TrapFrame); + /* Restore previous mode */ + KeGetCurrentThread()->PreviousMode = TrapFrame->PreviousPreviousMode; - /* Now exit the trap for real */ - KiExitTrap(TrapFrame, 0); + /* Check if this was a V8086 trap */ + if (TrapFrame->EFlags & EFLAGS_V86_MASK) KiTrapReturnNoSegments(TrapFrame); + + /* Check for user mode exit */ + if (TrapFrame->SegCs & MODE_MASK) KiTrapReturn(TrapFrame); + + /* Check for edited frame */ + if (KiIsFrameEdited(TrapFrame)) KiEditedTrapReturn(TrapFrame); + + /* Exit the trap to kernel mode */ + KiTrapReturnNoSegments(TrapFrame); } + /* TRAP HANDLERS **************************************************************/ VOID @@ -582,10 +655,7 @@ KiTrap06Handler(IN PKTRAP_FRAME TrapFrame) _disable(); /* Do a quick V86 exit if possible */ - if (__builtin_expect(TrapFrame->EFlags & EFLAGS_V86_MASK, 1)) KiExitV86Trap(TrapFrame); - - /* Exit trap the slow way */ - KiEoiHelper(TrapFrame); + KiExitV86Trap(TrapFrame); } /* Save trap frame */ @@ -842,10 +912,7 @@ KiTrap0DHandler(IN PKTRAP_FRAME TrapFrame) _disable(); /* Do a quick V86 exit if possible */ - if (__builtin_expect(TrapFrame->EFlags & EFLAGS_V86_MASK, 1)) KiExitV86Trap(TrapFrame); - - /* Exit trap the slow way */ - KiEoiHelper(TrapFrame); + KiExitV86Trap(TrapFrame); } /* Save trap frame */ @@ -909,7 +976,7 @@ KiTrap0DHandler(IN PKTRAP_FRAME TrapFrame) (((Instructions[i + 2] & 0x38) == 0x10) || // LLDT (Instructions[i + 2] == 0x18))) || // LTR ((Instructions[i + 1] == 0x01) && // LGDT or LIDT or LMSW - (((Instructions[i + 2] & 0x38) == 0x10) || // LLGT + (((Instructions[i + 2] & 0x38) == 0x10) || // LGDT (Instructions[i + 2] == 0x18) || // LIDT (Instructions[i + 2] == 0x30))) || // LMSW (Instructions[i + 1] == 0x08) || // INVD @@ -921,6 +988,7 @@ KiTrap0DHandler(IN PKTRAP_FRAME TrapFrame) (Instructions[i + 1] == 0x24) || // MOV YYY, DR (Instructions[i + 1] == 0x30) || // WRMSR (Instructions[i + 1] == 0x33)) // RDPMC + // INVLPG, INVLPGA, SYSRET { /* These are all privileged */ Privileged = TRUE; @@ -993,7 +1061,7 @@ KiTrap0DHandler(IN PKTRAP_FRAME TrapFrame) * a POP , which could cause an invalid segment if someone had messed * with the segment values. * - * Another case is a bogus SS, which would hit a GPF when doing the ired. + * Another case is a bogus SS, which would hit a GPF when doing the iret. * This could only be done through a buggy or malicious driver, or perhaps * the kernel debugger. * @@ -1067,9 +1135,14 @@ KiTrap0DHandler(IN PKTRAP_FRAME TrapFrame) /* Fix it */ TrapFrame->SegEs = (KGDT_R3_DATA | RPL_MASK); } - - /* Do a direct trap exit: restore volatiles only */ - KiExitTrap(TrapFrame, KTE_SKIP_PM_BIT | KTE_SKIP_SEG_BIT); + else + { + /* Whatever it is, we can't handle it */ + KiSystemFatalException(EXCEPTION_GP_FAULT, TrapFrame); + } + + /* Return to where we came from */ + KiTrapReturn(TrapFrame); } VOID @@ -1377,55 +1450,89 @@ KiDebugServiceHandler(IN PKTRAP_FRAME TrapFrame) } VOID -FASTCALL +FORCEINLINE DECLSPEC_NORETURN -KiSystemCall(IN ULONG SystemCallNumber, +KiSystemCall(IN PKTRAP_FRAME TrapFrame, IN PVOID Arguments) { PKTHREAD Thread; - PKTRAP_FRAME TrapFrame; PKSERVICE_TABLE_DESCRIPTOR DescriptorTable; ULONG Id, Offset, StackBytes, Result; PVOID Handler; + ULONG SystemCallNumber = TrapFrame->Eax; - /* Loop because we might need to try this twice in case of a GUI call */ - while (TRUE) + /* Get the current thread */ + Thread = KeGetCurrentThread(); + + /* Set debug header */ + KiFillTrapFrameDebug(TrapFrame); + + /* Chain trap frames */ + TrapFrame->Edx = (ULONG_PTR)Thread->TrapFrame; + + /* No error code */ + TrapFrame->ErrCode = 0; + + /* Save previous mode */ + TrapFrame->PreviousPreviousMode = Thread->PreviousMode; + + /* Save the SEH chain and terminate it for now */ + TrapFrame->ExceptionList = KeGetPcr()->NtTib.ExceptionList; + KeGetPcr()->NtTib.ExceptionList = EXCEPTION_CHAIN_END; + + /* Clear DR7 and check for debugging */ + TrapFrame->Dr7 = 0; + if (__builtin_expect(Thread->DispatcherHeader.DebugActive & 0xFF, 0)) { - /* Decode the system call number */ - Offset = (SystemCallNumber >> SERVICE_TABLE_SHIFT) & SERVICE_TABLE_MASK; - Id = SystemCallNumber & SERVICE_NUMBER_MASK; + UNIMPLEMENTED; + while (TRUE); + } + + /* Set thread fields */ + Thread->TrapFrame = TrapFrame; + Thread->PreviousMode = KiUserTrap(TrapFrame); + + /* Enable interrupts */ + _enable(); + + /* Decode the system call number */ + Offset = (SystemCallNumber >> SERVICE_TABLE_SHIFT) & SERVICE_TABLE_MASK; + Id = SystemCallNumber & SERVICE_NUMBER_MASK; - /* Get current thread, trap frame, and descriptor table */ - Thread = KeGetCurrentThread(); - TrapFrame = Thread->TrapFrame; - DescriptorTable = (PVOID)((ULONG_PTR)Thread->ServiceTable + Offset); + /* Get descriptor table */ + DescriptorTable = (PVOID)((ULONG_PTR)Thread->ServiceTable + Offset); - /* Validate the system call number */ - if (__builtin_expect(Id >= DescriptorTable->Limit, 0)) + /* Validate the system call number */ + if (__builtin_expect(Id >= DescriptorTable->Limit, 0)) + { + /* Check if this is a GUI call */ + if (!(Offset & SERVICE_TABLE_TEST)) { - /* Check if this is a GUI call */ - if (__builtin_expect(!(Offset & SERVICE_TABLE_TEST), 0)) - { - /* Fail the call */ - Result = STATUS_INVALID_SYSTEM_SERVICE; - goto ExitCall; - } - - /* Convert us to a GUI thread -- must wrap in ASM to get new EBP */ - Result = KiConvertToGuiThread(); - if (__builtin_expect(!NT_SUCCESS(Result), 0)) - { - /* Figure out how we should fail to the user */ - UNIMPLEMENTED; - while (TRUE); - } - - /* Try the call again */ - continue; + /* Fail the call */ + Result = STATUS_INVALID_SYSTEM_SERVICE; + goto ExitCall; } + + /* Convert us to a GUI thread -- must wrap in ASM to get new EBP */ + Result = KiConvertToGuiThread(); + if (!NT_SUCCESS(Result)) + { + /* Set the last error and fail */ + //SetLastWin32Error(RtlNtStatusToDosError(Result)); + goto ExitCall; + } + + /* Reload trap frame and descriptor table pointer from new stack */ + TrapFrame = *(volatile PVOID*)&Thread->TrapFrame; + DescriptorTable = (PVOID)(*(volatile ULONG_PTR*)&Thread->ServiceTable + Offset); - /* If we made it here, the call is good */ - break; + /* Validate the system call number again */ + if (Id >= DescriptorTable->Limit) + { + /* Fail the call */ + Result = STATUS_INVALID_SYSTEM_SERVICE; + goto ExitCall; + } } /* Check if this is a GUI call */ @@ -1468,45 +1575,13 @@ ExitCall: } VOID -FORCEINLINE +FASTCALL DECLSPEC_NORETURN -KiSystemCallHandler(IN PKTRAP_FRAME TrapFrame, - IN ULONG ServiceNumber, - IN PVOID Arguments, - IN PKTHREAD Thread, - IN KPROCESSOR_MODE PreviousMode, - IN KPROCESSOR_MODE PreviousPreviousMode, - IN USHORT SegFs) +KiSystemServiceHandler(IN PKTRAP_FRAME TrapFrame, + IN PVOID Arguments) { - /* No error code */ - TrapFrame->ErrCode = 0; - - /* Save previous mode and FS segment */ - TrapFrame->PreviousPreviousMode = PreviousPreviousMode; - TrapFrame->SegFs = SegFs; - - /* Save the SEH chain and terminate it for now */ - TrapFrame->ExceptionList = KeGetPcr()->NtTib.ExceptionList; - KeGetPcr()->NtTib.ExceptionList = EXCEPTION_CHAIN_END; - - /* Clear DR7 and check for debugging */ - TrapFrame->Dr7 = 0; - if (__builtin_expect(Thread->DispatcherHeader.DebugActive & 0xFF, 0)) - { - UNIMPLEMENTED; - while (TRUE); - } - - /* Set thread fields */ - Thread->TrapFrame = TrapFrame; - Thread->PreviousMode = PreviousMode; - - /* Set debug header */ - KiFillTrapFrameDebug(TrapFrame); - - /* Enable interrupts and make the call */ - _enable(); - KiSystemCall(ServiceNumber, Arguments); + /* Call the shared handler (inline) */ + KiSystemCall(TrapFrame, Arguments); } VOID @@ -1515,54 +1590,20 @@ DECLSPEC_NORETURN KiFastCallEntryHandler(IN PKTRAP_FRAME TrapFrame, IN PVOID Arguments) { - PKTHREAD Thread; - /* Set up a fake INT Stack and enable interrupts */ TrapFrame->HardwareSegSs = KGDT_R3_DATA | RPL_MASK; TrapFrame->HardwareEsp = (ULONG_PTR)Arguments; TrapFrame->EFlags = __readeflags() | EFLAGS_INTERRUPT_MASK; TrapFrame->SegCs = KGDT_R3_CODE | RPL_MASK; TrapFrame->Eip = SharedUserData->SystemCallReturn; + TrapFrame->SegFs = KGDT_R3_TEB | RPL_MASK; __writeeflags(0x2); - /* Get the current thread */ - Thread = KeGetCurrentThread(); - /* Arguments are actually 2 frames down (because of the double indirection) */ Arguments = (PVOID)(TrapFrame->HardwareEsp + 8); /* Call the shared handler (inline) */ - KiSystemCallHandler(TrapFrame, - TrapFrame->Eax, - Arguments, - Thread, - UserMode, - Thread->PreviousMode, - KGDT_R3_TEB | RPL_MASK); -} - -VOID -FASTCALL -DECLSPEC_NORETURN -KiSystemServiceHandler(IN PKTRAP_FRAME TrapFrame, - IN PVOID Arguments) -{ - PKTHREAD Thread; - - /* Get the current thread */ - Thread = KeGetCurrentThread(); - - /* Chain trap frames */ - TrapFrame->Edx = (ULONG_PTR)Thread->TrapFrame; - - /* Call the shared handler (inline) */ - KiSystemCallHandler(TrapFrame, - TrapFrame->Eax, - Arguments, - Thread, - KiUserTrap(TrapFrame), - Thread->PreviousMode, - TrapFrame->SegFs); + KiSystemCall(TrapFrame, Arguments); } /* diff --git a/subsystems/win32/csrss/csrsrv/init.c b/subsystems/win32/csrss/csrsrv/init.c index c6fa69b42de..51adb2cacca 100644 --- a/subsystems/win32/csrss/csrsrv/init.c +++ b/subsystems/win32/csrss/csrsrv/init.c @@ -622,7 +622,7 @@ CsrpLoadKernelModeDriver (int argc, char ** argv, char ** envp) WCHAR ImagePath [MAX_PATH + 1] = {0}; UNICODE_STRING ModuleName; - wcscpy (ImagePath, L"\\??\\c:\\reactos\\system32\\win32k.sys"); + wcscpy (ImagePath, L"\\SYSTEMROOT\\system32\\win32k.sys"); // wcscat (ImagePath, Data); RtlInitUnicodeString (& ModuleName, ImagePath); Status = NtSetSystemInformation(/* FIXME: SystemLoadAndCallImage */ diff --git a/subsystems/win32/win32k/eng/surface.c b/subsystems/win32/win32k/eng/surface.c index 126347bff98..464e7d0c3c1 100644 --- a/subsystems/win32/win32k/eng/surface.c +++ b/subsystems/win32/win32k/eng/surface.c @@ -613,9 +613,6 @@ SURFMEM_bCreateDib(IN PDEVBITMAPINFO BitmapInfo, /* For topdown, the base address starts with the bits */ pso->pvScan0 = pso->pvBits; pso->lDelta = ScanLine; - - /* Hack for FreeType/Font Rendering, cannot use the Aligned ScanLine */ - if (BitmapInfo->Format == BMF_1BPP) pso->lDelta = BitmapInfo->Width / 8; } else { diff --git a/subsystems/win32/win32k/objects/freetype.c b/subsystems/win32/win32k/objects/freetype.c index bdda9c20cc6..fea0c101ee9 100644 --- a/subsystems/win32/win32k/objects/freetype.c +++ b/subsystems/win32/win32k/objects/freetype.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -81,7 +82,7 @@ typedef struct _FONT_CACHE_ENTRY LIST_ENTRY ListEntry; int GlyphIndex; FT_Face Face; - FT_Glyph Glyph; + FT_BitmapGlyph BitmapGlyph; int Height; } FONT_CACHE_ENTRY, *PFONT_CACHE_ENTRY; static LIST_ENTRY FontCacheListHead; @@ -1349,7 +1350,7 @@ ftGdiGetRasterizerCaps(LPRASTERIZER_STATUS lprs) } -FT_Glyph APIENTRY +FT_BitmapGlyph APIENTRY ftGdiGlyphCacheGet( FT_Face Face, INT GlyphIndex, @@ -1376,10 +1377,10 @@ ftGdiGlyphCacheGet( RemoveEntryList(CurrentEntry); InsertHeadList(&FontCacheListHead, CurrentEntry); - return FontEntry->Glyph; + return FontEntry->BitmapGlyph; } -FT_Glyph APIENTRY +FT_BitmapGlyph APIENTRY ftGdiGlyphCacheSet( FT_Face Face, INT GlyphIndex, @@ -1390,6 +1391,8 @@ ftGdiGlyphCacheSet( FT_Glyph GlyphCopy; INT error; PFONT_CACHE_ENTRY NewEntry; + FT_Bitmap AlignedBitmap; + FT_BitmapGlyph BitmapGlyph; error = FT_Get_Glyph(GlyphSlot, &GlyphCopy); if (error) @@ -1397,6 +1400,7 @@ ftGdiGlyphCacheSet( DPRINT1("Failure caching glyph.\n"); return NULL; }; + error = FT_Glyph_To_Bitmap(&GlyphCopy, RenderMode, 0, 1); if (error) { @@ -1412,22 +1416,34 @@ ftGdiGlyphCacheSet( return NULL; } + BitmapGlyph = (FT_BitmapGlyph)GlyphCopy; + FT_Bitmap_New(&AlignedBitmap); + if(FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4)) + { + DPRINT1("Conversion failed\n"); + FT_Done_Glyph((FT_Glyph)BitmapGlyph); + return NULL; + } + + FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap); + BitmapGlyph->bitmap = AlignedBitmap; + NewEntry->GlyphIndex = GlyphIndex; NewEntry->Face = Face; - NewEntry->Glyph = GlyphCopy; + NewEntry->BitmapGlyph = BitmapGlyph; NewEntry->Height = Height; InsertHeadList(&FontCacheListHead, &NewEntry->ListEntry); if (FontCacheNumEntries++ > MAX_FONT_CACHE) { NewEntry = (PFONT_CACHE_ENTRY)FontCacheListHead.Blink; - FT_Done_Glyph(NewEntry->Glyph); + FT_Done_Glyph((FT_Glyph)NewEntry->BitmapGlyph); RemoveTailList(&FontCacheListHead); ExFreePool(NewEntry); FontCacheNumEntries--; } - return GlyphCopy; + return BitmapGlyph; } @@ -2112,7 +2128,7 @@ TextIntGetTextExtentPoint(PDC dc, PFONTGDI FontGDI; FT_Face face; FT_GlyphSlot glyph; - FT_Glyph realglyph; + FT_BitmapGlyph realglyph; INT error, n, glyph_index, i, previous; ULONGLONG TotalWidth = 0; FT_CharMap charmap, found = NULL; @@ -2208,7 +2224,7 @@ TextIntGetTextExtentPoint(PDC dc, TotalWidth += delta.x; } - TotalWidth += realglyph->advance.x >> 10; + TotalWidth += realglyph->root.advance.x >> 10; if (((TotalWidth + 32) >> 6) <= MaxExtent && NULL != Fit) { @@ -3133,8 +3149,7 @@ GreExtTextOutW( int error, glyph_index, n, i; FT_Face face; FT_GlyphSlot glyph; - FT_Glyph realglyph; - FT_BitmapGlyph realglyph2; + FT_BitmapGlyph realglyph; LONGLONG TextLeft, RealXStart; ULONG TextTop, previous, BackgroundLeft; FT_Bool use_kerning; @@ -3400,7 +3415,7 @@ GreExtTextOutW( TextWidth += delta.x; } - TextWidth += realglyph->advance.x >> 10; + TextWidth += realglyph->root.advance.x >> 10; previous = glyph_index; TempText++; @@ -3475,26 +3490,12 @@ GreExtTextOutW( } DPRINT("TextLeft: %d\n", TextLeft); DPRINT("TextTop: %d\n", TextTop); - - if (realglyph->format == ft_glyph_format_outline) - { - DPRINT1("Should already be done\n"); -// error = FT_Render_Glyph(glyph, RenderMode); - error = FT_Glyph_To_Bitmap(&realglyph, RenderMode, 0, 0); - if (error) - { - DPRINT1("WARNING: Failed to render glyph!\n"); - goto fail2; - } - } - realglyph2 = (FT_BitmapGlyph)realglyph; - - DPRINT("Advance: %d\n", realglyph->advance.x); + DPRINT("Advance: %d\n", realglyph->root.advance.x); if (fuOptions & ETO_OPAQUE) { DestRect.left = BackgroundLeft; - DestRect.right = (TextLeft + (realglyph->advance.x >> 10) + 32) >> 6; + DestRect.right = (TextLeft + (realglyph->root.advance.x >> 10) + 32) >> 6; DestRect.top = TextTop + yoff - ((face->size->metrics.ascender + 32) >> 6); DestRect.bottom = TextTop + yoff + ((32 - face->size->metrics.descender) >> 6); IntEngBitBlt( @@ -3512,31 +3513,25 @@ GreExtTextOutW( BackgroundLeft = DestRect.right; } - DestRect.left = ((TextLeft + 32) >> 6) + realglyph2->left; - DestRect.right = DestRect.left + realglyph2->bitmap.width; - DestRect.top = TextTop + yoff - realglyph2->top; - DestRect.bottom = DestRect.top + realglyph2->bitmap.rows; + DestRect.left = ((TextLeft + 32) >> 6) + realglyph->left; + DestRect.right = DestRect.left + realglyph->bitmap.width; + DestRect.top = TextTop + yoff - realglyph->top; + DestRect.bottom = DestRect.top + realglyph->bitmap.rows; - bitSize.cx = realglyph2->bitmap.width; - bitSize.cy = realglyph2->bitmap.rows; - MaskRect.right = realglyph2->bitmap.width; - MaskRect.bottom = realglyph2->bitmap.rows; + bitSize.cx = realglyph->bitmap.width; + bitSize.cy = realglyph->bitmap.rows; + MaskRect.right = realglyph->bitmap.width; + MaskRect.bottom = realglyph->bitmap.rows; /* * We should create the bitmap out of the loop at the biggest possible * glyph size. Then use memset with 0 to clear it and sourcerect to * limit the work of the transbitblt. - * - * FIXME: DIB bitmaps should have an lDelta which is a multiple of 4. - * Here we pass in the pitch from the FreeType bitmap, which is not - * guaranteed to be a multiple of 4. If it's not, we should expand - * the FreeType bitmap to a temporary bitmap. */ - HSourceGlyph = EngCreateBitmap(bitSize, realglyph2->bitmap.pitch, - (realglyph2->bitmap.pixel_mode == ft_pixel_mode_grays) ? - BMF_8BPP : BMF_1BPP, BMF_TOPDOWN, - realglyph2->bitmap.buffer); + HSourceGlyph = EngCreateBitmap(bitSize, realglyph->bitmap.pitch, + BMF_8BPP, BMF_TOPDOWN, + realglyph->bitmap.buffer); if ( !HSourceGlyph ) { DPRINT1("WARNING: EngLockSurface() failed!\n"); @@ -3590,7 +3585,7 @@ GreExtTextOutW( if (NULL == Dx) { - TextLeft += realglyph->advance.x >> 10; + TextLeft += realglyph->root.advance.x >> 10; DPRINT("new TextLeft: %d\n", TextLeft); } else