Announcement

Collapse
No announcement yet.

Please help calling a DLL function

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Please help calling a DLL function

    I have this super simple C# test function in a DLL within a class called "Program":

    Code:
    public static string GetTheWordFive()
    {
       return "Five";
    }
    I've tried calling it these two ways - both with the "archive" path as well as the fully qualified path:

    Code:
    result1 = DLL.CallFunction(SessionVar.Expand("%AppFolder%\\EcFtpClient.dll"), "Program.GetTheWordFive", "", DLL_RETURN_TYPE_STRING, DLL_CALL_CDECL);
    Dialog.Message("Title One", result1);
    
    result2 = DLL.CallFunction("C:\\MyFiles\\EcFtpClient.dll", "Program.GetTheWordFive", "", DLL_RETURN_TYPE_STRING, DLL_CALL_CDECL);
    Dialog.Message("Title Two", result2);
    And both times, I get dialog boxes that have a blank "message".
    What is the correct way to call this function?

  • #2
    I am unversed in C# programming, so I cannot help you with your code. Perhaps another developer can jump here and point you what you are missing.

    In a MFC DLL, you could declare a C function like this:
    Code:
    __declspec(dllexport) char *GetTheWordFive(void) {
       return("Five");
    }
    You would need to add the funcion name GetTheWordFive to the *.def file, so it would be exported and visible to processes loading the DLL. Then, in Lua, you would call the function like this, assuming that you added the DLL to the primer files of your Setup Factory project:

    Code:
    local sReply = DLL.CallFunction(SessionVar.Expand("%TempLaunchFolder%\\SampleDLL.dll"),
       "GetTheWordFive", "", DLL_RETURN_TYPE_STRING, DLL_CALL_CDECL);
    error = Application.GetLastError();
    if (error ~= 0) then
       Dialog.Message("Error", _tblErrorMessages[error], MB_OK, MB_ICONEXCLAMATION);
    else
       Dialog.Message("Output", "DLL.CallFunction() returned: " .. sReply, MB_OK, MB_ICONINFORMATION);
    end
    This results in the dialog below:
    Click image for larger version

