Loading dll in windows C for cross-platform design





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}







0















I wrote a c-code designed for linux platform.
Now, I want to make it cross-platform so to use in Windows as-well.
In my code, I dlopen an so file and utilize the functions inside it.
Below is how my code looks like. But I just found out that in windows, the way to load and use dynamic library is quite different.



void *mydynlib
mydynlib= dlopen("/libpath/dynlib.so",RTLD_LAZY);
void (*dynfunc1)() = dlsym(mydynlib,"dynfunc1");
void (*dynfunc2)(char*, char*, double) = dlsym(mydynlib,"dynfunc2");
int (*dynfunc3)() = dlsym(mydynlib,"dynfunc3");


From what I found, I need to use LoadLibrary&GetProcAddress instead of dlopen&dlsym. However, I do not know how to convert above line for windows using those. I've tried to search some examples for hours but couldn't find exact solution. If someone had this kind of experience, please give me a tip.
Excuse me if this is too obvious problem. I'm quite new to C. I usually write my program in python.










share|improve this question























  • LoadLibrary and GetProcAddress are documented at MSDN, and there are dozens (if not hundreds) of examples of their use here. Have you made any effort to read the documentation, search for exisitng posts, and try to do something yourself? Looking at the code you've posted, it should be a very simple task to convert them yourself, but you can't do that until you make an effort to try. You're not going to find exact examples, because no one else has your exact code to convert. It's your job to find an existing example and adapt it to fit your needs.

    – Ken White
    Nov 29 '18 at 1:40




















0















I wrote a c-code designed for linux platform.
Now, I want to make it cross-platform so to use in Windows as-well.
In my code, I dlopen an so file and utilize the functions inside it.
Below is how my code looks like. But I just found out that in windows, the way to load and use dynamic library is quite different.



void *mydynlib
mydynlib= dlopen("/libpath/dynlib.so",RTLD_LAZY);
void (*dynfunc1)() = dlsym(mydynlib,"dynfunc1");
void (*dynfunc2)(char*, char*, double) = dlsym(mydynlib,"dynfunc2");
int (*dynfunc3)() = dlsym(mydynlib,"dynfunc3");


From what I found, I need to use LoadLibrary&GetProcAddress instead of dlopen&dlsym. However, I do not know how to convert above line for windows using those. I've tried to search some examples for hours but couldn't find exact solution. If someone had this kind of experience, please give me a tip.
Excuse me if this is too obvious problem. I'm quite new to C. I usually write my program in python.










share|improve this question























  • LoadLibrary and GetProcAddress are documented at MSDN, and there are dozens (if not hundreds) of examples of their use here. Have you made any effort to read the documentation, search for exisitng posts, and try to do something yourself? Looking at the code you've posted, it should be a very simple task to convert them yourself, but you can't do that until you make an effort to try. You're not going to find exact examples, because no one else has your exact code to convert. It's your job to find an existing example and adapt it to fit your needs.

    – Ken White
    Nov 29 '18 at 1:40
















0












0








0








I wrote a c-code designed for linux platform.
Now, I want to make it cross-platform so to use in Windows as-well.
In my code, I dlopen an so file and utilize the functions inside it.
Below is how my code looks like. But I just found out that in windows, the way to load and use dynamic library is quite different.



void *mydynlib
mydynlib= dlopen("/libpath/dynlib.so",RTLD_LAZY);
void (*dynfunc1)() = dlsym(mydynlib,"dynfunc1");
void (*dynfunc2)(char*, char*, double) = dlsym(mydynlib,"dynfunc2");
int (*dynfunc3)() = dlsym(mydynlib,"dynfunc3");


From what I found, I need to use LoadLibrary&GetProcAddress instead of dlopen&dlsym. However, I do not know how to convert above line for windows using those. I've tried to search some examples for hours but couldn't find exact solution. If someone had this kind of experience, please give me a tip.
Excuse me if this is too obvious problem. I'm quite new to C. I usually write my program in python.










