Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
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
41 changes: 41 additions & 0 deletions Samples/ChatAppShare/AppxManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" xmlns:uap10="http://schemas.microsoft.com/appx/manifest/uap/windows10/10" xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities" IgnorableNamespaces="uap uap10 rescap">
<Identity Name="Weixin" Publisher="CN=ravishroshan" Version="1.0.1.0" ProcessorArchitecture="neutral" />
<Properties>
<DisplayName>Weixin</DisplayName>
<PublisherDisplayName>Weixin</PublisherDisplayName>
<Logo>Assets\WeChat150×150minin.png</Logo>
<uap10:AllowExternalContent>true</uap10:AllowExternalContent>
</Properties>
<Resources>
<Resource Language="en-us" />
</Resources>
<Dependencies>
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.19041.0" MaxVersionTested="10.0.26100.0" />
</Dependencies>
<Applications>
<Application Id="Weixin" Executable="SampleChatAppWithShare.exe" uap10:TrustLevel="mediumIL" uap10:RuntimeBehavior="win32App">
<uap:VisualElements AppListEntry="none" DisplayName="Weixin" Description="Weixin" BackgroundColor="transparent" Square150x150Logo="Assets\WeChat150×150mini.png" Square44x44Logo="Assets\WeChat44×44mini.png"></uap:VisualElements>
</Application>
<Application Id="WeixinShare" Executable="ShareApp.exe" uap10:TrustLevel="mediumIL" uap10:RuntimeBehavior="win32App">
<uap:VisualElements AppListEntry="none" DisplayName="Weixin" Description="Weixin" BackgroundColor="transparent" Square150x150Logo="Assets\WeChat150×150mini.png" Square44x44Logo="Assets\WeChat44×44mini.png"></uap:VisualElements>
<Extensions>
<uap:Extension Category="windows.shareTarget">
<uap:ShareTarget Description="Send to Weixin">
<uap:SupportedFileTypes>
<uap:SupportsAnyFileType />
</uap:SupportedFileTypes>
<uap:DataFormat>StorageItems</uap:DataFormat>
<uap:DataFormat>Bitmap</uap:DataFormat>
<uap:DataFormat>URI</uap:DataFormat>
<uap:DataFormat>Text</uap:DataFormat>
</uap:ShareTarget>
</uap:Extension>
</Extensions>
</Application>
</Applications>
<Capabilities>
<rescap:Capability Name="runFullTrust" />
<rescap:Capability Name="unvirtualizedResources" />
</Capabilities>
</Package>
44 changes: 44 additions & 0 deletions Samples/ChatAppShare/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
This repo contains a sample C++ application demonstrating how to use [Signed Sparse Packages](https://aka.ms/sparsepkgblog) to give a non-packaged desktop app access to new Windows APIs and features.

## Instructions

You can learn more about Signed Sparse Packages and Identity, Registration & Activation of Win32 apps in this [blogpost](https://aka.ms/sparsepkgblog) and in the [documentation](https://aka.ms/sparsepkgdocs).

### Requirements

1. Windows SDK version 10.0.19000.0 +
2. Windows OS version 10.0.19000.0 +
3. Microsoft Visual C++ Redistributables

### SampleChatAppWithShare

A non-package native Windows desktop Win32 GUI application written in C++. It installs a Signed Sparse Package and uses it to act as a Share Target.
* Registration of a Signed Sparse Package happens in PackageIdentity.cpp.

### ShareApp
* Handling of Shared Data happens in ShareTargetManager.cpp.

* Registration of a Signed Sparse Package happens in PackageIdentity.cpp.

### Packaging
* Manifest file to package both apps as external location is present in AppxManifest.xml at the root of this sample folder. For reference we have an MSIX as well.


### Building and running the sample

1. Make sure your machine has Developer Mode turned on.
2. Retarget the solution to the SDK version on your machine – Right click -> Retarget solution.
3. Add a project reference to the Windows.winmd file at "C:\Program Files (x86)\Windows Kits\10\UnionMetadata\\<SDK_Version>\Windows.winmd". (Right click PhotoStoreDemo project | Add | Reference| Browse | All files | Windows.winmd)
4. Update the Publisher value in the AppxManifest.xml file and in SampleChatAppWithShare.exe.manifest to match the Publisher value in your cert. If you need to create a cert for signing have a look at [Creating an app package signing certificate](https://docs.microsoft.com/en-us/windows/win32/appxpkg/how-to-create-a-package-signing-certificate).
5. Install your cert on the machine
6. Create a Sparse Package by packaging the updated contents of PackageWithExternalLocationCppSample using [App Packager](https://docs.microsoft.com/en-us/windows/win32/appxpkg/make-appx-package--makeappx-exe-) (MakeAppx.exe) and specifying the **/nv** flag. For example: MakeAppx.exe pack /d \<Path to directory with AppxManifest.xml> /p \<Output Path> mypackage.msix /nv
7. Sign the new Sparse Package. See [Signing an app package using SignTool](https://docs.microsoft.com/en-us/windows/win32/appxpkg/how-to-sign-a-package-using-signtool) or you can also use [Device Guard Signing](https://docs.microsoft.com/en-us/microsoft-store/device-guard-signing-portal).
8. In RegisterPackageWithExternalLocation() method (in PackageIdentity.cpp) update the value of **externalLocation** to match the output location of your VS Build binaries and the value of **packagePath** to match the path to your signed Sparse Package (.msix). Note that these values cannot be relative paths and must be complete paths.
9. Build the app
10. Copy the PhotoStoreDemoPkg\Assets folder and resources.pri file to the same location as your VS Build binaries. You can replace Assets with your own images.
11. Run the app

### Removing the package
If you need to remove the package from package manager you can run the following command in an admin command prompt:

powershell -c “get-appxpackage -name \*PackageWithExternalLocationCppSample\* | remove-appxpackage"
51 changes: 51 additions & 0 deletions Samples/ChatAppShare/SampleChatAppWithShare.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.14.36401.2
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SampleChatAppWithShare", "SampleChatAppWithShare\SampleChatAppWithShare.vcxproj", "{DD6EC845-790A-4BD4-B638-AF0964704337}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ShareApp", "ShareApp\ShareApp.vcxproj", "{006AFCE4-5393-4696-9319-9FDD3054774E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM64 = Debug|ARM64
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|ARM64 = Release|ARM64
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{DD6EC845-790A-4BD4-B638-AF0964704337}.Debug|ARM64.ActiveCfg = Debug|ARM64
{DD6EC845-790A-4BD4-B638-AF0964704337}.Debug|ARM64.Build.0 = Debug|ARM64
{DD6EC845-790A-4BD4-B638-AF0964704337}.Debug|x64.ActiveCfg = Debug|x64
{DD6EC845-790A-4BD4-B638-AF0964704337}.Debug|x64.Build.0 = Debug|x64
{DD6EC845-790A-4BD4-B638-AF0964704337}.Debug|x86.ActiveCfg = Debug|Win32
{DD6EC845-790A-4BD4-B638-AF0964704337}.Debug|x86.Build.0 = Debug|Win32
{DD6EC845-790A-4BD4-B638-AF0964704337}.Release|ARM64.ActiveCfg = Release|ARM64
{DD6EC845-790A-4BD4-B638-AF0964704337}.Release|ARM64.Build.0 = Release|ARM64
{DD6EC845-790A-4BD4-B638-AF0964704337}.Release|x64.ActiveCfg = Release|x64
{DD6EC845-790A-4BD4-B638-AF0964704337}.Release|x64.Build.0 = Release|x64
{DD6EC845-790A-4BD4-B638-AF0964704337}.Release|x86.ActiveCfg = Release|Win32
{DD6EC845-790A-4BD4-B638-AF0964704337}.Release|x86.Build.0 = Release|Win32
{006AFCE4-5393-4696-9319-9FDD3054774E}.Debug|ARM64.ActiveCfg = Debug|ARM64
{006AFCE4-5393-4696-9319-9FDD3054774E}.Debug|ARM64.Build.0 = Debug|ARM64
{006AFCE4-5393-4696-9319-9FDD3054774E}.Debug|x64.ActiveCfg = Debug|x64
{006AFCE4-5393-4696-9319-9FDD3054774E}.Debug|x64.Build.0 = Debug|x64
{006AFCE4-5393-4696-9319-9FDD3054774E}.Debug|x86.ActiveCfg = Debug|Win32
{006AFCE4-5393-4696-9319-9FDD3054774E}.Debug|x86.Build.0 = Debug|Win32
{006AFCE4-5393-4696-9319-9FDD3054774E}.Release|ARM64.ActiveCfg = Release|ARM64
{006AFCE4-5393-4696-9319-9FDD3054774E}.Release|ARM64.Build.0 = Release|ARM64
{006AFCE4-5393-4696-9319-9FDD3054774E}.Release|x64.ActiveCfg = Release|x64
{006AFCE4-5393-4696-9319-9FDD3054774E}.Release|x64.Build.0 = Release|x64
{006AFCE4-5393-4696-9319-9FDD3054774E}.Release|x86.ActiveCfg = Release|Win32
{006AFCE4-5393-4696-9319-9FDD3054774E}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {6709D164-3EDF-4B1A-894A-2C561B2062CC}
EndGlobalSection
EndGlobal
100 changes: 100 additions & 0 deletions Samples/ChatAppShare/SampleChatAppWithShare/BackgroundService.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#include "BackgroundService.h"
#include <iostream>

// Global constants definition
const std::string PIPE_NAME = "\\\\.\\pipe\\HelloWorldService";
const std::string HELLO_WORLD_RESPONSE = "Hello world";

HelloWorldService::HelloWorldService() : m_running(false) {}

HelloWorldService::~HelloWorldService() {
Stop();
}

bool HelloWorldService::Start() {
if (m_running) {
return false;
}

m_running = true;
m_serviceThread = std::thread(&HelloWorldService::ServiceLoop, this);

std::cout << "Hello World Service started. Listening on pipe: " << PIPE_NAME << std::endl;
return true;
}

void HelloWorldService::Stop() {
if (m_running) {
m_running = false;
if (m_serviceThread.joinable()) {
m_serviceThread.join();
}
std::cout << "Hello World Service stopped." << std::endl;
}
}

bool HelloWorldService::IsRunning() const {
return m_running;
}

void HelloWorldService::ServiceLoop() {
while (m_running) {
// Create named pipe
HANDLE hPipe = CreateNamedPipeA(
PIPE_NAME.c_str(),
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
1, // Max instances
1024, // Output buffer size
1024, // Input buffer size
0, // Default timeout
nullptr // Security attributes
);

if (hPipe == INVALID_HANDLE_VALUE) {
std::cerr << "Failed to create named pipe. Error: " << GetLastError() << std::endl;
continue;
}

// Wait for client connection
std::cout << "Waiting for client connection..." << std::endl;

if (ConnectNamedPipe(hPipe, nullptr) || GetLastError() == ERROR_PIPE_CONNECTED) {
std::cout << "Client connected!" << std::endl;
HandleClient(hPipe);
}
else {
std::cerr << "Failed to connect to client. Error: " << GetLastError() << std::endl;
}

CloseHandle(hPipe);
}
}

void HelloWorldService::HandleClient(HANDLE hPipe) {
char buffer[1024];
DWORD bytesRead;
DWORD bytesWritten;

// Read request from client
if (ReadFile(hPipe, buffer, sizeof(buffer) - 1, &bytesRead, nullptr)) {
buffer[bytesRead] = '\0';
std::cout << "Received request: " << buffer << std::endl;

// Send "Hello world" response
const char* response = HELLO_WORLD_RESPONSE.c_str();
if (WriteFile(hPipe, response, static_cast<DWORD>(HELLO_WORLD_RESPONSE.length()), &bytesWritten, nullptr)) {
std::cout << "Sent response: " << response << std::endl;
}
else {
std::cerr << "Failed to send response. Error: " << GetLastError() << std::endl;
}
}
else {
std::cerr << "Failed to read from client. Error: " << GetLastError() << std::endl;
}

// Flush the pipe to allow the client to read the pipe's contents before disconnecting
FlushFileBuffers(hPipe);
DisconnectNamedPipe(hPipe);
}
27 changes: 27 additions & 0 deletions Samples/ChatAppShare/SampleChatAppWithShare/BackgroundService.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#pragma once

#include <windows.h>
#include <string>
#include <thread>

// Forward declarations and constants
extern const std::string PIPE_NAME;
extern const std::string HELLO_WORLD_RESPONSE;

class HelloWorldService {
private:
bool m_running;
std::thread m_serviceThread;

public:
HelloWorldService();
~HelloWorldService();

bool Start();
void Stop();
bool IsRunning() const;

private:
void ServiceLoop();
void HandleClient(HANDLE hPipe);
};
Loading