diff --git a/src/coding.c b/src/coding.c
index 405284f..57f3063 100644
--- a/src/coding.c
+++ b/src/coding.c
@@ -310,7 +310,7 @@ Lisp_Object Qbuffer_file_coding_system;
 Lisp_Object Qpost_read_conversion, Qpre_write_conversion;
 Lisp_Object Qdefault_char;
 Lisp_Object Qno_conversion, Qundecided;
-Lisp_Object Qcharset, Qiso_2022, Qutf_8, Qutf_16, Qshift_jis, Qbig5;
+Lisp_Object Qcharset, Qiso_2022, Qutf_8, Qutf_16, Qutf_16le, Qutf_16be, Qutf_16_le, Qutf_16_be, Qshift_jis, Qbig5;
 Lisp_Object Qbig, Qlittle;
 Lisp_Object Qcoding_system_history;
 Lisp_Object Qvalid_codes;
@@ -10465,6 +10465,10 @@ syms_of_coding ()
   DEFSYM (Qutf_8_emacs, "utf-8-emacs");
 
   DEFSYM (Qutf_16, "utf-16");
+  DEFSYM (Qutf_16_le, "utf-16-le");
+  DEFSYM (Qutf_16_be, "utf-16-be");
+  DEFSYM (Qutf_16le, "utf-16le");
+  DEFSYM (Qutf_16be, "utf-16be");
   DEFSYM (Qbig, "big");
   DEFSYM (Qlittle, "little");
 
diff --git a/src/coding.h b/src/coding.h
index ca8878f..f37fd73 100644
--- a/src/coding.h
+++ b/src/coding.h
@@ -757,6 +757,7 @@ extern Lisp_Object preferred_coding_system P_ (());
 
 
 extern Lisp_Object Qutf_8, Qutf_8_emacs;
+extern Lisp_Object Qutf_16, Qutf_16_le, Qutf_16le, Qutf_16be, Qutf_16_be;
 
 extern Lisp_Object Qcoding_system, Qeol_type, Qcoding_category_index;
 extern Lisp_Object Qcoding_system_p;
diff --git a/src/w32fns.c b/src/w32fns.c
index 8003d79..91cfa5e 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -247,6 +247,8 @@ struct MONITOR_INFO
 DECLARE_HANDLE(HMONITOR);
 #endif
 
+#define HAS_UNICODE_WINDOWS (create_window_ex_unicode_fn != NULL)
+
 typedef BOOL (WINAPI * TrackMouseEvent_Proc)
   (IN OUT LPTRACKMOUSEEVENT lpEventTrack);
 typedef LONG (WINAPI * ImmGetCompositionString_Proc)
