microsoft / AppModelSamples

Sample code for AppModel features
MIT License
200 stars 102 forks source link

App icon doesn't appear #15

Open andrewleader opened 4 years ago

andrewleader commented 4 years ago

When running as a sparse package, the app icon on both taskbar and Action Center doesn't appear.

image

The icon appears fine when not running as a sparse package. Sparse package breaks the icon.

DrusTheAxe commented 3 years ago

The sample's bugged

Assets/* and resources.pri under Samples/SparsePackages/PhotoStoreDemoPkg/ should be under Samples/SparsePackages/PhotoStoreDemo/

Move resources.pri and Assets/* from Samples\SparsePackages\PhotoStoreDemoPkg to Samples\SparsePackages\PhotoStoreDemo as they need to be part of the ExternalLocation; the SparsePackage should only contain 'footprint' files (appxmanifest.xml, block map.xml, signature.p7x, contentgroup.xml). If a package has an ExternalLocation then Windows all look for all 'content' files (i.e. all not-footprint) in the ExternalLocation, not in the package directory (where appxmanifest.xml winds up)

The fix is...

I've got a branch with the fix but I can't push it to this repo (my github account's not authorized). Is there something I need to do to get my github account access to this repo? Or would you prefer to make the change (directions above)

  <ItemGroup>
    <Resource Include="resources.pri">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\BadgeLogo.scale-100.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\BadgeLogo.scale-125.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\BadgeLogo.scale-150.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\BadgeLogo.scale-200.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\BadgeLogo.scale-400.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\LargeTile.scale-100.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\LargeTile.scale-125.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\LargeTile.scale-150.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\LargeTile.scale-200.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\LargeTile.scale-400.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\SmallTile.scale-100.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\SmallTile.scale-125.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\SmallTile.scale-150.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\SmallTile.scale-200.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\SmallTile.scale-400.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\SplashScreen.scale-100.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\SplashScreen.scale-125.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\SplashScreen.scale-150.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\SplashScreen.scale-200.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\SplashScreen.scale-400.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\Square150x150Logo.scale-100.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\Square150x150Logo.scale-125.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\Square150x150Logo.scale-150.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\Square150x150Logo.scale-200.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\Square150x150Logo.scale-400.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\Square44x44Logo.altform-lightunplated_targetsize-16.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\Square44x44Logo.altform-lightunplated_targetsize-24.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\Square44x44Logo.altform-lightunplated_targetsize-256.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\Square44x44Logo.altform-lightunplated_targetsize-32.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\Square44x44Logo.altform-lightunplated_targetsize-48.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\Square44x44Logo.altform-unplated_targetsize-16.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\Square44x44Logo.altform-unplated_targetsize-24.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\Square44x44Logo.altform-unplated_targetsize-256.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\Square44x44Logo.altform-unplated_targetsize-32.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\Square44x44Logo.altform-unplated_targetsize-48.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\Square44x44Logo.scale-100.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\Square44x44Logo.scale-125.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\Square44x44Logo.scale-150.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\Square44x44Logo.scale-200.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\Square44x44Logo.scale-400.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\Square44x44Logo.targetsize-16.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\Square44x44Logo.targetsize-24.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\Square44x44Logo.targetsize-256.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\Square44x44Logo.targetsize-32.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\Square44x44Logo.targetsize-48.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\storelogo.scale-100.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\storelogo.scale-125.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\storelogo.scale-150.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\storelogo.scale-200.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\storelogo.scale-400.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\Wide310x150Logo.scale-100.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\Wide310x150Logo.scale-125.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\Wide310x150Logo.scale-150.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\Wide310x150Logo.scale-200.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
    <Resource Include="Assets\Wide310x150Logo.scale-400.png">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Resource>
  </ItemGroup>
BluePointLilac commented 1 year ago

I am late, but hope to help latecomers. The CreateProcess or ShellExecute callers program as a child process of COM Surrogate, but we could start the program through the Explorer, this eliminates the need to add more useless sparse package files to display taskbar icon.

void FindDesktopFolderView(REFIID riid, void** ppv)
{
    CComPtr<IShellWindows> spShellWindows;
    (void)spShellWindows.CoCreateInstance(CLSID_ShellWindows);

    CComVariant vtLoc(CSIDL_DESKTOP);
    CComVariant vtEmpty;
    long lhwnd;
    CComPtr<IDispatch> spdisp;
    spShellWindows->FindWindowSW(
        &vtLoc, &vtEmpty,
        SWC_DESKTOP, &lhwnd, SWFO_NEEDDISPATCH, &spdisp);

    CComPtr<IShellBrowser> spBrowser;
    CComQIPtr<IServiceProvider>(spdisp)->
        QueryService(SID_STopLevelBrowser,
            IID_PPV_ARGS(&spBrowser));

    CComPtr<IShellView> spView;
    spBrowser->QueryActiveShellView(&spView);

    spView->QueryInterface(riid, ppv);
}

void GetDesktopAutomationObject(REFIID riid, void** ppv)
{
    CComPtr<IShellView> spsv;
    FindDesktopFolderView(IID_PPV_ARGS(&spsv));
    CComPtr<IDispatch> spdispView;
    spsv->GetItemObject(SVGIO_BACKGROUND, IID_PPV_ARGS(&spdispView));
    spdispView->QueryInterface(riid, ppv);
}

//通过Explorer执行程序(这样可以让程序不作为COM Surrogate的子进程)
void ShellExecuteFromExplorer(
    PCWSTR pszFile, 
    PCWSTR pszParameters = nullptr,
    PCWSTR pszDirectory = nullptr, 
    PCWSTR pszOperation = nullptr, 
    int nShowCmd = SW_SHOWNORMAL)
{
    CComPtr<IShellFolderViewDual> spFolderView;
    GetDesktopAutomationObject(IID_PPV_ARGS(&spFolderView));
    CComPtr<IDispatch> spdispShell;
    spFolderView->get_Application(&spdispShell);

    CComQIPtr<IShellDispatch2>(spdispShell)
        ->ShellExecute(CComBSTR(pszFile),
            CComVariant(pszParameters ? pszParameters : L""),
            CComVariant(pszDirectory ? pszDirectory : L""),
            CComVariant(pszOperation ? pszOperation : L""),
            CComVariant(nShowCmd));
}
sessiontalk commented 9 months ago

I too had the same problem, but I was missing the resource.pri file. Can anyone say what the significance of this file is and why it is required. The taskbar and start menu icons dont appear without it

DrusTheAxe commented 9 months ago

resources.pri is used by MRT to do potential localization lookups. Windows not finding resources.pri (regardless its content) is a hard error (thus no icon). You don't need your icon listed in it, but resources.pri needs to exist.

The why...

Appxmanifest.xml string localization is explicit (e.g. DisplayName="ms-resource:foo" == MRT lookup vs DisplayName="foo" == string literal ("foo")).

path (aka file) localizations are implicit and always; there is no explicit syntax. Any manifested localized file is always run thru MRT and if matched the result is returned, and if not found the input is returned.

Thus the difference is

switch (type)
{
    case STRING:
        if value.startswith("ms-resource:")
        {
            string key = value.substring("ms-resource:".length())
            return MRT.Lookup(key)
        }
        else
        {
            return value
        }
        break
    case PATH:
        result = MRT.Lookup(value)
        if found
            return result
        return
            value
}

Thus if you manifest <Logo>foo.gif</> and you have a key "foo.gif" in your resources.pri then you get the associated resolved value from resources.pri, else you get "foo.gif".

Windows handles "no resources.pri" as an error, not equivalent to "empty resources.pri". Though that sounds nice. If that interests you please share your feedback.

P.S. As for why the string vs path discrepancy? I don't know, just that it dates back to MRT's creation in Win8. This discrepancy's been discussed a few times over the years but to date the ROI to address it hasn't been justified.