Name:	SCRN-2015-05-21-01.png
Views:	1
Size:	17.7 KB
ID:	284311
    I attached a sample project, and the DLL, so you can test this.

    Ulrich

    Comment


    • #3
      Instead of having it in the Primer Files, it was in the Archive Files section. So I added it to the Primer Files - and although it is progress - I now get this:
      "Failed to find the specified function within the DLL"
      as the message in your dialog box. So it sounds like it's finding the DLL just can't find the function.

      By the way, that C# function is certainly valid. :-)

      But I am not familiar with DEF files for C#. Does Setup Factory definitely require that? Please let me know; if that is the case, I will learn how to create one. Also, assuming I need one, where would the DEF file go - also in the Primer Files?

      Thank you very much!
      Eliezer

      Comment


      • #4
        I believe that you will need to read stuff like this in order to get this working. It might be easier if you use C/C++ to write your DLL instead of C#.

        Ulrich

        Comment


        • #5
          This is an ancient thread but my reply is relevant so am archiving the knowledge here. We've successfully used the tool at the link below to make it EASY to create unmanaged interfaces for .NET applications, including for use with Setup Factory.

          https://sites.google.com/site/robert...managedexports

          Comment


          • #6
            Greg,

            While this an old thread, any chance you would be willing to share an example of exactly how you make a DLL call from Setup Factory to managed .Net code?

            I downloaded the latest DllExports from GitHub and was able to successfully compile a simple .Net 4.5.2 VB.Net dll in VS 2019. Unfortunately, when I make the call from Setup Factory using DLL.CallFunction, I get an empty return value versus a simple text string or integer (depending on the call function).

            Any suggestions would be greatly appreciated.

            Thanks,
            Mark

            Comment


            • #7
              Originally posted by ruthema View Post
              Greg,

              While this an old thread, any chance you would be willing to share an example of exactly how you make a DLL call from Setup Factory to managed .Net code?

              I downloaded the latest DllExports from GitHub and was able to successfully compile a simple .Net 4.5.2 VB.Net dll in VS 2019. Unfortunately, when I make the call from Setup Factory using DLL.CallFunction, I get an empty return value versus a simple text string or integer (depending on the call function).

              Any suggestions would be greatly appreciated.

              Thanks,
              Mark
              Use DllExport nuget package, either configure using wizard at startup, or run DllExport.bat from that package, open solution, select your project, check "Installed", click apply.
              In your C++ code write something like this:

              Code:
              [DllExport("TestFunc")]
              public static void TestFunc()
              {
              MessageBox.Show("yepii");
              }
              Make sure that your project uses either x86 or x64 platform - same as installation.

              Add into installer your assembly as a primer file.

              In Lua script add following call:

              Code:
              dll = SessionVar.Expand("%TempLaunchFolder%\\DisplayMess age.dll")
              log("Calling " .. dll)
              DLL.CallFunction(dll, "TestFunc", "", DLL_RETURN_TYPE_LONG, DLL_CALL_CDECL)
              log("After all ")
              Haven't yet tried passing any arguments, but suspect should be trivial.

              Comment


              • #8
                Please note that if .net framework is not installed, then installer will simply crash. Make sure that you install .net framework first.

                Comment


                • #9
                  Returning string from a function...

                  C#:

                  Code:
                   [DllExport("TestFunc2")]
                  [return: MarshalAs(UnmanagedType.LPStr)]
                  public static String TestFunc2()
                  {
                  MessageBox.Show("yepii2");
                  return "func ret";
                  }
                  Lua:
                  Code:
                   ret = DLL.CallFunction(dll, "TestFunc2", "", DLL_RETURN_TYPE_STRING, DLL_CALL_CDECL)

                  Comment


                  • #10
                    Originally posted by Tarmo Pikaro View Post

                    In your C++ code write something like this:
                    That is of course C#, not C++, sorry.

                    Comment


                    • #11
                      Thanks for the posts. It continues to be a work in progress, but I am getting there.

                      Comment


                      • #12
                        Please note that after .net dll is loaded, it's not automatically deleted from temp folder anymore. Problem is that installer itself locks those files.

                        I have by myself added extra function on .net side to perform files deletion afterwards. It generates powershell script, which launches and waits for installer to exit.

                        Code:
                                /// <summary>
                                /// Installation uses .net framework assembly, but problem is that application itself cannot delete temporary folder, due to share violation with .net framework.
                                /// We start here powershell on background, which will wait for main process to exist, and perform folder / file deletion after that one.
                                /// </summary>
                                [DllExport("CleanupAfterApplicationExit")]
                                public static void CleanupAfterApplicationExit()
                                {
                                    try
                                    {
                                        var procId = Process.GetCurrentProcess().Id;
                        
                                        String dllPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
                                        String tempDir = Path.GetDirectoryName(dllPath);
                        
                                        // For testing purposes only, Setup factory normally places in temp folder named with "_ir_sf_temp"
                                        if (!tempDir.Contains("_ir_sf_temp"))
                                        {
                                            tempDir = Path.Combine(tempDir, "_ir_sf_temp");
                                            if (!Directory.Exists(tempDir))
                                            {
                                                Directory.CreateDirectory(tempDir);
                                            }
                                            File.Copy(dllPath, Path.Combine(tempDir, Path.GetFileName(dllPath)), true);
                                        }
                        
                                        String ps1Path = Path.Combine(Path.GetDirectoryName(tempDir), $"0_cleanup_{procId}.ps1");
                        
                                        String ps1 = $"$proc = [System.Diagnostics.Process]::GetProcessById({procId})\n" +
                                            "$proc.WaitForExit()\n" +
                                            $"Remove-Item -Recurse -Force \"{tempDir}\"\n" +
                                            $"Remove-Item -Path \"{ps1Path}\"\n"
                                        ;
                        
                                        File.WriteAllText(ps1Path, ps1);
                        
                                        var process = new Process();
                                        process.StartInfo.UseShellExecute = true;
                                        process.StartInfo.RedirectStandardOutput = false;
                                        process.StartInfo.WindowStyle = ProcessWindowStyle.Minimized;
                                        process.StartInfo.FileName = @"C:\windows\system32\windowspowershell\v1.0\powershell.exe";
                                        process.StartInfo.Arguments = "-executionpolicy bypass -file \"" + ps1Path + "\"";
                                        process.Start();
                                    }
                                    catch (Exception ex)
                                    {
                                        String msg = $"{ex.Message}\r\ncallstack: {ex.StackTrace}";
                                        EventLog.WriteEntry(".NET Runtime", msg, EventLogEntryType.Error, 1000);
                                    }
                                }
                        I'm calling that function from multiple places, either cancel or install successful. Need to try every situation.

                        Comment

                        Working...
                        X