Statistics
| Revision:

root / trunk / install / IzPack / src / native / ShellLink.cpp @ 11445

History | View | Annotate | Download (45.5 KB)

1
/*
2
 * IzPack Version 3.0.0 pre4 (build 2002.06.15)
3
 * Copyright (C) 2002 by Elmar Grom
4
 *
5
 * File :               ShellLink.c
6
 * Description :        Represents a MS-Windows Shell Link (shortcut)
7
 *                      This is the native counterpart to ShellLink.java
8
 * Author's email :     elmar@grom.net
9
 * Website :            http://www.izforge.com
10
 *
11
 * This program is free software; you can redistribute it and/or
12
 * modify it under the terms of the GNU General Public License
13
 * as published by the Free Software Foundation; either version 2
14
 * of the License, or any later version.
15
 *
16
 * This program is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
 * GNU General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU General Public License
22
 * along with this program; if not, write to the Free Software
23
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24
 */
25

    
26
#include "com_izforge_izpack_util_os_ShellLink.h"
27
#include <winerror.h>
28
#include <objbase.h>
29
#include <basetyps.h>
30
#include <shlobj.h>
31
#include <objidl.h>
32
#include <windows.h>
33
#include <tchar.h>
34

    
35
// --------------------------------------------------------------------------
36
// Gound rules used for the implementation of this native interface
37
// of ShellLink:
38
//
39
// 1) all functions return an integer success code
40
// 2) positive success codes report that everything went ok
41
// 3) negative success codes report some type of problem
42
// 4) a success code of 0 does not exist
43
// 5) 'get' functions deposit their results in the corresponding member
44
//    variables on the Java side.
45
// 6) "set' functions retrieve their input from the corresponding member
46
//    variables on the Java side.
47
// 7) functions other than 'get' and 'set' recive their input -if any- in
48
//    the form of arguments.
49
// 8) functions that are exposed on the Java side (public, protectd)
50
//    follow the Java naming conventions, in that they begin with a lower
51
//    case character.
52
// 9) all functions that have a Java wrapper by the same name follow the
53
//    Windows naming convention, in that they start with an upper case
54
//    letter. This avoids having to invent new method names for Java and
55
//    it allows to keep a clean naming convention on the Java side.
56
// ============================================================================
57
//
58
// I M P O R T A N T !
59
// -------------------
60
//
61
// This interface communicates with the OS via COM. In order for things to
62
// work properly, it is necessary to observe the following pattern of
63
// operation and to observe the order of execution (i.e. do not call
64
// getInterface() before calling initializeCOM()).
65
//
66
// 1) call initializeCOM() - It's best to do this in the constructor
67
// 2) call getInterface() - It's best to do this in the constructor as well
68
//
69
// 3) do your stuff (load, save, get, set ...)
70
//
71
// 4) call releaseInterface() before terminating the application, best done
72
//    in the finalizer
73
// 5) call releaseCOM() before terminating the application, best done
74
//    in the finalizer. Do NOT call this if the call to initializeCOM() did
75
//    not succeed, otherwise you'll mess things up pretty badly!
76
// ============================================================================
77
// Variables that must be declared on the Java side:
78
//
79
// private int     nativeHandle;
80
//
81
// private String  linkPath;
82
// private String  linkName;
83
//
84
// private String  arguments;
85
// private String  description;
86
// private String  iconPath;
87
// private String  targetPath;
88
// private String  workingDirectory;
89
//
90
// private int     hotkey;
91
// private int     iconIndex;
92
// private int     showCommand;
93
// private int     linkType;
94
// --------------------------------------------------------------------------
95

    
96
// --------------------------------------------------------------------------
97
// Macro Definitions
98
// --------------------------------------------------------------------------
99
#define   ACCESS                0         // index for retrieving the registry access key
100
#define   MIN_KEY               0         // for verifying that an index received in the form of a call parameter is actually leagal
101
#define   MAX_KEY               5         // for verifying that an index received in the form of a call parameter is actually leagal
102

    
103
// --------------------------------------------------------------------------
104
// Prototypes
105
// --------------------------------------------------------------------------
106
// Hey C crowd, don't freak out! ShellLink.h is auto generated and I'd like
107
// to have everything close by in this package. Besides, these are only used
108
// in this file...
109
// --------------------------------------------------------------------------
110
int  getNewHandle ();
111
void freeLinks ();
112

    
113
// --------------------------------------------------------------------------
114
// Constant Definitions
115
// --------------------------------------------------------------------------
116

    
117
// the registry keys to get access to the various shortcut locations for the current user
118
const char CURRENT_USER_KEY [5][100] =
119
{
120
  "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", // this is where the details are stored in the registry
121
  "Desktop",                                                               // this is where desktop shortcuts go
122
  "Programs",                                                              // this is where items of the progams menu go
123
  "Start Menu",                                                            // this is right in the start menu
124
  "Startup"                                                                // this is where stuff goes that should be executed on OS launch
125
};
126

    
127
// the registry keys to get access to the various shortcut locations for all users
128
const char ALL_USER_KEY [5][100] =
129
{
130
  "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", // this is where the details are stored in the registry
131
  "Common Desktop",                                                        // this is where desktop shortcuts go
132
  "Common Programs",                                                       // this is where items of the progams menu go
133
  "Common Start Menu",                                                     // this is right in the start menu
134
  "Common Startup"                                                         // this is where stuff goes that should be executed on OS launch
135
};
136

    
137
// Success Codes
138
const jint  SL_OK                 =  1;     // returned if a call was successful
139
const jint  SL_ERROR              = -1;     // unspecific return if a call was not successful
140
const jint  SL_INITIALIZED        = -2;     // return value from initialization functions if already initialized
141
const jint  SL_NOT_INITIALIZED    = -3;     // return value from uninitialization functions if never initialized
142
const jint  SL_OUT_OF_HANDLES     = -4;     // there are no more interface handles available
143
const jint  SL_NO_IPERSIST        = -5;     // could not get a handle for the IPersist interface
144
const jint  SL_NO_SAVE            = -6;     // could not save the link
145
const jint  SL_WRONG_DATA_TYPE    = -7;     // an unexpected data type has been passed or received
146
const jint  SL_CAN_NOT_READ_PATH  = -8;     // was not able to read the link path from the Windows Registry
147

    
148
const int   MAX_TEXT_LENGTH       =  1000;  // buffer size for text buffers
149
const int   ALLOC_INCREMENT       =  10;    // allocation increment for allocation of additional storage space for link references
150

    
151
// --------------------------------------------------------------------------
152
// Variable Declarations
153
// --------------------------------------------------------------------------
154
int           referenceCount      = 0;
155

    
156
// --------------------------------------------------------
157
// DLLs are not objects!
158
// --------------------
159
// What this means is that if multiple references are made
160
// to the same DLL in the same program space, no new
161
// storage is allocated for the variables in the DLL.
162
// For all practical purposes, variables in DLLs are equal
163
// to static variables in classes - all instances share
164
// the same storage space.
165
// ========================================================
166
// Since this code is designed to operate in conjunction
167
// with a Java class, there is a possibility for multiple
168
// instances of the class to acces this code 'simultaniously'.
169
// As a result, one instance could be modifying the link
170
// data for another instance. To avoid this, I am
171
// artificially creating multiple DLL 'instances' by
172
// providing a storage array for pointers to multiple
173
// instances of IShellLink. Each Java instance must
174
// access its IShellLink through a handle (the array
175
// index where its corresponding pointer is stored).
176
// ========================================================
177
// For details on how this works see:
178
// - getNewHandle()
179
// - freeLinks()
180
// --------------------------------------------------------
181
int           linkCapacity        = 0;      // indicates the current capacity for storing pointers
182
IShellLink**  p_shellLink         = NULL;   // pointers to the IShellLink interface
183

    
184
// --------------------------------------------------------------------------
185
// Gain COM access
186
//
187
// returns: SL_OK       if the initialization was successfull
188
//          SL_ERROR    otherwise
189
//
190
// I M P O R T A N T !!
191
// --------------------
192
//
193
// 1) This method must be called first!
194
// 2) The application must call releaseCOM() just before terminating but
195
//    only if a result of SL_OK was retruned form this function!
196
// --------------------------------------------------------------------------
197
JNIEXPORT jint JNICALL Java_com_izforge_izpack_util_os_ShellLink_initializeCOM (JNIEnv  *env,
198
                                                                                jobject  obj)
