Ver Mensaje Individual
  #1  
Antiguo 03-08-2015
Avatar de dec
dec dec is offline
Moderador
 
Registrado: Dec 2004
Ubicación: Alcobendas, Madrid, España
Posts: 12.630
Reputación: 27
dec Tiene un aura espectaculardec Tiene un aura espectacular
Cómo abrir una URL con Microsoft Edge en Windows 10

Hola a todos,

En Microsoft Windows 10 viene incorporado, además de Internet Explorer 11, otro navegador, Microsoft Edge. Buscando información sobre cómo abrir una determinada URL con este navegador, encontraremos que podemos usar la función "ShellExecute" (de toda la vida) proporcionando como argumento "FileName" una cadena similar a esta:

Código:
microsoft-edge:http://www.clubdelphi.com
Ya está. Ese es el truco. ¡¿Ese es el truco?!

Bueno, en realidad esto da para un poco más. Ponte en el caso de tener que detectar si Microsoft Edge está instalado o no en el sistema. Como ves arriba, no invocamos ningún ejecutable, y, de hecho, en mi sistema aparecen tres "MicrosoftEdge.exe" en lugares diferentes. Así que, ¿cómo saber que Microsoft Edge está disponible?

La forma de hacerlo (o al menos lo que yo he hecho) ha sido averiguando la versión de Windows en que corre mi programa. Ahora mismo, al menos, Microsoft Edge está disponible sólo en Windows 10, de modo que lo que tenemos que averiguar es si nuestro programa corre o no en Windows 10.

Y ahora sí, ese es el truco. ¡¿Ese es el truco?!

Bueno (bueno estaba y se murió, ¡pues no estaría tan bueno!), en realidad esto da para un poco más todavía. Resulta que hay cierto lío montado con el asunto de averiguar la versión de Windows desde nuestros programas. Microsoft ha llevado a cabo ciertos cambios (que tampoco conozco a fondo) en la forma en que se manejan las versiones de Windows.

De este modo, un programa escrito en Delphi XE2 (al menos) en Windows 10 nos dará datos erróneos si tratamos de usar el registro "SysUtils.TOSVersion", por ejemplo, o bien otras funciones del API de Windows para obtener la versión del sistema. Con nuestros propios ojos podremos ver que ejecutándose nuestro programa en Windows 10 este nos informa de que corre en Windows 8.

Buscando por internet encontré una unidad que implementa ciertas funciones de un nuevo API de Windows disponibles a partir de Windows 10, y que, sin atribuirme autoría alguna (creo que es una copia de cierto código C que también he podido ver, pero, desconozco la autoría) aquí están porque igual pueden serle a alguien tan útiles como a mí mismo:

Código Delphi [-]
unit AppBuilder.Shared.WindowsVersion;

interface

uses
  // Delphi
  Winapi.Windows,
  System.SysUtils;

const
  VER_SERVICEPACKMAJOR = $0000010;
  VER_MAJORVERSION = $0000002;
  VER_MINORVERSION = $0000001;
  VER_NT_WORKSTATION = 1;
  VER_PRODUCT_TYPE = $80;

  VER_EQUAL = 1;
  VER_GREATER = 2;
  VER_GREATER_EQUAL = 3;
  VER_LESS = 4;
  VER_LESS_EQUAL = 5;
  VER_AND = 6;
  VER_OR = 7;
  WIN32_WINNT_NT4 = $0400;
  WIN32_WINNT_WIN2K = $0500;
  WIN32_WINNT_WINXP = $0501;
  WIN32_WINNT_WS03 = $0502;
  WIN32_WINNT_VISTA = $0600;
  WIN32_WINNT_WS08 = $0600;
  WIN32_WINNT_LONGHORN = $0600;
  WIN32_WINNT_WIN7 = $0601;
  WIN32_WINNT_WIN8 = $0602;
  WIN32_WINNT_WINBLUE = $0603;
  WIN32_WINNT_WIN10 = $0A00;

  kernel32 = 'kernel32.dll';

type
  OSVERSIONINFOEX = record
    dwOSVersionInfoSize: DWord;
    dwMajorVersion: DWord;
    dwMinorVersion: DWord;
    dwBuildNumber: DWord;
    dwPlatformID: DWord;
    szCSDVersion: array [1 .. 128] of char;
    wServicePackMajor: Word;
    wServicePackMinor: Word;
    wSuiteMask: Word;
    wProductType: Byte;
    wReserved: Byte;
  end;

