{"thread":{"id":"46788","subject":"[PATCH] Win32: simplify loading of DLL functions","startedAt":"2017-09-19T15:25:01Z","lastAt":"2017-09-25T16:52:21Z","messageCount":9,"participants":["Johannes Schindelin","Jonathan Nieder","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"328388","messageId":"f5a3add27206df3e7f39efeac8a3c3b47f2b79f2.1505834586.git.johannes.schindelin@gmx.de","threadId":"46788","inReplyTo":null,"subject":"[PATCH] Win32: simplify loading of DLL functions","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-09-19T15:24:45Z","receivedAt":"2017-09-19T15:25:01Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Dynamic loading of DLL functions is duplicated in several places in Git\nfor Windows' source code.\n\nThis patch adds a pair of macros to simplify the process: the\nDECLARE_PROC_ADDR(<dll>, <return-type>, <function-name>,\n...<function-parameter-types>...) macro to be used at the beginning of a\ncode block, and the INIT_PROC_ADDR(<function-name>) macro to call before\nusing the declared function. The return value of the INIT_PROC_ADDR()\ncall has to be checked; If it is NULL, the function was not found in the\nspecified DLL.\n\nExample:\n\n        DECLARE_PROC_ADDR(kernel32.dll, BOOL, CreateHardLinkW,\n                          LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES);\n\n        if (!INIT_PROC_ADDR(CreateHardLinkW))\n                return error(\"Could not find CreateHardLinkW() function\";\n\n\tif (!CreateHardLinkW(source, target, NULL))\n\t\treturn error(\"could not create hardlink from %S to %S\",\n\t\t\t     source, target);\n\treturn 0;\n\nSigned-off-by: Karsten Blees <blees@dcon.de>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n\n\tSo far, there are no users (except in Git for Windows). Ben\n\tpromised to make use of it in his fsmonitor patch series.\n\nPublished-As: https://github.com/dscho/git/releases/tag/lazyload-v1\nFetch-It-Via: git fetch https://github.com/dscho/git lazyload-v1\n compat/win32/lazyload.h | 44 ++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 44 insertions(+)\n create mode 100644 compat/win32/lazyload.h\n\ndiff --git a/compat/win32/lazyload.h b/compat/win32/lazyload.h\nnew file mode 100644\nindex 00000000000..91c10dad2fb\n--- /dev/null\n+++ b/compat/win32/lazyload.h\n@@ -0,0 +1,44 @@\n+#ifndef LAZYLOAD_H\n+#define LAZYLOAD_H\n+\n+/* simplify loading of DLL functions */\n+\n+struct proc_addr {\n+\tconst char *const dll;\n+\tconst char *const function;\n+\tFARPROC pfunction;\n+\tunsigned initialized : 1;\n+};\n+\n+/* Declares a function to be loaded dynamically from a DLL. */\n+#define DECLARE_PROC_ADDR(dll, rettype, function, ...) \\\n+\tstatic struct proc_addr proc_addr_##function = \\\n+\t{ #dll, #function, NULL, 0 }; \\\n+\tstatic rettype (WINAPI *function)(__VA_ARGS__)\n+\n+/*\n+ * Loads a function from a DLL (once-only).\n+ * Returns non-NULL function pointer on success.\n+ * Returns NULL + errno == ENOSYS on failure.\n+ */\n+#define INIT_PROC_ADDR(function) \\\n+\t(function = get_proc_addr(&proc_addr_##function))\n+\n+static inline void *get_proc_addr(struct proc_addr *proc)\n+{\n+\t/* only do this once */\n+\tif (!proc->initialized) {\n+\t\tHANDLE hnd;\n+\t\tproc->initialized = 1;\n+\t\thnd = LoadLibraryExA(proc->dll, NULL,\n+\t\t\t\t     LOAD_LIBRARY_SEARCH_SYSTEM32);\n+\t\tif (hnd)\n+\t\t\tproc->pfunction = GetProcAddress(hnd, proc->function);\n+\t}\n+\t/* set ENOSYS if DLL or function was not found */\n+\tif (!proc->pfunction)\n+\t\terrno = ENOSYS;\n+\treturn proc->pfunction;\n+}\n+\n+#endif\n\nbase-commit: 9ddaf86b06a8078420f59aec8cab6daa93cf1a91\n-- \n2.14.1.windows.1.1020.g03faabc8bc8.dirty\n"},{"id":"328398","messageId":"20170919180742.GC75068@aiede.mtv.corp.google.com","threadId":"46788","inReplyTo":"f5a3add27206df3e7f39efeac8a3c3b47f2b79f2.1505834586.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH] Win32: simplify loading of DLL functions","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2017-09-19T18:07:42Z","receivedAt":"2017-09-19T18:07:51Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Hi,\n\nJohannes Schindelin wrote:\n\n> Dynamic loading of DLL functions is duplicated in several places in Git\n> for Windows' source code.\n>\n> This patch adds a pair of macros to simplify the process: the\n> DECLARE_PROC_ADDR(<dll>, <return-type>, <function-name>,\n> ...<function-parameter-types>...) macro to be used at the beginning of a\n> code block, and the INIT_PROC_ADDR(<function-name>) macro to call before\n> using the declared function. The return value of the INIT_PROC_ADDR()\n> call has to be checked; If it is NULL, the function was not found in the\n> specified DLL.\n>\n> Example:\n>\n>         DECLARE_PROC_ADDR(kernel32.dll, BOOL, CreateHardLinkW,\n>                           LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES);\n>\n>         if (!INIT_PROC_ADDR(CreateHardLinkW))\n>                 return error(\"Could not find CreateHardLinkW() function\";\n>\n> \tif (!CreateHardLinkW(source, target, NULL))\n> \t\treturn error(\"could not create hardlink from %S to %S\",\n> \t\t\t     source, target);\n> \treturn 0;\n\nnit: whitespace is a bit strange here (mixture of tabs and spaces).\n\nCould this example go near the top of the header instead?  That way,\nit's easier for people reading the header to see how to use it.\n\n> Signed-off-by: Karsten Blees <blees@dcon.de>\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n\nJust curious: what was Karsten's contribution?  (I ask mostly because\nI'm interested in kinds of collaboration git metadata is failing to\ncapture correctly --- e.g. pair programming.)\n\n>         So far, there are no users (except in Git for Windows). Ben\n>         promised to make use of it in his fsmonitor patch series.\n>\n>  compat/win32/lazyload.h | 44 ++++++++++++++++++++++++++++++++++++++++++++\n>  1 file changed, 44 insertions(+)\n>  create mode 100644 compat/win32/lazyload.h\n\nAre any of the Git for Windows users something that could go upstream\nalong with this patch?  That would help illustrate what a good caller\nlooks like, which should help with reviewing future patches that use\nthis code.\n\n> --- /dev/null\n> +++ b/compat/win32/lazyload.h\n> @@ -0,0 +1,44 @@\n[...]\n> +/* Declares a function to be loaded dynamically from a DLL. */\n> +#define DECLARE_PROC_ADDR(dll, rettype, function, ...) \\\n> +\tstatic struct proc_addr proc_addr_##function = \\\n> +\t{ #dll, #function, NULL, 0 }; \\\n> +\tstatic rettype (WINAPI *function)(__VA_ARGS__)\n> +\n> +/*\n> + * Loads a function from a DLL (once-only).\n> + * Returns non-NULL function pointer on success.\n> + * Returns NULL + errno == ENOSYS on failure.\n> + */\n> +#define INIT_PROC_ADDR(function) \\\n> +\t(function = get_proc_addr(&proc_addr_##function))\n\nProbably worth mentioning in the doc comment that this is not thread\nsafe, so a caller that wants to lazy-init in a threaded context is\nresponsible for doing their own locking.\n\n> +\n> +static inline void *get_proc_addr(struct proc_addr *proc)\n> +{\n> +\t/* only do this once */\n> +\tif (!proc->initialized) {\n> +\t\tHANDLE hnd;\n> +\t\tproc->initialized = 1;\n> +\t\thnd = LoadLibraryExA(proc->dll, NULL,\n> +\t\t\t\t     LOAD_LIBRARY_SEARCH_SYSTEM32);\n> +\t\tif (hnd)\n> +\t\t\tproc->pfunction = GetProcAddress(hnd, proc->function);\n> +\t}\n> +\t/* set ENOSYS if DLL or function was not found */\n> +\tif (!proc->pfunction)\n> +\t\terrno = ENOSYS;\n> +\treturn proc->pfunction;\n> +}\n\nstrerror(ENOSYS) is \"Function not implemented\".  Cute.\n\nReviewed-by: Jonathan Nieder <jrnieder@gmail.com>\n\nThanks,\nJonathan\n"},{"id":"328446","messageId":"xmqqvakenfma.fsf@gitster.mtv.corp.google.com","threadId":"46788","inReplyTo":"20170919180742.GC75068@aiede.mtv.corp.google.com","subject":"Re: [PATCH] Win32: simplify loading of DLL functions","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-09-20T04:44:29Z","receivedAt":"2017-09-20T04:44:36Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jonathan Nieder <jrnieder@gmail.com> writes:\n\n> ...\n> strerror(ENOSYS) is \"Function not implemented\".  Cute.\n>\n> Reviewed-by: Jonathan Nieder <jrnieder@gmail.com>\n\nThanks, both.  Will queue.\n"},{"id":"328503","messageId":"alpine.DEB.2.21.1.1709202235300.219280@virtualbox","threadId":"46788","inReplyTo":"20170919180742.GC75068@aiede.mtv.corp.google.com","subject":"Re: [PATCH] Win32: simplify loading of DLL functions","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-09-20T21:16:19Z","receivedAt":"2017-09-20T21:16:37Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Jonathan,\n\nOn Tue, 19 Sep 2017, Jonathan Nieder wrote:\n\n> Johannes Schindelin wrote:\n> \n> > Dynamic loading of DLL functions is duplicated in several places in Git\n> > for Windows' source code.\n> >\n> > This patch adds a pair of macros to simplify the process: the\n> > DECLARE_PROC_ADDR(<dll>, <return-type>, <function-name>,\n> > ...<function-parameter-types>...) macro to be used at the beginning of a\n> > code block, and the INIT_PROC_ADDR(<function-name>) macro to call before\n> > using the declared function. The return value of the INIT_PROC_ADDR()\n> > call has to be checked; If it is NULL, the function was not found in the\n> > specified DLL.\n> >\n> > Example:\n> >\n> >         DECLARE_PROC_ADDR(kernel32.dll, BOOL, CreateHardLinkW,\n> >                           LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES);\n> >\n> >         if (!INIT_PROC_ADDR(CreateHardLinkW))\n> >                 return error(\"Could not find CreateHardLinkW() function\";\n> >\n> > \tif (!CreateHardLinkW(source, target, NULL))\n> > \t\treturn error(\"could not create hardlink from %S to %S\",\n> > \t\t\t     source, target);\n> > \treturn 0;\n> \n> nit: whitespace is a bit strange here (mixture of tabs and spaces).\n\nHeh, I never thought that this would be a problem in *commit messages*.\nTBH I simply copy-edited the code from Git for Windows' source code.\n\n> Could this example go near the top of the header instead?  That way,\n> it's easier for people reading the header to see how to use it.\n\nFunny, I am *so* used to examples being at the very end, from tutorials to\nman pages.\n\nIf my experience is any indication, I would rather keep this order.\n\n> > Signed-off-by: Karsten Blees <blees@dcon.de>\n> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> > ---\n> \n> Just curious: what was Karsten's contribution?\n\nEssentially all of the code. I just moved it around, separated it out from\nthe patch introducing it, used it elsewhere (e.g. in compat/poll/, not yet\ncontributed to git/git) and replaced the LoadLibrary() call by\nLoadLibraryEx() for more precise control over the operation.\n\n> (I ask mostly because I'm interested in kinds of collaboration git\n> metadata is failing to capture correctly --- e.g. pair programming.)\n\nWell, then I have this challenge for you: make use of the history of Git\nfor Windows' master branch. It is rebased to git/git's maint (or for .0\nversions, master) using the \"merging rebase\" strategy (i.e. first merging\nthe to-be-rebased history using the \"ours\" strategy, then applying the\npatches on top, so that the previous commit history is part of the new\nhistory, yet there are still rebased patches ready to be prepared for\nsubmission to git/git). This strategy means that multiple versions of the\nsame patches exist.\n\n> >         So far, there are no users (except in Git for Windows). Ben\n> >         promised to make use of it in his fsmonitor patch series.\n> >\n> >  compat/win32/lazyload.h | 44 ++++++++++++++++++++++++++++++++++++++++++++\n> >  1 file changed, 44 insertions(+)\n> >  create mode 100644 compat/win32/lazyload.h\n> \n> Are any of the Git for Windows users something that could go upstream\n> along with this patch?  That would help illustrate what a good caller\n> looks like, which should help with reviewing future patches that use\n> this code.\n\nI do not currently have the time to do that, that's why I did not\naccompany the patch by any user.\n\nHowever, having said that, Ben's patch series will make for an *excellent*\nuser, fulfilling your wish.\n\n> > --- /dev/null\n> > +++ b/compat/win32/lazyload.h\n> > @@ -0,0 +1,44 @@\n> [...]\n> > +/* Declares a function to be loaded dynamically from a DLL. */\n> > +#define DECLARE_PROC_ADDR(dll, rettype, function, ...) \\\n> > +\tstatic struct proc_addr proc_addr_##function = \\\n> > +\t{ #dll, #function, NULL, 0 }; \\\n> > +\tstatic rettype (WINAPI *function)(__VA_ARGS__)\n> > +\n> > +/*\n> > + * Loads a function from a DLL (once-only).\n> > + * Returns non-NULL function pointer on success.\n> > + * Returns NULL + errno == ENOSYS on failure.\n> > + */\n> > +#define INIT_PROC_ADDR(function) \\\n> > +\t(function = get_proc_addr(&proc_addr_##function))\n> \n> Probably worth mentioning in the doc comment that this is not thread\n> safe, so a caller that wants to lazy-init in a threaded context is\n> responsible for doing their own locking.\n\nTrue.\n\n> > +static inline void *get_proc_addr(struct proc_addr *proc)\n> > +{\n> > +\t/* only do this once */\n> > +\tif (!proc->initialized) {\n> > +\t\tHANDLE hnd;\n> > +\t\tproc->initialized = 1;\n> > +\t\thnd = LoadLibraryExA(proc->dll, NULL,\n> > +\t\t\t\t     LOAD_LIBRARY_SEARCH_SYSTEM32);\n> > +\t\tif (hnd)\n> > +\t\t\tproc->pfunction = GetProcAddress(hnd, proc->function);\n> > +\t}\n> > +\t/* set ENOSYS if DLL or function was not found */\n> > +\tif (!proc->pfunction)\n> > +\t\terrno = ENOSYS;\n> > +\treturn proc->pfunction;\n> > +}\n> \n> strerror(ENOSYS) is \"Function not implemented\".  Cute.\n> \n> Reviewed-by: Jonathan Nieder <jrnieder@gmail.com>\n\nOkay, I'll add that for v2. Will wait a couple of days in case more stuff\ncrops up.\n\nCiao,\nDscho\n"},{"id":"328504","messageId":"20170920212310.GF27425@aiede.mtv.corp.google.com","threadId":"46788","inReplyTo":"alpine.DEB.2.21.1.1709202235300.219280@virtualbox","subject":"Re: [PATCH] Win32: simplify loading of DLL functions","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2017-09-20T21:23:10Z","receivedAt":"2017-09-20T21:23:18Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Johannes Schindelin wrote:\n> On Tue, 19 Sep 2017, Jonathan Nieder wrote:\n\n>> Could this example go near the top of the header instead?  That way,\n>> it's easier for people reading the header to see how to use it.\n>\n> Funny, I am *so* used to examples being at the very end, from tutorials to\n> man pages.\n>\n> If my experience is any indication, I would rather keep this order.\n\nSorry for the lack of clarity.  I meant \"near the top of the header\n*file*\".\n\n[...]\n>> Are any of the Git for Windows users something that could go upstream\n>> along with this patch?  That would help illustrate what a good caller\n>> looks like, which should help with reviewing future patches that use\n>> this code.\n>\n> I do not currently have the time to do that, that's why I did not\n> accompany the patch by any user.\n>\n> However, having said that, Ben's patch series will make for an *excellent*\n> user, fulfilling your wish.\n\nOk.  I think what you are saying is \"go ahead --- anyone is welcome to\ngrab some patches from git for windows and upstream them\", which is a\nperfectly reasonable answer.\n\n[...]\n>> Reviewed-by: Jonathan Nieder <jrnieder@gmail.com>\n>\n> Okay, I'll add that for v2. Will wait a couple of days in case more stuff\n> crops up.\n\nFWIW nothing I noticed came to the level of requiring a v2 imho.  If any\nof the ideas I mentioned seems good, they can go in patches on top.\n\nThe patch is in Junio's jch branch and I wouldn't be surprised if it\nhits \"next\" soon.\n\nThanks again,\nJonathan\n"},{"id":"328546","messageId":"xmqqwp4sk21s.fsf@gitster.mtv.corp.google.com","threadId":"46788","inReplyTo":"20170920212310.GF27425@aiede.mtv.corp.google.com","subject":"Re: [PATCH] Win32: simplify loading of DLL functions","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-09-21T06:18:07Z","receivedAt":"2017-09-21T06:18:15Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jonathan Nieder <jrnieder@gmail.com> writes:\n\n> Johannes Schindelin wrote:\n>> On Tue, 19 Sep 2017, Jonathan Nieder wrote:\n>\n>>> Could this example go near the top of the header instead?  That way,\n>>> it's easier for people reading the header to see how to use it.\n>>\n>> Funny, I am *so* used to examples being at the very end, from tutorials to\n>> man pages.\n>>\n>> If my experience is any indication, I would rather keep this order.\n>\n> Sorry for the lack of clarity.  I meant \"near the top of the header\n> *file*\".\n\nYeah, I think it would help to have something like that near the top\nof the header file for the potential users of the helper.\n\n> FWIW nothing I noticed came to the level of requiring a v2 imho.  If any\n> of the ideas I mentioned seems good, they can go in patches on top.\n\nTrue, too, and additional \"doc in header\" can also be done as a\nfollow-up.\n\nBut as I heard \"v2 in a few days\", I'll throw it in the \"Expecting a\nreroll\" bin for now.\n\nThanks, both.\n"},{"id":"328853","messageId":"cover.1506355545.git.johannes.schindelin@gmx.de","threadId":"46788","inReplyTo":"f5a3add27206df3e7f39efeac8a3c3b47f2b79f2.1505834586.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 0/1] Simplify loading of DLL functions on Windows","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-09-25T16:06:08Z","receivedAt":"2017-09-25T16:06:21Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Changes since v1:\n\n- repeated the example from the commit message in the .h file\n\n- mentioned that the function is not thread-safe.\n\n- added Jonathan's Reviewed-by: footer\n\n\nJohannes Schindelin (1):\n  Win32: simplify loading of DLL functions\n\n compat/win32/lazyload.h | 57 +++++++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 57 insertions(+)\n create mode 100644 compat/win32/lazyload.h\n\n\nbase-commit: 28996cec80690d2322359d3650a57e8de6e01eb6\nPublished-As: https://github.com/dscho/git/releases/tag/lazyload-v2\nFetch-It-Via: git fetch https://github.com/dscho/git lazyload-v2\n\nInterdiff vs v1:\n diff --git a/compat/win32/lazyload.h b/compat/win32/lazyload.h\n index 91c10dad2fb..9e631c8593f 100644\n --- a/compat/win32/lazyload.h\n +++ b/compat/win32/lazyload.h\n @@ -1,7 +1,19 @@\n  #ifndef LAZYLOAD_H\n  #define LAZYLOAD_H\n  \n -/* simplify loading of DLL functions */\n +/*\n + * A pair of macros to simplify loading of DLL functions. Example:\n + *\n + *   DECLARE_PROC_ADDR(kernel32.dll, BOOL, CreateHardLinkW,\n + *                     LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES);\n + *\n + *   if (!INIT_PROC_ADDR(CreateHardLinkW))\n + *           return error(\"Could not find CreateHardLinkW() function\";\n + *\n + *   if (!CreateHardLinkW(source, target, NULL))\n + *           return error(\"could not create hardlink from %S to %S\",\n + *                        source, target);\n + */\n  \n  struct proc_addr {\n  \tconst char *const dll;\n @@ -20,6 +32,7 @@ struct proc_addr {\n   * Loads a function from a DLL (once-only).\n   * Returns non-NULL function pointer on success.\n   * Returns NULL + errno == ENOSYS on failure.\n + * This function is not thread-safe.\n   */\n  #define INIT_PROC_ADDR(function) \\\n  \t(function = get_proc_addr(&proc_addr_##function))\n-- \n2.14.1.windows.1.1024.gf2dea585d74.dirty\n\n"},{"id":"328854","messageId":"177d34742e603aabb57046a0d5f9a5c6e40696ca.1506355545.git.johannes.schindelin@gmx.de","threadId":"46788","inReplyTo":"cover.1506355545.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 1/1] Win32: simplify loading of DLL functions","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-09-25T16:06:24Z","receivedAt":"2017-09-25T16:06:41Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Dynamic loading of DLL functions is duplicated in several places in Git\nfor Windows' source code.\n\nThis patch adds a pair of macros to simplify the process: the\nDECLARE_PROC_ADDR(<dll>, <return-type>, <function-name>,\n...<function-parameter-types>...) macro to be used at the beginning of a\ncode block, and the INIT_PROC_ADDR(<function-name>) macro to call before\nusing the declared function. The return value of the INIT_PROC_ADDR()\ncall has to be checked; If it is NULL, the function was not found in the\nspecified DLL.\n\nExample:\n\n        DECLARE_PROC_ADDR(kernel32.dll, BOOL, CreateHardLinkW,\n                          LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES);\n\n        if (!INIT_PROC_ADDR(CreateHardLinkW))\n                return error(\"Could not find CreateHardLinkW() function\";\n\n\tif (!CreateHardLinkW(source, target, NULL))\n\t\treturn error(\"could not create hardlink from %S to %S\",\n\t\t\t     source, target);\n\treturn 0;\n\nSigned-off-by: Karsten Blees <blees@dcon.de>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\nReviewed-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n compat/win32/lazyload.h | 57 +++++++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 57 insertions(+)\n create mode 100644 compat/win32/lazyload.h\n\ndiff --git a/compat/win32/lazyload.h b/compat/win32/lazyload.h\nnew file mode 100644\nindex 00000000000..9e631c8593f\n--- /dev/null\n+++ b/compat/win32/lazyload.h\n@@ -0,0 +1,57 @@\n+#ifndef LAZYLOAD_H\n+#define LAZYLOAD_H\n+\n+/*\n+ * A pair of macros to simplify loading of DLL functions. Example:\n+ *\n+ *   DECLARE_PROC_ADDR(kernel32.dll, BOOL, CreateHardLinkW,\n+ *                     LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES);\n+ *\n+ *   if (!INIT_PROC_ADDR(CreateHardLinkW))\n+ *           return error(\"Could not find CreateHardLinkW() function\";\n+ *\n+ *   if (!CreateHardLinkW(source, target, NULL))\n+ *           return error(\"could not create hardlink from %S to %S\",\n+ *                        source, target);\n+ */\n+\n+struct proc_addr {\n+\tconst char *const dll;\n+\tconst char *const function;\n+\tFARPROC pfunction;\n+\tunsigned initialized : 1;\n+};\n+\n+/* Declares a function to be loaded dynamically from a DLL. */\n+#define DECLARE_PROC_ADDR(dll, rettype, function, ...) \\\n+\tstatic struct proc_addr proc_addr_##function = \\\n+\t{ #dll, #function, NULL, 0 }; \\\n+\tstatic rettype (WINAPI *function)(__VA_ARGS__)\n+\n+/*\n+ * Loads a function from a DLL (once-only).\n+ * Returns non-NULL function pointer on success.\n+ * Returns NULL + errno == ENOSYS on failure.\n+ * This function is not thread-safe.\n+ */\n+#define INIT_PROC_ADDR(function) \\\n+\t(function = get_proc_addr(&proc_addr_##function))\n+\n+static inline void *get_proc_addr(struct proc_addr *proc)\n+{\n+\t/* only do this once */\n+\tif (!proc->initialized) {\n+\t\tHANDLE hnd;\n+\t\tproc->initialized = 1;\n+\t\thnd = LoadLibraryExA(proc->dll, NULL,\n+\t\t\t\t     LOAD_LIBRARY_SEARCH_SYSTEM32);\n+\t\tif (hnd)\n+\t\t\tproc->pfunction = GetProcAddress(hnd, proc->function);\n+\t}\n+\t/* set ENOSYS if DLL or function was not found */\n+\tif (!proc->pfunction)\n+\t\terrno = ENOSYS;\n+\treturn proc->pfunction;\n+}\n+\n+#endif\n-- \n2.14.1.windows.1.1024.gf2dea585d74.dirty\n"},{"id":"328859","messageId":"20170925165211.GN27425@aiede.mtv.corp.google.com","threadId":"46788","inReplyTo":"177d34742e603aabb57046a0d5f9a5c6e40696ca.1506355545.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v2 1/1] Win32: simplify loading of DLL functions","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2017-09-25T16:52:11Z","receivedAt":"2017-09-25T16:52:21Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Johannes Schindelin wrote:\n\n> Dynamic loading of DLL functions is duplicated in several places in Git\n> for Windows' source code.\n>\n> This patch adds a pair of macros to simplify the process: the\n> DECLARE_PROC_ADDR(<dll>, <return-type>, <function-name>,\n> ...<function-parameter-types>...) macro to be used at the beginning of a\n> code block, and the INIT_PROC_ADDR(<function-name>) macro to call before\n> using the declared function. The return value of the INIT_PROC_ADDR()\n> call has to be checked; If it is NULL, the function was not found in the\n> specified DLL.\n>\n> Example:\n>\n>         DECLARE_PROC_ADDR(kernel32.dll, BOOL, CreateHardLinkW,\n>                           LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES);\n>\n>         if (!INIT_PROC_ADDR(CreateHardLinkW))\n>                 return error(\"Could not find CreateHardLinkW() function\";\n>\n> \tif (!CreateHardLinkW(source, target, NULL))\n> \t\treturn error(\"could not create hardlink from %S to %S\",\n> \t\t\t     source, target);\n> \treturn 0;\n>\n> Signed-off-by: Karsten Blees <blees@dcon.de>\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> Reviewed-by: Jonathan Nieder <jrnieder@gmail.com>\n\nYep, this is indeed\n\nReviewed-by: Jonathan Nieder <jrnieder@gmail.com>\n\n> ---\n>  compat/win32/lazyload.h | 57 +++++++++++++++++++++++++++++++++++++++++++++++++\n>  1 file changed, 57 insertions(+)\n>  create mode 100644 compat/win32/lazyload.h\n\nThanks,\nJonathan\n"}]}