@@ -258,6 +260,20 @@ typedef HWND (WINAPI * ImmSetCompositionWindow_Proc) (IN HIMC context,
 typedef HMONITOR (WINAPI * MonitorFromPoint_Proc) (IN POINT pt, IN DWORD flags);
 typedef BOOL (WINAPI * GetMonitorInfo_Proc)
   (IN HMONITOR monitor, OUT struct MONITOR_INFO* info);
+typedef ATOM (WINAPI * RegisterClassW_Proc) (CONST WNDCLASS *lpWndClass);
+typedef HWND (WINAPI * CreateWindowExW_Proc)
+  (DWORD dwExStyle, LPCWSTR lpClassName, LPCWSTR lpWindowName, DWORD dwStyle,
+  int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu,
+  HINSTANCE hInstance, LPVOID lpParam);
+typedef BOOL (WINAPI * SetWindowText_Proc) (HWND hWnd, LPCSTR lpString);
+typedef BOOL (WINAPI * GetMessage_Proc) (LPMSG lpMsg, HWND hWnd, UINT
+                                        wMsgFilterMin, UINT wMsgFilterMax);
+typedef BOOL (WINAPI * MessageProc_Proc) (HWND hWnd, UINT msg,
+                                         WPARAM wParam, LPARAM lParam);
+typedef LRESULT (WINAPI * DispatchMessage_Proc) (const MSG *lpmsg);
+typedef BOOL (WINAPI * PeekMessage_Proc)
+  (LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin,
+  UINT wMsgFilterMax, UINT wRemoveMsg);
 
 TrackMouseEvent_Proc track_mouse_event_fn = NULL;
 ClipboardSequence_Proc clipboard_sequence_fn = NULL;
@@ -267,6 +283,14 @@ ImmReleaseContext_Proc release_ime_context_fn = NULL;
 ImmSetCompositionWindow_Proc set_ime_composition_window_fn = NULL;
 MonitorFromPoint_Proc monitor_from_point_fn = NULL;
 GetMonitorInfo_Proc get_monitor_info_fn = NULL;
+RegisterClassW_Proc register_class_unicode_fn = NULL;
+CreateWindowExW_Proc create_window_ex_unicode_fn = NULL;
+SetWindowText_Proc set_window_text_fn = NULL;
+GetMessage_Proc get_message_fn = NULL;
+MessageProc_Proc post_message_fn = NULL;
+MessageProc_Proc def_window_proc_fn = NULL;
+DispatchMessage_Proc dispatch_message_fn = NULL;
+PeekMessage_Proc peek_message_fn = NULL;
 
 extern AppendMenuW_Proc unicode_append_menu;
 
@@ -1871,11 +1895,18 @@ x_set_name (f, name, explicit)
 
   if (FRAME_W32_WINDOW (f))
     {
-      if (STRING_MULTIBYTE (name))
-	name = ENCODE_SYSTEM (name);
+      /* ensure name is null-terminated */
+      if (SREF (name, SBYTES (name) - 1))
+        name = make_string (SDATA (name), SBYTES (name) + 1);
 
       BLOCK_INPUT;
-      SetWindowText (FRAME_W32_WINDOW (f), SDATA (name));
+      if (HAS_UNICODE_WINDOWS)
+          name = code_convert_string_norecord(name, Qutf_16le, 1);
+      else
+        if (STRING_MULTIBYTE (name))
+          name = ENCODE_SYSTEM (name);
+
+      set_window_text_fn (FRAME_W32_WINDOW (f), SDATA (name));
       UNBLOCK_INPUT;
     }
 }
@@ -1923,11 +1954,18 @@ x_set_title (f, name, old_name)
 
   if (FRAME_W32_WINDOW (f))
     {
-      if (STRING_MULTIBYTE (name))
-	name = ENCODE_SYSTEM (name);
+      /* ensure name is null-terminated */
+      if (SREF (name, SBYTES (name) - 1))
+        name = make_string (SDATA (name), SBYTES (name) + 1);
 
       BLOCK_INPUT;
-      SetWindowText (FRAME_W32_WINDOW (f), SDATA (name));
+      if (HAS_UNICODE_WINDOWS)
+        name = code_convert_string_norecord(name, Qutf_16le, 1);
+      else
+        if (STRING_MULTIBYTE (name))
+          name = ENCODE_SYSTEM (name);
+      
+      set_window_text_fn (FRAME_W32_WINDOW (f), SDATA (name));
       UNBLOCK_INPUT;
     }
 }
