Re: Empty LST files?
On Sunday, 31 July 2016 at 17:01:32 UTC, Seb wrote: On Sunday, 31 July 2016 at 16:55:52 UTC, Seb wrote: On Sunday, 31 July 2016 at 16:48:52 UTC, Thalamus wrote: On Sunday, 31 July 2016 at 16:08:49 UTC, Seb wrote: On Sunday, 31 July 2016 at 15:30:46 UTC, Thalamus wrote: [...] How about setting the source path directly? With a recent enough dmd version this can be done automatically like here: https://github.com/dlang/dmd/pull/5990/files Thanks Seb. Has this been included in an official version release yet? (I'm not sure how to tell. I've only used Git a small amount.) thanks! Nope it has been added five days ago. You might grab a dmd-nightly build from here https://dlang.org/download.html To clarify I am talking about ___FILE_FULL_PATH__, maybe hard-coding the source directory could also work for you? In the end, I elected to go with a separate solution for test EXEs with the project hierarchy echoed as solution folders. Although this adds some extra overhead to maintain this echo, that can be automated as part of the main solution's build. And it seems to me that there are inherent advantages to going this route. For instance, were this all still in one solution, I'd either have to add additional configurations (32-bit w/ -cov, and 64-bit w/ -cov), or I'd have to manually add -cov to each project whenever I wanted coverage info and later remove it, or I'd have to wait for the code coverage files to be created after every run. A separate solution allows me to maintain -cov for all configurations isolated from my main development mode. So it's there when I want it and gone when I don't, seamlessly. Thanks to everyone for their input!
Re: Empty LST files?
On Sunday, 31 July 2016 at 16:08:49 UTC, Seb wrote: On Sunday, 31 July 2016 at 15:30:46 UTC, Thalamus wrote: On Sunday, 31 July 2016 at 14:03:49 UTC, Thalamus wrote: [...] After a couple more hours today, I found a couple of solutions. Neither is satisfactory. [...] How about setting the source path directly? With a recent enough dmd version this can be done automatically like here: https://github.com/dlang/dmd/pull/5990/files Thanks Seb. Has this been included in an official version release yet? (I'm not sure how to tell. I've only used Git a small amount.) thanks!
Re: Empty LST files?
On Sunday, 31 July 2016 at 14:03:49 UTC, Thalamus wrote: On Sunday, 31 July 2016 at 10:05:04 UTC, Basile B. wrote: On Sunday, 31 July 2016 at 08:29:47 UTC, Basile B. wrote: On Sunday, 31 July 2016 at 01:10:40 UTC, Thalamus wrote: Any idea what I'm doing wrong? Yes, what's going wrong is quite actually you said that the LST is well generated but empty so my previous answer is wrong, also i was focused on unittest coverage which doesn't seem to be what you want to verify. Thank Basile. Yes, these aren't unit tests, but rather integration tests, end-to-end tests, etc., all of which are driven from external EXEs. This is a complex application consisting (thus far) of 17 D and C# projects. Within a single project, D (and Visual D) work very well, but across projects I've run into a lot of challenges. Not being able to build these projects into DLLs without resorting to C-linkage for D-to-D interop (which Benjamin Thaut is working on fixing) was tough to swallow, and I can't used LIBs because in some cases I have projects that are not referenced at build time but whose classes are instead discovered at run time, so I'm forced to resort to OBJs for now. Code coverage is a must, though, so I'm really digging in here. I found part of the problem: Hitting F5 in Visual Studio after a fresh rebuild was giving me an error "cannot launch debugger... hr = 89710016" which looks to be related to Visual D. Subsequent runs work fine, but it was annoying me so I added the EXE itself as the startup project. This ran properly every time, but it resulted the LST files ending up in the build folder, and they were all empty. So I switched back to the test project as the startup project and, after the errant run, it generated LSTs in the EXE project root folder as expected. In this case, all the test EXE LST files were populated as expected, but all of the LSTs for the code being tested were still empty. I really don't need code coverage numbers for the test code, and currently I still get none for the code I do need to measure. But it's still progress. If anyone else has ideas I'd love to hear them. Otherwise, if I figure it out, I will add a quick explanation to this thread. thanks! After a couple more hours today, I found a couple of solutions. Neither is satisfactory. The first is to include the project that builds the EXE in the same folder as the project that builds the OBJ. The problem with this is that each OBJ will also have to have its own EXE, and aggregating information from each of these EXEs becomes a real chore. The second is to include all the source files directly in the test EXE project, AND to move the test EXE into its own solution. Having to maintain the same module hierarchy in two projects is obviously error prone. Having to maintain the separate solution is not a problem, really, but the reason it's necessary is a bit annoying: it seems that Visual D automatically includes the OBJ for any project previously built in the build process of subsequent projects, so whether you build the test EXE first or last, you end up with multiple definition problems, once in the EXE and once in the project OBJ, or once in the project and once in the EXE's OBJ. Either way the build breaks. If anyone has a third alternative, please let me know! Otherwise, I'll have to select the lesser of these two evils. thanks!
Re: Empty LST files?
On Sunday, 31 July 2016 at 10:05:04 UTC, Basile B. wrote: On Sunday, 31 July 2016 at 08:29:47 UTC, Basile B. wrote: On Sunday, 31 July 2016 at 01:10:40 UTC, Thalamus wrote: Any idea what I'm doing wrong? Yes, what's going wrong is quite actually you said that the LST is well generated but empty so my previous answer is wrong, also i was focused on unittest coverage which doesn't seem to be what you want to verify. Thank Basile. Yes, these aren't unit tests, but rather integration tests, end-to-end tests, etc., all of which are driven from external EXEs. This is a complex application consisting (thus far) of 17 D and C# projects. Within a single project, D (and Visual D) work very well, but across projects I've run into a lot of challenges. Not being able to build these projects into DLLs without resorting to C-linkage for D-to-D interop (which Benjamin Thaut is working on fixing) was tough to swallow, and I can't used LIBs because in some cases I have projects that are not referenced at build time but whose classes are instead discovered at run time, so I'm forced to resort to OBJs for now. Code coverage is a must, though, so I'm really digging in here. I found part of the problem: Hitting F5 in Visual Studio after a fresh rebuild was giving me an error "cannot launch debugger... hr = 89710016" which looks to be related to Visual D. Subsequent runs work fine, but it was annoying me so I added the EXE itself as the startup project. This ran properly every time, but it resulted the LST files ending up in the build folder, and they were all empty. So I switched back to the test project as the startup project and, after the errant run, it generated LSTs in the EXE project root folder as expected. In this case, all the test EXE LST files were populated as expected, but all of the LSTs for the code being tested were still empty. I really don't need code coverage numbers for the test code, and currently I still get none for the code I do need to measure. But it's still progress. If anyone else has ideas I'd love to hear them. Otherwise, if I figure it out, I will add a quick explanation to this thread. thanks!
Empty LST files?
I'm running into a problem where when I specify -cov in the DMD compiler command, the coverage LST files are generated, but they're all empty. Has anyone else run into this before? My command line is: dmd -m64 -gc -debug -w -wi -cov -X -Xf"obj\Unit.json" -I\ -deps="obj\Unit.dep" -c -odobj\Unit.build.rsp Interfaces.obj Invokers.obj (plus a whole lot of other .objs) This is for a test EXE. I thought there may be some trouble when generating files for the .d from the .obj files, but even the .d files local to the test EXE end up with empty LST files. Any idea what I'm doing wrong? thanks!
Re: Registration-free COM client
On Wednesday, 29 June 2016 at 19:21:50 UTC, John wrote: On Wednesday, 29 June 2016 at 14:51:10 UTC, Thalamus wrote: [...] A little research reveals that C# COM servers don't export DllGetClassObject, or any of the COM server plumbing. "Registering for COM interop" merely adds the registry entries - which is the step you're trying to avoid by loading the DLL dynamically. Then you'd run regasm on it to generate a type library. https://msdn.microsoft.com/en-us/library/aa645738(v=vs.71).aspx Thanks John! Yes, I did forget to add : IUnknown. I would have caught that, but I appreciate you pointing that out. Thanks also for the link to the regasm article.
Re: Registration-free COM client
On Tuesday, 28 June 2016 at 02:30:56 UTC, thedeemon wrote: To load load a COM object from a given file (DLL or AX) without having it registered, just load the file with CoLoadLibrary() and use its DllGetClassObject() function to get IClassFactory which will give you any kind of object in this library. Here's how I do it (in my case the requested object has "IBaseFilter" COM interface): Thanks to both of you! I was hoping there would be a code-only solution, and I'm glad to see one is possible. It isn't quite working for me yet, though. I can get the HINSTANCE in the CoLoadLibrary call, but GetProcAddress for DllGetClassObject fails, with ERROR_PROC_NOT_FOUND. I've never written a COM server before (only clients), so I must be building the C# assembly incorrectly. I'm just not sure how. Everything across the board is built as 64-bit, and I've selected "Register for COM interop". The C# is pretty simple: [ComVisible(true)] [Guid("B99B6E64-966C-4655-B633-D0108F4DE909")] public interface ITestInterface { int Identifier(); } [ComVisible(true)] [Guid("0F8BDA67-D6CF-42D0-A62D-E19BD7864362")] [ClassInterface(ClassInterfaceType.None)] public class TestClass : ITestInterface { public int Identifier() { return 42; } } and the D code (mostly unchanged from your example): interface ITestInterface { int Identifier(); } ITestInterface GetInstance() { import std.exception; import core.sys.windows.com; GUID iid = { 0xB99B6E64, 0x966C, 0x4655, [0xB6, 0x33, 0xD0, 0x10, 0x8F, 0x4D, 0xE9, 0x09]}; GUID clsid = { 0x0F8BDA67, 0xD6CF, 0x42D0, [0xA6, 0x2D, 0xE1, 0x9B, 0xD7, 0x86, 0x43, 0x62]}; HINSTANCE hinst = CoLoadLibrary(cast(wchar*)r"managed\bin\test.dll".toUTF16z, 0); //CoFreeLibrary will need to be called later. enforce!COMException(hinst); LPFNGETCLASSOBJECT fnGetClassObject = cast(LPFNGETCLASSOBJECT)GetProcAddress(hinst, "DllGetClassObject"); enforce!COMException(fnGetClassObject); IClassFactory factory; auto factory_iid = IID_IClassFactory; fnGetClassObject(, _iid, cast(void**)).checkHR("fnGetClassObject failed"); enforce!COMException(factory); ITestInterface instance; factory.CreateInstance(null, , cast(void**)).checkHR("factory.CreateInstance"); return instance; } Any ideas what I'm missing? thanks! Gene
Registration-free COM client
Hi everyone, I've succeeded in using D as a client for regular (registered) COM servers in the past, but in this case, I'm building the server as well. I would like to avoid registering it if possible so XCOPY-like deployment remains an option. Can a registration-free COM client be built in D? If so, how can the code be setup to consume the manifest file, or alternately, is there a way to just point D to the correct assembly directly in code? Some background info: The project I'm working on requires a high degree of D and C# interop. Getting C# to invoke D via C linkage is simple, but I've encountered a lot of problems the other way around. Although it's technically possible to get pointers to C# objects such that the same approach could be used, doing so would require large portions of the code to be marked unsafe, the objects to be instantiated as fixed, use of GCHandle.Alloc, etc., which has a high dev learning curve and scalability issues. The typical solution is to use delegates as callbacks. This works, but it doesn't scale well to more complex scenarios. You can send a struct of delegates to the D layer and use that to access public methods in a class, but if one of those methods would normally return a instance of a different class and the caller will need to invoke methods within that other class, this approach breaks down. For example, MyClassInstance.MyProperty.DoSomething() can't be modeled as MyClassInstanceDelegate.MyPropertyDelegate.DoSomethingDelegate(). This fails marshaling, because delegates are not blittable. There's very likely a way to structure complex delegate hierarchies that would in the end be marshalable, but the implementation and maintenance overhead would be sizable. This leaves COM, which seems like it would work fine, on Windows anyway. (I'm not sure about Linux, but maybe some combo of Mono and WINE would do it? Not a high prio right now.) I'm hoping, though, to avoid having to register the C# COM server to keep things as simple as possible. thanks!
Re: TypeInfo_Interface from runtime string?
On Wednesday, 22 June 2016 at 15:46:15 UTC, Thalamus wrote: On Wednesday, 22 June 2016 at 15:43:08 UTC, Basile B. wrote: On Wednesday, 22 June 2016 at 15:15:51 UTC, Thalamus wrote: [...] No need for a constructor. typeid() returns a static instance that's pre-allocated. [...] Thanks Basile. Hit Send too soon... Thanks Basile. As it turned out I was already doing something very similar for mapping types to interfaces and to other types, using shared static constructors to perform registration into associative arrays, e.g. TypeInfo_Class[TypeInfo_Class] and TypeInfo_Interface[TypeInfo_Class] So I can easily add TypeInfo_Interface[string] and TypeInfo_Class[string] as part of the existing registration process and then expose a simple lookup method. Thanks for the good idea! :)
Re: TypeInfo_Interface from runtime string?
On Wednesday, 22 June 2016 at 15:43:08 UTC, Basile B. wrote: On Wednesday, 22 June 2016 at 15:15:51 UTC, Thalamus wrote: [...] No need for a constructor. typeid() returns a static instance that's pre-allocated. [...] Thanks Basile.
TypeInfo_Interface from runtime string?
Hi everyone, My project includes lots of .Net interop via C linkage. One of the things I need to do is refer in C# to an interface declared in the D code, and then to actually work with the interface concretely in the D layer. So, I need to get a TypeInfo_Interface object from a string passed in from C#. The problem isn't in marshaling the string between C# and D, but rather what to do with the string once I have it in D. So in the D code, where interfaceName is the fully qualified name of an interface, e.g. "MyPackage.MyModule.MyInterface", what I would like is something like: TypeInfo_Interface theInterface = new TypeInfo_Interface(interfaceName); But there's no such constructor. Apologies if this seems like it should be obvious, but I couldn't find anything in the forums or the wider web. :) thanks, Thalamus
Re: Convert wchar* to wstring?
On Tuesday, 5 April 2016 at 19:19:10 UTC, ag0aep6g wrote: On 05.04.2016 20:44, Thalamus wrote: [...] Aside: D has syntax for "// For wchar_t.": `import core.stdc.stddef: wchar_t;`. [...] wchar_t is not wchar. wstring is not (portably) compatible with a wchar_t array. If you actually have a wchar_t* and you want a wstring as opposed to a wchar_t[], then you will potentially have to do some converting. If you have a wchar*, then don't use wcslen, as that's defined in terms of wchar_t. There may be some function for finding the first null wchar from a wchar*, but I don't know it, and writing out a loop isn't exactly hard: wstring toWstring(const(wchar)* value) { if (value is null) return null; auto cursor = value; while (*cursor != 0) ++cursor; return value[0 .. cursor - value].dup; } Thank you for the feedback. You are correct.
Re: Convert wchar* to wstring?
On Tuesday, 5 April 2016 at 11:26:44 UTC, Thalamus wrote: Thanks everyone! You've all been very helpful. For anyone who has the same question and happens on this thread, I wanted to post what I finally came up with. I combined the information everyone in this thread gave me with what I saw in Phobos source for the to!string() implementation, closely following the latter. The important to!string() code is in the toImpl implementation in conv.d at line 880. The existing code uses strlen, but that's an ANSI function. Fortunately, D has wcslen available, too. import core.stdc.stddef; // For wchar_t. This is defined differently for Windows vs POSIX. import core.stdc.wchar_; // For wcslen. wstring toWstring(wchar_t* value) { return value ? cast(wstring) value[0..wcslen(wstr)].dup : null; } The Phobos code notes that this operation is unsafe, because there's no guarantee the string is null-terminated as it should be. That's definitely true. The only outcome you can be really sure is accurate is an access violation. :) thanks! Thalamus
Re: Convert wchar* to wstring?
Thanks everyone! You've all been very helpful.
Re: Debugging D DLL from C# app with C linkage for native Unity 5 plugin
On Wednesday, 30 March 2016 at 07:38:07 UTC, Benjamin Thaut wrote: On Tuesday, 29 March 2016 at 23:41:28 UTC, Thalamus wrote: dmd dllmain.d dll.def -w -wi -g -map -ofLogic.dll -m64 -debug -shared Anyone know what I should try next? Am I missing something simple? :) thanks! Thalamus You should be using "-gc" instead of "-g" when building 64-bit D programs that should be debugged with visual studio. Otherwise the visual studio debugger might get confused over some of the symbol names. (Because they contain '.') Thanks Benjamin! I changed over to -gc. I spent another couple of hours on this and finally figured it out. As it turns out, it wasn't necessary to change Just My Code. Enabling Mixed Mode debugging didn't work, but that's what set me down the path where I was able to find the answer. Unity is an odd duck in a lot of ways. They use Mono to provide cross-platform portability, and that decision led them to use their own custom subset of .NET 3.5. Although I had eliminated Unity and Mono from the repro, I had accidentally left that subset on the C# EXE. Because of this, VS uses a different managed code debugger (v3.5, v3.0, v2.0 instead of v4.6, v4.5, v4.0). This version doesn't play nicely with the Native debugger. By default, VS determines the debuggers to use automatically. So in this scenario, if you launch the EXE and then attach, it only loads the managed debugger (without telling you). If you select the old Managed and the Native debuggers in the Attach to Process dialog's Attach to: drop down list, an "Interop debugging is not supported" error pops up when you click Attach. (This is the same error you get if you select "Enable native code debugging" on the C# EXE's Debug property page.) The solution is to select only Native or the older Managed debugger, but never both. That means that you can't hit F5 to launch the EXE in debug mode and then step through native code, which is inconvenient. But for my purposes debugging through Unity, attaching to an already running process is the only scenario I really need to work anyway. The C# layer is a very thin interop and marshaling layer between the C++ (hopefully soon D) core and Unity, so 99% of the time I'll need to debug only the native code anyway. The transition between the two is the only thing that can't be stepped through, and there isn't a whole lot to that. As it turns out, I never saw this with the C++ version of the core logic because there were no C# projects in the solution, so VS automatically chose the Native one without my knowledge. Hope this helps someone else in the future! thanks, Gene
Debugging D DLL from C# app with C linkage for native Unity 5 plugin
Apologies if this has been discussed before, but I wasn't able to find anything similar on the forums or web. I can't seem to figure out how to debug a D DLL from a C# EXE. (My actual purpose here is to use D to build native plugins for Unity 5, but Unity and Mono aren't necessary to repro the problem I'm running into.) The D DLL and C# are both built as 64-bit. (C# is not set to AnyCPU). Using VS 2015 and Visual D, I can drive the D DLL from the C# EXE without any problems, but the debugger doesn't load the D DLL symbols. The DLL and PDB are in the same folder as the C# EXE. Everything behaves the same if I link to the DLL statically using P/Invoke or dynamically using LoadLibrary. Everything from the D DLL is exposed as extern(C), listed in the .def, etc. When I drive the DLL from a D EXE, I can break into the debugger easily, whether I attach at launch or attach to the process when it's already running. I'm building the DLL using: dmd dllmain.d dll.def -w -wi -g -map -ofLogic.dll -m64 -debug -shared Anyone know what I should try next? Am I missing something simple? :) thanks! Thalamus
Re: Shared static constructors from C# EXE
On Friday, 26 February 2016 at 08:37:35 UTC, Benjamin Thaut wrote: On Thursday, 25 February 2016 at 17:46:18 UTC, Thalamus wrote: On Thursday, 25 February 2016 at 16:05:37 UTC, Benjamin Thaut wrote: [...] Thanks Benjamin. When I went to whittle this down to its barest essentials, though, the repro is pretty simple. It involves LIBs, but not Dlls, and it doesn't require anything but a single D EXE. [...] The problem is that when you build with -lib the resulting library is optimized for linker stripping. E.g. everything that is not directly used will not be pulled into the final executable. If you want everything in the final exectuable you shouldn't be using a .lib file. Instead compile with -c resutling in a .obj file and link the resulting .obj file into your executable. Then everything will end up in the final executable even if its not directly used. Kind Regards Benjamin Thaut Thanks Benjamin! I knew there had to be some simple thing I didn't know I needed to do here. It worked like a charm in the simple repro. In my actual code, I'm running into _deh_beg already defined and a few more linker errors, but I haven't had the chance to delve there yet. thanks again!
Re: Shared static constructors from C# EXE
On Thursday, 25 February 2016 at 16:05:37 UTC, Benjamin Thaut wrote: On Thursday, 25 February 2016 at 14:42:14 UTC, Thalamus wrote: your entry point. Hi Guillaume, Thanks for responding so quickly! I had found that wiki page before and I'd been following the "DLLs with a C Interface" section closely. I had forgotten to add -shared when building the DLL, but the behavior didn't change when I added it. So, I added a call to Runtime.initialize() as the first line of the endpoint I'm exposing. (I also made sure that this was the only endpoint invoked and that it was only invoked once just to be cautious.) I can see Runtime.initialize() being called, but the Class A shared static constructor still is not called when run from the C# EXE. Do you have any other ideas? In the meantime, I'm working on putting together a minimal repro source, but the scenario is a bit complicated so there's a lot of details to whittle away. thanks! Gene You shouldn't be calling Runtime.initialize() manually. Just do the following in one of your source files: import core.sys.windows.dll; mixin SimpleDllMain; This will generate a DllMain that will correctly initialize and deinitialize druntime. Kind Regards Benjamin Thaut Thanks Benjamin. When I went to whittle this down to its barest essentials, though, the repro is pretty simple. It involves LIBs, but not Dlls, and it doesn't require anything but a single D EXE. NOTE: if attempting to repro any of this, you must do a clean build after changing build.cmd or main.d before you'll see a change in behavior. I have the shared static ctors output files to make it really easy to see. If you have Class A: module ClassA; import std.file; import std.stdio; export class ClassA { shared static this() { File file = File(r"c:\A.txt", "w"); file.writeln("Called A's shared static constructor."); file.flush(); file.close(); } } and you have Class B: module ClassB; import std.file; import std.stdio; export class ClassB { shared static this() { File file = File(r"c:\B.txt", "w"); file.writeln("Called B's shared static constructor."); file.flush(); file.close(); } } and you have main.d: void main() { } And you build it in one step into an EXE: dmd -m64 -debug ClassA.d ClassB.d main.d -ofDriver.exe Then you run Driver.exe, both A.txt and B.txt are created. But, if you build it as a LIB and then link the LIB to the EXE: dmd -c -lib -m64 -debug ClassA.d ClassB.d -ofInit.lib dmd -m64 -debug Init.lib main.d -ofDriver.exe When you run Driver.exe, neither are created. If you then add "import ClassA" to main.d and clean build, only A.txt will be created, or instead if you add "import ClassB", then only B.txt is created. Also, if either of these is included, Driver.exp and Driver.lib are emitted by the build, whereas otherwise they aren't. It looks from this like a class in a linked LIB that is not directly imported will not have its shared static constructor called. Am I missing something obvious? :) Long term I will need all this not only in separate LIBs but in separate DLLs. My scenario is roughly like this (-> indicate dependencies): ClassA : IClass -> ClassManagement ClassB : IClass -> ClassManagement EntryPoint -> ClassManagement, ClassB, IClass Then EntryPoint asks ClassManagement to give it an instance of ClassB's complement (ClassA). ClassManagement only knows anything about any of these classes via TypeInfo_Class object mappings, and it uses Object.factory to instantiate them. EntryPoint and its dependencies then work with that object via the IClass interface. I've gotten this to work in C# easily and C++ with some effort. (Class map population was, of course, very different for each, though.) I can probably figure out a way to make this work for now, but if there's a way to ensure shared static ctors are run in this scenario without importing modules across separation boundaries, it would be a very good thing. thanks! Gene
Re: Shared static constructors from C# EXE
On Thursday, 25 February 2016 at 14:07:21 UTC, Guillaume Piolat wrote: On Thursday, 25 February 2016 at 14:01:30 UTC, Thalamus wrote: I don't control the EXE itself and the code I write to interface with it must be either C# or JavaScript, but this repros with a test C# driver EXE as well. The interfacing C# code can only be aware of the exposed D DLL functions defined in .def and shouldn't be aware directly of Class A, B, or ClassMapper, the factory specifically, etc.. Make sure your DLL must initialize the D runtime, which is where shared static constructors should get called. http://wiki.dlang.org/Win32_DLLs_in_D Alternatively you can call Runtime.initialize() yourself in your entry point. Hi Guillaume, Thanks for responding so quickly! I had found that wiki page before and I'd been following the "DLLs with a C Interface" section closely. I had forgotten to add -shared when building the DLL, but the behavior didn't change when I added it. So, I added a call to Runtime.initialize() as the first line of the endpoint I'm exposing. (I also made sure that this was the only endpoint invoked and that it was only invoked once just to be cautious.) I can see Runtime.initialize() being called, but the Class A shared static constructor still is not called when run from the C# EXE. Do you have any other ideas? In the meantime, I'm working on putting together a minimal repro source, but the scenario is a bit complicated so there's a lot of details to whittle away. thanks! Gene
Shared static constructors from C# EXE
Hi everyone, I looked in the forums and Google in general but I didn't find a similar question, and I'm stumped. I have a scenario where a set of classes must be registered with a class mapper and then instantiated via a factory. The classes themselves are agnostic of one another, and all interaction with these classes after instantiation is via interfaces. I've succeeded in having the classes register themselves at runtime by using shared static constructors, which is really seamless! This works just fine when the EXE is written in D, but only a subset of shared static constructors get called when the EXE is written in C#. A few more details: ClassMapper class includes a shared static constructor that initializes a class map associative array, and it exposes a public Map() function an Instantiate(TypeInfo_Class classType, etc.) function. Class A and Class B both have shared static constructors that call Map() to register themselves. The above is built into a D EXE, and ClassMapper.map is fully populated before main() starts. -OR- The above is built into a D DLL with a CreateClassB() function exposed via .def, etc. A C# EXE invokes CreateClassB() via p/invoke. The call works just fine, and ClassB and anything class B calls, recursively, are all registered with ClassMapper.map just fine, because their shared static constructors are invoked. But, Class A is not in the map because its shared static constructor is never called. I don't control the EXE itself and the code I write to interface with it must be either C# or JavaScript, but this repros with a test C# driver EXE as well. The interfacing C# code can only be aware of the exposed D DLL functions defined in .def and shouldn't be aware directly of Class A, B, or ClassMapper, the factory specifically, etc.. Has anyone seen this before, or have an idea for a workaround? The best workaround I've come up with so far is to use a registry config file instead of calls to Map() so the ClassMapper can populate itself. It's not a very elegant solution, but it was the best I was able to come up with for C++ too. (In C# I've used class attributes, which I had thought was elegant. D's shared static constructors are even more so, though.) thanks much! Thalamus
Re: Linking a DLL to a DLL with packages
On Sunday, 10 January 2016 at 15:58:55 UTC, Benjamin Thaut wrote: Am 09.01.2016 um 16:45 schrieb Thalamus: Hi Benjamin, I wouldn't say I need DLLs to work fully _really_ badly. The only non-negligible issue with single very large binaries that's crossed my mind is patching, but we're years away from having to worry about that too much. That being said, I'm definitely willing to do some testing, especially for something that helps us down the road. I'll follow up with you offline. Thanks! Great, some help with bugfixing and testing would be greatly apreciated. I didn't get any e-mail from you yet, I assume you didn't send one? Kind Regards Benjamin Thaut Hi Benjamin. Sorry for the delay. It's been a very busy week. I just hit Send on a mail to you.
Re: Linking a DLL to a DLL with packages
On Friday, 8 January 2016 at 12:13:15 UTC, Benjamin Thaut wrote: On Thursday, 7 January 2016 at 19:29:43 UTC, Thalamus wrote: Hi everyone, First off, I've been working with D for a couple of weeks now and I think it's the bee's knees! :) Except for DLLs. thanks! :) Dlls don't currently work on Windows. The only thing that works is giving your dlls a C-like interface. If you need any kind of D interface (classes, modules, etc) it won't work. I'm currently working on this, if you need it really badly and are willing to help bug testing send me a mail to code at benjamin-thaut.de Kind Regards Benjamin Thaut Hi Benjamin, I wouldn't say I need DLLs to work fully _really_ badly. The only non-negligible issue with single very large binaries that's crossed my mind is patching, but we're years away from having to worry about that too much. That being said, I'm definitely willing to do some testing, especially for something that helps us down the road. I'll follow up with you offline. Thanks!
Linking a DLL to a DLL with packages
Hi everyone, First off, I've been working with D for a couple of weeks now and I think it's the bee's knees! :) Except for DLLs. I've been combing through forum posts and Google for this situation. Several threads and articles are close but don't quite cover what I'm doing here. On Windows 10, using DMD, I'm creating (currently) six DLLs and several EXEs. Some of the DLLs and all of the EXEs are dependent on some subset of DLLs. Everything works great if, instead of DLLs, I just statically link everything, but that's not really what I want to do. To boil it down, let's say I have a DLL called Extensions, which includes a package.d file for its modules with module name General. I can successfully build this DLL with the command line: "dmd dllmain.d module1.d module2.d package.d othermodule.d extensions.def -ofExtensions.dll -g -map" and then "implib.exe /noi /system Extensions.lib Extensions.dll" Then, I have a DLL called Platforms. Within is modulea which includes a module-scope "import Extensions.General" line. I build it with: "dmd dllmain.d modulea.d moduleb.d package.d othermodulea.d platforms.def ..\Extensions\Extensions.lib -ofPlatforms.dll -g -map" (I've tried varying these extensively, including -I paths, separating out the compile step from the linking step, and many other educated and desperate guesses, with no success.) So I have a package.d in both DLLs. When I build Platforms, I get: modulea.d(60): Error: module Extensions.General is in file 'General.d' which cannot be read. But of course there is no General.d because the package module has to be named package.d. I've tried changing the name and many, many other things, but no dice. Does anyone have other ideas? I'd really rather avoid a single giant EXE at the end, if I can. thanks! :)