function IsWindowsXPOrGreater: Bool; stdcall;
function IsWindowsXPSP1OrGreater: Bool; stdcall;
function IsWindowsXPSP2OrGreater: Bool; stdcall;
function IsWindowsXPSP3OrGreater: Bool; stdcall;
function IsWindowsVistaOrGreater: Bool; stdcall;
function IsWindowsVistaSP1OrGreater: Bool; stdcall;
function IsWindowsVistaSP2OrGreater: Bool; stdcall;
function IsWindows7OrGreater: Bool; stdcall;
function IsWindows7SP1OrGreater: Bool; stdcall;
function IsWindows8OrGreater: Bool; stdcall;
function IsWindows8Point1OrGreater: Bool; stdcall;
function IsWindows10OrGreater: Bool; stdcall;
function IsWindowsServer: Bool; stdcall;

function IsWindowsVersionOrGreater(wMajorVersion, wMinorVersion,
  wServicePackMajor: Word): Bool; stdcall;

implementation

function VerifyVersionInfo(var LPOSVERSIONINFOEX: OSVERSIONINFOEX;
  dwTypeMask: DWord; dwlConditionMask: int64): Bool; stdcall;
  external kernel32 name 'VerifyVersionInfoA';

function VerSetConditionMask(dwlConditionMask: int64; dwTypeBitMask: DWord;
  dwConditionMask: Byte): int64; stdcall; external kernel32;

function IsWindowsVersionOrGreater;
var
  osvi: OSVERSIONINFOEX;
  condmask: int64;
begin
  FillChar(osvi, sizeof(osvi), 0);
  osvi.dwOSVersionInfoSize := sizeof(osvi);
  FillChar(condmask, 8, 0);
  condmask := VerSetConditionMask(condmask, VER_MAJORVERSION,
    VER_GREATER_EQUAL);
  condmask := VerSetConditionMask(condmask, VER_MINORVERSION,
    VER_GREATER_EQUAL);
  condmask := VerSetConditionMask(condmask, VER_SERVICEPACKMAJOR,
    VER_GREATER_EQUAL);
  osvi.dwMajorVersion := wMajorVersion;
  osvi.dwMinorVersion := wMinorVersion;
  osvi.wServicePackMajor := wServicePackMajor;
  Result := VerifyVersionInfo(osvi, VER_MAJORVERSION or VER_MINORVERSION or
    VER_SERVICEPACKMAJOR, condmask) <> false;
end;

function IsWindowsXPOrGreater;
begin
  Result := IsWindowsVersionOrGreater(HiByte(WIN32_WINNT_WINXP),
    LOBYTE(WIN32_WINNT_WINXP), 0);
end;

function IsWindowsXPSP1OrGreater;
begin
  Result := IsWindowsVersionOrGreater(HiByte(WIN32_WINNT_WINXP),
    LOBYTE(WIN32_WINNT_WINXP), 1);
end;

function IsWindowsXPSP2OrGreater;
begin
  Result := IsWindowsVersionOrGreater(HiByte(WIN32_WINNT_WINXP),
    LOBYTE(WIN32_WINNT_WINXP), 2);
end;

function IsWindowsXPSP3OrGreater;
begin
  Result := IsWindowsVersionOrGreater(HiByte(WIN32_WINNT_WINXP),
    LOBYTE(WIN32_WINNT_WINXP), 3);
end;

function IsWindowsVistaOrGreater;
begin
  Result := IsWindowsVersionOrGreater(HiByte(WIN32_WINNT_VISTA),
    LOBYTE(WIN32_WINNT_VISTA), 0);
end;

function IsWindowsVistaSP1OrGreater;
begin
  Result := IsWindowsVersionOrGreater(HiByte(WIN32_WINNT_VISTA),
    LOBYTE(WIN32_WINNT_VISTA), 1);
end;

function IsWindowsVistaSP2OrGreater;
begin
  Result := IsWindowsVersionOrGreater(HiByte(WIN32_WINNT_VISTA),
    LOBYTE(WIN32_WINNT_VISTA), 2);
end;

function IsWindows7OrGreater;
begin
  Result := IsWindowsVersionOrGreater(HiByte(WIN32_WINNT_WIN7),
    LOBYTE(WIN32_WINNT_WIN7), 0);
end;

