Unleashing External Power: Triggering DLLs in Electron Apps with Node.js 20.14 and .NET 8

Avihu Pinko
4 min readJun 30, 2024

--

Introduction:

Electron, the framework powering desktop applications like Slack and Discord, excels at bridging the gap between web technologies and native functionalities. This article explores how to leverage Node.js 20.14 and .NET 8 to seamlessly trigger external DLLs within your Electron applications, unlocking the power of existing native libraries.

Approaches to Triggering External DLLs:

  • Node-FFI (Consider for Legacy Projects): While Node-FFI remains a popular library, it’s important to note that it primarily receives support for older Node.js versions. Here’s an example of using Node-FFI to call a function from a DLL (replace with your specific function and DLL names):
const ffi = require('node-ffi');
// Load the DLL
const myDll = ffi.Library('./path/to/your/dll.dll', {
'myFunction': ['int', ['int', 'string']]
});
// Call the function from the DLL
const result = myDll.myFunction(42, 'Hello from Node.js!');
console.log(result);
  • .NET Wrapper with Electron-Edge-js (Recommended for Modern Projects): This approach leverages .NET 8 to create a wrapper around your external DLL. Electron-Edge-js then facilitates communication between the Node.js code in your Electron application and the .NET wrapper. This approach offers advantages like improved performance and access to a wider range of .NET functionalities. Here’s a breakdown of the steps involved:
  1. Create a .NET 8 Class: Develop a C# class in your .NET 8 project that exposes methods to interact with your external DLL. This class will serve as the bridge between your Electron application and the native functionalities within the DLL.

Example (assuming your DLL name is external.dll):

public class DllWrapper
{
[DllImport("external.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern int Function1(string prop1, string prop2);

public async Task<object> Function1Async(dynamic input)
{
string prop1 = (string)input.prop1;
string prop2 = (string)input.prop2;
int result = Function1(prop1, prop2);
return result;
}
}
  • Utilize Electron-Edge-js: In your Node.js code (within your Electron application), use Electron-Edge-js to interact with the .NET wrapper class created in step 1. Here’s an example of using Electron-Edge-js to call the Function1Async method exposed by the .NET wrapper class:
const electronEdge = require('electron-edge-js');

const { Function1Async } = electronEdge.func({
assemblyFile: path.join(__dirname, 'path/to/your/wrapper.dll'), // Replace with your DLL path
typeName: 'YourNameSpace.DllWrapper', // Replace with your namespace and class name
methodName: 'Function1Async'
});

async function callNativeFunction() {
const result = await Function1Async({ prop1: 'value1', prop2: 'value2' });
console.log(`Result from native function: ${result}`);
}

callNativeFunction();

Choosing the Right Approach:

The choice between Node-FFI and the .NET wrapper approach depends on your specific needs:

  1. Node-FFI (Consider for Legacy Projects): If you’re working on an existing project that uses Node-FFI with an older Node.js version and requires minimal changes, it might be an option to continue using it. However, be mindful of potential compatibility issues when upgrading to newer Node.js versions in the future.
  2. .NET Wrapper with Electron-Edge-js (Recommended for Modern Projects): Opt for the .NET wrapper approach if you’re starting a new project or want to leverage the benefits of modern Node.js versions. Electron-Edge-js is actively maintained and ensures compatibility with the latest Node.js releases. It also offers advantages like:
  • Access to a wider range of .NET functionalities beyond basic function calls.
  • Improved performance optimization using .NET 8’s capabilities.
  • A more structured and maintainable codebase for complex interactions with the external DLL.

Benefits of Using a .NET Wrapper:

  • Improved Maintainability: The .NET wrapper class encapsulates the interaction with the external DLL, making your Node.js code cleaner and easier to understand. You can modify the wrapper logic without affecting the rest of your Electron application. This separation of concerns improves code maintainability in the long run.
  • Type Safety: .NET 8 offers type safety, which helps prevent errors during development and improves code reliability. By explicitly defining the data types for function arguments and return values in the wrapper class, you can catch potential type mismatches at compile time. This leads to a more robust application.
  • Access to .NET Functionalities: You can leverage additional functionalities provided by .NET 8 within your wrapper class, potentially simplifying complex tasks compared to pure JavaScript implementations. For instance, you might use .NET’s asynchronous programming features to handle long-running operations from the external DLL efficiently within your Electron application.

Additional Considerations:

  • Error Handling: Implement proper error handling mechanisms in both the .NET wrapper and your Node.js code to gracefully handle potential issues during communication with the external DLL. Consider error scenarios like:
  • The external DLL might not be found or loaded correctly.
  • Function calls within the DLL might encounter errors.
  • Communication between Electron-Edge-js and the .NET wrapper might fail.
  • You can leverage exception handling mechanisms in .NET to catch errors within the wrapper and provide meaningful error messages to your Node.js code.
  • Testing: Rigorously test your Electron application’s interaction with the external DLL through various scenarios to ensure everything functions as expected. Write unit tests for the .NET wrapper class and integration tests for your Electron application to cover different functionalities. This ensures a reliable and well-functioning application.

Conclusion:

Leveraging Node.js 20.14 and .NET 8, you can effectively trigger external DLLs within your Electron applications. While Node-FFI can be an option for legacy projects, the .NET wrapper approach with Electron-Edge-js offers a more robust and future-proof solution for modern Electron development. This approach provides improved maintainability, type safety, access to .NET functionalities, and a clear separation of concerns between your Electron application and the external DLL logic. Remember to carefully consider error handling and robust testing strategies to ensure a reliable and well-functioning application.

Further Exploration:

  • Explore the official documentation for Electron-Edge-js (https://github.com/agracio/electron-edge-js) for in-depth usage examples and advanced configuration options.
  • Refer to the .NET 8 documentation (https://learn.microsoft.com/en-us/dotnet/) to delve deeper into functionalities that you can leverage within your .NET wrapper class. Explore features like asynchronous programming, exception handling, and advanced data structures within .NET that can enhance your wrapper’s capabilities.

By understanding these concepts and approaches, you can effectively bridge the gap between web technologies and native functionalities within your Electron applications, empowering you to create powerful and versatile desktop experiences.

--

--