@@ -1968,20 +2006,42 @@ static BOOL
 w32_init_class (hinst)
      HINSTANCE hinst;
 {
-  WNDCLASS wc;
-
-  wc.style = CS_HREDRAW | CS_VREDRAW;
-  wc.lpfnWndProc = (WNDPROC) w32_wnd_proc;
-  wc.cbClsExtra = 0;
-  wc.cbWndExtra = WND_EXTRA_BYTES;
-  wc.hInstance = hinst;
-  wc.hIcon = LoadIcon (hinst, EMACS_CLASS);
-  wc.hCursor = w32_load_cursor (IDC_ARROW);
-  wc.hbrBackground = NULL; /* GetStockObject (WHITE_BRUSH);  */
-  wc.lpszMenuName = NULL;
-  wc.lpszClassName = EMACS_CLASS;
-
-  return (RegisterClass (&wc));
+  if (register_class_unicode_fn)
+    {
+      WNDCLASSW wc;
+
+      wc.style = CS_HREDRAW | CS_VREDRAW;
+      wc.lpfnWndProc = (WNDPROC) w32_wnd_proc;
+      wc.cbClsExtra = 0;
+      wc.cbWndExtra = WND_EXTRA_BYTES;
+      wc.hInstance = hinst;
+      wc.hIcon = LoadIcon (hinst, EMACS_CLASS);
+      wc.hCursor = w32_load_cursor (IDC_ARROW);
+      wc.hbrBackground = NULL; /* GetStockObject (WHITE_BRUSH);  */
+      wc.lpszMenuName = NULL;
+
+      Lisp_Object classStr = make_string(EMACS_CLASS, strlen(EMACS_CLASS) + 1);
+      classStr = code_convert_string_norecord(classStr, Qutf_16le, 1);
+      wc.lpszClassName = (LPWSTR) SDATA (classStr);
+      return (register_class_unicode_fn (&wc));
+    }
+  else
+    {
+      WNDCLASSA wc;
+
+      wc.style = CS_HREDRAW | CS_VREDRAW;
+      wc.lpfnWndProc = (WNDPROC) w32_wnd_proc;
+      wc.cbClsExtra = 0;
+      wc.cbWndExtra = WND_EXTRA_BYTES;
+      wc.hInstance = hinst;
+      wc.hIcon = LoadIcon (hinst, EMACS_CLASS);
+      wc.hCursor = w32_load_cursor (IDC_ARROW);
+      wc.hbrBackground = NULL; /* GetStockObject (WHITE_BRUSH);  */
+      wc.lpszMenuName = NULL;
+
+      wc.lpszClassName = EMACS_CLASS;
+      return (RegisterClass (&wc));
+    }
 }
 
 static HWND
@@ -2007,10 +2067,11 @@ w32_createwindow (f)
 {
   HWND hwnd;
   RECT rect;
+  Lisp_Object classStr = make_string (EMACS_CLASS, strlen (EMACS_CLASS) + 1);
+  Lisp_Object nameStr = make_string (f->namebuf, strlen(f->namebuf) + 1);
   Lisp_Object top = Qunbound;
   Lisp_Object left = Qunbound;
   struct w32_display_info *dpyinfo = &one_w32_display_info;
-
   rect.left = rect.top = 0;
   rect.right = FRAME_PIXEL_WIDTH (f);
   rect.bottom = FRAME_PIXEL_HEIGHT (f);
@@ -2038,18 +2099,40 @@ w32_createwindow (f)
       top = x_get_arg (dpyinfo, Qnil, Qtop, "top", "Top", RES_TYPE_NUMBER);
     }
 
