Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NativeCommon.cs assumes Realm.dll is available in folder at runtime #1249

Closed
jonstodle opened this issue Feb 22, 2017 · 4 comments

Comments

@jonstodle
Copy link

commented Feb 22, 2017

Goal

Initiate Realm database instance

Expected Results

App not crashing and Realm running

Actual Results

App crashes at first attempt to call Realm.GetInstance()

Steps & Code to Reproduce

When Realm initiates it tries to add the wrappers to the system path: source.
When I try to instantiate Realm I get the following error: System.ArgumentException: 'The path is not of a legal form'

Stacktrace:

at System.IO.Path.NormalizePath(String path, Boolean fullCheck, Int32 maxPathLength, Boolean expandShortPaths)
at System.IO.Path.GetDirectoryName(String path)
at Realms.NativeCommon.Initialize() i C:\jenkins\workspace\realm_realm-dotnet_PR-1223-4E2DZQNMDOPNV3XKK66RA6LTQ6DJHQAOF3TMUKV5U3XROLMF622Q\Shared\Realm.Shared\Native\NativeCommon.cs:line 81
at Realms.Realm..cctor() i C:\jenkins\workspace\realm_realm-dotnet_PR-1223-4E2DZQNMDOPNV3XKK66RA6LTQ6DJHQAOF3TMUKV5U3XROLMF622Q\Shared\Realm.Shared\Realm.cs:line 52

I use Costura to package all DLLs into a single exe file. It works as expected when running from Debug or Release when developing. Moving the packaged exe file to another folder does not work.

By renaming Realm.dll to !Realm.dll I can reproduce the problem even in Debug when developing.

It looks like Realm assumes Realm.dll is located in the same folder as the exe that references it. It also assumes that the folder containing Realm.dll also conatains the following paths: lib\Win32\x64\realm-wrappers.dll and lib\Win32\x86\realm-wrappers.dll.

This setup will probably work nicely using an installer which copies all the right files to all the right locations, but it's not optimal when using Realm in a "stand-alone exe".

Code Sample

var realm = Realm.GetInstance(); // < This throws an exception

Version of Realm and tooling

Realm version(s): 1.0.4

Xamarin/Visual Studio version: VS2017RC (15.0.26206.0 D15REL)

Which operating system version and device: Windows 10 Enterprise 1607

@fealebenpae

This comment has been minimized.

Copy link
Contributor

commented Feb 23, 2017

Hey @jonstodle,

Realm assumes its assemblies are located on disk in this instance, yes. You can use Costura's CreateTemporaryAssemblies option to have it extract the assemblies somewhere on disk before loading them so that Path.GetDirectoryName(typeof(NativeCommon).Assembly.Location) will work. It'll add a non-existent location to PATH but that ought not be an issue as long as you've added the native realm-wrappers.dll libraries as embedded resources in your app under the costura32 and costura64 folders so that they get preloaded by Costura.

Costura looks interesting, and I believe it might be possible to add out-of-the-box support for it. If you'd be interested in that, please open a new issue requesting it so that other users can vote and help us measure interest and prioritize accordingly.

@AndyDentFree

This comment has been minimized.

Copy link
Contributor

commented Feb 23, 2017

Costura looks really clever, and I'm big Richter fan, but there may be a gotcha using loading without a temporary copy.

I'm not sure if this would apply but in a former life I did quite a bit of consulting in REALbasic. Back in 2008 they ran into issues with a similar single-executable packaging and loading idea. I found a long essay on why which goes through why this fails on a small number of machines:

the operating system simply does not allow for DLLs to be loaded by anything other than the OS loader...application compatibility shims. Microsoft's OS loader handles these shims internally, and there is absolutely, positively, no way for us to mimic the functionality. We must use the system loader to load DLLs in order for them to be loaded properly.

...

many times Microsoft comes out with a hotfix that includes more compatibility shims. They have an ever-growing database of times when a shim needs to be loaded. And if the shim isn't loaded, the bugs can be spectacular. Sometimes they're subtle crashes at any point during the application's session. Sometimes it's a crash when the app launches, or a big hairy dialog that makes no sense at various times, etc. What's more, something as simple as installing a hotfix could break an application, but only one one particular hardware configuration!

@jonstodle

This comment has been minimized.

Copy link
Author

commented Feb 23, 2017

I'll try the Costura config when I get back to the dev box

@jonstodle

This comment has been minimized.

Copy link
Author

commented Feb 28, 2017

Finally got back after a bit of travelling.

With the suggested config for Costura it worked like a charm. Here's the gist for those coming here from Google:

  • Edit the Costura element in FodyWeavers.xml to be <Costura CreateTemporaryAssemblies="true" Unmanaged32Assemblies="realm-wrappers" Unmanaged64Assemblies="realm-wrappers"/>
  • Create the folders Costura32 and Costura64 in the root of your project.
  • Add the realm-wrappers.dll from <project folder>\bin\Debug\lib\win32\x86 to Costura32 and <project folder>\bin\Debug\lib\win32\x64 to Costura64
  • Right click the added DLLs and click on Properties and set Build Action to Embedded Resource
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
6 participants
You can’t perform that action at this time.