diff --git a/dlls/kernel/change.c b/dlls/kernel/change.c
index 8a740a01b23..3a59a5e626d 100644
--- a/dlls/kernel/change.c
+++ b/dlls/kernel/change.c
@@ -27,6 +27,7 @@
 #include "windef.h"
 #include "winbase.h"
 #include "winerror.h"
+#include "ntstatus.h"
 #include "wine/windef16.h"
 #include "wine/server.h"
 #include "wine/debug.h"
@@ -39,23 +40,15 @@ WINE_DEFAULT_DEBUG_CHANNEL(file);
 HANDLE WINAPI FindFirstChangeNotificationA( LPCSTR lpPathName, BOOL bWatchSubtree,
                                             DWORD dwNotifyFilter )
 {
-    HANDLE file, ret = INVALID_HANDLE_VALUE;
+    UNICODE_STRING pathW;
+    HANDLE ret = INVALID_HANDLE_VALUE;
 
-    TRACE( "%s %d %lx\n", debugstr_a(lpPathName), bWatchSubtree, dwNotifyFilter );
-
-    if ((file = CreateFileA( lpPathName, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
-                             OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 )) == INVALID_HANDLE_VALUE)
-        return INVALID_HANDLE_VALUE;
-
-    SERVER_START_REQ( create_change_notification )
+    if (RtlCreateUnicodeStringFromAsciiz( &pathW, lpPathName ))
     {
-        req->handle  = file;
-        req->subtree = bWatchSubtree;
-        req->filter  = dwNotifyFilter;
-        if (!wine_server_call_err( req )) ret = reply->handle;
+        ret = FindFirstChangeNotificationW( pathW.Buffer, bWatchSubtree, dwNotifyFilter );
+        RtlFreeUnicodeString( &pathW );
     }
-    SERVER_END_REQ;
-    CloseHandle( file );
+    else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
     return ret;
 }
 
