Change the regional settings format for Sysem.Variants.VarToWideStr

孤者浪人 提交于 2020-01-04 09:36:25

问题


A third party component (FastReports) on my application is using extensively the System.Variants.VarToWideStr function, which is fine except that it ignores the regional settings I need that application to use.

Example:

FormatSettings.ShortDateFormat := 'dd/mm/yyyy';
ShowMessage(VarToWideStr(Date));
FormatSettings.ShortDateFormat := 'yyyy/mm/dd';
ShowMessage(VarToWideStr(Date));

This code always returns the same string, ignoring the regional settings that I indicate the application to use.

Do you know of another way to change the regional settings that the application (concretely VarToWideStr) is going to use ?.


回答1:


I think you're screwed by awful design of Variants unit as well as FastReport. VarToWideStr calls VarToWideStrDef which invokes implicit _VarToWStr, then DateToWStrViaOS and finally VarBStrFromDate from unit System.VarUtils.

In fact VarBStrFromDate is a reference to function and its implementation depends on compiler. On Windows 32/64 this is just a reference to VarBstrFromDate from oleaut32.dll. Non-Windows compilers fall back to converting the value via DateTimeToStr (single argument invariant) which uses global format settings and 'C' format specifier to format the value.

There is no good way around that, because all those routines depend too much on global state. Luckily (??) you can point VarBStrFromDate to your own implementation. You can get inspired by default implementation for non-Windows platforms seen in function BackupVarBStrFromDate of unit System.VarUtils. Then you can do something like this:

uses
  System.SysUtils, System.Variants, System.VarUtils, System.DateUtils;

function MyVarBstrFromDate(dateIn: TDateTime; LCID: Integer; dwFlags: Integer;
  out bstrOut: WideString): HRESULT; stdcall;
begin
  if LCID = VAR_LOCALE_USER_DEFAULT then
  begin
    bstrOut := DateTimeToStr(dateIn);
    Result := VAR_OK;
  end
  else
    Result := VAR_NOTIMPL;
end;

{ ... }

System.VarUtils.VarBstrFromDate := MyVarBstrFromDate;
FormatSettings.ShortDateFormat := 'yyyy-mm-dd';
FormatSettings.LongTimeFormat := 'hh:nn:ss';
Writeln(VarToWideStr(EncodeDate(2019, 11, 29)));
Writeln(VarToWideStr(EncodeDateTime(2019, 11, 29, 10, 30, 50, 700)));

to get the result:

2019-11-29
2019-11-29 10:30:50

You need to be aware that this changes the behavior of all routines that rely on VarBstrFromDate throughout the entire application.

The same goes for VarToStr. See also here, where the author suggest extracting the date value from variant before conversion to string.



来源:https://stackoverflow.com/questions/59100960/change-the-regional-settings-format-for-sysem-variants-vartowidestr

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!