199
{
200
  HRESULT hres;
201

    
202
  if (referenceCount > 0)
203
  {
204
    referenceCount++;
205
    return (SL_OK);
206
  }
207

    
208
  hres = CoInitializeEx (NULL, COINIT_APARTMENTTHREADED);
209

    
210
  if (SUCCEEDED (hres))
211
  {
212
    referenceCount++;
213
    return (SL_OK);
214
  }
215

    
216
  return (SL_ERROR);
217
}
218

    
219
// --------------------------------------------------------------------------
220
// Releases COM and frees associated resources. This function should be
221
// called as the very last operation before the application terminates.
222
// Call this function only if a prior call to initializeCOM() returned SL_OK.
223
//
224
// returns: SL_OK               under normal circumstances
225
//          SL_NOT_INITIALIZED  if the reference count indicates that no
226
//                              current users exist.
227
// --------------------------------------------------------------------------
228
JNIEXPORT jint JNICALL Java_com_izforge_izpack_util_os_ShellLink_releaseCOM (JNIEnv  *env,
229
                                                                             jobject  obj)
230
{
231
  referenceCount--;
232

    
233
  if (referenceCount == 0)
234
  {
235
    CoUninitialize ();
236
    // This is the end of things, so this is a good time to
237
    // free the storage for the IShellLink pointers.
238
    freeLinks ();
239
    return (SL_OK);
240
  }
241
  else if (referenceCount < 0)
242
  {
243
    referenceCount++;
244
    return (SL_NOT_INITIALIZED);
245
  }
246
  else
247
  {
248
    return (SL_OK);
249
  }
250
}
251

    
252
// --------------------------------------------------------------------------
253
// This function gains access to the ISchellLink interface. It must be
254
// called before any other calls can be made but after initializeCOM().
255
//
256
// I M P O R T A N T !!
257
// --------------------
258
//
259
// releaseInterface() must be called before terminating the application!
260
// --------------------------------------------------------------------------
261
JNIEXPORT jint JNICALL Java_com_izforge_izpack_util_os_ShellLink_getInterface (JNIEnv  *env,
262
                                                                               jobject  obj)
263
{
264
  HRESULT hres;
265
  int     handle;
266

    
267
  // Get a handle
268
  handle = getNewHandle ();
269
  if (handle < 0)
270
  {
271
    return (SL_OUT_OF_HANDLES);
272
  }
273

    
274
  // Store the handle on the Java side
275
  jclass      cls       = (env)->GetObjectClass  (obj);
276
  jfieldID    handleID  = (env)->GetFieldID      (cls, "nativeHandle", "I");
277

    
278
  (env)->SetIntField (obj, handleID, (jint)handle);
279

    
280
  /*
281
   * Note: CoCreateInstance() supports only the creation of a single instance.
282
   * Need to find out how to use CoGetClassObject() to create multiple instances.
283
   * It should be possible to have multiple instances available, got to make this work!
284
   */
285

    
286
  // Get a pointer to the IShellLink interface
287
  hres = CoCreateInstance (CLSID_ShellLink,
288
                           NULL,
289
                           CLSCTX_INPROC_SERVER,
290
                           IID_IShellLink,
291
                           (void **)&p_shellLink [handle]);
292

    
293
  // Do error handling
294
  if (SUCCEEDED (hres))
295
  {
296
    return (SL_OK);
297
  }
298

    
299
  return (SL_ERROR);
300
}
301

    
302
// --------------------------------------------------------------------------
303
// This function returns a new handle to be used for the next client. If no
304
// more handles are available -1 is returnd.
305
// --------------------------------------------------------------------------
306
int getNewHandle ()
307
{
308
  IShellLink* pointer;
309

    
310
  // loop through the array to find an unoccupied location
311
  int i;
312
  for (i = 0; i < linkCapacity; i++)
313
  {
314
    pointer = p_shellLink [i];
315
    // if an unoccupied location is found return the index
316
    if (pointer == NULL)
317
    {
318
      return (i);
319
    }
320
  }
321

    
322
  // if we get here, all locations are in use and we need to
323
  // create more storage space to satisfy the request
324
  int   newSize     = sizeof (IShellLink*) * (linkCapacity + ALLOC_INCREMENT);
325
  void* tempPointer = realloc ((void *)p_shellLink, newSize);
326

    
327
  if (tempPointer != NULL)
328
  {
329
    p_shellLink  = (IShellLink**)tempPointer;
330
    linkCapacity = linkCapacity + ALLOC_INCREMENT;
331

    
332
    for (int k = i; k < linkCapacity; k++)
333
    {
334
      p_shellLink [k] = NULL;
335
    }
336
    return (i);
337
  }
338
  else
339
  {
340
    return (-1);
341
  }
342
}
343

    
344
// --------------------------------------------------------------------------
345
// This function frees the storage that was allocated for the storage of
346
// pointers to IShellLink interfaces. It also cleans up any interfaces that
347
// have not yet been reliquished (clients left a mess -> bad boy!).
348
// --------------------------------------------------------------------------
349
void freeLinks ()
350
{
351
  if (p_shellLink != NULL)
352
  {
353
    // loop through the array and release any interfaces that
354
    // have not been freed yet
355
    IShellLink* pointer;
356
    for (int i = 0; i < linkCapacity; i++)
357
    {
358
      pointer = p_shellLink [i];
359
      // if an unoccupied location is found, return the index
360
      if (pointer != NULL)
361
      {
362
        pointer->Release ();
363
        p_shellLink [i] = NULL;
364
      }
365
    }
366

    
367
    // free the pointer storage itself
368
    linkCapacity = 0;
369
    free (p_shellLink);
370
  }
371
}
372

    
373
// --------------------------------------------------------------------------
374
// This function frees this dll, allowing the operating system to remove
375
// the code from memory and releasing the reference to the dll on disk. 
376
// After this call this dll can not be used any more.
377
//
378
// THIS FUNCTION DOES NOT RETURN !!!
379
// --------------------------------------------------------------------------
380
JNIEXPORT void JNICALL Java_com_izforge_izpack_util_os_ShellLink_FreeLibrary (JNIEnv *env, 
381
                                                                              jobject obj,
382
                                                                              jstring name)