@@ -65,13 +58,36 @@ HANDLE WINAPI FindFirstChangeNotificationA( LPCSTR lpPathName, BOOL bWatchSubtre
 HANDLE WINAPI FindFirstChangeNotificationW( LPCWSTR lpPathName, BOOL bWatchSubtree,
                                             DWORD dwNotifyFilter)
 {
+    UNICODE_STRING nt_name;
+    OBJECT_ATTRIBUTES attr;
+    IO_STATUS_BLOCK io;
+    NTSTATUS status;
     HANDLE file, ret = INVALID_HANDLE_VALUE;
 
     TRACE( "%s %d %lx\n", debugstr_w(lpPathName), bWatchSubtree, dwNotifyFilter );
 
-    if ((file = CreateFileW( lpPathName, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
-                             OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 )) == INVALID_HANDLE_VALUE)
+    if (!RtlDosPathNameToNtPathName_U( lpPathName, &nt_name, NULL, NULL ))
+    {
+        SetLastError( ERROR_PATH_NOT_FOUND );
         return INVALID_HANDLE_VALUE;
+    }
+
+    attr.Length = sizeof(attr);
+    attr.RootDirectory = 0;
+    attr.Attributes = OBJ_CASE_INSENSITIVE;
+    attr.ObjectName = &nt_name;
+    attr.SecurityDescriptor = NULL;
+    attr.SecurityQualityOfService = NULL;
+
+    status = NtOpenFile( &file, 0, &attr, &io, 0,
+                         FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT );
+    RtlFreeUnicodeString( &nt_name );
+
+    if (status != STATUS_SUCCESS)
+    {
+        SetLastError( RtlNtStatusToDosError(status) );
+        return INVALID_HANDLE_VALUE;
+    }
 
     SERVER_START_REQ( create_change_notification )
     {
diff --git a/dlls/kernel/file.c b/dlls/kernel/file.c
index ded6a64e0fc..8dfeb9888f1 100644
--- a/dlls/kernel/file.c
+++ b/dlls/kernel/file.c
@@ -626,10 +626,12 @@ HANDLE WINAPI FindFirstFileExW( LPCWSTR filename, FINDEX_INFO_LEVELS level,
                                 LPVOID data, FINDEX_SEARCH_OPS search_op,
                                 LPVOID filter, DWORD flags)
 {
-    WCHAR buffer[MAX_PATH];
-    WCHAR *mask, *tmp = buffer;
+    WCHAR *mask, *p;
     FIND_FIRST_INFO *info = NULL;
-    DWORD size;
+    UNICODE_STRING nt_name;
+    OBJECT_ATTRIBUTES attr;
+    IO_STATUS_BLOCK io;
+    NTSTATUS status;
 
     if ((search_op != FindExSearchNameMatch) || (flags != 0))
     {
@@ -641,22 +643,12 @@ HANDLE WINAPI FindFirstFileExW( LPCWSTR filename, FINDEX_INFO_LEVELS level,
         FIXME("info level %d not implemented\n", level );
         return INVALID_HANDLE_VALUE;
     }
-    size = RtlGetFullPathName_U( filename, sizeof(buffer), buffer, &mask );
-    if (!size)
+
+    if (!RtlDosPathNameToNtPathName_U( filename, &nt_name, &mask, NULL ))
     {
         SetLastError( ERROR_PATH_NOT_FOUND );
         return INVALID_HANDLE_VALUE;
     }
-    if (size > sizeof(buffer))
-    {
-        tmp = HeapAlloc( GetProcessHeap(), 0, size );
-        if (!tmp)
-        {
-            SetLastError( ERROR_NOT_ENOUGH_MEMORY );
-            return INVALID_HANDLE_VALUE;
-        }
-        size = RtlGetFullPathName_U( filename, size, tmp, &mask );
-    }
 
     if (!mask || !*mask)
     {
@@ -675,29 +667,43 @@ HANDLE WINAPI FindFirstFileExW( LPCWSTR filename, FINDEX_INFO_LEVELS level,
         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
         goto error;
     }
+
+    /* truncate dir name before mask */
     *mask = 0;
+    nt_name.Length = (mask - nt_name.Buffer) * sizeof(WCHAR);
 
     /* check if path is the root of the drive */
     info->is_root = FALSE;
-    if (tmp[0] && tmp[1] == ':')
+    p = nt_name.Buffer + 4;  /* skip \??\ prefix */
+    if (p[0] && p[1] == ':')
     {
-        WCHAR *p = tmp + 2;
+        p += 2;
         while (*p == '\\') p++;
         info->is_root = (*p == 0);
     }
 
-    info->handle = CreateFileW( tmp, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
-                                OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 );
-    if (info->handle == INVALID_HANDLE_VALUE)
+    attr.Length = sizeof(attr);
+    attr.RootDirectory = 0;
+    attr.Attributes = OBJ_CASE_INSENSITIVE;
+    attr.ObjectName = &nt_name;
+    attr.SecurityDescriptor = NULL;
+    attr.SecurityQualityOfService = NULL;
+
+    status = NtOpenFile( &info->handle, GENERIC_READ, &attr, &io,
+                         FILE_SHARE_READ | FILE_SHARE_WRITE,
+                         FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT );
+
+    if (status != STATUS_SUCCESS)
     {
         RtlFreeUnicodeString( &info->mask );
+        SetLastError( RtlNtStatusToDosError(status) );
         goto error;
     }
+    RtlFreeUnicodeString( &nt_name );
 
     RtlInitializeCriticalSection( &info->cs );
     info->data_pos = 0;
     info->data_len = 0;
-    if (tmp != buffer) HeapFree( GetProcessHeap(), 0, tmp );
 
     if (!FindNextFileW( (HANDLE)info, data ))
     {
@@ -709,8 +715,8 @@ HANDLE WINAPI FindFirstFileExW( LPCWSTR filename, FINDEX_INFO_LEVELS level,
     return (HANDLE)info;
 
 error:
-    if (tmp != buffer) HeapFree( GetProcessHeap(), 0, tmp );
     if (info) HeapFree( GetProcessHeap(), 0, info );
+    RtlFreeUnicodeString( &nt_name );
     return INVALID_HANDLE_VALUE;
 }