-  FRAME_W32_WINDOW (f) = hwnd
-    = CreateWindow (EMACS_CLASS,
-		    f->namebuf,
-		    f->output_data.w32->dwStyle | WS_CLIPCHILDREN,
-		    EQ (left, Qunbound) ? CW_USEDEFAULT : XINT (left),
-		    EQ (top, Qunbound) ? CW_USEDEFAULT : XINT (top),
-		    rect.right - rect.left,
-		    rect.bottom - rect.top,
-		    NULL,
-		    NULL,
-		    hinst,
-		    NULL);
+  if (HAS_UNICODE_WINDOWS)
+    {
+      classStr = code_convert_string_norecord(classStr, Qutf_16le, 1);
+      nameStr = code_convert_string_norecord(nameStr, Qutf_16le, 1);
+      FRAME_W32_WINDOW (f) = hwnd
+        = create_window_ex_unicode_fn (
+          0,
+          (LPWSTR) SDATA (classStr),
+          (LPWSTR) SDATA (nameStr),
+          f->output_data.w32->dwStyle | WS_CLIPCHILDREN,
+          EQ (left, Qunbound) ? CW_USEDEFAULT : XINT (left),
+          EQ (top, Qunbound) ? CW_USEDEFAULT : XINT (top),
+          rect.right - rect.left,
+          rect.bottom - rect.top,
+          NULL,
+          NULL,
+          hinst,
+          NULL);
+    }
+  else
+    {
+      FRAME_W32_WINDOW (f) = hwnd
+        = CreateWindowA (SDATA (classStr),
+                        SDATA (nameStr),
+                        f->output_data.w32->dwStyle | WS_CLIPCHILDREN,
+                        EQ (left, Qunbound) ? CW_USEDEFAULT : XINT (left),
+                        EQ (top, Qunbound) ? CW_USEDEFAULT : XINT (top),
+                        rect.right - rect.left,
+                        rect.bottom - rect.top,
+                        NULL,
+                        NULL,
+                        hinst,
+                        NULL);
+    }
 
   if (hwnd)
     {
@@ -2441,7 +2524,7 @@ w32_msg_pump (deferred_msg * msg_buf)
 
   msh_mousewheel = RegisterWindowMessage (MSH_MOUSEWHEEL);
 
-  while (GetMessage (&msg, NULL, 0, 0))
+  while (get_message_fn (&msg, NULL, 0, 0))
     {
       if (msg.hwnd == NULL)
 	{
@@ -2536,7 +2619,7 @@ w32_msg_pump (deferred_msg * msg_buf)
 	}
       else
 	{
-	  DispatchMessage (&msg);
+          dispatch_message_fn (&msg);
 	}
 
       /* Exit nested loop when our deferred message has completed.  */
@@ -2649,7 +2732,7 @@ w32_msg_worker (void *arg)
 
   /* Ensure our message queue is created */
 
-  PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
+  peek_message_fn (&msg, NULL, 0, 0, PM_NOREMOVE);
 
   if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
     abort ();
@@ -2897,7 +2980,7 @@ w32_wnd_proc (hwnd, msg, wParam, lParam)
 
     case WM_HOTKEY:
       /* Synchronize hot keys with normal input.  */
-      PostMessage (hwnd, WM_KEYDOWN, HIWORD (lParam), 0);
+      post_message_fn (hwnd, WM_KEYDOWN, HIWORD (lParam), 0);
       return (0);
 
     case WM_KEYUP:
@@ -3964,10 +4047,10 @@ w32_wnd_proc (hwnd, msg, wParam, lParam)
 	  {
 	    MSG amsg;
 	    /* Eat any mouse messages during popupmenu */
-	    while (PeekMessage (&amsg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST,
+	    while (peek_message_fn (&amsg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST,
 				PM_REMOVE));
 	    /* Get the menu selection, if any */
-	    if (PeekMessage (&amsg, hwnd, WM_COMMAND, WM_COMMAND, PM_REMOVE))
+	    if (peek_message_fn (&amsg, hwnd, WM_COMMAND, WM_COMMAND, PM_REMOVE))
 	      {
 		retval =  LOWORD (amsg.wParam);
 	      }
@@ -3995,7 +4078,7 @@ w32_wnd_proc (hwnd, msg, wParam, lParam)
 	}
 
     dflt:
-      return DefWindowProc (hwnd, msg, wParam, lParam);
+      return (def_window_proc_fn (hwnd, msg, wParam, lParam));
     }
 
 
@@ -4011,7 +4094,7 @@ my_create_window (f)
 
   if (!PostThreadMessage (dwWindowsThreadId, WM_EMACS_CREATEWINDOW, (WPARAM)f, 0))
     abort ();
-  GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
+  get_message_fn (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
 }
 
 
@@ -6277,7 +6360,7 @@ If optional parameter FRAME is not specified, use selected frame.  */)
 
   CHECK_NUMBER (command);
 
-  PostMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, XINT (command), 0);
+  post_message_fn (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, XINT (command), 0);
 
   return Qnil;
 }