383
{
384
  // convert the name from Java string type
385
  const char *libraryName = (env)->GetStringUTFChars (name, 0);
386

    
387
  // get a module handle 
388
  HMODULE handle = GetModuleHandle (libraryName);
389

    
390
  // release the string object
391
  (env)->ReleaseStringUTFChars (name, libraryName);
392
  
393
  // now we are rady to free the library
394
  FreeLibraryAndExitThread (handle, 0);
395
}
396

    
397
// --------------------------------------------------------------------------
398
// Releases the interface
399
// --------------------------------------------------------------------------
400
JNIEXPORT jint JNICALL Java_com_izforge_izpack_util_os_ShellLink_releaseInterface (JNIEnv  *env,
401
                                                                                   jobject  obj)
402
{
403
  // Get the handle from the Java side
404
  jclass      cls       = (env)->GetObjectClass  (obj);
405
  jfieldID    handleID  = (env)->GetFieldID      (cls, "nativeHandle", "I");
406
  jint        handle    = (env)->GetIntField     (obj, handleID);
407

    
408
  if (handle < 0)
409
  {
410
    return (SL_OK);
411
  }
412
  
413
  if (p_shellLink [handle] == NULL)
414
  {
415
    return (SL_NOT_INITIALIZED);
416
  }
417

    
418
  p_shellLink [handle]->Release ();
419
  p_shellLink [handle] = NULL;
420
  (env)->SetIntField (obj, handleID, -1);
421
  return (SL_OK);
422
}
423

    
424
// --------------------------------------------------------------------------
425
// Retrieves the command-line arguments associated with a shell link object
426
//
427
// Result is deposited in 'arguments'
428
// --------------------------------------------------------------------------
429
JNIEXPORT jint JNICALL Java_com_izforge_izpack_util_os_ShellLink_GetArguments (JNIEnv  *env,
430
                                                                               jobject  obj)
431
{
432
  char    arguments [MAX_TEXT_LENGTH];
433
  HRESULT hres;
434

    
435
  // Get the handle from the Java side
436
  jclass      cls       = (env)->GetObjectClass  (obj);
437
  jfieldID    handleID  = (env)->GetFieldID      (cls, "nativeHandle", "I");
438
  jint        handle    = (env)->GetIntField     (obj, handleID);
439

    
440
  hres = p_shellLink [handle]->GetArguments (arguments,
441
                                             MAX_TEXT_LENGTH);
442

    
443
  // ------------------------------------------------------
444
  // set the member variables
445
  // ------------------------------------------------------
446
  if (SUCCEEDED (hres))
447
  {
448
    jfieldID  argumentsID = (env)->GetFieldID      (cls, "arguments", "Ljava/lang/String;");
449
    jstring   j_arguments = (env)->NewStringUTF    (arguments);
450

    
451
    (env)->SetObjectField (obj, argumentsID, j_arguments);
452
    return (SL_OK);
453
  }
454
  else
455
  {
456
    return (SL_ERROR);
457
  }
458
}
459

    
460
// --------------------------------------------------------------------------
461
// Retrieves the description string for a shell link object.
462
//
463
// Result is deposited in 'description'
464
// --------------------------------------------------------------------------
465
JNIEXPORT jint JNICALL Java_com_izforge_izpack_util_os_ShellLink_GetDescription (JNIEnv  *env,
466
                                                                                 jobject  obj)
467
{
468
  char description [MAX_TEXT_LENGTH];
469
  HRESULT hres;
470

    
471
  // Get the handle from the Java side
472
  jclass      cls       = (env)->GetObjectClass  (obj);
473
  jfieldID    handleID  = (env)->GetFieldID      (cls, "nativeHandle", "I");
474
  jint        handle    = (env)->GetIntField     (obj, handleID);
475

    
476
  hres = p_shellLink [handle]->GetDescription (description,
477
                                               MAX_TEXT_LENGTH);
478

    
479
  if (SUCCEEDED (hres))
480
  {
481
    jfieldID  descriptionID = (env)->GetFieldID      (cls, "description", "Ljava/lang/String;");
482
    jstring   j_description = (env)->NewStringUTF    (description); // convert to Java String type
483

    
484
    (env)->SetObjectField (obj, descriptionID, j_description);
485
    return (SL_OK);
486
  }
487
  else
488
  {
489
    return (SL_ERROR);
490
  }
491
}
492

    
493
// --------------------------------------------------------------------------
494
// Retrieves the hot key for a shell link object.
495
//
496
// Result is deposited in 'hotkey'
497
// --------------------------------------------------------------------------
498
JNIEXPORT jint JNICALL Java_com_izforge_izpack_util_os_ShellLink_GetHotkey        (JNIEnv  *env,
499
                                                                             jobject  obj)
