bug-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: 21.x feature request: windows shortcut support


From: Steve Kemp
Subject: Re: 21.x feature request: windows shortcut support
Date: 10 Oct 2001 03:49:56 -0700

rms@gnu.org (Richard Stallman) wrote:
> Support for non-GNU-like systems is low priority for us.  If you want
> to implement this, we will probably merge it in, if a Windows
> maintainer likes the code.

  I actually put together some code to do this a while back - its 
 something I've been meaning to post for a while, to gnu.emacs.sources
 / gnu.emacs.bugs.

  Anyway, below is a patch to implement `w32-resolve-shortcut', 
 usage is something like this:

  (setq target (w32-resolve-shortcut "d:/t.lnk"))

  Once you have this function the resolving of files on loading 
 becomes trivial.

  The patch is a bit longer than I like, because the inclusion of
 a Windows header file needed for the definitions of IShellLink, etc,
 caused conficts over the names of some enum members, so I had to
 rename them.

  Context diff follows.

  (The code could be improved, but is functional, and handles 
 errors appropriately).

Steve
---
# GNU Stuff on Windows.
http://GNUSoftware.com/


diff --recursive --context emacs-20.7-orig/src/makefile.nt
emacs-20.7/src/makefile.nt
*** emacs-20.7-orig/src/makefile.nt     Wed Oct 10 09:20:33 2001
--- emacs-20.7/src/makefile.nt  Wed Oct 10 10:33:10 2001
***************
*** 174,179 ****
--- 174,180 ----
        user32.lib      \
        mpr.lib         \
        shell32.lib     \
+       ole32.lib       \
        setargv.obj
  
  #

diff --recursive --context emacs-20.7-orig/src/w32fns.c
emacs-20.7/src/w32fns.c
*** emacs-20.7-orig/src/w32fns.c        Wed Oct 10 09:20:36 2001
--- emacs-20.7/src/w32fns.c     Wed Oct 10 10:39:27 2001
***************
*** 44,49 ****
--- 44,51 ----
  
  #include <commdlg.h>
  #include <shellapi.h>
+ #include <windows.h>
+ #include <shlobj.h>
  
  extern void abort ();
  extern void free_frame_menubar ();
***************
*** 2653,2659 ****
  /* Types we might convert a resource string into.  */
  enum resource_types
    {
!     number, boolean, string, symbol
    };
  
  /* Return the value of parameter PARAM.
--- 2655,2661 ----
  /* Types we might convert a resource string into.  */
  enum resource_types
    {
!     w32_number, w32_boolean, w32_string, w32_symbol
    };
  
  /* Return the value of parameter PARAM.
***************
*** 2693,2702 ****
  
          switch (type)
            {
!           case number:
              return make_number (atoi (XSTRING (tem)->data));
  
!           case boolean:
              tem = Fdowncase (tem);
              if (!strcmp (XSTRING (tem)->data, "on")
                  || !strcmp (XSTRING (tem)->data, "true"))
--- 2695,2704 ----
  
          switch (type)
            {
!           case w32_number:
              return make_number (atoi (XSTRING (tem)->data));
  
!           case w32_boolean:
              tem = Fdowncase (tem);
              if (!strcmp (XSTRING (tem)->data, "on")
                  || !strcmp (XSTRING (tem)->data, "true"))
***************
*** 2704,2713 ****
              else 
                return Qnil;
  
!           case string:
              return tem;
  
!           case symbol:
              /* As a special case, we map the values `true' and `on'
                 to Qt, and `false' and `off' to Qnil.  */
              {
--- 2706,2715 ----
              else 
                return Qnil;
  
!           case w32_string:
              return tem;
  
!           case w32_symbol:
              /* As a special case, we map the values `true' and `on'
                 to Qt, and `false' and `off' to Qnil.  */
              {
***************
*** 2840,2848 ****
    f->output_data.w32->top_pos = 0;
    f->output_data.w32->left_pos = 0;
  
!   tem0 = x_get_arg (parms, Qheight, 0, 0, number);
!   tem1 = x_get_arg (parms, Qwidth, 0, 0, number);
!   tem2 = x_get_arg (parms, Quser_size, 0, 0, number);
    if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
      {
        if (!EQ (tem0, Qunbound))
--- 2842,2850 ----
    f->output_data.w32->top_pos = 0;
    f->output_data.w32->left_pos = 0;
  
!   tem0 = x_get_arg (parms, Qheight, 0, 0, w32_number);
!   tem1 = x_get_arg (parms, Qwidth, 0, 0, w32_number);
!   tem2 = x_get_arg (parms, Quser_size, 0, 0, w32_number);
    if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
      {
        if (!EQ (tem0, Qunbound))
***************
*** 2870,2878 ****
    f->output_data.w32->pixel_width = CHAR_TO_PIXEL_WIDTH (f,
f->width);
    f->output_data.w32->pixel_height = CHAR_TO_PIXEL_HEIGHT (f,
f->height);
  
!   tem0 = x_get_arg (parms, Qtop, 0, 0, number);
!   tem1 = x_get_arg (parms, Qleft, 0, 0, number);
!   tem2 = x_get_arg (parms, Quser_position, 0, 0, number);
    if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
      {
        if (EQ (tem0, Qminus))
--- 2872,2880 ----
    f->output_data.w32->pixel_width = CHAR_TO_PIXEL_WIDTH (f,
f->width);
    f->output_data.w32->pixel_height = CHAR_TO_PIXEL_HEIGHT (f,
f->height);
  
!   tem0 = x_get_arg (parms, Qtop, 0, 0, w32_number);
!   tem1 = x_get_arg (parms, Qleft, 0, 0, w32_number);
!   tem2 = x_get_arg (parms, Quser_position, 0, 0, w32_number);
    if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
      {
        if (EQ (tem0, Qminus))
***************
*** 4670,4677 ****
  
    /* Set the position of the icon.  Note that Windows 95 groups all
       icons in the tray.  */
!   icon_x = x_get_arg (parms, Qicon_left, 0, 0, number);
!   icon_y = x_get_arg (parms, Qicon_top, 0, 0, number);
    if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
      {
        CHECK_NUMBER (icon_x, 0);
--- 4672,4679 ----
  
    /* Set the position of the icon.  Note that Windows 95 groups all
       icons in the tray.  */
!   icon_x = x_get_arg (parms, Qicon_left, 0, 0, w32_number);
!   icon_y = x_get_arg (parms, Qicon_top, 0, 0, w32_number);
    if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
      {
        CHECK_NUMBER (icon_x, 0);
***************
*** 4688,4694 ****
  #if 0 /* TODO */
    /* Start up iconic or window? */
    x_wm_set_window_state
!     (f, (EQ (x_get_arg (parms, Qvisibility, 0, 0, symbol), Qicon)
         ? IconicState
         : NormalState));
  
--- 4690,4696 ----
  #if 0 /* TODO */
    /* Start up iconic or window? */
    x_wm_set_window_state
!     (f, (EQ (x_get_arg (parms, Qvisibility, 0, 0, w32_symbol),
Qicon)
         ? IconicState
         : NormalState));
  
***************
*** 4733,4739 ****
       until we know if this frame has a specified name.  */
    Vx_resource_name = Vinvocation_name;
  
!   display = x_get_arg (parms, Qdisplay, 0, 0, string);
    if (EQ (display, Qunbound))
      display = Qnil;
    dpyinfo = check_x_display_info (display);
--- 4735,4741 ----
       until we know if this frame has a specified name.  */
    Vx_resource_name = Vinvocation_name;
  
!   display = x_get_arg (parms, Qdisplay, 0, 0, w32_string);
    if (EQ (display, Qunbound))
      display = Qnil;
    dpyinfo = check_x_display_info (display);
***************
*** 4743,4749 ****
    kb = &the_only_kboard;
  #endif
  
!   name = x_get_arg (parms, Qname, "name", "Name", string);
    if (!STRINGP (name)
        && ! EQ (name, Qunbound)
        && ! NILP (name))
--- 4745,4751 ----
    kb = &the_only_kboard;
  #endif
  
!   name = x_get_arg (parms, Qname, "name", "Name", w32_string);
    if (!STRINGP (name)
        && ! EQ (name, Qunbound)
        && ! NILP (name))
***************
*** 4753,4759 ****
      Vx_resource_name = name;
  
    /* See if parent window is specified.  */
!   parent = x_get_arg (parms, Qparent_id, NULL, NULL, number);
    if (EQ (parent, Qunbound))
      parent = Qnil;
    if (! NILP (parent))
--- 4755,4761 ----
      Vx_resource_name = name;
  
    /* See if parent window is specified.  */
!   parent = x_get_arg (parms, Qparent_id, NULL, NULL, w32_number);
    if (EQ (parent, Qunbound))
      parent = Qnil;
    if (! NILP (parent))
***************
*** 4764,4770 ****
       it to make_frame_without_minibuffer.  */
    frame = Qnil;
    GCPRO4 (parms, parent, name, frame);
!   tem = x_get_arg (parms, Qminibuffer, 0, 0, symbol);
    if (EQ (tem, Qnone) || NILP (tem))
      f = make_frame_without_minibuffer (Qnil, kb, display);
    else if (EQ (tem, Qonly))
--- 4766,4772 ----
       it to make_frame_without_minibuffer.  */
    frame = Qnil;
    GCPRO4 (parms, parent, name, frame);
!   tem = x_get_arg (parms, Qminibuffer, 0, 0, w32_symbol);
    if (EQ (tem, Qnone) || NILP (tem))
      f = make_frame_without_minibuffer (Qnil, kb, display);
    else if (EQ (tem, Qonly))
***************
*** 4791,4797 ****
    FRAME_FONTSET (f) = -1;
  
    f->icon_name
!     = x_get_arg (parms, Qicon_name, "iconName", "Title", string);
    if (! STRINGP (f->icon_name))
      f->icon_name = Qnil;
  
--- 4793,4799 ----
    FRAME_FONTSET (f) = -1;
  
    f->icon_name
!     = x_get_arg (parms, Qicon_name, "iconName", "Title",
w32_string);
    if (! STRINGP (f->icon_name))
      f->icon_name = Qnil;
  
***************
*** 4840,4846 ****
    {
      Lisp_Object font;
  
!     font = x_get_arg (parms, Qfont, "font", "Font", string);
      BLOCK_INPUT;
      /* First, try whatever font the caller has specified.  */
      if (STRINGP (font))
--- 4842,4848 ----
    {
      Lisp_Object font;
  
!     font = x_get_arg (parms, Qfont, "font", "Font", w32_string);
      BLOCK_INPUT;
      /* First, try whatever font the caller has specified.  */
      if (STRINGP (font))
***************
*** 4864,4874 ****
        font = build_string ("Fixedsys");
  
      x_default_parameter (f, parms, Qfont, font, 
!                        "font", "Font", string);
    }
  
    x_default_parameter (f, parms, Qborder_width, make_number (2),
!                      "borderwidth", "BorderWidth", number);
    /* This defaults to 2 in order to match xterm.  We recognize
either
       internalBorderWidth or internalBorder (which is what xterm
calls
       it).  */
--- 4866,4876 ----
        font = build_string ("Fixedsys");
  
      x_default_parameter (f, parms, Qfont, font, 
!                        "font", "Font", w32_string);
    }
  
    x_default_parameter (f, parms, Qborder_width, make_number (2),
!                      "borderwidth", "BorderWidth", w32_number);
    /* This defaults to 2 in order to match xterm.  We recognize
either
       internalBorderWidth or internalBorder (which is what xterm
calls
       it).  */
***************
*** 4877,4913 ****
        Lisp_Object value;
  
        value = x_get_arg (parms, Qinternal_border_width,
!                        "internalBorder", "BorderWidth", number);
        if (! EQ (value, Qunbound))
        parms = Fcons (Fcons (Qinternal_border_width, value),
                       parms);
      }
    /* Default internalBorderWidth to 0 on Windows to match other
programs.  */
    x_default_parameter (f, parms, Qinternal_border_width, make_number
(0),
!                      "internalBorderWidth", "BorderWidth", number);
    x_default_parameter (f, parms, Qvertical_scroll_bars, Qt,
!                      "verticalScrollBars", "ScrollBars", boolean);
  
    /* Also do the stuff which must be set before the window exists. 
*/
    x_default_parameter (f, parms, Qforeground_color, build_string
("black"),
!                      "foreground", "Foreground", string);
    x_default_parameter (f, parms, Qbackground_color, build_string
("white"),
!                      "background", "Background", string);
    x_default_parameter (f, parms, Qmouse_color, build_string
("black"),
!                      "pointerColor", "Foreground", string);
    x_default_parameter (f, parms, Qcursor_color, build_string
("black"),
!                      "cursorColor", "Foreground", string);
    x_default_parameter (f, parms, Qborder_color, build_string
("black"),
!                      "borderColor", "BorderColor", string);
  
    x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1),
!                      "menuBar", "MenuBar", number);
    x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
!                      "scrollBarWidth", "ScrollBarWidth", number);
    x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
!                      "bufferPredicate", "BufferPredicate", symbol);
    x_default_parameter (f, parms, Qtitle, Qnil,
!                      "title", "Title", string);
  
    f->output_data.w32->dwStyle = WS_OVERLAPPEDWINDOW;
    f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO
(f)->root_window;
--- 4879,4915 ----
        Lisp_Object value;
  
        value = x_get_arg (parms, Qinternal_border_width,
!                        "internalBorder", "BorderWidth", w32_number);
        if (! EQ (value, Qunbound))
        parms = Fcons (Fcons (Qinternal_border_width, value),
                       parms);
      }
    /* Default internalBorderWidth to 0 on Windows to match other
programs.  */
    x_default_parameter (f, parms, Qinternal_border_width, make_number
(0),
!                      "internalBorderWidth", "BorderWidth", w32_number);
    x_default_parameter (f, parms, Qvertical_scroll_bars, Qt,
!                      "verticalScrollBars", "ScrollBars", w32_boolean);
  
    /* Also do the stuff which must be set before the window exists. 
*/
    x_default_parameter (f, parms, Qforeground_color, build_string
("black"),
!                      "foreground", "Foreground", w32_string);
    x_default_parameter (f, parms, Qbackground_color, build_string
("white"),
!                      "background", "Background", w32_string);
    x_default_parameter (f, parms, Qmouse_color, build_string
("black"),
!                      "pointerColor", "Foreground", w32_string);
    x_default_parameter (f, parms, Qcursor_color, build_string
("black"),
!                      "cursorColor", "Foreground", w32_string);
    x_default_parameter (f, parms, Qborder_color, build_string
("black"),
!                      "borderColor", "BorderColor", w32_string);
  
    x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1),
!                      "menuBar", "MenuBar", w32_number);
    x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