share|improve this question














I wrote a c-code designed for linux platform.
Now, I want to make it cross-platform so to use in Windows as-well.
In my code, I dlopen an so file and utilize the functions inside it.
Below is how my code looks like. But I just found out that in windows, the way to load and use dynamic library is quite different.



void *mydynlib
mydynlib= dlopen("/libpath/dynlib.so",RTLD_LAZY);
void (*dynfunc1)() = dlsym(mydynlib,"dynfunc1");
void (*dynfunc2)(char*, char*, double) = dlsym(mydynlib,"dynfunc2");
int (*dynfunc3)() = dlsym(mydynlib,"dynfunc3");


From what I found, I need to use LoadLibrary&GetProcAddress instead of dlopen&dlsym. However, I do not know how to convert above line for windows using those. I've tried to search some examples for hours but couldn't find exact solution. If someone had this kind of experience, please give me a tip.
Excuse me if this is too obvious problem. I'm quite new to C. I usually write my program in python.







c windows dll shared-libraries dlopen






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 29 '18 at 1:29









윤제균윤제균

275




275













  • LoadLibrary and GetProcAddress are documented at MSDN, and there are dozens (if not hundreds) of examples of their use here. Have you made any effort to read the documentation, search for exisitng posts, and try to do something yourself? Looking at the code you've posted, it should be a very simple task to convert them yourself, but you can't do that until you make an effort to try. You're not going to find exact examples, because no one else has your exact code to convert. It's your job to find an existing example and adapt it to fit your needs.

    – Ken White
    Nov 29 '18 at 1:40





















  • LoadLibrary and GetProcAddress are documented at MSDN, and there are dozens (if not hundreds) of examples of their use here. Have you made any effort to read the documentation, search for exisitng posts, and try to do something yourself? Looking at the code you've posted, it should be a very simple task to convert them yourself, but you can't do that until you make an effort to try. You're not going to find exact examples, because no one else has your exact code to convert. It's your job to find an existing example and adapt it to fit your needs.

    – Ken White
    Nov 29 '18 at 1:40



















LoadLibrary and GetProcAddress are documented at MSDN, and there are dozens (if not hundreds) of examples of their use here. Have you made any effort to read the documentation, search for exisitng posts, and try to do something yourself? Looking at the code you've posted, it should be a very simple task to convert them yourself, but you can't do that until you make an effort to try. You're not going to find exact examples, because no one else has your exact code to convert. It's your job to find an existing example and adapt it to fit your needs.

– Ken White
Nov 29 '18 at 1:40







LoadLibrary and GetProcAddress are documented at MSDN, and there are dozens (if not hundreds) of examples of their use here. Have you made any effort to read the documentation, search for exisitng posts, and try to do something yourself? Looking at the code you've posted, it should be a very simple task to convert them yourself, but you can't do that until you make an effort to try. You're not going to find exact examples, because no one else has your exact code to convert. It's your job to find an existing example and adapt it to fit your needs.

– Ken White
Nov 29 '18 at 1:40














2 Answers
2






active

oldest

votes


















1














You could use macros that change depending on the OS you're on:



#ifdef __linux__
#define LIBTYPE void*
#define OPENLIB(libname) dlopen((libname), RTLD_LAZY)
#define LIBFUNC(lib, fn) dlsym((lib), (fn))
#elif defined(WINVER)
#define LIBTYPE HINSTANCE
#define OPENLIB(libname) LoadLibraryW(L ## libname)
#define LIBFUNC(lib, fn) GetProcAddress((lib), (fn))
#endif