500
{
501
  WORD    hotkey;
502
  HRESULT hres;
503

    
504
  // Get the handle from the Java side
505
  jclass      cls       = (env)->GetObjectClass  (obj);
506
  jfieldID    handleID  = (env)->GetFieldID      (cls, "nativeHandle", "I");
507
  jint        handle    = (env)->GetIntField     (obj, handleID);
508

    
509
  hres = p_shellLink [handle]->GetHotkey (&hotkey);
510

    
511
  if (SUCCEEDED (hres))
512
  {
513
    jfieldID  hotkeyID = (env)->GetFieldID      (cls, "hotkey", "I");
514

    
515
    (env)->SetIntField (obj, hotkeyID, (jint)hotkey);
516
    return (SL_OK);
517
  }
518
  else
519
  {
520
    return (SL_ERROR);
521
  }
522
}
523

    
524
// --------------------------------------------------------------------------
525
// Retrieves the location (path and index) of the icon for a shell link object.
526
//
527
// The path is deposited in 'iconPath'
528
// The index is deposited in 'iconIndex'
529
// --------------------------------------------------------------------------
530
JNIEXPORT jint JNICALL Java_com_izforge_izpack_util_os_ShellLink_GetIconLocation        (JNIEnv  *env,
531
                                                                                   jobject  obj)
532
{
533
  HRESULT hres;
534
  char    iconPath [MAX_PATH];
535
  int     iconIndex;
536

    
537
  // Get the handle from the Java side
538
  jclass      cls       = (env)->GetObjectClass  (obj);
539
  jfieldID    handleID  = (env)->GetFieldID      (cls, "nativeHandle", "I");
540
  jint        handle    = (env)->GetIntField     (obj, handleID);
541

    
542
  hres = p_shellLink [handle]->GetIconLocation (iconPath,
543
                                                MAX_PATH,
544
                                                &iconIndex);
545

    
546
  // ------------------------------------------------------
547
  // set the member variables
548
  // ------------------------------------------------------
549
  if (SUCCEEDED (hres))
550
  {
551
    jfieldID  pathID      = (env)->GetFieldID      (cls, "iconPath", "Ljava/lang/String;");
552
    jfieldID  indexID     = (env)->GetFieldID      (cls, "iconIndex", "I");
553
    jstring   j_iconPath  = (env)->NewStringUTF    (iconPath);
554

    
555
    (env)->SetObjectField  (obj, pathID, j_iconPath);
556
    (env)->SetIntField     (obj, indexID, (jint)iconIndex);
557
    return (SL_OK);
558
  }
559
  else
560
  {
561
    return (SL_ERROR);
562
  }
563
}
564

    
565
// --------------------------------------------------------------------------
566
// Retrieves the path and filename of a shell link object.
567
//
568
// Result is deposited in 'targetPath'
569
// --------------------------------------------------------------------------
570
JNIEXPORT jint JNICALL Java_com_izforge_izpack_util_os_ShellLink_GetPath (JNIEnv  *env,
571
                                                                          jobject  obj)
572
{
573
  WIN32_FIND_DATA findData;
574
  char            targetPath [MAX_PATH];
575
  HRESULT hres;
576

    
577
  // Get the handle from the Java side
578
  jclass      cls       = (env)->GetObjectClass  (obj);
579
  jfieldID    handleID  = (env)->GetFieldID      (cls, "nativeHandle", "I");
580
  jint        handle    = (env)->GetIntField     (obj, handleID);
581

    
582
  hres = p_shellLink [handle]->GetPath (targetPath,
583
                                        MAX_PATH,
584
                                        &findData,
585
                                        SLGP_UNCPRIORITY);
586

    
587
  // ------------------------------------------------------
588
  // set the member variables
589
  // ------------------------------------------------------
590
  if (SUCCEEDED (hres))
591
  {
592
    jfieldID  pathID        = (env)->GetFieldID      (cls, "targetPath", "Ljava/lang/String;");
593
    jstring   j_targetPath  = (env)->NewStringUTF    (targetPath);
594

    
595
    (env)->SetObjectField (obj, pathID, j_targetPath);
596
    return (SL_OK);
597
  }
598
  else
599
  {
600
    return (SL_ERROR);
601
  }
602
}
603

    
604
// --------------------------------------------------------------------------
605
// Retrieves the show (SW_) command for a shell link object.
606
//
607
// Result is deposited in 'showCommand'
608
// --------------------------------------------------------------------------
609
JNIEXPORT jint JNICALL Java_com_izforge_izpack_util_os_ShellLink_GetShowCommand (JNIEnv  *env,
610
                                                                                 jobject  obj)
611
{
612
  HRESULT   hres;
613
  int       showCommand;
614

    
615
  // Get the handle from the Java side
616
  jclass      cls       = (env)->GetObjectClass  (obj);
617
  jfieldID    handleID  = (env)->GetFieldID      (cls, "nativeHandle", "I");
618
  jint        handle    = (env)->GetIntField     (obj, handleID);
619

    
620
  hres = p_shellLink [handle]->GetShowCmd (&showCommand);
621

    
622
  // ------------------------------------------------------
623
  // set the member variables
624
  // ------------------------------------------------------
625
  if (SUCCEEDED (hres))
626
  {
627
    jfieldID  commandID = (env)->GetFieldID      (cls, "showCommand", "I");
628

    
629
    (env)->SetIntField (obj, commandID, (jint)showCommand);
630
    return (SL_OK);
631
  }
632
  else
633
  {
634
    return (SL_ERROR);
635
  }
636
}
637

    
638
// --------------------------------------------------------------------------
639
// Retrieves the name of the working directory for a shell link object.
640
//
641
// Result is deposited in 'workingDirectory'
642
// --------------------------------------------------------------------------
643
JNIEXPORT jint JNICALL Java_com_izforge_izpack_util_os_ShellLink_GetWorkingDirectory        (JNIEnv  *env,
644
                                                                                       jobject  obj)
