Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
CODE PROJECT For Those Who Code
  • Home
  • Articles
  • FAQ
Community
  1. Home
  2. General Programming
  3. C#
  4. Call a function from a dynamically loaded C dll [Answered]

Call a function from a dynamically loaded C dll [Answered]

Scheduled Pinned Locked Moved C#
csharpc++question
9 Posts 4 Posters 1 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • B Offline
    B Offline
    Bernhard Hiller
    wrote on last edited by
    #1

    Hi there, when we want to use a function from a C dll, we have to declare it like:

        \[DllImport(ThirdPartyDll)\]
        private static extern int SomeFunction(string Param1, and so on);
    

    Now, ThirdParty provides a row of dlls with all of them implementing that SomeFunction with the same signature (only some interenal parameters differ leading to different results). We want our users to select the dll they want to use for that purpose. That means, ThirdPartyDll in [DllImport(ThirdPartyDll)] must become a variable instead of a constant. But C# does not allow a variable at the DllImport declaration. In old C++, that's possible, I do not remember the exact way, there was some use of function pointers. But this is a program written in C# (.Net 2.0). How can we do that here? Looking forward to your hints. Bernhard

    G A 2 Replies Last reply
    0
    • B Bernhard Hiller

      Hi there, when we want to use a function from a C dll, we have to declare it like:

          \[DllImport(ThirdPartyDll)\]
          private static extern int SomeFunction(string Param1, and so on);
      

      Now, ThirdParty provides a row of dlls with all of them implementing that SomeFunction with the same signature (only some interenal parameters differ leading to different results). We want our users to select the dll they want to use for that purpose. That means, ThirdPartyDll in [DllImport(ThirdPartyDll)] must become a variable instead of a constant. But C# does not allow a variable at the DllImport declaration. In old C++, that's possible, I do not remember the exact way, there was some use of function pointers. But this is a program written in C# (.Net 2.0). How can we do that here? Looking forward to your hints. Bernhard

      G Offline
      G Offline
      Gonzalo Cao
      wrote on last edited by
      #2

      I don't know if you have better ways to do this, but one idea is to declare them all and after that you define a Delegate with the same signature. This way you can assign the corresponding function to the delegate, this way you got pretty much the same functionality that you get with pointers to functions.

      B 1 Reply Last reply
      0
      • G Gonzalo Cao

        I don't know if you have better ways to do this, but one idea is to declare them all and after that you define a Delegate with the same signature. This way you can assign the corresponding function to the delegate, this way you got pretty much the same functionality that you get with pointers to functions.

        B Offline
        B Offline
        Bernhard Hiller
        wrote on last edited by
        #3

        Thanks for this idea. In most cases it would do the job. But ThirdParty might provide another such dll with a new name, and it cannot be used before the function of that specific dll was declared. In C++ there is some way to do that, but in C#?

        1 Reply Last reply
        0
        • B Bernhard Hiller

          Hi there, when we want to use a function from a C dll, we have to declare it like:

              \[DllImport(ThirdPartyDll)\]
              private static extern int SomeFunction(string Param1, and so on);
          

          Now, ThirdParty provides a row of dlls with all of them implementing that SomeFunction with the same signature (only some interenal parameters differ leading to different results). We want our users to select the dll they want to use for that purpose. That means, ThirdPartyDll in [DllImport(ThirdPartyDll)] must become a variable instead of a constant. But C# does not allow a variable at the DllImport declaration. In old C++, that's possible, I do not remember the exact way, there was some use of function pointers. But this is a program written in C# (.Net 2.0). How can we do that here? Looking forward to your hints. Bernhard

          A Offline
          A Offline
          Alan N
          wrote on last edited by
          #4

          Bernhard, Dynamically loading an unmanaged dll uses an almost direct translation of C code. In the example note the use of 1) the UnmanagedFunctionPointer attribute on the SomeFunction delegate declaration 2) the Marshal.GetDelegateForFunctionPointer method to convert the raw function pointer to the C# friendly delegate.

          using System;
          using System.Runtime.InteropServices;
          internal class DynamicLoad {
          [DllImport("kernel32.dll", SetLastError = true)]
          private static extern IntPtr LoadLibrary(String dllToLoad);

          [DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
          private static extern IntPtr GetProcAddress(IntPtr hModule, string procName);

          [DllImport("kernel32.dll", SetLastError = true)]
          private static extern bool FreeLibrary(IntPtr hModule);

          // Assuming CharSet.Ansi, you may be Unicode.
          [UnmanagedFunctionPointer(CallingConvention.StdCall, SetLastError = false, CharSet = CharSet.Ansi)]
          internal delegate int SomeFunction(string Param1);

          private IntPtr dllPtr;
          internal SomeFunction someFunction;

          internal Boolean Load(String dllPath) {
          dllPtr = LoadLibrary(dllPath);
          // Int32 code = Marshal.GetLastWin32Error();
          // TODO: error handling
          if (dllPtr != IntPtr.Zero) {
          try {
          someFunction = (SomeFunction)Marshal.GetDelegateForFunctionPointer(
          GetProcAddress(dllPtr, "SomeFunction"),
          typeof(SomeFunction));
          } catch (ArgumentNullException) {
          // SomeFunction was not found
          Unload();
          }
          }
          return (dllPtr != IntPtr.Zero);
          }

          internal void Unload() {
          bool result = FreeLibrary(dllPtr);
          // TODO: error handling
          dllPtr = IntPtr.Zero;
          }
          }

          Alan.

          B G 2 Replies Last reply
          0
          • A Alan N

            Bernhard, Dynamically loading an unmanaged dll uses an almost direct translation of C code. In the example note the use of 1) the UnmanagedFunctionPointer attribute on the SomeFunction delegate declaration 2) the Marshal.GetDelegateForFunctionPointer method to convert the raw function pointer to the C# friendly delegate.

            using System;
            using System.Runtime.InteropServices;
            internal class DynamicLoad {
            [DllImport("kernel32.dll", SetLastError = true)]
            private static extern IntPtr LoadLibrary(String dllToLoad);

            [DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
            private static extern IntPtr GetProcAddress(IntPtr hModule, string procName);

            [DllImport("kernel32.dll", SetLastError = true)]
            private static extern bool FreeLibrary(IntPtr hModule);

            // Assuming CharSet.Ansi, you may be Unicode.
            [UnmanagedFunctionPointer(CallingConvention.StdCall, SetLastError = false, CharSet = CharSet.Ansi)]
            internal delegate int SomeFunction(string Param1);

            private IntPtr dllPtr;
            internal SomeFunction someFunction;

            internal Boolean Load(String dllPath) {
            dllPtr = LoadLibrary(dllPath);
            // Int32 code = Marshal.GetLastWin32Error();
            // TODO: error handling
            if (dllPtr != IntPtr.Zero) {
            try {
            someFunction = (SomeFunction)Marshal.GetDelegateForFunctionPointer(
            GetProcAddress(dllPtr, "SomeFunction"),
            typeof(SomeFunction));
            } catch (ArgumentNullException) {
            // SomeFunction was not found
            Unload();
            }
            }
            return (dllPtr != IntPtr.Zero);
            }

            internal void Unload() {
            bool result = FreeLibrary(dllPtr);
            // TODO: error handling
            dllPtr = IntPtr.Zero;
            }
            }

            Alan.

            B Offline
            B Offline
            Bernhard Hiller
            wrote on last edited by
            #5

            Alan, wow! Extremely complicated don't-c-sharp-code, but it works! Lots of thanks, Bernhard

            P 1 Reply Last reply
            0
            • B Bernhard Hiller

              Alan, wow! Extremely complicated don't-c-sharp-code, but it works! Lots of thanks, Bernhard

              P Offline
              P Offline
              Phil J Pearson
              wrote on last edited by
              #6

              Not really so complicated - he just makes it look complicated with his loony formatting :) ;P . However, I gave him a lolly because it's a very good answer.

              Phil


              The opinions expressed in this post are not necessarily those of the author, especially if you find them impolite, inaccurate or inflammatory.

              1 Reply Last reply
              0
              • A Alan N

                Bernhard, Dynamically loading an unmanaged dll uses an almost direct translation of C code. In the example note the use of 1) the UnmanagedFunctionPointer attribute on the SomeFunction delegate declaration 2) the Marshal.GetDelegateForFunctionPointer method to convert the raw function pointer to the C# friendly delegate.

                using System;
                using System.Runtime.InteropServices;
                internal class DynamicLoad {
                [DllImport("kernel32.dll", SetLastError = true)]
                private static extern IntPtr LoadLibrary(String dllToLoad);

                [DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
                private static extern IntPtr GetProcAddress(IntPtr hModule, string procName);

                [DllImport("kernel32.dll", SetLastError = true)]
                private static extern bool FreeLibrary(IntPtr hModule);

                // Assuming CharSet.Ansi, you may be Unicode.
                [UnmanagedFunctionPointer(CallingConvention.StdCall, SetLastError = false, CharSet = CharSet.Ansi)]
                internal delegate int SomeFunction(string Param1);

                private IntPtr dllPtr;
                internal SomeFunction someFunction;

                internal Boolean Load(String dllPath) {
                dllPtr = LoadLibrary(dllPath);
                // Int32 code = Marshal.GetLastWin32Error();
                // TODO: error handling
                if (dllPtr != IntPtr.Zero) {
                try {
                someFunction = (SomeFunction)Marshal.GetDelegateForFunctionPointer(
                GetProcAddress(dllPtr, "SomeFunction"),
                typeof(SomeFunction));
                } catch (ArgumentNullException) {
                // SomeFunction was not found
                Unload();
                }
                }
                return (dllPtr != IntPtr.Zero);
                }

                internal void Unload() {
                bool result = FreeLibrary(dllPtr);
                // TODO: error handling
                dllPtr = IntPtr.Zero;
                }
                }

                Alan.

                G Offline
                G Offline
                Gonzalo Cao
                wrote on last edited by
                #7

                Ok, now, that's an answer :). And now here's a question, what if SomeMethod's signatures does not match the delegate signature?? Do I get an ArgumentException?? I know this should be a problem since he knows the signature of the method. Just asking out of curiosity.

                B 1 Reply Last reply
                0
                • G Gonzalo Cao

                  Ok, now, that's an answer :). And now here's a question, what if SomeMethod's signatures does not match the delegate signature?? Do I get an ArgumentException?? I know this should be a problem since he knows the signature of the method. Just asking out of curiosity.

                  B Offline
                  B Offline
                  Bernhard Hiller
                  wrote on last edited by
                  #8

                  Just tested that. I inserted another parameter before the normal first parameter (which is the name of a file), then called the function. The int value returned by the function is an error code, now the result was 1. According to the documentation of the manufacturer "1" means "File access error", i.e. my first parameter (although it was an int) was treated as the expected parameter (a string denoting the file name), and extra parameters seem to have been discarded. In summary, you do not get an exception, the function just executes (and may happen to return an error code or destroy your system).

                  G 1 Reply Last reply
                  0
                  • B Bernhard Hiller

                    Just tested that. I inserted another parameter before the normal first parameter (which is the name of a file), then called the function. The int value returned by the function is an error code, now the result was 1. According to the documentation of the manufacturer "1" means "File access error", i.e. my first parameter (although it was an int) was treated as the expected parameter (a string denoting the file name), and extra parameters seem to have been discarded. In summary, you do not get an exception, the function just executes (and may happen to return an error code or destroy your system).

                    G Offline
                    G Offline
                    Gonzalo Cao
                    wrote on last edited by
                    #9

                    Thank you :)

                    1 Reply Last reply
                    0
                    Reply
                    • Reply as topic
                    Log in to reply
                    • Oldest to Newest
                    • Newest to Oldest
                    • Most Votes


                    • Login

                    • Don't have an account? Register

                    • Login or register to search.
                    • First post
                      Last post
                    0
                    • Categories
                    • Recent
                    • Tags
                    • Popular
                    • World
                    • Users
                    • Groups