!                      "scrollBarWidth", "ScrollBarWidth", w32_number);
    x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
!                      "bufferPredicate", "BufferPredicate", w32_symbol);
    x_default_parameter (f, parms, Qtitle, Qnil,
!                      "title", "Title", w32_string);
  
    f->output_data.w32->dwStyle = WS_OVERLAPPEDWINDOW;
    f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO
(f)->root_window;
***************
*** 4937,4950 ****
    /* We need to do this after creating the window, so that the
       icon-creation functions can say whose icon they're describing. 
*/
    x_default_parameter (f, parms, Qicon_type, Qnil,
!                      "bitmapIcon", "BitmapIcon", symbol);
  
    x_default_parameter (f, parms, Qauto_raise, Qnil,
!                      "autoRaise", "AutoRaiseLower", boolean);
    x_default_parameter (f, parms, Qauto_lower, Qnil,
!                      "autoLower", "AutoRaiseLower", boolean);
    x_default_parameter (f, parms, Qcursor_type, Qbox,
!                      "cursorType", "CursorType", symbol);
  
    /* Dimensions, especially f->height, must be done via
change_frame_size.
       Change will not be effected unless different from the current
--- 4939,4952 ----
    /* We need to do this after creating the window, so that the
       icon-creation functions can say whose icon they're describing. 
*/
    x_default_parameter (f, parms, Qicon_type, Qnil,
!                      "bitmapIcon", "BitmapIcon", w32_symbol);
  
    x_default_parameter (f, parms, Qauto_raise, Qnil,
!                      "autoRaise", "AutoRaiseLower", w32_boolean);
    x_default_parameter (f, parms, Qauto_lower, Qnil,
!                      "autoLower", "AutoRaiseLower", w32_boolean);
    x_default_parameter (f, parms, Qcursor_type, Qbox,
!                      "cursorType", "CursorType", w32_symbol);
  
    /* Dimensions, especially f->height, must be done via
change_frame_size.
       Change will not be effected unless different from the current
***************
*** 4961,4967 ****
    x_wm_set_size_hint (f, window_prompting, 0);
    UNBLOCK_INPUT;
  
!   tem = x_get_arg (parms, Qunsplittable, 0, 0, boolean);
    f->no_split = minibuffer_only || EQ (tem, Qt);
  
    UNGCPRO;
--- 4963,4969 ----
    x_wm_set_size_hint (f, window_prompting, 0);
    UNBLOCK_INPUT;
  
!   tem = x_get_arg (parms, Qunsplittable, 0, 0, w32_boolean);
    f->no_split = minibuffer_only || EQ (tem, Qt);
  
    UNGCPRO;
***************
*** 4983,4989 ****
      {
        Lisp_Object visibility;
  
!       visibility = x_get_arg (parms, Qvisibility, 0, 0, symbol);
        if (EQ (visibility, Qunbound))
        visibility = Qt;
  
--- 4985,4991 ----
      {
        Lisp_Object visibility;
  
!       visibility = x_get_arg (parms, Qvisibility, 0, 0, w32_symbol);
        if (EQ (visibility, Qunbound))
        visibility = Qt;
  
***************
*** 6983,6988 ****
--- 6985,7079 ----
  
  
  /* These are the w32 specialized functions */