645
{
646
  HRESULT hres;
647
  char workingDirectory [MAX_PATH];
648

    
649
  // Get the handle from the Java side
650
  jclass      cls       = (env)->GetObjectClass  (obj);
651
  jfieldID    handleID  = (env)->GetFieldID      (cls, "nativeHandle", "I");
652
  jint        handle    = (env)->GetIntField     (obj, handleID);
653

    
654
  hres = p_shellLink [handle]->GetWorkingDirectory (workingDirectory,
655
                                                    MAX_PATH);
656

    
657
  // ------------------------------------------------------
658
  // set the member variables
659
  // ------------------------------------------------------
660
  if (SUCCEEDED (hres))
661
  {
662
    jfieldID  directoryID         = (env)->GetFieldID      (cls, "workingDirectory", "Ljava/lang/String;");
663
    jstring   j_workingDirectory  = (env)->NewStringUTF    (workingDirectory);
664

    
665
    (env)->SetObjectField (obj, directoryID, j_workingDirectory);
666
    return (SL_OK);
667
  }
668
  else
669
  {
670
    return (SL_ERROR);
671
  }
672
}
673

    
674
// --------------------------------------------------------------------------
675
// Resolves a shell link by searching for the shell link object and
676
// updating the shell link path and its list of identifiers (if necessary).
677
//
678
// I recommend to call this function before saving the shortcut. This will
679
// ensure that the link is working and all the identifiers are updated, so
680
// that the link will actually work when used later on. If for some reason
681
// the link can not be resolved, at least the creating application knows
682
// about this.
683
// --------------------------------------------------------------------------
684
JNIEXPORT jint JNICALL Java_com_izforge_izpack_util_os_ShellLink_Resolve        (JNIEnv  *env,
685
                                                                           jobject  obj)
686
{
687
  HRESULT hres;
688

    
689
  // Get the handle from the Java side
690
  jclass      cls       = (env)->GetObjectClass  (obj);
691
  jfieldID    handleID  = (env)->GetFieldID      (cls, "nativeHandle", "I");
692
  jint        handle    = (env)->GetIntField     (obj, handleID);
693

    
694
  hres = p_shellLink [handle]->Resolve (NULL,
695
                                        SLR_NO_UI | SLR_UPDATE);
696

    
697
  if (SUCCEEDED (hres))
698
  {
699
    return (SL_OK);
700
  }
701
  else
702
  {
703
    return (SL_ERROR);
704
  }
705
}
706

    
707
// --------------------------------------------------------------------------
708
// Sets the command-line arguments associated with a shell link object.
709
//
710
// Input is taken from 'arguments'
711
// --------------------------------------------------------------------------
712
JNIEXPORT jint JNICALL Java_com_izforge_izpack_util_os_ShellLink_SetArguments (JNIEnv  *env,
713
                                                                               jobject  obj)
714
{
715
  HRESULT hres;
716

    
717
  // Get the handle from the Java side
718
  jclass      cls       = (env)->GetObjectClass  (obj);
719
  jfieldID    handleID  = (env)->GetFieldID      (cls, "nativeHandle", "I");
720
  jint        handle    = (env)->GetIntField     (obj, handleID);
721

    
722
  // ------------------------------------------------------
723
  // get the member variables
724
  // ------------------------------------------------------
725
  jfieldID    argumentsID = (env)->GetFieldID               (cls, "arguments", "Ljava/lang/String;");
726
  jstring     j_arguments = (jstring)(env)->GetObjectField  (obj, argumentsID);
727
  const char *arguments   = (env)->GetStringUTFChars        (j_arguments, 0);
728

    
729
  hres = p_shellLink [handle]->SetArguments (arguments);
730

    
731
  (env)->ReleaseStringUTFChars (j_arguments, arguments);
732

    
733
  if (SUCCEEDED (hres))
734
  {
735
    return (SL_OK);
736
  }
737
  else
738
  {
739
    return (SL_ERROR);
740
  }
741
}
742

    
743
// --------------------------------------------------------------------------
744
// Sets the description string for a shell link object.
745
//
746
// Input is taken from 'description'
747
// --------------------------------------------------------------------------
748
JNIEXPORT jint JNICALL Java_com_izforge_izpack_util_os_ShellLink_SetDescription (JNIEnv  *env,
749
                                                                                 jobject  obj)
750
{
751
  HRESULT hres;
752

    
753
  // Get the handle from the Java side
754
  jclass      cls       = (env)->GetObjectClass  (obj);
755
  jfieldID    handleID  = (env)->GetFieldID      (cls, "nativeHandle", "I");
756
  jint        handle    = (env)->GetIntField     (obj, handleID);
757

    
758
  // ------------------------------------------------------
759
  // get the member variables
760
  // ------------------------------------------------------
761
  jfieldID    descriptionID = (env)->GetFieldID               (cls, "description", "Ljava/lang/String;");
762
  jstring     j_description = (jstring)(env)->GetObjectField  (obj, descriptionID);
763
  const char *description   = (env)->GetStringUTFChars        (j_description, 0);
764

    
765
  hres = p_shellLink [handle]->SetDescription (description);
766

    
767
  (env)->ReleaseStringUTFChars (j_description, description);
768

    
769
  if (SUCCEEDED (hres))
770
  {
771
    return (SL_OK);
772
  }
773
  else
774
  {
775
    return (SL_ERROR);
776
  }
777
}
778

    
779
// --------------------------------------------------------------------------
780
// Sets the hot key for a shell link object.
781
//
782
// Input is taken from 'hotkey'
783
// --------------------------------------------------------------------------
784
JNIEXPORT jint JNICALL Java_com_izforge_izpack_util_os_ShellLink_SetHotkey        (JNIEnv  *env,
785
                                                                             jobject  obj)
