Re: Passing string array to C

2020-09-10 Thread Andre Pany via Digitalmars-d-learn
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

2020-09-10 Thread FreeSlave via Digitalmars-d-learn
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

2020-09-10 Thread Ali Çehreli via Digitalmars-d-learn
[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

2020-09-10 Thread Adam D. Ruppe via Digitalmars-d-learn

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

2020-09-10 Thread John Chapman via Digitalmars-d-learn

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

2020-09-10 Thread Andre Pany via Digitalmars-d-learn

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

2020-09-10 Thread kinke via Digitalmars-d-learn

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

2020-09-10 Thread Adam D. Ruppe via Digitalmars-d-learn
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

2020-09-10 Thread FreeSlave via Digitalmars-d-learn
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

2020-09-10 Thread Joseph Rushton Wakeling via Digitalmars-d-learn

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

2020-09-10 Thread drug via Digitalmars-d-learn

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

2020-09-10 Thread burt via Digitalmars-d-learn

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

2020-09-10 Thread Joseph Rushton Wakeling via Digitalmars-d-learn

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

2020-09-10 Thread kinke via Digitalmars-d-learn

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

2020-09-10 Thread burt via Digitalmars-d-learn

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

2020-09-10 Thread John Chapman via Digitalmars-d-learn

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.