@@ -6508,7 +6591,7 @@ DEFUN ("w32-unregister-hot-key", Fw32_unregister_hot_key,
 #endif
 	{
 	  MSG msg;
-	  GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
+          get_message_fn (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
 	}
       return Qt;
     }
@@ -6588,7 +6671,7 @@ is set to off if the low bit of NEW-STATE is zero, otherwise on.  */)
 #endif
     {
       MSG msg;
-      GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
+      get_message_fn (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
       return make_number (msg.wParam);
     }
   return Qnil;
@@ -7312,6 +7395,22 @@ globals_of_w32fns ()
     GetProcAddress (user32_lib, "MonitorFromPoint");
   get_monitor_info_fn = (GetMonitorInfo_Proc)
     GetProcAddress (user32_lib, "GetMonitorInfoA");
+  register_class_unicode_fn = (RegisterClassW_Proc)
+    GetProcAddress (user32_lib, "RegisterClassW");
+  create_window_ex_unicode_fn = (CreateWindowExW_Proc)
+    GetProcAddress (user32_lib, "CreateWindowExW");
+  set_window_text_fn = (SetWindowText_Proc)
+    GetProcAddress (user32_lib, HAS_UNICODE_WINDOWS ? "SetWindowTextW" : "SetWindowTextA");
+  get_message_fn = (GetMessage_Proc)
+    GetProcAddress (user32_lib, HAS_UNICODE_WINDOWS ? "GetMessageW" : "GetMessageA");
+  post_message_fn = (MessageProc_Proc)
+    GetProcAddress (user32_lib, HAS_UNICODE_WINDOWS ? "PostMessageW" : "PostMessageA");
+  def_window_proc_fn = (MessageProc_Proc)
+    GetProcAddress (user32_lib, HAS_UNICODE_WINDOWS ? "DefWindowProcW" : "DefWindowProcA");
+  dispatch_message_fn = (DispatchMessage_Proc)
+    GetProcAddress (user32_lib, HAS_UNICODE_WINDOWS ? "DispatchMessageW" : "DispatchMessageA");
+  peek_message_fn = (PeekMessage_Proc)
+    GetProcAddress (user32_lib, HAS_UNICODE_WINDOWS ? "PeekMessageW" : "PeekMessageA");
 
   {
     HMODULE imm32_lib = GetModuleHandle ("imm32.dll");
diff --git a/src/w32term.c b/src/w32term.c
index b7642b4..5f28b2b 100644
--- a/src/w32term.c
+++ b/src/w32term.c
@@ -4229,10 +4229,14 @@ w32_read_socket (sd, expected, hold_quit)
 	      XSETFRAME (inev.frame_or_window, f);
 	      inev.timestamp = msg.msg.time;
 
+
               if (msg.msg.message == WM_UNICHAR)
                 {
                   inev.code = msg.msg.wParam;
                 }
+              else if (IsWindowUnicode (msg.msg.hwnd)) {
+                inev.code = msg.msg.wParam;
+              }
               else if (msg.msg.wParam < 256)
                 {
                   wchar_t code;
@@ -4245,7 +4249,7 @@ w32_read_socket (sd, expected, hold_quit)
                       dbcs[0] = dbcs_lead;
                       dbcs_lead = 0;
                       if (!MultiByteToWideChar (keyboard_codepage, 0,
-						dbcs, 2, &code, 1))
+                                               dbcs, 2, &code, 1))
                         {
                           /* Garbage */
                           DebPrint (("Invalid DBCS sequence: %d %d\n",
@@ -4255,7 +4259,7 @@ w32_read_socket (sd, expected, hold_quit)
                         }
                     }
                   else if (IsDBCSLeadByteEx (keyboard_codepage,
-					     (BYTE) msg.msg.wParam))
+                                            (BYTE) msg.msg.wParam))
                     {
                       dbcs_lead = (char) msg.msg.wParam;
                       inev.kind = NO_EVENT;
@@ -4264,7 +4268,7 @@ w32_read_socket (sd, expected, hold_quit)
                   else
                     {
                       if (!MultiByteToWideChar (keyboard_codepage, 0,
-						&dbcs[1], 1, &code, 1))
+                                               &dbcs[1], 1, &code, 1))
                         {
                           /* What to do with garbage? */
                           DebPrint (("Invalid character: %d\n", dbcs[1]));