786
{
787
  HRESULT hres;
788

    
789
  // Get the handle from the Java side
790
  jclass      cls       = (env)->GetObjectClass  (obj);
791
  jfieldID    handleID  = (env)->GetFieldID      (cls, "nativeHandle", "I");
792
  jint        handle    = (env)->GetIntField     (obj, handleID);
793

    
794
  // ------------------------------------------------------
795
  // get the member variables
796
  // ------------------------------------------------------
797
  jfieldID    hotkeyID  = (env)->GetFieldID      (cls, "hotkey", "I");
798
  jint        hotkey    = (env)->GetIntField     (obj, hotkeyID);
799

    
800
  hres = p_shellLink [handle]->SetHotkey ((unsigned short)hotkey);
801
  if (SUCCEEDED (hres))
802
  {
803
    return (SL_OK);
804
  }
805
  else
806
  {
807
    return (SL_ERROR);
808
  }
809
}
810

    
811
// --------------------------------------------------------------------------
812
// Sets the location (path and index) of the icon for a shell link object.
813
//
814
// The path is taken from 'iconPath'
815
// The index is taken from 'iconIndex'
816
// --------------------------------------------------------------------------
817
JNIEXPORT jint JNICALL Java_com_izforge_izpack_util_os_ShellLink_SetIconLocation        (JNIEnv  *env,
818
                                                                                   jobject  obj)
819
{
820
  HRESULT hres;
821

    
822
  // Get the handle from the Java side
823
  jclass      cls       = (env)->GetObjectClass  (obj);
824
  jfieldID    handleID  = (env)->GetFieldID      (cls, "nativeHandle", "I");
825
  jint        handle    = (env)->GetIntField     (obj, handleID);
826

    
827
  // ------------------------------------------------------
828
  // get the member variables
829
  // ------------------------------------------------------
830
  jfieldID    pathID        = (env)->GetFieldID               (cls, "iconPath", "Ljava/lang/String;");
831
  jstring     j_iconPath    = (jstring)(env)->GetObjectField  (obj, pathID);
832
  const char *iconPath      = (env)->GetStringUTFChars        (j_iconPath, 0);
833

    
834
  jfieldID    indexID       = (env)->GetFieldID               (cls, "iconIndex", "I");
835
  jint        iconIndex     = (env)->GetIntField              (obj, indexID);
836

    
837
  hres = p_shellLink [handle]->SetIconLocation (iconPath,
838
                                                iconIndex);
839

    
840
  (env)->ReleaseStringUTFChars (j_iconPath, iconPath);
841

    
842
  if (SUCCEEDED (hres))
843
  {
844
    return (SL_OK);
845
  }
846
  else
847
  {
848
    return (SL_ERROR);
849
  }
850
}
851

    
852
// --------------------------------------------------------------------------
853
// Sets the path and filename of a shell link object.
854
//
855
// Input is taken from 'targetPath'
856
// --------------------------------------------------------------------------
857
JNIEXPORT jint JNICALL Java_com_izforge_izpack_util_os_ShellLink_SetPath        (JNIEnv  *env,
858
                                                                           jobject  obj)
859
{
860
  HRESULT hres;
861

    
862
  // Get the handle from the Java side
863
  jclass      cls       = (env)->GetObjectClass  (obj);
864
  jfieldID    handleID  = (env)->GetFieldID      (cls, "nativeHandle", "I");
865
  jint        handle    = (env)->GetIntField     (obj, handleID);
866

    
867
  // ------------------------------------------------------
868
  // get the member variables
869
  // ------------------------------------------------------
870
  jfieldID    pathID        = (env)->GetFieldID               (cls, "targetPath", "Ljava/lang/String;");
871
  jstring     j_targetPath  = (jstring)(env)->GetObjectField  (obj, pathID);
872
  const char *targetPath    = (env)->GetStringUTFChars        (j_targetPath, 0);
873

    
874
  hres = p_shellLink [handle]->SetPath (targetPath);
875

    
876
  (env)->ReleaseStringUTFChars (j_targetPath, targetPath);
877

    
878
  if (SUCCEEDED (hres))
879
  {
880
    return (SL_OK);
881
  }
882
  else
883
  {
884
    return (SL_ERROR);
885
  }
886
}
887

    
888
// --------------------------------------------------------------------------
889
// Sets the show (SW_) command for a shell link object.
890
//
891
// Input is taken from 'showCommand'
892
// --------------------------------------------------------------------------
893
JNIEXPORT jint JNICALL Java_com_izforge_izpack_util_os_ShellLink_SetShowCommand (JNIEnv  *env,
894
                                                                                 jobject  obj)
895
{
896
  HRESULT hres;
897

    
898
  // Get the handle from the Java side
899
  jclass      cls       = (env)->GetObjectClass  (obj);
900
  jfieldID    handleID  = (env)->GetFieldID      (cls, "nativeHandle", "I");
901
  jint        handle    = (env)->GetIntField     (obj, handleID);
902

    
903
  // ------------------------------------------------------
904
  // get the member variables
905
  // ------------------------------------------------------
906
  jfieldID    commandID   = (env)->GetFieldID      (cls, "showCommand", "I");
907
  jint        showCommand = (env)->GetIntField     (obj, commandID);
908

    
909
  hres = p_shellLink [handle]->SetShowCmd (showCommand);
910
  if (SUCCEEDED (hres))
911
  {
912
    return (SL_OK);
913
  }
914
  else
915
  {
916
    return (SL_ERROR);
917
  }
918
}
919

    
920
// --------------------------------------------------------------------------
921
// Sets the name of the working directory for a shell link object.
922
//
923
// Input is taken from 'workingDirectory'
924
// --------------------------------------------------------------------------
925
JNIEXPORT jint JNICALL Java_com_izforge_izpack_util_os_ShellLink_SetWorkingDirectory        (JNIEnv  *env,
926
                                                                                       jobject  obj)
927
{
928
  HRESULT hres;
929

    
930
  // Get the handle from the Java side
931
  jclass      cls       = (env)->GetObjectClass  (obj);
932
  jfieldID    handleID  = (env)->GetFieldID      (cls, "nativeHandle", "I");
933
  jint        handle    = (env)->GetIntField     (obj, handleID);
934

    
935
  // ------------------------------------------------------
936
  // get the member variables
937
  // ------------------------------------------------------
938
  jfieldID    pathID              = (env)->GetFieldID               (cls, "workingDirectory", "Ljava/lang/String;");
939
  jstring     j_workingDirectory  = (jstring)(env)->GetObjectField  (obj, pathID);
940
  const char *workingDirectory    = (env)->GetStringUTFChars        (j_workingDirectory, 0);
941

    
942
  hres = p_shellLink [handle]->SetWorkingDirectory (workingDirectory);
943

    
944
  (env)->ReleaseStringUTFChars (j_workingDirectory, workingDirectory);
945

    
946
  if (SUCCEEDED (hres))
947
  {
948
    return (SL_OK);
949
  }
950
  else
951
  {
952
    return (SL_ERROR);
953
  }
954
}
955

    
956
// --------------------------------------------------------------------------
957
// This function saves the shell link.
958
//
959
// name - the fully qualified path for saving the shortcut.
960
// --------------------------------------------------------------------------
961
JNIEXPORT jint JNICALL Java_com_izforge_izpack_util_os_ShellLink_saveLink (JNIEnv  *env,
962
                                                                           jobject  obj,
963
                                                                           jstring  name)