function IsWindows7SP1OrGreater;
begin
  Result := IsWindowsVersionOrGreater(HiByte(WIN32_WINNT_WIN7),
    LOBYTE(WIN32_WINNT_WIN7), 0);
end;

function IsWindows8OrGreater;
begin
  Result := IsWindowsVersionOrGreater(HiByte(WIN32_WINNT_WIN8),
    LOBYTE(WIN32_WINNT_WIN8), 0);
end;

function IsWindows8Point1OrGreater;
begin
  Result := IsWindowsVersionOrGreater(HiByte(WIN32_WINNT_WINBLUE),
    LOBYTE(WIN32_WINNT_WINBLUE), 0);
end;

function IsWindows10OrGreater;
begin
  Result := IsWindowsVersionOrGreater(HiByte(WIN32_WINNT_WIN10),
    LOBYTE(WIN32_WINNT_WIN10), 0);
end;

function IsWindowsServer;
var
  osvi: OSVERSIONINFOEX;
  condmask: int64;
begin
  FillChar(osvi, sizeof(osvi), 0);
  osvi.dwOSVersionInfoSize := sizeof(osvi);
  FillChar(condmask, 8, 0);
  condmask := VerSetConditionMask(condmask, VER_PRODUCT_TYPE, VER_EQUAL);
  osvi.wProductType := VER_NT_WORKSTATION;
  Result := not VerifyVersionInfo(osvi, VER_PRODUCT_TYPE, condmask) <> false;
end;

end.

Así que en principio con estas funciones podemos averiguar si nuestro programa correo finalmente en Windows 10, de modo que podamos abrir una URL con el navegador Microsoft Edge, por ejemplo. Sin embargo, ni siquiera estas funciones ofrecerán los resultados esperados... ¡este truco no va a terminar nunca!

En efecto, tenemos que utilizar un manifiesto para nuestro programa diferente del que incluye Delphi XE2, al menos, porque, de lo contrario, las funciones anteriores (u otras) ofrecerán resultados equivocados, por lo menos, confundirán Windows 10 con Windows 8. Básicamente, podemos partir del manifiesto que usa Delphi por defecto:

Código:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
 <dependency>
   <dependentAssembly>
     <assemblyIdentity
       type="win32"
       name="Microsoft.Windows.Common-Controls"
       version="6.0.0.0"
       publicKeyToken="6595b64144ccf1df"
       language="*"
       processorArchitecture="*"/>
   </dependentAssembly>
 </dependency>
 <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
   <security>
     <requestedPrivileges>
       <requestedExecutionLevel
         level="asInvoker"
         uiAccess="false"/>
       </requestedPrivileges>
   </security>
 </trustInfo>
</assembly>
A este manifiesto hemos de añadir una opción de compatibilidad al menos: para indicar que nuestro programa requiere de las nuevas características de Windows 10:

Código:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
 <dependency>
   <dependentAssembly>
     <assemblyIdentity
       type="win32"
       name="Microsoft.Windows.Common-Controls"
       version="6.0.0.0"
       publicKeyToken="6595b64144ccf1df"
       language="*"
       processorArchitecture="*"/>
   </dependentAssembly>
 </dependency>
 <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
   <security>
     <requestedPrivileges>
       <requestedExecutionLevel
         level="asInvoker"
         uiAccess="false"/>
       </requestedPrivileges>
   </security>
 </trustInfo>
 <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
  <application>
   <!--This Id value indicates the application supports Windows 7 functionality-->
   <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
   <!--This Id value indicates the application supports Windows 8 functionality-->
   <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
   <!--This Id value indicates the application supports Windows 8.1 functionality-->
   <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
   <!-- This Id value indicates the application supports Windows 10 functionality -->
   <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
  </application>
 </compatibility>
</assembly>
El manifiesto anterior es el que yo he empezado a usar en mis programas y, una vez lo añadamos a los mismos:



... ahora sí, podremos usar las funciones anteriores para averiguar si nuestro programa corre en Windows 10.

¡Fin del truco!

En conclusión:

Por lo que parece, a partir de Windows 10 (que yo sepa) los programas que no incluyan en su manifiesto la compatibilidad con dicha versión de Windows, tampoco podrán delegar en la versión del sistema operativo, o sea, el programa no tendrá modo de saber si corre en Windows 10, al menos usando los recursos y funciones habituales.
__________________
David Esperalta
www.davidesperalta.com
Responder Con Cita