Re: Passing string array to C
On Thursday, 10 September 2020 at 15:41:17 UTC, Adam D. Ruppe wrote: On Thursday, 10 September 2020 at 14:31:41 UTC, Andre Pany wrote: [...] You messed up the pointers. [...] Fantastic, thank you so much Adam. Kind regards André
Re: Access violation when using IShellFolder2
On Thursday, 10 September 2020 at 15:20:54 UTC, John Chapman wrote: On Thursday, 10 September 2020 at 13:30:15 UTC, FreeSlave wrote: Thanks. I tried this, but VarDateFromStr does not succeed for me. It turns out the shell embeds some control characters in the string, specifically 8206 and 8207. So remove those before passing it to VarDateFromStr. auto temp = strRet.pOleStr[0 .. lstrlenW(strRet.pOleStr)] .replace(cast(wchar)8206, "") .replace(cast(wchar)8207, ""); DATE date; VarDateFromStr((temp ~ '\0').ptr, LOCALE_USER_DEFAULT, 0, ); Thank you again for consulting. I thought these character are part of the date format. This is all working now.
Reducing .init effect of a struct that has large static array members
[tldr; I have come up with a way of removing all undesired effects of large static array struct members. See conclusion at the bottom.] Continuing the discussion at https://forum.dlang.org/thread/rdk3m2$725$1...@digitalmars.com and understanding kinke's comments there better... And this is all with dmd... 1) Assuming that static array members are really required in the program, the following definition is not desirable because S.init is embedded into the binary image as 8000 bytes (I have much bigger ones in the wild): struct S { double[1000] a; } static assert (S.init.sizeof == 8000); // That S.init is embedded into the binary One way of proving that S.init is indeed embedded into the binary is running obj2asm that is shipped with dmd: 'obj2asm deneme.o') So, that is not good. 2) In order to remove that huge S.init from the program, one can initialize the member with '= void': struct S { double[1000] a = void; } pragma(msg, S.init); // <-- Aside: As a side effect, this output is // now just "S()" and does not include // an array of 1000 elements. Although now the binary does not contain an S.init of 8000 bytes, it contains CPU instructions to set 1000 elements: xor EAX,EAX mov 0E0C0h[RBP],EAX mov 0E0C4h[RBP],EAX [... many more to set all elements ...] WAT!!! :) That is not good either because now the compiled code is large. (I think and hope other compilers use memset() here.) As explained in that earlier thread and as seen above, contrary to spec (perhaps to an earlier spec?) and fortunately, '= void' does not "leave the elements uninitialized" but the elements are now 0.0. So, that's doubly [pun] bad: The code is large and the elements are not double.nan. 3) To remove that huge struct initialization code, one can @disable the default constructor. And to provide double.nan values, one can provide a function; which may be named specially, or marked with a UDA or some other way. Below, I use a constructor that takes a special type to mark that this is my "default constructor": struct DefaultCtor {}// <-- My special "marker" struct S { double[1000] a = void; @disable this(); this(DefaultCtor) {// <-- My "default constructor" a[] = double.init; // <-- Good: not 0.0 anymore } } void main() { auto s = S(DefaultCtor());// <-- But now the syntax is ugly import std; assert(s.a[42].isNaN); } 4) CONCLUSION: The following 'defaulted' template makes the syntax acceptable as well at least for Ali: struct DefaultCtor {} // Special type used as a user-defined UDA ;) struct S { double[1000] a = void; // To not embed S.init into the binary @disable this();// To not generate many CPU instructions this(DefaultCtor) { // My "default constructor". (This could a[] = double.init;// be a template to not even need a // theoretical rvalue parameter.) } } template defaulted(T) { // Generic template for my default constructor syntax enum defaulted = { return T(DefaultCtor()); }(); } void main() { auto s = defaulted!S; // My default construction syntax } That method works for me. Am I missing something? Ali
Re: Passing string array to C
On Thursday, 10 September 2020 at 14:31:41 UTC, Andre Pany wrote: Why does it crash? You messed up the pointers. A string is one star. An array of strings is two stars. A pointer to an array of strings is /three/ stars. --- import std; void main() { size_t* i; // this need not be a pointer either btw const(wchar)** r; // array of strings sample(, ); // pass pointer to array of strings // Try to read the 2 string values auto arr = r[0..*i]; // slice array of strings writeln(to!string(arr[0])); // Works writeln(to!string(arr[1])); // all good } // taking a pointer to an array of strings so 3 stars extern(C) export void sample(const(wchar)*** r, size_t** c) { string[] arr = ["foo¤", "bar"]; auto z = new const(wchar)*[arr.length]; foreach(i, ref p; z) { p = toUTF16z(arr[i]); } // previously you were sending the first string // but not the pointer to the array // so then when you index above, arr[1] is bad math *r = [0]; *c = new size_t(); **c = arr.length; } ---
Re: Access violation when using IShellFolder2
On Thursday, 10 September 2020 at 13:30:15 UTC, FreeSlave wrote: Thanks. I tried this, but VarDateFromStr does not succeed for me. It turns out the shell embeds some control characters in the string, specifically 8206 and 8207. So remove those before passing it to VarDateFromStr. auto temp = strRet.pOleStr[0 .. lstrlenW(strRet.pOleStr)] .replace(cast(wchar)8206, "") .replace(cast(wchar)8207, ""); DATE date; VarDateFromStr((temp ~ '\0').ptr, LOCALE_USER_DEFAULT, 0, );
Passing string array to C
Hi, I have this coding. Function `sample` will later be called from C and should provide access to a string array. I tried to read the string values after the function call and I can access the first string, but for the second string, there is an access violation. Why does it crash? Kind regards André ``` import std; void main() { size_t* i; const(wchar)* r; sample(, ); // Try to read the 2 string values const(wchar) ** r2; r2 = auto arr = r2[0..*i]; writeln(to!string(arr[0])); // Works writeln(to!string(arr[1])); // Fails } extern(C) export void sample(const(wchar)** r, size_t** c) { string[] arr = ["fooä", "bar"]; auto z = new const(wchar)*[arr.length]; foreach(i, ref p; z) { p = toUTF16z(arr[i]); } *r = z[0]; *c = new size_t(); **c = arr.length; } ```
Re: Trouble with Android and arsd.jni
On Thursday, 10 September 2020 at 13:14:00 UTC, burt wrote: However, the app is still crashing when I load it, and there appears to be an issue in Runtime.initialize(), which is called from JNI_OnLoad(), which is defined in arsd.jni. The debugger tells me that it was calling `getStaticTLSRange`, which calls `safeAssert` in the `__foreachbody`, which fails and eventually aborts. That safeAssert would print a useful message, but I guess you can obtain the msg/reason via debugging as well. - This is most likely due to *not* using the required bfd linker (which is used by default when linking via LDC and otherwise selectable via `-linker=bfd`). If you're linking manually via clang, try `-fuse-ld=bfd`.
Re: UDA inheritance
On Thursday, 10 September 2020 at 13:06:41 UTC, Joseph Rushton Wakeling wrote: `hasUDA!(T, AnotherUDA)` ...do you have to use hasUDA? The language works with class UDAs, but hasUDA doesn't support it. If you write your own test function though you can: ``import std.traits; class BaseUDA { static BaseUDA opCall(string a) { return new BaseUDA(a); } string a_; string a() { return a_; } this(string a) { this.a_ = a; } } class DerivedUDA : BaseUDA { static DerivedUDA opCall(string a) { return new DerivedUDA(a); } this(string a) { super(a); } } @DerivedUDA("test") struct Test {} BaseUDA hasOurUda(T)() { BaseUDA found = null; foreach(uda; __traits(getAttributes, T)) { static if(is(typeof(uda) : BaseUDA)) found = uda; } return found; } pragma(msg, hasOurUda!Test); ``` Or, of course, if you are making your own function, you can still do a plain type == a || b, but the class is fairly natural for more user extension. the opCall there is not necessary, it just saves the `new`. This is equally valid: @(new DerivedUDA("test")) struct Test {} You could also use static immutable class instances kinda like enum instances: --- import std.traits; class BaseUDA { string a_; string a() const { return a_; } this(string a) immutable { this.a_ = a; } static immutable A = new immutable BaseUDA("A"); static immutable B = new immutable BaseUDA("B"); } class DerivedUDA : BaseUDA { this(string a) immutable { super(a); } static immutable C = new immutable DerivedUDA("C"); } // or use B or C or wahtever @(DerivedUDA.A) struct Test {} pragma(msg, __traits(getAttributes, Test)); immutable(BaseUDA) hasOurUda(T)() { // awkward to work around unreachable code warning BaseUDA found = null; foreach(uda; __traits(getAttributes, T)) { static if(is(typeof(uda) : const BaseUDA)) found = cast() uda; } return cast(immutable) found; } pragma(msg, hasOurUda!Test); --- so if you are willing to write your own test function there's a lot of options to consider. But if you're stuck with Phobos... well, back to the drawing bard.
Re: Access violation when using IShellFolder2
On Thursday, 10 September 2020 at 06:43:35 UTC, John Chapman wrote: On Wednesday, 9 September 2020 at 22:44:50 UTC, FreeSlave wrote: Btw do you know how to parse a date returned by GetDetailsOf? Couldn't find any examples in C++. I actually can see digits representing date and time as a part of the string, but I would prefer to use some winapi function to translate it into some time type instead of manually parsing the result. You could look at passing the str.pOleStr field in the SHELLDETAILS you got from GetDetailsOf to VarDateFromStr. It will give you a DATE value that VariantTimeToSystemTime will convert to a SYSTEMTIME from which you can get the years, months, days etc. For example: SHELLDETAILS details; GetDetailsOf(pidl, 3, ); DATE date; VarDateFromStr(details.str.pOleStr, LOCALE_USER_DEFAULT, 0, ); SYSTEMTIME st; VariantTimeToSystemTime(date, ); auto year = st.wYear; auto month = st.wMonth; You can convert that into a more D-friendly SysTime object using SYSTEMTIMEToSysTime from the std.datetime package. Thanks. I tried this, but VarDateFromStr does not succeed for me. Here's the updated example. Note that I use a column 2 to retrieve the date because that's the deletion date column for recycle bin folder. import core.sys.windows.windows; import core.sys.windows.shlobj; import core.sys.windows.wtypes; import core.sys.windows.oaidl; import std.exception; import std.datetime; pragma(lib, "Ole32"); pragma(lib, "OleAut32"); interface IShellFolder2 : IShellFolder { HRESULT GetDefaultSearchGUID(GUID*); HRESULT EnumSearches(IEnumExtraSearch*); HRESULT GetDefaultColumn(DWORD, ULONG*, ULONG*); HRESULT GetDefaultColumnState(UINT, SHCOLSTATEF*); HRESULT GetDetailsEx(LPCITEMIDLIST, const(SHCOLUMNID)*, VARIANT*); HRESULT GetDetailsOf(LPCITEMIDLIST, UINT, SHELLDETAILS*); HRESULT MapColumnToSCID(UINT, SHCOLUMNID*); } import std.stdio; static @trusted string StrRetToString(ref scope STRRET strRet) { import std.string : fromStringz; switch (strRet.uType) { case STRRET_CSTR: return fromStringz(strRet.cStr.ptr).idup; case STRRET_OFFSET: writeln("STRRET_OFFSET!"); return string.init; case STRRET_WSTR: char[MAX_PATH] szTemp; auto len = WideCharToMultiByte (CP_UTF8, 0, strRet.pOleStr, -1, szTemp.ptr, szTemp.sizeof, null, null); scope(exit) CoTaskMemFree(strRet.pOleStr); if (len) return szTemp[0..len-1].idup; else return string.init; default: return string.init; } } static @trusted SysTime StrRetToSysTime(ref scope STRRET strRet) { enforce(strRet.uType == STRRET_WSTR, "Expected STRRET_WSTR"); DATE date; enforce(SUCCEEDED(VarDateFromStr(strRet.pOleStr, LOCALE_USER_DEFAULT, 0, )), "Failed to convert string to date value"); SYSTEMTIME sysTime; VariantTimeToSystemTime(date, ); return SYSTEMTIMEToSysTime(); } void main() { OleInitialize(null); scope(exit) OleUninitialize(); IShellFolder desktop; LPITEMIDLIST pidlRecycleBin; enforce(SUCCEEDED(SHGetDesktopFolder()), "Failed to get desktop shell folder"); assert(desktop); scope(exit) desktop.Release(); enforce(SUCCEEDED(SHGetSpecialFolderLocation(null, CSIDL_BITBUCKET, )), "Failed to get recycle bin location"); assert(pidlRecycleBin); scope(exit) ILFree(pidlRecycleBin); IShellFolder2 recycleBin; enforce(SUCCEEDED(desktop.BindToObject(pidlRecycleBin, null, _IShellFolder2, cast(LPVOID *))), "Failed to get recycle bin shell folder"); assert(recycleBin); scope(exit) recycleBin.Release(); IEnumIDList enumFiles; with(SHCONTF) enforce(SUCCEEDED(recycleBin.EnumObjects(null, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, )), "Failed to enumerate objects in recycle bin"); scope(exit) enumFiles.Release(); LPITEMIDLIST pidl; while (enumFiles.Next(1, , null) != S_FALSE) { string name; string originalLocation; SysTime deletionTime; SHELLDETAILS details; if(SUCCEEDED(recycleBin.GetDetailsOf(pidl,0,))) { name = StrRetToString(details.str); } if(SUCCEEDED(recycleBin.GetDetailsOf(pidl,1,))) { originalLocation = StrRetToString(details.str); } if(SUCCEEDED(recycleBin.GetDetailsOf(pidl,2,))) { deletionTime = StrRetToSysTime(details.str); } writefln("Name: %s, original location: %s, datetime: %s", name, originalLocation, deletionTime); CoTaskMemFree(pidl); } }
Re: UDA inheritance
On Thursday, 10 September 2020 at 13:14:47 UTC, drug wrote: Just a thought - couldn't you use classes for this? Get an UDA and check if it is a descendant of the specific class. Yes, I did wonder about that, but it doesn't allow all the inference that I'm looking for. For example: class First { enum A; enum B; } class Second : First { } @(Second.A) struct MySecond { } import std.traits : hasUDA; static assert(hasUDA!(MySecond, Second.A)); // OK! static assert(hasUDA!(MySecond, First.A)); // OK! static assert(hasUDA!(MySecond, Second));// fails static assert(hasUDA!(MySecond, First)); // fails It's obvious _why_, of course, given how I set the above up. And this contrasts with what one can do with enums: enum Something { A, B } @(Something.A) struct MySomething { } import std.traits : hasUDA; static assert(hasUDA!(MySomething, Something.A)); // OK! static assert(hasUDA!(MySomething, Something));// OK! ... where I can check for the enum specialization _or_ the general enum type and have things just work. I'm looking, ideally, to be able to do both. I did try something like: enum First { A, B } enum Second : First { A = First.A, B = First.B } ... but that doesn't work. Hence why I thought it might be worth making a forum post.
Re: UDA inheritance
On 9/10/20 4:06 PM, Joseph Rushton Wakeling wrote: Hello folks, Is there any way to define UDAs such that they automatically inherit other UDA definitions? For example, suppose I define: enum BaseUDA { A, B } Is there a way to define `AnotherUDA` such that if `hasUDA!(T, AnotherUDA)` then it is a given that `hasUDA!(T, BaseUDA)` will also be true? (And similarly for the `A`, `B` specializations?) The use-case here is to create a UDA that defines some general distinction of code properties, and to allow downstream code to define its own more specialized cases of that distinction. Thanks in advance for any thoughts or advice! Thanks and best wishes, -- Joe Just a thought - couldn't you use classes for this? Get an UDA and check if it is a descendant of the specific class.
Re: Trouble with Android and arsd.jni
On Thursday, 10 September 2020 at 11:58:51 UTC, kinke wrote: On Thursday, 10 September 2020 at 11:16:55 UTC, burt wrote: However, I am getting linker errors, telling me that _tlsend, _tlsstart and __bss_end__ are missing. Perhaps you happen to use some stale artifacts? These magic symbols aren't used anymore in druntime since LDC v1.21, and not defined by the compiler anymore. You also don't need the dummy main() anymore. The object file containing the undefined references should shed some light on what's still referencing them. I'm not sure if this was the cause, but I believe I was using old libdruntime-ldc.a and libphobos2-ldc.a files which where downloaded from before v1.21. So that issue is fixed. However, the app is still crashing when I load it, and there appears to be an issue in Runtime.initialize(), which is called from JNI_OnLoad(), which is defined in arsd.jni. The debugger tells me that it was calling `getStaticTLSRange`, which calls `safeAssert` in the `__foreachbody`, which fails and eventually aborts.
UDA inheritance
Hello folks, Is there any way to define UDAs such that they automatically inherit other UDA definitions? For example, suppose I define: enum BaseUDA { A, B } Is there a way to define `AnotherUDA` such that if `hasUDA!(T, AnotherUDA)` then it is a given that `hasUDA!(T, BaseUDA)` will also be true? (And similarly for the `A`, `B` specializations?) The use-case here is to create a UDA that defines some general distinction of code properties, and to allow downstream code to define its own more specialized cases of that distinction. Thanks in advance for any thoughts or advice! Thanks and best wishes, -- Joe
Re: Trouble with Android and arsd.jni
On Thursday, 10 September 2020 at 11:16:55 UTC, burt wrote: However, I am getting linker errors, telling me that _tlsend, _tlsstart and __bss_end__ are missing. Perhaps you happen to use some stale artifacts? These magic symbols aren't used anymore in druntime since LDC v1.21, and not defined by the compiler anymore. You also don't need the dummy main() anymore. The object file containing the undefined references should shed some light on what's still referencing them.
Trouble with Android and arsd.jni
Hello, I'm trying to upgrade and improve an Android project I was working on a while ago. For this reason, I decided to upgrade my compiler to the newest LDC (v1.23.0). I am using the arsd.jni library for the JNI headers and for initializing the runtime. However, I am getting linker errors, telling me that _tlsend, _tlsstart and __bss_end__ are missing. So I tried to fix these by adding empty declarations for them myself (as I saw in another post): ```d extern(C) __gshared { @section(".tdata") int _tlsstart = 0; @section(".tcommon") int _tlsend = 0; } ``` However, when doing this, it causes my app to crash, specifically on jni.d:1033 when calling `Runtime.initialize()`. The stack trace shows there is an assertion error in rt.sections_android in the foreach body of `getStaticTLSRange`. I also tried adding an empty `void main() {}` instead, with the same result. PR #2991 in dlang/druntime seems to have changed the way the TLS is emulated on Android or something. I have no clue what is going on and how to fix these errors, so if someone could help that would be much appreciated. Thank you.
Re: Access violation when using IShellFolder2
On Wednesday, 9 September 2020 at 22:44:50 UTC, FreeSlave wrote: Btw do you know how to parse a date returned by GetDetailsOf? Couldn't find any examples in C++. I actually can see digits representing date and time as a part of the string, but I would prefer to use some winapi function to translate it into some time type instead of manually parsing the result. You could look at passing the str.pOleStr field in the SHELLDETAILS you got from GetDetailsOf to VarDateFromStr. It will give you a DATE value that VariantTimeToSystemTime will convert to a SYSTEMTIME from which you can get the years, months, days etc. For example: SHELLDETAILS details; GetDetailsOf(pidl, 3, ); DATE date; VarDateFromStr(details.str.pOleStr, LOCALE_USER_DEFAULT, 0, ); SYSTEMTIME st; VariantTimeToSystemTime(date, ); auto year = st.wYear; auto month = st.wMonth; You can convert that into a more D-friendly SysTime object using SYSTEMTIMEToSysTime from the std.datetime package.