share|improve this answer































    1














    Once in my youth I created something like this:



    /* dlfcn.h */

    #ifndef DLFCN_H
    #define DLFCN_H

    #define RTLD_GLOBAL 0x100 /* do not hide entries in this module */
    #define RTLD_LOCAL 0x000 /* hide entries in this module */

    #define RTLD_LAZY 0x000 /* accept unresolved externs */
    #define RTLD_NOW 0x001 /* abort if module has unresolved externs */

    /*
    How to call in Windows:

    void *h = dlopen ("path\library.dll", flags)
    void (*fun)() = dlsym (h, "entry")
    */

    #ifdef __cplusplus
    extern "C" {
    #endif

    void *dlopen (const char *filename, int flag);
    int dlclose (void *handle);

    void *dlsym (void *handle, const char *name);

    const char *dlerror (void);

    #ifdef __cplusplus
    }
    #endif

    #endif


    and dlfcn.c:



    /* dlfcn.c */ 

    #include <inttypes.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <windows.h>

    static struct {
    long lasterror;
    const char *err_rutin;
    } var = {
    0,
    NULL
    };

    void *dlopen (const char *filename, int flags)
    {
    HINSTANCE hInst;

    hInst= LoadLibrary (filename);
    if (hInst==NULL) {
    var.lasterror = GetLastError ();
    var.err_rutin = "dlopen";
    }
    return hInst;
    }

    int dlclose (void *handle)
    {
    BOOL ok;
    int rc= 0;

    ok= FreeLibrary ((HINSTANCE)handle);
    if (! ok) {
    var.lasterror = GetLastError ();
    var.err_rutin = "dlclose";
    rc= -1;
    }
    return rc;
    }

    void *dlsym (void *handle, const char *name)
    {
    FARPROC fp;

    fp= GetProcAddress ((HINSTANCE)handle, name);
    if (!fp) {
    var.lasterror = GetLastError ();
    var.err_rutin = "dlsym";
    }
    return (void *)(intptr_t)fp;
    }

    const char *dlerror (void)
    {
    static char errstr [88];

    if (var.lasterror) {
    sprintf (errstr, "%s error #%ld", var.err_rutin, var.lasterror);
    return errstr;
    } else {
    return NULL;
    }
    }





    share|improve this answer
























      Your Answer






      StackExchange.ifUsing("editor", function () {
      StackExchange.using("externalEditor", function () {
      StackExchange.using("snippets", function () {
      StackExchange.snippets.init();
      });
      });
      }, "code-snippets");

      StackExchange.ready(function() {
      var channelOptions = {
      tags: "".split(" "),
      id: "1"
      };
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function() {
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled) {
      StackExchange.using("snippets", function() {
      createEditor();
      });
      }
      else {
      createEditor();
      }
      });

      function createEditor() {
      StackExchange.prepareEditor({
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: true,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      imageUploader: {
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      },
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      });


      }
      });














      draft saved

      draft discarded


















      StackExchange.ready(
      function () {
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53530566%2floading-dll-in-windows-c-for-cross-platform-design%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      2 Answers
      2






      active

      oldest

      votes








      2 Answers
      2






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      1














      You could use macros that change depending on the OS you're on:



      #ifdef __linux__
      #define LIBTYPE void*
      #define OPENLIB(libname) dlopen((libname), RTLD_LAZY)
      #define LIBFUNC(lib, fn) dlsym((lib), (fn))
      #elif defined(WINVER)
      #define LIBTYPE HINSTANCE
      #define OPENLIB(libname) LoadLibraryW(L ## libname)
      #define LIBFUNC(lib, fn) GetProcAddress((lib), (fn))
      #endif





      share|improve this answer




























        1














        You could use macros that change depending on the OS you're on:



        #ifdef __linux__
        #define LIBTYPE void*
        #define OPENLIB(libname) dlopen((libname), RTLD_LAZY)
        #define LIBFUNC(lib, fn) dlsym((lib), (fn))
        #elif defined(WINVER)
        #define LIBTYPE HINSTANCE
        #define OPENLIB(libname) LoadLibraryW(L ## libname)
        #define LIBFUNC(lib, fn) GetProcAddress((lib), (fn))
        #endif





        share|improve this answer


























          1












          1








          1







          You could use macros that change depending on the OS you're on:



          #ifdef __linux__
          #define LIBTYPE void*
          #define OPENLIB(libname) dlopen((libname), RTLD_LAZY)
          #define LIBFUNC(lib, fn) dlsym((lib), (fn))
          #elif defined(WINVER)
          #define LIBTYPE HINSTANCE
          #define OPENLIB(libname) LoadLibraryW(L ## libname)
          #define LIBFUNC(lib, fn) GetProcAddress((lib), (fn))
          #endif





          share|improve this answer













          You could use macros that change depending on the OS you're on:



          #ifdef __linux__
          #define LIBTYPE void*
          #define OPENLIB(libname) dlopen((libname), RTLD_LAZY)
          #define LIBFUNC(lib, fn) dlsym((lib), (fn))
          #elif defined(WINVER)
          #define LIBTYPE HINSTANCE
          #define OPENLIB(libname) LoadLibraryW(L ## libname)
          #define LIBFUNC(lib, fn) GetProcAddress((lib), (fn))
          #endif






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 29 '18 at 1:51









          Govind ParmarGovind Parmar

          13.1k53764




          13.1k53764

























              1














              Once in my youth I created something like this:



              /* dlfcn.h */

              #ifndef DLFCN_H
              #define DLFCN_H

              #define RTLD_GLOBAL 0x100 /* do not hide entries in this module */
              #define RTLD_LOCAL 0x000 /* hide entries in this module */

              #define RTLD_LAZY 0x000 /* accept unresolved externs */
              #define RTLD_NOW 0x001 /* abort if module has unresolved externs */

              /*
              How to call in Windows:

              void *h = dlopen ("path\library.dll", flags)
              void (*fun)() = dlsym (h, "entry")
              */

              #ifdef __cplusplus
              extern "C" {
              #endif

              void *dlopen (const char *filename, int flag);
              int dlclose (void *handle);

              void *dlsym (void *handle, const char *name);

              const char *dlerror (void);

              #ifdef __cplusplus
              }
              #endif

              #endif


              and dlfcn.c:



              /* dlfcn.c */ 

              #include <inttypes.h>
              #include <stdio.h>
              #include <stdlib.h>
              #include <string.h>
              #include <windows.h>

              static struct {
              long lasterror;
              const char *err_rutin;
              } var = {
              0,
              NULL
              };

              void *dlopen (const char *filename, int flags)
              {
              HINSTANCE hInst;

              hInst= LoadLibrary (filename);
              if (hInst==NULL) {
              var.lasterror = GetLastError ();
              var.err_rutin = "dlopen";
              }
              return hInst;
              }

              int dlclose (void *handle)
              {
              BOOL ok;
              int rc= 0;

              ok= FreeLibrary ((HINSTANCE)handle);
              if (! ok) {
              var.lasterror = GetLastError ();
              var.err_rutin = "dlclose";
              rc= -1;
              }
              return rc;
              }

              void *dlsym (void *handle, const char *name)
              {
              FARPROC fp;

              fp= GetProcAddress ((HINSTANCE)handle, name);
              if (!fp) {
              var.lasterror = GetLastError ();
              var.err_rutin = "dlsym";
              }
              return (void *)(intptr_t)fp;
              }

              const char *dlerror (void)
              {
              static char errstr [88];

              if (var.lasterror) {
              sprintf (errstr, "%s error #%ld", var.err_rutin, var.lasterror);
              return errstr;
              } else {
              return NULL;
              }
              }





              share|improve this answer




























                1














                Once in my youth I created something like this:



                /* dlfcn.h */

                #ifndef DLFCN_H
                #define DLFCN_H

                #define RTLD_GLOBAL 0x100 /* do not hide entries in this module */
                #define RTLD_LOCAL 0x000 /* hide entries in this module */

                #define RTLD_LAZY 0x000 /* accept unresolved externs */
                #define RTLD_NOW 0x001 /* abort if module has unresolved externs */

                /*
                How to call in Windows:

                void *h = dlopen ("path\library.dll", flags)
                void (*fun)() = dlsym (h, "entry")
                */

                #ifdef __cplusplus
                extern "C" {
                #endif

                void *dlopen (const char *filename, int flag);
                int dlclose (void *handle);

                void *dlsym (void *handle, const char *name);

                const char *dlerror (void);

                #ifdef __cplusplus
                }
                #endif

                #endif


                and dlfcn.c:



                /* dlfcn.c */ 

                #include <inttypes.h>
                #include <stdio.h>
                #include <stdlib.h>
                #include <string.h>
                #include <windows.h>

                static struct {
                long lasterror;
                const char *err_rutin;
                } var = {
                0,
                NULL
                };

                void *dlopen (const char *filename, int flags)
                {
                HINSTANCE hInst;

                hInst= LoadLibrary (filename);
                if (hInst==NULL) {
                var.lasterror = GetLastError ();
                var.err_rutin = "dlopen";
                }
                return hInst;
                }

                int dlclose (void *handle)
                {
                BOOL ok;
                int rc= 0;

                ok= FreeLibrary ((HINSTANCE)handle);
                if (! ok) {
                var.lasterror = GetLastError ();
                var.err_rutin = "dlclose";
                rc= -1;
                }
                return rc;
                }

                void *dlsym (void *handle, const char *name)
                {
                FARPROC fp;

                fp= GetProcAddress ((HINSTANCE)handle, name);
                if (!fp) {
                var.lasterror = GetLastError ();
                var.err_rutin = "dlsym";
                }
                return (void *)(intptr_t)fp;
                }

                const char *dlerror (void)
                {
                static char errstr [88];

                if (var.lasterror) {
                sprintf (errstr, "%s error #%ld", var.err_rutin, var.lasterror);
                return errstr;
                } else {
                return NULL;
                }
                }





                share|improve this answer


























                  1












                  1








                  1







                  Once in my youth I created something like this:



                  /* dlfcn.h */

                  #ifndef DLFCN_H
                  #define DLFCN_H

                  #define RTLD_GLOBAL 0x100 /* do not hide entries in this module */
                  #define RTLD_LOCAL 0x000 /* hide entries in this module */

                  #define RTLD_LAZY 0x000 /* accept unresolved externs */
                  #define RTLD_NOW 0x001 /* abort if module has unresolved externs */

                  /*
                  How to call in Windows:

                  void *h = dlopen ("path\library.dll", flags)
                  void (*fun)() = dlsym (h, "entry")
                  */

                  #ifdef __cplusplus
                  extern "C" {
                  #endif

                  void *dlopen (const char *filename, int flag);
                  int dlclose (void *handle);

                  void *dlsym (void *handle, const char *name);

                  const char *dlerror (void);

                  #ifdef __cplusplus
                  }
                  #endif

                  #endif


                  and dlfcn.c:



                  /* dlfcn.c */ 

                  #include <inttypes.h>
                  #include <stdio.h>
                  #include <stdlib.h>
                  #include <string.h>
                  #include <windows.h>

                  static struct {
                  long lasterror;
                  const char *err_rutin;
                  } var = {
                  0,
                  NULL
                  };

                  void *dlopen (const char *filename, int flags)
                  {
                  HINSTANCE hInst;

                  hInst= LoadLibrary (filename);
                  if (hInst==NULL) {
                  var.lasterror = GetLastError ();
                  var.err_rutin = "dlopen";
                  }
                  return hInst;
                  }

                  int dlclose (void *handle)
                  {
                  BOOL ok;
                  int rc= 0;

                  ok= FreeLibrary ((HINSTANCE)handle);
                  if (! ok) {
                  var.lasterror = GetLastError ();
                  var.err_rutin = "dlclose";
                  rc= -1;
                  }
                  return rc;
                  }

                  void *dlsym (void *handle, const char *name)
                  {
                  FARPROC fp;

                  fp= GetProcAddress ((HINSTANCE)handle, name);
                  if (!fp) {
                  var.lasterror = GetLastError ();
                  var.err_rutin = "dlsym";
                  }
                  return (void *)(intptr_t)fp;
                  }

                  const char *dlerror (void)
                  {
                  static char errstr [88];

                  if (var.lasterror) {
                  sprintf (errstr, "%s error #%ld", var.err_rutin, var.lasterror);
                  return errstr;
                  } else {
                  return NULL;
                  }
                  }





                  share|improve this answer













                  Once in my youth I created something like this:



                  /* dlfcn.h */

                  #ifndef DLFCN_H
                  #define DLFCN_H

                  #define RTLD_GLOBAL 0x100 /* do not hide entries in this module */
                  #define RTLD_LOCAL 0x000 /* hide entries in this module */

                  #define RTLD_LAZY 0x000 /* accept unresolved externs */
                  #define RTLD_NOW 0x001 /* abort if module has unresolved externs */

                  /*
                  How to call in Windows:

                  void *h = dlopen ("path\library.dll", flags)
                  void (*fun)() = dlsym (h, "entry")
                  */

                  #ifdef __cplusplus
                  extern "C" {
                  #endif

                  void *dlopen (const char *filename, int flag);
                  int dlclose (void *handle);

                  void *dlsym (void *handle, const char *name);

                  const char *dlerror (void);

                  #ifdef __cplusplus
                  }
                  #endif

                  #endif


                  and dlfcn.c:



                  /* dlfcn.c */ 

                  #include <inttypes.h>
                  #include <stdio.h>
                  #include <stdlib.h>
                  #include <string.h>
                  #include <windows.h>

                  static struct {
                  long lasterror;
                  const char *err_rutin;
                  } var = {
                  0,
                  NULL
                  };

                  void *dlopen (const char *filename, int flags)
                  {
                  HINSTANCE hInst;

                  hInst= LoadLibrary (filename);
                  if (hInst==NULL) {
                  var.lasterror = GetLastError ();
                  var.err_rutin = "dlopen";
                  }
                  return hInst;
                  }

                  int dlclose (void *handle)
                  {
                  BOOL ok;
                  int rc= 0;

                  ok= FreeLibrary ((HINSTANCE)handle);
                  if (! ok) {
                  var.lasterror = GetLastError ();
                  var.err_rutin = "dlclose";
                  rc= -1;
                  }
                  return rc;
                  }

                  void *dlsym (void *handle, const char *name)
                  {
                  FARPROC fp;

                  fp= GetProcAddress ((HINSTANCE)handle, name);
                  if (!fp) {
                  var.lasterror = GetLastError ();
                  var.err_rutin = "dlsym";
                  }
                  return (void *)(intptr_t)fp;
                  }

                  const char *dlerror (void)
                  {
                  static char errstr [88];

                  if (var.lasterror) {
                  sprintf (errstr, "%s error #%ld", var.err_rutin, var.lasterror);
                  return errstr;
                  } else {
                  return NULL;
                  }
                  }






                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Nov 29 '18 at 6:06









                  Lorinczy ZsigmondLorinczy Zsigmond

                  9551716




                  9551716






























                      draft saved

                      draft discarded




















































                      Thanks for contributing an answer to Stack Overflow!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function () {
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53530566%2floading-dll-in-windows-c-for-cross-platform-design%23new-answer', 'question_page');
                      }
                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      Contact image not getting when fetch all contact list from iPhone by CNContact

                      count number of partitions of a set with n elements into k subsets

                      A CLEAN and SIMPLE way to add appendices to Table of Contents and bookmarks