Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

User/aeloros/crashandforeground #1416

Merged
merged 4 commits into from
Sep 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions dev/AppLifecycle/AppInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,8 +216,11 @@ namespace winrt::Microsoft::Windows::AppLifecycle::implementation
wil::unique_event cleanupEvent;
cleanupEvent.create(wil::EventOptions::ManualReset, eventName.c_str());

// Enqueue the request and signal the other instance.
// Enqueue the request and transfer foreground rights.
EnqueueRedirectionRequestId(id);
AllowSetForegroundWindow(m_processId);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume you don't care if this succeeds or not? (ignoring BOOl return value)


// Signal the activation.
m_innerActivated.SetEvent();

// Wait for the other instance to open the memory mapped file before exiting and cleaning our interest in it.
Expand Down Expand Up @@ -247,6 +250,9 @@ namespace winrt::Microsoft::Windows::AppLifecycle::implementation

IVector<Microsoft::Windows::AppLifecycle::AppInstance> AppInstance::GetInstances()
{
// Force the singleton init.
GetCurrent();

IVector<Microsoft::Windows::AppLifecycle::AppInstance> instances{ winrt::single_threaded_vector<Microsoft::Windows::AppLifecycle::AppInstance>() };

// Grab the list of processes while under the lock, and then drop it since we'll be calling out to other code.
Expand Down Expand Up @@ -294,12 +300,14 @@ namespace winrt::Microsoft::Windows::AppLifecycle::implementation

AppLifecycle::AppInstance AppInstance::FindOrRegisterForKey(hstring const& key)
{
// Force the singleton init.
GetCurrent();

// Try to register and return the current instance. If we fail to do that, then
// search and find the correct instance.
if (s_current->TrySetKey(key.c_str()))
{
// Register the class as owning the key, and return it.
return s_current.as<AppLifecycle::AppInstance>();
return GetCurrent();
}

return s_current->FindForKey(key.c_str());
Expand Down
2 changes: 1 addition & 1 deletion dev/WindowsAppRuntime_BootstrapDLL/MddBootstrap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ CLSID FindDDLM(
if ((id.size() >= maxIdLength) ||
(swscanf_s(id.c_str(), L"ddlm-%hu.%hu.%hu.%hu-%9s", &version.Major, &version.Minor, &version.Build, &version.Revision, architectureAsString, static_cast<unsigned>(ARRAYSIZE(architectureAsString))) != 5))
{
(void)LOG_HR_MSG(ERROR_INVALID_DATA, "%ls", id.c_str());
(void)LOG_WIN32_MSG(ERROR_INVALID_DATA, "%ls", id.c_str());
aeloros marked this conversation as resolved.
Show resolved Hide resolved
continue;
}

Expand Down
137 changes: 111 additions & 26 deletions test/TestApps/ManualTestApp/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,35 @@ using namespace winrt::Microsoft::Windows::AppLifecycle;

using namespace std::chrono;

bool IsPackagedProcess()
HWND g_window = NULL;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: HWND g_window{};

Obligatory favorite link ;-) ES.23: Prefer the {}-initializer syntax

wchar_t g_windowClass[] = L"TestWndClass"; // the main window class name
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: wchar_t g_windowClass[]{ L"TestWndClass"; };

Or even 'const auto' if you prefer


ATOM _RegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing parameter names

(yes, technically not required, but useful and you have the protocol down below)

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

std::wstring GetFullIdentityString()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'GetFullIdentityString' is GetCurrentPackageFullName but return as a std::wstring?

Even better if added to dev\common\AppModel.Identity.h

namespace appModel::Identity
{
inline bool IsPackagedProcess()
{
    ...
}

inline std::wstring GetCurrentPackageFullName()
{
    WCHAR packageFullName[PACKAGE_FULL_NAME_MAX_LENGTH + 1]{};
    UINT32 n{ static_cast<UINT32>(ARRAYSIZE(packageFullName)) };
    const auto rc{ ::GetCurrentPackageFullName(&n, packageFullName) };
    if (rc == APPMODEL_ERROR_NO_PACKAGE)
    {
        return std::wstring();
    }
    THROW_IF_WIN32_ERROR(rc);
    return std::wstring(packageFullName);
}
...

{
std::wstring identityString;
WCHAR idNameBuffer[PACKAGE_FULL_NAME_MAX_LENGTH + 1];
UINT32 idNameBufferLen = ARRAYSIZE(idNameBuffer);
if (::GetCurrentPackageFullName(&idNameBufferLen, idNameBuffer) == ERROR_SUCCESS)
{
identityString = idNameBuffer;
}

return identityString;
}

bool HasIdentity()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove and changed callers to

#include <appmodel.identity.h>
...
if (AppModel::Identity::IsPackagedProcess())

{
UINT32 n{};
return ::GetCurrentPackageFullName(&n, nullptr) == ERROR_INSUFFICIENT_BUFFER;;
static bool hasIdentity = !(GetFullIdentityString()).empty();
return hasIdentity;
}

bool NeedDynamicDependencies()
{
return !IsPackagedProcess();
return !HasIdentity();
}

HRESULT BootstrapInitialize()
Expand All @@ -36,10 +56,10 @@ HRESULT BootstrapInitialize()
constexpr PCWSTR c_PackagePublisherId{ L"8wekyb3d8bbwe" };
RETURN_IF_FAILED(MddBootstrapTestInitialize(c_PackageNamePrefix, c_PackagePublisherId));

// Version <major>.0.0.0 to find any framework package for this major version
const UINT64 c_Version_Major{ 4 };
PACKAGE_VERSION minVersion{ static_cast<UINT64>(c_Version_Major) << 48 };
RETURN_IF_FAILED(MddBootstrapInitialize(c_Version_Major, nullptr, minVersion));
// Major.Minor version, MinVersion=0 to find any framework package for this major.minor version
const UINT32 c_Version_MajorMinor{ 0x00040001 };
const PACKAGE_VERSION minVersion{};
RETURN_IF_FAILED(MddBootstrapInitialize(c_Version_MajorMinor, nullptr, minVersion));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DrusTheAxe - when you go add your generated versioning headers, please make a pass and find and fix anybody calling Mdd with manual parameters in samples & tests.


return S_OK;
}
Expand All @@ -64,6 +84,7 @@ void OnActivated(const winrt::Windows::Foundation::IInspectable&, const AppActiv
{
auto launchArgs = args.Data().as<ILaunchActivatedEventArgs>();
wprintf(L"Activated via redirection with args: %s\n", launchArgs.Arguments().c_str());
SetForegroundWindow(g_window);
}

int main()
Expand All @@ -72,34 +93,98 @@ int main()

THROW_IF_FAILED(BootstrapInitialize());

auto args = AppInstance::GetCurrent().GetActivatedEventArgs();
auto myKeyInstance = AppInstance::FindOrRegisterForKey(L"MyKey");
AppInstance::Activated_revoker token;

for (const auto& instance : AppInstance::GetInstances())
AppInstance keyInstance = AppInstance::FindOrRegisterForKey(L"derp.txt");
if (!keyInstance.IsCurrent())
{
wprintf(L"key: %s, isCurrent: %d\n", instance.Key().c_str(), instance.IsCurrent());
keyInstance.RedirectActivationToAsync(AppInstance::GetCurrent().GetActivatedEventArgs()).get();
}

if (myKeyInstance)
else
{
if (myKeyInstance.IsCurrent())
AppInstance thisInstance = AppInstance::GetCurrent();
token = thisInstance.Activated(
auto_revoke, [&thisInstance](
const auto& sender, const AppActivationArguments& args)
{ OnActivated(sender, args); }
);

auto hInstance = GetModuleHandle(NULL);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: nullptr

_RegisterClass(hInstance);

// Perform application initialization:
if (!InitInstance(hInstance, SW_SHOWDEFAULT))
{
printf("Key owner activated!\n");

// Sign up for the activated event.
auto token = myKeyInstance.Activated(auto_revoke, [&myKeyInstance](const auto& sender, const AppActivationArguments& args) { OnActivated(sender, args); });

printf("Activated, waiting for redirections!\n");
WaitForActivations().get();
return 1;
}
else

// Main message loop:
MSG msg;
BOOL msgRet;
while ((msgRet = GetMessage(&msg, NULL, 0, 0)) != 0)
{
printf("Redirecting to key owner!\n");
myKeyInstance.RedirectActivationToAsync(args).get();
printf("Finished redirecting!\n");
if (msgRet == -1)
{
return (int)GetLastError();
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}

BootstrapShutdown();
return 0;
}

ATOM _RegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex = {};

wcex.cbSize = sizeof(wcex);

wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.lpszClassName = g_windowClass;

return RegisterClassEx(&wcex);
}

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
g_window = CreateWindow(g_windowClass, L"ContainerWindowingTestApp", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

if (!g_window)
{
return FALSE;
}

ShowWindow(g_window, nCmdShow);
UpdateWindow(g_window);
return TRUE;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;

switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
break;

case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}