Wine-devel
Threads by month
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
November 2018
- 75 participants
- 771 discussions
23 Nov '18
Signed-off-by: Hans Leidekker <hans(a)codeweavers.com>
---
dlls/winhttp/request.c | 12 ++++++------
dlls/winhttp/session.c | 9 +++------
dlls/winhttp/winhttp_private.h | 2 +-
3 files changed, 10 insertions(+), 13 deletions(-)
diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c
index 27628c3292..9817287fe2 100644
--- a/dlls/winhttp/request.c
+++ b/dlls/winhttp/request.c
@@ -191,9 +191,9 @@ static struct task_header *dequeue_task( struct request *request )
return task;
}
-static DWORD CALLBACK task_proc( LPVOID param )
+static void CALLBACK task_proc( TP_CALLBACK_INSTANCE *instance, void *ctx )
{
- struct request *request = param;
+ struct request *request = ctx;
HANDLE handles[2];
handles[0] = request->task_wait;
@@ -221,21 +221,20 @@ static DWORD CALLBACK task_proc( LPVOID param )
request->task_cs.DebugInfo->Spare[0] = 0;
DeleteCriticalSection( &request->task_cs );
request->hdr.vtbl->destroy( &request->hdr );
- return 0;
+ return;
default:
ERR("wait failed %u (%u)\n", err, GetLastError());
break;
}
}
- return 0;
}
static BOOL queue_task( struct task_header *task )
{
struct request *request = task->request;
- if (!request->task_thread)
+ if (!request->task_wait)
{
if (!(request->task_wait = CreateEventW( NULL, FALSE, FALSE, NULL ))) return FALSE;
if (!(request->task_cancel = CreateEventW( NULL, FALSE, FALSE, NULL )))
@@ -244,7 +243,7 @@ static BOOL queue_task( struct task_header *task )
request->task_wait = NULL;
return FALSE;
}
- if (!(request->task_thread = CreateThread( NULL, 0, task_proc, request, 0, NULL )))
+ if (!TrySubmitThreadpoolCallback( task_proc, request, NULL ))
{
CloseHandle( request->task_wait );
request->task_wait = NULL;
@@ -252,6 +251,7 @@ static BOOL queue_task( struct task_header *task )
request->task_cancel = NULL;
return FALSE;
}
+ request->task_proc_running = TRUE;
InitializeCriticalSection( &request->task_cs );
request->task_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": request.task_cs");
}
diff --git a/dlls/winhttp/session.c b/dlls/winhttp/session.c
index 2051d4282b..f8d98d0c86 100644
--- a/dlls/winhttp/session.c
+++ b/dlls/winhttp/session.c
@@ -601,14 +601,11 @@ static void request_destroy( struct object_header *hdr )
TRACE("%p\n", request);
- if (request->task_thread)
+ if (request->task_proc_running)
{
- /* Signal to the task proc to quit. It will call
- this again when it does. */
- HANDLE thread = request->task_thread;
- request->task_thread = 0;
+ /* Signal to the task proc to quit. It will call this again when it does. */
+ request->task_proc_running = FALSE;
SetEvent( request->task_cancel );
- CloseHandle( thread );
return;
}
release_object( &request->connect->hdr );
diff --git a/dlls/winhttp/winhttp_private.h b/dlls/winhttp/winhttp_private.h
index 2ee868c657..14cee4403b 100644
--- a/dlls/winhttp/winhttp_private.h
+++ b/dlls/winhttp/winhttp_private.h
@@ -204,7 +204,7 @@ struct request
struct authinfo *proxy_authinfo;
HANDLE task_wait;
HANDLE task_cancel;
- HANDLE task_thread;
+ BOOL task_proc_running;
struct list task_queue;
CRITICAL_SECTION task_cs;
struct
--
2.11.0
1
0
[v6 PATCH 1/5] comctl32/tests: Confirm that emptying the listbox sends LB_RESETCONTENT to itself.
by Nikolay Sivov 23 Nov '18
by Nikolay Sivov 23 Nov '18
23 Nov '18
From: Gabriel Ivăncescu <gabrielopcode(a)gmail.com>
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/comctl32/tests/listbox.c | 91 +++++++++++++++++++++++++++--------
1 file changed, 70 insertions(+), 21 deletions(-)
diff --git a/dlls/comctl32/tests/listbox.c b/dlls/comctl32/tests/listbox.c
index 43da3caa42..362447e083 100644
--- a/dlls/comctl32/tests/listbox.c
+++ b/dlls/comctl32/tests/listbox.c
@@ -34,6 +34,7 @@
enum seq_index
{
+ LB_SEQ_INDEX,
PARENT_SEQ_INDEX,
NUM_MSG_SEQUENCES
};
@@ -90,9 +91,47 @@ static const char BAD_EXTENSION[] = "*.badtxt";
#define ID_LISTBOX 1
+static LRESULT WINAPI listbox_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
+ static LONG defwndproc_counter = 0;
+ struct message msg = { 0 };
+ LRESULT ret;
+
+ switch (message)
+ {
+ case WM_SIZE:
+ case WM_GETTEXT:
+ case WM_PAINT:
+ case WM_ERASEBKGND:
+ case WM_WINDOWPOSCHANGING:
+ case WM_WINDOWPOSCHANGED:
+ case WM_NCCALCSIZE:
+ case WM_NCPAINT:
+ case WM_NCHITTEST:
+ case WM_DEVICECHANGE:
+ break;
+
+ default:
+ msg.message = message;
+ msg.flags = sent|wparam|lparam;
+ if (defwndproc_counter) msg.flags |= defwinproc;
+ msg.wParam = wParam;
+ msg.lParam = lParam;
+ add_message(sequences, LB_SEQ_INDEX, &msg);
+ }
+
+ defwndproc_counter++;
+ ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
+ defwndproc_counter--;
+
+ return ret;
+}
+
static HWND create_listbox(DWORD add_style, HWND parent)
{
INT_PTR ctl_id = 0;
+ WNDPROC oldproc;
HWND handle;
if (parent)
@@ -107,6 +146,9 @@ static HWND create_listbox(DWORD add_style, HWND parent)
SendMessageA(handle, LB_ADDSTRING, 0, (LPARAM) strings[2]);
SendMessageA(handle, LB_ADDSTRING, 0, (LPARAM) strings[3]);
+ oldproc = (WNDPROC)SetWindowLongPtrA(handle, GWLP_WNDPROC, (LONG_PTR)listbox_wnd_proc);
+ SetWindowLongPtrA(handle, GWLP_USERDATA, (LONG_PTR)oldproc);
+
return handle;
}
@@ -167,9 +209,18 @@ static void keypress(HWND handle, WPARAM keycode, BYTE scancode, BOOL extended)
static void run_test(DWORD style, const struct listbox_test test)
{
+ static const struct message delete_seq[] =
+ {
+ { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
+ { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
+ { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
+ { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
+ { LB_RESETCONTENT, sent|wparam|lparam|defwinproc, 0, 0 },
+ { 0 }
+ };
struct listbox_stat answer;
+ int i, res, count;
RECT second_item;
- int i, res;
HWND hLB;
hLB = create_listbox (style, 0);
@@ -224,8 +275,17 @@ static void run_test(DWORD style, const struct listbox_test test)
ok(res == LB_ERR, "Expected LB_ERR items, got %d\n", res);
res = SendMessageA(hLB, LB_DELETESTRING, 4, 0);
ok(res == LB_ERR, "Expected LB_ERR items, got %d\n", res);
- res = SendMessageA(hLB, LB_GETCOUNT, 0, 0);
- ok(res == 4, "Expected 4 items, got %d\n", res);
+ count = SendMessageA(hLB, LB_GETCOUNT, 0, 0);
+ ok(count == 4, "Unexpected item count %d.\n", count);
+
+ /* Emptying listbox sends a LB_RESETCONTENT to itself. */
+ flush_sequence(sequences, LB_SEQ_INDEX);
+ for (i = count; i--;)
+ {
+ res = SendMessageA(hLB, LB_DELETESTRING, 0, 0);
+ ok(res == i, "Unexpected return value %d.\n", res);
+ }
+ ok_sequence(sequences, LB_SEQ_INDEX, delete_seq, "Emptying listbox", FALSE);
DestroyWindow(hLB);
}
@@ -1815,34 +1875,23 @@ static void test_set_count( void )
DestroyWindow( parent );
}
-static int lb_getlistboxinfo;
-
-static LRESULT WINAPI listbox_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
-{
- WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
-
- if (message == LB_GETLISTBOXINFO)
- lb_getlistboxinfo++;
-
- return CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
-}
-
static void test_GetListBoxInfo(void)
{
+ static const struct message getlistboxinfo_seq[] =
+ {
+ { LB_GETLISTBOXINFO, sent },
+ { 0 }
+ };
HWND listbox, parent;
- WNDPROC oldproc;
DWORD ret;
parent = create_parent();
listbox = create_listbox(WS_CHILD | WS_VISIBLE, parent);
- oldproc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (LONG_PTR)listbox_subclass_proc);
- SetWindowLongPtrA(listbox, GWLP_USERDATA, (LONG_PTR)oldproc);
-
- lb_getlistboxinfo = 0;
+ flush_sequences(sequences, NUM_MSG_SEQUENCES);
ret = GetListBoxInfo(listbox);
ok(ret > 0, "got %d\n", ret);
- ok(lb_getlistboxinfo == 1, "got %d\n", lb_getlistboxinfo);
+ ok_sequence(sequences, LB_SEQ_INDEX, getlistboxinfo_seq, "GetListBoxInfo()", FALSE);
DestroyWindow(listbox);
DestroyWindow(parent);
--
2.19.1
1
4
23 Nov '18
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
dlls/setupapi/tests/devinst.c | 204 ++++++++++++++++++------------------------
1 file changed, 87 insertions(+), 117 deletions(-)
diff --git a/dlls/setupapi/tests/devinst.c b/dlls/setupapi/tests/devinst.c
index 7d485dd145..7461eb5841 100644
--- a/dlls/setupapi/tests/devinst.c
+++ b/dlls/setupapi/tests/devinst.c
@@ -36,7 +36,6 @@
static BOOL is_wow64;
/* function pointers */
-static HDEVINFO (WINAPI *pSetupDiCreateDeviceInfoList)(GUID*,HWND);
static HDEVINFO (WINAPI *pSetupDiCreateDeviceInfoListExW)(GUID*,HWND,PCWSTR,PVOID);
static BOOL (WINAPI *pSetupDiCreateDeviceInterfaceA)(HDEVINFO, PSP_DEVINFO_DATA, const GUID *, PCSTR, DWORD, PSP_DEVICE_INTERFACE_DATA);
static BOOL (WINAPI *pSetupDiCallClassInstaller)(DI_FUNCTION, HDEVINFO, PSP_DEVINFO_DATA);
@@ -44,8 +43,6 @@ static BOOL (WINAPI *pSetupDiDestroyDeviceInfoList)(HDEVINFO);
static BOOL (WINAPI *pSetupDiEnumDeviceInterfaces)(HDEVINFO, PSP_DEVINFO_DATA, const GUID *, DWORD, PSP_DEVICE_INTERFACE_DATA);
static BOOL (WINAPI *pSetupDiGetINFClassA)(PCSTR, LPGUID, PSTR, DWORD, PDWORD);
static HKEY (WINAPI *pSetupDiOpenClassRegKeyExA)(GUID*,REGSAM,DWORD,PCSTR,PVOID);
-static HKEY (WINAPI *pSetupDiOpenDevRegKey)(HDEVINFO, PSP_DEVINFO_DATA, DWORD, DWORD, DWORD, REGSAM);
-static HKEY (WINAPI *pSetupDiCreateDevRegKeyW)(HDEVINFO, PSP_DEVINFO_DATA, DWORD, DWORD, DWORD, HINF, PCWSTR);
static BOOL (WINAPI *pSetupDiCreateDeviceInfoA)(HDEVINFO, PCSTR, GUID *, PCSTR, HWND, DWORD, PSP_DEVINFO_DATA);
static BOOL (WINAPI *pSetupDiCreateDeviceInfoW)(HDEVINFO, PCWSTR, GUID *, PCWSTR, HWND, DWORD, PSP_DEVINFO_DATA);
static BOOL (WINAPI *pSetupDiGetDeviceInterfaceDetailA)(HDEVINFO, PSP_DEVICE_INTERFACE_DATA, PSP_DEVICE_INTERFACE_DETAIL_DATA_A, DWORD, PDWORD, PSP_DEVINFO_DATA);
@@ -71,7 +68,6 @@ static void init_function_pointers(void)
pSetupDiCreateDeviceInfoA = (void *)GetProcAddress(hSetupAPI, "SetupDiCreateDeviceInfoA");
pSetupDiCreateDeviceInfoW = (void *)GetProcAddress(hSetupAPI, "SetupDiCreateDeviceInfoW");
- pSetupDiCreateDeviceInfoList = (void *)GetProcAddress(hSetupAPI, "SetupDiCreateDeviceInfoList");
pSetupDiCreateDeviceInfoListExW = (void *)GetProcAddress(hSetupAPI, "SetupDiCreateDeviceInfoListExW");
pSetupDiCreateDeviceInterfaceA = (void *)GetProcAddress(hSetupAPI, "SetupDiCreateDeviceInterfaceA");
pSetupDiDestroyDeviceInfoList = (void *)GetProcAddress(hSetupAPI, "SetupDiDestroyDeviceInfoList");
@@ -79,8 +75,6 @@ static void init_function_pointers(void)
pSetupDiEnumDeviceInterfaces = (void *)GetProcAddress(hSetupAPI, "SetupDiEnumDeviceInterfaces");
pSetupDiGetDeviceInterfaceDetailA = (void *)GetProcAddress(hSetupAPI, "SetupDiGetDeviceInterfaceDetailA");
pSetupDiOpenClassRegKeyExA = (void *)GetProcAddress(hSetupAPI, "SetupDiOpenClassRegKeyExA");
- pSetupDiOpenDevRegKey = (void *)GetProcAddress(hSetupAPI, "SetupDiOpenDevRegKey");
- pSetupDiCreateDevRegKeyW = (void *)GetProcAddress(hSetupAPI, "SetupDiCreateDevRegKeyW");
pSetupDiRegisterDeviceInfo = (void *)GetProcAddress(hSetupAPI, "SetupDiRegisterDeviceInfo");
pSetupDiGetClassDevsA = (void *)GetProcAddress(hSetupAPI, "SetupDiGetClassDevsA");
pSetupDiGetClassDevsW = (void *)GetProcAddress(hSetupAPI, "SetupDiGetClassDevsW");
@@ -823,7 +817,7 @@ static void test_device_iface_detail(void)
devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, devclass);
}
-static void testDevRegKey(void)
+static void test_device_key(void)
{
static const WCHAR classKey[] = {'S','y','s','t','e','m','\\',
'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
@@ -835,128 +829,104 @@ static void testDevRegKey(void)
'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
'E','n','u','m','\\','R','o','o','t','\\',
'L','E','G','A','C','Y','_','B','O','G','U','S',0};
+ SP_DEVINFO_DATA device = {sizeof(device)};
BOOL ret;
HDEVINFO set;
HKEY key = NULL;
+ LONG res;
SetLastError(0xdeadbeef);
- key = pSetupDiCreateDevRegKeyW(NULL, NULL, 0, 0, 0, NULL, NULL);
- ok(key == INVALID_HANDLE_VALUE,
- "Expected INVALID_HANDLE_VALUE, got %p\n", key);
- ok(GetLastError() == ERROR_INVALID_HANDLE,
- "Expected ERROR_INVALID_HANDLE, got %08x\n", GetLastError());
+ key = SetupDiCreateDevRegKeyW(NULL, NULL, 0, 0, 0, NULL, NULL);
+ ok(key == INVALID_HANDLE_VALUE, "Expected failure.\n");
+ ok(GetLastError() == ERROR_INVALID_HANDLE, "Got unexpected error %#x.\n", GetLastError());
- set = pSetupDiCreateDeviceInfoList(&guid, NULL);
- ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %d\n", GetLastError());
- if (set)
- {
- SP_DEVINFO_DATA devInfo = { sizeof(devInfo), { 0 } };
- LONG res;
+ set = SetupDiCreateDeviceInfoList(&guid, NULL);
+ ok(set != NULL, "Failed to create device list, error %#x.\n", GetLastError());
+
+ res = RegOpenKeyW(HKEY_LOCAL_MACHINE, bogus, &key);
+ ok(res != ERROR_SUCCESS, "Key should not exist.\n");
+ RegCloseKey(key);
+
+ ret = SetupDiCreateDeviceInfoA(set, "ROOT\\LEGACY_BOGUS\\0000", &guid, NULL, NULL, 0, &device);
+ ok(ret, "Failed to create device, error %#x.\n", GetLastError());
+ ok(!RegOpenKeyW(HKEY_LOCAL_MACHINE, bogus, &key), "Key should exist.\n");
+ RegCloseKey(key);
+
+ SetLastError(0xdeadbeef);
+ key = SetupDiOpenDevRegKey(NULL, NULL, 0, 0, 0, 0);
+ ok(key == INVALID_HANDLE_VALUE, "Expected failure.\n");
+ ok(GetLastError() == ERROR_INVALID_HANDLE, "Got unexpected error %#x.\n", GetLastError());
- /* The device info key shouldn't be there */
- res = RegOpenKeyW(HKEY_LOCAL_MACHINE, bogus, &key);
- ok(res != ERROR_SUCCESS, "Expected key to not exist\n");
+ SetLastError(0xdeadbeef);
+ key = SetupDiOpenDevRegKey(set, NULL, 0, 0, 0, 0);
+ ok(key == INVALID_HANDLE_VALUE, "Expected failure.\n");
+ ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got unexpected error %#x.\n", GetLastError());
+
+ SetLastError(0xdeadbeef);
+ key = SetupDiOpenDevRegKey(set, &device, 0, 0, 0, 0);
+ ok(key == INVALID_HANDLE_VALUE, "Expected failure.\n");
+ ok(GetLastError() == ERROR_INVALID_FLAGS, "Got unexpected error %#x.\n", GetLastError());
+
+ SetLastError(0xdeadbeef);
+ key = SetupDiOpenDevRegKey(set, &device, DICS_FLAG_GLOBAL, 0, 0, 0);
+ ok(key == INVALID_HANDLE_VALUE, "Expected failure.\n");
+ ok(GetLastError() == ERROR_INVALID_FLAGS, "Got unexpected error %#x.\n", GetLastError());
+
+ SetLastError(0xdeadbeef);
+ key = SetupDiOpenDevRegKey(set, &device, DICS_FLAG_GLOBAL, 0, DIREG_BOTH, 0);
+ ok(key == INVALID_HANDLE_VALUE, "Expected failure.\n");
+ ok(GetLastError() == ERROR_INVALID_FLAGS, "Got unexpected error %#x.\n", GetLastError());
+
+ SetLastError(0xdeadbeef);
+ key = SetupDiOpenDevRegKey(set, &device, DICS_FLAG_GLOBAL, 0, DIREG_DRV, 0);
+ ok(key == INVALID_HANDLE_VALUE, "Expected failure.\n");
+ ok(GetLastError() == ERROR_DEVINFO_NOT_REGISTERED, "Got unexpected error %#x.\n", GetLastError());
+
+ ret = SetupDiRegisterDeviceInfo(set, &device, 0, NULL, NULL, NULL);
+ ok(ret, "Failed to register device, error %#x.\n", GetLastError());
+
+ SetLastError(0xdeadbeef);
+ key = SetupDiOpenDevRegKey(set, &device, DICS_FLAG_GLOBAL, 0, DIREG_DRV, 0);
+ ok(key == INVALID_HANDLE_VALUE, "Expected failure.\n");
+ ok(GetLastError() == ERROR_KEY_DOES_NOT_EXIST, "Got unexpected error %#x.\n", GetLastError());
+
+ SetLastError(0xdeadbeef);
+ res = RegOpenKeyW(HKEY_LOCAL_MACHINE, classKey, &key);
+todo_wine
+ ok(res == ERROR_FILE_NOT_FOUND, "Key should not exist.\n");
+ RegCloseKey(key);
+
+ key = SetupDiCreateDevRegKeyW(set, &device, DICS_FLAG_GLOBAL, 0, DIREG_DRV, NULL, NULL);
+ ok(key != INVALID_HANDLE_VALUE || GetLastError() == ERROR_KEY_DOES_NOT_EXIST, /* Vista+ */
+ "Failed to create device key, error %#x.\n", GetLastError());
+ if (key != INVALID_HANDLE_VALUE)
+ {
RegCloseKey(key);
- /* Create the device information */
- ret = pSetupDiCreateDeviceInfoA(set, "ROOT\\LEGACY_BOGUS\\0000", &guid,
- NULL, NULL, 0, &devInfo);
- ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
- /* The device info key should have been created */
- ok(!RegOpenKeyW(HKEY_LOCAL_MACHINE, bogus, &key),
- "Expected registry key to exist\n");
+
+ ok(!RegOpenKeyW(HKEY_LOCAL_MACHINE, classKey, &key), "Key should exist.\n");
RegCloseKey(key);
+
SetLastError(0xdeadbeef);
- key = pSetupDiOpenDevRegKey(NULL, NULL, 0, 0, 0, 0);
- ok(!key || key == INVALID_HANDLE_VALUE,
- "Expected INVALID_HANDLE_VALUE or a NULL key (NT4)\n");
- ok(GetLastError() == ERROR_INVALID_HANDLE,
- "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
- SetLastError(0xdeadbeef);
- key = pSetupDiOpenDevRegKey(set, NULL, 0, 0, 0, 0);
- ok(key == INVALID_HANDLE_VALUE &&
- GetLastError() == ERROR_INVALID_PARAMETER,
- "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
- SetLastError(0xdeadbeef);
- key = pSetupDiOpenDevRegKey(set, &devInfo, 0, 0, 0, 0);
- ok(key == INVALID_HANDLE_VALUE &&
- GetLastError() == ERROR_INVALID_FLAGS,
- "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
- SetLastError(0xdeadbeef);
- key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0, 0, 0);
- ok(key == INVALID_HANDLE_VALUE &&
- GetLastError() == ERROR_INVALID_FLAGS,
- "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
- SetLastError(0xdeadbeef);
- key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
- DIREG_BOTH, 0);
- ok(key == INVALID_HANDLE_VALUE &&
- GetLastError() == ERROR_INVALID_FLAGS,
- "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
- SetLastError(0xdeadbeef);
- key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
- DIREG_DRV, 0);
- ok(key == INVALID_HANDLE_VALUE &&
- GetLastError() == ERROR_DEVINFO_NOT_REGISTERED,
- "Expected ERROR_DEVINFO_NOT_REGISTERED, got %08x\n", GetLastError());
- SetLastError(0xdeadbeef);
- ret = pSetupDiRegisterDeviceInfo(set, &devInfo, 0, NULL, NULL, NULL);
- ok(ret, "SetupDiRegisterDeviceInfo failed: %08x\n", GetLastError());
- SetLastError(0xdeadbeef);
- key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
- DIREG_DRV, 0);
- /* The software key isn't created by default */
- ok(key == INVALID_HANDLE_VALUE &&
- GetLastError() == ERROR_KEY_DOES_NOT_EXIST,
- "Expected ERROR_KEY_DOES_NOT_EXIST, got %08x\n", GetLastError());
- SetLastError(0xdeadbeef);
- key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
- DIREG_DEV, 0);
- todo_wine
- ok(key == INVALID_HANDLE_VALUE &&
- GetLastError() == ERROR_KEY_DOES_NOT_EXIST,
- "Expected ERROR_KEY_DOES_NOT_EXIST, got %08x\n", GetLastError());
- SetLastError(0xdeadbeef);
- /* The class key shouldn't be there */
- res = RegOpenKeyW(HKEY_LOCAL_MACHINE, classKey, &key);
- todo_wine
- ok(res != ERROR_SUCCESS, "Expected key to not exist\n");
+ key = SetupDiOpenDevRegKey(set, &device, DICS_FLAG_GLOBAL, 0, DIREG_DRV, 0);
+todo_wine {
+ ok(key == INVALID_HANDLE_VALUE, "Expected failure.\n");
+ ok(GetLastError() == ERROR_INVALID_DATA || GetLastError() == ERROR_ACCESS_DENIED, /* win2k3 */
+ "Got unexpected error %#x.\n", GetLastError());
+}
+
+ key = SetupDiOpenDevRegKey(set, &device, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ);
+ ok(key != INVALID_HANDLE_VALUE, "Failed to open device key, error %#x.\n", GetLastError());
RegCloseKey(key);
- /* Create the device reg key */
- key = pSetupDiCreateDevRegKeyW(set, &devInfo, DICS_FLAG_GLOBAL, 0,
- DIREG_DRV, NULL, NULL);
- /* Vista and higher don't actually create the key */
- ok(key != INVALID_HANDLE_VALUE || GetLastError() == ERROR_KEY_DOES_NOT_EXIST,
- "SetupDiCreateDevRegKey failed: %08x\n", GetLastError());
- if (key != INVALID_HANDLE_VALUE)
- {
- RegCloseKey(key);
- /* The class key should have been created */
- ok(!RegOpenKeyW(HKEY_LOCAL_MACHINE, classKey, &key),
- "Expected registry key to exist\n");
- RegCloseKey(key);
- SetLastError(0xdeadbeef);
- key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
- DIREG_DRV, 0);
- todo_wine
- ok(key == INVALID_HANDLE_VALUE &&
- (GetLastError() == ERROR_INVALID_DATA ||
- GetLastError() == ERROR_ACCESS_DENIED), /* win2k3 */
- "Expected ERROR_INVALID_DATA or ERROR_ACCESS_DENIED, got %08x\n", GetLastError());
- key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
- DIREG_DRV, KEY_READ);
- ok(key != INVALID_HANDLE_VALUE, "SetupDiOpenDevRegKey failed: %08x\n",
- GetLastError());
- RegCloseKey(key);
- }
+ }
- ret = pSetupDiRemoveDevice(set, &devInfo);
- todo_wine ok(ret, "got %u\n", GetLastError());
- pSetupDiDestroyDeviceInfoList(set);
+ ret = SetupDiRemoveDevice(set, &device);
+todo_wine
+ ok(ret, "Failed to remove device, error %#x.\n", GetLastError());
+ SetupDiDestroyDeviceInfoList(set);
- /* remove once Wine is fixed */
- devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, bogus);
- devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, classKey);
- }
+ /* remove once Wine is fixed */
+ devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, bogus);
+ devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, classKey);
}
static void testRegisterAndGetDetail(void)
@@ -1557,7 +1527,7 @@ START_TEST(devinst)
test_register_device_info();
test_device_iface();
test_device_iface_detail();
- testDevRegKey();
+ test_device_key();
testRegisterAndGetDetail();
testDeviceRegistryPropertyA();
testDeviceRegistryPropertyW();
--
2.14.1
1
3
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
.../api-ms-win-core-path-l1-1-0.spec | 2 +-
dlls/kernelbase/kernelbase.spec | 2 +-
dlls/kernelbase/path.c | 11 ++
dlls/kernelbase/tests/path.c | 105 ++++++++++++++++++
include/pathcch.h | 1 +
5 files changed, 119 insertions(+), 2 deletions(-)
diff --git a/dlls/api-ms-win-core-path-l1-1-0/api-ms-win-core-path-l1-1-0.spec b/dlls/api-ms-win-core-path-l1-1-0/api-ms-win-core-path-l1-1-0.spec
index c48fe7b49b..6896e4a8d4 100644
--- a/dlls/api-ms-win-core-path-l1-1-0/api-ms-win-core-path-l1-1-0.spec
+++ b/dlls/api-ms-win-core-path-l1-1-0/api-ms-win-core-path-l1-1-0.spec
@@ -5,7 +5,7 @@
@ stdcall PathCchAddExtension(wstr long wstr) kernelbase.PathCchAddExtension
@ stub PathCchAppend
@ stub PathCchAppendEx
-@ stub PathCchCanonicalize
+@ stdcall PathCchCanonicalize(ptr long wstr) kernelbase.PathCchCanonicalize
@ stdcall PathCchCanonicalizeEx(ptr long wstr long) kernelbase.PathCchCanonicalizeEx
@ stub PathCchCombine
@ stub PathCchCombineEx
diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec
index 340f0e2105..752d489fba 100644
--- a/dlls/kernelbase/kernelbase.spec
+++ b/dlls/kernelbase/kernelbase.spec
@@ -1034,7 +1034,7 @@
@ stdcall PathCchAddExtension(wstr long wstr)
# @ stub PathCchAppend
# @ stub PathCchAppendEx
-# @ stub PathCchCanonicalize
+@ stdcall PathCchCanonicalize(ptr long wstr)
@ stdcall PathCchCanonicalizeEx(ptr long wstr long)
# @ stub PathCchCombine
# @ stub PathCchCombineEx
diff --git a/dlls/kernelbase/path.c b/dlls/kernelbase/path.c
index f04f30e5ba..cc15d1c097 100644
--- a/dlls/kernelbase/path.c
+++ b/dlls/kernelbase/path.c
@@ -389,6 +389,17 @@ HRESULT WINAPI PathCchAddExtension(WCHAR *path, SIZE_T size, const WCHAR *extens
return S_OK;
}
+HRESULT WINAPI PathCchCanonicalize(WCHAR *out, SIZE_T size, const WCHAR *in)
+{
+ TRACE("%p %lu %s\n", out, size, wine_dbgstr_w(in));
+
+ /* Not X:\ and path > MAX_PATH - 4, return HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) */
+ if (strlenW(in) > MAX_PATH - 4 && !(isalphaW(in[0]) && in[1] == ':' && in[2] == '\\'))
+ return HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE);
+
+ return PathCchCanonicalizeEx(out, size, in, PATHCCH_NONE);
+}
+
HRESULT WINAPI PathCchCanonicalizeEx(WCHAR *out, SIZE_T size, const WCHAR *in, DWORD flags)
{
WCHAR *buffer;
diff --git a/dlls/kernelbase/tests/path.c b/dlls/kernelbase/tests/path.c
index 74be5eb120..6f95e40c11 100644
--- a/dlls/kernelbase/tests/path.c
+++ b/dlls/kernelbase/tests/path.c
@@ -34,6 +34,7 @@ HRESULT (WINAPI *pPathAllocCanonicalize)(const WCHAR *path_in, DWORD flags, WCHA
HRESULT (WINAPI *pPathCchAddBackslash)(WCHAR *out, SIZE_T size);
HRESULT (WINAPI *pPathCchAddBackslashEx)(WCHAR *out, SIZE_T size, WCHAR **endptr, SIZE_T *remaining);
HRESULT (WINAPI *pPathCchAddExtension)(WCHAR *path, SIZE_T size, const WCHAR *extension);
+HRESULT (WINAPI *pPathCchCanonicalize)(WCHAR *out, SIZE_T size, const WCHAR *in);
HRESULT (WINAPI *pPathCchCanonicalizeEx)(WCHAR *out, SIZE_T size, const WCHAR *in, DWORD flags);
HRESULT (WINAPI *pPathCchCombineEx)(WCHAR *out, SIZE_T size, const WCHAR *path1, const WCHAR *path2, DWORD flags);
HRESULT (WINAPI *pPathCchFindExtension)(const WCHAR *path, SIZE_T size, const WCHAR **extension);
@@ -668,6 +669,108 @@ static void test_PathCchAddExtension(void)
}
}
+static void test_PathCchCanonicalize(void)
+{
+ WCHAR path_inW[MAX_PATH], path_outW[MAX_PATH];
+ CHAR path_outA[MAX_PATH];
+ HRESULT hr;
+ INT i;
+
+ if (!pPathCchCanonicalize)
+ {
+ win_skip("PathCchCanonicalize() is not available.\n");
+ return;
+ }
+
+ /* No NULL check for path pointers on Windows */
+ if (0)
+ {
+ hr = pPathCchCanonicalize(NULL, ARRAY_SIZE(path_outW), path_inW);
+ ok(hr == E_INVALIDARG, "expect hr %#x, got %#x\n", E_INVALIDARG, hr);
+
+ /* MSDN says NULL path_in result in a backslash added to path_out, but the fact is that it would crash */
+ hr = pPathCchCanonicalize(path_outW, ARRAY_SIZE(path_outW), NULL);
+ ok(hr == E_INVALIDARG, "expect hr %#x, got %#x\n", E_INVALIDARG, hr);
+ }
+
+ hr = pPathCchCanonicalize(path_outW, 0, path_inW);
+ ok(hr == E_INVALIDARG, "expect hr %#x, got %#x\n", E_INVALIDARG, hr);
+
+ /* Test path length */
+ for (i = 0; i < MAX_PATH - 3; i++) path_inW[i] = 'a';
+ path_inW[MAX_PATH - 3] = '\0';
+ memset(path_outW, 0, sizeof(path_outW));
+ hr = pPathCchCanonicalize(path_outW, ARRAY_SIZE(path_outW), path_inW);
+ ok(hr == HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), "expect hr %#x, got %#x %s\n",
+ HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), hr, wine_dbgstr_w(path_outW));
+ ok(lstrlenW(path_outW) == 0, "got %d\n", lstrlenW(path_outW));
+
+ path_inW[0] = 'C';
+ path_inW[1] = ':';
+ path_inW[2] = '\\';
+ hr = pPathCchCanonicalize(path_outW, ARRAY_SIZE(path_outW), path_inW);
+ ok(hr == S_OK, "expect hr %#x, got %#x\n", S_OK, hr);
+
+ path_inW[MAX_PATH - 4] = '\0';
+ hr = pPathCchCanonicalize(path_outW, ARRAY_SIZE(path_outW), path_inW);
+ ok(hr == S_OK, "expect hr %#x, got %#x\n", S_OK, hr);
+
+ /* Insufficient buffer size handling */
+ hr = pPathCchCanonicalize(path_outW, 1, path_inW);
+ ok(hr == STRSAFE_E_INSUFFICIENT_BUFFER, "expect hr %#x, got %#x\n", STRSAFE_E_INSUFFICIENT_BUFFER, hr);
+
+ for (i = 0; i < ARRAY_SIZE(alloccanonicalize_tests); i++)
+ {
+ const struct alloccanonicalize_test *t = alloccanonicalize_tests + i;
+
+ /* Skip testing X: path input, this case is different compared to PathAllocCanonicalize */
+ /* Skip test cases where a flag is used */
+ if (!lstrcmpA("C:", t->path_in) || t->flags) continue;
+
+ MultiByteToWideChar(CP_ACP, 0, t->path_in, -1, path_inW, ARRAY_SIZE(path_inW));
+ hr = pPathCchCanonicalize(path_outW, ARRAY_SIZE(path_outW), path_inW);
+ ok(hr == t->hr, "path %s expect result %#x, got %#x\n", t->path_in, t->hr, hr);
+ if (SUCCEEDED(hr))
+ {
+ WideCharToMultiByte(CP_ACP, 0, path_outW, -1, path_outA, ARRAY_SIZE(path_outA), NULL, NULL);
+ ok(!lstrcmpA(path_outA, t->path_out), "path \"%s\" expect output path \"%s\", got \"%s\"\n", t->path_in,
+ t->path_out, path_outA);
+ }
+ }
+
+ /* X: path input */
+ /* Fill a \ at the end of X: if there is enough space */
+ MultiByteToWideChar(CP_ACP, 0, "C:", -1, path_inW, ARRAY_SIZE(path_inW));
+ hr = pPathCchCanonicalize(path_outW, ARRAY_SIZE(path_outW), path_inW);
+ ok(hr == S_OK, "path %s expect result %#x, got %#x\n", "C:", S_OK, hr);
+ if (SUCCEEDED(hr))
+ {
+ WideCharToMultiByte(CP_ACP, 0, path_outW, -1, path_outA, ARRAY_SIZE(path_outA), NULL, NULL);
+ ok(!lstrcmpA(path_outA, "C:\\"), "path \"%s\" expect output path \"%s\", got \"%s\"\n", "C:", "C:\\",
+ path_outA);
+ }
+
+ /* Don't fill a \ at the end of X: if there isn't enough space */
+ MultiByteToWideChar(CP_ACP, 0, "C:", -1, path_inW, ARRAY_SIZE(path_inW));
+ hr = pPathCchCanonicalize(path_outW, 3, path_inW);
+ ok(hr == S_OK, "path %s expect result %#x, got %#x\n", "C:", S_OK, hr);
+ if (SUCCEEDED(hr))
+ {
+ WideCharToMultiByte(CP_ACP, 0, path_outW, -1, path_outA, ARRAY_SIZE(path_outA), NULL, NULL);
+ ok(!lstrcmpA(path_outA, "C:"), "path \"%s\" expect output path \"%s\", got \"%s\"\n", "C:", "C:\\", path_outA);
+ }
+
+ /* Don't fill a \ at the end of X: if there is character following X: */
+ MultiByteToWideChar(CP_ACP, 0, "C:a", -1, path_inW, ARRAY_SIZE(path_inW));
+ hr = pPathCchCanonicalize(path_outW, ARRAY_SIZE(path_outW), path_inW);
+ ok(hr == S_OK, "path %s expect result %#x, got %#x\n", "C:a", S_OK, hr);
+ if (SUCCEEDED(hr))
+ {
+ WideCharToMultiByte(CP_ACP, 0, path_outW, -1, path_outA, ARRAY_SIZE(path_outA), NULL, NULL);
+ ok(!lstrcmpA(path_outA, "C:a"), "path \"%s\" expect output path \"%s\", got \"%s\"\n", "C:a", "C:a", path_outA);
+ }
+}
+
static void test_PathCchCanonicalizeEx(void)
{
WCHAR path_inW[PATHCCH_MAX_CCH + 1], path_outW[PATHCCH_MAX_CCH];
@@ -1836,6 +1939,7 @@ START_TEST(path)
pPathCchAddBackslash = (void *)GetProcAddress(hmod, "PathCchAddBackslash");
pPathCchAddBackslashEx = (void *)GetProcAddress(hmod, "PathCchAddBackslashEx");
pPathCchAddExtension = (void *)GetProcAddress(hmod, "PathCchAddExtension");
+ pPathCchCanonicalize = (void *)GetProcAddress(hmod, "PathCchCanonicalize");
pPathCchCanonicalizeEx = (void *)GetProcAddress(hmod, "PathCchCanonicalizeEx");
pPathCchFindExtension = (void *)GetProcAddress(hmod, "PathCchFindExtension");
pPathCchIsRoot = (void *)GetProcAddress(hmod, "PathCchIsRoot");
@@ -1854,6 +1958,7 @@ START_TEST(path)
test_PathCchAddBackslash();
test_PathCchAddBackslashEx();
test_PathCchAddExtension();
+ test_PathCchCanonicalize();
test_PathCchCanonicalizeEx();
test_PathCchFindExtension();
test_PathCchIsRoot();
diff --git a/include/pathcch.h b/include/pathcch.h
index fb92c3b1aa..708e00e146 100644
--- a/include/pathcch.h
+++ b/include/pathcch.h
@@ -30,6 +30,7 @@ HRESULT WINAPI PathAllocCanonicalize(const WCHAR *path_in, DWORD flags, WCHAR **
HRESULT WINAPI PathCchAddBackslash(WCHAR *path, SIZE_T size);
HRESULT WINAPI PathCchAddBackslashEx(WCHAR *path, SIZE_T size, WCHAR **end, SIZE_T *remaining);
HRESULT WINAPI PathCchAddExtension(WCHAR *path, SIZE_T size, const WCHAR *extension);
+HRESULT WINAPI PathCchCanonicalize(WCHAR *out, SIZE_T size, const WCHAR *in);
HRESULT WINAPI PathCchCanonicalizeEx(WCHAR *out, SIZE_T size, const WCHAR *in, DWORD flags);
HRESULT WINAPI PathCchCombineEx(WCHAR *out, SIZE_T size, const WCHAR *path1, const WCHAR *path2, DWORD flags);
HRESULT WINAPI PathCchFindExtension(const WCHAR *path, SIZE_T size, const WCHAR **extension);
--
2.19.1
1
0
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=44999
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
.../api-ms-win-core-path-l1-1-0.spec | 2 +-
dlls/kernelbase/kernelbase.spec | 2 +-
dlls/kernelbase/path.c | 39 +++++
dlls/kernelbase/tests/path.c | 143 ++++++++++++++++++
include/pathcch.h | 1 +
5 files changed, 185 insertions(+), 2 deletions(-)
diff --git a/dlls/api-ms-win-core-path-l1-1-0/api-ms-win-core-path-l1-1-0.spec b/dlls/api-ms-win-core-path-l1-1-0/api-ms-win-core-path-l1-1-0.spec
index 9bce0ace95..c48fe7b49b 100644
--- a/dlls/api-ms-win-core-path-l1-1-0/api-ms-win-core-path-l1-1-0.spec
+++ b/dlls/api-ms-win-core-path-l1-1-0/api-ms-win-core-path-l1-1-0.spec
@@ -6,7 +6,7 @@
@ stub PathCchAppend
@ stub PathCchAppendEx
@ stub PathCchCanonicalize
-@ stub PathCchCanonicalizeEx
+@ stdcall PathCchCanonicalizeEx(ptr long wstr long) kernelbase.PathCchCanonicalizeEx
@ stub PathCchCombine
@ stub PathCchCombineEx
@ stdcall PathCchFindExtension(wstr long ptr) kernelbase.PathCchFindExtension
diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec
index 8273d5f1b1..340f0e2105 100644
--- a/dlls/kernelbase/kernelbase.spec
+++ b/dlls/kernelbase/kernelbase.spec
@@ -1035,7 +1035,7 @@
# @ stub PathCchAppend
# @ stub PathCchAppendEx
# @ stub PathCchCanonicalize
-# @ stub PathCchCanonicalizeEx
+@ stdcall PathCchCanonicalizeEx(ptr long wstr long)
# @ stub PathCchCombine
# @ stub PathCchCombineEx
@ stdcall PathCchFindExtension(wstr long ptr)
diff --git a/dlls/kernelbase/path.c b/dlls/kernelbase/path.c
index 659a17bd09..f04f30e5ba 100644
--- a/dlls/kernelbase/path.c
+++ b/dlls/kernelbase/path.c
@@ -389,6 +389,45 @@ HRESULT WINAPI PathCchAddExtension(WCHAR *path, SIZE_T size, const WCHAR *extens
return S_OK;
}
+HRESULT WINAPI PathCchCanonicalizeEx(WCHAR *out, SIZE_T size, const WCHAR *in, DWORD flags)
+{
+ WCHAR *buffer;
+ SIZE_T length;
+ HRESULT hr;
+
+ TRACE("%p %lu %s %#x\n", out, size, wine_dbgstr_w(in), flags);
+
+ if (!size) return E_INVALIDARG;
+
+ hr = PathAllocCanonicalize(in, flags, &buffer);
+ if (FAILED(hr)) return hr;
+
+ length = strlenW(buffer);
+ if (size < length + 1)
+ {
+ /* No root and path > MAX_PATH - 4, return HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) */
+ if (length > MAX_PATH - 4 && !(in[0] == '\\' || (isalphaW(in[0]) && in[1] == ':' && in[2] == '\\')))
+ hr = HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE);
+ else
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ memcpy(out, buffer, (length + 1) * sizeof(WCHAR));
+
+ /* Fill a backslash at the end of X: */
+ if (isalphaW(out[0]) && out[1] == ':' && !out[2] && size > 3)
+ {
+ out[2] = '\\';
+ out[3] = 0;
+ }
+ }
+
+ LocalFree(buffer);
+ return hr;
+}
+
HRESULT WINAPI PathCchFindExtension(const WCHAR *path, SIZE_T size, const WCHAR **extension)
{
const WCHAR *lastpoint = NULL;
diff --git a/dlls/kernelbase/tests/path.c b/dlls/kernelbase/tests/path.c
index 0a55369d99..74be5eb120 100644
--- a/dlls/kernelbase/tests/path.c
+++ b/dlls/kernelbase/tests/path.c
@@ -34,6 +34,7 @@ HRESULT (WINAPI *pPathAllocCanonicalize)(const WCHAR *path_in, DWORD flags, WCHA
HRESULT (WINAPI *pPathCchAddBackslash)(WCHAR *out, SIZE_T size);
HRESULT (WINAPI *pPathCchAddBackslashEx)(WCHAR *out, SIZE_T size, WCHAR **endptr, SIZE_T *remaining);
HRESULT (WINAPI *pPathCchAddExtension)(WCHAR *path, SIZE_T size, const WCHAR *extension);
+HRESULT (WINAPI *pPathCchCanonicalizeEx)(WCHAR *out, SIZE_T size, const WCHAR *in, DWORD flags);
HRESULT (WINAPI *pPathCchCombineEx)(WCHAR *out, SIZE_T size, const WCHAR *path1, const WCHAR *path2, DWORD flags);
HRESULT (WINAPI *pPathCchFindExtension)(const WCHAR *path, SIZE_T size, const WCHAR **extension);
BOOL (WINAPI *pPathCchIsRoot)(const WCHAR *path);
@@ -667,6 +668,146 @@ static void test_PathCchAddExtension(void)
}
}
+static void test_PathCchCanonicalizeEx(void)
+{
+ WCHAR path_inW[PATHCCH_MAX_CCH + 1], path_outW[PATHCCH_MAX_CCH];
+ CHAR path_outA[4096];
+ BOOL skip_new_flags = TRUE;
+ HRESULT hr;
+ INT i;
+
+ if (!pPathCchCanonicalizeEx)
+ {
+ win_skip("PathCchCanonicalizeEx() is not available.\n");
+ return;
+ }
+
+ /* No NULL check for path pointers on Windows */
+ if (0)
+ {
+ hr = pPathCchCanonicalizeEx(NULL, ARRAY_SIZE(path_outW), path_inW, 0);
+ ok(hr == E_INVALIDARG, "expect hr %#x, got %#x\n", E_INVALIDARG, hr);
+
+ /* MSDN says NULL path_in result in a backslash added to path_out, but the fact is that it would crash */
+ hr = pPathCchCanonicalizeEx(path_outW, ARRAY_SIZE(path_outW), NULL, 0);
+ ok(hr == E_INVALIDARG, "expect hr %#x, got %#x\n", E_INVALIDARG, hr);
+ }
+
+ path_outW[0] = 0xff;
+ hr = pPathCchCanonicalizeEx(path_outW, 0, path_inW, 0);
+ ok(hr == E_INVALIDARG, "expect hr %#x, got %#x\n", E_INVALIDARG, hr);
+ ok(path_outW[0] = 0xff, "expect path_outW unchanged\n");
+
+ /* Test path length */
+ for (i = 0; i < ARRAY_SIZE(path_inW) - 1; i++) path_inW[i] = 'a';
+ path_inW[PATHCCH_MAX_CCH] = '\0';
+ hr = pPathCchCanonicalizeEx(path_outW, ARRAY_SIZE(path_outW), path_inW, PATHCCH_ALLOW_LONG_PATHS);
+ ok(hr == HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), "expect hr %#x, got %#x\n",
+ HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), hr);
+
+ path_inW[PATHCCH_MAX_CCH - 1] = '\0';
+ hr = pPathCchCanonicalizeEx(path_outW, ARRAY_SIZE(path_outW), path_inW, PATHCCH_ALLOW_LONG_PATHS);
+ ok(hr == S_OK, "expect hr %#x, got %#x\n", S_OK, hr);
+
+ hr = pPathCchCanonicalizeEx(path_outW, 1, path_inW, PATHCCH_ALLOW_LONG_PATHS);
+ ok(hr == HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), "expect hr %#x, got %#x\n",
+ HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), hr);
+
+ /* No root and path > MAX_PATH - 4, return HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) */
+ path_inW[MAX_PATH - 3] = '\0';
+ hr = pPathCchCanonicalizeEx(path_outW, 1, path_inW, 0);
+ ok(hr == HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), "expect hr %#x, got %#x\n",
+ HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), hr);
+
+ /* Has root and path > MAX_PATH - 4 */
+ path_inW[0] = 'C';
+ path_inW[1] = ':';
+ path_inW[2] = '\\';
+ hr = pPathCchCanonicalizeEx(path_outW, 1, path_inW, 0);
+ ok(hr == STRSAFE_E_INSUFFICIENT_BUFFER, "expect hr %#x, got %#x\n", STRSAFE_E_INSUFFICIENT_BUFFER, hr);
+
+ path_inW[0] = '\\';
+ path_inW[1] = path_inW[2] = 'a';
+ hr = pPathCchCanonicalizeEx(path_outW, 1, path_inW, 0);
+ ok(hr == STRSAFE_E_INSUFFICIENT_BUFFER, "expect hr %#x, got %#x\n", STRSAFE_E_INSUFFICIENT_BUFFER, hr);
+
+ path_inW[0] = path_inW[1] = '\\';
+ path_inW[2] = 'a';
+ hr = pPathCchCanonicalizeEx(path_outW, 1, path_inW, 0);
+ ok(hr == STRSAFE_E_INSUFFICIENT_BUFFER, "expect hr %#x, got %#x\n", STRSAFE_E_INSUFFICIENT_BUFFER, hr);
+
+ /* path <= MAX_PATH - 4 */
+ path_inW[0] = path_inW[1] = path_inW[2] = 'a';
+ path_inW[MAX_PATH - 4] = '\0';
+ hr = pPathCchCanonicalizeEx(path_outW, 1, path_inW, 0);
+ ok(hr == STRSAFE_E_INSUFFICIENT_BUFFER, "expect hr %#x, got %#x\n", STRSAFE_E_INSUFFICIENT_BUFFER, hr);
+
+ /* Check if flags added after Windows 10 1709 are supported */
+ MultiByteToWideChar(CP_ACP, 0, "C:\\", -1, path_inW, ARRAY_SIZE(path_inW));
+ hr = pPathCchCanonicalizeEx(path_outW, ARRAY_SIZE(path_outW), path_inW, PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS);
+ if (hr == E_INVALIDARG) skip_new_flags = FALSE;
+
+ for (i = 0; i < ARRAY_SIZE(alloccanonicalize_tests); i++)
+ {
+ const struct alloccanonicalize_test *t = alloccanonicalize_tests + i;
+
+ /* Skip testing X: path input, this case is different compared to PathAllocCanonicalize */
+ if (!lstrcmpA("C:", t->path_in)) continue;
+
+ if (((PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS | PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS
+ | PATHCCH_DO_NOT_NORMALIZE_SEGMENTS | PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH
+ | PATHCCH_ENSURE_TRAILING_SLASH)
+ & t->flags)
+ && skip_new_flags)
+ {
+ win_skip("Skip testing new flags added after Windows 10 1709\n");
+ return;
+ }
+
+ MultiByteToWideChar(CP_ACP, 0, t->path_in, -1, path_inW, ARRAY_SIZE(path_inW));
+ hr = pPathCchCanonicalizeEx(path_outW, ARRAY_SIZE(path_outW), path_inW, t->flags);
+ ok(hr == t->hr, "path %s expect result %#x, got %#x\n", t->path_in, t->hr, hr);
+ if (SUCCEEDED(hr))
+ {
+ WideCharToMultiByte(CP_ACP, 0, path_outW, -1, path_outA, ARRAY_SIZE(path_outA), NULL, NULL);
+ ok(!lstrcmpA(path_outA, t->path_out), "path \"%s\" expect output path \"%s\", got \"%s\"\n", t->path_in,
+ t->path_out, path_outA);
+ }
+ }
+
+ /* X: path input */
+ /* Fill a \ at the end of X: if there is enough space */
+ MultiByteToWideChar(CP_ACP, 0, "C:", -1, path_inW, ARRAY_SIZE(path_inW));
+ hr = pPathCchCanonicalizeEx(path_outW, ARRAY_SIZE(path_outW), path_inW, 0);
+ ok(hr == S_OK, "path %s expect result %#x, got %#x\n", "C:", S_OK, hr);
+ if (SUCCEEDED(hr))
+ {
+ WideCharToMultiByte(CP_ACP, 0, path_outW, -1, path_outA, ARRAY_SIZE(path_outA), NULL, NULL);
+ ok(!lstrcmpA(path_outA, "C:\\"), "path \"%s\" expect output path \"%s\", got \"%s\"\n", "C:", "C:\\",
+ path_outA);
+ }
+
+ /* Don't fill a \ at the end of X: if there isn't enough space */
+ MultiByteToWideChar(CP_ACP, 0, "C:", -1, path_inW, ARRAY_SIZE(path_inW));
+ hr = pPathCchCanonicalizeEx(path_outW, 3, path_inW, 0);
+ ok(hr == S_OK, "path %s expect result %#x, got %#x\n", "C:", S_OK, hr);
+ if (SUCCEEDED(hr))
+ {
+ WideCharToMultiByte(CP_ACP, 0, path_outW, -1, path_outA, ARRAY_SIZE(path_outA), NULL, NULL);
+ ok(!lstrcmpA(path_outA, "C:"), "path \"%s\" expect output path \"%s\", got \"%s\"\n", "C:", "C:\\", path_outA);
+ }
+
+ /* Don't fill a \ at the end of X: if there is character following X: */
+ MultiByteToWideChar(CP_ACP, 0, "C:a", -1, path_inW, ARRAY_SIZE(path_inW));
+ hr = pPathCchCanonicalizeEx(path_outW, ARRAY_SIZE(path_outW), path_inW, 0);
+ ok(hr == S_OK, "path %s expect result %#x, got %#x\n", "C:a", S_OK, hr);
+ if (SUCCEEDED(hr))
+ {
+ WideCharToMultiByte(CP_ACP, 0, path_outW, -1, path_outA, ARRAY_SIZE(path_outA), NULL, NULL);
+ ok(!lstrcmpA(path_outA, "C:a"), "path \"%s\" expect output path \"%s\", got \"%s\"\n", "C:a", "C:a", path_outA);
+ }
+}
+
struct findextension_test
{
const CHAR *path;
@@ -1695,6 +1836,7 @@ START_TEST(path)
pPathCchAddBackslash = (void *)GetProcAddress(hmod, "PathCchAddBackslash");
pPathCchAddBackslashEx = (void *)GetProcAddress(hmod, "PathCchAddBackslashEx");
pPathCchAddExtension = (void *)GetProcAddress(hmod, "PathCchAddExtension");
+ pPathCchCanonicalizeEx = (void *)GetProcAddress(hmod, "PathCchCanonicalizeEx");
pPathCchFindExtension = (void *)GetProcAddress(hmod, "PathCchFindExtension");
pPathCchIsRoot = (void *)GetProcAddress(hmod, "PathCchIsRoot");
pPathCchRemoveBackslash = (void *)GetProcAddress(hmod, "PathCchRemoveBackslash");
@@ -1712,6 +1854,7 @@ START_TEST(path)
test_PathCchAddBackslash();
test_PathCchAddBackslashEx();
test_PathCchAddExtension();
+ test_PathCchCanonicalizeEx();
test_PathCchFindExtension();
test_PathCchIsRoot();
test_PathCchRemoveBackslash();
diff --git a/include/pathcch.h b/include/pathcch.h
index b1d6be249d..fb92c3b1aa 100644
--- a/include/pathcch.h
+++ b/include/pathcch.h
@@ -30,6 +30,7 @@ HRESULT WINAPI PathAllocCanonicalize(const WCHAR *path_in, DWORD flags, WCHAR **
HRESULT WINAPI PathCchAddBackslash(WCHAR *path, SIZE_T size);
HRESULT WINAPI PathCchAddBackslashEx(WCHAR *path, SIZE_T size, WCHAR **end, SIZE_T *remaining);
HRESULT WINAPI PathCchAddExtension(WCHAR *path, SIZE_T size, const WCHAR *extension);
+HRESULT WINAPI PathCchCanonicalizeEx(WCHAR *out, SIZE_T size, const WCHAR *in, DWORD flags);
HRESULT WINAPI PathCchCombineEx(WCHAR *out, SIZE_T size, const WCHAR *path1, const WCHAR *path2, DWORD flags);
HRESULT WINAPI PathCchFindExtension(const WCHAR *path, SIZE_T size, const WCHAR **extension);
BOOL WINAPI PathCchIsRoot(const WCHAR *path);
--
2.19.1
1
0
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
.../api-ms-win-core-path-l1-1-0.spec | 2 +-
dlls/kernelbase/kernelbase.spec | 2 +-
dlls/kernelbase/path.c | 182 +++++++++++
dlls/kernelbase/tests/path.c | 306 ++++++++++++++++++
include/pathcch.h | 2 +
5 files changed, 492 insertions(+), 2 deletions(-)
diff --git a/dlls/api-ms-win-core-path-l1-1-0/api-ms-win-core-path-l1-1-0.spec b/dlls/api-ms-win-core-path-l1-1-0/api-ms-win-core-path-l1-1-0.spec
index 725f16448f..9bce0ace95 100644
--- a/dlls/api-ms-win-core-path-l1-1-0/api-ms-win-core-path-l1-1-0.spec
+++ b/dlls/api-ms-win-core-path-l1-1-0/api-ms-win-core-path-l1-1-0.spec
@@ -1,4 +1,4 @@
-@ stub PathAllocCanonicalize
+@ stdcall PathAllocCanonicalize(wstr long ptr) kernelbase.PathAllocCanonicalize
@ stub PathAllocCombine
@ stdcall PathCchAddBackslash(wstr long) kernelbase.PathCchAddBackslash
@ stdcall PathCchAddBackslashEx(wstr long ptr ptr) kernelbase.PathCchAddBackslashEx
diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec
index e7bb62d75c..8273d5f1b1 100644
--- a/dlls/kernelbase/kernelbase.spec
+++ b/dlls/kernelbase/kernelbase.spec
@@ -1023,7 +1023,7 @@
@ stdcall PathAddBackslashW(wstr) shlwapi.PathAddBackslashW
@ stdcall PathAddExtensionA(str str) shlwapi.PathAddExtensionA
@ stdcall PathAddExtensionW(wstr wstr) shlwapi.PathAddExtensionW
-# @ stub PathAllocCanonicalize
+@ stdcall PathAllocCanonicalize(wstr long ptr)
# @ stub PathAllocCombine
@ stdcall PathAppendA(str str) shlwapi.PathAppendA
@ stdcall PathAppendW(wstr wstr) shlwapi.PathAppendW
diff --git a/dlls/kernelbase/path.c b/dlls/kernelbase/path.c
index c3fca8b9cf..659a17bd09 100644
--- a/dlls/kernelbase/path.c
+++ b/dlls/kernelbase/path.c
@@ -126,6 +126,188 @@ static const WCHAR *get_root_end(const WCHAR *path)
return NULL;
}
+HRESULT WINAPI PathAllocCanonicalize(const WCHAR *path_in, DWORD flags, WCHAR **path_out)
+{
+ WCHAR *buffer, *dst;
+ const WCHAR *src;
+ const WCHAR *root_end;
+ SIZE_T buffer_size, length;
+
+ TRACE("%s %#x %p\n", debugstr_w(path_in), flags, path_out);
+
+ if (!path_in || !path_out
+ || ((flags & PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS) && (flags & PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS))
+ || (flags & (PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS | PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS)
+ && !(flags & PATHCCH_ALLOW_LONG_PATHS))
+ || ((flags & PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH) && (flags & PATHCCH_ALLOW_LONG_PATHS)))
+ {
+ if (path_out) *path_out = NULL;
+ return E_INVALIDARG;
+ }
+
+ length = strlenW(path_in);
+ if ((length + 1 > MAX_PATH && !(flags & (PATHCCH_ALLOW_LONG_PATHS | PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH)))
+ || (length + 1 > PATHCCH_MAX_CCH))
+ {
+ *path_out = NULL;
+ return HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE);
+ }
+
+ /* PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH implies PATHCCH_DO_NOT_NORMALIZE_SEGMENTS */
+ if (flags & PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH) flags |= PATHCCH_DO_NOT_NORMALIZE_SEGMENTS;
+
+ /* path length + possible \\?\ addition + possible \ addition + NUL */
+ buffer_size = (length + 6) * sizeof(WCHAR);
+ buffer = LocalAlloc(LMEM_ZEROINIT, buffer_size);
+ if (!buffer)
+ {
+ *path_out = NULL;
+ return E_OUTOFMEMORY;
+ }
+
+ src = path_in;
+ dst = buffer;
+
+ root_end = get_root_end(path_in);
+ if (root_end) root_end = buffer + (root_end - path_in);
+
+ /* Copy path root */
+ if (root_end)
+ {
+ memcpy(dst, src, (root_end - buffer + 1) * sizeof(WCHAR));
+ src += root_end - buffer + 1;
+ if(PathCchStripPrefix(dst, length + 6) == S_OK)
+ {
+ /* Fill in \ in X:\ if the \ is missing */
+ if(isalphaW(dst[0]) && dst[1] == ':' && dst[2]!= '\\')
+ {
+ dst[2] = '\\';
+ dst[3] = 0;
+ }
+ dst = buffer + strlenW(buffer);
+ root_end = dst;
+ }
+ else
+ dst += root_end - buffer + 1;
+ }
+
+ while (*src)
+ {
+ if (src[0] == '.')
+ {
+ if (src[1] == '.')
+ {
+ /* Keep one . after * */
+ if (dst > buffer && dst[-1] == '*')
+ {
+ *dst++ = *src++;
+ continue;
+ }
+
+ /* Keep the . if one of the following is true:
+ * 1. PATHCCH_DO_NOT_NORMALIZE_SEGMENTS
+ * 2. in form of a..b
+ */
+ if (dst > buffer
+ && (((flags & PATHCCH_DO_NOT_NORMALIZE_SEGMENTS) && dst[-1] != '\\')
+ || (dst[-1] != '\\' && src[2] != '\\' && src[2])))
+ {
+ *dst++ = *src++;
+ *dst++ = *src++;
+ continue;
+ }
+
+ /* Remove the \ before .. if the \ is not part of root */
+ if (dst > buffer && dst[-1] == '\\' && (!root_end || dst - 1 > root_end))
+ {
+ *--dst = '\0';
+ /* Remove characters until a \ is encountered */
+ while (dst > buffer)
+ {
+ if (dst[-1] == '\\')
+ {
+ *--dst = 0;
+ break;
+ }
+ else
+ *--dst = 0;
+ }
+ }
+ /* Remove the extra \ after .. if the \ before .. wasn't deleted */
+ else if (src[2] == '\\')
+ src++;
+
+ src += 2;
+ }
+ else
+ {
+ /* Keep the . if one of the following is true:
+ * 1. PATHCCH_DO_NOT_NORMALIZE_SEGMENTS
+ * 2. in form of a.b, which is used in domain names
+ * 3. *.
+ */
+ if (dst > buffer
+ && ((flags & PATHCCH_DO_NOT_NORMALIZE_SEGMENTS && dst[-1] != '\\')
+ || (dst[-1] != '\\' && src[1] != '\\' && src[1]) || (dst[-1] == '*')))
+ {
+ *dst++ = *src++;
+ continue;
+ }
+
+ /* Remove the \ before . if the \ is not part of root */
+ if (dst > buffer && dst[-1] == '\\' && (!root_end || dst - 1 > root_end)) dst--;
+ /* Remove the extra \ after . if the \ before . wasn't deleted */
+ else if (src[1] == '\\')
+ src++;
+
+ src++;
+ }
+
+ /* If X:\ is not complete, then complete it */
+ if (isalphaW(buffer[0]) && buffer[1] == ':' && buffer[2] != '\\')
+ {
+ root_end = buffer + 2;
+ dst = buffer + 3;
+ buffer[2] = '\\';
+ /* If next character is \, use the \ to fill in */
+ if (src[0] == '\\') src++;
+ }
+ }
+ /* Copy over */
+ else
+ *dst++ = *src++;
+ }
+ /* End the path */
+ *dst = 0;
+
+ /* If result path is empty, fill in \ */
+ if (!*buffer)
+ {
+ buffer[0] = '\\';
+ buffer[1] = 0;
+ }
+
+ /* Extend the path if needed */
+ length = strlenW(buffer);
+ if (((length + 1 > MAX_PATH && isalphaW(buffer[0]) && buffer[1] == ':')
+ || (isalphaW(buffer[0]) && buffer[1] == ':' && flags & PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH))
+ && !(flags & PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS))
+ {
+ memmove(buffer + 4, buffer, (length + 1) * sizeof(WCHAR));
+ buffer[0] = '\\';
+ buffer[1] = '\\';
+ buffer[2] = '?';
+ buffer[3] = '\\';
+ }
+
+ /* Add a trailing backslash to the path if needed */
+ if (flags & PATHCCH_ENSURE_TRAILING_SLASH)
+ PathCchAddBackslash(buffer, buffer_size);
+
+ *path_out = buffer;
+ return S_OK;
+}
+
HRESULT WINAPI PathCchAddBackslash(WCHAR *path, SIZE_T size)
{
return PathCchAddBackslashEx(path, size, NULL, NULL);
diff --git a/dlls/kernelbase/tests/path.c b/dlls/kernelbase/tests/path.c
index 8981b3a08a..0a55369d99 100644
--- a/dlls/kernelbase/tests/path.c
+++ b/dlls/kernelbase/tests/path.c
@@ -30,6 +30,7 @@
#include "wine/test.h"
+HRESULT (WINAPI *pPathAllocCanonicalize)(const WCHAR *path_in, DWORD flags, WCHAR **path_out);
HRESULT (WINAPI *pPathCchAddBackslash)(WCHAR *out, SIZE_T size);
HRESULT (WINAPI *pPathCchAddBackslashEx)(WCHAR *out, SIZE_T size, WCHAR **endptr, SIZE_T *remaining);
HRESULT (WINAPI *pPathCchAddExtension)(WCHAR *path, SIZE_T size, const WCHAR *extension);
@@ -46,6 +47,309 @@ HRESULT (WINAPI *pPathCchStripPrefix)(WCHAR *path, SIZE_T size);
HRESULT (WINAPI *pPathCchStripToRoot)(WCHAR *path, SIZE_T size);
BOOL (WINAPI *pPathIsUNCEx)(const WCHAR *path, const WCHAR **server);
+struct alloccanonicalize_test
+{
+ const CHAR *path_in;
+ const CHAR *path_out;
+ DWORD flags;
+ HRESULT hr;
+};
+
+static const struct alloccanonicalize_test alloccanonicalize_tests[] =
+{
+ /* Malformed path */
+ {"C:a", "C:a", 0, S_OK},
+ {"\\\\?\\C:", "C:\\", 0, S_OK},
+ {"\\\\?C:\\a", "\\\\?C:\\a", 0, S_OK},
+ {"\\\\?UNC\\a", "\\\\?UNC\\a", 0, S_OK},
+ {"\\\\?\\UNCa", "\\\\?\\UNCa", 0, S_OK},
+ {"\\\\?C:a", "\\\\?C:a", 0, S_OK},
+
+ /* No . */
+ {"", "\\", 0, S_OK},
+ {"C:", "C:", 0, S_OK},
+ {"C:\\", "C:\\", 0, S_OK},
+ {"\\\\?\\C:\\a", "C:\\a", 0, S_OK},
+ {"\\\\?\\UNC\\a", "\\\\a", 0, S_OK},
+
+ /* . */
+ {".", "\\", 0, S_OK},
+ {"..", "\\", 0, S_OK},
+ {"...", "\\", 0, S_OK},
+ {"*.", "*.", 0, S_OK},
+ {"*..", "*.", 0, S_OK},
+ {"*...", "*.", 0, S_OK},
+ {"a.", "a", 0, S_OK},
+ {"a.b", "a.b", 0, S_OK},
+ {"a\\.", "a", 0, S_OK},
+ {"a\\.\\b", "a\\b", 0, S_OK},
+ {"C:.", "C:\\", 0, S_OK},
+ {"C:\\.", "C:\\", 0, S_OK},
+ {"C:\\.\\", "C:\\", 0, S_OK},
+ {"C:\\a.", "C:\\a", 0, S_OK},
+ {"C:\\a\\.", "C:\\a", 0, S_OK},
+ {"C:\\a\\\\.", "C:\\a\\", 0, S_OK},
+ {"C:\\a\\\\\\.", "C:\\a\\\\", 0, S_OK},
+ {"\\.", "\\", 0, S_OK},
+ {"\\\\.", "\\\\", 0, S_OK},
+ {"\\\\.\\", "\\\\", 0, S_OK},
+ {"\\\\\\.", "\\\\", 0, S_OK},
+ {"\\\\.\\\\", "\\\\\\", 0, S_OK},
+ {"\\\\\\\\.", "\\\\\\", 0, S_OK},
+ {"\\?\\.", "\\?", 0, S_OK},
+ {"\\\\?\\.", "\\\\?", 0, S_OK},
+ {"\\192.168.1.1\\a", "\\192.168.1.1\\a", 0, S_OK},
+ {"\\a.168.1.1\\a", "\\a.168.1.1\\a", 0, S_OK},
+ {"\\\\192.168.1.1\\a", "\\\\192.168.1.1\\a", 0, S_OK},
+ {"\\\\a.168.1.1\\b", "\\\\a.168.1.1\\b", 0, S_OK},
+ {"\\\\?\\C:.", "C:\\", 0, S_OK},
+ {"\\\\?\\C:\\.", "C:\\", 0, S_OK},
+ {"\\\\?\\UNC\\.", "\\\\", 0, S_OK},
+ {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\.",
+ "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\", 0, S_OK},
+
+ /* .. */
+ {"a..", "a", 0, S_OK},
+ {"a..b", "a..b", 0, S_OK},
+ {"a\\..", "\\", 0, S_OK},
+ {"a\\..\\", "\\", 0, S_OK},
+ {"a\\..\\b", "\\b", 0, S_OK},
+ {"C:..", "C:\\", 0, S_OK},
+ {"C:\\..", "C:\\", 0, S_OK},
+ {"C:\\\\..", "C:\\", 0, S_OK},
+ {"C:\\..\\", "C:\\", 0, S_OK},
+ {"C:\\a\\..", "C:\\", 0, S_OK},
+ {"C:\\a\\\\..", "C:\\a", 0, S_OK},
+ {"C:\\a\\\\\\..", "C:\\a\\", 0, S_OK},
+ {"C:\\a\\..\\b", "C:\\b", 0, S_OK},
+ {"C:\\a\\..\\\\b", "C:\\\\b", 0, S_OK},
+ {"\\..", "\\", 0, S_OK},
+ {"\\\\..", "\\\\", 0, S_OK},
+ {"\\\\\\..", "\\", 0, S_OK},
+ {"\\\\..\\", "\\\\", 0, S_OK},
+ {"\\\\\\..", "\\", 0, S_OK},
+ {"\\\\..\\\\", "\\\\\\", 0, S_OK},
+ {"\\\\\\\\..", "\\\\", 0, S_OK},
+ {"\\?\\..", "\\", 0, S_OK},
+ {"\\a\\..", "\\", 0, S_OK},
+ {"\\\\?\\..", "\\", 0, S_OK},
+ {"\\\\a\\..", "\\", 0, S_OK},
+ {"\\a\\..\\b", "\\b", 0, S_OK},
+ {"\\a\\b\\..", "\\a", 0, S_OK},
+ {"\\?\\UNC\\..", "\\?", 0, S_OK},
+ {"\\?\\C:\\..", "\\?", 0, S_OK},
+ {"\\\\?\\C:..", "C:\\", 0, S_OK},
+ {"\\\\?\\C:\\..", "C:\\", 0, S_OK},
+ {"\\\\?\\UNC\\..", "\\\\", 0, S_OK},
+ {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}..",
+ "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}", 0, S_OK},
+ {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\..",
+ "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\", 0, S_OK},
+ {"\\\\?\\UNC\\a\\b\\..", "\\\\a", 0, S_OK},
+ {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\a\\b\\..",
+ "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\a", 0, S_OK},
+
+ /* . and .. */
+ {"C:\\a\\.\\b\\..\\", "C:\\a\\", 0, S_OK},
+ {"\\a\\.\\b\\..\\", "\\a\\", 0, S_OK},
+ {"\\?\\a\\.\\b\\..\\", "\\?\\a\\", 0, S_OK},
+ {"\\\\.\\a\\.\\b\\..\\", "\\\\a\\", 0, S_OK},
+ {"\\\\?\\a\\.\\b\\..\\", "\\\\?\\a\\", 0, S_OK},
+ {"\\\\.\\..", "\\\\", 0, S_OK},
+
+ /* PATHCCH_ALLOW_LONG_PATHS */
+ /* Input path with prefix \\?\ and length of MAXPATH + 1, HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) = 0x800700ce */
+ {"\\\\?\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", NULL, 0, 0x800700ce},
+ /* Input path with prefix C:\ and length of MAXPATH + 1 */
+ {"C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", NULL, 0, 0x800700ce},
+ {"C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "\\\\?\\C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", PATHCCH_ALLOW_LONG_PATHS, S_OK},
+ /* Input path with prefix C: and length of MAXPATH + 1 */
+ {"C:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "\\\\?\\C:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", PATHCCH_ALLOW_LONG_PATHS, S_OK},
+ /* Input path with prefix C:\ and length of MAXPATH + 1 and with .. */
+ {"C:\\..\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", PATHCCH_ALLOW_LONG_PATHS, S_OK},
+ /* Input path with prefix \\?\ and length of MAXPATH + 1 */
+ {"\\\\?\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "\\\\?\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", PATHCCH_ALLOW_LONG_PATHS, S_OK},
+ /* Input path with prefix \ and length of MAXPATH + 1 */
+ {"\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", PATHCCH_ALLOW_LONG_PATHS, S_OK},
+ /* Input path with length of MAXPATH with PATHCCH_ALLOW_LONG_PATHS disabled*/
+ {"C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 0, S_OK},
+ /* Input path with length of MAXPATH */
+ {"C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", PATHCCH_ALLOW_LONG_PATHS, S_OK},
+
+ /* Flags added after Windows 10 1709 */
+ /* PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS */
+ /* PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS without PATHCCH_ALLOW_LONG_PATHS */
+ {"", NULL, PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS, E_INVALIDARG},
+ /* Input path with prefix C:\ and length of MAXPATH + 1 and PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS */
+ {"C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ PATHCCH_ALLOW_LONG_PATHS | PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS, S_OK},
+
+ /* PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS */
+ /* PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS without PATHCCH_ALLOW_LONG_PATHS */
+ {"", NULL, PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS, E_INVALIDARG},
+ /* Both PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS and PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS */
+ {"", "\\", PATHCCH_ALLOW_LONG_PATHS | PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS | PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS,
+ E_INVALIDARG},
+ /* Input path with prefix C:\ and length of MAXPATH + 1 and PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS */
+ {"C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "\\\\?\\C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ PATHCCH_ALLOW_LONG_PATHS | PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS, S_OK},
+ /* Input path with prefix C:\ and length of MAXPATH and PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS */
+ {"C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ PATHCCH_ALLOW_LONG_PATHS | PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS, S_OK},
+
+ /* PATHCCH_DO_NOT_NORMALIZE_SEGMENTS */
+ /* No effect for spaces */
+ {"C:\\a \\", "C:\\a \\", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
+ {"C:\\a\\ ", "C:\\a\\ ", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
+ {"C:\\a ", "C:\\a ", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
+ {"C:\\a ", "C:\\a ", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
+ {"C:\\a. ", "C:\\a. ", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
+ {"\\a \\", "\\a \\", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
+ {"\\a\\ ", "\\a\\ ", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
+ {"\\\\a \\", "\\\\a \\", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
+ {"\\\\a\\ ", "\\\\a\\ ", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
+ {"\\\\?\\ ", "\\\\?\\ ", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
+ /* Keep trailing dot */
+ {"*..", "*..", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
+ {".", "\\", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
+ {"..", "\\", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
+ {"C:.", "C:.", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
+ {"C:..", "C:..", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
+ {"C:\\a\\.", "C:\\a", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
+ {"C:\\a\\..", "C:\\", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
+ {"C:\\a.", "C:\\a.", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
+ {"C:\\a..", "C:\\a..", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
+
+ /* PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH */
+ {"C:\\a\\", "\\\\?\\C:\\a\\", PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH, S_OK},
+ {"", NULL, PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH | PATHCCH_ALLOW_LONG_PATHS, E_INVALIDARG},
+ {"\\a\\", "\\a\\", PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH, S_OK},
+ {"\\\\?\\C:\\a\\", "\\\\?\\C:\\a\\", PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH, S_OK},
+ /* Implication of PATHCCH_DO_NOT_NORMALIZE_SEGMENTS by PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH */
+ {"\\a.", "\\a.", PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH, S_OK},
+
+ /* PATHCCH_ENSURE_TRAILING_SLASH */
+ {"\\", "\\", PATHCCH_ENSURE_TRAILING_SLASH, S_OK},
+ {"C:\\", "C:\\", PATHCCH_ENSURE_TRAILING_SLASH, S_OK},
+ {"C:\\a\\.", "C:\\a\\", PATHCCH_ENSURE_TRAILING_SLASH, S_OK},
+ {"C:\\a", "C:\\a\\", PATHCCH_ENSURE_TRAILING_SLASH, S_OK}
+};
+
+static void test_PathAllocCanonicalize(void)
+{
+ WCHAR path_inW[1024], path_maxW[PATHCCH_MAX_CCH + 1];
+ WCHAR *path_outW;
+ CHAR path_outA[1024];
+ BOOL skip_new_flags = TRUE;
+ HRESULT hr;
+ INT i;
+
+ if (!pPathAllocCanonicalize)
+ {
+ win_skip("PathAllocCanonicalize() is not available.\n");
+ return;
+ }
+
+ /* No NULL check for path on Windows */
+ if (0)
+ {
+ hr = pPathAllocCanonicalize(NULL, 0, &path_outW);
+ ok(hr == E_INVALIDARG, "expect hr %#x, got %#x\n", E_INVALIDARG, hr);
+ }
+
+ MultiByteToWideChar(CP_ACP, 0, "C:\\", -1, path_inW, ARRAY_SIZE(path_inW));
+ hr = pPathAllocCanonicalize(path_inW, 0, NULL);
+ ok(hr == E_INVALIDARG, "expect hr %#x, got %#x\n", E_INVALIDARG, hr);
+
+ /* Test longest path */
+ for (i = 0; i < ARRAY_SIZE(path_maxW) - 1; i++) path_maxW[i] = 'a';
+ path_maxW[PATHCCH_MAX_CCH] = '\0';
+ path_outW = (WCHAR *)0xdeadbeef;
+ hr = pPathAllocCanonicalize(path_maxW, PATHCCH_ALLOW_LONG_PATHS, &path_outW);
+ ok(hr == HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), "expect hr %#x, got %#x\n",
+ HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), hr);
+ ok(path_outW == NULL, "expect path_outW null, got %p\n", path_outW);
+
+ path_maxW[PATHCCH_MAX_CCH - 1] = '\0';
+ hr = pPathAllocCanonicalize(path_maxW, PATHCCH_ALLOW_LONG_PATHS, &path_outW);
+ ok(hr == S_OK, "expect hr %#x, got %#x\n", S_OK, hr);
+
+ /* Check if flags added after Windows 10 1709 are supported */
+ MultiByteToWideChar(CP_ACP, 0, "C:\\", -1, path_inW, ARRAY_SIZE(path_inW));
+ hr = pPathAllocCanonicalize(path_inW, PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS, &path_outW);
+ if (hr == E_INVALIDARG) skip_new_flags = FALSE;
+
+ for (i = 0; i < ARRAY_SIZE(alloccanonicalize_tests); i++)
+ {
+ const struct alloccanonicalize_test *t = alloccanonicalize_tests + i;
+
+ if (((PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS | PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS
+ | PATHCCH_DO_NOT_NORMALIZE_SEGMENTS | PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH
+ | PATHCCH_ENSURE_TRAILING_SLASH)
+ & t->flags)
+ && skip_new_flags)
+ {
+ win_skip("Skip testing new flags added after Windows 10 1709\n");
+ return;
+ }
+
+ MultiByteToWideChar(CP_ACP, 0, t->path_in, -1, path_inW, ARRAY_SIZE(path_inW));
+ hr = pPathAllocCanonicalize(path_inW, t->flags, &path_outW);
+ ok(hr == t->hr, "path %s expect result %#x, got %#x\n", t->path_in, t->hr, hr);
+ if (SUCCEEDED(hr))
+ {
+ WideCharToMultiByte(CP_ACP, 0, path_outW, -1, path_outA, ARRAY_SIZE(path_outA), NULL, NULL);
+ ok(!lstrcmpA(path_outA, t->path_out), "path \"%s\" expect output path \"%s\", got \"%s\"\n", t->path_in,
+ t->path_out, path_outA);
+ LocalFree(path_outW);
+ }
+ }
+}
+
static const struct
{
const char *path1;
@@ -1386,6 +1690,7 @@ START_TEST(path)
{
HMODULE hmod = LoadLibraryA("kernelbase.dll");
+ pPathAllocCanonicalize = (void *)GetProcAddress(hmod, "PathAllocCanonicalize");
pPathCchCombineEx = (void *)GetProcAddress(hmod, "PathCchCombineEx");
pPathCchAddBackslash = (void *)GetProcAddress(hmod, "PathCchAddBackslash");
pPathCchAddBackslashEx = (void *)GetProcAddress(hmod, "PathCchAddBackslashEx");
@@ -1402,6 +1707,7 @@ START_TEST(path)
pPathCchStripToRoot = (void *)GetProcAddress(hmod, "PathCchStripToRoot");
pPathIsUNCEx = (void *)GetProcAddress(hmod, "PathIsUNCEx");
+ test_PathAllocCanonicalize();
test_PathCchCombineEx();
test_PathCchAddBackslash();
test_PathCchAddBackslashEx();
diff --git a/include/pathcch.h b/include/pathcch.h
index 12a6fc5511..b1d6be249d 100644
--- a/include/pathcch.h
+++ b/include/pathcch.h
@@ -22,9 +22,11 @@
#define PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS 0x04
#define PATHCCH_DO_NOT_NORMALIZE_SEGMENTS 0x08
#define PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH 0x10
+#define PATHCCH_ENSURE_TRAILING_SLASH 0x20
#define PATHCCH_MAX_CCH 0x8000
+HRESULT WINAPI PathAllocCanonicalize(const WCHAR *path_in, DWORD flags, WCHAR **path_out);
HRESULT WINAPI PathCchAddBackslash(WCHAR *path, SIZE_T size);
HRESULT WINAPI PathCchAddBackslashEx(WCHAR *path, SIZE_T size, WCHAR **end, SIZE_T *remaining);
HRESULT WINAPI PathCchAddExtension(WCHAR *path, SIZE_T size, const WCHAR *extension);
--
2.19.1
1
0
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
.../api-ms-win-core-path-l1-1-0.spec | 2 +-
dlls/kernelbase/kernelbase.spec | 2 +-
dlls/kernelbase/path.c | 37 +++++
dlls/kernelbase/tests/path.c | 126 ++++++++++++++++++
include/pathcch.h | 1 +
5 files changed, 166 insertions(+), 2 deletions(-)
diff --git a/dlls/api-ms-win-core-path-l1-1-0/api-ms-win-core-path-l1-1-0.spec b/dlls/api-ms-win-core-path-l1-1-0/api-ms-win-core-path-l1-1-0.spec
index fcc3d7ffad..725f16448f 100644
--- a/dlls/api-ms-win-core-path-l1-1-0/api-ms-win-core-path-l1-1-0.spec
+++ b/dlls/api-ms-win-core-path-l1-1-0/api-ms-win-core-path-l1-1-0.spec
@@ -14,7 +14,7 @@
@ stdcall PathCchRemoveBackslash(wstr long) kernelbase.PathCchRemoveBackslash
@ stdcall PathCchRemoveBackslashEx(wstr long ptr ptr) kernelbase.PathCchRemoveBackslashEx
@ stdcall PathCchRemoveExtension(wstr long) kernelbase.PathCchRemoveExtension
-@ stub PathCchRemoveFileSpec
+@ stdcall PathCchRemoveFileSpec(wstr long) kernelbase.PathCchRemoveFileSpec
@ stdcall PathCchRenameExtension(wstr long wstr) kernelbase.PathCchRenameExtension
@ stdcall PathCchSkipRoot(wstr ptr) kernelbase.PathCchSkipRoot
@ stdcall PathCchStripPrefix(wstr long) kernelbase.PathCchStripPrefix
diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec
index 252f47c5c7..e7bb62d75c 100644
--- a/dlls/kernelbase/kernelbase.spec
+++ b/dlls/kernelbase/kernelbase.spec
@@ -1043,7 +1043,7 @@
@ stdcall PathCchRemoveBackslash(wstr long)
@ stdcall PathCchRemoveBackslashEx(wstr long ptr ptr)
@ stdcall PathCchRemoveExtension(wstr long)
-# @ stub PathCchRemoveFileSpec
+@ stdcall PathCchRemoveFileSpec(wstr long)
@ stdcall PathCchRenameExtension(wstr long wstr)
@ stdcall PathCchSkipRoot(wstr ptr)
@ stdcall PathCchStripPrefix(wstr long)
diff --git a/dlls/kernelbase/path.c b/dlls/kernelbase/path.c
index b28abc437c..c3fca8b9cf 100644
--- a/dlls/kernelbase/path.c
+++ b/dlls/kernelbase/path.c
@@ -346,6 +346,43 @@ HRESULT WINAPI PathCchRemoveExtension(WCHAR *path, SIZE_T size)
return next == extension ? S_FALSE : S_OK;
}
+HRESULT WINAPI PathCchRemoveFileSpec(WCHAR *path, SIZE_T size)
+{
+ const WCHAR *root_end = NULL;
+ SIZE_T length;
+ WCHAR *last;
+
+ TRACE("%s %lu\n", wine_dbgstr_w(path), size);
+
+ if (!path || !size || size > PATHCCH_MAX_CCH) return E_INVALIDARG;
+
+ if (PathCchIsRoot(path)) return S_FALSE;
+
+ PathCchSkipRoot(path, &root_end);
+
+ /* The backslash at the end of UNC and \\* are not considered part of root in this case */
+ if (root_end && root_end > path && root_end[-1] == '\\'
+ && (is_prefixed_unc(path) || (path[0] == '\\' && path[1] == '\\' && path[2] != '?')))
+ root_end--;
+
+ length = strlenW(path);
+ last = path + length - 1;
+ while (last >= path && (!root_end || last >= root_end))
+ {
+ if (last - path >= size) return E_INVALIDARG;
+
+ if (*last == '\\')
+ {
+ *last-- = 0;
+ break;
+ }
+
+ *last-- = 0;
+ }
+
+ return last != path + length - 1 ? S_OK : S_FALSE;
+}
+
HRESULT WINAPI PathCchRenameExtension(WCHAR *path, SIZE_T size, const WCHAR *extension)
{
HRESULT hr;
diff --git a/dlls/kernelbase/tests/path.c b/dlls/kernelbase/tests/path.c
index dc76b9b5c7..8981b3a08a 100644
--- a/dlls/kernelbase/tests/path.c
+++ b/dlls/kernelbase/tests/path.c
@@ -39,6 +39,7 @@ BOOL (WINAPI *pPathCchIsRoot)(const WCHAR *path);
HRESULT (WINAPI *pPathCchRemoveBackslash)(WCHAR *path, SIZE_T path_size);
HRESULT (WINAPI *pPathCchRemoveBackslashEx)(WCHAR *path, SIZE_T path_size, WCHAR **path_end, SIZE_T *free_size);
HRESULT (WINAPI *pPathCchRemoveExtension)(WCHAR *path, SIZE_T size);
+HRESULT (WINAPI *pPathCchRemoveFileSpec)(WCHAR *path, SIZE_T size);
HRESULT (WINAPI *pPathCchRenameExtension)(WCHAR *path, SIZE_T size, const WCHAR *extension);
HRESULT (WINAPI *pPathCchSkipRoot)(const WCHAR *path, const WCHAR **root_end);
HRESULT (WINAPI *pPathCchStripPrefix)(WCHAR *path, SIZE_T size);
@@ -787,6 +788,129 @@ static void test_PathCchRemoveExtension(void)
}
}
+struct removefilespec_test
+{
+ const CHAR *path;
+ const CHAR *expected;
+ HRESULT hr;
+ SIZE_T size;
+};
+
+static const struct removefilespec_test removefilespec_tests[] =
+{
+ {"", "", S_FALSE},
+ {"a", "", S_OK},
+ {"a\\", "a", S_OK},
+ {"a\\b", "a", S_OK},
+
+ {"\\", "\\", S_FALSE},
+ {"\\a", "\\", S_OK},
+ {"\\a\\", "\\a", S_OK},
+ {"\\a\\b", "\\a", S_OK},
+
+ {"\\\\", "\\\\", S_FALSE},
+ {"\\\\a", "\\\\a", S_FALSE},
+ {"\\\\a\\", "\\\\a", S_OK},
+ {"\\\\a\\b", "\\\\a\\b", S_FALSE},
+ {"\\\\a\\b\\", "\\\\a\\b", S_OK},
+ {"\\\\a\\b\\c", "\\\\a\\b", S_OK},
+
+ {"C:", "C:", S_FALSE},
+ {"C:a", "C:", S_OK},
+ {"C:a\\", "C:a", S_OK},
+ {"C:a\\b", "C:a", S_OK},
+
+ {"C:\\", "C:\\", S_FALSE},
+ {"C:\\a", "C:\\", S_OK},
+ {"C:\\a\\", "C:\\a", S_OK},
+ {"C:\\a\\b", "C:\\a", S_OK},
+
+ {"\\\\?\\", "\\\\?", S_OK},
+ {"\\\\?\\a", "\\\\?", S_OK},
+ {"\\\\?\\a\\", "\\\\?\\a", S_OK},
+ {"\\\\?\\a\\b", "\\\\?\\a", S_OK},
+
+ {"\\\\?\\C:", "\\\\?\\C:", S_FALSE},
+ {"\\\\?\\C:a", "\\\\?\\C:", S_OK},
+ {"\\\\?\\C:a\\", "\\\\?\\C:a", S_OK},
+ {"\\\\?\\C:a\\b", "\\\\?\\C:a", S_OK},
+
+ {"\\\\?\\C:\\", "\\\\?\\C:\\", S_FALSE},
+ {"\\\\?\\C:\\a", "\\\\?\\C:\\", S_OK},
+ {"\\\\?\\C:\\a\\", "\\\\?\\C:\\a", S_OK},
+ {"\\\\?\\C:\\a\\b", "\\\\?\\C:\\a", S_OK},
+
+ {"\\\\?\\UNC\\", "\\\\?\\UNC\\", S_FALSE},
+ {"\\\\?\\UNC\\a", "\\\\?\\UNC\\a", S_FALSE},
+ {"\\\\?\\UNC\\a\\", "\\\\?\\UNC\\a", S_OK},
+ {"\\\\?\\UNC\\a\\b", "\\\\?\\UNC\\a\\b", S_FALSE},
+ {"\\\\?\\UNC\\a\\b\\", "\\\\?\\UNC\\a\\b", S_OK},
+ {"\\\\?\\UNC\\a\\b\\c", "\\\\?\\UNC\\a\\b", S_OK},
+
+ {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}",
+ "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}", S_FALSE},
+ {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}a",
+ "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}", S_OK},
+ {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}a\\",
+ "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}a", S_OK},
+ {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}a\\b",
+ "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}a", S_OK},
+
+ {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\",
+ "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\", S_FALSE},
+ {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\a",
+ "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\", S_OK},
+ {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\a\\",
+ "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\a", S_OK},
+ {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\a\\b",
+ "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\a", S_OK},
+
+ /* Size tests */
+ {"C:\\a", NULL, E_INVALIDARG, PATHCCH_MAX_CCH + 1},
+ {"C:\\a", "C:\\", S_OK, PATHCCH_MAX_CCH},
+ /* Size < original path length + 1, read beyond size */
+ {"C:\\a", "C:\\", S_OK, ARRAY_SIZE("C:\\a") - 1},
+ /* Size < result path length + 1 */
+ {"C:\\a", NULL, E_INVALIDARG, ARRAY_SIZE("C:\\") - 1}
+};
+
+static void test_PathCchRemoveFileSpec(void)
+{
+ WCHAR pathW[PATHCCH_MAX_CCH] = {0};
+ CHAR pathA[PATHCCH_MAX_CCH];
+ SIZE_T size;
+ HRESULT hr;
+ INT i;
+
+ if (!pPathCchRemoveFileSpec)
+ {
+ win_skip("PathCchRemoveFileSpec() is not available.\n");
+ return;
+ }
+
+ /* Null arguments */
+ hr = pPathCchRemoveFileSpec(NULL, ARRAY_SIZE(pathW));
+ ok(hr == E_INVALIDARG, "expect %#x, got %#x\n", E_INVALIDARG, hr);
+
+ hr = pPathCchRemoveFileSpec(pathW, 0);
+ ok(hr == E_INVALIDARG, "expect %#x, got %#x\n", E_INVALIDARG, hr);
+
+ for (i = 0; i < ARRAY_SIZE(removefilespec_tests); i++)
+ {
+ const struct removefilespec_test *t = removefilespec_tests + i;
+
+ MultiByteToWideChar(CP_ACP, 0, t->path, -1, pathW, ARRAY_SIZE(pathW));
+ size = t->size ? t->size : ARRAY_SIZE(pathW);
+ hr = pPathCchRemoveFileSpec(pathW, size);
+ ok(hr == t->hr, "path %s expect result %#x, got %#x\n", t->path, t->hr, hr);
+ if (SUCCEEDED(hr))
+ {
+ WideCharToMultiByte(CP_ACP, 0, pathW, -1, pathA, ARRAY_SIZE(pathA), NULL, NULL);
+ ok(!lstrcmpA(pathA, t->expected), "path %s expect stripped path %s, got %s\n", t->path, t->expected, pathA);
+ }
+ }
+}
+
struct renameextension_test
{
const CHAR *path;
@@ -1271,6 +1395,7 @@ START_TEST(path)
pPathCchRemoveBackslash = (void *)GetProcAddress(hmod, "PathCchRemoveBackslash");
pPathCchRemoveBackslashEx = (void *)GetProcAddress(hmod, "PathCchRemoveBackslashEx");
pPathCchRemoveExtension = (void *)GetProcAddress(hmod, "PathCchRemoveExtension");
+ pPathCchRemoveFileSpec = (void *)GetProcAddress(hmod, "PathCchRemoveFileSpec");
pPathCchRenameExtension = (void *)GetProcAddress(hmod, "PathCchRenameExtension");
pPathCchSkipRoot = (void *)GetProcAddress(hmod, "PathCchSkipRoot");
pPathCchStripPrefix = (void *)GetProcAddress(hmod, "PathCchStripPrefix");
@@ -1286,6 +1411,7 @@ START_TEST(path)
test_PathCchRemoveBackslash();
test_PathCchRemoveBackslashEx();
test_PathCchRemoveExtension();
+ test_PathCchRemoveFileSpec();
test_PathCchRenameExtension();
test_PathCchSkipRoot();
test_PathCchStripPrefix();
diff --git a/include/pathcch.h b/include/pathcch.h
index f4c8377059..12a6fc5511 100644
--- a/include/pathcch.h
+++ b/include/pathcch.h
@@ -34,6 +34,7 @@ BOOL WINAPI PathCchIsRoot(const WCHAR *path);
HRESULT WINAPI PathCchRemoveBackslash(WCHAR *path, SIZE_T path_size);
HRESULT WINAPI PathCchRemoveBackslashEx(WCHAR *path, SIZE_T path_size, WCHAR **path_end, SIZE_T *free_size);
HRESULT WINAPI PathCchRemoveExtension(WCHAR *path, SIZE_T size);
+HRESULT WINAPI PathCchRemoveFileSpec(WCHAR *path, SIZE_T size);
HRESULT WINAPI PathCchRenameExtension(WCHAR *path, SIZE_T size, const WCHAR *extension);
HRESULT WINAPI PathCchSkipRoot(const WCHAR *path, const WCHAR **root_end);
HRESULT WINAPI PathCchStripPrefix(WCHAR *path, SIZE_T size);
--
2.19.1
1
0
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
.../api-ms-win-core-path-l1-1-0.spec | 2 +-
dlls/kernelbase/kernelbase.spec | 2 +-
dlls/kernelbase/path.c | 10 ++++
dlls/kernelbase/tests/path.c | 49 +++++++++++++++++++
include/pathcch.h | 1 +
5 files changed, 62 insertions(+), 2 deletions(-)
diff --git a/dlls/api-ms-win-core-path-l1-1-0/api-ms-win-core-path-l1-1-0.spec b/dlls/api-ms-win-core-path-l1-1-0/api-ms-win-core-path-l1-1-0.spec
index 3caaf80acb..fcc3d7ffad 100644
--- a/dlls/api-ms-win-core-path-l1-1-0/api-ms-win-core-path-l1-1-0.spec
+++ b/dlls/api-ms-win-core-path-l1-1-0/api-ms-win-core-path-l1-1-0.spec
@@ -11,7 +11,7 @@
@ stub PathCchCombineEx
@ stdcall PathCchFindExtension(wstr long ptr) kernelbase.PathCchFindExtension
@ stdcall PathCchIsRoot(wstr) kernelbase.PathCchIsRoot
-@ stub PathCchRemoveBackslash
+@ stdcall PathCchRemoveBackslash(wstr long) kernelbase.PathCchRemoveBackslash
@ stdcall PathCchRemoveBackslashEx(wstr long ptr ptr) kernelbase.PathCchRemoveBackslashEx
@ stdcall PathCchRemoveExtension(wstr long) kernelbase.PathCchRemoveExtension
@ stub PathCchRemoveFileSpec
diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec
index a08fd2c046..252f47c5c7 100644
--- a/dlls/kernelbase/kernelbase.spec
+++ b/dlls/kernelbase/kernelbase.spec
@@ -1040,7 +1040,7 @@
# @ stub PathCchCombineEx
@ stdcall PathCchFindExtension(wstr long ptr)
@ stdcall PathCchIsRoot(wstr)
-# @ stub PathCchRemoveBackslash
+@ stdcall PathCchRemoveBackslash(wstr long)
@ stdcall PathCchRemoveBackslashEx(wstr long ptr ptr)
@ stdcall PathCchRemoveExtension(wstr long)
# @ stub PathCchRemoveFileSpec
diff --git a/dlls/kernelbase/path.c b/dlls/kernelbase/path.c
index 05fcc2b265..b28abc437c 100644
--- a/dlls/kernelbase/path.c
+++ b/dlls/kernelbase/path.c
@@ -278,6 +278,16 @@ BOOL WINAPI PathCchIsRoot(const WCHAR *path)
return FALSE;
}
+HRESULT WINAPI PathCchRemoveBackslash(WCHAR *path, SIZE_T path_size)
+{
+ WCHAR *path_end;
+ SIZE_T free_size;
+
+ TRACE("%s %lu\n", debugstr_w(path), path_size);
+
+ return PathCchRemoveBackslashEx(path, path_size, &path_end, &free_size);
+}
+
HRESULT WINAPI PathCchRemoveBackslashEx(WCHAR *path, SIZE_T path_size, WCHAR **path_end, SIZE_T *free_size)
{
const WCHAR *root_end;
diff --git a/dlls/kernelbase/tests/path.c b/dlls/kernelbase/tests/path.c
index 0050e1a643..dc76b9b5c7 100644
--- a/dlls/kernelbase/tests/path.c
+++ b/dlls/kernelbase/tests/path.c
@@ -36,6 +36,7 @@ HRESULT (WINAPI *pPathCchAddExtension)(WCHAR *path, SIZE_T size, const WCHAR *ex
HRESULT (WINAPI *pPathCchCombineEx)(WCHAR *out, SIZE_T size, const WCHAR *path1, const WCHAR *path2, DWORD flags);
HRESULT (WINAPI *pPathCchFindExtension)(const WCHAR *path, SIZE_T size, const WCHAR **extension);
BOOL (WINAPI *pPathCchIsRoot)(const WCHAR *path);
+HRESULT (WINAPI *pPathCchRemoveBackslash)(WCHAR *path, SIZE_T path_size);
HRESULT (WINAPI *pPathCchRemoveBackslashEx)(WCHAR *path, SIZE_T path_size, WCHAR **path_end, SIZE_T *free_size);
HRESULT (WINAPI *pPathCchRemoveExtension)(WCHAR *path, SIZE_T size);
HRESULT (WINAPI *pPathCchRenameExtension)(WCHAR *path, SIZE_T size, const WCHAR *extension);
@@ -593,6 +594,52 @@ static const struct removebackslashex_test removebackslashex_tests [] =
"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\a", 50, 2, S_OK}
};
+static void test_PathCchRemoveBackslash(void)
+{
+ WCHAR pathW[PATHCCH_MAX_CCH];
+ CHAR pathA[PATHCCH_MAX_CCH];
+ HRESULT hr;
+ SIZE_T path_size;
+ INT i;
+
+ if (!pPathCchRemoveBackslash)
+ {
+ win_skip("PathCchRemoveBackslash() is not available.\n");
+ return;
+ }
+
+ /* No NULL check for path on Windows */
+ if (0)
+ {
+ hr = pPathCchRemoveBackslash(NULL, PATHCCH_MAX_CCH);
+ ok(hr == E_INVALIDARG, "expect hr %#x, got %#x\n", E_INVALIDARG, hr);
+ }
+
+ MultiByteToWideChar(CP_ACP, 0, "C:\\a\\", -1, pathW, ARRAY_SIZE(pathW));
+ hr = pPathCchRemoveBackslash(pathW, 0);
+ ok(hr == E_INVALIDARG, "expect hr %#x, got %#x\n", E_INVALIDARG, hr);
+
+ hr = pPathCchRemoveBackslash(pathW, PATHCCH_MAX_CCH + 1);
+ ok(hr == S_OK, "expect hr %#x, got %#x\n", S_OK, hr);
+
+ hr = pPathCchRemoveBackslash(pathW, PATHCCH_MAX_CCH);
+ ok(hr == S_FALSE, "expect hr %#x, got %#x\n", S_FALSE, hr);
+
+ for (i = 0; i < ARRAY_SIZE(removebackslashex_tests); i++)
+ {
+ const struct removebackslashex_test *t = removebackslashex_tests + i;
+ path_size = MultiByteToWideChar(CP_ACP, 0, t->path_in, -1, pathW, ARRAY_SIZE(pathW));
+ hr = pPathCchRemoveBackslash(pathW, path_size);
+ ok(hr == t->hr, "path %s expect result %#x, got %#x\n", t->path_in, t->hr, hr);
+ if (SUCCEEDED(hr))
+ {
+ WideCharToMultiByte(CP_ACP, 0, pathW, -1, pathA, ARRAY_SIZE(pathA), NULL, NULL);
+ ok(!lstrcmpA(pathA, t->path_out), "path %s expect output path %s, got %s\n", t->path_in, t->path_out,
+ pathA);
+ }
+ }
+}
+
static void test_PathCchRemoveBackslashEx(void)
{
WCHAR pathW[PATHCCH_MAX_CCH];
@@ -1221,6 +1268,7 @@ START_TEST(path)
pPathCchAddExtension = (void *)GetProcAddress(hmod, "PathCchAddExtension");
pPathCchFindExtension = (void *)GetProcAddress(hmod, "PathCchFindExtension");
pPathCchIsRoot = (void *)GetProcAddress(hmod, "PathCchIsRoot");
+ pPathCchRemoveBackslash = (void *)GetProcAddress(hmod, "PathCchRemoveBackslash");
pPathCchRemoveBackslashEx = (void *)GetProcAddress(hmod, "PathCchRemoveBackslashEx");
pPathCchRemoveExtension = (void *)GetProcAddress(hmod, "PathCchRemoveExtension");
pPathCchRenameExtension = (void *)GetProcAddress(hmod, "PathCchRenameExtension");
@@ -1235,6 +1283,7 @@ START_TEST(path)
test_PathCchAddExtension();
test_PathCchFindExtension();
test_PathCchIsRoot();
+ test_PathCchRemoveBackslash();
test_PathCchRemoveBackslashEx();
test_PathCchRemoveExtension();
test_PathCchRenameExtension();
diff --git a/include/pathcch.h b/include/pathcch.h
index f7de815d16..f4c8377059 100644
--- a/include/pathcch.h
+++ b/include/pathcch.h
@@ -31,6 +31,7 @@ HRESULT WINAPI PathCchAddExtension(WCHAR *path, SIZE_T size, const WCHAR *extens
HRESULT WINAPI PathCchCombineEx(WCHAR *out, SIZE_T size, const WCHAR *path1, const WCHAR *path2, DWORD flags);
HRESULT WINAPI PathCchFindExtension(const WCHAR *path, SIZE_T size, const WCHAR **extension);
BOOL WINAPI PathCchIsRoot(const WCHAR *path);
+HRESULT WINAPI PathCchRemoveBackslash(WCHAR *path, SIZE_T path_size);
HRESULT WINAPI PathCchRemoveBackslashEx(WCHAR *path, SIZE_T path_size, WCHAR **path_end, SIZE_T *free_size);
HRESULT WINAPI PathCchRemoveExtension(WCHAR *path, SIZE_T size);
HRESULT WINAPI PathCchRenameExtension(WCHAR *path, SIZE_T size, const WCHAR *extension);
--
2.19.1
1
0
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
.../api-ms-win-core-path-l1-1-0.spec | 2 +-
dlls/kernelbase/kernelbase.spec | 2 +-
dlls/kernelbase/path.c | 39 ++++++
dlls/kernelbase/tests/path.c | 116 ++++++++++++++++++
include/pathcch.h | 1 +
5 files changed, 158 insertions(+), 2 deletions(-)
diff --git a/dlls/api-ms-win-core-path-l1-1-0/api-ms-win-core-path-l1-1-0.spec b/dlls/api-ms-win-core-path-l1-1-0/api-ms-win-core-path-l1-1-0.spec
index 61eb22031e..3caaf80acb 100644
--- a/dlls/api-ms-win-core-path-l1-1-0/api-ms-win-core-path-l1-1-0.spec
+++ b/dlls/api-ms-win-core-path-l1-1-0/api-ms-win-core-path-l1-1-0.spec
@@ -12,7 +12,7 @@
@ stdcall PathCchFindExtension(wstr long ptr) kernelbase.PathCchFindExtension
@ stdcall PathCchIsRoot(wstr) kernelbase.PathCchIsRoot
@ stub PathCchRemoveBackslash
-@ stub PathCchRemoveBackslashEx
+@ stdcall PathCchRemoveBackslashEx(wstr long ptr ptr) kernelbase.PathCchRemoveBackslashEx
@ stdcall PathCchRemoveExtension(wstr long) kernelbase.PathCchRemoveExtension
@ stub PathCchRemoveFileSpec
@ stdcall PathCchRenameExtension(wstr long wstr) kernelbase.PathCchRenameExtension
diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec
index ffb5a95721..a08fd2c046 100644
--- a/dlls/kernelbase/kernelbase.spec
+++ b/dlls/kernelbase/kernelbase.spec
@@ -1041,7 +1041,7 @@
@ stdcall PathCchFindExtension(wstr long ptr)
@ stdcall PathCchIsRoot(wstr)
# @ stub PathCchRemoveBackslash
-# @ stub PathCchRemoveBackslashEx
+@ stdcall PathCchRemoveBackslashEx(wstr long ptr ptr)
@ stdcall PathCchRemoveExtension(wstr long)
# @ stub PathCchRemoveFileSpec
@ stdcall PathCchRenameExtension(wstr long wstr)
diff --git a/dlls/kernelbase/path.c b/dlls/kernelbase/path.c
index 75faf0b79c..05fcc2b265 100644
--- a/dlls/kernelbase/path.c
+++ b/dlls/kernelbase/path.c
@@ -278,6 +278,45 @@ BOOL WINAPI PathCchIsRoot(const WCHAR *path)
return FALSE;
}
+HRESULT WINAPI PathCchRemoveBackslashEx(WCHAR *path, SIZE_T path_size, WCHAR **path_end, SIZE_T *free_size)
+{
+ const WCHAR *root_end;
+ SIZE_T path_length;
+
+ TRACE("%s %lu %p %p\n", debugstr_w(path), path_size, path_end, free_size);
+
+ if (!path_size || !path_end || !free_size)
+ {
+ if (path_end) *path_end = NULL;
+ if (free_size) *free_size = 0;
+ return E_INVALIDARG;
+ }
+
+ path_length = strnlenW(path, path_size);
+ if (path_length == path_size && !path[path_length]) return E_INVALIDARG;
+
+ root_end = get_root_end(path);
+ if (path_length > 0 && path[path_length - 1] == '\\')
+ {
+ *path_end = path + path_length - 1;
+ *free_size = path_size - path_length + 1;
+ /* If the last character is beyond end of root */
+ if (!root_end || path + path_length - 1 > root_end)
+ {
+ path[path_length - 1] = 0;
+ return S_OK;
+ }
+ else
+ return S_FALSE;
+ }
+ else
+ {
+ *path_end = path + path_length;
+ *free_size = path_size - path_length;
+ return S_FALSE;
+ }
+}
+
HRESULT WINAPI PathCchRemoveExtension(WCHAR *path, SIZE_T size)
{
const WCHAR *extension;
diff --git a/dlls/kernelbase/tests/path.c b/dlls/kernelbase/tests/path.c
index 2edd49b0af..0050e1a643 100644
--- a/dlls/kernelbase/tests/path.c
+++ b/dlls/kernelbase/tests/path.c
@@ -36,6 +36,7 @@ HRESULT (WINAPI *pPathCchAddExtension)(WCHAR *path, SIZE_T size, const WCHAR *ex
HRESULT (WINAPI *pPathCchCombineEx)(WCHAR *out, SIZE_T size, const WCHAR *path1, const WCHAR *path2, DWORD flags);
HRESULT (WINAPI *pPathCchFindExtension)(const WCHAR *path, SIZE_T size, const WCHAR **extension);
BOOL (WINAPI *pPathCchIsRoot)(const WCHAR *path);
+HRESULT (WINAPI *pPathCchRemoveBackslashEx)(WCHAR *path, SIZE_T path_size, WCHAR **path_end, SIZE_T *free_size);
HRESULT (WINAPI *pPathCchRemoveExtension)(WCHAR *path, SIZE_T size);
HRESULT (WINAPI *pPathCchRenameExtension)(WCHAR *path, SIZE_T size, const WCHAR *extension);
HRESULT (WINAPI *pPathCchSkipRoot)(const WCHAR *path, const WCHAR **root_end);
@@ -544,6 +545,119 @@ static void test_PathCchIsRoot(void)
}
}
+struct removebackslashex_test
+{
+ const CHAR *path_in;
+ const CHAR *path_out;
+ int end_offset;
+ SIZE_T free_size;
+ HRESULT hr;
+};
+
+static const struct removebackslashex_test removebackslashex_tests [] =
+{
+ {"", "", 0, 1, S_FALSE},
+ {"C", "C", 1, 1, S_FALSE},
+ {"C\\", "C", 1, 2, S_OK},
+ {"C:", "C:", 2, 1, S_FALSE},
+ {"C:\\", "C:\\", 2, 2, S_FALSE},
+ {"C:\\\\", "C:\\", 3, 2, S_OK},
+ {"C:\\a\\", "C:\\a", 4, 2, S_OK},
+ {"C:\\a\\\\", "C:\\a\\", 5, 2, S_OK},
+ {"\\", "\\", 0, 2, S_FALSE},
+ {"\\\\", "\\\\", 1, 2, S_FALSE},
+ {"\\?\\", "\\?", 2, 2, S_OK},
+ {"\\?\\\\", "\\?\\", 3, 2, S_OK},
+ {"\\a\\", "\\a", 2, 2, S_OK},
+ {"\\a\\\\", "\\a\\", 3, 2, S_OK},
+ {"\\\\a\\", "\\\\a", 3, 2, S_OK},
+ {"\\\\a\\b\\", "\\\\a\\b", 5, 2, S_OK},
+ {"\\\\a\\\\", "\\\\a\\", 4, 2, S_OK},
+ {"\\\\?\\", "\\\\?", 3, 2, S_OK},
+ {"\\\\?\\\\", "\\\\?\\", 4, 2, S_OK},
+ {"\\\\?\\C:", "\\\\?\\C:", 6, 1, S_FALSE},
+ {"\\\\?\\C:\\", "\\\\?\\C:\\", 6, 2, S_FALSE},
+ {"\\?\\UNC\\", "\\?\\UNC", 6, 2, S_OK},
+ {"\\\\?\\UNC", "\\\\?\\UNC", 7, 1, S_FALSE},
+ {"\\\\?\\UNC\\", "\\\\?\\UNC\\", 7, 2, S_FALSE},
+ {"\\\\?\\UNC\\a", "\\\\?\\UNC\\a", 9, 1, S_FALSE},
+ {"\\\\?\\UNC\\a\\", "\\\\?\\UNC\\a", 9, 2, S_OK},
+ {"\\\\?\\UNC\\a\\b\\", "\\\\?\\UNC\\a\\b", 11, 2, S_OK},
+ {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}",
+ "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}", 48, 1, S_FALSE},
+ {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\",
+ "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\", 48, 2, S_FALSE},
+ {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\a",
+ "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\a", 50, 1, S_FALSE},
+ {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\a\\",
+ "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\a", 50, 2, S_OK}
+};
+
+static void test_PathCchRemoveBackslashEx(void)
+{
+ WCHAR pathW[PATHCCH_MAX_CCH];
+ CHAR pathA[PATHCCH_MAX_CCH];
+ WCHAR *path_end;
+ SIZE_T path_size, free_size;
+ HRESULT hr;
+ INT i;
+
+ if (!pPathCchRemoveBackslashEx)
+ {
+ win_skip("PathCchRemoveBackslashEx() is not available.\n");
+ return;
+ }
+
+ /* No NULL check for path on Windows */
+ if (0)
+ {
+ hr = pPathCchRemoveBackslashEx(NULL, 0, &path_end, &path_size);
+ ok(hr == E_INVALIDARG, "expect hr %#x, got %#x\n", E_INVALIDARG, hr);
+ }
+
+ path_size = MultiByteToWideChar(CP_ACP, 0, "C:\\a\\", -1, pathW, ARRAY_SIZE(pathW));
+ hr = pPathCchRemoveBackslashEx(pathW, 0, &path_end, &path_size);
+ ok(hr == E_INVALIDARG, "expect hr %#x, got %#x\n", E_INVALIDARG, hr);
+
+ free_size = 0xdeadbeef;
+ hr = pPathCchRemoveBackslashEx(pathW, path_size, NULL, &free_size);
+ ok(hr == E_INVALIDARG, "expect hr %#x, got %#x\n", E_INVALIDARG, hr);
+ ok(free_size == 0, "expect %d, got %lu\n", 0, free_size);
+
+ path_end = (WCHAR *)0xdeadbeef;
+ hr = pPathCchRemoveBackslashEx(pathW, path_size, &path_end, NULL);
+ ok(hr == E_INVALIDARG, "expect hr %#x, got %#x\n", E_INVALIDARG, hr);
+ ok(path_end == NULL, "expect null, got %p\n", path_end);
+
+ hr = pPathCchRemoveBackslashEx(pathW, PATHCCH_MAX_CCH + 1, &path_end, &free_size);
+ ok(hr == S_OK, "expect hr %#x, got %#x\n", S_OK, hr);
+
+ hr = pPathCchRemoveBackslashEx(pathW, PATHCCH_MAX_CCH, &path_end, &free_size);
+ ok(hr == S_FALSE, "expect hr %#x, got %#x\n", S_FALSE, hr);
+
+ /* Size < original path length + 1, don't read beyond size */
+ MultiByteToWideChar(CP_ACP, 0, "C:\\a", -1, pathW, ARRAY_SIZE(pathW));
+ hr = pPathCchRemoveBackslashEx(pathW, ARRAY_SIZE("C:\\a") - 1, &path_end, &free_size);
+ ok(hr == E_INVALIDARG, "expect result %#x, got %#x\n", E_INVALIDARG, hr);
+
+ for (i = 0; i < ARRAY_SIZE(removebackslashex_tests); i++)
+ {
+ const struct removebackslashex_test *t = removebackslashex_tests + i;
+ path_size = MultiByteToWideChar(CP_ACP, 0, t->path_in, -1, pathW, ARRAY_SIZE(pathW));
+ hr = pPathCchRemoveBackslashEx(pathW, path_size, &path_end, &free_size);
+ ok(hr == t->hr, "path %s expect result %#x, got %#x\n", t->path_in, t->hr, hr);
+ if (SUCCEEDED(hr))
+ {
+ ok(path_end - pathW == t->end_offset, "path %s expect end offset %d, got %d\n", t->path_in, t->end_offset,
+ path_end - pathW);
+ ok(free_size == t->free_size, "path %s expect free size %lu, got %lu\n", t->path_in, t->free_size, free_size);
+ WideCharToMultiByte(CP_ACP, 0, pathW, -1, pathA, ARRAY_SIZE(pathA), NULL, NULL);
+ ok(!lstrcmpA(pathA, t->path_out), "path %s expect output path %s, got %s\n", t->path_in, t->path_out,
+ pathA);
+ }
+ }
+}
+
struct removeextension_test
{
const CHAR *path;
@@ -1107,6 +1221,7 @@ START_TEST(path)
pPathCchAddExtension = (void *)GetProcAddress(hmod, "PathCchAddExtension");
pPathCchFindExtension = (void *)GetProcAddress(hmod, "PathCchFindExtension");
pPathCchIsRoot = (void *)GetProcAddress(hmod, "PathCchIsRoot");
+ pPathCchRemoveBackslashEx = (void *)GetProcAddress(hmod, "PathCchRemoveBackslashEx");
pPathCchRemoveExtension = (void *)GetProcAddress(hmod, "PathCchRemoveExtension");
pPathCchRenameExtension = (void *)GetProcAddress(hmod, "PathCchRenameExtension");
pPathCchSkipRoot = (void *)GetProcAddress(hmod, "PathCchSkipRoot");
@@ -1120,6 +1235,7 @@ START_TEST(path)
test_PathCchAddExtension();
test_PathCchFindExtension();
test_PathCchIsRoot();
+ test_PathCchRemoveBackslashEx();
test_PathCchRemoveExtension();
test_PathCchRenameExtension();
test_PathCchSkipRoot();
diff --git a/include/pathcch.h b/include/pathcch.h
index 443ccd3a4f..f7de815d16 100644
--- a/include/pathcch.h
+++ b/include/pathcch.h
@@ -31,6 +31,7 @@ HRESULT WINAPI PathCchAddExtension(WCHAR *path, SIZE_T size, const WCHAR *extens
HRESULT WINAPI PathCchCombineEx(WCHAR *out, SIZE_T size, const WCHAR *path1, const WCHAR *path2, DWORD flags);
HRESULT WINAPI PathCchFindExtension(const WCHAR *path, SIZE_T size, const WCHAR **extension);
BOOL WINAPI PathCchIsRoot(const WCHAR *path);
+HRESULT WINAPI PathCchRemoveBackslashEx(WCHAR *path, SIZE_T path_size, WCHAR **path_end, SIZE_T *free_size);
HRESULT WINAPI PathCchRemoveExtension(WCHAR *path, SIZE_T size);
HRESULT WINAPI PathCchRenameExtension(WCHAR *path, SIZE_T size, const WCHAR *extension);
HRESULT WINAPI PathCchSkipRoot(const WCHAR *path, const WCHAR **root_end);
--
2.19.1
1
0
[PATCH 7/7] winhttp: Return an error from WinHttpReceiveResponse if there's no connection.
by Hans Leidekker 22 Nov '18
by Hans Leidekker 22 Nov '18
22 Nov '18
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=46175
Signed-off-by: Hans Leidekker <hans(a)codeweavers.com>
---
dlls/winhttp/request.c | 6 ++++++
dlls/winhttp/tests/winhttp.c | 5 +++++
2 files changed, 11 insertions(+)
diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c
index 54173f1ff4..27628c3292 100644
--- a/dlls/winhttp/request.c
+++ b/dlls/winhttp/request.c
@@ -2736,6 +2736,12 @@ static BOOL receive_response( struct request *request, BOOL async )
BOOL ret;
DWORD size, query, status;
+ if (!request->netconn)
+ {
+ SetLastError( ERROR_WINHTTP_INCORRECT_HANDLE_STATE );
+ return FALSE;
+ }
+
netconn_set_timeout( request->netconn, FALSE, request->receive_response_timeout );
for (;;)
{
diff --git a/dlls/winhttp/tests/winhttp.c b/dlls/winhttp/tests/winhttp.c
index 4779cfd1a7..3f9125154f 100644
--- a/dlls/winhttp/tests/winhttp.c
+++ b/dlls/winhttp/tests/winhttp.c
@@ -2086,6 +2086,11 @@ static void test_resolve_timeout(void)
ok(GetLastError() == ERROR_WINHTTP_NAME_NOT_RESOLVED,
"expected ERROR_WINHTTP_NAME_NOT_RESOLVED got %u\n", GetLastError());
+ ret = WinHttpReceiveResponse( req, NULL );
+ ok( !ret && (GetLastError() == ERROR_WINHTTP_INCORRECT_HANDLE_STATE ||
+ GetLastError() == ERROR_WINHTTP_OPERATION_CANCELLED /* < win7 */),
+ "got %u\n", GetLastError() );
+
WinHttpCloseHandle(req);
WinHttpCloseHandle(con);
WinHttpCloseHandle(ses);
--
2.11.0
2
1