964
{
965
  // Get the handle from the Java side
966
  jclass      cls       = (env)->GetObjectClass  (obj);
967
  jfieldID    handleID  = (env)->GetFieldID      (cls, "nativeHandle", "I");
968
  jint        handle    = (env)->GetIntField     (obj, handleID);
969

    
970
  // ----------------------------------------------------
971
  // Query IShellLink for the IPersistFile interface for
972
  // saving the shell link in persistent storage.
973
  // ----------------------------------------------------
974
  IPersistFile* p_persistFile;
975
  HRESULT       hres = p_shellLink [handle]->QueryInterface (IID_IPersistFile,
976
                                                             (void **)&p_persistFile);
977

    
978
  if (!SUCCEEDED (hres))
979
  {
980
    return (SL_NO_IPERSIST);
981
  }
982

    
983
  // ----------------------------------------------------
984
  // convert from Java string type
985
  // ----------------------------------------------------
986
  const unsigned short *pathName = (env)->GetStringChars (name, 0);
987
  
988
  // ----------------------------------------------------
989
  // Save the link
990
  // ----------------------------------------------------
991
  hres = p_persistFile->Save   ((wchar_t*)pathName, FALSE);
992
  p_persistFile->SaveCompleted ((wchar_t*)pathName);
993
  
994
  // ----------------------------------------------------
995
  // Release the pointer to IPersistFile
996
  // and the string object
997
  // ----------------------------------------------------
998
  p_persistFile->Release ();
999
  (env)->ReleaseStringChars (name, pathName);
1000

    
1001
  // ------------------------------------------------------
1002
  // return success code
1003
  // ------------------------------------------------------
1004
  if (SUCCEEDED (hres))
1005
  {
1006
    return (SL_OK);
1007
  }
1008
  else
1009
  {
1010
    return (SL_NO_SAVE);
1011
  }
1012
}
1013

    
1014
// --------------------------------------------------------------------------
1015
// This function loads a shell link.
1016
//
1017
// name - the fully qualified path for loading the shortcut.
1018
// --------------------------------------------------------------------------
1019
JNIEXPORT jint JNICALL Java_com_izforge_izpack_util_os_ShellLink_loadLink (JNIEnv  *env,
1020
                                                                           jobject  obj,
1021
                                                                           jstring  name)
1022
{
1023
  HRESULT     hres;
1024

    
1025
  // Get the handle from the Java side
1026
  jclass      cls       = (env)->GetObjectClass  (obj);
1027
  jfieldID    handleID  = (env)->GetFieldID      (cls, "nativeHandle", "I");
1028
  jint        handle    = (env)->GetIntField     (obj, handleID);
1029

    
1030
  // ----------------------------------------------------
1031
  // Query IShellLink for the IPersistFile interface for
1032
  // saving the shell link in persistent storage.
1033
  // ----------------------------------------------------
1034
  IPersistFile* p_persistFile;
1035
  hres = p_shellLink [handle]->QueryInterface (IID_IPersistFile,
1036
                                               (void **)&p_persistFile);
1037

    
1038
  if (SUCCEEDED (hres))
1039
  {
1040
    // convert from Java string type
1041
    const unsigned short *pathName = (env)->GetStringChars (name, 0);
1042

    
1043
    // --------------------------------------------------
1044
    // Load the link
1045
    // --------------------------------------------------
1046
    hres = p_persistFile->Load ((wchar_t *)pathName,
1047
                                STGM_DIRECT    |
1048
                                STGM_READWRITE |
1049
                                STGM_SHARE_EXCLUSIVE);
1050

    
1051
    // --------------------------------------------------
1052
    // Release the pointer to IPersistFile
1053
    // --------------------------------------------------
1054
    p_persistFile->Release ();
1055
    (env)->ReleaseStringChars (name, pathName);
1056
  }
1057

    
1058
  // ------------------------------------------------------
1059
  // return success code
1060
  // ------------------------------------------------------
1061
  if (SUCCEEDED (hres))
1062
  {
1063
    return (SL_OK);
1064
  }
1065
  else
1066
  {
1067
    return (SL_ERROR);
1068
  }
1069
}
1070

    
1071

    
1072
// --------------------------------------------------------------------------
1073
// resolves a Windows Standard path using SHGetPathFromIDList
1074
// inputs:
1075
//  inc iCsidl - one of the CSIDL
1076
//    valid          CSIDL_COMMON_DESKTOPDIRECTORY
1077
//                                CSIDL_COMMON_STARTMENU        
1078
//                                CSIDL_COMMON_PROGRAMS
1079
//                                CSIDL_COMMON_STARTUP
1080
//                   CSIDL_DESKTOPDIRECTORY
1081
//                                CSIDL_STARTMENU        
1082
//                                CSIDL_PROGRAMS
1083
//                                CSIDL_STARTUP
1084
// returns:
1085
//   the Windows Standard Path in szPath.
1086
// --------------------------------------------------------------------------
1087
LONG GetLinkPath( int iCsidl, LPTSTR szPath )
1088
{
1089
    HRESULT hr;
1090

    
1091
    // Allocate a pointer to an Item ID list
1092
    LPITEMIDLIST pidl;
1093

    
1094
    // Get a pointer to an item ID list that
1095
    // represents the path of a special folder
1096
    hr = SHGetSpecialFolderLocation(NULL, iCsidl, &pidl);
1097

    
1098
    if ( SUCCEEDED(hr) )
1099
    {
1100
        // Convert the item ID list's binary
1101
        // representation into a file system path
1102
        BOOL f = SHGetPathFromIDList(pidl, szPath);
1103

    
1104
        // Allocate a pointer to an IMalloc interface
1105
        LPMALLOC pMalloc;
1106

    
1107
        // Get the address of our task allocator's IMalloc interface
1108
        hr = SHGetMalloc(&pMalloc);
1109

    
1110
        // Free the item ID list allocated by SHGetSpecialFolderLocation
1111
        pMalloc->Free(pidl);
1112

    
1113
        // Free our task allocator
1114
        pMalloc->Release();
1115

    
1116
                if ( f == FALSE )
1117
                {
1118
                    *szPath = TCHAR('\0');
1119
                        return E_FAIL;
1120
                }
1121

    
1122
        // return the special folder's path (contained in szPath)
1123
        return S_OK;
1124
    }
1125
        else
1126
        {
1127
                // null path for error return.
1128
                *szPath = TCHAR('\0');
1129
        }
1130

    
1131
        return E_FAIL;
1132
}
1133

    
1134
// --------------------------------------------------------------------------
1135
// This function retrieves the location of the folders that hold shortcuts.
1136
// The information comes from SHGetSpecialFolderLocation, 
1137
// since it's more accurate.
1138
//  SHGetSpecialFolderLocation (since shell32.dll ver 4.0 - win 95, IE 3).
1139
//
1140
// target   - where the path should point. The following are legal values
1141
//            to use
1142
//
1143
//            1 - path for shortcuts that show on the desktop
1144
//            2 - path for shortcuts that show in the Programs menu
1145
//            3 - path for shortcuts that show in the start menu
1146
//            4 - path to the Startup group. These shortcuts are executed
1147
//                at OS launch time
1148
//
1149
//            Note: all other values cause an empty string to be returned
1150
//
1151
// Program groups (sub-menus) in the programs and start menus can be created
1152
// by creating a new folder at the indicated location and placing the links
1153
// in that folder. These folders can be nested to any depth with each level
1154
// creating an additional menu level.
1155
//
1156
// Results are deposited in 'currentUserLinkPath' and 'allUsersLinkPath' 
1157
// respectively
1158
// --------------------------------------------------------------------------
1159
// --------------------------------------------------------------------------
1160
JNIEXPORT jint JNICALL Java_com_izforge_izpack_util_os_ShellLink_GetFullLinkPath
1161
  (JNIEnv *env, jobject obj, jint utype, jint ltype)
