Friday, January 2, 2015

Run Windows 8 Metro Application from Desktop Application

After failed to create Rainmeter plugin which launch windows 8 application, i decide to make an application which launch windows 8 application from console application.

File: IApplicationAcitvationManager.h (For GCC/G++ Compiler)
// IApplicationActivationManager for MinGW
#pragma once
#ifdef _MSC_VER
#error "Not for Microsoft Compiler!"
#endif
#ifndef _SHLOBJIDL_H 
#include <shobjidl.h>
#endif
 
#ifdef __cplusplus
extern "C" {
#endif
const IID IID_IApplicationActivationManager={0x2e941141,0x7f97,0x4756,{0xba,0x1d,0x9d,0xec,0xde,0x89,0x4a,0x3d}};  // Visual Studio 2012 ShObjIdl.h:9159
const CLSID CLSID_ApplicationActivationManager={0x45BA127D,0x10A8,0x46EA,{0x8A,0xB7,0x56,0xEA,0x90,0x78,0x94,0x3C}}; // Visual Studio 2012 ShObjIdl.h:9399
 
typedef enum ACTIVATEOPTIONS {
 AO_NONE=0,
 AO_DESIGNMODE=1,
 AO_NOERRORUI=2,
 AO_NOSPLASHSCREEN=4
} ACTIVATEOPTIONS;
 
#define INTERFACE IApplicationActivationManager
DECLARE_INTERFACE_(IApplicationActivationManager,IUnknown) {
 STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
 STDMETHOD_(ULONG,AddRef)(THIS) PURE;
 STDMETHOD_(ULONG,Release)(THIS) PURE;
 // Activates the specified Windows Store app for the generic launch contract (Windows.Launch) in the current session.
 STDMETHOD(ActivateApplication)(THIS_ const wchar_t*,const wchar_t*,ACTIVATEOPTIONS,unsigned long*) PURE;
 // Activates the specified Windows Store app for the file contract (Windows.File).
 // IShellItem doesn't exist. Replace with LPVOID
 STDMETHOD(ActivateForFile)(THIS_ const wchar_t*,void*,const wchar_t*,unsigned long*) PURE;
 // Activates the specified Windows Store app for the protocol contract (Windows.Protocol).
 // IShellItem doesn't exist. Replace with LPVOID
 STDMETHOD(ActivateForProtocol)(THIS_ const wchar_t*,void*,unsigned long*) PURE;
};
#undef INTERFACE
#ifdef __cplusplus
}
#endif

And here's the application to launch Windows 8 Application from desktop(File Apptest.cpp)
#include <stdio.h>
#include <Windows.h>
#include <ShObjIdl.h>
#include <string>
#ifndef _MSC_VER
#include "IApplicationActivationManager.h"
extern "C" __declspec(dllimport) HRESULT __stdcall CoAllowSetForegroundWindow(IUnknown *pUnk,LPVOID lpvReserved);
#endif
 
int main(int argc,char** argv) {
 IApplicationActivationManager* _;
 std::string __;
 size_t ___;
 if(argc<2) {
  printf("usage: %s <app package id>\r\n",argv[0]);
  return 1;
 }
 __=argv[1];
 CoInitializeEx(nullptr,COINIT_APARTMENTTHREADED);
 CoCreateInstance(CLSID_ApplicationActivationManager,nullptr,CLSCTX_LOCAL_SERVER,IID_IApplicationActivationManager,(void**)&_);
 CoAllowSetForegroundWindow(_,nullptr);
 _->ActivateApplication(std::wstring(__.begin(),__.end()).c_str(),nullptr,AO_NONE,(DWORD*)&___);
 return 0;
}

Command Line i used to Compile: g++ -std=c++11 -o ConsoleApplication1.exe -L"%VSLIBDIR%" -static-libgcc -static-libstdc++ ConsoleApplication1/AppTest.cpp -lole32 -loleaut32
Set VSLIBDIR to your Windows 8 SDK Lib directory(for CoInitializeEx and CoAllowSetForegroundWindow)(Windows 8 SDK)

Note: Tested in Visual Studio 2012 and GCC v4.8.1
Note2: Enum app package id powershell command(source):
$installedapps = get-AppxPackage
foreach ($app in $installedapps)
{
    foreach ($id in (Get-AppxPackageManifest $app).package.applications.application.id)
    {
        $app.packagefamilyname + "!" + $id
    }
}