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.


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, );



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: 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.


Re: Access violation when using IShellFolder2

2020-09-09 Thread FreeSlave via Digitalmars-d-learn
On Wednesday, 9 September 2020 at 07:18:04 UTC, John Chapman 
wrote:

On Tuesday, 8 September 2020 at 22:24:22 UTC, FreeSlave wrote:
However if I change the type of recycleBin variable to 
IShellFolder (not IShellFolder2), the crash does not happen.


Does IShellFolder2 require some special handling?


The issue is caused by druntime's definition of IShellFolder2. 
To fix it temporarily, just redefine it in your module 
somewhere:


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*);
}

IShellFolder2 isn't the only culprit - IShellView2 will need 
fixing too if you intend to use it. There are probably others 
as well.


Redefinition did the trick, thank you.

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.


Re: Access violation when using IShellFolder2

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

On Tuesday, 8 September 2020 at 22:24:22 UTC, FreeSlave wrote:
However if I change the type of recycleBin variable to 
IShellFolder (not IShellFolder2), the crash does not happen.


Does IShellFolder2 require some special handling?


The issue is caused by druntime's definition of IShellFolder2. To 
fix it temporarily, just redefine it in your module somewhere:


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*);
}

IShellFolder2 isn't the only culprit - IShellView2 will need 
fixing too if you intend to use it. There are probably others as 
well.




Access violation when using IShellFolder2

2020-09-08 Thread FreeSlave via Digitalmars-d-learn

Consider the following code:

import core.sys.windows.windows;
import core.sys.windows.shlobj;
import core.sys.windows.wtypes;

import std.exception;

pragma(lib, "Ole32");

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");

enumFiles.Release();
}

For me this code crashes with error:

object.Error@(0): Access Violation

0x75B4EBB8 in SHELL32_CLocationContextMenu_Create
0x004023A9
0x0040493B
0x004048B5
0x0040474E
0x00402C9A
0x0040250B
0x75816359 in BaseThreadInitThunk
0x76F07C24 in RtlGetAppContainerNamedObjectPath
0x76F07BF4 in RtlGetAppContainerNamedObjectPath

However if I change the type of recycleBin variable to 
IShellFolder (not IShellFolder2), the crash does not happen.


Does IShellFolder2 require some special handling?