1162
{
1163
  ULONG   ul_size = MAX_PATH;       // buffer size
1164
  TCHAR   szPath [MAX_PATH];        // path we are looking for 
1165
  int          csidl;
1166
  jclass        cls;
1167
  jfieldID  pathID;
1168
  jstring   j_path;
1169
  LONG                 successCode;
1170
  
1171
  if ((ltype > MIN_KEY) && (ltype < MAX_KEY))
1172
  {
1173
        //translate request into a CSIDL, based on user-type and link-type
1174

    
1175
        // user type
1176
        if ( utype == com_izforge_izpack_util_os_ShellLink_ALL_USERS )
1177
        {
1178
                switch ( ltype )                // link type
1179
                {
1180
                        case ( com_izforge_izpack_util_os_ShellLink_DESKTOP ) :
1181
                        csidl = CSIDL_COMMON_DESKTOPDIRECTORY;
1182
                        break;
1183

    
1184
                        case ( com_izforge_izpack_util_os_ShellLink_START_MENU ) :
1185
                        csidl = CSIDL_COMMON_STARTMENU;
1186
                        break;
1187

    
1188
                        case ( com_izforge_izpack_util_os_ShellLink_PROGRAM_MENU ) :
1189
                        csidl = CSIDL_COMMON_PROGRAMS;
1190
                        break;
1191

    
1192
                        case ( com_izforge_izpack_util_os_ShellLink_STARTUP ) :
1193
                        csidl = CSIDL_COMMON_STARTUP;
1194
                        break;
1195

    
1196
                        default :
1197
                        break;
1198
                }
1199

    
1200
                successCode = GetLinkPath( csidl, szPath );
1201

    
1202
                if ( SUCCEEDED(successCode) )
1203
                {
1204

    
1205
                        // ------------------------------------------------------
1206
                        // set the member variables
1207
                        // ------------------------------------------------------
1208
                        cls    = (env)->GetObjectClass (obj);
1209
                        pathID = (env)->GetFieldID     (cls, "allUsersLinkPath", "Ljava/lang/String;");
1210
                        j_path = (env)->NewStringUTF   (szPath);
1211

    
1212
                        (env)->SetObjectField (obj, pathID, j_path);
1213
                        return (SL_OK);
1214
                }
1215
                else
1216
                {
1217
                        // failure code from GetLinkPath()
1218
                        return successCode;
1219
                }
1220
        }
1221
        else if ( utype == com_izforge_izpack_util_os_ShellLink_CURRENT_USER )
1222
        {
1223
                switch ( ltype )                // link type
1224
                {
1225
                        case ( com_izforge_izpack_util_os_ShellLink_DESKTOP ) :
1226
                        csidl = CSIDL_DESKTOPDIRECTORY;
1227
                        break;
1228

    
1229
                        case ( com_izforge_izpack_util_os_ShellLink_START_MENU ) :
1230
                        csidl = CSIDL_STARTMENU;
1231
                        break;
1232

    
1233
                        case ( com_izforge_izpack_util_os_ShellLink_PROGRAM_MENU ) :
1234
                        csidl = CSIDL_PROGRAMS;
1235
                        break;
1236

    
1237
                        case ( com_izforge_izpack_util_os_ShellLink_STARTUP ) :
1238
                        csidl = CSIDL_STARTUP;
1239
                        break;
1240

    
1241
                        default :
1242
                        break;
1243
                }
1244

    
1245
                successCode = GetLinkPath( csidl, szPath );
1246

    
1247
                if ( SUCCEEDED(successCode) )
1248
                {
1249
                        // ------------------------------------------------------
1250
                        // set the member variables
1251
                        // ------------------------------------------------------
1252
                        cls    = (env)->GetObjectClass (obj);
1253
                        pathID = (env)->GetFieldID     (cls, "currentUserLinkPath", "Ljava/lang/String;");
1254
                        j_path = (env)->NewStringUTF   (szPath);
1255

    
1256
                        (env)->SetObjectField (obj, pathID, j_path);
1257

    
1258
                        return (SL_OK);
1259
                }
1260
                else
1261
                {
1262
                        // failure code from GetLinkPath()
1263
                        return successCode;
1264
                }
1265
        }
1266

    
1267
  }
1268

    
1269
  return SL_CAN_NOT_READ_PATH;
1270
}
1271