+ DEFUN ("w32-resolve-shortcut", Fw32_resolve_shortcut,
Sw32_resolve_shortcut, 0, 1, 0,
+   "Return the target of a Windows shortcut.\n\
+ Find, and return the target of a Windows shortcut file,\n\
+ returns nil on error.\n\
+ LINKFILE is the name of the link file to resolve.\n")
+      (linkfile)
+      Lisp_Object linkfile;
+ {
+     Lisp_Object target;
+     HRESULT hres;
+     IShellLink* psl;
+ 
+     char szGotPath[MAX_PATH];
+     WIN32_FIND_DATA wfd;
+ 
+     CoInitialize( NULL );
+ 
+     // Get a pointer to the IShellLink interface.
+     hres = CoCreateInstance(&CLSID_ShellLink, NULL,
CLSCTX_INPROC_SERVER,
+                             &IID_IShellLink,  (void**)&psl);
+     if (SUCCEEDED(hres))
+     {
+         IPersistFile* ppf;
+ 
+         // Get a pointer to the IPersistFile interface.
+         hres = psl->lpVtbl->QueryInterface(psl,&IID_IPersistFile,
&ppf);
+         if (SUCCEEDED(hres))
+         {
+             WORD wsz[MAX_PATH];
+ 
+             // Ensure string is Unicode.
+             MultiByteToWideChar(CP_ACP, 0, ((char *) XSTRING
(linkfile)->data), -1, wsz,
+                                 MAX_PATH);
+ 
+             // Load the shell link.
+             hres = ppf->lpVtbl->Load(ppf,wsz, STGM_READ);
+             if (SUCCEEDED(hres))
+             {
+                 // Resolve the link.
+                 hres = psl->lpVtbl->Resolve(psl,NULL,
SLR_ANY_MATCH);
+ 
+                 if (SUCCEEDED(hres))
+                 {
+                     // Get the path to the link target.
+                     hres = psl->lpVtbl->GetPath(psl, szGotPath,
MAX_PATH, (WIN32_FIND_DATA*)&wfd,
+                                         SLGP_UNCPRIORITY);
+                     // Store the result.
+                     target = build_string( szGotPath );
+                 }
+                 else
+                 {
+ #ifdef _DEBUG_LNK_
+                     error("Failed to resolve\n" );
+ #endif                    
+                     return( Qnil );
+                 }
+                 // Release pointer to IPersistFile interface.
+                 ppf->lpVtbl->Release(ppf);
+             }
+             else
+             {
+ #ifdef _DEBUG_LNK_
+                 error("Failed to load\n" );
+ #endif
+                 return Qnil;
+             }
+             // Release pointer to IShellLink interface.
+             psl->lpVtbl->Release(psl);
+         }
+         else
+         {
+ #ifdef _DEBUG_LNK_
+             error("Failed to query interface\n" );
+ #endif
+             return( Qnil );
+         }
+     }
+     else
+     {
+ #ifdef _DEBUG_LNK_
+         error("Failed to create object\n" );
+ #endif
+         return Qnil;
+     }
+ 
+     CoUninitialize();
+ 
+     return target;
+ }
  
  DEFUN ("w32-select-font", Fw32_select_font, Sw32_select_font, 0, 1,
0,
     "This will display the W32 font dialog and return an X font
string corresponding to the selection.")
***************
*** 7632,7638 ****
    defsubr (&Sx_synchronize);
  
    /* W32 specific functions */
! 
    defsubr (&Sw32_focus_frame);
    defsubr (&Sw32_select_font);
    defsubr (&Sw32_define_rgb_color);
--- 7723,7729 ----
    defsubr (&Sx_synchronize);
  
    /* W32 specific functions */
!   defsubr (&Sw32_resolve_shortcut);
    defsubr (&Sw32_focus_frame);
    defsubr (&Sw32_select_font);
    defsubr (&Sw32_define_rgb_color);



reply via email to

[Prev in Thread] Current Thread [Next in Thread]