diff --git a/Samples/ChatAppShare/AppxManifest.xml b/Samples/ChatAppShare/AppxManifest.xml
new file mode 100644
index 0000000..45fd999
--- /dev/null
+++ b/Samples/ChatAppShare/AppxManifest.xml
@@ -0,0 +1,41 @@
+
+
+
+
+ Weixin
+ Weixin
+ Assets\WeChat150×150minin.png
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ StorageItems
+ Bitmap
+ URI
+ Text
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Samples/ChatAppShare/README.md b/Samples/ChatAppShare/README.md
new file mode 100644
index 0000000..4d1a81e
--- /dev/null
+++ b/Samples/ChatAppShare/README.md
@@ -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\\\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 \ /p \ 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"
diff --git a/Samples/ChatAppShare/SampleChatAppWithShare.sln b/Samples/ChatAppShare/SampleChatAppWithShare.sln
new file mode 100644
index 0000000..d31f7b8
--- /dev/null
+++ b/Samples/ChatAppShare/SampleChatAppWithShare.sln
@@ -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
diff --git a/Samples/ChatAppShare/SampleChatAppWithShare/BackgroundService.cpp b/Samples/ChatAppShare/SampleChatAppWithShare/BackgroundService.cpp
new file mode 100644
index 0000000..4b01cee
--- /dev/null
+++ b/Samples/ChatAppShare/SampleChatAppWithShare/BackgroundService.cpp
@@ -0,0 +1,100 @@
+#include "BackgroundService.h"
+#include
+
+// 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(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);
+}
\ No newline at end of file
diff --git a/Samples/ChatAppShare/SampleChatAppWithShare/BackgroundService.h b/Samples/ChatAppShare/SampleChatAppWithShare/BackgroundService.h
new file mode 100644
index 0000000..a7f81a2
--- /dev/null
+++ b/Samples/ChatAppShare/SampleChatAppWithShare/BackgroundService.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#include
+#include
+#include
+
+// 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);
+};
diff --git a/Samples/ChatAppShare/SampleChatAppWithShare/ChatManager.cpp b/Samples/ChatAppShare/SampleChatAppWithShare/ChatManager.cpp
new file mode 100644
index 0000000..b00ebb6
--- /dev/null
+++ b/Samples/ChatAppShare/SampleChatAppWithShare/ChatManager.cpp
@@ -0,0 +1,132 @@
+#include "ChatManager.h"
+#include "ChatModels.h"
+#include "FileManager.h"
+#include "UIManager.h"
+#include
+#include
+#include
+
+void LoadContactChat(int contactIndex)
+{
+ if (!IsValidContactIndex(contactIndex)) return;
+
+ selectedContactIndex = contactIndex;
+ const Contact& contact = contacts[contactIndex];
+
+ // Update contact name with status indicator
+ std::wstring headerText = contact.name + L" " + L" (" + contact.status + L")";
+ SetWindowText(hContactName, headerText.c_str());
+
+ // Clear and populate chat display with better formatting
+ SetWindowText(hChatDisplay, L"");
+
+ std::wstring chatText;
+ for (const auto& message : contact.messages) {
+ // Add timestamps and better message formatting
+ SYSTEMTIME st;
+ GetLocalTime(&st);
+ WCHAR timeStr[50];
+ swprintf_s(timeStr, 50, L"[%02d:%02d] ", st.wHour, st.wMinute);
+
+ if (message.find(L"You:") == 0) {
+ chatText += L" "; // Right align for your messages
+ chatText += timeStr + message + L"\r\n\r\n";
+ } else {
+ chatText += timeStr + message + L"\r\n\r\n";
+ }
+ }
+
+ SetWindowText(hChatDisplay, chatText.c_str());
+
+ // Scroll to bottom
+ ::SendMessage(hChatDisplay, EM_SETSEL, -1, -1);
+ ::SendMessage(hChatDisplay, EM_SCROLLCARET, 0, 0);
+
+ // Update shared files list
+ UpdateSharedFilesList();
+
+ // Refresh contact list to show selection
+ InvalidateRect(hContactsList, NULL, TRUE);
+}
+
+void AddMessageToChat(const std::wstring& message, bool isOutgoing)
+{
+ Contact* contact = GetSelectedContact();
+ if (!contact) return;
+
+ // Add timestamp to message
+ SYSTEMTIME st;
+ GetLocalTime(&st);
+ WCHAR timeStr[50];
+ swprintf_s(timeStr, 50, L"[%02d:%02d] ", st.wHour, st.wMinute);
+
+ std::wstring formattedMessage;
+ if (isOutgoing) {
+ formattedMessage = L"You: " + message + L" ??";
+ } else {
+ formattedMessage = contact->name + L": " + message;
+ }
+
+ contact->messages.push_back(formattedMessage);
+ contact->lastMessage = message.length() > 50 ? message.substr(0, 47) + L"..." : message;
+
+ // Update chat display
+ LoadContactChat(selectedContactIndex);
+
+ // Refresh contacts list to update last message preview
+ InvalidateRect(hContactsList, NULL, TRUE);
+}
+
+void SendChatMessage()
+{
+ if (selectedContactIndex < 0) return;
+
+ WCHAR buffer[1024];
+ GetWindowText(hMessageInput, buffer, 1024);
+
+ std::wstring message(buffer);
+ if (!message.empty()) {
+ AddMessageToChat(message, true);
+ SetWindowText(hMessageInput, L"");
+
+ // Simulate auto-reply after a short delay
+ SetTimer(GetParent(hMessageInput), 1, 2000, NULL);
+ }
+}
+
+void ProcessAutoReply(HWND hWnd, int timerType)
+{
+ if (selectedContactIndex < 0) return;
+
+ KillTimer(hWnd, timerType);
+
+ if (timerType == 1) {
+ // Auto-reply from the selected contact with more variety
+ std::vector autoReplies = {
+ L"Got it!",
+ L"Thanks for letting me know!",
+ L"Sounds good!",
+ L"I'll get back to you soon.",
+ L"Perfect!",
+ L"Absolutely!",
+ L"Let me think about it.",
+ L"Great idea!"
+ };
+
+ int replyIndex = rand() % autoReplies.size();
+ AddMessageToChat(autoReplies[replyIndex], false);
+ }
+ else if (timerType == 2) {
+ // Auto-reply acknowledging the shared file
+ std::vector fileReplies = {
+ L"Thanks for sharing the file!",
+ L"Got the file, will check it out.",
+ L"File received, thanks! ??",
+ L"Perfect timing, I needed this file.",
+ L"Awesome, downloading now!"
+ };
+
+ int replyIndex = rand() % fileReplies.size();
+ AddMessageToChat(fileReplies[replyIndex], false);
+ }
+}
\ No newline at end of file
diff --git a/Samples/ChatAppShare/SampleChatAppWithShare/ChatManager.h b/Samples/ChatAppShare/SampleChatAppWithShare/ChatManager.h
new file mode 100644
index 0000000..daefb88
--- /dev/null
+++ b/Samples/ChatAppShare/SampleChatAppWithShare/ChatManager.h
@@ -0,0 +1,10 @@
+#pragma once
+
+#include
+#include
+
+// Chat management functions
+void LoadContactChat(int contactIndex);
+void SendChatMessage();
+void AddMessageToChat(const std::wstring& message, bool isOutgoing);
+void ProcessAutoReply(HWND hWnd, int timerType);
\ No newline at end of file
diff --git a/Samples/ChatAppShare/SampleChatAppWithShare/ChatModels.cpp b/Samples/ChatAppShare/SampleChatAppWithShare/ChatModels.cpp
new file mode 100644
index 0000000..db4f520
--- /dev/null
+++ b/Samples/ChatAppShare/SampleChatAppWithShare/ChatModels.cpp
@@ -0,0 +1,48 @@
+#include "ChatModels.h"
+
+// Global data definitions
+std::vector contacts;
+std::map> chatHistory;
+int selectedContactIndex = -1;
+
+void InitializeContacts()
+{
+ contacts = {
+ {L"Alice Johnson", L"Hey, how are you?", {L"Alice: Hey, how are you?", L"You: I'm doing great, thanks!", L"Alice: That's wonderful to hear!"}, {}, L"Available", true},
+ {L"Bob Smith", L"See you tomorrow!", {L"Bob: Are we still meeting tomorrow?", L"You: Yes, see you at 3 PM", L"Bob: See you tomorrow!"}, {}, L"In a meeting", true},
+ {L"Carol Williams", L"Thanks for the help", {L"Carol: Could you help me with the project?", L"You: Of course! What do you need?", L"Carol: Thanks for the help"}, {}, L"Available", true},
+ {L"David Brown", L"Great presentation!", {L"David: Great presentation today!", L"You: Thank you! I'm glad you liked it"}, {}, L"Away", false},
+ {L"Emma Davis", L"Coffee later?", {L"Emma: Want to grab coffee later?", L"You: Sure! What time works for you?", L"Emma: Coffee later?"}, {}, L"Available", true},
+ {L"Frank Miller", L"Happy Birthday!", {L"Frank: Happy Birthday!", L"You: Thank you so much!"}, {}, L"Busy", true},
+ {L"Grace Wilson", L"Meeting rescheduled", {L"Grace: Meeting has been rescheduled to 4 PM", L"You: Got it, thanks for letting me know"}, {}, L"Available", true},
+ {L"Henry Taylor", L"Weekend plans?", {L"Henry: Any plans for the weekend?", L"You: Nothing concrete yet", L"Henry: Weekend plans?"}, {}, L"Offline", false},
+ {L"Ivy Anderson", L"Project update", {L"Ivy: Here's the project update you requested", L"You: Perfect, reviewing it now"}, {}, L"Available", true},
+ {L"Jack Thompson", L"Game night Friday", {L"Jack: Game night this Friday?", L"You: Count me in!", L"Jack: Game night Friday"}, {}, L"Gaming", true},
+ {L"Kate Garcia", L"Recipe sharing", {L"Kate: Loved that recipe you shared!", L"You: I'm so glad you enjoyed it!"}, {}, L"Cooking", true},
+ {L"Leo Martinez", L"Workout buddy", {L"Leo: Gym session tomorrow morning?", L"You: Absolutely! 7 AM as usual?"}, {}, L"At the gym", true},
+ {L"Mia Rodriguez", L"Book recommendation", {L"Mia: Any good book recommendations?", L"You: I just finished a great mystery novel"}, {}, L"Reading", true},
+ {L"Noah Lee", L"Tech discussion", {L"Noah: Thoughts on the new framework?", L"You: It looks promising! Want to discuss over lunch?"}, {}, L"Coding", true},
+ {L"Olivia Clark", L"Travel planning", {L"Olivia: Planning the vacation itinerary", L"You: Excited to see what you've planned!"}, {}, L"Traveling", false}
+ };
+
+ // Add some sample shared files to demonstrate the feature
+ SYSTEMTIME st;
+ GetSystemTime(&st);
+
+ contacts[0].sharedFiles.push_back({L"Project_Proposal.docx", L"C:\\Documents\\Project_Proposal.docx", L"Alice", st});
+ contacts[1].sharedFiles.push_back({L"Meeting_Notes.pdf", L"C:\\Documents\\Meeting_Notes.pdf", L"Bob", st});
+ contacts[2].sharedFiles.push_back({L"Budget_Spreadsheet.xlsx", L"C:\\Documents\\Budget_Spreadsheet.xlsx", L"Carol", st});
+}
+
+Contact* GetSelectedContact()
+{
+ if (IsValidContactIndex(selectedContactIndex)) {
+ return &contacts[selectedContactIndex];
+ }
+ return nullptr;
+}
+
+bool IsValidContactIndex(int index)
+{
+ return index >= 0 && index < (int)contacts.size();
+}
\ No newline at end of file
diff --git a/Samples/ChatAppShare/SampleChatAppWithShare/ChatModels.h b/Samples/ChatAppShare/SampleChatAppWithShare/ChatModels.h
new file mode 100644
index 0000000..3fb7531
--- /dev/null
+++ b/Samples/ChatAppShare/SampleChatAppWithShare/ChatModels.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#include
+#include
+#include
+#include
+
+struct SharedFile {
+ std::wstring fileName;
+ std::wstring filePath;
+ std::wstring sharedBy;
+ SYSTEMTIME timeShared;
+};
+
+struct Contact {
+ std::wstring name;
+ std::wstring lastMessage;
+ std::vector messages;
+ std::vector sharedFiles;
+ std::wstring status;
+ bool isOnline;
+};
+
+// Global data
+extern std::vector contacts;
+extern std::map> chatHistory;
+extern int selectedContactIndex;
+
+// Contact management functions
+void InitializeContacts();
+Contact* GetSelectedContact();
+bool IsValidContactIndex(int index);
\ No newline at end of file
diff --git a/Samples/ChatAppShare/SampleChatAppWithShare/ContactSelectionDialog.cpp b/Samples/ChatAppShare/SampleChatAppWithShare/ContactSelectionDialog.cpp
new file mode 100644
index 0000000..ba1aeca
--- /dev/null
+++ b/Samples/ChatAppShare/SampleChatAppWithShare/ContactSelectionDialog.cpp
@@ -0,0 +1,275 @@
+#include "ContactSelectionDialog.h"
+#include "Resource.h"
+#include "UIConstants.h"
+#include
+
+// Static member initialization
+ContactSelectionDialog::SelectionResult ContactSelectionDialog::s_dialogResult;
+std::wstring ContactSelectionDialog::s_currentFilePath;
+std::wstring ContactSelectionDialog::s_currentFileName;
+
+ContactSelectionDialog::SelectionResult ContactSelectionDialog::ShowContactSelectionDialog(HWND hParent, const std::wstring& filePath, const std::wstring& fileName)
+{
+ // Store the file information for the dialog
+ s_currentFilePath = filePath;
+ s_currentFileName = fileName;
+
+ // Reset the result
+ s_dialogResult = SelectionResult();
+
+ // Show the modal dialog
+ INT_PTR result = DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_CONTACT_SELECTION), hParent, ContactSelectionDlgProc);
+
+ if (result == IDOK)
+ {
+ s_dialogResult.wasSelected = true;
+ s_dialogResult.filePath = s_currentFilePath;
+ s_dialogResult.fileName = s_currentFileName;
+ }
+ else
+ {
+ s_dialogResult.wasSelected = false;
+ }
+
+ return s_dialogResult;
+}
+
+INT_PTR CALLBACK ContactSelectionDialog::ContactSelectionDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message)
+ {
+ case WM_INITDIALOG:
+ {
+ // Set the dialog title with file name
+ std::wstring title = L"Share \"" + s_currentFileName + L"\" - Select Contact";
+ SetWindowText(hDlg, title.c_str());
+
+ // Set up the dialog layout and styling
+ SetupDialogSizing(hDlg);
+
+ // Initialize and populate the contact list
+ HWND hListBox = GetDlgItem(hDlg, IDC_CONTACT_SELECTION_LIST);
+ if (hListBox)
+ {
+ InitializeContactList(hListBox);
+ PopulateContactList(hListBox);
+ }
+
+ // Set up the share message edit control
+ HWND hMessageEdit = GetDlgItem(hDlg, IDC_SHARE_MESSAGE_EDIT);
+ if (hMessageEdit)
+ {
+ std::wstring defaultMessage = L"I'm sharing \"" + s_currentFileName + L"\" with you!";
+ SetWindowText(hMessageEdit, defaultMessage.c_str());
+ }
+
+ // Initially disable the Select button until a contact is chosen
+ EnableWindow(GetDlgItem(hDlg, IDC_SELECT_CONTACT_BUTTON), FALSE);
+
+ // Center the dialog on the parent
+ RECT rcParent, rcDlg;
+ HWND hParent = GetParent(hDlg);
+ if (hParent)
+ {
+ GetWindowRect(hParent, &rcParent);
+ GetWindowRect(hDlg, &rcDlg);
+
+ int x = rcParent.left + (rcParent.right - rcParent.left - (rcDlg.right - rcDlg.left)) / 2;
+ int y = rcParent.top + (rcParent.bottom - rcParent.top - (rcDlg.bottom - rcDlg.top)) / 2;
+
+ SetWindowPos(hDlg, HWND_TOP, x, y, 0, 0, SWP_NOSIZE);
+ }
+
+ return TRUE;
+ }
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDC_CONTACT_SELECTION_LIST:
+ if (HIWORD(wParam) == LBN_SELCHANGE)
+ {
+ int selectedIndex = (int)SendDlgItemMessage(hDlg, IDC_CONTACT_SELECTION_LIST, LB_GETCURSEL, 0, 0);
+ HandleContactSelection(hDlg, selectedIndex);
+ }
+ else if (HIWORD(wParam) == LBN_DBLCLK)
+ {
+ // Double-click selects and closes dialog
+ OnSelectContact(hDlg);
+ }
+ break;
+
+ case IDC_SELECT_CONTACT_BUTTON:
+ OnSelectContact(hDlg);
+ break;
+
+ case IDC_CANCEL_SELECTION_BUTTON:
+ case IDCANCEL:
+ OnCancel(hDlg);
+ break;
+
+ case IDOK:
+ OnSelectContact(hDlg);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ OnCancel(hDlg);
+ break;
+ }
+
+ return FALSE;
+}
+
+void ContactSelectionDialog::InitializeContactList(HWND hListBox)
+{
+ // Set up the list box for contact display
+ SendMessage(hListBox, LB_RESETCONTENT, 0, 0);
+}
+
+void ContactSelectionDialog::PopulateContactList(HWND hListBox)
+{
+ // Clear existing items
+ SendMessage(hListBox, LB_RESETCONTENT, 0, 0);
+
+ // Ensure contacts are initialized
+ if (contacts.empty())
+ {
+ InitializeContacts();
+ }
+
+ // Debug logging
+ OutputDebugStringW((L"ContactSelectionDialog: Populating list with " + std::to_wstring(contacts.size()) + L" contacts\n").c_str());
+
+ // Add all contacts to the list
+ for (size_t i = 0; i < contacts.size(); ++i)
+ {
+ const Contact& contact = contacts[i];
+
+ // Create display text with contact name and status
+ std::wstring displayText = contact.name + L" - " + contact.status;
+ if (!contact.isOnline)
+ {
+ displayText += L" (Offline)";
+ }
+
+ int itemIndex = (int)SendMessage(hListBox, LB_ADDSTRING, 0, (LPARAM)displayText.c_str());
+
+ // Store the contact index as item data
+ SendMessage(hListBox, LB_SETITEMDATA, itemIndex, (LPARAM)i);
+
+ // Debug log each contact being added
+ OutputDebugStringW((L"ContactSelectionDialog: Added contact " + std::to_wstring(i) + L": " + contact.name + L"\n").c_str());
+ }
+
+ // If no contacts were added, add a placeholder
+ if (contacts.empty())
+ {
+ SendMessage(hListBox, LB_ADDSTRING, 0, (LPARAM)L"No contacts available");
+ OutputDebugStringW(L"ContactSelectionDialog: No contacts available - added placeholder\n");
+ }
+ else
+ {
+ OutputDebugStringW((L"ContactSelectionDialog: Successfully populated " + std::to_wstring(contacts.size()) + L" contacts\n").c_str());
+ }
+}
+
+void ContactSelectionDialog::HandleContactSelection(HWND hDlg, int selectedIndex)
+{
+ if (selectedIndex != LB_ERR)
+ {
+ // Enable the Select button when a contact is selected
+ EnableWindow(GetDlgItem(hDlg, IDC_SELECT_CONTACT_BUTTON), TRUE);
+
+ // Get the contact index from item data
+ HWND hListBox = GetDlgItem(hDlg, IDC_CONTACT_SELECTION_LIST);
+ int contactIndex = (int)SendMessage(hListBox, LB_GETITEMDATA, selectedIndex, 0);
+
+ if (contactIndex >= 0 && contactIndex < (int)contacts.size())
+ {
+ // Update the share message with the selected contact's name
+ const Contact& contact = contacts[contactIndex];
+ std::wstring personalizedMessage = L"Hey " + contact.name + L"! I'm sharing \"" + s_currentFileName + L"\" with you.";
+
+ HWND hMessageEdit = GetDlgItem(hDlg, IDC_SHARE_MESSAGE_EDIT);
+ if (hMessageEdit)
+ {
+ SetWindowText(hMessageEdit, personalizedMessage.c_str());
+ }
+ }
+ }
+ else
+ {
+ // Disable the Select button when no contact is selected
+ EnableWindow(GetDlgItem(hDlg, IDC_SELECT_CONTACT_BUTTON), FALSE);
+ }
+}
+
+void ContactSelectionDialog::OnSelectContact(HWND hDlg)
+{
+ HWND hListBox = GetDlgItem(hDlg, IDC_CONTACT_SELECTION_LIST);
+ int selectedIndex = (int)SendMessage(hListBox, LB_GETCURSEL, 0, 0);
+
+ if (selectedIndex == LB_ERR)
+ {
+ MessageBox(hDlg, L"Please select a contact to share with.", L"No Contact Selected", MB_OK | MB_ICONWARNING);
+ return;
+ }
+
+ // Check if contacts are available
+ if (contacts.empty())
+ {
+ MessageBox(hDlg, L"No contacts are available. Please ensure the application is properly initialized.", L"No Contacts Available", MB_OK | MB_ICONWARNING);
+ return;
+ }
+
+ // Get the contact index from item data
+ int contactIndex = (int)SendMessage(hListBox, LB_GETITEMDATA, selectedIndex, 0);
+
+ // Debug logging
+ OutputDebugStringW((L"ContactSelectionDialog: Selected contact index: " + std::to_wstring(contactIndex) + L", total contacts: " + std::to_wstring(contacts.size()) + L"\n").c_str());
+
+ if (contactIndex >= 0 && contactIndex < (int)contacts.size())
+ {
+ // Get the share message
+ HWND hMessageEdit = GetDlgItem(hDlg, IDC_SHARE_MESSAGE_EDIT);
+ WCHAR messageBuffer[512] = {0};
+ if (hMessageEdit)
+ {
+ GetWindowText(hMessageEdit, messageBuffer, 512);
+ }
+
+ // Store the result
+ s_dialogResult.contactIndex = contactIndex;
+ s_dialogResult.shareMessage = messageBuffer;
+
+ // Debug logging
+ OutputDebugStringW((L"ContactSelectionDialog: Contact selected - " + contacts[contactIndex].name + L"\n").c_str());
+
+ // Close dialog with success
+ EndDialog(hDlg, IDOK);
+ }
+ else
+ {
+ MessageBox(hDlg, L"Invalid contact selection. Please try again.", L"Selection Error", MB_OK | MB_ICONERROR);
+ OutputDebugStringW((L"ContactSelectionDialog: Invalid contact index: " + std::to_wstring(contactIndex) + L"\n").c_str());
+ }
+}
+
+void ContactSelectionDialog::OnCancel(HWND hDlg)
+{
+ // Close dialog with cancel
+ EndDialog(hDlg, IDCANCEL);
+}
+
+void ContactSelectionDialog::SetupDialogSizing(HWND hDlg)
+{
+ // Set dialog size (approximately 400x500 pixels)
+ SetWindowPos(hDlg, NULL, 0, 0, 420, 520, SWP_NOMOVE | SWP_NOZORDER);
+}
+
+void ContactSelectionDialog::ApplyModernStyling(HWND hDlg)
+{
+ // Modern styling is optional for now - skip to avoid dependencies
+}
\ No newline at end of file
diff --git a/Samples/ChatAppShare/SampleChatAppWithShare/ContactSelectionDialog.h b/Samples/ChatAppShare/SampleChatAppWithShare/ContactSelectionDialog.h
new file mode 100644
index 0000000..fc06ffe
--- /dev/null
+++ b/Samples/ChatAppShare/SampleChatAppWithShare/ContactSelectionDialog.h
@@ -0,0 +1,45 @@
+#pragma once
+
+#include
+#include
+#include
+#include "ChatModels.h"
+
+// Contact Selection Dialog Manager
+class ContactSelectionDialog
+{
+public:
+ // Structure to hold the result of contact selection
+ struct SelectionResult
+ {
+ bool wasSelected;
+ int contactIndex;
+ std::wstring shareMessage;
+ std::wstring filePath;
+ std::wstring fileName;
+
+ SelectionResult() : wasSelected(false), contactIndex(-1) {}
+ };
+
+ // Show the contact selection dialog
+ static SelectionResult ShowContactSelectionDialog(HWND hParent, const std::wstring& filePath, const std::wstring& fileName);
+
+private:
+ // Dialog procedure for contact selection
+ static INT_PTR CALLBACK ContactSelectionDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
+
+ // Helper functions
+ static void InitializeContactList(HWND hListBox);
+ static void PopulateContactList(HWND hListBox);
+ static void UpdateContactListDisplay(HWND hListBox);
+ static void HandleContactSelection(HWND hDlg, int selectedIndex);
+ static void OnSelectContact(HWND hDlg);
+ static void OnCancel(HWND hDlg);
+ static void SetupDialogSizing(HWND hDlg);
+ static void ApplyModernStyling(HWND hDlg);
+
+ // Static data for dialog communication
+ static SelectionResult s_dialogResult;
+ static std::wstring s_currentFilePath;
+ static std::wstring s_currentFileName;
+};
\ No newline at end of file
diff --git a/Samples/ChatAppShare/SampleChatAppWithShare/FileManager.cpp b/Samples/ChatAppShare/SampleChatAppWithShare/FileManager.cpp
new file mode 100644
index 0000000..31ace5f
--- /dev/null
+++ b/Samples/ChatAppShare/SampleChatAppWithShare/FileManager.cpp
@@ -0,0 +1,154 @@
+#include "FileManager.h"
+#include "ChatModels.h"
+#include "ChatManager.h"
+#include "UIManager.h"
+#include
+#include
+
+#pragma comment(lib, "comdlg32.lib")
+
+// External declarations for UI window handles
+extern HWND hSharedFilesList;
+extern HWND hContactsList;
+
+void ShareFile()
+{
+ // Check if a contact is selected first
+ if (selectedContactIndex < 0) {
+ MessageBox(NULL, L"Please select a contact to share files with.", L"No Contact Selected", MB_OK | MB_ICONWARNING);
+ return;
+ }
+
+ // Get the main window handle (parent of the share file button)
+ HWND hMainWindow = GetParent(hSharedFilesList);
+ while (GetParent(hMainWindow))
+ {
+ hMainWindow = GetParent(hMainWindow);
+ }
+
+ OPENFILENAME ofn;
+ WCHAR szFile[260] = {0};
+
+ ZeroMemory(&ofn, sizeof(ofn));
+ ofn.lStructSize = sizeof(ofn);
+ ofn.hwndOwner = hMainWindow; // Set the main window as owner
+ ofn.lpstrFile = szFile;
+ ofn.nMaxFile = sizeof(szFile);
+ ofn.lpstrFilter = L"All Files\0*.*\0?? Text Files\0*.TXT\0?? Document Files\0*.DOC;*.DOCX\0??? Image Files\0*.BMP;*.JPG;*.PNG;*.GIF\0?? PDF Files\0*.PDF\0?? Excel Files\0*.XLS;*.XLSX\0";
+ ofn.nFilterIndex = 1;
+ ofn.lpstrFileTitle = NULL;
+ ofn.nMaxFileTitle = 0;
+ ofn.lpstrInitialDir = NULL;
+ ofn.lpstrTitle = L"Select File to Share";
+ ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_EXPLORER;
+
+ if (GetOpenFileName(&ofn))
+ {
+ // Extract file name from full path
+ std::wstring fullPath(szFile);
+ size_t lastSlash = fullPath.find_last_of(L"\\");
+ std::wstring fileName;
+ if (lastSlash != std::wstring::npos)
+ {
+ fileName = fullPath.substr(lastSlash + 1);
+ }
+ else
+ {
+ fileName = fullPath;
+ }
+
+ // Create shared file entry
+ SharedFile newFile;
+ newFile.fileName = fileName;
+ newFile.filePath = fullPath;
+ newFile.sharedBy = L"You";
+ GetSystemTime(&newFile.timeShared);
+
+ // Add file to the currently selected contact's shared files
+ if (selectedContactIndex >= 0 && selectedContactIndex < (int)contacts.size())
+ {
+ contacts[selectedContactIndex].sharedFiles.push_back(newFile);
+
+ // Add file sharing notification to chat
+ std::wstring fileShareMsg = L"?? Shared file: " + fileName;
+ AddMessageToChat(fileShareMsg, true);
+
+ // Update UI
+ AddSharedFileToChat(newFile, true);
+
+ // Update contacts list display to show the shared activity
+ InvalidateRect(hContactsList, NULL, TRUE);
+
+ // Show success message with current contact
+ std::wstring successMsg = L"File \"" + fileName + L"\" has been shared with " + contacts[selectedContactIndex].name + L"!";
+ MessageBox(hMainWindow, successMsg.c_str(), L"File Shared Successfully", MB_OK | MB_ICONINFORMATION);
+
+ // Simulate auto-reply from contact acknowledging the file
+ SetTimer(hMainWindow, 2, 2000, NULL);
+ }
+ }
+}
+
+void AddSharedFileToChat(const SharedFile& file, bool isOutgoing)
+{
+ Contact* contact = GetSelectedContact();
+ if (!contact) return;
+
+ std::wstring sharer = isOutgoing ? L"You" : contact->name;
+
+ // Format file sharing message with timestamp
+ SYSTEMTIME st;
+ GetLocalTime(&st);
+ WCHAR timeStr[50];
+ swprintf_s(timeStr, 50, L"[%02d:%02d] ", st.wHour, st.wMinute);
+
+ std::wstring shareMessage = sharer + L" shared: " + file.fileName + L" ??";
+ contact->messages.push_back(shareMessage);
+
+ // Update last message preview
+ contact->lastMessage = L"?? " + file.fileName;
+
+ // Add to shared files list
+ contact->sharedFiles.push_back(file);
+
+ // Refresh UI
+ LoadContactChat(selectedContactIndex);
+ UpdateSharedFilesList();
+}
+
+void OpenSharedFile(int fileIndex)
+{
+ Contact* contact = GetSelectedContact();
+ if (!contact || fileIndex < 0 || fileIndex >= (int)contact->sharedFiles.size()) {
+ return;
+ }
+
+ const SharedFile& file = contact->sharedFiles[fileIndex];
+
+ // Try to open the file with the default application
+ HINSTANCE result = ShellExecute(NULL, L"open", file.filePath.c_str(), NULL, NULL, SW_SHOWNORMAL);
+
+ if ((intptr_t)result <= 32) {
+ // If opening failed, show file location in explorer
+ std::wstring explorerCmd = L"/select,\"" + file.filePath + L"\"";
+ ShellExecute(NULL, L"open", L"explorer.exe", explorerCmd.c_str(), NULL, SW_SHOWNORMAL);
+ }
+}
+
+void UpdateSharedFilesList()
+{
+ if (!hSharedFilesList) return;
+
+ Contact* contact = GetSelectedContact();
+
+ // Clear the list
+ SendMessage(hSharedFilesList, LB_RESETCONTENT, 0, 0);
+
+ if (!contact) return;
+
+ // Add shared files to the list
+ for (const auto& file : contact->sharedFiles) {
+ std::wstring displayText = file.fileName + L" (shared by " + file.sharedBy + L")";
+ SendMessage(hSharedFilesList, LB_ADDSTRING, 0, (LPARAM)displayText.c_str());
+ }
+}
\ No newline at end of file
diff --git a/Samples/ChatAppShare/SampleChatAppWithShare/FileManager.h b/Samples/ChatAppShare/SampleChatAppWithShare/FileManager.h
new file mode 100644
index 0000000..e28e4db
--- /dev/null
+++ b/Samples/ChatAppShare/SampleChatAppWithShare/FileManager.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include
+#include
+#include "ChatModels.h"
+
+// File management functions
+void ShareFile();
+void AddSharedFileToChat(const SharedFile& file, bool isOutgoing);
+void UpdateSharedFilesList();
+void OpenSharedFile(int fileIndex);
+std::wstring GetFileExtensionIcon(const std::wstring& filePath);
+std::wstring FormatFileSize(DWORD fileSize);
\ No newline at end of file
diff --git a/Samples/ChatAppShare/SampleChatAppWithShare/ModernUI.cpp b/Samples/ChatAppShare/SampleChatAppWithShare/ModernUI.cpp
new file mode 100644
index 0000000..ca30eb2
--- /dev/null
+++ b/Samples/ChatAppShare/SampleChatAppWithShare/ModernUI.cpp
@@ -0,0 +1,128 @@
+#include "ModernUI.h"
+#include "UIConstants.h"
+#include
+
+#pragma comment(lib, "gdiplus.lib")
+
+// Modern UI Variables definitions
+HBRUSH hBrushBackground = nullptr;
+HBRUSH hBrushSurface = nullptr;
+HBRUSH hBrushPrimary = nullptr;
+HBRUSH hBrushHover = nullptr;
+HFONT hFontRegular = nullptr;
+HFONT hFontBold = nullptr;
+HFONT hFontTitle = nullptr;
+HPEN hPenBorder = nullptr;
+
+void InitializeModernUI()
+{
+ // Create brushes for modern color scheme
+ hBrushBackground = CreateSolidBrush(COLOR_APP_BACKGROUND);
+ hBrushSurface = CreateSolidBrush(COLOR_SURFACE);
+ hBrushPrimary = CreateSolidBrush(COLOR_PRIMARY);
+ hBrushHover = CreateSolidBrush(COLOR_HOVER);
+
+ // Create modern fonts
+ hFontRegular = CreateFont(16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
+ DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
+ CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Segoe UI");
+
+ hFontBold = CreateFont(16, 0, 0, 0, FW_SEMIBOLD, FALSE, FALSE, FALSE,
+ DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
+ CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Segoe UI");
+
+ hFontTitle = CreateFont(20, 0, 0, 0, FW_SEMIBOLD, FALSE, FALSE, FALSE,
+ DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
+ CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Segoe UI");
+
+ // Create pen for borders
+ hPenBorder = CreatePen(PS_SOLID, 1, COLOR_BORDER);
+
+ // Initialize GDI+
+ Gdiplus::GdiplusStartupInput gdiplusStartupInput;
+ ULONG_PTR gdiplusToken;
+ Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
+}
+
+void CleanupModernUI()
+{
+ // Cleanup GDI objects
+ if (hBrushBackground) DeleteObject(hBrushBackground);
+ if (hBrushSurface) DeleteObject(hBrushSurface);
+ if (hBrushPrimary) DeleteObject(hBrushPrimary);
+ if (hBrushHover) DeleteObject(hBrushHover);
+ if (hFontRegular) DeleteObject(hFontRegular);
+ if (hFontBold) DeleteObject(hFontBold);
+ if (hFontTitle) DeleteObject(hFontTitle);
+ if (hPenBorder) DeleteObject(hPenBorder);
+
+ // Shutdown GDI+
+ Gdiplus::GdiplusShutdown(NULL);
+}
+
+void DrawModernButton(HDC hdc, RECT rect, const std::wstring& text, bool isHovered, bool isPressed)
+{
+ // Create rounded rectangle region
+ HRGN hRgn = CreateRoundRectRgn(rect.left, rect.top, rect.right, rect.bottom, 8, 8);
+
+ // Fill background
+ HBRUSH hBrush = CreateSolidBrush(isPressed ? COLOR_PRIMARY_DARK :
+ isHovered ? COLOR_PRIMARY : COLOR_PRIMARY);
+ FillRgn(hdc, hRgn, hBrush);
+ DeleteObject(hBrush);
+
+ // Draw border with a brush instead of pen
+ HBRUSH borderBrush = CreateSolidBrush(COLOR_BORDER);
+ FrameRgn(hdc, hRgn, borderBrush, 1, 1);
+ DeleteObject(borderBrush);
+ DeleteObject(hRgn);
+
+ // Draw text
+ SetBkMode(hdc, TRANSPARENT);
+ SetTextColor(hdc, RGB(255, 255, 255));
+ SelectObject(hdc, hFontBold);
+
+ DrawText(hdc, text.c_str(), -1, &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
+}
+
+void DrawContactItem(HDC hdc, RECT rect, const Contact& contact, bool isSelected)
+{
+ // Fill background
+ HBRUSH bgBrush = CreateSolidBrush(isSelected ? COLOR_HOVER : COLOR_SURFACE);
+ FillRect(hdc, &rect, bgBrush);
+ DeleteObject(bgBrush);
+
+ // Draw avatar circle
+ int avatarX = rect.left + 12;
+ int avatarY = rect.top + (rect.bottom - rect.top - AVATAR_SIZE) / 2;
+
+ HBRUSH avatarBrush = CreateSolidBrush(COLOR_PRIMARY);
+ HPEN avatarPen = CreatePen(PS_SOLID, 2, contact.isOnline ? RGB(34, 197, 94) : RGB(156, 163, 175));
+
+ SelectObject(hdc, avatarBrush);
+ SelectObject(hdc, avatarPen);
+
+ Ellipse(hdc, avatarX, avatarY, avatarX + AVATAR_SIZE, avatarY + AVATAR_SIZE);
+
+ DeleteObject(avatarBrush);
+ DeleteObject(avatarPen);
+
+ // Draw contact name
+ SetBkMode(hdc, TRANSPARENT);
+ SetTextColor(hdc, COLOR_TEXT_PRIMARY);
+ SelectObject(hdc, hFontBold);
+
+ RECT nameRect = {avatarX + AVATAR_SIZE + 12, rect.top + 8, rect.right - 8, rect.top + 28};
+ DrawText(hdc, contact.name.c_str(), -1, &nameRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
+
+ // Draw status
+ SetTextColor(hdc, COLOR_TEXT_SECONDARY);
+ SelectObject(hdc, hFontRegular);
+
+ RECT statusRect = {avatarX + AVATAR_SIZE + 12, rect.top + 30, rect.right - 8, rect.top + 48};
+ DrawText(hdc, contact.status.c_str(), -1, &statusRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
+
+ // Draw last message preview
+ RECT msgRect = {avatarX + AVATAR_SIZE + 12, rect.top + 50, rect.right - 8, rect.bottom - 8};
+ DrawText(hdc, contact.lastMessage.c_str(), -1, &msgRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
+}
\ No newline at end of file
diff --git a/Samples/ChatAppShare/SampleChatAppWithShare/ModernUI.h b/Samples/ChatAppShare/SampleChatAppWithShare/ModernUI.h
new file mode 100644
index 0000000..3cb9ea7
--- /dev/null
+++ b/Samples/ChatAppShare/SampleChatAppWithShare/ModernUI.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include
+#include
+#include "ChatModels.h"
+
+// Modern UI Variables
+extern HBRUSH hBrushBackground;
+extern HBRUSH hBrushSurface;
+extern HBRUSH hBrushPrimary;
+extern HBRUSH hBrushHover;
+extern HFONT hFontRegular;
+extern HFONT hFontBold;
+extern HFONT hFontTitle;
+extern HPEN hPenBorder;
+
+// Modern UI Functions
+void InitializeModernUI();
+void CleanupModernUI();
+void DrawModernButton(HDC hdc, RECT rect, const std::wstring& text, bool isHovered, bool isPressed);
+void DrawContactItem(HDC hdc, RECT rect, const Contact& contact, bool isSelected);
\ No newline at end of file
diff --git a/Samples/ChatAppShare/SampleChatAppWithShare/PackageIdentity.cpp b/Samples/ChatAppShare/SampleChatAppWithShare/PackageIdentity.cpp
new file mode 100644
index 0000000..4f4ace9
--- /dev/null
+++ b/Samples/ChatAppShare/SampleChatAppWithShare/PackageIdentity.cpp
@@ -0,0 +1,463 @@
+#include "framework.h"
+#include "PackageIdentity.h"
+#include
+#include
+#include
+#include
+#include
+
+// Package Identity Variables
+bool g_isSparsePackageSupported = false;
+bool g_isRunningWithIdentity = false;
+bool g_packageIdentityInitialized = false;
+
+// Initialize package identity management
+bool InitializePackageIdentity()
+{
+ if (g_packageIdentityInitialized)
+ return true;
+
+ OutputDebugStringW(L"ChatApp: Initializing package identity management...\n");
+
+ // Check OS support for sparse packages
+ g_isSparsePackageSupported = IsSparsePackageSupported();
+
+ // Check if already running with identity
+ g_isRunningWithIdentity = IsRunningWithIdentity();
+
+ g_packageIdentityInitialized = true;
+
+ wchar_t statusLog[256];
+ swprintf_s(statusLog, L"ChatApp: Package Identity Status - Sparse supported: %s, Has identity: %s\n",
+ g_isSparsePackageSupported ? L"Yes" : L"No",
+ g_isRunningWithIdentity ? L"Yes" : L"No");
+ OutputDebugStringW(statusLog);
+
+ return true;
+}
+
+// Register package with external location (improved implementation)
+HRESULT RegisterPackageWithExternalLocation(const std::wstring& externalLocation, const std::wstring& packagePath)
+{
+ try
+ {
+ OutputDebugStringW(L"ChatApp: Attempting to register package with external location...\n");
+
+ wchar_t logBuffer[512];
+ swprintf_s(logBuffer, L"ChatApp: External location: %s\n", externalLocation.c_str());
+ OutputDebugStringW(logBuffer);
+ swprintf_s(logBuffer, L"ChatApp: Package path: %s\n", packagePath.c_str());
+ OutputDebugStringW(logBuffer);
+
+ // Check if the package file exists
+ DWORD fileAttributes = GetFileAttributesW(packagePath.c_str());
+ if (fileAttributes == INVALID_FILE_ATTRIBUTES)
+ {
+ OutputDebugStringW(L"ChatApp: Package file not found, trying PowerShell registration method.\n");
+ return RegisterPackageWithExternalLocationPowerShell(externalLocation, packagePath);
+ }
+
+ // Try PowerShell registration first as it's more reliable
+ HRESULT powershellResult = RegisterPackageWithExternalLocationPowerShell(externalLocation, packagePath);
+ if (SUCCEEDED(powershellResult))
+ {
+ OutputDebugStringW(L"ChatApp: Package registration via PowerShell succeeded.\n");
+ return powershellResult;
+ }
+
+ // If PowerShell failed, log the error
+ wchar_t errorLog[256];
+ swprintf_s(errorLog, L"ChatApp: PowerShell registration failed with HRESULT: 0x%08X\n", powershellResult);
+ OutputDebugStringW(errorLog);
+
+ // For now, return the PowerShell result since we don't have other registration methods implemented
+ return powershellResult;
+ }
+ catch (...)
+ {
+ OutputDebugStringW(L"ChatApp: Exception occurred during package registration\n");
+ return E_FAIL;
+ }
+}
+
+// Alternative implementation using PowerShell for package registration
+HRESULT RegisterPackageWithExternalLocationPowerShell(const std::wstring& externalLocation, const std::wstring& packagePath)
+{
+ try
+ {
+ OutputDebugStringW(L"ChatApp: Attempting PowerShell package registration...\n");
+
+ // Check if the package file exists
+ DWORD fileAttributes = GetFileAttributesW(packagePath.c_str());
+ if (fileAttributes == INVALID_FILE_ATTRIBUTES)
+ {
+ wchar_t errorLog[512];
+ swprintf_s(errorLog, L"ChatApp: Package file not found at: %s\n", packagePath.c_str());
+ OutputDebugStringW(errorLog);
+ return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+ }
+
+ // Build PowerShell command for MSIX package registration with external location
+ // Use Add-AppxPackage with -ExternalLocation parameter
+ std::wstring powershellCmd = L"powershell.exe -ExecutionPolicy Bypass -Command \"";
+ powershellCmd += L"try { ";
+ powershellCmd += L"Add-AppxPackage -Path '";
+ powershellCmd += packagePath;
+ powershellCmd += L"' -ExternalLocation '";
+ powershellCmd += externalLocation;
+ powershellCmd += L"' -ForceTargetApplicationShutdown; ";
+ powershellCmd += L"Write-Host 'Package registration successful'; ";
+ powershellCmd += L"exit 0; ";
+ powershellCmd += L"} catch { ";
+ powershellCmd += L"Write-Host ('Package registration failed: ' + $_.Exception.Message); ";
+ powershellCmd += L"exit 1; ";
+ powershellCmd += L"}\"";
+
+ wchar_t logBuffer[1024];
+ swprintf_s(logBuffer, L"ChatApp: PowerShell command: %s\n", powershellCmd.c_str());
+ OutputDebugStringW(logBuffer);
+
+ // Execute PowerShell command
+ STARTUPINFOW si = {};
+ PROCESS_INFORMATION pi = {};
+ si.cb = sizeof(si);
+ si.dwFlags = STARTF_USESHOWWINDOW;
+ si.wShowWindow = SW_HIDE;
+
+ BOOL success = CreateProcessW(
+ nullptr,
+ const_cast(powershellCmd.c_str()),
+ nullptr,
+ nullptr,
+ FALSE,
+ CREATE_NO_WINDOW,
+ nullptr,
+ nullptr,
+ &si,
+ &pi
+ );
+
+ if (success)
+ {
+ OutputDebugStringW(L"ChatApp: PowerShell process started, waiting for completion...\n");
+
+ // Wait for PowerShell to complete (with timeout)
+ DWORD waitResult = WaitForSingleObject(pi.hProcess, 60000); // Increased timeout for package registration
+
+ DWORD exitCode = 0;
+ if (waitResult == WAIT_OBJECT_0)
+ {
+ GetExitCodeProcess(pi.hProcess, &exitCode);
+ wchar_t exitLog[256];
+ swprintf_s(exitLog, L"ChatApp: PowerShell process completed with exit code: %d\n", exitCode);
+ OutputDebugStringW(exitLog);
+ }
+ else if (waitResult == WAIT_TIMEOUT)
+ {
+ OutputDebugStringW(L"ChatApp: PowerShell process timed out. Package registration may still be in progress.\n");
+ TerminateProcess(pi.hProcess, 1);
+ exitCode = 1;
+ }
+ else
+ {
+ DWORD waitError = GetLastError();
+ wchar_t waitLog[256];
+ swprintf_s(waitLog, L"ChatApp: Wait failed with error: %d\n", waitError);
+ OutputDebugStringW(waitLog);
+ exitCode = 1;
+ }
+
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+
+ return (exitCode == 0) ? S_OK : E_FAIL;
+ }
+ else
+ {
+ DWORD error = GetLastError();
+ wchar_t errorLog[256];
+ swprintf_s(errorLog, L"ChatApp: Failed to start PowerShell process. Error: %d\n", error);
+ OutputDebugStringW(errorLog);
+ return HRESULT_FROM_WIN32(error);
+ }
+ }
+ catch (...)
+ {
+ OutputDebugStringW(L"ChatApp: Exception occurred during PowerShell package registration\n");
+ return E_FAIL;
+ }
+}
+
+// Relaunch the current application
+void RelaunchApplication()
+{
+ OutputDebugStringW(L"ChatApp: Attempting to relaunch application...\n");
+
+ wchar_t exePath[MAX_PATH] = {0};
+ DWORD len = GetModuleFileNameW(nullptr, exePath, MAX_PATH);
+ if (len == 0 || len == MAX_PATH)
+ {
+ OutputDebugStringW(L"ChatApp: Failed to get executable path for relaunch.\n");
+ return;
+ }
+
+ // Log the executable path
+ wchar_t logBuffer[512];
+ swprintf_s(logBuffer, L"ChatApp: Relaunching: %s\n", exePath);
+ OutputDebugStringW(logBuffer);
+
+ // Add a small delay to allow package registration to complete
+ Sleep(2000);
+
+ // Use ShellExecuteW to relaunch the current executable
+ HINSTANCE result = ShellExecuteW(nullptr, L"open", exePath, nullptr, nullptr, SW_SHOWNORMAL);
+
+ // Fix: Use proper casting for x64 compatibility
+ INT_PTR resultValue = reinterpret_cast(result);
+ if (resultValue <= 32)
+ {
+ // Log the error
+ wchar_t errorLog[256];
+ swprintf_s(errorLog, L"ChatApp: Failed to relaunch application. ShellExecute error code: %lld\n",
+ static_cast(resultValue));
+ OutputDebugStringW(errorLog);
+
+ // Try alternative relaunch method using CreateProcess
+ OutputDebugStringW(L"ChatApp: Trying alternative relaunch method...\n");
+
+ STARTUPINFOW si = {};
+ PROCESS_INFORMATION pi = {};
+ si.cb = sizeof(si);
+ si.dwFlags = STARTF_USESHOWWINDOW;
+ si.wShowWindow = SW_SHOWNORMAL;
+
+ BOOL createResult = CreateProcessW(
+ exePath,
+ nullptr,
+ nullptr,
+ nullptr,
+ FALSE,
+ 0,
+ nullptr,
+ nullptr,
+ &si,
+ &pi
+ );
+
+ if (createResult)
+ {
+ OutputDebugStringW(L"ChatApp: Alternative relaunch method succeeded.\n");
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ }
+ else
+ {
+ DWORD createError = GetLastError();
+ wchar_t createErrorLog[256];
+ swprintf_s(createErrorLog, L"ChatApp: Alternative relaunch also failed. Error: %d\n", createError);
+ OutputDebugStringW(createErrorLog);
+ }
+ }
+ else
+ {
+ OutputDebugStringW(L"ChatApp: Application relaunch initiated successfully.\n");
+ }
+}
+
+// Checks if the OS version is Windows 10 2004 (build 19041) or later
+bool IsSparsePackageSupported()
+{
+ // Windows 10 2004 is version 10.0.19041
+ OSVERSIONINFOEXW osvi = {};
+ osvi.dwOSVersionInfoSize = sizeof(osvi);
+
+ // Get the actual version using RtlGetVersion (undocumented but reliable)
+ typedef LONG (WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOEXW);
+ HMODULE hMod = ::GetModuleHandleW(L"ntdll.dll");
+ if (hMod) {
+ RtlGetVersionPtr fxPtr = (RtlGetVersionPtr)::GetProcAddress(hMod, "RtlGetVersion");
+ if (fxPtr != nullptr) {
+ fxPtr((PRTL_OSVERSIONINFOEXW)&osvi);
+
+ // Log version information for debugging
+ wchar_t log[256];
+ swprintf_s(log, L"ChatApp: Current OS Version: %u.%u.%u\n",
+ osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber);
+ OutputDebugStringW(log);
+ }
+ }
+
+ // Compare with required version (Windows 10 2004 build 19041)
+ if (osvi.dwMajorVersion > 10 ||
+ (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion > 0) ||
+ (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0 && osvi.dwBuildNumber >= 19041))
+ {
+ OutputDebugStringW(L"ChatApp: Sparse package is supported on this OS.\n");
+ return true;
+ }
+
+ OutputDebugStringW(L"ChatApp: Sparse package is NOT supported on this OS.\n");
+ return false;
+}
+
+// Returns true if the app is running with package identity
+bool IsRunningWithIdentity()
+{
+ UINT32 length = 0;
+ LONG rc = GetCurrentPackageFullName(&length, nullptr);
+
+ if (rc == ERROR_INSUFFICIENT_BUFFER)
+ {
+ std::vector packageFullName(length);
+ rc = GetCurrentPackageFullName(&length, packageFullName.data());
+ if (rc == ERROR_SUCCESS)
+ {
+ OutputDebugStringW(L"ChatApp: Running with package identity.\n");
+ return true;
+ }
+ }
+
+ OutputDebugStringW(L"ChatApp: Not running with package identity.\n");
+ return false;
+}
+
+// Helper to get the directory of the current executable
+std::wstring GetExecutableDirectory()
+{
+ wchar_t exePath[MAX_PATH] = {0};
+ DWORD len = GetModuleFileNameW(nullptr, exePath, MAX_PATH);
+ if (len == 0 || len == MAX_PATH)
+ {
+ OutputDebugStringW(L"ChatApp: Failed to get executable path.\n");
+ return L"";
+ }
+
+ std::wstring path(exePath);
+ size_t pos = path.find_last_of(L"\\/");
+ if (pos != std::wstring::npos)
+ path = path.substr(0, pos);
+
+ return path;
+}
+
+// Initialize package identity-specific flows and features
+void InitializePackageIdentityFlow()
+{
+ OutputDebugStringW(L"ChatApp: Initializing package identity-specific flows...\n");
+
+ if (!g_isRunningWithIdentity) {
+ OutputDebugStringW(L"ChatApp: Not running with package identity - skipping identity-specific flows.\n");
+ return;
+ }
+
+ // TODO: Add package identity-specific initialization here:
+
+ // 1. Single Instance Management
+ // - Check for existing app instances
+ // - Register current instance
+ // - Handle instance redirection
+
+ // 2. Share Target Registration
+ // - Check for share target activation
+ // - Initialize share target handlers
+ // - Set up cross-process communication
+
+ // 3. Enhanced Security Features
+ // - Initialize secure file handling
+ // - Set up identity-based permissions
+ // - Enable enhanced data protection
+
+ // 4. App Model Integration
+ // - Register activation handlers
+ // - Set up background task support
+ // - Initialize notification system
+
+ OutputDebugStringW(L"ChatApp: Package identity flows initialized (placeholder - features to be implemented).\n");
+}
+
+// Helper to validate MSIX package existence and basic properties
+bool ValidateMsixPackage(const std::wstring& packagePath)
+{
+ OutputDebugStringW(L"ChatApp: Validating MSIX package...\n");
+
+ // Check if file exists
+ DWORD fileAttributes = GetFileAttributesW(packagePath.c_str());
+ if (fileAttributes == INVALID_FILE_ATTRIBUTES)
+ {
+ wchar_t errorLog[512];
+ swprintf_s(errorLog, L"ChatApp: MSIX package not found at: %s\n", packagePath.c_str());
+ OutputDebugStringW(errorLog);
+ return false;
+ }
+
+ // Check if it's a file (not a directory)
+ if (fileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ {
+ OutputDebugStringW(L"ChatApp: Package path points to a directory, not a file.\n");
+ return false;
+ }
+
+ // Check file extension
+ size_t dotPos = packagePath.find_last_of(L'.');
+ if (dotPos == std::wstring::npos)
+ {
+ OutputDebugStringW(L"ChatApp: Package file has no extension.\n");
+ return false;
+ }
+
+ std::wstring extension = packagePath.substr(dotPos);
+ std::transform(extension.begin(), extension.end(), extension.begin(), ::towlower);
+
+ if (extension != L".msix" && extension != L".appx")
+ {
+ wchar_t extLog[256];
+ swprintf_s(extLog, L"ChatApp: Package has unexpected extension: %s\n", extension.c_str());
+ OutputDebugStringW(extLog);
+ return false;
+ }
+
+ // Get file size
+ HANDLE hFile = CreateFileW(packagePath.c_str(), GENERIC_READ, FILE_SHARE_READ,
+ nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
+ if (hFile != INVALID_HANDLE_VALUE)
+ {
+ LARGE_INTEGER fileSize;
+ if (GetFileSizeEx(hFile, &fileSize))
+ {
+ wchar_t sizeLog[256];
+ swprintf_s(sizeLog, L"ChatApp: Package size: %lld bytes\n", fileSize.QuadPart);
+ OutputDebugStringW(sizeLog);
+ }
+ CloseHandle(hFile);
+ }
+
+ OutputDebugStringW(L"ChatApp: MSIX package validation passed.\n");
+ return true;
+}
+
+// Get current package identity status as a formatted string
+std::wstring GetPackageIdentityStatus()
+{
+ std::wstring status = L"ChatApp Package Identity Status:\n";
+ status += L"- Sparse package supported: " + std::wstring(g_isSparsePackageSupported ? L"Yes" : L"No") + L"\n";
+ status += L"- Running with identity: " + std::wstring(g_isRunningWithIdentity ? L"Yes" : L"No") + L"\n";
+ status += L"- Initialized: " + std::wstring(g_packageIdentityInitialized ? L"Yes" : L"No") + L"\n";
+
+ if (g_isRunningWithIdentity)
+ {
+ // Try to get package full name
+ UINT32 length = 0;
+ LONG rc = GetCurrentPackageFullName(&length, nullptr);
+ if (rc == ERROR_INSUFFICIENT_BUFFER && length > 0)
+ {
+ std::vector packageFullName(length);
+ rc = GetCurrentPackageFullName(&length, packageFullName.data());
+ if (rc == ERROR_SUCCESS)
+ {
+ status += L"- Package full name: " + std::wstring(packageFullName.data()) + L"\n";
+ }
+ }
+ }
+
+ return status;
+}
\ No newline at end of file
diff --git a/Samples/ChatAppShare/SampleChatAppWithShare/PackageIdentity.h b/Samples/ChatAppShare/SampleChatAppWithShare/PackageIdentity.h
new file mode 100644
index 0000000..e97fa85
--- /dev/null
+++ b/Samples/ChatAppShare/SampleChatAppWithShare/PackageIdentity.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include
+#include
+
+// Package Identity Variables
+extern bool g_isSparsePackageSupported;
+extern bool g_isRunningWithIdentity;
+extern bool g_packageIdentityInitialized;
+
+// Package Identity Management functions
+bool IsSparsePackageSupported();
+bool IsRunningWithIdentity();
+bool InitializePackageIdentity();
+void InitializePackageIdentityFlow();
+std::wstring GetExecutableDirectory();
+HRESULT RegisterPackageWithExternalLocation(const std::wstring& externalLocation, const std::wstring& packagePath);
+HRESULT RegisterPackageWithExternalLocationPowerShell(const std::wstring& externalLocation, const std::wstring& packagePath);
+void RelaunchApplication();
+
+// Helper functions
+bool ValidateMsixPackage(const std::wstring& packagePath);
+std::wstring GetPackageIdentityStatus();
\ No newline at end of file
diff --git a/Samples/ChatAppShare/SampleChatAppWithShare/Resource.h b/Samples/ChatAppShare/SampleChatAppWithShare/Resource.h
new file mode 100644
index 0000000..e41d7d3
--- /dev/null
+++ b/Samples/ChatAppShare/SampleChatAppWithShare/Resource.h
@@ -0,0 +1,48 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by SampleChatAppWithShare.rc
+
+#define IDS_APP_TITLE 103
+
+#define IDR_MAINFRAME 128
+#define IDD_SAMPLECHATAPPWITHSHARE_DIALOG 102
+#define IDD_ABOUTBOX 103
+#define IDD_CONTACT_SELECTION 104
+#define IDM_ABOUT 105
+#define IDM_EXIT 106
+#define IDI_SAMPLECHATAPPWITHSHARE 107
+#define IDI_SMALL 108
+#define IDC_SAMPLECHATAPPWITHSHARE 109
+#define IDC_MYICON 2
+
+// Chat Application Controls
+#define IDC_CONTACTS_LIST 1001
+#define IDC_CHAT_DISPLAY 1002
+#define IDC_MESSAGE_INPUT 1003
+#define IDC_SEND_BUTTON 1004
+#define IDC_CONTACT_NAME 1005
+#define IDC_SHARE_FILE_BUTTON 1006
+#define IDC_SHARED_FILES_LIST 1007
+
+// Contact Selection Dialog Controls
+#define IDC_CONTACT_SELECTION_LIST 1008
+#define IDC_SELECT_CONTACT_BUTTON 1009
+#define IDC_CANCEL_SELECTION_BUTTON 1010
+#define IDC_SHARE_MESSAGE_EDIT 1011
+#define IDC_DIALOG_TITLE 1012
+
+#ifndef IDC_STATIC
+#define IDC_STATIC -1
+#endif
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+
+#define _APS_NO_MFC 130
+#define _APS_NEXT_RESOURCE_VALUE 129
+#define _APS_NEXT_COMMAND_VALUE 32771
+#define _APS_NEXT_CONTROL_VALUE 1013
+#define _APS_NEXT_SYMED_VALUE 110
+#endif
+#endif
diff --git a/Samples/ChatAppShare/SampleChatAppWithShare/SampleChatAppWithShare.cpp b/Samples/ChatAppShare/SampleChatAppWithShare/SampleChatAppWithShare.cpp
new file mode 100644
index 0000000..b6a14e0
--- /dev/null
+++ b/Samples/ChatAppShare/SampleChatAppWithShare/SampleChatAppWithShare.cpp
@@ -0,0 +1,467 @@
+// SampleChatAppWithShare.cpp : Defines the entry point for the application.
+//
+
+#include "framework.h"
+#include "SampleChatAppWithShare.h"
+#include "UIConstants.h"
+#include "ChatModels.h"
+#include "ModernUI.h"
+#include "ChatManager.h"
+#include "FileManager.h"
+#include "UIManager.h"
+#include "PackageIdentity.h"
+#include "ShareTargetManager.h"
+#include "BackgroundService.h"
+#include "WindowProcs.h"
+#include
+#include
+#include
+#include
+#include
+
+#pragma comment(lib, "comctl32.lib")
+#pragma comment(lib, "shell32.lib")
+#pragma comment(lib, "uxtheme.lib")
+#pragma comment(lib, "ole32.lib")
+// Add WinRT libraries to fix linking error
+#pragma comment(lib, "windowsapp.lib")
+#pragma comment(lib, "runtimeobject.lib")
+
+using namespace winrt;
+using namespace Windows::Foundation;
+using namespace Windows::ApplicationModel;
+using namespace Windows::ApplicationModel::Activation;
+using namespace Windows::ApplicationModel::DataTransfer;
+using namespace Windows::ApplicationModel::DataTransfer::ShareTarget;
+
+// Global Variables:
+HINSTANCE hInst; // current instance
+WCHAR szTitle[MAX_LOADSTRING]; // The title bar text
+WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
+
+// Global flag to track if we're in share-only mode
+bool g_isShareOnlyMode = false;
+
+// Forward declarations of functions included in this code module:
+ATOM MyRegisterClass(HINSTANCE hInstance);
+BOOL InitInstance(HINSTANCE, int);
+LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
+INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
+
+int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
+ _In_opt_ HINSTANCE hPrevInstance,
+ _In_ LPWSTR lpCmdLine,
+ _In_ int nCmdShow)
+{
+ UNREFERENCED_PARAMETER(hPrevInstance);
+ UNREFERENCED_PARAMETER(lpCmdLine);
+
+ // Init package identity checks
+ InitializePackageIdentity();
+ HelloWorldService service;
+
+ // Initialize WinRT with proper error handling
+ try
+ {
+ winrt::init_apartment();
+ OutputDebugStringW(L"ChatApp: WinRT initialized successfully.\n");
+ }
+ catch (hresult_error const& ex)
+ {
+ std::wstring errorMsg = L"ChatApp: WinRT initialization failed: " + std::wstring(ex.message().c_str()) +
+ L" (HRESULT: 0x" + std::to_wstring(static_cast(ex.code())) + L")\n";
+ OutputDebugStringW(errorMsg.c_str());
+ }
+ catch (...)
+ {
+ OutputDebugStringW(L"ChatApp: WinRT initialization failed with unknown error.\n");
+ }
+
+ // Initialize Share Target Manager
+ ShareTargetManager::Initialize();
+
+ // Note: Don't process share target activation here - UI isn't created yet
+ // This will be handled after UI creation in WndProc WM_CREATE
+
+ // Check if this is a share target activation to determine if we need the main window
+ if (g_isRunningWithIdentity && ShareTargetManager::IsShareTargetActivation())
+ {
+ g_isShareOnlyMode = true;
+ OutputDebugStringW(L"ChatApp: Running in share-only mode - main window will not be created\n");
+ }
+
+ if (g_isSparsePackageSupported && !g_isRunningWithIdentity)
+ {
+ std::wstring executableDir = GetExecutableDirectory();
+ std::wstring packagePath = executableDir + L"\\Weixin_1.0.2.0_x86__v4k3sbdawh17a.msix";
+
+ // Validate the MSIX package before attempting registration
+ if (ValidateMsixPackage(packagePath))
+ {
+ HRESULT result = RegisterPackageWithExternalLocation(executableDir, packagePath);
+ if (SUCCEEDED(result))
+ {
+ OutputDebugStringW(L"ChatApp: Package registration succeeded. Relaunching...\n");
+ RelaunchApplication();
+ return 0; // Exit after relaunch
+ }
+ else
+ {
+ // Log the error but continue without package identity
+ wchar_t errorLog[256];
+ swprintf_s(errorLog, L"ChatApp: Failed to register package. HRESULT: 0x%08X. Continuing without package identity.\n", result);
+ OutputDebugStringW(errorLog);
+ }
+ }
+ else
+ {
+ OutputDebugStringW(L"ChatApp: MSIX package validation failed. Continuing without package identity.\n");
+ }
+ }
+ else if (g_isRunningWithIdentity)
+ {
+ HelloWorldService service;
+
+ if (!service.Start()) {
+ return 1;
+ }
+ // Process share target activation using the ShareTargetManager
+ ShareTargetManager::ProcessActivationArgs();
+ }
+ else
+ {
+ // Log the current status
+ std::wstring status = GetPackageIdentityStatus();
+ OutputDebugStringW(status.c_str());
+ }
+
+ // Initialize COM for shell operations
+ CoInitialize(NULL);
+
+ // Initialize common controls
+ INITCOMMONCONTROLSEX icex;
+ icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
+ icex.dwICC = ICC_LISTVIEW_CLASSES | ICC_STANDARD_CLASSES;
+ InitCommonControlsEx(&icex);
+
+ // Initialize global strings
+ LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
+ LoadStringW(hInstance, IDC_SAMPLECHATAPPWITHSHARE, szWindowClass, MAX_LOADSTRING);
+
+ if (!g_isShareOnlyMode)
+ {
+ // Only register window class if we're not in share-only mode
+ MyRegisterClass(hInstance);
+
+ // Initialize modern UI
+ InitializeModernUI();
+ }
+
+ // Initialize dummy contacts (needed for share target)
+ InitializeContacts();
+
+ if (g_isShareOnlyMode)
+ {
+ // In share-only mode, process the share target directly without creating a window
+ OutputDebugStringW(L"ChatApp: Processing share target in share-only mode\n");
+ ShareTargetManager::ProcessActivationArgs();
+ }
+ else
+ {
+ // Normal mode: create and show the main window
+ if (!InitInstance(hInstance, nCmdShow))
+ {
+ return FALSE;
+ }
+ }
+
+ HACCEL hAccelTable = nullptr;
+ if (!g_isShareOnlyMode)
+ {
+ hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_SAMPLECHATAPPWITHSHARE));
+ }
+
+ MSG msg;
+
+ // Main message loop:
+ while (GetMessage(&msg, nullptr, 0, 0))
+ {
+ if (!g_isShareOnlyMode && !TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ else if (g_isShareOnlyMode)
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+ if (service.IsRunning())
+ {
+ service.Stop();
+ }
+ CoUninitialize();
+ return (int) msg.wParam;
+}
+
+//
+// FUNCTION: MyRegisterClass()
+//
+// PURPOSE: Registers the window class.
+//
+ATOM MyRegisterClass(HINSTANCE hInstance)
+{
+ WNDCLASSEXW wcex;
+
+ wcex.cbSize = sizeof(WNDCLASSEX);
+
+ wcex.style = CS_HREDRAW | CS_VREDRAW;
+ wcex.lpfnWndProc = WndProc;
+ wcex.cbClsExtra = 0;
+ wcex.cbWndExtra = 0;
+ wcex.hInstance = hInstance;
+ wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_SAMPLECHATAPPWITHSHARE));
+ wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
+ wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
+ wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_SAMPLECHATAPPWITHSHARE);
+ wcex.lpszClassName = szWindowClass;
+ wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
+
+ return RegisterClassExW(&wcex);
+}
+
+//
+// FUNCTION: InitInstance(HINSTANCE, int)
+//
+// PURPOSE: Saves instance handle and creates main window
+//
+// COMMENTS:
+//
+// In this function, we save the instance handle in a global variable and
+// create and display the main program window.
+//
+BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
+{
+ hInst = hInstance; // Store instance handle in our global variable
+
+ HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT, 0, 1200, 700, nullptr, nullptr, hInstance, nullptr);
+
+ if (!hWnd)
+ {
+ return FALSE;
+ }
+
+ ShowWindow(hWnd, nCmdShow);
+ UpdateWindow(hWnd);
+
+ return TRUE;
+}
+
+//
+// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
+//
+// PURPOSE: Processes messages for the main window.
+//
+LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message)
+ {
+ case WM_CREATE:
+ CreateChatUI(hWnd);
+
+ // Process share target activation after UI is created
+ if (g_isRunningWithIdentity)
+ {
+ ShareTargetManager::ProcessActivationArgs();
+ }
+ break;
+
+ case WM_SIZE:
+ ResizeChatUI(hWnd);
+ break;
+
+ case WM_CTLCOLORSTATIC:
+ {
+ HDC hdcStatic = (HDC)wParam;
+ SetTextColor(hdcStatic, COLOR_TEXT_PRIMARY);
+ SetBkColor(hdcStatic, COLOR_APP_BACKGROUND);
+ return (INT_PTR)hBrushBackground;
+ }
+
+ case WM_CTLCOLOREDIT:
+ {
+ HDC hdcEdit = (HDC)wParam;
+ SetTextColor(hdcEdit, COLOR_TEXT_PRIMARY);
+ SetBkColor(hdcEdit, COLOR_SURFACE);
+ return (INT_PTR)hBrushSurface;
+ }
+
+ case WM_CTLCOLORLISTBOX:
+ {
+ HDC hdcList = (HDC)wParam;
+ SetTextColor(hdcList, COLOR_TEXT_PRIMARY);
+ SetBkColor(hdcList, COLOR_SURFACE);
+ return (INT_PTR)hBrushSurface;
+ }
+
+ case WM_PAINT:
+ {
+ PAINTSTRUCT ps;
+ HDC hdc = BeginPaint(hWnd, &ps);
+
+ // Fill the main window background with modern color
+ RECT rect;
+ GetClientRect(hWnd, &rect);
+ FillRect(hdc, &rect, hBrushBackground);
+
+ EndPaint(hWnd, &ps);
+ }
+ break;
+
+ case WM_COMMAND:
+ {
+ int wmId = LOWORD(wParam);
+ int wmEvent = HIWORD(wParam);
+
+ // Parse the menu selections:
+ switch (wmId)
+ {
+ case IDM_ABOUT:
+ DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
+ break;
+ case IDM_EXIT:
+ DestroyWindow(hWnd);
+ break;
+ case IDC_CONTACTS_LIST:
+ if (wmEvent == LBN_SELCHANGE) {
+ int selectedIndex = (int)::SendMessage(hContactsList, LB_GETCURSEL, 0, 0);
+ LoadContactChat(selectedIndex);
+ UpdateSharedFilesList();
+ }
+ break;
+ case IDC_SEND_BUTTON:
+ SendChatMessage();
+ break;
+ case IDC_SHARE_FILE_BUTTON:
+ ShareFile();
+ break;
+ case IDC_SHARED_FILES_LIST:
+ if (wmEvent == LBN_DBLCLK) {
+ int selectedFile = (int)::SendMessage(hSharedFilesList, LB_GETCURSEL, 0, 0);
+ OpenSharedFile(selectedFile);
+ }
+ break;
+ case IDC_MESSAGE_INPUT:
+ if (wmEvent == EN_CHANGE) {
+ // Enable/disable send button based on input with visual feedback
+ WCHAR buffer[1024];
+ GetWindowText(hMessageInput, buffer, 1024);
+ bool hasText = wcslen(buffer) > 0;
+ EnableWindow(hSendButton, hasText);
+ InvalidateRect(hSendButton, NULL, FALSE);
+ }
+ break;
+ case 2000: // Test WinRT Share Target Status
+ {
+ // Use ShareTargetManager to get status
+ std::wstring statusInfo = ShareTargetManager::GetShareTargetStatus();
+ MessageBoxW(hWnd, statusInfo.c_str(), L"WinRT Share Target Status", MB_OK | MB_ICONINFORMATION);
+ }
+ break;
+ default:
+ return DefWindowProc(hWnd, message, wParam, lParam);
+ }
+ }
+ break;
+
+ case WM_TIMER:
+ ProcessAutoReply(hWnd, (int)wParam);
+ break;
+
+ case WM_KEYDOWN:
+ {
+ if (GetFocus() == hMessageInput && wParam == VK_RETURN) {
+ if (!(GetKeyState(VK_SHIFT) & 0x8000)) {
+ // Enter without Shift sends the message
+ SendChatMessage();
+ return 0;
+ }
+ }
+ }
+ break;
+
+ case WM_DESTROY:
+ CleanupModernUI();
+ PostQuitMessage(0);
+ break;
+
+ default:
+ return DefWindowProc(hWnd, message, wParam, lParam);
+ }
+ return 0;
+}
+
+// Message handler for about box.
+INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ UNREFERENCED_PARAMETER(lParam);
+ switch (message)
+ {
+ case WM_INITDIALOG:
+ {
+ // Add WinRT and package identity information to the about dialog
+ std::wstring aboutText = L"Chat Application with WinRT Share Target Support\n\n";
+
+ // Test WinRT status
+ try
+ {
+ winrt::check_hresult(S_OK);
+ aboutText += L"? WinRT Status: ? Initialized and Working\n";
+
+ if (g_isRunningWithIdentity)
+ {
+ if (ShareTargetManager::IsShareTargetActivation())
+ {
+ aboutText += L"?? Share Target: ? Currently Activated via Windows Share Sheet\n";
+ }
+ else
+ {
+ aboutText += L"?? Share Target: ? Ready for Activation\n";
+ }
+ }
+ else
+ {
+ aboutText += L"?? Share Target: ? Package Identity Required\n";
+ }
+ }
+ catch (...)
+ {
+ aboutText += L"?? WinRT Status: ? Error or Not Available\n";
+ }
+
+ aboutText += L"?? Package Identity: " + std::wstring(g_isRunningWithIdentity ? L"? Available" : L"? Not Available") + L"\n";
+ aboutText += L"?? Sparse Package Support: " + std::wstring(g_isSparsePackageSupported ? L"? Supported" : L"? Not Supported") + L"\n\n";
+ aboutText += L"Current Features:\n";
+ aboutText += L"? WinRT Runtime Integration\n";
+ aboutText += L"? Windows Share Target Support\n";
+ aboutText += L"? Package Identity Management\n";
+ aboutText += L"? MSIX Package Registration\n";
+ aboutText += L"? Modern Chat UI\n\n";
+ aboutText += GetPackageIdentityStatus();
+
+ SetDlgItemTextW(hDlg, IDC_STATIC, aboutText.c_str());
+ return (INT_PTR)TRUE;
+ }
+
+ case WM_COMMAND:
+ if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
+ {
+ EndDialog(hDlg, LOWORD(wParam));
+ return (INT_PTR)TRUE;
+ }
+ break;
+ }
+ return (INT_PTR)FALSE;
+}
diff --git a/Samples/ChatAppShare/SampleChatAppWithShare/SampleChatAppWithShare.exe.manifest b/Samples/ChatAppShare/SampleChatAppWithShare/SampleChatAppWithShare.exe.manifest
new file mode 100644
index 0000000..7f9aa02
--- /dev/null
+++ b/Samples/ChatAppShare/SampleChatAppWithShare/SampleChatAppWithShare.exe.manifest
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/Samples/ChatAppShare/SampleChatAppWithShare/SampleChatAppWithShare.h b/Samples/ChatAppShare/SampleChatAppWithShare/SampleChatAppWithShare.h
new file mode 100644
index 0000000..d00d47e
--- /dev/null
+++ b/Samples/ChatAppShare/SampleChatAppWithShare/SampleChatAppWithShare.h
@@ -0,0 +1,3 @@
+#pragma once
+
+#include "resource.h"
diff --git a/Samples/ChatAppShare/SampleChatAppWithShare/SampleChatAppWithShare.ico b/Samples/ChatAppShare/SampleChatAppWithShare/SampleChatAppWithShare.ico
new file mode 100644
index 0000000..b3ec03b
Binary files /dev/null and b/Samples/ChatAppShare/SampleChatAppWithShare/SampleChatAppWithShare.ico differ
diff --git a/Samples/ChatAppShare/SampleChatAppWithShare/SampleChatAppWithShare.rc b/Samples/ChatAppShare/SampleChatAppWithShare/SampleChatAppWithShare.rc
new file mode 100644
index 0000000..966faca
Binary files /dev/null and b/Samples/ChatAppShare/SampleChatAppWithShare/SampleChatAppWithShare.rc differ
diff --git a/Samples/ChatAppShare/SampleChatAppWithShare/SampleChatAppWithShare.vcxproj b/Samples/ChatAppShare/SampleChatAppWithShare/SampleChatAppWithShare.vcxproj
new file mode 100644
index 0000000..3adf298
--- /dev/null
+++ b/Samples/ChatAppShare/SampleChatAppWithShare/SampleChatAppWithShare.vcxproj
@@ -0,0 +1,237 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+ Debug
+ ARM64
+
+
+ Release
+ ARM64
+
+
+
+ 17.0
+ Win32Proj
+ {dd6ec845-790a-4bd4-b638-af0964704337}
+ SampleChatAppWithShare
+ 10.0
+
+
+
+ Application
+ true
+ v143
+ Unicode
+
+
+ Application
+ false
+ v143
+ true
+ Unicode
+
+
+ Application
+ true
+ v143
+ Unicode
+
+
+ Application
+ false
+ v143
+ true
+ Unicode
+
+
+ Application
+ true
+ v143
+ Unicode
+
+
+ Application
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)
+ true
+ stdcpp17
+
+
+ Windows
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)
+ true
+ stdcpp17
+
+
+ Windows
+ true
+
+
+
+
+ Level3
+ true
+ _DEBUG;_WINDOWS;%(PreprocessorDefinitions)
+ true
+ stdcpp17
+
+
+ Windows
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_WINDOWS;%(PreprocessorDefinitions)
+ true
+ stdcpp17
+
+
+ Windows
+ true
+
+
+
+
+ Level3
+ true
+ _DEBUG;_WINDOWS;%(PreprocessorDefinitions)
+ true
+ stdcpp17
+
+
+ Windows
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_WINDOWS;%(PreprocessorDefinitions)
+ true
+ stdcpp17
+
+
+ Windows
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Samples/ChatAppShare/SampleChatAppWithShare/SampleChatAppWithShare.vcxproj.filters b/Samples/ChatAppShare/SampleChatAppWithShare/SampleChatAppWithShare.vcxproj.filters
new file mode 100644
index 0000000..781bdd3
--- /dev/null
+++ b/Samples/ChatAppShare/SampleChatAppWithShare/SampleChatAppWithShare.vcxproj.filters
@@ -0,0 +1,125 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Resource Files
+
+
+
+
+ Resource Files
+
+
+ Resource Files
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Samples/ChatAppShare/SampleChatAppWithShare/ShareTargetManager.cpp b/Samples/ChatAppShare/SampleChatAppWithShare/ShareTargetManager.cpp
new file mode 100644
index 0000000..82131dc
--- /dev/null
+++ b/Samples/ChatAppShare/SampleChatAppWithShare/ShareTargetManager.cpp
@@ -0,0 +1,425 @@
+#include "ShareTargetManager.h"
+#include "PackageIdentity.h"
+#include "ContactSelectionDialog.h"
+#include "ChatManager.h"
+#include "ChatModels.h"
+#include "FileManager.h"
+#include "framework.h"
+#include
+
+// Static member initialization
+bool ShareTargetManager::s_initialized = false;
+bool ShareTargetManager::s_shareTargetSupported = false;
+
+void ShareTargetManager::Initialize()
+{
+ if (s_initialized)
+ return;
+
+ LogShareInfo(L"Initializing Share Target Manager...");
+
+ try
+ {
+ // Check if WinRT and package identity are available
+ if (g_isRunningWithIdentity)
+ {
+ s_shareTargetSupported = true;
+ LogShareInfo(L"Share Target support available with package identity.");
+ }
+ else
+ {
+ s_shareTargetSupported = false;
+ LogShareInfo(L"Share Target requires package identity (not available).");
+ }
+ }
+ catch (winrt::hresult_error const& ex)
+ {
+ std::wstring error = L"Share Target initialization error: " + std::wstring(ex.message().c_str());
+ LogShareError(error);
+ s_shareTargetSupported = false;
+ }
+ catch (...)
+ {
+ LogShareError(L"Unknown error during Share Target initialization.");
+ s_shareTargetSupported = false;
+ }
+
+ s_initialized = true;
+ LogShareInfo(L"Share Target Manager initialized successfully.");
+}
+
+bool ShareTargetManager::IsShareTargetAvailable()
+{
+ if (!s_initialized)
+ Initialize();
+
+ return s_shareTargetSupported && g_isRunningWithIdentity;
+}
+
+bool ShareTargetManager::IsShareTargetActivation()
+{
+ if (!IsShareTargetAvailable())
+ return false;
+
+ try
+ {
+ auto activationArgs = winrt::Windows::ApplicationModel::AppInstance::GetActivatedEventArgs();
+ return activationArgs && activationArgs.Kind() == winrt::Windows::ApplicationModel::Activation::ActivationKind::ShareTarget;
+ }
+ catch (...)
+ {
+ LogShareError(L"Error checking share target activation.");
+ return false;
+ }
+}
+
+bool ShareTargetManager::ProcessActivationArgs()
+{
+ if (!IsShareTargetAvailable())
+ return false;
+
+ // Add a static flag to prevent multiple processing
+ static bool s_alreadyProcessed = false;
+ if (s_alreadyProcessed) {
+ LogShareInfo(L"Share target already processed - skipping duplicate call");
+ return false;
+ }
+
+ try
+ {
+ auto activationArgs = winrt::Windows::ApplicationModel::AppInstance::GetActivatedEventArgs();
+ if (activationArgs && activationArgs.Kind() == winrt::Windows::ApplicationModel::Activation::ActivationKind::ShareTarget)
+ {
+ LogShareInfo(L"? Share Target activation detected!");
+ s_alreadyProcessed = true; // Mark as processed
+
+ // Ensure contacts are initialized (critical for share target scenarios)
+ if (contacts.empty())
+ {
+ LogShareInfo(L"Initializing contacts for share target scenario...");
+ InitializeContacts();
+ }
+
+ // Process the share target directly here
+ auto shareArgs = activationArgs.as();
+ auto shareOperation = shareArgs.ShareOperation();
+ auto data = shareOperation.Data();
+
+ // Extract shared content information for the contact selection dialog
+ std::wstring sharedContentSummary = L"Shared Content";
+ std::wstring sharedFiles;
+ bool hasFiles = false;
+
+ // Collect information about what's being shared
+ std::vector sharedItems;
+
+ // Check for different data formats
+ if (data.Contains(winrt::Windows::ApplicationModel::DataTransfer::StandardDataFormats::Text()))
+ {
+ try
+ {
+ auto textAsync = data.GetTextAsync();
+ auto text = textAsync.get();
+ sharedItems.push_back(L"Text: " + std::wstring(text.c_str()));
+ LogShareInfo(L"Received shared text.");
+ }
+ catch (...)
+ {
+ sharedItems.push_back(L"Text: [Error retrieving text]");
+ LogShareError(L"Error retrieving shared text.");
+ }
+ }
+
+ if (data.Contains(winrt::Windows::ApplicationModel::DataTransfer::StandardDataFormats::WebLink()))
+ {
+ try
+ {
+ auto webLinkAsync = data.GetWebLinkAsync();
+ auto webLink = webLinkAsync.get();
+ sharedItems.push_back(L"Web Link: " + std::wstring(webLink.ToString().c_str()));
+ LogShareInfo(L"Received shared web link.");
+ }
+ catch (...)
+ {
+ sharedItems.push_back(L"Web Link: [Error retrieving web link]");
+ LogShareError(L"Error retrieving shared web link.");
+ }
+ }
+
+ if (data.Contains(winrt::Windows::ApplicationModel::DataTransfer::StandardDataFormats::Bitmap()))
+ {
+ try
+ {
+ auto bitmapAsync = data.GetBitmapAsync();
+ auto bitmapRef = bitmapAsync.get();
+ sharedItems.push_back(L"Image/Bitmap content");
+ LogShareInfo(L"Received shared bitmap.");
+ }
+ catch (...)
+ {
+ sharedItems.push_back(L"Image: [Error retrieving image]");
+ LogShareError(L"Error retrieving shared bitmap.");
+ }
+ }
+
+ if (data.Contains(winrt::Windows::ApplicationModel::DataTransfer::StandardDataFormats::StorageItems()))
+ {
+ try
+ {
+ auto storageItemsAsync = data.GetStorageItemsAsync();
+ auto storageItems = storageItemsAsync.get();
+
+ hasFiles = true;
+ std::wstring filesInfo = std::to_wstring(storageItems.Size()) + L" file(s)";
+
+ if (storageItems.Size() == 1)
+ {
+ auto item = storageItems.GetAt(0);
+ sharedFiles = item.Name().c_str();
+ sharedContentSummary = sharedFiles;
+ }
+ else if (storageItems.Size() > 1)
+ {
+ sharedFiles = L"Multiple Files (" + std::to_wstring(storageItems.Size()) + L")";
+ sharedContentSummary = sharedFiles;
+ }
+
+ for (uint32_t i = 0; i < storageItems.Size(); i++)
+ {
+ auto item = storageItems.GetAt(i);
+ filesInfo += L"\n - " + std::wstring(item.Name().c_str());
+ }
+
+ sharedItems.push_back(filesInfo);
+ LogShareInfo(L"Received shared files.");
+ }
+ catch (...)
+ {
+ sharedItems.push_back(L"Files: [Error retrieving files]");
+ LogShareError(L"Error retrieving shared files.");
+ }
+ }
+
+ // If no specific content type found, use generic description
+ if (sharedItems.empty())
+ {
+ sharedContentSummary = L"Shared Content";
+ sharedItems.push_back(L"Unknown content type");
+ }
+
+ // Get the main window handle for dialog parent
+ HWND hMainWindow = GetActiveWindow();
+ if (!hMainWindow)
+ {
+ hMainWindow = GetForegroundWindow();
+ }
+ if (!hMainWindow)
+ {
+ // Try to find the main chat application window
+ hMainWindow = FindWindow(NULL, L"Chat Application");
+ }
+
+ // Log the number of contacts available for debugging
+ LogShareInfo(L"Available contacts: " + std::to_wstring(contacts.size()));
+
+ // Show contact selection dialog for the shared content
+ ContactSelectionDialog::SelectionResult result =
+ ContactSelectionDialog::ShowContactSelectionDialog(hMainWindow, L"", sharedContentSummary);
+
+ if (result.wasSelected)
+ {
+ // User selected a contact - add the shared content to that contact's chat
+ if (result.contactIndex >= 0 && result.contactIndex < (int)contacts.size())
+ {
+ int previousSelection = selectedContactIndex;
+ selectedContactIndex = result.contactIndex;
+
+ LogShareInfo(L"Setting selectedContactIndex to: " + std::to_wstring(result.contactIndex));
+ LogShareInfo(L"Selected contact name: " + contacts[result.contactIndex].name);
+
+ // Add messages directly to the selected contact instead of relying on selectedContactIndex
+ Contact& selectedContact = contacts[result.contactIndex];
+
+ // Add the custom share message if provided
+ if (!result.shareMessage.empty())
+ {
+ std::wstring formattedShareMessage = L"You: " + result.shareMessage + L" ??";
+ selectedContact.messages.push_back(formattedShareMessage);
+ LogShareInfo(L"Added share message: " + result.shareMessage);
+ }
+
+ // Add shared content messages to the chat
+ for (const auto& item : sharedItems)
+ {
+ std::wstring shareMsg = L"?? Received via Share: " + item;
+ std::wstring formattedMessage = selectedContact.name + L": " + shareMsg;
+ selectedContact.messages.push_back(formattedMessage);
+ LogShareInfo(L"Added shared content message: " + shareMsg);
+ }
+
+ // Update the last message preview for this contact
+ if (!sharedItems.empty())
+ {
+ std::wstring lastMsg = L"?? Received via Share: " + sharedItems[0];
+ selectedContact.lastMessage = lastMsg.length() > 50 ? lastMsg.substr(0, 47) + L"..." : lastMsg;
+ }
+
+ // If files were shared, add them to the contact's shared files list
+ if (hasFiles && data.Contains(winrt::Windows::ApplicationModel::DataTransfer::StandardDataFormats::StorageItems()))
+ {
+ try
+ {
+ auto storageItemsAsync = data.GetStorageItemsAsync();
+ auto storageItems = storageItemsAsync.get();
+
+ for (uint32_t i = 0; i < storageItems.Size(); i++)
+ {
+ auto item = storageItems.GetAt(i);
+
+ // Create shared file entry
+ SharedFile newFile;
+ newFile.fileName = item.Name().c_str();
+ newFile.filePath = item.Path().c_str(); // Get full path if available
+ newFile.sharedBy = L"External Share";
+ GetSystemTime(&newFile.timeShared);
+
+ selectedContact.sharedFiles.push_back(newFile);
+ LogShareInfo(L"Added shared file: " + newFile.fileName);
+ }
+ }
+ catch (...)
+ {
+ LogShareError(L"Error adding shared files to contact.");
+ }
+ }
+
+ // Show success message and exit the application
+ std::wstring successMsg = L"Content has been shared successfully with " + contacts[result.contactIndex].name + L"!\n\nThe application will now close.";
+ MessageBoxW(hMainWindow, successMsg.c_str(), L"Sharing Complete", MB_OK | MB_ICONINFORMATION);
+
+ LogShareInfo(L"Share target content added to contact: " + contacts[result.contactIndex].name);
+ LogShareInfo(L"Selected contact index set to: " + std::to_wstring(result.contactIndex));
+ LogShareInfo(L"Contact now has " + std::to_wstring(selectedContact.messages.size()) + L" messages");
+
+ // Report completion to Windows
+ shareOperation.ReportCompleted();
+
+ LogShareInfo(L"Share target processing completed successfully. Exiting application.");
+
+ // Exit the application after successful sharing
+ PostQuitMessage(0);
+ return true;
+ }
+ }
+ else
+ {
+ // User cancelled - show a brief message and exit
+ MessageBoxW(hMainWindow, L"Share operation was cancelled.\n\nThe application will now close.", L"Share Cancelled", MB_OK | MB_ICONINFORMATION);
+ LogShareInfo(L"Share target operation cancelled by user.");
+
+ // Report completion to Windows
+ shareOperation.ReportCompleted();
+
+ LogShareInfo(L"Share target processing cancelled. Exiting application.");
+
+ // Exit the application after cancellation
+ PostQuitMessage(0);
+ return true;
+ }
+
+ // Report completion to Windows
+ shareOperation.ReportCompleted();
+
+ LogShareInfo(L"Share target processing completed successfully.");
+ return true;
+ }
+ else
+ {
+ LogShareInfo(L"Running with package identity but not as share target.");
+ return false;
+ }
+ }
+ catch (winrt::hresult_error const& ex)
+ {
+ s_alreadyProcessed = true; // Mark as processed even on error to prevent retries
+ std::wstring error = L"Error checking activation args: " + std::wstring(ex.message().c_str()) +
+ L" (HRESULT: 0x" + std::to_wstring(static_cast(ex.code())) + L")";
+ LogShareError(error);
+ MessageBoxW(nullptr, L"Error processing shared content", L"Share Target Error", MB_OK | MB_ICONERROR);
+ return false;
+ }
+ catch (...)
+ {
+ s_alreadyProcessed = true; // Mark as processed even on error to prevent retries
+ LogShareError(L"Unknown error checking activation arguments.");
+ MessageBoxW(nullptr, L"Unknown error processing shared content", L"Share Target Error", MB_OK | MB_ICONERROR);
+ return false;
+ }
+}
+
+std::wstring ShareTargetManager::GetShareTargetStatus()
+{
+ if (!s_initialized)
+ Initialize();
+
+ std::wstring status = L"WinRT Share Target Integration Status:\n\n";
+
+ try
+ {
+ winrt::check_hresult(S_OK);
+ status += L"?? WinRT Runtime: ? Available and Working\n";
+ status += L"?? Package Identity: " + std::wstring(g_isRunningWithIdentity ? L"? Available" : L"? Not Available") + L"\n";
+ status += L"?? Sparse Package Support: " + std::wstring(g_isSparsePackageSupported ? L"? Supported" : L"? Not Supported") + L"\n\n";
+
+ // Test activation
+ if (g_isRunningWithIdentity)
+ {
+ try
+ {
+ if (IsShareTargetActivation())
+ {
+ status += L"?? Share Target: ? Currently Activated\n";
+ }
+ else
+ {
+ status += L"?? Share Target: ?? Not Currently Activated\n";
+ }
+ }
+ catch (...)
+ {
+ status += L"?? Share Target: ? Error Checking Activation\n";
+ }
+ }
+ else
+ {
+ status += L"?? Share Target: ? Package Identity Required\n";
+ }
+
+ status += GetPackageIdentityStatus();
+ status += L"\n\n?? WinRT Share Target integration is complete and ready!";
+ }
+ catch (winrt::hresult_error const& ex)
+ {
+ status += L"?? WinRT Runtime: ? Error\n";
+ status += L"Error: " + std::wstring(ex.message().c_str()) + L"\n";
+ status += L"HRESULT: 0x" + std::to_wstring(static_cast(ex.code())) + L"\n";
+ }
+ catch (...)
+ {
+ status += L"?? WinRT Runtime: ? Unknown Error\n";
+ }
+
+ return status;
+}
+
+void ShareTargetManager::LogShareInfo(const std::wstring& message)
+{
+ std::wstring logMessage = L"ChatApp: " + message + L"\n";
+ OutputDebugStringW(logMessage.c_str());
+}
+
+void ShareTargetManager::LogShareError(const std::wstring& error)
+{
+ std::wstring logMessage = L"ChatApp: ShareTarget ERROR - " + error + L"\n";
+ OutputDebugStringW(logMessage.c_str());
+}
\ No newline at end of file
diff --git a/Samples/ChatAppShare/SampleChatAppWithShare/ShareTargetManager.h b/Samples/ChatAppShare/SampleChatAppWithShare/ShareTargetManager.h
new file mode 100644
index 0000000..2281410
--- /dev/null
+++ b/Samples/ChatAppShare/SampleChatAppWithShare/ShareTargetManager.h
@@ -0,0 +1,33 @@
+#pragma once
+
+#include
+#include
+
+// Simple Share Target Manager with minimal dependencies
+class ShareTargetManager
+{
+public:
+ // Initialize the share target manager
+ static void Initialize();
+
+ // Check if the current activation is a share target
+ static bool IsShareTargetActivation();
+
+ // Check activation arguments and process if it's a share target
+ static bool ProcessActivationArgs();
+
+ // Get share target status information
+ static std::wstring GetShareTargetStatus();
+
+ // Check if share target is available (requires package identity)
+ static bool IsShareTargetAvailable();
+
+private:
+ // Logging helpers
+ static void LogShareInfo(const std::wstring& message);
+ static void LogShareError(const std::wstring& error);
+
+private:
+ static bool s_initialized;
+ static bool s_shareTargetSupported;
+};
\ No newline at end of file
diff --git a/Samples/ChatAppShare/SampleChatAppWithShare/UIConstants.h b/Samples/ChatAppShare/SampleChatAppWithShare/UIConstants.h
new file mode 100644
index 0000000..ff28af5
--- /dev/null
+++ b/Samples/ChatAppShare/SampleChatAppWithShare/UIConstants.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include
+
+// Include resource.h for resource constants
+#include "resource.h"
+
+// Modern UI Color Scheme
+#define COLOR_PRIMARY RGB(64, 128, 255) // Modern blue
+#define COLOR_PRIMARY_DARK RGB(45, 100, 220) // Darker blue for hover
+#define COLOR_APP_BACKGROUND RGB(248, 249, 250) // Light gray background
+#define COLOR_SURFACE RGB(255, 255, 255) // White surface
+#define COLOR_TEXT_PRIMARY RGB(33, 37, 41) // Dark text
+#define COLOR_TEXT_SECONDARY RGB(108, 117, 125) // Gray text
+#define COLOR_BORDER RGB(222, 226, 230) // Light border
+#define COLOR_HOVER RGB(248, 249, 250) // Hover background
+#define COLOR_CHAT_BUBBLE_OUT RGB(0, 123, 255) // Outgoing message
+#define COLOR_CHAT_BUBBLE_IN RGB(233, 236, 239) // Incoming message
+
+// UI Constants
+#define MAX_LOADSTRING 100
+#define CONTACT_ITEM_HEIGHT 72
+#define AVATAR_SIZE 40
\ No newline at end of file
diff --git a/Samples/ChatAppShare/SampleChatAppWithShare/UIManager.cpp b/Samples/ChatAppShare/SampleChatAppWithShare/UIManager.cpp
new file mode 100644
index 0000000..bdd4808
--- /dev/null
+++ b/Samples/ChatAppShare/SampleChatAppWithShare/UIManager.cpp
@@ -0,0 +1,142 @@
+#include "UIManager.h"
+#include "UIConstants.h"
+#include "ModernUI.h"
+#include "ChatModels.h"
+#include "FileManager.h"
+#include "WindowProcs.h"
+#include
+
+#pragma comment(lib, "comctl32.lib")
+
+// External declaration - hInst is defined in the main cpp file
+extern HINSTANCE hInst;
+
+// UI Window handles definitions
+HWND hContactsList = nullptr;
+HWND hChatDisplay = nullptr;
+HWND hMessageInput = nullptr;
+HWND hSendButton = nullptr;
+HWND hContactName = nullptr;
+HWND hShareFileButton = nullptr;
+HWND hSharedFilesList = nullptr;
+
+void CreateChatUI(HWND hWnd)
+{
+ RECT rect;
+ GetClientRect(hWnd, &rect);
+
+ int width = rect.right - rect.left;
+ int height = rect.bottom - rect.top;
+
+ // Set window background to modern color
+ SetClassLongPtr(hWnd, GCLP_HBRBACKGROUND, (LONG_PTR)hBrushBackground);
+
+ // Create contacts list (left panel) with modern styling
+ hContactsList = CreateWindowEx(
+ WS_EX_CLIENTEDGE,
+ L"LISTBOX", NULL,
+ WS_CHILD | WS_VISIBLE | WS_VSCROLL | LBS_NOTIFY | LBS_OWNERDRAWFIXED,
+ 20, 20, 280, height - 40,
+ hWnd, (HMENU)IDC_CONTACTS_LIST, hInst, NULL);
+
+ // Set custom item height for contact list
+ ::SendMessage(hContactsList, LB_SETITEMHEIGHT, 0, CONTACT_ITEM_HEIGHT);
+
+ // Create contact name label with modern styling
+ hContactName = CreateWindow(L"STATIC", L"Select a contact to start chatting",
+ WS_CHILD | WS_VISIBLE | SS_LEFT,
+ 320, 20, 300, 30,
+ hWnd, (HMENU)IDC_CONTACT_NAME, hInst, NULL);
+
+ // Create chat display area with modern styling
+ hChatDisplay = CreateWindowEx(
+ WS_EX_CLIENTEDGE,
+ L"EDIT", NULL,
+ WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_MULTILINE | ES_READONLY | ES_AUTOVSCROLL,
+ 320, 60, width - 600, height - 280,
+ hWnd, (HMENU)IDC_CHAT_DISPLAY, hInst, NULL);
+
+ // Create shared files section header
+ CreateWindow(L"STATIC", L"Shared Files",
+ WS_CHILD | WS_VISIBLE | SS_LEFT,
+ width - 260, 20, 120, 30,
+ hWnd, NULL, hInst, NULL);
+
+ // Create shared files list with modern styling
+ hSharedFilesList = CreateWindowEx(
+ WS_EX_CLIENTEDGE,
+ L"LISTBOX", NULL,
+ WS_CHILD | WS_VISIBLE | WS_VSCROLL | LBS_NOTIFY,
+ width - 260, 60, 240, height - 280,
+ hWnd, (HMENU)IDC_SHARED_FILES_LIST, hInst, NULL);
+
+ // Create message input with placeholder styling
+ hMessageInput = CreateWindowEx(
+ WS_EX_CLIENTEDGE,
+ L"EDIT", NULL,
+ WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_AUTOVSCROLL,
+ 320, height - 200, width - 600, 60,
+ hWnd, (HMENU)IDC_MESSAGE_INPUT, hInst, NULL);
+
+ // Create modern styled buttons
+ hSendButton = CreateWindow(L"BUTTON", L"Send",
+ WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_OWNERDRAW,
+ 320, height - 130, 100, 45,
+ hWnd, (HMENU)IDC_SEND_BUTTON, hInst, NULL);
+
+ hShareFileButton = CreateWindow(L"BUTTON", L"Share File",
+ WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_OWNERDRAW,
+ 440, height - 130, 120, 45,
+ hWnd, (HMENU)IDC_SHARE_FILE_BUTTON, hInst, NULL);
+
+ // Populate contacts list
+ for (const auto& contact : contacts) {
+ ::SendMessage(hContactsList, LB_ADDSTRING, 0, (LPARAM)contact.name.c_str());
+ }
+
+ // Apply modern fonts to controls
+ ::SendMessage(hContactName, WM_SETFONT, (WPARAM)hFontTitle, TRUE);
+ ::SendMessage(hChatDisplay, WM_SETFONT, (WPARAM)hFontRegular, TRUE);
+ ::SendMessage(hMessageInput, WM_SETFONT, (WPARAM)hFontRegular, TRUE);
+ ::SendMessage(hSharedFilesList, WM_SETFONT, (WPARAM)hFontRegular, TRUE);
+
+ // Subclass buttons for custom drawing
+ SetupCustomWindowProcs();
+
+ // Set modern background colors
+ SetupWindowColors();
+}
+
+void ResizeChatUI(HWND hWnd)
+{
+ RECT rect;
+ GetClientRect(hWnd, &rect);
+ int width = rect.right - rect.left;
+ int height = rect.bottom - rect.top;
+
+ if (hContactsList) {
+ SetWindowPos(hContactsList, NULL, 20, 20, 280, height - 40, SWP_NOZORDER);
+ }
+ if (hChatDisplay) {
+ SetWindowPos(hChatDisplay, NULL, 320, 60, width - 600, height - 280, SWP_NOZORDER);
+ }
+ if (hSharedFilesList) {
+ SetWindowPos(hSharedFilesList, NULL, width - 260, 60, 240, height - 280, SWP_NOZORDER);
+ }
+ if (hMessageInput) {
+ SetWindowPos(hMessageInput, NULL, 320, height - 200, width - 600, 60, SWP_NOZORDER);
+ }
+ if (hSendButton) {
+ SetWindowPos(hSendButton, NULL, 320, height - 130, 100, 45, SWP_NOZORDER);
+ }
+ if (hShareFileButton) {
+ SetWindowPos(hShareFileButton, NULL, 440, height - 130, 120, 45, SWP_NOZORDER);
+ }
+}
+
+void SetupWindowColors()
+{
+ SetClassLongPtr(hChatDisplay, GCLP_HBRBACKGROUND, (LONG_PTR)hBrushSurface);
+ SetClassLongPtr(hMessageInput, GCLP_HBRBACKGROUND, (LONG_PTR)hBrushSurface);
+ SetClassLongPtr(hSharedFilesList, GCLP_HBRBACKGROUND, (LONG_PTR)hBrushSurface);
+}
\ No newline at end of file
diff --git a/Samples/ChatAppShare/SampleChatAppWithShare/UIManager.h b/Samples/ChatAppShare/SampleChatAppWithShare/UIManager.h
new file mode 100644
index 0000000..74c2a14
--- /dev/null
+++ b/Samples/ChatAppShare/SampleChatAppWithShare/UIManager.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include
+
+// UI Window handles
+extern HWND hContactsList;
+extern HWND hChatDisplay;
+extern HWND hMessageInput;
+extern HWND hSendButton;
+extern HWND hContactName;
+extern HWND hShareFileButton;
+extern HWND hSharedFilesList;
+
+// UI management functions
+void CreateChatUI(HWND hWnd);
+void ResizeChatUI(HWND hWnd);
+void SetupWindowColors();
\ No newline at end of file
diff --git a/Samples/ChatAppShare/SampleChatAppWithShare/WindowProcs.cpp b/Samples/ChatAppShare/SampleChatAppWithShare/WindowProcs.cpp
new file mode 100644
index 0000000..ce00862
--- /dev/null
+++ b/Samples/ChatAppShare/SampleChatAppWithShare/WindowProcs.cpp
@@ -0,0 +1,168 @@
+#include "WindowProcs.h"
+#include "UIConstants.h"
+#include "ModernUI.h"
+#include "ChatModels.h"
+#include "UIManager.h"
+
+// External declarations for UI window handles
+extern HWND hSendButton;
+extern HWND hShareFileButton;
+extern HWND hContactsList;
+
+// Window procedure storage for subclassing
+WNDPROC originalButtonProc = nullptr;
+WNDPROC originalListBoxProc = nullptr;
+
+void SetupCustomWindowProcs()
+{
+ // Subclass buttons for custom drawing
+ originalButtonProc = (WNDPROC)SetWindowLongPtr(hSendButton, GWLP_WNDPROC, (LONG_PTR)ModernButtonProc);
+ SetWindowLongPtr(hShareFileButton, GWLP_WNDPROC, (LONG_PTR)ModernButtonProc);
+
+ // Subclass contact list for custom drawing
+ originalListBoxProc = (WNDPROC)SetWindowLongPtr(hContactsList, GWLP_WNDPROC, (LONG_PTR)ModernListBoxProc);
+}
+
+// Modern button subclass procedure
+LRESULT CALLBACK ModernButtonProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static bool isHovered = false;
+ static bool isPressed = false;
+
+ switch (msg)
+ {
+ case WM_PAINT:
+ {
+ PAINTSTRUCT ps;
+ HDC hdc = BeginPaint(hWnd, &ps);
+
+ RECT rect;
+ GetClientRect(hWnd, &rect);
+
+ WCHAR text[256];
+ GetWindowText(hWnd, text, 256);
+
+ DrawModernButton(hdc, rect, std::wstring(text), isHovered, isPressed);
+
+ EndPaint(hWnd, &ps);
+ return 0;
+ }
+
+ case WM_MOUSEMOVE:
+ if (!isHovered)
+ {
+ isHovered = true;
+ InvalidateRect(hWnd, NULL, FALSE);
+
+ TRACKMOUSEEVENT tme = {};
+ tme.cbSize = sizeof(tme);
+ tme.dwFlags = TME_LEAVE;
+ tme.hwndTrack = hWnd;
+ TrackMouseEvent(&tme);
+ }
+ break;
+
+ case WM_MOUSELEAVE:
+ isHovered = false;
+ InvalidateRect(hWnd, NULL, FALSE);
+ break;
+
+ case WM_LBUTTONDOWN:
+ isPressed = true;
+ InvalidateRect(hWnd, NULL, FALSE);
+ SetCapture(hWnd);
+ break;
+
+ case WM_LBUTTONUP:
+ if (isPressed)
+ {
+ isPressed = false;
+ InvalidateRect(hWnd, NULL, FALSE);
+ ReleaseCapture();
+
+ // Send click notification to parent
+ HWND hParent = GetParent(hWnd);
+ int controlId = GetDlgCtrlID(hWnd);
+ ::SendMessage(hParent, WM_COMMAND, MAKEWPARAM(controlId, BN_CLICKED), (LPARAM)hWnd);
+ }
+ break;
+ }
+
+ return CallWindowProc(originalButtonProc, hWnd, msg, wParam, lParam);
+}
+
+// Modern listbox subclass procedure
+LRESULT CALLBACK ModernListBoxProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg)
+ {
+ case WM_LBUTTONDOWN:
+ if (hWnd == hContactsList)
+ {
+ // Handle mouse click to ensure proper contact selection with scrolling
+ POINT pt = { LOWORD(lParam), HIWORD(lParam) };
+
+ // Calculate which contact was clicked based on the scroll position
+ int topIndex = (int)::SendMessage(hWnd, LB_GETTOPINDEX, 0, 0);
+ int clickedVisiblePos = pt.y / CONTACT_ITEM_HEIGHT;
+ int actualContactIndex = topIndex + clickedVisiblePos;
+
+ // Ensure the clicked contact is valid
+ if (actualContactIndex >= 0 && actualContactIndex < (int)contacts.size())
+ {
+ // Set the correct selection in the listbox
+ ::SendMessage(hWnd, LB_SETCURSEL, actualContactIndex, 0);
+
+ // Trigger the selection change event to update the UI
+ HWND hParent = GetParent(hWnd);
+ int controlId = GetDlgCtrlID(hWnd);
+ ::SendMessage(hParent, WM_COMMAND, MAKEWPARAM(controlId, LBN_SELCHANGE), (LPARAM)hWnd);
+
+ return 0; // We handled the click
+ }
+ }
+ break;
+
+ case WM_PAINT:
+ if (hWnd == hContactsList)
+ {
+ PAINTSTRUCT ps;
+ HDC hdc = BeginPaint(hWnd, &ps);
+
+ RECT clientRect;
+ GetClientRect(hWnd, &clientRect);
+
+ // Fill background
+ FillRect(hdc, &clientRect, hBrushSurface);
+
+ int itemCount = (int)contacts.size();
+ int selectedIndex = (int)::SendMessage(hWnd, LB_GETCURSEL, 0, 0);
+
+ // Get the first visible item index to handle scrolling correctly
+ int topIndex = (int)::SendMessage(hWnd, LB_GETTOPINDEX, 0, 0);
+
+ // Calculate how many items can be visible
+ int visibleItemCount = (clientRect.bottom / CONTACT_ITEM_HEIGHT) + 1;
+
+ // Draw only the visible items
+ for (int visiblePos = 0; visiblePos < visibleItemCount; visiblePos++)
+ {
+ int actualIndex = topIndex + visiblePos;
+
+ // Stop if we've reached the end of the contact list
+ if (actualIndex >= itemCount) break;
+
+ RECT itemRect = {0, visiblePos * CONTACT_ITEM_HEIGHT, clientRect.right, (visiblePos + 1) * CONTACT_ITEM_HEIGHT};
+
+ // Draw the contact that should be visible at this position
+ DrawContactItem(hdc, itemRect, contacts[actualIndex], actualIndex == selectedIndex);
+ }
+
+ EndPaint(hWnd, &ps);
+ return 0;
+ }
+ break;
+ }
+
+ return CallWindowProc(originalListBoxProc, hWnd, msg, wParam, lParam);
+}
\ No newline at end of file
diff --git a/Samples/ChatAppShare/SampleChatAppWithShare/WindowProcs.h b/Samples/ChatAppShare/SampleChatAppWithShare/WindowProcs.h
new file mode 100644
index 0000000..97c8623
--- /dev/null
+++ b/Samples/ChatAppShare/SampleChatAppWithShare/WindowProcs.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include
+
+// Window procedures
+LRESULT CALLBACK ModernButtonProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+LRESULT CALLBACK ModernListBoxProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+// Original window procedures storage
+extern WNDPROC originalButtonProc;
+extern WNDPROC originalListBoxProc;
+
+// Setup functions
+void SetupCustomWindowProcs();
\ No newline at end of file
diff --git a/Samples/ChatAppShare/SampleChatAppWithShare/framework.h b/Samples/ChatAppShare/SampleChatAppWithShare/framework.h
new file mode 100644
index 0000000..414c103
--- /dev/null
+++ b/Samples/ChatAppShare/SampleChatAppWithShare/framework.h
@@ -0,0 +1,29 @@
+// header.h : include file for standard system include files,
+// or project specific include files
+//
+
+#pragma once
+
+#include "targetver.h"
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+
+// Windows Header Files
+#include
+
+// WinRT Headers for Share Target functionality
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+// C RunTime Header Files
+#include
+#include
+#include
+#include
diff --git a/Samples/ChatAppShare/SampleChatAppWithShare/small.ico b/Samples/ChatAppShare/SampleChatAppWithShare/small.ico
new file mode 100644
index 0000000..b3ec03b
Binary files /dev/null and b/Samples/ChatAppShare/SampleChatAppWithShare/small.ico differ
diff --git a/Samples/ChatAppShare/SampleChatAppWithShare/targetver.h b/Samples/ChatAppShare/SampleChatAppWithShare/targetver.h
new file mode 100644
index 0000000..bf75e08
--- /dev/null
+++ b/Samples/ChatAppShare/SampleChatAppWithShare/targetver.h
@@ -0,0 +1,6 @@
+#pragma once
+
+// // Including SDKDDKVer.h defines the highest available Windows platform.
+// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
+// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
+#include
diff --git a/Samples/ChatAppShare/ShareApp/ChatManager.cpp b/Samples/ChatAppShare/ShareApp/ChatManager.cpp
new file mode 100644
index 0000000..b00ebb6
--- /dev/null
+++ b/Samples/ChatAppShare/ShareApp/ChatManager.cpp
@@ -0,0 +1,132 @@
+#include "ChatManager.h"
+#include "ChatModels.h"
+#include "FileManager.h"
+#include "UIManager.h"
+#include
+#include
+#include
+
+void LoadContactChat(int contactIndex)
+{
+ if (!IsValidContactIndex(contactIndex)) return;
+
+ selectedContactIndex = contactIndex;
+ const Contact& contact = contacts[contactIndex];
+
+ // Update contact name with status indicator
+ std::wstring headerText = contact.name + L" " + L" (" + contact.status + L")";
+ SetWindowText(hContactName, headerText.c_str());
+
+ // Clear and populate chat display with better formatting
+ SetWindowText(hChatDisplay, L"");
+
+ std::wstring chatText;
+ for (const auto& message : contact.messages) {
+ // Add timestamps and better message formatting
+ SYSTEMTIME st;
+ GetLocalTime(&st);
+ WCHAR timeStr[50];
+ swprintf_s(timeStr, 50, L"[%02d:%02d] ", st.wHour, st.wMinute);
+
+ if (message.find(L"You:") == 0) {
+ chatText += L" "; // Right align for your messages
+ chatText += timeStr + message + L"\r\n\r\n";
+ } else {
+ chatText += timeStr + message + L"\r\n\r\n";
+ }
+ }
+
+ SetWindowText(hChatDisplay, chatText.c_str());
+
+ // Scroll to bottom
+ ::SendMessage(hChatDisplay, EM_SETSEL, -1, -1);
+ ::SendMessage(hChatDisplay, EM_SCROLLCARET, 0, 0);
+
+ // Update shared files list
+ UpdateSharedFilesList();
+
+ // Refresh contact list to show selection
+ InvalidateRect(hContactsList, NULL, TRUE);
+}
+
+void AddMessageToChat(const std::wstring& message, bool isOutgoing)
+{
+ Contact* contact = GetSelectedContact();
+ if (!contact) return;
+
+ // Add timestamp to message
+ SYSTEMTIME st;
+ GetLocalTime(&st);
+ WCHAR timeStr[50];
+ swprintf_s(timeStr, 50, L"[%02d:%02d] ", st.wHour, st.wMinute);
+
+ std::wstring formattedMessage;
+ if (isOutgoing) {
+ formattedMessage = L"You: " + message + L" ??";
+ } else {
+ formattedMessage = contact->name + L": " + message;
+ }
+
+ contact->messages.push_back(formattedMessage);
+ contact->lastMessage = message.length() > 50 ? message.substr(0, 47) + L"..." : message;
+
+ // Update chat display
+ LoadContactChat(selectedContactIndex);
+
+ // Refresh contacts list to update last message preview
+ InvalidateRect(hContactsList, NULL, TRUE);
+}
+
+void SendChatMessage()
+{
+ if (selectedContactIndex < 0) return;
+
+ WCHAR buffer[1024];
+ GetWindowText(hMessageInput, buffer, 1024);
+
+ std::wstring message(buffer);
+ if (!message.empty()) {
+ AddMessageToChat(message, true);
+ SetWindowText(hMessageInput, L"");
+
+ // Simulate auto-reply after a short delay
+ SetTimer(GetParent(hMessageInput), 1, 2000, NULL);
+ }
+}
+
+void ProcessAutoReply(HWND hWnd, int timerType)
+{
+ if (selectedContactIndex < 0) return;
+
+ KillTimer(hWnd, timerType);
+
+ if (timerType == 1) {
+ // Auto-reply from the selected contact with more variety
+ std::vector autoReplies = {
+ L"Got it!",
+ L"Thanks for letting me know!",
+ L"Sounds good!",
+ L"I'll get back to you soon.",
+ L"Perfect!",
+ L"Absolutely!",
+ L"Let me think about it.",
+ L"Great idea!"
+ };
+
+ int replyIndex = rand() % autoReplies.size();
+ AddMessageToChat(autoReplies[replyIndex], false);
+ }
+ else if (timerType == 2) {
+ // Auto-reply acknowledging the shared file
+ std::vector fileReplies = {
+ L"Thanks for sharing the file!",
+ L"Got the file, will check it out.",
+ L"File received, thanks! ??",
+ L"Perfect timing, I needed this file.",
+ L"Awesome, downloading now!"
+ };
+
+ int replyIndex = rand() % fileReplies.size();
+ AddMessageToChat(fileReplies[replyIndex], false);
+ }
+}
\ No newline at end of file
diff --git a/Samples/ChatAppShare/ShareApp/ChatManager.h b/Samples/ChatAppShare/ShareApp/ChatManager.h
new file mode 100644
index 0000000..daefb88
--- /dev/null
+++ b/Samples/ChatAppShare/ShareApp/ChatManager.h
@@ -0,0 +1,10 @@
+#pragma once
+
+#include
+#include
+
+// Chat management functions
+void LoadContactChat(int contactIndex);
+void SendChatMessage();
+void AddMessageToChat(const std::wstring& message, bool isOutgoing);
+void ProcessAutoReply(HWND hWnd, int timerType);
\ No newline at end of file
diff --git a/Samples/ChatAppShare/ShareApp/ChatModels.cpp b/Samples/ChatAppShare/ShareApp/ChatModels.cpp
new file mode 100644
index 0000000..db4f520
--- /dev/null
+++ b/Samples/ChatAppShare/ShareApp/ChatModels.cpp
@@ -0,0 +1,48 @@
+#include "ChatModels.h"
+
+// Global data definitions
+std::vector contacts;
+std::map> chatHistory;
+int selectedContactIndex = -1;
+
+void InitializeContacts()
+{
+ contacts = {
+ {L"Alice Johnson", L"Hey, how are you?", {L"Alice: Hey, how are you?", L"You: I'm doing great, thanks!", L"Alice: That's wonderful to hear!"}, {}, L"Available", true},
+ {L"Bob Smith", L"See you tomorrow!", {L"Bob: Are we still meeting tomorrow?", L"You: Yes, see you at 3 PM", L"Bob: See you tomorrow!"}, {}, L"In a meeting", true},
+ {L"Carol Williams", L"Thanks for the help", {L"Carol: Could you help me with the project?", L"You: Of course! What do you need?", L"Carol: Thanks for the help"}, {}, L"Available", true},
+ {L"David Brown", L"Great presentation!", {L"David: Great presentation today!", L"You: Thank you! I'm glad you liked it"}, {}, L"Away", false},
+ {L"Emma Davis", L"Coffee later?", {L"Emma: Want to grab coffee later?", L"You: Sure! What time works for you?", L"Emma: Coffee later?"}, {}, L"Available", true},
+ {L"Frank Miller", L"Happy Birthday!", {L"Frank: Happy Birthday!", L"You: Thank you so much!"}, {}, L"Busy", true},
+ {L"Grace Wilson", L"Meeting rescheduled", {L"Grace: Meeting has been rescheduled to 4 PM", L"You: Got it, thanks for letting me know"}, {}, L"Available", true},
+ {L"Henry Taylor", L"Weekend plans?", {L"Henry: Any plans for the weekend?", L"You: Nothing concrete yet", L"Henry: Weekend plans?"}, {}, L"Offline", false},
+ {L"Ivy Anderson", L"Project update", {L"Ivy: Here's the project update you requested", L"You: Perfect, reviewing it now"}, {}, L"Available", true},
+ {L"Jack Thompson", L"Game night Friday", {L"Jack: Game night this Friday?", L"You: Count me in!", L"Jack: Game night Friday"}, {}, L"Gaming", true},
+ {L"Kate Garcia", L"Recipe sharing", {L"Kate: Loved that recipe you shared!", L"You: I'm so glad you enjoyed it!"}, {}, L"Cooking", true},
+ {L"Leo Martinez", L"Workout buddy", {L"Leo: Gym session tomorrow morning?", L"You: Absolutely! 7 AM as usual?"}, {}, L"At the gym", true},
+ {L"Mia Rodriguez", L"Book recommendation", {L"Mia: Any good book recommendations?", L"You: I just finished a great mystery novel"}, {}, L"Reading", true},
+ {L"Noah Lee", L"Tech discussion", {L"Noah: Thoughts on the new framework?", L"You: It looks promising! Want to discuss over lunch?"}, {}, L"Coding", true},
+ {L"Olivia Clark", L"Travel planning", {L"Olivia: Planning the vacation itinerary", L"You: Excited to see what you've planned!"}, {}, L"Traveling", false}
+ };
+
+ // Add some sample shared files to demonstrate the feature
+ SYSTEMTIME st;
+ GetSystemTime(&st);
+
+ contacts[0].sharedFiles.push_back({L"Project_Proposal.docx", L"C:\\Documents\\Project_Proposal.docx", L"Alice", st});
+ contacts[1].sharedFiles.push_back({L"Meeting_Notes.pdf", L"C:\\Documents\\Meeting_Notes.pdf", L"Bob", st});
+ contacts[2].sharedFiles.push_back({L"Budget_Spreadsheet.xlsx", L"C:\\Documents\\Budget_Spreadsheet.xlsx", L"Carol", st});
+}
+
+Contact* GetSelectedContact()
+{
+ if (IsValidContactIndex(selectedContactIndex)) {
+ return &contacts[selectedContactIndex];
+ }
+ return nullptr;
+}
+
+bool IsValidContactIndex(int index)
+{
+ return index >= 0 && index < (int)contacts.size();
+}
\ No newline at end of file
diff --git a/Samples/ChatAppShare/ShareApp/ChatModels.h b/Samples/ChatAppShare/ShareApp/ChatModels.h
new file mode 100644
index 0000000..3fb7531
--- /dev/null
+++ b/Samples/ChatAppShare/ShareApp/ChatModels.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#include
+#include
+#include
+#include
+
+struct SharedFile {
+ std::wstring fileName;
+ std::wstring filePath;
+ std::wstring sharedBy;
+ SYSTEMTIME timeShared;
+};
+
+struct Contact {
+ std::wstring name;
+ std::wstring lastMessage;
+ std::vector messages;
+ std::vector sharedFiles;
+ std::wstring status;
+ bool isOnline;
+};
+
+// Global data
+extern std::vector contacts;
+extern std::map> chatHistory;
+extern int selectedContactIndex;
+
+// Contact management functions
+void InitializeContacts();
+Contact* GetSelectedContact();
+bool IsValidContactIndex(int index);
\ No newline at end of file
diff --git a/Samples/ChatAppShare/ShareApp/ContactSelectionDialog.cpp b/Samples/ChatAppShare/ShareApp/ContactSelectionDialog.cpp
new file mode 100644
index 0000000..ba1aeca
--- /dev/null
+++ b/Samples/ChatAppShare/ShareApp/ContactSelectionDialog.cpp
@@ -0,0 +1,275 @@
+#include "ContactSelectionDialog.h"
+#include "Resource.h"
+#include "UIConstants.h"
+#include
+
+// Static member initialization
+ContactSelectionDialog::SelectionResult ContactSelectionDialog::s_dialogResult;
+std::wstring ContactSelectionDialog::s_currentFilePath;
+std::wstring ContactSelectionDialog::s_currentFileName;
+
+ContactSelectionDialog::SelectionResult ContactSelectionDialog::ShowContactSelectionDialog(HWND hParent, const std::wstring& filePath, const std::wstring& fileName)
+{
+ // Store the file information for the dialog
+ s_currentFilePath = filePath;
+ s_currentFileName = fileName;
+
+ // Reset the result
+ s_dialogResult = SelectionResult();
+
+ // Show the modal dialog
+ INT_PTR result = DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_CONTACT_SELECTION), hParent, ContactSelectionDlgProc);
+
+ if (result == IDOK)
+ {
+ s_dialogResult.wasSelected = true;
+ s_dialogResult.filePath = s_currentFilePath;
+ s_dialogResult.fileName = s_currentFileName;
+ }
+ else
+ {
+ s_dialogResult.wasSelected = false;
+ }
+
+ return s_dialogResult;
+}
+
+INT_PTR CALLBACK ContactSelectionDialog::ContactSelectionDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message)
+ {
+ case WM_INITDIALOG:
+ {
+ // Set the dialog title with file name
+ std::wstring title = L"Share \"" + s_currentFileName + L"\" - Select Contact";
+ SetWindowText(hDlg, title.c_str());
+
+ // Set up the dialog layout and styling
+ SetupDialogSizing(hDlg);
+
+ // Initialize and populate the contact list
+ HWND hListBox = GetDlgItem(hDlg, IDC_CONTACT_SELECTION_LIST);
+ if (hListBox)
+ {
+ InitializeContactList(hListBox);
+ PopulateContactList(hListBox);
+ }
+
+ // Set up the share message edit control
+ HWND hMessageEdit = GetDlgItem(hDlg, IDC_SHARE_MESSAGE_EDIT);
+ if (hMessageEdit)
+ {
+ std::wstring defaultMessage = L"I'm sharing \"" + s_currentFileName + L"\" with you!";
+ SetWindowText(hMessageEdit, defaultMessage.c_str());
+ }
+
+ // Initially disable the Select button until a contact is chosen
+ EnableWindow(GetDlgItem(hDlg, IDC_SELECT_CONTACT_BUTTON), FALSE);
+
+ // Center the dialog on the parent
+ RECT rcParent, rcDlg;
+ HWND hParent = GetParent(hDlg);
+ if (hParent)
+ {
+ GetWindowRect(hParent, &rcParent);
+ GetWindowRect(hDlg, &rcDlg);
+
+ int x = rcParent.left + (rcParent.right - rcParent.left - (rcDlg.right - rcDlg.left)) / 2;
+ int y = rcParent.top + (rcParent.bottom - rcParent.top - (rcDlg.bottom - rcDlg.top)) / 2;
+
+ SetWindowPos(hDlg, HWND_TOP, x, y, 0, 0, SWP_NOSIZE);
+ }
+
+ return TRUE;
+ }
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDC_CONTACT_SELECTION_LIST:
+ if (HIWORD(wParam) == LBN_SELCHANGE)
+ {
+ int selectedIndex = (int)SendDlgItemMessage(hDlg, IDC_CONTACT_SELECTION_LIST, LB_GETCURSEL, 0, 0);
+ HandleContactSelection(hDlg, selectedIndex);
+ }
+ else if (HIWORD(wParam) == LBN_DBLCLK)
+ {
+ // Double-click selects and closes dialog
+ OnSelectContact(hDlg);
+ }
+ break;
+
+ case IDC_SELECT_CONTACT_BUTTON:
+ OnSelectContact(hDlg);
+ break;
+
+ case IDC_CANCEL_SELECTION_BUTTON:
+ case IDCANCEL:
+ OnCancel(hDlg);
+ break;
+
+ case IDOK:
+ OnSelectContact(hDlg);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ OnCancel(hDlg);
+ break;
+ }
+
+ return FALSE;
+}
+
+void ContactSelectionDialog::InitializeContactList(HWND hListBox)
+{
+ // Set up the list box for contact display
+ SendMessage(hListBox, LB_RESETCONTENT, 0, 0);
+}
+
+void ContactSelectionDialog::PopulateContactList(HWND hListBox)
+{
+ // Clear existing items
+ SendMessage(hListBox, LB_RESETCONTENT, 0, 0);
+
+ // Ensure contacts are initialized
+ if (contacts.empty())
+ {
+ InitializeContacts();
+ }
+
+ // Debug logging
+ OutputDebugStringW((L"ContactSelectionDialog: Populating list with " + std::to_wstring(contacts.size()) + L" contacts\n").c_str());
+
+ // Add all contacts to the list
+ for (size_t i = 0; i < contacts.size(); ++i)
+ {
+ const Contact& contact = contacts[i];
+
+ // Create display text with contact name and status
+ std::wstring displayText = contact.name + L" - " + contact.status;
+ if (!contact.isOnline)
+ {
+ displayText += L" (Offline)";
+ }
+
+ int itemIndex = (int)SendMessage(hListBox, LB_ADDSTRING, 0, (LPARAM)displayText.c_str());
+
+ // Store the contact index as item data
+ SendMessage(hListBox, LB_SETITEMDATA, itemIndex, (LPARAM)i);
+
+ // Debug log each contact being added
+ OutputDebugStringW((L"ContactSelectionDialog: Added contact " + std::to_wstring(i) + L": " + contact.name + L"\n").c_str());
+ }
+
+ // If no contacts were added, add a placeholder
+ if (contacts.empty())
+ {
+ SendMessage(hListBox, LB_ADDSTRING, 0, (LPARAM)L"No contacts available");
+ OutputDebugStringW(L"ContactSelectionDialog: No contacts available - added placeholder\n");
+ }
+ else
+ {
+ OutputDebugStringW((L"ContactSelectionDialog: Successfully populated " + std::to_wstring(contacts.size()) + L" contacts\n").c_str());
+ }
+}
+
+void ContactSelectionDialog::HandleContactSelection(HWND hDlg, int selectedIndex)
+{
+ if (selectedIndex != LB_ERR)
+ {
+ // Enable the Select button when a contact is selected
+ EnableWindow(GetDlgItem(hDlg, IDC_SELECT_CONTACT_BUTTON), TRUE);
+
+ // Get the contact index from item data
+ HWND hListBox = GetDlgItem(hDlg, IDC_CONTACT_SELECTION_LIST);
+ int contactIndex = (int)SendMessage(hListBox, LB_GETITEMDATA, selectedIndex, 0);
+
+ if (contactIndex >= 0 && contactIndex < (int)contacts.size())
+ {
+ // Update the share message with the selected contact's name
+ const Contact& contact = contacts[contactIndex];
+ std::wstring personalizedMessage = L"Hey " + contact.name + L"! I'm sharing \"" + s_currentFileName + L"\" with you.";
+
+ HWND hMessageEdit = GetDlgItem(hDlg, IDC_SHARE_MESSAGE_EDIT);
+ if (hMessageEdit)
+ {
+ SetWindowText(hMessageEdit, personalizedMessage.c_str());
+ }
+ }
+ }
+ else
+ {
+ // Disable the Select button when no contact is selected
+ EnableWindow(GetDlgItem(hDlg, IDC_SELECT_CONTACT_BUTTON), FALSE);
+ }
+}
+
+void ContactSelectionDialog::OnSelectContact(HWND hDlg)
+{
+ HWND hListBox = GetDlgItem(hDlg, IDC_CONTACT_SELECTION_LIST);
+ int selectedIndex = (int)SendMessage(hListBox, LB_GETCURSEL, 0, 0);
+
+ if (selectedIndex == LB_ERR)
+ {
+ MessageBox(hDlg, L"Please select a contact to share with.", L"No Contact Selected", MB_OK | MB_ICONWARNING);
+ return;
+ }
+
+ // Check if contacts are available
+ if (contacts.empty())
+ {
+ MessageBox(hDlg, L"No contacts are available. Please ensure the application is properly initialized.", L"No Contacts Available", MB_OK | MB_ICONWARNING);
+ return;
+ }
+
+ // Get the contact index from item data
+ int contactIndex = (int)SendMessage(hListBox, LB_GETITEMDATA, selectedIndex, 0);
+
+ // Debug logging
+ OutputDebugStringW((L"ContactSelectionDialog: Selected contact index: " + std::to_wstring(contactIndex) + L", total contacts: " + std::to_wstring(contacts.size()) + L"\n").c_str());
+
+ if (contactIndex >= 0 && contactIndex < (int)contacts.size())
+ {
+ // Get the share message
+ HWND hMessageEdit = GetDlgItem(hDlg, IDC_SHARE_MESSAGE_EDIT);
+ WCHAR messageBuffer[512] = {0};
+ if (hMessageEdit)
+ {
+ GetWindowText(hMessageEdit, messageBuffer, 512);
+ }
+
+ // Store the result
+ s_dialogResult.contactIndex = contactIndex;
+ s_dialogResult.shareMessage = messageBuffer;
+
+ // Debug logging
+ OutputDebugStringW((L"ContactSelectionDialog: Contact selected - " + contacts[contactIndex].name + L"\n").c_str());
+
+ // Close dialog with success
+ EndDialog(hDlg, IDOK);
+ }
+ else
+ {
+ MessageBox(hDlg, L"Invalid contact selection. Please try again.", L"Selection Error", MB_OK | MB_ICONERROR);
+ OutputDebugStringW((L"ContactSelectionDialog: Invalid contact index: " + std::to_wstring(contactIndex) + L"\n").c_str());
+ }
+}
+
+void ContactSelectionDialog::OnCancel(HWND hDlg)
+{
+ // Close dialog with cancel
+ EndDialog(hDlg, IDCANCEL);
+}
+
+void ContactSelectionDialog::SetupDialogSizing(HWND hDlg)
+{
+ // Set dialog size (approximately 400x500 pixels)
+ SetWindowPos(hDlg, NULL, 0, 0, 420, 520, SWP_NOMOVE | SWP_NOZORDER);
+}
+
+void ContactSelectionDialog::ApplyModernStyling(HWND hDlg)
+{
+ // Modern styling is optional for now - skip to avoid dependencies
+}
\ No newline at end of file
diff --git a/Samples/ChatAppShare/ShareApp/ContactSelectionDialog.h b/Samples/ChatAppShare/ShareApp/ContactSelectionDialog.h
new file mode 100644
index 0000000..fc06ffe
--- /dev/null
+++ b/Samples/ChatAppShare/ShareApp/ContactSelectionDialog.h
@@ -0,0 +1,45 @@
+#pragma once
+
+#include
+#include
+#include
+#include "ChatModels.h"
+
+// Contact Selection Dialog Manager
+class ContactSelectionDialog
+{
+public:
+ // Structure to hold the result of contact selection
+ struct SelectionResult
+ {
+ bool wasSelected;
+ int contactIndex;
+ std::wstring shareMessage;
+ std::wstring filePath;
+ std::wstring fileName;
+
+ SelectionResult() : wasSelected(false), contactIndex(-1) {}
+ };
+
+ // Show the contact selection dialog
+ static SelectionResult ShowContactSelectionDialog(HWND hParent, const std::wstring& filePath, const std::wstring& fileName);
+
+private:
+ // Dialog procedure for contact selection
+ static INT_PTR CALLBACK ContactSelectionDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
+
+ // Helper functions
+ static void InitializeContactList(HWND hListBox);
+ static void PopulateContactList(HWND hListBox);
+ static void UpdateContactListDisplay(HWND hListBox);
+ static void HandleContactSelection(HWND hDlg, int selectedIndex);
+ static void OnSelectContact(HWND hDlg);
+ static void OnCancel(HWND hDlg);
+ static void SetupDialogSizing(HWND hDlg);
+ static void ApplyModernStyling(HWND hDlg);
+
+ // Static data for dialog communication
+ static SelectionResult s_dialogResult;
+ static std::wstring s_currentFilePath;
+ static std::wstring s_currentFileName;
+};
\ No newline at end of file
diff --git a/Samples/ChatAppShare/ShareApp/FileManager.cpp b/Samples/ChatAppShare/ShareApp/FileManager.cpp
new file mode 100644
index 0000000..31ace5f
--- /dev/null
+++ b/Samples/ChatAppShare/ShareApp/FileManager.cpp
@@ -0,0 +1,154 @@
+#include "FileManager.h"
+#include "ChatModels.h"
+#include "ChatManager.h"
+#include "UIManager.h"
+#include
+#include
+
+#pragma comment(lib, "comdlg32.lib")
+
+// External declarations for UI window handles
+extern HWND hSharedFilesList;
+extern HWND hContactsList;
+
+void ShareFile()
+{
+ // Check if a contact is selected first
+ if (selectedContactIndex < 0) {
+ MessageBox(NULL, L"Please select a contact to share files with.", L"No Contact Selected", MB_OK | MB_ICONWARNING);
+ return;
+ }
+
+ // Get the main window handle (parent of the share file button)
+ HWND hMainWindow = GetParent(hSharedFilesList);
+ while (GetParent(hMainWindow))
+ {
+ hMainWindow = GetParent(hMainWindow);
+ }
+
+ OPENFILENAME ofn;
+ WCHAR szFile[260] = {0};
+
+ ZeroMemory(&ofn, sizeof(ofn));
+ ofn.lStructSize = sizeof(ofn);
+ ofn.hwndOwner = hMainWindow; // Set the main window as owner
+ ofn.lpstrFile = szFile;
+ ofn.nMaxFile = sizeof(szFile);
+ ofn.lpstrFilter = L"All Files\0*.*\0?? Text Files\0*.TXT\0?? Document Files\0*.DOC;*.DOCX\0??? Image Files\0*.BMP;*.JPG;*.PNG;*.GIF\0?? PDF Files\0*.PDF\0?? Excel Files\0*.XLS;*.XLSX\0";
+ ofn.nFilterIndex = 1;
+ ofn.lpstrFileTitle = NULL;
+ ofn.nMaxFileTitle = 0;
+ ofn.lpstrInitialDir = NULL;
+ ofn.lpstrTitle = L"Select File to Share";
+ ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_EXPLORER;
+
+ if (GetOpenFileName(&ofn))
+ {
+ // Extract file name from full path
+ std::wstring fullPath(szFile);
+ size_t lastSlash = fullPath.find_last_of(L"\\");
+ std::wstring fileName;
+ if (lastSlash != std::wstring::npos)
+ {
+ fileName = fullPath.substr(lastSlash + 1);
+ }
+ else
+ {
+ fileName = fullPath;
+ }
+
+ // Create shared file entry
+ SharedFile newFile;
+ newFile.fileName = fileName;
+ newFile.filePath = fullPath;
+ newFile.sharedBy = L"You";
+ GetSystemTime(&newFile.timeShared);
+
+ // Add file to the currently selected contact's shared files
+ if (selectedContactIndex >= 0 && selectedContactIndex < (int)contacts.size())
+ {
+ contacts[selectedContactIndex].sharedFiles.push_back(newFile);
+
+ // Add file sharing notification to chat
+ std::wstring fileShareMsg = L"?? Shared file: " + fileName;
+ AddMessageToChat(fileShareMsg, true);
+
+ // Update UI
+ AddSharedFileToChat(newFile, true);
+
+ // Update contacts list display to show the shared activity
+ InvalidateRect(hContactsList, NULL, TRUE);
+
+ // Show success message with current contact
+ std::wstring successMsg = L"File \"" + fileName + L"\" has been shared with " + contacts[selectedContactIndex].name + L"!";
+ MessageBox(hMainWindow, successMsg.c_str(), L"File Shared Successfully", MB_OK | MB_ICONINFORMATION);
+
+ // Simulate auto-reply from contact acknowledging the file
+ SetTimer(hMainWindow, 2, 2000, NULL);
+ }
+ }
+}
+
+void AddSharedFileToChat(const SharedFile& file, bool isOutgoing)
+{
+ Contact* contact = GetSelectedContact();
+ if (!contact) return;
+
+ std::wstring sharer = isOutgoing ? L"You" : contact->name;
+
+ // Format file sharing message with timestamp
+ SYSTEMTIME st;
+ GetLocalTime(&st);
+ WCHAR timeStr[50];
+ swprintf_s(timeStr, 50, L"[%02d:%02d] ", st.wHour, st.wMinute);
+
+ std::wstring shareMessage = sharer + L" shared: " + file.fileName + L" ??";
+ contact->messages.push_back(shareMessage);
+
+ // Update last message preview
+ contact->lastMessage = L"?? " + file.fileName;
+
+ // Add to shared files list
+ contact->sharedFiles.push_back(file);
+
+ // Refresh UI
+ LoadContactChat(selectedContactIndex);
+ UpdateSharedFilesList();
+}
+
+void OpenSharedFile(int fileIndex)
+{
+ Contact* contact = GetSelectedContact();
+ if (!contact || fileIndex < 0 || fileIndex >= (int)contact->sharedFiles.size()) {
+ return;
+ }
+
+ const SharedFile& file = contact->sharedFiles[fileIndex];
+
+ // Try to open the file with the default application
+ HINSTANCE result = ShellExecute(NULL, L"open", file.filePath.c_str(), NULL, NULL, SW_SHOWNORMAL);
+
+ if ((intptr_t)result <= 32) {
+ // If opening failed, show file location in explorer
+ std::wstring explorerCmd = L"/select,\"" + file.filePath + L"\"";
+ ShellExecute(NULL, L"open", L"explorer.exe", explorerCmd.c_str(), NULL, SW_SHOWNORMAL);
+ }
+}
+
+void UpdateSharedFilesList()
+{
+ if (!hSharedFilesList) return;
+
+ Contact* contact = GetSelectedContact();
+
+ // Clear the list
+ SendMessage(hSharedFilesList, LB_RESETCONTENT, 0, 0);
+
+ if (!contact) return;
+
+ // Add shared files to the list
+ for (const auto& file : contact->sharedFiles) {
+ std::wstring displayText = file.fileName + L" (shared by " + file.sharedBy + L")";
+ SendMessage(hSharedFilesList, LB_ADDSTRING, 0, (LPARAM)displayText.c_str());
+ }
+}
\ No newline at end of file
diff --git a/Samples/ChatAppShare/ShareApp/FileManager.h b/Samples/ChatAppShare/ShareApp/FileManager.h
new file mode 100644
index 0000000..e28e4db
--- /dev/null
+++ b/Samples/ChatAppShare/ShareApp/FileManager.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include
+#include
+#include "ChatModels.h"
+
+// File management functions
+void ShareFile();
+void AddSharedFileToChat(const SharedFile& file, bool isOutgoing);
+void UpdateSharedFilesList();
+void OpenSharedFile(int fileIndex);
+std::wstring GetFileExtensionIcon(const std::wstring& filePath);
+std::wstring FormatFileSize(DWORD fileSize);
\ No newline at end of file
diff --git a/Samples/ChatAppShare/ShareApp/HelloWorldClient.cpp b/Samples/ChatAppShare/ShareApp/HelloWorldClient.cpp
new file mode 100644
index 0000000..6fa189d
--- /dev/null
+++ b/Samples/ChatAppShare/ShareApp/HelloWorldClient.cpp
@@ -0,0 +1,67 @@
+#include "HelloWorldClient.h"
+#include
+#include
+
+const std::string HelloWorldClient::PIPE_NAME = "\\\\.\\pipe\\HelloWorldService";
+
+std::string HelloWorldClient::GetHelloWorld() {
+ HANDLE hPipe;
+ char buffer[1024];
+ DWORD bytesRead, bytesWritten;
+
+ // Try to open the named pipe
+ while (true) {
+ hPipe = CreateFileA(
+ PIPE_NAME.c_str(),
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ nullptr,
+ OPEN_EXISTING,
+ 0,
+ nullptr
+ );
+
+ if (hPipe != INVALID_HANDLE_VALUE) {
+ break;
+ }
+
+ if (GetLastError() != ERROR_PIPE_BUSY) {
+ std::cerr << "Could not open pipe. Error: " << GetLastError() << std::endl;
+ return "";
+ }
+
+ // All pipe instances are busy, wait a bit
+ if (!WaitNamedPipeA(PIPE_NAME.c_str(), TIMEOUT_MS)) {
+ std::cerr << "Could not open pipe: timeout after " << TIMEOUT_MS << "ms." << std::endl;
+ return "";
+ }
+ }
+
+ // Set pipe to message-read mode
+ DWORD dwMode = PIPE_READMODE_MESSAGE;
+ if (!SetNamedPipeHandleState(hPipe, &dwMode, nullptr, nullptr)) {
+ std::cerr << "SetNamedPipeHandleState failed. Error: " << GetLastError() << std::endl;
+ CloseHandle(hPipe);
+ return "";
+ }
+
+ // Send a request message to the pipe server
+ const char* message = "GET_HELLO_WORLD";
+ if (!WriteFile(hPipe, message, static_cast(strlen(message)), &bytesWritten, nullptr)) {
+ std::cerr << "WriteFile to pipe failed. Error: " << GetLastError() << std::endl;
+ CloseHandle(hPipe);
+ return "";
+ }
+
+ // Read the response from the server
+ if (ReadFile(hPipe, buffer, sizeof(buffer) - 1, &bytesRead, nullptr)) {
+ buffer[bytesRead] = '\0';
+ CloseHandle(hPipe);
+ return std::string(buffer);
+ }
+ else {
+ std::cerr << "ReadFile from pipe failed. Error: " << GetLastError() << std::endl;
+ CloseHandle(hPipe);
+ return "";
+ }
+}
\ No newline at end of file
diff --git a/Samples/ChatAppShare/ShareApp/HelloWorldClient.h b/Samples/ChatAppShare/ShareApp/HelloWorldClient.h
new file mode 100644
index 0000000..900eb72
--- /dev/null
+++ b/Samples/ChatAppShare/ShareApp/HelloWorldClient.h
@@ -0,0 +1,25 @@
+#pragma once
+#include
+#include
+
+/**
+ * HelloWorldClient - A simple client class to communicate with the HelloWorld background service
+ *
+ * Usage:
+ * std::string response = HelloWorldClient::GetHelloWorld();
+ * if (!response.empty()) {
+ * // Use the response
+ * }
+ */
+class HelloWorldClient {
+public:
+ /**
+ * Connects to the HelloWorld background service and requests "Hello world"
+ * @return The response from the service, or empty string if failed
+ */
+ static std::string GetHelloWorld();
+
+private:
+ static const std::string PIPE_NAME;
+ static const int TIMEOUT_MS = 20000; // 20 seconds
+};
\ No newline at end of file
diff --git a/Samples/ChatAppShare/ShareApp/ModernUI.cpp b/Samples/ChatAppShare/ShareApp/ModernUI.cpp
new file mode 100644
index 0000000..ca30eb2
--- /dev/null
+++ b/Samples/ChatAppShare/ShareApp/ModernUI.cpp
@@ -0,0 +1,128 @@
+#include "ModernUI.h"
+#include "UIConstants.h"
+#include
+
+#pragma comment(lib, "gdiplus.lib")
+
+// Modern UI Variables definitions
+HBRUSH hBrushBackground = nullptr;
+HBRUSH hBrushSurface = nullptr;
+HBRUSH hBrushPrimary = nullptr;
+HBRUSH hBrushHover = nullptr;
+HFONT hFontRegular = nullptr;
+HFONT hFontBold = nullptr;
+HFONT hFontTitle = nullptr;
+HPEN hPenBorder = nullptr;
+
+void InitializeModernUI()
+{
+ // Create brushes for modern color scheme
+ hBrushBackground = CreateSolidBrush(COLOR_APP_BACKGROUND);
+ hBrushSurface = CreateSolidBrush(COLOR_SURFACE);
+ hBrushPrimary = CreateSolidBrush(COLOR_PRIMARY);
+ hBrushHover = CreateSolidBrush(COLOR_HOVER);
+
+ // Create modern fonts
+ hFontRegular = CreateFont(16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
+ DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
+ CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Segoe UI");
+
+ hFontBold = CreateFont(16, 0, 0, 0, FW_SEMIBOLD, FALSE, FALSE, FALSE,
+ DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
+ CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Segoe UI");
+
+ hFontTitle = CreateFont(20, 0, 0, 0, FW_SEMIBOLD, FALSE, FALSE, FALSE,
+ DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
+ CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Segoe UI");
+
+ // Create pen for borders
+ hPenBorder = CreatePen(PS_SOLID, 1, COLOR_BORDER);
+
+ // Initialize GDI+
+ Gdiplus::GdiplusStartupInput gdiplusStartupInput;
+ ULONG_PTR gdiplusToken;
+ Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
+}
+
+void CleanupModernUI()
+{
+ // Cleanup GDI objects
+ if (hBrushBackground) DeleteObject(hBrushBackground);
+ if (hBrushSurface) DeleteObject(hBrushSurface);
+ if (hBrushPrimary) DeleteObject(hBrushPrimary);
+ if (hBrushHover) DeleteObject(hBrushHover);
+ if (hFontRegular) DeleteObject(hFontRegular);
+ if (hFontBold) DeleteObject(hFontBold);
+ if (hFontTitle) DeleteObject(hFontTitle);
+ if (hPenBorder) DeleteObject(hPenBorder);
+
+ // Shutdown GDI+
+ Gdiplus::GdiplusShutdown(NULL);
+}
+
+void DrawModernButton(HDC hdc, RECT rect, const std::wstring& text, bool isHovered, bool isPressed)
+{
+ // Create rounded rectangle region
+ HRGN hRgn = CreateRoundRectRgn(rect.left, rect.top, rect.right, rect.bottom, 8, 8);
+
+ // Fill background
+ HBRUSH hBrush = CreateSolidBrush(isPressed ? COLOR_PRIMARY_DARK :
+ isHovered ? COLOR_PRIMARY : COLOR_PRIMARY);
+ FillRgn(hdc, hRgn, hBrush);
+ DeleteObject(hBrush);
+
+ // Draw border with a brush instead of pen
+ HBRUSH borderBrush = CreateSolidBrush(COLOR_BORDER);
+ FrameRgn(hdc, hRgn, borderBrush, 1, 1);
+ DeleteObject(borderBrush);
+ DeleteObject(hRgn);
+
+ // Draw text
+ SetBkMode(hdc, TRANSPARENT);
+ SetTextColor(hdc, RGB(255, 255, 255));
+ SelectObject(hdc, hFontBold);
+
+ DrawText(hdc, text.c_str(), -1, &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
+}
+
+void DrawContactItem(HDC hdc, RECT rect, const Contact& contact, bool isSelected)
+{
+ // Fill background
+ HBRUSH bgBrush = CreateSolidBrush(isSelected ? COLOR_HOVER : COLOR_SURFACE);
+ FillRect(hdc, &rect, bgBrush);
+ DeleteObject(bgBrush);
+
+ // Draw avatar circle
+ int avatarX = rect.left + 12;
+ int avatarY = rect.top + (rect.bottom - rect.top - AVATAR_SIZE) / 2;
+
+ HBRUSH avatarBrush = CreateSolidBrush(COLOR_PRIMARY);
+ HPEN avatarPen = CreatePen(PS_SOLID, 2, contact.isOnline ? RGB(34, 197, 94) : RGB(156, 163, 175));
+
+ SelectObject(hdc, avatarBrush);
+ SelectObject(hdc, avatarPen);
+
+ Ellipse(hdc, avatarX, avatarY, avatarX + AVATAR_SIZE, avatarY + AVATAR_SIZE);
+
+ DeleteObject(avatarBrush);
+ DeleteObject(avatarPen);
+
+ // Draw contact name
+ SetBkMode(hdc, TRANSPARENT);
+ SetTextColor(hdc, COLOR_TEXT_PRIMARY);
+ SelectObject(hdc, hFontBold);
+
+ RECT nameRect = {avatarX + AVATAR_SIZE + 12, rect.top + 8, rect.right - 8, rect.top + 28};
+ DrawText(hdc, contact.name.c_str(), -1, &nameRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
+
+ // Draw status
+ SetTextColor(hdc, COLOR_TEXT_SECONDARY);
+ SelectObject(hdc, hFontRegular);
+
+ RECT statusRect = {avatarX + AVATAR_SIZE + 12, rect.top + 30, rect.right - 8, rect.top + 48};
+ DrawText(hdc, contact.status.c_str(), -1, &statusRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
+
+ // Draw last message preview
+ RECT msgRect = {avatarX + AVATAR_SIZE + 12, rect.top + 50, rect.right - 8, rect.bottom - 8};
+ DrawText(hdc, contact.lastMessage.c_str(), -1, &msgRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
+}
\ No newline at end of file
diff --git a/Samples/ChatAppShare/ShareApp/ModernUI.h b/Samples/ChatAppShare/ShareApp/ModernUI.h
new file mode 100644
index 0000000..3cb9ea7
--- /dev/null
+++ b/Samples/ChatAppShare/ShareApp/ModernUI.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include
+#include
+#include "ChatModels.h"
+
+// Modern UI Variables
+extern HBRUSH hBrushBackground;
+extern HBRUSH hBrushSurface;
+extern HBRUSH hBrushPrimary;
+extern HBRUSH hBrushHover;
+extern HFONT hFontRegular;
+extern HFONT hFontBold;
+extern HFONT hFontTitle;
+extern HPEN hPenBorder;
+
+// Modern UI Functions
+void InitializeModernUI();
+void CleanupModernUI();
+void DrawModernButton(HDC hdc, RECT rect, const std::wstring& text, bool isHovered, bool isPressed);
+void DrawContactItem(HDC hdc, RECT rect, const Contact& contact, bool isSelected);
\ No newline at end of file
diff --git a/Samples/ChatAppShare/ShareApp/PackageIdentity.cpp b/Samples/ChatAppShare/ShareApp/PackageIdentity.cpp
new file mode 100644
index 0000000..4f4ace9
--- /dev/null
+++ b/Samples/ChatAppShare/ShareApp/PackageIdentity.cpp
@@ -0,0 +1,463 @@
+#include "framework.h"
+#include "PackageIdentity.h"
+#include
+#include
+#include
+#include
+#include
+
+// Package Identity Variables
+bool g_isSparsePackageSupported = false;
+bool g_isRunningWithIdentity = false;
+bool g_packageIdentityInitialized = false;
+
+// Initialize package identity management
+bool InitializePackageIdentity()
+{
+ if (g_packageIdentityInitialized)
+ return true;
+
+ OutputDebugStringW(L"ChatApp: Initializing package identity management...\n");
+
+ // Check OS support for sparse packages
+ g_isSparsePackageSupported = IsSparsePackageSupported();
+
+ // Check if already running with identity
+ g_isRunningWithIdentity = IsRunningWithIdentity();
+
+ g_packageIdentityInitialized = true;
+
+ wchar_t statusLog[256];
+ swprintf_s(statusLog, L"ChatApp: Package Identity Status - Sparse supported: %s, Has identity: %s\n",
+ g_isSparsePackageSupported ? L"Yes" : L"No",
+ g_isRunningWithIdentity ? L"Yes" : L"No");
+ OutputDebugStringW(statusLog);
+
+ return true;
+}
+
+// Register package with external location (improved implementation)
+HRESULT RegisterPackageWithExternalLocation(const std::wstring& externalLocation, const std::wstring& packagePath)
+{
+ try
+ {
+ OutputDebugStringW(L"ChatApp: Attempting to register package with external location...\n");
+
+ wchar_t logBuffer[512];
+ swprintf_s(logBuffer, L"ChatApp: External location: %s\n", externalLocation.c_str());
+ OutputDebugStringW(logBuffer);
+ swprintf_s(logBuffer, L"ChatApp: Package path: %s\n", packagePath.c_str());
+ OutputDebugStringW(logBuffer);
+
+ // Check if the package file exists
+ DWORD fileAttributes = GetFileAttributesW(packagePath.c_str());
+ if (fileAttributes == INVALID_FILE_ATTRIBUTES)
+ {
+ OutputDebugStringW(L"ChatApp: Package file not found, trying PowerShell registration method.\n");
+ return RegisterPackageWithExternalLocationPowerShell(externalLocation, packagePath);
+ }
+
+ // Try PowerShell registration first as it's more reliable
+ HRESULT powershellResult = RegisterPackageWithExternalLocationPowerShell(externalLocation, packagePath);
+ if (SUCCEEDED(powershellResult))
+ {
+ OutputDebugStringW(L"ChatApp: Package registration via PowerShell succeeded.\n");
+ return powershellResult;
+ }
+
+ // If PowerShell failed, log the error
+ wchar_t errorLog[256];
+ swprintf_s(errorLog, L"ChatApp: PowerShell registration failed with HRESULT: 0x%08X\n", powershellResult);
+ OutputDebugStringW(errorLog);
+
+ // For now, return the PowerShell result since we don't have other registration methods implemented
+ return powershellResult;
+ }
+ catch (...)
+ {
+ OutputDebugStringW(L"ChatApp: Exception occurred during package registration\n");
+ return E_FAIL;
+ }
+}
+
+// Alternative implementation using PowerShell for package registration
+HRESULT RegisterPackageWithExternalLocationPowerShell(const std::wstring& externalLocation, const std::wstring& packagePath)
+{
+ try
+ {
+ OutputDebugStringW(L"ChatApp: Attempting PowerShell package registration...\n");
+
+ // Check if the package file exists
+ DWORD fileAttributes = GetFileAttributesW(packagePath.c_str());
+ if (fileAttributes == INVALID_FILE_ATTRIBUTES)
+ {
+ wchar_t errorLog[512];
+ swprintf_s(errorLog, L"ChatApp: Package file not found at: %s\n", packagePath.c_str());
+ OutputDebugStringW(errorLog);
+ return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+ }
+
+ // Build PowerShell command for MSIX package registration with external location
+ // Use Add-AppxPackage with -ExternalLocation parameter
+ std::wstring powershellCmd = L"powershell.exe -ExecutionPolicy Bypass -Command \"";
+ powershellCmd += L"try { ";
+ powershellCmd += L"Add-AppxPackage -Path '";
+ powershellCmd += packagePath;
+ powershellCmd += L"' -ExternalLocation '";
+ powershellCmd += externalLocation;
+ powershellCmd += L"' -ForceTargetApplicationShutdown; ";
+ powershellCmd += L"Write-Host 'Package registration successful'; ";
+ powershellCmd += L"exit 0; ";
+ powershellCmd += L"} catch { ";
+ powershellCmd += L"Write-Host ('Package registration failed: ' + $_.Exception.Message); ";
+ powershellCmd += L"exit 1; ";
+ powershellCmd += L"}\"";
+
+ wchar_t logBuffer[1024];
+ swprintf_s(logBuffer, L"ChatApp: PowerShell command: %s\n", powershellCmd.c_str());
+ OutputDebugStringW(logBuffer);
+
+ // Execute PowerShell command
+ STARTUPINFOW si = {};
+ PROCESS_INFORMATION pi = {};
+ si.cb = sizeof(si);
+ si.dwFlags = STARTF_USESHOWWINDOW;
+ si.wShowWindow = SW_HIDE;
+
+ BOOL success = CreateProcessW(
+ nullptr,
+ const_cast(powershellCmd.c_str()),
+ nullptr,
+ nullptr,
+ FALSE,
+ CREATE_NO_WINDOW,
+ nullptr,
+ nullptr,
+ &si,
+ &pi
+ );
+
+ if (success)
+ {
+ OutputDebugStringW(L"ChatApp: PowerShell process started, waiting for completion...\n");
+
+ // Wait for PowerShell to complete (with timeout)
+ DWORD waitResult = WaitForSingleObject(pi.hProcess, 60000); // Increased timeout for package registration
+
+ DWORD exitCode = 0;
+ if (waitResult == WAIT_OBJECT_0)
+ {
+ GetExitCodeProcess(pi.hProcess, &exitCode);
+ wchar_t exitLog[256];
+ swprintf_s(exitLog, L"ChatApp: PowerShell process completed with exit code: %d\n", exitCode);
+ OutputDebugStringW(exitLog);
+ }
+ else if (waitResult == WAIT_TIMEOUT)
+ {
+ OutputDebugStringW(L"ChatApp: PowerShell process timed out. Package registration may still be in progress.\n");
+ TerminateProcess(pi.hProcess, 1);
+ exitCode = 1;
+ }
+ else
+ {
+ DWORD waitError = GetLastError();
+ wchar_t waitLog[256];
+ swprintf_s(waitLog, L"ChatApp: Wait failed with error: %d\n", waitError);
+ OutputDebugStringW(waitLog);
+ exitCode = 1;
+ }
+
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+
+ return (exitCode == 0) ? S_OK : E_FAIL;
+ }
+ else
+ {
+ DWORD error = GetLastError();
+ wchar_t errorLog[256];
+ swprintf_s(errorLog, L"ChatApp: Failed to start PowerShell process. Error: %d\n", error);
+ OutputDebugStringW(errorLog);
+ return HRESULT_FROM_WIN32(error);
+ }
+ }
+ catch (...)
+ {
+ OutputDebugStringW(L"ChatApp: Exception occurred during PowerShell package registration\n");
+ return E_FAIL;
+ }
+}
+
+// Relaunch the current application
+void RelaunchApplication()
+{
+ OutputDebugStringW(L"ChatApp: Attempting to relaunch application...\n");
+
+ wchar_t exePath[MAX_PATH] = {0};
+ DWORD len = GetModuleFileNameW(nullptr, exePath, MAX_PATH);
+ if (len == 0 || len == MAX_PATH)
+ {
+ OutputDebugStringW(L"ChatApp: Failed to get executable path for relaunch.\n");
+ return;
+ }
+
+ // Log the executable path
+ wchar_t logBuffer[512];
+ swprintf_s(logBuffer, L"ChatApp: Relaunching: %s\n", exePath);
+ OutputDebugStringW(logBuffer);
+
+ // Add a small delay to allow package registration to complete
+ Sleep(2000);
+
+ // Use ShellExecuteW to relaunch the current executable
+ HINSTANCE result = ShellExecuteW(nullptr, L"open", exePath, nullptr, nullptr, SW_SHOWNORMAL);
+
+ // Fix: Use proper casting for x64 compatibility
+ INT_PTR resultValue = reinterpret_cast(result);
+ if (resultValue <= 32)
+ {
+ // Log the error
+ wchar_t errorLog[256];
+ swprintf_s(errorLog, L"ChatApp: Failed to relaunch application. ShellExecute error code: %lld\n",
+ static_cast(resultValue));
+ OutputDebugStringW(errorLog);
+
+ // Try alternative relaunch method using CreateProcess
+ OutputDebugStringW(L"ChatApp: Trying alternative relaunch method...\n");
+
+ STARTUPINFOW si = {};
+ PROCESS_INFORMATION pi = {};
+ si.cb = sizeof(si);
+ si.dwFlags = STARTF_USESHOWWINDOW;
+ si.wShowWindow = SW_SHOWNORMAL;
+
+ BOOL createResult = CreateProcessW(
+ exePath,
+ nullptr,
+ nullptr,
+ nullptr,
+ FALSE,
+ 0,
+ nullptr,
+ nullptr,
+ &si,
+ &pi
+ );
+
+ if (createResult)
+ {
+ OutputDebugStringW(L"ChatApp: Alternative relaunch method succeeded.\n");
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ }
+ else
+ {
+ DWORD createError = GetLastError();
+ wchar_t createErrorLog[256];
+ swprintf_s(createErrorLog, L"ChatApp: Alternative relaunch also failed. Error: %d\n", createError);
+ OutputDebugStringW(createErrorLog);
+ }
+ }
+ else
+ {
+ OutputDebugStringW(L"ChatApp: Application relaunch initiated successfully.\n");
+ }
+}
+
+// Checks if the OS version is Windows 10 2004 (build 19041) or later
+bool IsSparsePackageSupported()
+{
+ // Windows 10 2004 is version 10.0.19041
+ OSVERSIONINFOEXW osvi = {};
+ osvi.dwOSVersionInfoSize = sizeof(osvi);
+
+ // Get the actual version using RtlGetVersion (undocumented but reliable)
+ typedef LONG (WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOEXW);
+ HMODULE hMod = ::GetModuleHandleW(L"ntdll.dll");
+ if (hMod) {
+ RtlGetVersionPtr fxPtr = (RtlGetVersionPtr)::GetProcAddress(hMod, "RtlGetVersion");
+ if (fxPtr != nullptr) {
+ fxPtr((PRTL_OSVERSIONINFOEXW)&osvi);
+
+ // Log version information for debugging
+ wchar_t log[256];
+ swprintf_s(log, L"ChatApp: Current OS Version: %u.%u.%u\n",
+ osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber);
+ OutputDebugStringW(log);
+ }
+ }
+
+ // Compare with required version (Windows 10 2004 build 19041)
+ if (osvi.dwMajorVersion > 10 ||
+ (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion > 0) ||
+ (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0 && osvi.dwBuildNumber >= 19041))
+ {
+ OutputDebugStringW(L"ChatApp: Sparse package is supported on this OS.\n");
+ return true;
+ }
+
+ OutputDebugStringW(L"ChatApp: Sparse package is NOT supported on this OS.\n");
+ return false;
+}
+
+// Returns true if the app is running with package identity
+bool IsRunningWithIdentity()
+{
+ UINT32 length = 0;
+ LONG rc = GetCurrentPackageFullName(&length, nullptr);
+
+ if (rc == ERROR_INSUFFICIENT_BUFFER)
+ {
+ std::vector packageFullName(length);
+ rc = GetCurrentPackageFullName(&length, packageFullName.data());
+ if (rc == ERROR_SUCCESS)
+ {
+ OutputDebugStringW(L"ChatApp: Running with package identity.\n");
+ return true;
+ }
+ }
+
+ OutputDebugStringW(L"ChatApp: Not running with package identity.\n");
+ return false;
+}
+
+// Helper to get the directory of the current executable
+std::wstring GetExecutableDirectory()
+{
+ wchar_t exePath[MAX_PATH] = {0};
+ DWORD len = GetModuleFileNameW(nullptr, exePath, MAX_PATH);
+ if (len == 0 || len == MAX_PATH)
+ {
+ OutputDebugStringW(L"ChatApp: Failed to get executable path.\n");
+ return L"";
+ }
+
+ std::wstring path(exePath);
+ size_t pos = path.find_last_of(L"\\/");
+ if (pos != std::wstring::npos)
+ path = path.substr(0, pos);
+
+ return path;
+}
+
+// Initialize package identity-specific flows and features
+void InitializePackageIdentityFlow()
+{
+ OutputDebugStringW(L"ChatApp: Initializing package identity-specific flows...\n");
+
+ if (!g_isRunningWithIdentity) {
+ OutputDebugStringW(L"ChatApp: Not running with package identity - skipping identity-specific flows.\n");
+ return;
+ }
+
+ // TODO: Add package identity-specific initialization here:
+
+ // 1. Single Instance Management
+ // - Check for existing app instances
+ // - Register current instance
+ // - Handle instance redirection
+
+ // 2. Share Target Registration
+ // - Check for share target activation
+ // - Initialize share target handlers
+ // - Set up cross-process communication
+
+ // 3. Enhanced Security Features
+ // - Initialize secure file handling
+ // - Set up identity-based permissions
+ // - Enable enhanced data protection
+
+ // 4. App Model Integration
+ // - Register activation handlers
+ // - Set up background task support
+ // - Initialize notification system
+
+ OutputDebugStringW(L"ChatApp: Package identity flows initialized (placeholder - features to be implemented).\n");
+}
+
+// Helper to validate MSIX package existence and basic properties
+bool ValidateMsixPackage(const std::wstring& packagePath)
+{
+ OutputDebugStringW(L"ChatApp: Validating MSIX package...\n");
+
+ // Check if file exists
+ DWORD fileAttributes = GetFileAttributesW(packagePath.c_str());
+ if (fileAttributes == INVALID_FILE_ATTRIBUTES)
+ {
+ wchar_t errorLog[512];
+ swprintf_s(errorLog, L"ChatApp: MSIX package not found at: %s\n", packagePath.c_str());
+ OutputDebugStringW(errorLog);
+ return false;
+ }
+
+ // Check if it's a file (not a directory)
+ if (fileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ {
+ OutputDebugStringW(L"ChatApp: Package path points to a directory, not a file.\n");
+ return false;
+ }
+
+ // Check file extension
+ size_t dotPos = packagePath.find_last_of(L'.');
+ if (dotPos == std::wstring::npos)
+ {
+ OutputDebugStringW(L"ChatApp: Package file has no extension.\n");
+ return false;
+ }
+
+ std::wstring extension = packagePath.substr(dotPos);
+ std::transform(extension.begin(), extension.end(), extension.begin(), ::towlower);
+
+ if (extension != L".msix" && extension != L".appx")
+ {
+ wchar_t extLog[256];
+ swprintf_s(extLog, L"ChatApp: Package has unexpected extension: %s\n", extension.c_str());
+ OutputDebugStringW(extLog);
+ return false;
+ }
+
+ // Get file size
+ HANDLE hFile = CreateFileW(packagePath.c_str(), GENERIC_READ, FILE_SHARE_READ,
+ nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
+ if (hFile != INVALID_HANDLE_VALUE)
+ {
+ LARGE_INTEGER fileSize;
+ if (GetFileSizeEx(hFile, &fileSize))
+ {
+ wchar_t sizeLog[256];
+ swprintf_s(sizeLog, L"ChatApp: Package size: %lld bytes\n", fileSize.QuadPart);
+ OutputDebugStringW(sizeLog);
+ }
+ CloseHandle(hFile);
+ }
+
+ OutputDebugStringW(L"ChatApp: MSIX package validation passed.\n");
+ return true;
+}
+
+// Get current package identity status as a formatted string
+std::wstring GetPackageIdentityStatus()
+{
+ std::wstring status = L"ChatApp Package Identity Status:\n";
+ status += L"- Sparse package supported: " + std::wstring(g_isSparsePackageSupported ? L"Yes" : L"No") + L"\n";
+ status += L"- Running with identity: " + std::wstring(g_isRunningWithIdentity ? L"Yes" : L"No") + L"\n";
+ status += L"- Initialized: " + std::wstring(g_packageIdentityInitialized ? L"Yes" : L"No") + L"\n";
+
+ if (g_isRunningWithIdentity)
+ {
+ // Try to get package full name
+ UINT32 length = 0;
+ LONG rc = GetCurrentPackageFullName(&length, nullptr);
+ if (rc == ERROR_INSUFFICIENT_BUFFER && length > 0)
+ {
+ std::vector packageFullName(length);
+ rc = GetCurrentPackageFullName(&length, packageFullName.data());
+ if (rc == ERROR_SUCCESS)
+ {
+ status += L"- Package full name: " + std::wstring(packageFullName.data()) + L"\n";
+ }
+ }
+ }
+
+ return status;
+}
\ No newline at end of file
diff --git a/Samples/ChatAppShare/ShareApp/PackageIdentity.h b/Samples/ChatAppShare/ShareApp/PackageIdentity.h
new file mode 100644
index 0000000..e97fa85
--- /dev/null
+++ b/Samples/ChatAppShare/ShareApp/PackageIdentity.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include
+#include
+
+// Package Identity Variables
+extern bool g_isSparsePackageSupported;
+extern bool g_isRunningWithIdentity;
+extern bool g_packageIdentityInitialized;
+
+// Package Identity Management functions
+bool IsSparsePackageSupported();
+bool IsRunningWithIdentity();
+bool InitializePackageIdentity();
+void InitializePackageIdentityFlow();
+std::wstring GetExecutableDirectory();
+HRESULT RegisterPackageWithExternalLocation(const std::wstring& externalLocation, const std::wstring& packagePath);
+HRESULT RegisterPackageWithExternalLocationPowerShell(const std::wstring& externalLocation, const std::wstring& packagePath);
+void RelaunchApplication();
+
+// Helper functions
+bool ValidateMsixPackage(const std::wstring& packagePath);
+std::wstring GetPackageIdentityStatus();
\ No newline at end of file
diff --git a/Samples/ChatAppShare/ShareApp/Resource.h b/Samples/ChatAppShare/ShareApp/Resource.h
new file mode 100644
index 0000000..e41d7d3
--- /dev/null
+++ b/Samples/ChatAppShare/ShareApp/Resource.h
@@ -0,0 +1,48 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by SampleChatAppWithShare.rc
+
+#define IDS_APP_TITLE 103
+
+#define IDR_MAINFRAME 128
+#define IDD_SAMPLECHATAPPWITHSHARE_DIALOG 102
+#define IDD_ABOUTBOX 103
+#define IDD_CONTACT_SELECTION 104
+#define IDM_ABOUT 105
+#define IDM_EXIT 106
+#define IDI_SAMPLECHATAPPWITHSHARE 107
+#define IDI_SMALL 108
+#define IDC_SAMPLECHATAPPWITHSHARE 109
+#define IDC_MYICON 2
+
+// Chat Application Controls
+#define IDC_CONTACTS_LIST 1001
+#define IDC_CHAT_DISPLAY 1002
+#define IDC_MESSAGE_INPUT 1003
+#define IDC_SEND_BUTTON 1004
+#define IDC_CONTACT_NAME 1005
+#define IDC_SHARE_FILE_BUTTON 1006
+#define IDC_SHARED_FILES_LIST 1007
+
+// Contact Selection Dialog Controls
+#define IDC_CONTACT_SELECTION_LIST 1008
+#define IDC_SELECT_CONTACT_BUTTON 1009
+#define IDC_CANCEL_SELECTION_BUTTON 1010
+#define IDC_SHARE_MESSAGE_EDIT 1011
+#define IDC_DIALOG_TITLE 1012
+
+#ifndef IDC_STATIC
+#define IDC_STATIC -1
+#endif
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+
+#define _APS_NO_MFC 130
+#define _APS_NEXT_RESOURCE_VALUE 129
+#define _APS_NEXT_COMMAND_VALUE 32771
+#define _APS_NEXT_CONTROL_VALUE 1013
+#define _APS_NEXT_SYMED_VALUE 110
+#endif
+#endif
diff --git a/Samples/ChatAppShare/ShareApp/ShareApp.cpp b/Samples/ChatAppShare/ShareApp/ShareApp.cpp
new file mode 100644
index 0000000..d0ecc24
--- /dev/null
+++ b/Samples/ChatAppShare/ShareApp/ShareApp.cpp
@@ -0,0 +1,469 @@
+// SampleChatAppWithShare.cpp : Defines the entry point for the application.
+//
+
+#include "framework.h"
+#include "ShareApp.h"
+#include "UIConstants.h"
+#include "ChatModels.h"
+#include "ModernUI.h"
+#include "ChatManager.h"
+#include "FileManager.h"
+#include "UIManager.h"
+#include "PackageIdentity.h"
+#include "ShareTargetManager.h"
+#include "HelloWorldClient.h"
+#include "WindowProcs.h"
+#include
+#include
+#include
+#include
+#include
+
+#pragma comment(lib, "comctl32.lib")
+#pragma comment(lib, "shell32.lib")
+#pragma comment(lib, "uxtheme.lib")
+#pragma comment(lib, "ole32.lib")
+// Add WinRT libraries to fix linking error
+#pragma comment(lib, "windowsapp.lib")
+#pragma comment(lib, "runtimeobject.lib")
+
+using namespace winrt;
+using namespace Windows::Foundation;
+using namespace Windows::ApplicationModel;
+using namespace Windows::ApplicationModel::Activation;
+using namespace Windows::ApplicationModel::DataTransfer;
+using namespace Windows::ApplicationModel::DataTransfer::ShareTarget;
+
+// Global Variables:
+HINSTANCE hInst; // current instance
+WCHAR szTitle[MAX_LOADSTRING]; // The title bar text
+WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
+
+// Global flag to track if we're in share-only mode
+bool g_isShareOnlyMode = false;
+
+// Forward declarations of functions included in this code module:
+ATOM MyRegisterClass(HINSTANCE hInstance);
+BOOL InitInstance(HINSTANCE, int);
+LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
+INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
+
+int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
+ _In_opt_ HINSTANCE hPrevInstance,
+ _In_ LPWSTR lpCmdLine,
+ _In_ int nCmdShow)
+{
+ UNREFERENCED_PARAMETER(hPrevInstance);
+ UNREFERENCED_PARAMETER(lpCmdLine);
+
+ // Init package identity checks
+ InitializePackageIdentity();
+
+ // Initialize WinRT with proper error handling
+ try
+ {
+ winrt::init_apartment();
+ OutputDebugStringW(L"ChatApp: WinRT initialized successfully.\n");
+ }
+ catch (hresult_error const& ex)
+ {
+ std::wstring errorMsg = L"ChatApp: WinRT initialization failed: " + std::wstring(ex.message().c_str()) +
+ L" (HRESULT: 0x" + std::to_wstring(static_cast(ex.code())) + L")\n";
+ OutputDebugStringW(errorMsg.c_str());
+ }
+ catch (...)
+ {
+ OutputDebugStringW(L"ChatApp: WinRT initialization failed with unknown error.\n");
+ }
+
+ // Initialize Share Target Manager
+ ShareTargetManager::Initialize();
+ // Add 3 mins sleep to allow time for service to start when debugging
+
+ // Note: Don't process share target activation here - UI isn't created yet
+ // This will be handled after UI creation in WndProc WM_CREATE
+
+ // Check if this is a share target activation to determine if we need the main window
+ if (g_isRunningWithIdentity && ShareTargetManager::IsShareTargetActivation())
+ {
+ g_isShareOnlyMode = true;
+ OutputDebugStringW(L"ChatApp: Running in share-only mode - main window will not be created\n");
+ }
+
+ if (g_isSparsePackageSupported && !g_isRunningWithIdentity)
+ {
+ std::wstring executableDir = GetExecutableDirectory();
+ std::wstring packagePath = executableDir + L"\\Weixin_1.0.2.0_x86__v4k3sbdawh17a.msix";
+
+ // Validate the MSIX package before attempting registration
+ if (ValidateMsixPackage(packagePath))
+ {
+ HRESULT result = RegisterPackageWithExternalLocation(executableDir, packagePath);
+ if (SUCCEEDED(result))
+ {
+ OutputDebugStringW(L"ChatApp: Package registration succeeded. Relaunching...\n");
+ RelaunchApplication();
+ return 0; // Exit after relaunch
+ }
+ else
+ {
+ // Log the error but continue without package identity
+ wchar_t errorLog[256];
+ swprintf_s(errorLog, L"ChatApp: Failed to register package. HRESULT: 0x%08X. Continuing without package identity.\n", result);
+ OutputDebugStringW(errorLog);
+ }
+ }
+ else
+ {
+ OutputDebugStringW(L"ChatApp: MSIX package validation failed. Continuing without package identity.\n");
+ }
+ }
+ else if (g_isRunningWithIdentity)
+ {
+ std::string response = HelloWorldClient::GetHelloWorld();
+
+ if (!response.empty()) {
+ OutputDebugStringW(L"Response from service: ");
+ }
+ else {
+ OutputDebugStringW(L"Failed to get response from service.");
+ OutputDebugStringW(L"Make sure the HelloWorld service is running.");
+ }
+
+ // Process share target activation using the ShareTargetManager
+ ShareTargetManager::ProcessActivationArgs();
+ }
+ else
+ {
+ // Log the current status
+ std::wstring status = GetPackageIdentityStatus();
+ OutputDebugStringW(status.c_str());
+ }
+
+ // Initialize COM for shell operations
+ CoInitialize(NULL);
+
+ // Initialize common controls
+ INITCOMMONCONTROLSEX icex;
+ icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
+ icex.dwICC = ICC_LISTVIEW_CLASSES | ICC_STANDARD_CLASSES;
+ InitCommonControlsEx(&icex);
+
+ // Initialize global strings
+ LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
+ LoadStringW(hInstance, IDC_SAMPLECHATAPPWITHSHARE, szWindowClass, MAX_LOADSTRING);
+
+ if (!g_isShareOnlyMode)
+ {
+ // Only register window class if we're not in share-only mode
+ MyRegisterClass(hInstance);
+
+ // Initialize modern UI
+ InitializeModernUI();
+ }
+
+ // Initialize dummy contacts (needed for share target)
+ InitializeContacts();
+
+ if (g_isShareOnlyMode)
+ {
+ // In share-only mode, process the share target directly without creating a window
+ OutputDebugStringW(L"ChatApp: Processing share target in share-only mode\n");
+ ShareTargetManager::ProcessActivationArgs();
+ }
+ else
+ {
+ // Normal mode: create and show the main window
+ if (!InitInstance(hInstance, nCmdShow))
+ {
+ return FALSE;
+ }
+ }
+
+ HACCEL hAccelTable = nullptr;
+ if (!g_isShareOnlyMode)
+ {
+ hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_SAMPLECHATAPPWITHSHARE));
+ }
+
+ MSG msg;
+
+ // Main message loop:
+ while (GetMessage(&msg, nullptr, 0, 0))
+ {
+ if (!g_isShareOnlyMode && !TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ else if (g_isShareOnlyMode)
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+ CoUninitialize();
+ return (int) msg.wParam;
+}
+
+//
+// FUNCTION: MyRegisterClass()
+//
+// PURPOSE: Registers the window class.
+//
+ATOM MyRegisterClass(HINSTANCE hInstance)
+{
+ WNDCLASSEXW wcex;
+
+ wcex.cbSize = sizeof(WNDCLASSEX);
+
+ wcex.style = CS_HREDRAW | CS_VREDRAW;
+ wcex.lpfnWndProc = WndProc;
+ wcex.cbClsExtra = 0;
+ wcex.cbWndExtra = 0;
+ wcex.hInstance = hInstance;
+ wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_SAMPLECHATAPPWITHSHARE));
+ wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
+ wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
+ wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_SAMPLECHATAPPWITHSHARE);
+ wcex.lpszClassName = szWindowClass;
+ wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
+
+ return RegisterClassExW(&wcex);
+}
+
+//
+// FUNCTION: InitInstance(HINSTANCE, int)
+//
+// PURPOSE: Saves instance handle and creates main window
+//
+// COMMENTS:
+//
+// In this function, we save the instance handle in a global variable and
+// create and display the main program window.
+//
+BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
+{
+ hInst = hInstance; // Store instance handle in our global variable
+
+ HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT, 0, 1200, 700, nullptr, nullptr, hInstance, nullptr);
+
+ if (!hWnd)
+ {
+ return FALSE;
+ }
+
+ ShowWindow(hWnd, nCmdShow);
+ UpdateWindow(hWnd);
+
+ return TRUE;
+}
+
+//
+// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
+//
+// PURPOSE: Processes messages for the main window.
+//
+LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message)
+ {
+ case WM_CREATE:
+ CreateChatUI(hWnd);
+
+ // Process share target activation after UI is created
+ if (g_isRunningWithIdentity)
+ {
+ ShareTargetManager::ProcessActivationArgs();
+ }
+ break;
+
+ case WM_SIZE:
+ ResizeChatUI(hWnd);
+ break;
+
+ case WM_CTLCOLORSTATIC:
+ {
+ HDC hdcStatic = (HDC)wParam;
+ SetTextColor(hdcStatic, COLOR_TEXT_PRIMARY);
+ SetBkColor(hdcStatic, COLOR_APP_BACKGROUND);
+ return (INT_PTR)hBrushBackground;
+ }
+
+ case WM_CTLCOLOREDIT:
+ {
+ HDC hdcEdit = (HDC)wParam;
+ SetTextColor(hdcEdit, COLOR_TEXT_PRIMARY);
+ SetBkColor(hdcEdit, COLOR_SURFACE);
+ return (INT_PTR)hBrushSurface;
+ }
+
+ case WM_CTLCOLORLISTBOX:
+ {
+ HDC hdcList = (HDC)wParam;
+ SetTextColor(hdcList, COLOR_TEXT_PRIMARY);
+ SetBkColor(hdcList, COLOR_SURFACE);
+ return (INT_PTR)hBrushSurface;
+ }
+
+ case WM_PAINT:
+ {
+ PAINTSTRUCT ps;
+ HDC hdc = BeginPaint(hWnd, &ps);
+
+ // Fill the main window background with modern color
+ RECT rect;
+ GetClientRect(hWnd, &rect);
+ FillRect(hdc, &rect, hBrushBackground);
+
+ EndPaint(hWnd, &ps);
+ }
+ break;
+
+ case WM_COMMAND:
+ {
+ int wmId = LOWORD(wParam);
+ int wmEvent = HIWORD(wParam);
+
+ // Parse the menu selections:
+ switch (wmId)
+ {
+ case IDM_ABOUT:
+ DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
+ break;
+ case IDM_EXIT:
+ DestroyWindow(hWnd);
+ break;
+ case IDC_CONTACTS_LIST:
+ if (wmEvent == LBN_SELCHANGE) {
+ int selectedIndex = (int)::SendMessage(hContactsList, LB_GETCURSEL, 0, 0);
+ LoadContactChat(selectedIndex);
+ UpdateSharedFilesList();
+ }
+ break;
+ case IDC_SEND_BUTTON:
+ SendChatMessage();
+ break;
+ case IDC_SHARE_FILE_BUTTON:
+ ShareFile();
+ break;
+ case IDC_SHARED_FILES_LIST:
+ if (wmEvent == LBN_DBLCLK) {
+ int selectedFile = (int)::SendMessage(hSharedFilesList, LB_GETCURSEL, 0, 0);
+ OpenSharedFile(selectedFile);
+ }
+ break;
+ case IDC_MESSAGE_INPUT:
+ if (wmEvent == EN_CHANGE) {
+ // Enable/disable send button based on input with visual feedback
+ WCHAR buffer[1024];
+ GetWindowText(hMessageInput, buffer, 1024);
+ bool hasText = wcslen(buffer) > 0;
+ EnableWindow(hSendButton, hasText);
+ InvalidateRect(hSendButton, NULL, FALSE);
+ }
+ break;
+ case 2000: // Test WinRT Share Target Status
+ {
+ // Use ShareTargetManager to get status
+ std::wstring statusInfo = ShareTargetManager::GetShareTargetStatus();
+ MessageBoxW(hWnd, statusInfo.c_str(), L"WinRT Share Target Status", MB_OK | MB_ICONINFORMATION);
+ }
+ break;
+ default:
+ return DefWindowProc(hWnd, message, wParam, lParam);
+ }
+ }
+ break;
+
+ case WM_TIMER:
+ ProcessAutoReply(hWnd, (int)wParam);
+ break;
+
+ case WM_KEYDOWN:
+ {
+ if (GetFocus() == hMessageInput && wParam == VK_RETURN) {
+ if (!(GetKeyState(VK_SHIFT) & 0x8000)) {
+ // Enter without Shift sends the message
+ SendChatMessage();
+ return 0;
+ }
+ }
+ }
+ break;
+
+ case WM_DESTROY:
+ CleanupModernUI();
+ PostQuitMessage(0);
+ break;
+
+ default:
+ return DefWindowProc(hWnd, message, wParam, lParam);
+ }
+ return 0;
+}
+
+// Message handler for about box.
+INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ UNREFERENCED_PARAMETER(lParam);
+ switch (message)
+ {
+ case WM_INITDIALOG:
+ {
+ // Add WinRT and package identity information to the about dialog
+ std::wstring aboutText = L"Chat Application with WinRT Share Target Support\n\n";
+
+ // Test WinRT status
+ try
+ {
+ winrt::check_hresult(S_OK);
+ aboutText += L"? WinRT Status: ? Initialized and Working\n";
+
+ if (g_isRunningWithIdentity)
+ {
+ if (ShareTargetManager::IsShareTargetActivation())
+ {
+ aboutText += L"?? Share Target: ? Currently Activated via Windows Share Sheet\n";
+ }
+ else
+ {
+ aboutText += L"?? Share Target: ? Ready for Activation\n";
+ }
+ }
+ else
+ {
+ aboutText += L"?? Share Target: ? Package Identity Required\n";
+ }
+ }
+ catch (...)
+ {
+ aboutText += L"?? WinRT Status: ? Error or Not Available\n";
+ }
+
+ aboutText += L"?? Package Identity: " + std::wstring(g_isRunningWithIdentity ? L"? Available" : L"? Not Available") + L"\n";
+ aboutText += L"?? Sparse Package Support: " + std::wstring(g_isSparsePackageSupported ? L"? Supported" : L"? Not Supported") + L"\n\n";
+ aboutText += L"Current Features:\n";
+ aboutText += L"? WinRT Runtime Integration\n";
+ aboutText += L"? Windows Share Target Support\n";
+ aboutText += L"? Package Identity Management\n";
+ aboutText += L"? MSIX Package Registration\n";
+ aboutText += L"? Modern Chat UI\n\n";
+ aboutText += GetPackageIdentityStatus();
+
+ SetDlgItemTextW(hDlg, IDC_STATIC, aboutText.c_str());
+ return (INT_PTR)TRUE;
+ }
+
+ case WM_COMMAND:
+ if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
+ {
+ EndDialog(hDlg, LOWORD(wParam));
+ return (INT_PTR)TRUE;
+ }
+ break;
+ }
+ return (INT_PTR)FALSE;
+}
diff --git a/Samples/ChatAppShare/ShareApp/ShareApp.exe.manifest b/Samples/ChatAppShare/ShareApp/ShareApp.exe.manifest
new file mode 100644
index 0000000..0247996
--- /dev/null
+++ b/Samples/ChatAppShare/ShareApp/ShareApp.exe.manifest
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/Samples/ChatAppShare/ShareApp/ShareApp.h b/Samples/ChatAppShare/ShareApp/ShareApp.h
new file mode 100644
index 0000000..d00d47e
--- /dev/null
+++ b/Samples/ChatAppShare/ShareApp/ShareApp.h
@@ -0,0 +1,3 @@
+#pragma once
+
+#include "resource.h"
diff --git a/Samples/ChatAppShare/ShareApp/ShareApp.ico b/Samples/ChatAppShare/ShareApp/ShareApp.ico
new file mode 100644
index 0000000..b3ec03b
Binary files /dev/null and b/Samples/ChatAppShare/ShareApp/ShareApp.ico differ
diff --git a/Samples/ChatAppShare/ShareApp/ShareApp.rc b/Samples/ChatAppShare/ShareApp/ShareApp.rc
new file mode 100644
index 0000000..83cf040
Binary files /dev/null and b/Samples/ChatAppShare/ShareApp/ShareApp.rc differ
diff --git a/Samples/ChatAppShare/ShareApp/ShareApp.vcxproj b/Samples/ChatAppShare/ShareApp/ShareApp.vcxproj
new file mode 100644
index 0000000..b230869
--- /dev/null
+++ b/Samples/ChatAppShare/ShareApp/ShareApp.vcxproj
@@ -0,0 +1,238 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+ Debug
+ ARM64
+
+
+ Release
+ ARM64
+
+
+
+ 17.0
+ Win32Proj
+ {006AFCE4-5393-4696-9319-9FDD3054774E}
+ ShareApp
+ 10.0
+
+
+
+ Application
+ true
+ v143
+ Unicode
+
+
+ Application
+ false
+ v143
+ true
+ Unicode
+
+
+ Application
+ true
+ v143
+ Unicode
+
+
+ Application
+ false
+ v143
+ true
+ Unicode
+
+
+ Application
+ true
+ v143
+ Unicode
+
+
+ Application
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)
+ true
+ stdcpp17
+
+
+ Windows
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)
+ true
+ stdcpp17
+
+
+ Windows
+ true
+
+
+
+
+ Level3
+ true
+ _DEBUG;_WINDOWS;%(PreprocessorDefinitions)
+ true
+ stdcpp17
+
+
+ Windows
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_WINDOWS;%(PreprocessorDefinitions)
+ true
+ stdcpp17
+
+
+ Windows
+ true
+
+
+
+
+ Level3
+ true
+ _DEBUG;_WINDOWS;%(PreprocessorDefinitions)
+ true
+ stdcpp17
+
+
+ Windows
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_WINDOWS;%(PreprocessorDefinitions)
+ true
+ stdcpp17
+
+
+ Windows
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Samples/ChatAppShare/ShareApp/ShareApp.vcxproj.filters b/Samples/ChatAppShare/ShareApp/ShareApp.vcxproj.filters
new file mode 100644
index 0000000..a44014c
--- /dev/null
+++ b/Samples/ChatAppShare/ShareApp/ShareApp.vcxproj.filters
@@ -0,0 +1,126 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Resource Files
+
+
+
+
+ Resource Files
+
+
+ Resource Files
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Samples/ChatAppShare/ShareApp/ShareTargetManager.cpp b/Samples/ChatAppShare/ShareApp/ShareTargetManager.cpp
new file mode 100644
index 0000000..07d85ea
--- /dev/null
+++ b/Samples/ChatAppShare/ShareApp/ShareTargetManager.cpp
@@ -0,0 +1,777 @@
+#include "ShareTargetManager.h"
+#include "PackageIdentity.h"
+#include "ContactSelectionDialog.h"
+#include "ChatManager.h"
+#include "ChatModels.h"
+#include "FileManager.h"
+#include "framework.h"
+#include
+
+// Static member initialization
+bool ShareTargetManager::s_initialized = false;
+bool ShareTargetManager::s_shareTargetSupported = false;
+
+void ShareTargetManager::Initialize()
+{
+ if (s_initialized)
+ return;
+
+ LogShareInfo(L"Initializing Share Target Manager...");
+
+ try
+ {
+ // Check if WinRT and package identity are available
+ if (g_isRunningWithIdentity)
+ {
+ s_shareTargetSupported = true;
+ LogShareInfo(L"Share Target support available with package identity.");
+ }
+ else
+ {
+ s_shareTargetSupported = false;
+ LogShareInfo(L"Share Target requires package identity (not available).");
+ }
+ }
+ catch (winrt::hresult_error const& ex)
+ {
+ std::wstring error = L"Share Target initialization error: " + std::wstring(ex.message().c_str());
+ LogShareError(error);
+ s_shareTargetSupported = false;
+ }
+ catch (...)
+ {
+ LogShareError(L"Unknown error during Share Target initialization.");
+ s_shareTargetSupported = false;
+ }
+
+ s_initialized = true;
+ LogShareInfo(L"Share Target Manager initialized successfully.");
+}
+
+bool ShareTargetManager::IsShareTargetAvailable()
+{
+ if (!s_initialized)
+ Initialize();
+
+ return s_shareTargetSupported && g_isRunningWithIdentity;
+}
+
+bool ShareTargetManager::IsShareTargetActivation()
+{
+ if (!IsShareTargetAvailable())
+ return false;
+
+ try
+ {
+ auto activationArgs = winrt::Windows::ApplicationModel::AppInstance::GetActivatedEventArgs();
+ return activationArgs && activationArgs.Kind() == winrt::Windows::ApplicationModel::Activation::ActivationKind::ShareTarget;
+ }
+ catch (...)
+ {
+ LogShareError(L"Error checking share target activation.");
+ return false;
+ }
+}
+
+bool ShareTargetManager::ProcessActivationArgs()
+{
+ if (!IsShareTargetAvailable())
+ return false;
+
+ // Add a static flag to prevent multiple processing
+ static bool s_alreadyProcessed = false;
+ if (s_alreadyProcessed) {
+ LogShareInfo(L"Share target already processed - skipping duplicate call");
+ return false;
+ }
+
+ try
+ {
+ auto activationArgs = winrt::Windows::ApplicationModel::AppInstance::GetActivatedEventArgs();
+ if (activationArgs && activationArgs.Kind() == winrt::Windows::ApplicationModel::Activation::ActivationKind::ShareTarget)
+ {
+ LogShareInfo(L"? Share Target activation detected!");
+ s_alreadyProcessed = true; // Mark as processed
+
+ // Process the share target directly here
+ auto shareArgs = activationArgs.as();
+ auto shareOperation = shareArgs.ShareOperation();
+ auto data = shareOperation.Data();
+
+ // Extract shared content information for the contact selection dialog
+ std::wstring sharedContentSummary = L"Shared Content";
+ std::wstring sharedFiles;
+ bool hasFiles = false;
+
+ // Collect information about what's being shared
+ std::vector sharedItems;
+
+ // Check for different data formats
+ if (data.Contains(winrt::Windows::ApplicationModel::DataTransfer::StandardDataFormats::Text()))
+ {
+ try
+ {
+ auto textAsync = data.GetTextAsync();
+ auto text = textAsync.get();
+ sharedItems.push_back(L"Text: " + std::wstring(text.c_str()));
+ LogShareInfo(L"Received shared text.");
+ }
+ catch (...)
+ {
+ sharedItems.push_back(L"Text: [Error retrieving text]");
+ LogShareError(L"Error retrieving shared text.");
+ }
+ }
+
+ if (data.Contains(winrt::Windows::ApplicationModel::DataTransfer::StandardDataFormats::WebLink()))
+ {
+ try
+ {
+ auto webLinkAsync = data.GetWebLinkAsync();
+ auto webLink = webLinkAsync.get();
+ sharedItems.push_back(L"Web Link: " + std::wstring(webLink.ToString().c_str()));
+ LogShareInfo(L"Received shared web link.");
+ }
+ catch (...)
+ {
+ sharedItems.push_back(L"Web Link: [Error retrieving web link]");
+ LogShareError(L"Error retrieving shared web link.");
+ }
+ }
+
+ if (data.Contains(winrt::Windows::ApplicationModel::DataTransfer::StandardDataFormats::Bitmap()))
+ {
+ try
+ {
+ auto bitmapAsync = data.GetBitmapAsync();
+ auto bitmapRef = bitmapAsync.get();
+ sharedItems.push_back(L"Image/Bitmap content");
+ LogShareInfo(L"Received shared bitmap.");
+ }
+ catch (...)
+ {
+ sharedItems.push_back(L"Image: [Error retrieving image]");
+ LogShareError(L"Error retrieving shared bitmap.");
+ }
+ }
+
+ if (data.Contains(winrt::Windows::ApplicationModel::DataTransfer::StandardDataFormats::StorageItems()))
+ {
+ try
+ {
+ auto storageItemsAsync = data.GetStorageItemsAsync();
+ auto storageItems = storageItemsAsync.get();
+
+ hasFiles = true;
+ std::wstring filesInfo = std::to_wstring(storageItems.Size()) + L" file(s)";
+
+ if (storageItems.Size() == 1)
+ {
+ auto item = storageItems.GetAt(0);
+ sharedFiles = item.Name().c_str();
+ sharedContentSummary = sharedFiles;
+ }
+ else if (storageItems.Size() > 1)
+ {
+ sharedFiles = L"Multiple Files (" + std::to_wstring(storageItems.Size()) + L")";
+ sharedContentSummary = sharedFiles;
+ }
+
+ for (uint32_t i = 0; i < storageItems.Size(); i++)
+ {
+ auto item = storageItems.GetAt(i);
+ filesInfo += L"\n - " + std::wstring(item.Name().c_str());
+ }
+
+ sharedItems.push_back(filesInfo);
+ LogShareInfo(L"Received shared files.");
+ }
+ catch (...)
+ {
+ sharedItems.push_back(L"Files: [Error retrieving files]");
+ LogShareError(L"Error retrieving shared files.");
+ }
+ }
+
+ // If no specific content type found, use generic description
+ if (sharedItems.empty())
+ {
+ sharedContentSummary = L"Shared Content";
+ sharedItems.push_back(L"Unknown content type");
+ }
+
+ // Get the main window handle for dialog parent - try to find or launch SampleChatAppWithShare first
+ HWND hMainWindow = FindOrLaunchPackageApplication(L"SampleChatAppWithShare.exe");
+ if (!hMainWindow)
+ {
+ LogShareInfo(L"Package application not found/launched, using fallback window detection");
+
+ // Fallback to original logic
+ hMainWindow = GetActiveWindow();
+ if (!hMainWindow)
+ {
+ hMainWindow = GetForegroundWindow();
+ }
+ if (!hMainWindow)
+ {
+ // Try to find the main chat application window
+ hMainWindow = FindWindow(NULL, L"Chat Application");
+ }
+ }
+ else
+ {
+ LogShareInfo(L"Successfully found/launched package application for dialog parenting");
+ }
+
+ // Ensure contacts are initialized (critical for share target scenarios)
+ if (contacts.empty())
+ {
+ LogShareInfo(L"Initializing contacts for share target scenario...");
+
+ // [TODO] Get contacts from the main app.
+ InitializeContacts();
+ }
+
+ // Log the number of contacts available for debugging
+ LogShareInfo(L"Available contacts: " + std::to_wstring(contacts.size()));
+
+ // Show contact selection dialog for the shared content
+ ContactSelectionDialog::SelectionResult result =
+ ContactSelectionDialog::ShowContactSelectionDialog(hMainWindow, L"", sharedContentSummary);
+
+ if (result.wasSelected)
+ {
+ // User selected a contact - add the shared content to that contact's chat
+ if (result.contactIndex >= 0 && result.contactIndex < (int)contacts.size())
+ {
+ int previousSelection = selectedContactIndex;
+ selectedContactIndex = result.contactIndex;
+
+ LogShareInfo(L"Setting selectedContactIndex to: " + std::to_wstring(result.contactIndex));
+ LogShareInfo(L"Selected contact name: " + contacts[result.contactIndex].name);
+
+ // Add messages directly to the selected contact instead of relying on selectedContactIndex
+ Contact& selectedContact = contacts[result.contactIndex];
+
+ // Add the custom share message if provided
+ if (!result.shareMessage.empty())
+ {
+ std::wstring formattedShareMessage = L"You: " + result.shareMessage + L" ??";
+ selectedContact.messages.push_back(formattedShareMessage);
+ LogShareInfo(L"Added share message: " + result.shareMessage);
+ }
+
+ // Add shared content messages to the chat
+ for (const auto& item : sharedItems)
+ {
+ std::wstring shareMsg = L"?? Received via Share: " + item;
+ std::wstring formattedMessage = selectedContact.name + L": " + shareMsg;
+ selectedContact.messages.push_back(formattedMessage);
+ LogShareInfo(L"Added shared content message: " + shareMsg);
+ }
+
+ // Update the last message preview for this contact
+ if (!sharedItems.empty())
+ {
+ std::wstring lastMsg = L"?? Received via Share: " + sharedItems[0];
+ selectedContact.lastMessage = lastMsg.length() > 50 ? lastMsg.substr(0, 47) + L"..." : lastMsg;
+ }
+
+ // [TODO] Store path somewhere for main application to pick.
+ // If files were shared, add them to the contact's shared files list
+ if (hasFiles && data.Contains(winrt::Windows::ApplicationModel::DataTransfer::StandardDataFormats::StorageItems()))
+ {
+ try
+ {
+ auto storageItemsAsync = data.GetStorageItemsAsync();
+ auto storageItems = storageItemsAsync.get();
+
+ for (uint32_t i = 0; i < storageItems.Size(); i++)
+ {
+ auto item = storageItems.GetAt(i);
+
+ // Create shared file entry
+ SharedFile newFile;
+ newFile.fileName = item.Name().c_str();
+ newFile.filePath = item.Path().c_str(); // Get full path if available
+ newFile.sharedBy = L"External Share";
+ GetSystemTime(&newFile.timeShared);
+
+ selectedContact.sharedFiles.push_back(newFile);
+ LogShareInfo(L"Added shared file: " + newFile.fileName);
+ }
+ }
+ catch (...)
+ {
+ LogShareError(L"Error adding shared files to contact.");
+ }
+ }
+
+ // Show success message and exit the application
+ std::wstring successMsg = L"Content has been shared successfully with " + contacts[result.contactIndex].name + L"!\n\nThe application will now close.";
+ MessageBoxW(hMainWindow, successMsg.c_str(), L"Sharing Complete", MB_OK | MB_ICONINFORMATION);
+
+ LogShareInfo(L"Share target content added to contact: " + contacts[result.contactIndex].name);
+ LogShareInfo(L"Selected contact index set to: " + std::to_wstring(result.contactIndex));
+ LogShareInfo(L"Contact now has " + std::to_wstring(selectedContact.messages.size()) + L" messages");
+
+ // Report completion to Windows
+ shareOperation.ReportCompleted();
+
+ LogShareInfo(L"Share target processing completed successfully. Exiting application.");
+
+ // Exit the application after successful sharing
+ PostQuitMessage(0);
+ return true;
+ }
+ }
+ else
+ {
+ // User cancelled - show a brief message and exit
+ MessageBoxW(hMainWindow, L"Share operation was cancelled.\n\nThe application will now close.", L"Share Cancelled", MB_OK | MB_ICONINFORMATION);
+ LogShareInfo(L"Share target operation cancelled by user.");
+
+ // Report completion to Windows
+ shareOperation.ReportCompleted();
+
+ LogShareInfo(L"Share target processing cancelled. Exiting application.");
+
+ // Exit the application after cancellation
+ PostQuitMessage(0);
+ return true;
+ }
+
+ // Report completion to Windows
+ shareOperation.ReportCompleted();
+
+ LogShareInfo(L"Share target processing completed successfully.");
+ return true;
+ }
+ else
+ {
+ LogShareInfo(L"Running with package identity but not as share target.");
+ return false;
+ }
+ }
+ catch (winrt::hresult_error const& ex)
+ {
+ s_alreadyProcessed = true; // Mark as processed even on error to prevent retries
+ std::wstring error = L"Error checking activation args: " + std::wstring(ex.message().c_str()) +
+ L" (HRESULT: 0x" + std::to_wstring(static_cast(ex.code())) + L")";
+ LogShareError(error);
+ MessageBoxW(nullptr, L"Error processing shared content", L"Share Target Error", MB_OK | MB_ICONERROR);
+ return false;
+ }
+ catch (...)
+ {
+ s_alreadyProcessed = true; // Mark as processed even on error to prevent retries
+ LogShareError(L"Unknown error checking activation arguments.");
+ MessageBoxW(nullptr, L"Unknown error processing shared content", L"Share Target Error", MB_OK | MB_ICONERROR);
+ return false;
+ }
+}
+
+std::wstring ShareTargetManager::GetShareTargetStatus()
+{
+ if (!s_initialized)
+ Initialize();
+
+ std::wstring status = L"WinRT Share Target Integration Status:\n\n";
+
+ try
+ {
+ winrt::check_hresult(S_OK);
+ status += L"?? WinRT Runtime: ? Available and Working\n";
+ status += L"?? Package Identity: " + std::wstring(g_isRunningWithIdentity ? L"? Available" : L"? Not Available") + L"\n";
+ status += L"?? Sparse Package Support: " + std::wstring(g_isSparsePackageSupported ? L"? Supported" : L"? Not Supported") + L"\n\n";
+
+ // Test activation
+ if (g_isRunningWithIdentity)
+ {
+ try
+ {
+ if (IsShareTargetActivation())
+ {
+ status += L"?? Share Target: ? Currently Activated\n";
+ }
+ else
+ {
+ status += L"?? Share Target: ?? Not Currently Activated\n";
+ }
+ }
+ catch (...)
+ {
+ status += L"?? Share Target: ? Error Checking Activation\n";
+ }
+ }
+ else
+ {
+ status += L"?? Share Target: ? Package Identity Required\n";
+ }
+
+ status += GetPackageIdentityStatus();
+ status += L"\n\n?? WinRT Share Target integration is complete and ready!";
+ }
+ catch (winrt::hresult_error const& ex)
+ {
+ status += L"?? WinRT Runtime: ? Error\n";
+ status += L"Error: " + std::wstring(ex.message().c_str()) + L"\n";
+ status += L"HRESULT: 0x" + std::to_wstring(static_cast(ex.code())) + L"\n";
+ }
+ catch (...)
+ {
+ status += L"?? WinRT Runtime: ? Unknown Error\n";
+ }
+
+ return status;
+}
+
+void ShareTargetManager::LogShareInfo(const std::wstring& message)
+{
+ std::wstring logMessage = L"ChatApp: " + message + L"\n";
+ OutputDebugStringW(logMessage.c_str());
+}
+
+void ShareTargetManager::LogShareError(const std::wstring& error)
+{
+ std::wstring logMessage = L"ChatApp: ShareTarget ERROR - " + error + L"\n";
+ OutputDebugStringW(logMessage.c_str());
+}
+
+// Helper function to get all processes in the same package using proper Package Manager APIs
+std::vector ShareTargetManager::GetPackageProcesses()
+{
+ std::vector packageProcesses;
+
+ if (!g_isRunningWithIdentity)
+ {
+ LogShareError(L"GetPackageProcesses called without package identity");
+ return packageProcesses;
+ }
+
+ try
+ {
+ // Get the current package family name first
+ UINT32 currentPackageFamilyNameLength = 0;
+ LONG result = GetCurrentPackageFamilyName(¤tPackageFamilyNameLength, nullptr);
+
+ if (result != ERROR_INSUFFICIENT_BUFFER)
+ {
+ LogShareError(L"Failed to get current package family name length: " + std::to_wstring(result));
+ return packageProcesses;
+ }
+
+ std::wstring currentPackageFamilyName(currentPackageFamilyNameLength, L'\0');
+ result = GetCurrentPackageFamilyName(¤tPackageFamilyNameLength, currentPackageFamilyName.data());
+
+ if (result != ERROR_SUCCESS)
+ {
+ LogShareError(L"Failed to get current package family name: " + std::to_wstring(result));
+ return packageProcesses;
+ }
+
+ // Remove null terminator that GetCurrentPackageFamilyName includes in the length
+ if (!currentPackageFamilyName.empty() && currentPackageFamilyName.back() == L'\0')
+ {
+ currentPackageFamilyName.pop_back();
+ }
+
+ LogShareInfo(L"Current package family name: " + currentPackageFamilyName);
+
+ // Enumerate all processes and check their package family names
+ HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+ if (hSnapshot == INVALID_HANDLE_VALUE)
+ {
+ LogShareError(L"Failed to create process snapshot");
+ return packageProcesses;
+ }
+
+ PROCESSENTRY32W processEntry = {};
+ processEntry.dwSize = sizeof(PROCESSENTRY32W);
+
+ if (Process32FirstW(hSnapshot, &processEntry))
+ {
+ do
+ {
+ if (IsProcessInSamePackage(processEntry.th32ProcessID, currentPackageFamilyName))
+ {
+ packageProcesses.push_back(processEntry.th32ProcessID);
+ LogShareInfo(L"Found package process: " + std::wstring(processEntry.szExeFile) +
+ L" (PID: " + std::to_wstring(processEntry.th32ProcessID) + L")");
+ }
+ } while (Process32NextW(hSnapshot, &processEntry));
+ }
+
+ CloseHandle(hSnapshot);
+ }
+ catch (...)
+ {
+ LogShareError(L"Exception in GetPackageProcesses");
+ }
+
+ LogShareInfo(L"Found " + std::to_wstring(packageProcesses.size()) + L" processes in the same package");
+ return packageProcesses;
+}
+
+// Helper function to check if a process is in the same package using proper Package Manager APIs
+bool ShareTargetManager::IsProcessInSamePackage(DWORD processId)
+{
+ if (!g_isRunningWithIdentity)
+ return false;
+
+ // Get the current package family name first
+ UINT32 currentPackageFamilyNameLength = 0;
+ LONG result = GetCurrentPackageFamilyName(¤tPackageFamilyNameLength, nullptr);
+ if (result != ERROR_INSUFFICIENT_BUFFER)
+ return false;
+
+ std::wstring currentPackageFamilyName(currentPackageFamilyNameLength, L'\0');
+ result = GetCurrentPackageFamilyName(¤tPackageFamilyNameLength, currentPackageFamilyName.data());
+ if (result != ERROR_SUCCESS)
+ return false;
+
+ // Remove null terminator
+ if (!currentPackageFamilyName.empty() && currentPackageFamilyName.back() == L'\0')
+ {
+ currentPackageFamilyName.pop_back();
+ }
+
+ return IsProcessInSamePackage(processId, currentPackageFamilyName);
+}
+
+// Overloaded helper function to check if a process is in the same package
+bool ShareTargetManager::IsProcessInSamePackage(DWORD processId, const std::wstring& targetPackageFamilyName)
+{
+ if (!g_isRunningWithIdentity)
+ return false;
+
+ try
+ {
+ // Open the target process to get its package information
+ HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, processId);
+ if (hProcess == NULL)
+ {
+ // Process might not be accessible or may have exited
+ return false;
+ }
+
+ // Get the package family name for the target process
+ UINT32 packageFamilyNameLength = 0;
+ LONG result = GetPackageFamilyName(hProcess, &packageFamilyNameLength, nullptr);
+
+ if (result == APPMODEL_ERROR_NO_PACKAGE)
+ {
+ // Process is not packaged
+ CloseHandle(hProcess);
+ return false;
+ }
+
+ if (result != ERROR_INSUFFICIENT_BUFFER)
+ {
+ CloseHandle(hProcess);
+ return false;
+ }
+
+ std::wstring processPackageFamilyName(packageFamilyNameLength, L'\0');
+ result = GetPackageFamilyName(hProcess, &packageFamilyNameLength, processPackageFamilyName.data());
+
+ CloseHandle(hProcess);
+
+ if (result != ERROR_SUCCESS)
+ {
+ return false;
+ }
+
+ // Remove null terminator
+ if (!processPackageFamilyName.empty() && processPackageFamilyName.back() == L'\0')
+ {
+ processPackageFamilyName.pop_back();
+ }
+
+ // Compare package family names
+ bool isSamePackage = (processPackageFamilyName == targetPackageFamilyName);
+
+ if (isSamePackage)
+ {
+ LogShareInfo(L"Process " + std::to_wstring(processId) + L" is in the same package: " + processPackageFamilyName);
+ }
+
+ return isSamePackage;
+ }
+ catch (...)
+ {
+ LogShareError(L"Exception in IsProcessInSamePackage for PID: " + std::to_wstring(processId));
+ return false;
+ }
+}
+
+// Helper function to find the main window of the package application
+HWND ShareTargetManager::FindPackageApplicationWindow(const std::wstring& windowTitle)
+{
+ LogShareInfo(L"Searching for window with title: " + windowTitle);
+
+ // First try to find the window by title
+ HWND hWnd = FindWindowW(NULL, windowTitle.c_str());
+ if (hWnd)
+ {
+ // Verify it belongs to a process in our package
+ DWORD processId = 0;
+ GetWindowThreadProcessId(hWnd, &processId);
+
+ if (IsProcessInSamePackage(processId))
+ {
+ LogShareInfo(L"Found package application window (PID: " + std::to_wstring(processId) + L")");
+ return hWnd;
+ }
+ else
+ {
+ LogShareInfo(L"Found window but not in same package");
+ }
+ }
+
+ // If not found by title, enumerate all windows and check each one
+ std::vector packageProcesses = GetPackageProcesses();
+
+ for (DWORD processId : packageProcesses)
+ {
+ // Find the main window for this process
+ struct EnumData
+ {
+ DWORD processId;
+ HWND hWnd;
+ } enumData = { processId, NULL };
+
+ EnumWindows([](HWND hWnd, LPARAM lParam) -> BOOL
+ {
+ EnumData* pData = reinterpret_cast(lParam);
+ DWORD windowProcessId = 0;
+ GetWindowThreadProcessId(hWnd, &windowProcessId);
+
+ if (windowProcessId == pData->processId && IsWindowVisible(hWnd))
+ {
+ // Check if this is a main window (has no parent and is not a tool window)
+ HWND hParent = GetParent(hWnd);
+ LONG_PTR exStyle = GetWindowLongPtr(hWnd, GWL_EXSTYLE);
+
+ if (!hParent && !(exStyle & WS_EX_TOOLWINDOW))
+ {
+ pData->hWnd = hWnd;
+ return FALSE; // Stop enumeration
+ }
+ }
+ return TRUE; // Continue enumeration
+ }, reinterpret_cast(&enumData));
+
+ if (enumData.hWnd)
+ {
+ LogShareInfo(L"Found main window for package process (PID: " + std::to_wstring(processId) + L")");
+ return enumData.hWnd;
+ }
+ }
+
+ LogShareInfo(L"No package application window found");
+ return NULL;
+}
+
+// Helper function to launch the package application
+bool ShareTargetManager::LaunchPackageApplication(const std::wstring& appExecutableName)
+{
+ LogShareInfo(L"Attempting to launch: " + appExecutableName);
+
+ try
+ {
+ // Get the current executable directory to use as working directory
+ std::wstring executableDir = GetExecutableDirectory();
+
+ SHELLEXECUTEINFOW shellInfo = {};
+ shellInfo.cbSize = sizeof(SHELLEXECUTEINFOW);
+ shellInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI;
+ shellInfo.lpVerb = L"open";
+ shellInfo.lpFile = appExecutableName.c_str();
+ shellInfo.lpParameters = NULL;
+ shellInfo.lpDirectory = executableDir.empty() ? NULL : executableDir.c_str();
+ shellInfo.nShow = SW_SHOWNORMAL;
+
+ LogShareInfo(L"Launch directory: " + (executableDir.empty() ? L"[NULL - using current directory]" : executableDir));
+
+ if (ShellExecuteExW(&shellInfo))
+ {
+ if (shellInfo.hProcess)
+ {
+ LogShareInfo(L"Successfully launched " + appExecutableName);
+ CloseHandle(shellInfo.hProcess);
+ return true;
+ }
+ }
+
+ DWORD error = GetLastError();
+ LogShareError(L"Failed to launch " + appExecutableName + L" (Error: " + std::to_wstring(error) + L")");
+ return false;
+ }
+ catch (...)
+ {
+ LogShareError(L"Exception in LaunchPackageApplication");
+ return false;
+ }
+}
+
+// Helper function to wait for the application window to appear
+HWND ShareTargetManager::WaitForApplicationWindow(const std::wstring& windowTitle, DWORD timeoutMs)
+{
+ LogShareInfo(L"Waiting for application window: " + windowTitle + L" (timeout: " + std::to_wstring(timeoutMs) + L"ms)");
+
+ DWORD startTime = GetTickCount();
+ HWND hWnd = NULL;
+
+ while ((GetTickCount() - startTime) < timeoutMs)
+ {
+ hWnd = FindPackageApplicationWindow(windowTitle);
+ if (hWnd)
+ {
+ LogShareInfo(L"Application window found after " + std::to_wstring(GetTickCount() - startTime) + L"ms");
+ return hWnd;
+ }
+
+ Sleep(250); // Check every 250ms
+ }
+
+ LogShareError(L"Timeout waiting for application window");
+ return NULL;
+}
+
+// Main function to find or launch the package application
+HWND ShareTargetManager::FindOrLaunchPackageApplication(const std::wstring& appExecutableName)
+{
+ LogShareInfo(L"FindOrLaunchPackageApplication called for: " + appExecutableName);
+
+ // First try to find an existing window
+ HWND hWnd = FindPackageApplicationWindow(L"Chat Application");
+ if (hWnd)
+ {
+ LogShareInfo(L"Found existing Chat Application window");
+ return hWnd;
+ }
+
+ // If not found, try to launch the application
+ LogShareInfo(L"Chat Application not found, attempting to launch");
+ if (LaunchPackageApplication(appExecutableName))
+ {
+ // Wait for the application window to appear
+ hWnd = WaitForApplicationWindow(L"Chat Application", 10000);
+ if (hWnd)
+ {
+ LogShareInfo(L"Successfully launched and found Chat Application window");
+ return hWnd;
+ }
+ else
+ {
+ LogShareError(L"Application launched but window not found");
+ }
+ }
+ else
+ {
+ LogShareError(L"Failed to launch application");
+ }
+
+ return NULL;
+}
\ No newline at end of file
diff --git a/Samples/ChatAppShare/ShareApp/ShareTargetManager.h b/Samples/ChatAppShare/ShareApp/ShareTargetManager.h
new file mode 100644
index 0000000..bd6c2df
--- /dev/null
+++ b/Samples/ChatAppShare/ShareApp/ShareTargetManager.h
@@ -0,0 +1,48 @@
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#pragma comment(lib, "shell32.lib")
+
+// Simple Share Target Manager with minimal dependencies
+class ShareTargetManager
+{
+public:
+ // Initialize the share target manager
+ static void Initialize();
+
+ // Check if the current activation is a share target
+ static bool IsShareTargetActivation();
+
+ // Check activation arguments and process if it's a share target
+ static bool ProcessActivationArgs();
+
+ // Get share target status information
+ static std::wstring GetShareTargetStatus();
+
+ // Check if share target is available (requires package identity)
+ static bool IsShareTargetAvailable();
+
+private:
+ // Logging helpers
+ static void LogShareInfo(const std::wstring& message);
+ static void LogShareError(const std::wstring& error);
+
+ // Package application discovery and launch helpers using proper Package Manager APIs
+ static std::vector GetPackageProcesses();
+ static bool IsProcessInSamePackage(DWORD processId);
+ static bool IsProcessInSamePackage(DWORD processId, const std::wstring& targetPackageFamilyName);
+ static HWND FindPackageApplicationWindow(const std::wstring& windowTitle);
+ static bool LaunchPackageApplication(const std::wstring& appExecutableName);
+ static HWND WaitForApplicationWindow(const std::wstring& windowTitle, DWORD timeoutMs = 10000);
+ static HWND FindOrLaunchPackageApplication(const std::wstring& appExecutableName);
+
+private:
+ static bool s_initialized;
+ static bool s_shareTargetSupported;
+};
\ No newline at end of file
diff --git a/Samples/ChatAppShare/ShareApp/UIConstants.h b/Samples/ChatAppShare/ShareApp/UIConstants.h
new file mode 100644
index 0000000..ff28af5
--- /dev/null
+++ b/Samples/ChatAppShare/ShareApp/UIConstants.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include
+
+// Include resource.h for resource constants
+#include "resource.h"
+
+// Modern UI Color Scheme
+#define COLOR_PRIMARY RGB(64, 128, 255) // Modern blue
+#define COLOR_PRIMARY_DARK RGB(45, 100, 220) // Darker blue for hover
+#define COLOR_APP_BACKGROUND RGB(248, 249, 250) // Light gray background
+#define COLOR_SURFACE RGB(255, 255, 255) // White surface
+#define COLOR_TEXT_PRIMARY RGB(33, 37, 41) // Dark text
+#define COLOR_TEXT_SECONDARY RGB(108, 117, 125) // Gray text
+#define COLOR_BORDER RGB(222, 226, 230) // Light border
+#define COLOR_HOVER RGB(248, 249, 250) // Hover background
+#define COLOR_CHAT_BUBBLE_OUT RGB(0, 123, 255) // Outgoing message
+#define COLOR_CHAT_BUBBLE_IN RGB(233, 236, 239) // Incoming message
+
+// UI Constants
+#define MAX_LOADSTRING 100
+#define CONTACT_ITEM_HEIGHT 72
+#define AVATAR_SIZE 40
\ No newline at end of file
diff --git a/Samples/ChatAppShare/ShareApp/UIManager.cpp b/Samples/ChatAppShare/ShareApp/UIManager.cpp
new file mode 100644
index 0000000..bdd4808
--- /dev/null
+++ b/Samples/ChatAppShare/ShareApp/UIManager.cpp
@@ -0,0 +1,142 @@
+#include "UIManager.h"
+#include "UIConstants.h"
+#include "ModernUI.h"
+#include "ChatModels.h"
+#include "FileManager.h"
+#include "WindowProcs.h"
+#include
+
+#pragma comment(lib, "comctl32.lib")
+
+// External declaration - hInst is defined in the main cpp file
+extern HINSTANCE hInst;
+
+// UI Window handles definitions
+HWND hContactsList = nullptr;
+HWND hChatDisplay = nullptr;
+HWND hMessageInput = nullptr;
+HWND hSendButton = nullptr;
+HWND hContactName = nullptr;
+HWND hShareFileButton = nullptr;
+HWND hSharedFilesList = nullptr;
+
+void CreateChatUI(HWND hWnd)
+{
+ RECT rect;
+ GetClientRect(hWnd, &rect);
+
+ int width = rect.right - rect.left;
+ int height = rect.bottom - rect.top;
+
+ // Set window background to modern color
+ SetClassLongPtr(hWnd, GCLP_HBRBACKGROUND, (LONG_PTR)hBrushBackground);
+
+ // Create contacts list (left panel) with modern styling
+ hContactsList = CreateWindowEx(
+ WS_EX_CLIENTEDGE,
+ L"LISTBOX", NULL,
+ WS_CHILD | WS_VISIBLE | WS_VSCROLL | LBS_NOTIFY | LBS_OWNERDRAWFIXED,
+ 20, 20, 280, height - 40,
+ hWnd, (HMENU)IDC_CONTACTS_LIST, hInst, NULL);
+
+ // Set custom item height for contact list
+ ::SendMessage(hContactsList, LB_SETITEMHEIGHT, 0, CONTACT_ITEM_HEIGHT);
+
+ // Create contact name label with modern styling
+ hContactName = CreateWindow(L"STATIC", L"Select a contact to start chatting",
+ WS_CHILD | WS_VISIBLE | SS_LEFT,
+ 320, 20, 300, 30,
+ hWnd, (HMENU)IDC_CONTACT_NAME, hInst, NULL);
+
+ // Create chat display area with modern styling
+ hChatDisplay = CreateWindowEx(
+ WS_EX_CLIENTEDGE,
+ L"EDIT", NULL,
+ WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_MULTILINE | ES_READONLY | ES_AUTOVSCROLL,
+ 320, 60, width - 600, height - 280,
+ hWnd, (HMENU)IDC_CHAT_DISPLAY, hInst, NULL);
+
+ // Create shared files section header
+ CreateWindow(L"STATIC", L"Shared Files",
+ WS_CHILD | WS_VISIBLE | SS_LEFT,
+ width - 260, 20, 120, 30,
+ hWnd, NULL, hInst, NULL);
+
+ // Create shared files list with modern styling
+ hSharedFilesList = CreateWindowEx(
+ WS_EX_CLIENTEDGE,
+ L"LISTBOX", NULL,
+ WS_CHILD | WS_VISIBLE | WS_VSCROLL | LBS_NOTIFY,
+ width - 260, 60, 240, height - 280,
+ hWnd, (HMENU)IDC_SHARED_FILES_LIST, hInst, NULL);
+
+ // Create message input with placeholder styling
+ hMessageInput = CreateWindowEx(
+ WS_EX_CLIENTEDGE,
+ L"EDIT", NULL,
+ WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_AUTOVSCROLL,
+ 320, height - 200, width - 600, 60,
+ hWnd, (HMENU)IDC_MESSAGE_INPUT, hInst, NULL);
+
+ // Create modern styled buttons
+ hSendButton = CreateWindow(L"BUTTON", L"Send",
+ WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_OWNERDRAW,
+ 320, height - 130, 100, 45,
+ hWnd, (HMENU)IDC_SEND_BUTTON, hInst, NULL);
+
+ hShareFileButton = CreateWindow(L"BUTTON", L"Share File",
+ WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_OWNERDRAW,
+ 440, height - 130, 120, 45,
+ hWnd, (HMENU)IDC_SHARE_FILE_BUTTON, hInst, NULL);
+
+ // Populate contacts list
+ for (const auto& contact : contacts) {
+ ::SendMessage(hContactsList, LB_ADDSTRING, 0, (LPARAM)contact.name.c_str());
+ }
+
+ // Apply modern fonts to controls
+ ::SendMessage(hContactName, WM_SETFONT, (WPARAM)hFontTitle, TRUE);
+ ::SendMessage(hChatDisplay, WM_SETFONT, (WPARAM)hFontRegular, TRUE);
+ ::SendMessage(hMessageInput, WM_SETFONT, (WPARAM)hFontRegular, TRUE);
+ ::SendMessage(hSharedFilesList, WM_SETFONT, (WPARAM)hFontRegular, TRUE);
+
+ // Subclass buttons for custom drawing
+ SetupCustomWindowProcs();
+
+ // Set modern background colors
+ SetupWindowColors();
+}
+
+void ResizeChatUI(HWND hWnd)
+{
+ RECT rect;
+ GetClientRect(hWnd, &rect);
+ int width = rect.right - rect.left;
+ int height = rect.bottom - rect.top;
+
+ if (hContactsList) {
+ SetWindowPos(hContactsList, NULL, 20, 20, 280, height - 40, SWP_NOZORDER);
+ }
+ if (hChatDisplay) {
+ SetWindowPos(hChatDisplay, NULL, 320, 60, width - 600, height - 280, SWP_NOZORDER);
+ }
+ if (hSharedFilesList) {
+ SetWindowPos(hSharedFilesList, NULL, width - 260, 60, 240, height - 280, SWP_NOZORDER);
+ }
+ if (hMessageInput) {
+ SetWindowPos(hMessageInput, NULL, 320, height - 200, width - 600, 60, SWP_NOZORDER);
+ }
+ if (hSendButton) {
+ SetWindowPos(hSendButton, NULL, 320, height - 130, 100, 45, SWP_NOZORDER);
+ }
+ if (hShareFileButton) {
+ SetWindowPos(hShareFileButton, NULL, 440, height - 130, 120, 45, SWP_NOZORDER);
+ }
+}
+
+void SetupWindowColors()
+{
+ SetClassLongPtr(hChatDisplay, GCLP_HBRBACKGROUND, (LONG_PTR)hBrushSurface);
+ SetClassLongPtr(hMessageInput, GCLP_HBRBACKGROUND, (LONG_PTR)hBrushSurface);
+ SetClassLongPtr(hSharedFilesList, GCLP_HBRBACKGROUND, (LONG_PTR)hBrushSurface);
+}
\ No newline at end of file
diff --git a/Samples/ChatAppShare/ShareApp/UIManager.h b/Samples/ChatAppShare/ShareApp/UIManager.h
new file mode 100644
index 0000000..74c2a14
--- /dev/null
+++ b/Samples/ChatAppShare/ShareApp/UIManager.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include
+
+// UI Window handles
+extern HWND hContactsList;
+extern HWND hChatDisplay;
+extern HWND hMessageInput;
+extern HWND hSendButton;
+extern HWND hContactName;
+extern HWND hShareFileButton;
+extern HWND hSharedFilesList;
+
+// UI management functions
+void CreateChatUI(HWND hWnd);
+void ResizeChatUI(HWND hWnd);
+void SetupWindowColors();
\ No newline at end of file
diff --git a/Samples/ChatAppShare/ShareApp/WindowProcs.cpp b/Samples/ChatAppShare/ShareApp/WindowProcs.cpp
new file mode 100644
index 0000000..ce00862
--- /dev/null
+++ b/Samples/ChatAppShare/ShareApp/WindowProcs.cpp
@@ -0,0 +1,168 @@
+#include "WindowProcs.h"
+#include "UIConstants.h"
+#include "ModernUI.h"
+#include "ChatModels.h"
+#include "UIManager.h"
+
+// External declarations for UI window handles
+extern HWND hSendButton;
+extern HWND hShareFileButton;
+extern HWND hContactsList;
+
+// Window procedure storage for subclassing
+WNDPROC originalButtonProc = nullptr;
+WNDPROC originalListBoxProc = nullptr;
+
+void SetupCustomWindowProcs()
+{
+ // Subclass buttons for custom drawing
+ originalButtonProc = (WNDPROC)SetWindowLongPtr(hSendButton, GWLP_WNDPROC, (LONG_PTR)ModernButtonProc);
+ SetWindowLongPtr(hShareFileButton, GWLP_WNDPROC, (LONG_PTR)ModernButtonProc);
+
+ // Subclass contact list for custom drawing
+ originalListBoxProc = (WNDPROC)SetWindowLongPtr(hContactsList, GWLP_WNDPROC, (LONG_PTR)ModernListBoxProc);
+}
+
+// Modern button subclass procedure
+LRESULT CALLBACK ModernButtonProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static bool isHovered = false;
+ static bool isPressed = false;
+
+ switch (msg)
+ {
+ case WM_PAINT:
+ {
+ PAINTSTRUCT ps;
+ HDC hdc = BeginPaint(hWnd, &ps);
+
+ RECT rect;
+ GetClientRect(hWnd, &rect);
+
+ WCHAR text[256];
+ GetWindowText(hWnd, text, 256);
+
+ DrawModernButton(hdc, rect, std::wstring(text), isHovered, isPressed);
+
+ EndPaint(hWnd, &ps);
+ return 0;
+ }
+
+ case WM_MOUSEMOVE:
+ if (!isHovered)
+ {
+ isHovered = true;
+ InvalidateRect(hWnd, NULL, FALSE);
+
+ TRACKMOUSEEVENT tme = {};
+ tme.cbSize = sizeof(tme);
+ tme.dwFlags = TME_LEAVE;
+ tme.hwndTrack = hWnd;
+ TrackMouseEvent(&tme);
+ }
+ break;
+
+ case WM_MOUSELEAVE:
+ isHovered = false;
+ InvalidateRect(hWnd, NULL, FALSE);
+ break;
+
+ case WM_LBUTTONDOWN:
+ isPressed = true;
+ InvalidateRect(hWnd, NULL, FALSE);
+ SetCapture(hWnd);
+ break;
+
+ case WM_LBUTTONUP:
+ if (isPressed)
+ {
+ isPressed = false;
+ InvalidateRect(hWnd, NULL, FALSE);
+ ReleaseCapture();
+
+ // Send click notification to parent
+ HWND hParent = GetParent(hWnd);
+ int controlId = GetDlgCtrlID(hWnd);
+ ::SendMessage(hParent, WM_COMMAND, MAKEWPARAM(controlId, BN_CLICKED), (LPARAM)hWnd);
+ }
+ break;
+ }
+
+ return CallWindowProc(originalButtonProc, hWnd, msg, wParam, lParam);
+}
+
+// Modern listbox subclass procedure
+LRESULT CALLBACK ModernListBoxProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg)
+ {
+ case WM_LBUTTONDOWN:
+ if (hWnd == hContactsList)
+ {
+ // Handle mouse click to ensure proper contact selection with scrolling
+ POINT pt = { LOWORD(lParam), HIWORD(lParam) };
+
+ // Calculate which contact was clicked based on the scroll position
+ int topIndex = (int)::SendMessage(hWnd, LB_GETTOPINDEX, 0, 0);
+ int clickedVisiblePos = pt.y / CONTACT_ITEM_HEIGHT;
+ int actualContactIndex = topIndex + clickedVisiblePos;
+
+ // Ensure the clicked contact is valid
+ if (actualContactIndex >= 0 && actualContactIndex < (int)contacts.size())
+ {
+ // Set the correct selection in the listbox
+ ::SendMessage(hWnd, LB_SETCURSEL, actualContactIndex, 0);
+
+ // Trigger the selection change event to update the UI
+ HWND hParent = GetParent(hWnd);
+ int controlId = GetDlgCtrlID(hWnd);
+ ::SendMessage(hParent, WM_COMMAND, MAKEWPARAM(controlId, LBN_SELCHANGE), (LPARAM)hWnd);
+
+ return 0; // We handled the click
+ }
+ }
+ break;
+
+ case WM_PAINT:
+ if (hWnd == hContactsList)
+ {
+ PAINTSTRUCT ps;
+ HDC hdc = BeginPaint(hWnd, &ps);
+
+ RECT clientRect;
+ GetClientRect(hWnd, &clientRect);
+
+ // Fill background
+ FillRect(hdc, &clientRect, hBrushSurface);
+
+ int itemCount = (int)contacts.size();
+ int selectedIndex = (int)::SendMessage(hWnd, LB_GETCURSEL, 0, 0);
+
+ // Get the first visible item index to handle scrolling correctly
+ int topIndex = (int)::SendMessage(hWnd, LB_GETTOPINDEX, 0, 0);
+
+ // Calculate how many items can be visible
+ int visibleItemCount = (clientRect.bottom / CONTACT_ITEM_HEIGHT) + 1;
+
+ // Draw only the visible items
+ for (int visiblePos = 0; visiblePos < visibleItemCount; visiblePos++)
+ {
+ int actualIndex = topIndex + visiblePos;
+
+ // Stop if we've reached the end of the contact list
+ if (actualIndex >= itemCount) break;
+
+ RECT itemRect = {0, visiblePos * CONTACT_ITEM_HEIGHT, clientRect.right, (visiblePos + 1) * CONTACT_ITEM_HEIGHT};
+
+ // Draw the contact that should be visible at this position
+ DrawContactItem(hdc, itemRect, contacts[actualIndex], actualIndex == selectedIndex);
+ }
+
+ EndPaint(hWnd, &ps);
+ return 0;
+ }
+ break;
+ }
+
+ return CallWindowProc(originalListBoxProc, hWnd, msg, wParam, lParam);
+}
\ No newline at end of file
diff --git a/Samples/ChatAppShare/ShareApp/WindowProcs.h b/Samples/ChatAppShare/ShareApp/WindowProcs.h
new file mode 100644
index 0000000..97c8623
--- /dev/null
+++ b/Samples/ChatAppShare/ShareApp/WindowProcs.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include
+
+// Window procedures
+LRESULT CALLBACK ModernButtonProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+LRESULT CALLBACK ModernListBoxProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+// Original window procedures storage
+extern WNDPROC originalButtonProc;
+extern WNDPROC originalListBoxProc;
+
+// Setup functions
+void SetupCustomWindowProcs();
\ No newline at end of file
diff --git a/Samples/ChatAppShare/ShareApp/framework.h b/Samples/ChatAppShare/ShareApp/framework.h
new file mode 100644
index 0000000..414c103
--- /dev/null
+++ b/Samples/ChatAppShare/ShareApp/framework.h
@@ -0,0 +1,29 @@
+// header.h : include file for standard system include files,
+// or project specific include files
+//
+
+#pragma once
+
+#include "targetver.h"
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+
+// Windows Header Files
+#include
+
+// WinRT Headers for Share Target functionality
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+// C RunTime Header Files
+#include
+#include
+#include
+#include
diff --git a/Samples/ChatAppShare/ShareApp/small.ico b/Samples/ChatAppShare/ShareApp/small.ico
new file mode 100644
index 0000000..b3ec03b
Binary files /dev/null and b/Samples/ChatAppShare/ShareApp/small.ico differ
diff --git a/Samples/ChatAppShare/ShareApp/targetver.h b/Samples/ChatAppShare/ShareApp/targetver.h
new file mode 100644
index 0000000..bf75e08
--- /dev/null
+++ b/Samples/ChatAppShare/ShareApp/targetver.h
@@ -0,0 +1,6 @@
+#pragma once
+
+// // Including SDKDDKVer.h defines the highest available Windows platform.
+// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
+// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
+#include
diff --git a/Samples/ChatAppShare/Weixin_1.0.2.0_x86__v4k3sbdawh17a.msix b/Samples/ChatAppShare/Weixin_1.0.2.0_x86__v4k3sbdawh17a.msix
new file mode 100644
index 0000000..b5c2681
Binary files /dev/null and b/Samples/ChatAppShare/Weixin_1.0.2.0_x86__v4k3sbdawh17a.msix differ
diff --git a/Samples/PackageWithExternalLocation/cppwinrt/PackageWithExternalLocationCppApp/WinMain.cpp b/Samples/PackageWithExternalLocation/cppwinrt/PackageWithExternalLocationCppApp/WinMain.cpp
index 9815300..37e154b 100644
--- a/Samples/PackageWithExternalLocation/cppwinrt/PackageWithExternalLocationCppApp/WinMain.cpp
+++ b/Samples/PackageWithExternalLocation/cppwinrt/PackageWithExternalLocationCppApp/WinMain.cpp
@@ -2,16 +2,29 @@
#include
#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include // Add this include for GetCurrentPackageFullName
+#include
using namespace winrt;
using namespace winrt::Windows::Management::Deployment;
using namespace winrt::Windows::ApplicationModel::Activation;
+using namespace winrt::Windows::ApplicationModel::DataTransfer::ShareTarget;
+using namespace winrt::Windows::ApplicationModel::DataTransfer;
+using namespace winrt::Windows::Storage;
#pragma comment(lib, "mfplat.lib")
#pragma comment(lib, "mf.lib")
#pragma comment(lib, "mfreadwrite.lib")
#pragma comment(lib, "evr.lib")
#pragma comment(lib, "d3d9.lib")
+#pragma comment(lib, "Shell32.lib")
using namespace Microsoft::WRL;
@@ -164,6 +177,41 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
return DefWindowProc(hwnd, msg, wParam, lParam);
}
+// Checks if the OS version is Windows 10 2004 (build 19041) or later
+bool IsSparsePackageSupported()
+{
+ // Windows 10 2004 is version 10.0.19041
+ OSVERSIONINFOEXW osvi = {};
+ osvi.dwOSVersionInfoSize = sizeof(osvi);
+
+ // Get the actual version using RtlGetVersion (undocumented but reliable)
+ typedef LONG (WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOEXW);
+ HMODULE hMod = ::GetModuleHandleW(L"ntdll.dll");
+ if (hMod) {
+ RtlGetVersionPtr fxPtr = (RtlGetVersionPtr)::GetProcAddress(hMod, "RtlGetVersion");
+ if (fxPtr != nullptr) {
+ fxPtr((PRTL_OSVERSIONINFOEXW)&osvi);
+ wchar_t log[256];
+ swprintf_s(log, L"Current OS Version: %u.%u.%u\n", osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber);
+ OutputDebugStringW(log);
+ }
+ }
+
+ // Log the required version
+ OutputDebugStringW(L"Required minimum version: 10.0.19041\n");
+
+ // Compare with required version
+ if (osvi.dwMajorVersion > 10 ||
+ (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion > 0) ||
+ (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0 && osvi.dwBuildNumber >= 19041))
+ {
+ OutputDebugStringW(L"Sparse package is supported on this OS.\n");
+ return true;
+ }
+ OutputDebugStringW(L"Sparse package is NOT supported on this OS.\n");
+ return false;
+}
+
HRESULT RegisterPackageWithExternalLocation(const std::wstring& externalLocation, const std::wstring& packagePath)
{
winrt::Windows::Management::Deployment::PackageManager packageManager;
@@ -174,7 +222,88 @@ HRESULT RegisterPackageWithExternalLocation(const std::wstring& externalLocation
return static_cast(result.ExtendedErrorCode().value);
}
-int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow)
+// Returns true if the app is running with package identity
+bool IsRunningWithIdentity()
+{
+ UINT32 length = 0;
+ LONG rc = GetCurrentPackageFullName(&length, nullptr);
+
+ // Existing code remains unchanged
+ if (rc == ERROR_INSUFFICIENT_BUFFER)
+ {
+ std::wstring packageFullName(length, L'\0');
+ rc = GetCurrentPackageFullName(&length, packageFullName.data());
+ return rc == ERROR_SUCCESS;
+ }
+ return false;
+}
+
+// Relaunches the current executable
+void RelaunchApplication()
+{
+ wchar_t exePath[MAX_PATH] = {0};
+ // Ensure the buffer is zero-initialized and check for errors
+ DWORD len = GetModuleFileNameW(nullptr, exePath, MAX_PATH);
+ if (len == 0 || len == MAX_PATH)
+ return; // Failed to get path or path too long
+
+ // Use ShellExecuteW to relaunch the current executable
+ HINSTANCE result = ShellExecuteW(nullptr, L"open", exePath, nullptr, nullptr, SW_SHOWNORMAL);
+ if ((INT_PTR)result <= 32)
+ {
+ // Optionally log or handle the error here
+ OutputDebugStringW(L"Failed to relaunch application.\n");
+ }
+}
+
+// Add this function to handle share activation
+winrt::Windows::Foundation::IAsyncAction HandleShareTarget(winrt::Windows::Foundation::IInspectable const& args)
+{
+ auto shareArgs = args.as();
+ ShareOperation shareOperation = shareArgs.ShareOperation();
+
+ if (shareOperation.Data().Contains(StandardDataFormats::Bitmap()))
+ {
+ auto bitmapRef = co_await shareOperation.Data().GetBitmapAsync();
+ // TODO: Convert bitmapRef to a format you can display in your Win32 window
+ MessageBox(nullptr, L"Received a bitmap via Share Target.", L"Share Target", MB_OK);
+ shareOperation.ReportCompleted();
+ }
+ else if (shareOperation.Data().Contains(StandardDataFormats::StorageItems()))
+ {
+ winrt::Windows::Foundation::Collections::IVectorView items = co_await shareOperation.Data().GetStorageItemsAsync();
+ for (auto const& item : items)
+ {
+ if (auto file = item.try_as())
+ {
+ std::wstring msg = L"Received file: " + std::wstring(file.Name().c_str());
+ MessageBox(nullptr, msg.c_str(), L"Share Target", MB_OK);
+ }
+ }
+ shareOperation.ReportCompleted();
+ }
+ else
+ {
+ MessageBox(nullptr, L"No supported image format received.", L"Share Target", MB_OK);
+ shareOperation.ReportCompleted();
+ }
+}
+
+// Helper to get the directory of the current executable (build output path)
+std::wstring GetExecutableDirectory()
+{
+ wchar_t exePath[MAX_PATH] = {0};
+ DWORD len = GetModuleFileNameW(nullptr, exePath, MAX_PATH);
+ if (len == 0 || len == MAX_PATH)
+ return L"";
+ std::wstring path(exePath);
+ size_t pos = path.find_last_of(L"\\/");
+ if (pos != std::wstring::npos)
+ path = path.substr(0, pos);
+ return path;
+}
+
+int RunWebcamAppMainLoop(HINSTANCE hInstance, int nCmdShow)
{
MFStartup(MF_VERSION);
@@ -195,7 +324,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow)
ShowWindow(hwndVideo, nCmdShow);
// Initialize webcam
- if (FAILED(InitializeWebcam(hwndVideo)))
+ if (FAILED(InitializeWebcam(hwndVideo)))
{
MessageBox(nullptr, L"Failed to initialize webcam. Please check if app is running with identity. If not, turn on camera usage for desktop app in Settings and relaunch.", L"Error", MB_ICONERROR);
return -1;
@@ -203,7 +332,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow)
// Main message loop
MSG msg = {};
- while (GetMessage(&msg, nullptr, 0, 0))
+ while (GetMessage(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
@@ -212,6 +341,53 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow)
return 0;
}
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow)
+{
+ if (!IsSparsePackageSupported())
+ {
+ OutputDebugStringW(L"Sparse package is not supported. Application is not running with package identity.\n");
+ return RunWebcamAppMainLoop(hInstance, nCmdShow);
+ }
+
+ winrt::init_apartment();
+
+ // Check if running with identity
+ if (!IsRunningWithIdentity())
+ {
+ // Given that for this installer we are not creating any installer, externalLocation is derived from the build output directory
+ // Replace this with Existing unpackaged App Install root location here.
+ std::wstring externalLocation = GetExecutableDirectory();
+
+ // Since your Sparse package(Package with external location) .msix file will be located in the existing unpackaged app install root location,
+ // use the same externalLocation to get .msix.
+ // For this sample to work, you would need to create .msix((Package with external location)) at same location as the build executable.
+ std::wstring packagePath = externalLocation + L"\\PackageWithExternalLocationCppSample_1.0.0.0_x86__8h66172c634n0.msix";
+
+ HRESULT hr = RegisterPackageWithExternalLocation(externalLocation, packagePath);
+ if (SUCCEEDED(hr))
+ {
+ RelaunchApplication();
+ return 0;
+ }
+ else
+ {
+ OutputDebugStringW(L"Application is not running with package identity.\n");
+ return RunWebcamAppMainLoop(hInstance, nCmdShow);
+ }
+ }
+
+ auto activationArgs = winrt::Windows::ApplicationModel::AppInstance::GetActivatedEventArgs();
+ if (activationArgs)
+ {
+ if (activationArgs.Kind() == winrt::Windows::ApplicationModel::Activation::ActivationKind::ShareTarget)
+ {
+ HandleShareTarget(activationArgs).get(); // Wait for coroutine to finish
+ return 0;
+ }
+ }
+ return RunWebcamAppMainLoop(hInstance, nCmdShow);
+}
+
void RemovePackageWithExternalLocation() // example of how to uninstall a package with external location
{
winrt::Windows::Management::Deployment::PackageManager packageManager;
diff --git a/Samples/PackageWithExternalLocation/cppwinrt/PackageWithExternalLocationCppSample/AppxManifest.xml b/Samples/PackageWithExternalLocation/cppwinrt/PackageWithExternalLocationCppSample/AppxManifest.xml
index 6728cb6..47ea56e 100644
--- a/Samples/PackageWithExternalLocation/cppwinrt/PackageWithExternalLocationCppSample/AppxManifest.xml
+++ b/Samples/PackageWithExternalLocation/cppwinrt/PackageWithExternalLocationCppSample/AppxManifest.xml
@@ -1,5 +1,5 @@
-
-
+
+
+
+
+
+
+ .jpg
+ .jpeg
+ .png
+ .gif
+
+ StorageItems
+ Bitmap
+
+
+
\ No newline at end of file
diff --git a/Samples/PackageWithExternalLocation/cppwinrt/PackageWithExternalLocationCppSample/resources.pri b/Samples/PackageWithExternalLocation/cppwinrt/PackageWithExternalLocationCppSample/resources.pri
new file mode 100644
index 0000000..d78fac5
Binary files /dev/null and b/Samples/PackageWithExternalLocation/cppwinrt/PackageWithExternalLocationCppSample/resources.pri differ
diff --git a/Samples/PackageWithExternalLocation/cppwinrt/README.md b/Samples/PackageWithExternalLocation/cppwinrt/README.md
new file mode 100644
index 0000000..3912c39
--- /dev/null
+++ b/Samples/PackageWithExternalLocation/cppwinrt/README.md
@@ -0,0 +1,39 @@
+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
+
+### PackageWithExternalLocationCppApp
+
+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 and handling of Shared photos happens in WinMain.cpp.
+
+* Files to package and sign to create a Sparse Package for use with the app are located in the PackageWithExternalLocationCppSample directory.
+
+
+### 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\\\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 PackageWithExternalLocationCppApp.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 \ /p \ 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 the WinMain method (in WinMain.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
+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"
\ No newline at end of file
diff --git a/Samples/SampleChatAppWithShare/README.md b/Samples/SampleChatAppWithShare/README.md
new file mode 100644
index 0000000..c378030
--- /dev/null
+++ b/Samples/SampleChatAppWithShare/README.md
@@ -0,0 +1,41 @@
+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.
+
+* Handling of Shared Data happens in ShareTargetManager.cpp.
+
+* Files to package and sign to create a Sparse Package for use with the app are located in the PackageWithExternalLocationCppSample directory inside PackageWithExternalLocation sample.
+
+
+### 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\\\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 \ /p \ 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"
\ No newline at end of file
diff --git a/Samples/SampleChatAppWithShare/SampleChatAppWithShare.sln b/Samples/SampleChatAppWithShare/SampleChatAppWithShare.sln
new file mode 100644
index 0000000..8833b0a
--- /dev/null
+++ b/Samples/SampleChatAppWithShare/SampleChatAppWithShare.sln
@@ -0,0 +1,37 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.14.36401.2 d17.14
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SampleChatAppWithShare", "SampleChatAppWithShare\SampleChatAppWithShare.vcxproj", "{DD6EC845-790A-4BD4-B638-AF0964704337}"
+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
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {6709D164-3EDF-4B1A-894A-2C561B2062CC}
+ EndGlobalSection
+EndGlobal
diff --git a/Samples/SampleChatAppWithShare/SampleChatAppWithShare/ChatManager.cpp b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/ChatManager.cpp
new file mode 100644
index 0000000..b00ebb6
--- /dev/null
+++ b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/ChatManager.cpp
@@ -0,0 +1,132 @@
+#include "ChatManager.h"
+#include "ChatModels.h"
+#include "FileManager.h"
+#include "UIManager.h"
+#include
+#include
+#include
+
+void LoadContactChat(int contactIndex)
+{
+ if (!IsValidContactIndex(contactIndex)) return;
+
+ selectedContactIndex = contactIndex;
+ const Contact& contact = contacts[contactIndex];
+
+ // Update contact name with status indicator
+ std::wstring headerText = contact.name + L" " + L" (" + contact.status + L")";
+ SetWindowText(hContactName, headerText.c_str());
+
+ // Clear and populate chat display with better formatting
+ SetWindowText(hChatDisplay, L"");
+
+ std::wstring chatText;
+ for (const auto& message : contact.messages) {
+ // Add timestamps and better message formatting
+ SYSTEMTIME st;
+ GetLocalTime(&st);
+ WCHAR timeStr[50];
+ swprintf_s(timeStr, 50, L"[%02d:%02d] ", st.wHour, st.wMinute);
+
+ if (message.find(L"You:") == 0) {
+ chatText += L" "; // Right align for your messages
+ chatText += timeStr + message + L"\r\n\r\n";
+ } else {
+ chatText += timeStr + message + L"\r\n\r\n";
+ }
+ }
+
+ SetWindowText(hChatDisplay, chatText.c_str());
+
+ // Scroll to bottom
+ ::SendMessage(hChatDisplay, EM_SETSEL, -1, -1);
+ ::SendMessage(hChatDisplay, EM_SCROLLCARET, 0, 0);
+
+ // Update shared files list
+ UpdateSharedFilesList();
+
+ // Refresh contact list to show selection
+ InvalidateRect(hContactsList, NULL, TRUE);
+}
+
+void AddMessageToChat(const std::wstring& message, bool isOutgoing)
+{
+ Contact* contact = GetSelectedContact();
+ if (!contact) return;
+
+ // Add timestamp to message
+ SYSTEMTIME st;
+ GetLocalTime(&st);
+ WCHAR timeStr[50];
+ swprintf_s(timeStr, 50, L"[%02d:%02d] ", st.wHour, st.wMinute);
+
+ std::wstring formattedMessage;
+ if (isOutgoing) {
+ formattedMessage = L"You: " + message + L" ??";
+ } else {
+ formattedMessage = contact->name + L": " + message;
+ }
+
+ contact->messages.push_back(formattedMessage);
+ contact->lastMessage = message.length() > 50 ? message.substr(0, 47) + L"..." : message;
+
+ // Update chat display
+ LoadContactChat(selectedContactIndex);
+
+ // Refresh contacts list to update last message preview
+ InvalidateRect(hContactsList, NULL, TRUE);
+}
+
+void SendChatMessage()
+{
+ if (selectedContactIndex < 0) return;
+
+ WCHAR buffer[1024];
+ GetWindowText(hMessageInput, buffer, 1024);
+
+ std::wstring message(buffer);
+ if (!message.empty()) {
+ AddMessageToChat(message, true);
+ SetWindowText(hMessageInput, L"");
+
+ // Simulate auto-reply after a short delay
+ SetTimer(GetParent(hMessageInput), 1, 2000, NULL);
+ }
+}
+
+void ProcessAutoReply(HWND hWnd, int timerType)
+{
+ if (selectedContactIndex < 0) return;
+
+ KillTimer(hWnd, timerType);
+
+ if (timerType == 1) {
+ // Auto-reply from the selected contact with more variety
+ std::vector autoReplies = {
+ L"Got it!",
+ L"Thanks for letting me know!",
+ L"Sounds good!",
+ L"I'll get back to you soon.",
+ L"Perfect!",
+ L"Absolutely!",
+ L"Let me think about it.",
+ L"Great idea!"
+ };
+
+ int replyIndex = rand() % autoReplies.size();
+ AddMessageToChat(autoReplies[replyIndex], false);
+ }
+ else if (timerType == 2) {
+ // Auto-reply acknowledging the shared file
+ std::vector fileReplies = {
+ L"Thanks for sharing the file!",
+ L"Got the file, will check it out.",
+ L"File received, thanks! ??",
+ L"Perfect timing, I needed this file.",
+ L"Awesome, downloading now!"
+ };
+
+ int replyIndex = rand() % fileReplies.size();
+ AddMessageToChat(fileReplies[replyIndex], false);
+ }
+}
\ No newline at end of file
diff --git a/Samples/SampleChatAppWithShare/SampleChatAppWithShare/ChatManager.h b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/ChatManager.h
new file mode 100644
index 0000000..daefb88
--- /dev/null
+++ b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/ChatManager.h
@@ -0,0 +1,10 @@
+#pragma once
+
+#include
+#include
+
+// Chat management functions
+void LoadContactChat(int contactIndex);
+void SendChatMessage();
+void AddMessageToChat(const std::wstring& message, bool isOutgoing);
+void ProcessAutoReply(HWND hWnd, int timerType);
\ No newline at end of file
diff --git a/Samples/SampleChatAppWithShare/SampleChatAppWithShare/ChatModels.cpp b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/ChatModels.cpp
new file mode 100644
index 0000000..db4f520
--- /dev/null
+++ b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/ChatModels.cpp
@@ -0,0 +1,48 @@
+#include "ChatModels.h"
+
+// Global data definitions
+std::vector contacts;
+std::map> chatHistory;
+int selectedContactIndex = -1;
+
+void InitializeContacts()
+{
+ contacts = {
+ {L"Alice Johnson", L"Hey, how are you?", {L"Alice: Hey, how are you?", L"You: I'm doing great, thanks!", L"Alice: That's wonderful to hear!"}, {}, L"Available", true},
+ {L"Bob Smith", L"See you tomorrow!", {L"Bob: Are we still meeting tomorrow?", L"You: Yes, see you at 3 PM", L"Bob: See you tomorrow!"}, {}, L"In a meeting", true},
+ {L"Carol Williams", L"Thanks for the help", {L"Carol: Could you help me with the project?", L"You: Of course! What do you need?", L"Carol: Thanks for the help"}, {}, L"Available", true},
+ {L"David Brown", L"Great presentation!", {L"David: Great presentation today!", L"You: Thank you! I'm glad you liked it"}, {}, L"Away", false},
+ {L"Emma Davis", L"Coffee later?", {L"Emma: Want to grab coffee later?", L"You: Sure! What time works for you?", L"Emma: Coffee later?"}, {}, L"Available", true},
+ {L"Frank Miller", L"Happy Birthday!", {L"Frank: Happy Birthday!", L"You: Thank you so much!"}, {}, L"Busy", true},
+ {L"Grace Wilson", L"Meeting rescheduled", {L"Grace: Meeting has been rescheduled to 4 PM", L"You: Got it, thanks for letting me know"}, {}, L"Available", true},
+ {L"Henry Taylor", L"Weekend plans?", {L"Henry: Any plans for the weekend?", L"You: Nothing concrete yet", L"Henry: Weekend plans?"}, {}, L"Offline", false},
+ {L"Ivy Anderson", L"Project update", {L"Ivy: Here's the project update you requested", L"You: Perfect, reviewing it now"}, {}, L"Available", true},
+ {L"Jack Thompson", L"Game night Friday", {L"Jack: Game night this Friday?", L"You: Count me in!", L"Jack: Game night Friday"}, {}, L"Gaming", true},
+ {L"Kate Garcia", L"Recipe sharing", {L"Kate: Loved that recipe you shared!", L"You: I'm so glad you enjoyed it!"}, {}, L"Cooking", true},
+ {L"Leo Martinez", L"Workout buddy", {L"Leo: Gym session tomorrow morning?", L"You: Absolutely! 7 AM as usual?"}, {}, L"At the gym", true},
+ {L"Mia Rodriguez", L"Book recommendation", {L"Mia: Any good book recommendations?", L"You: I just finished a great mystery novel"}, {}, L"Reading", true},
+ {L"Noah Lee", L"Tech discussion", {L"Noah: Thoughts on the new framework?", L"You: It looks promising! Want to discuss over lunch?"}, {}, L"Coding", true},
+ {L"Olivia Clark", L"Travel planning", {L"Olivia: Planning the vacation itinerary", L"You: Excited to see what you've planned!"}, {}, L"Traveling", false}
+ };
+
+ // Add some sample shared files to demonstrate the feature
+ SYSTEMTIME st;
+ GetSystemTime(&st);
+
+ contacts[0].sharedFiles.push_back({L"Project_Proposal.docx", L"C:\\Documents\\Project_Proposal.docx", L"Alice", st});
+ contacts[1].sharedFiles.push_back({L"Meeting_Notes.pdf", L"C:\\Documents\\Meeting_Notes.pdf", L"Bob", st});
+ contacts[2].sharedFiles.push_back({L"Budget_Spreadsheet.xlsx", L"C:\\Documents\\Budget_Spreadsheet.xlsx", L"Carol", st});
+}
+
+Contact* GetSelectedContact()
+{
+ if (IsValidContactIndex(selectedContactIndex)) {
+ return &contacts[selectedContactIndex];
+ }
+ return nullptr;
+}
+
+bool IsValidContactIndex(int index)
+{
+ return index >= 0 && index < (int)contacts.size();
+}
\ No newline at end of file
diff --git a/Samples/SampleChatAppWithShare/SampleChatAppWithShare/ChatModels.h b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/ChatModels.h
new file mode 100644
index 0000000..3fb7531
--- /dev/null
+++ b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/ChatModels.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#include
+#include
+#include
+#include
+
+struct SharedFile {
+ std::wstring fileName;
+ std::wstring filePath;
+ std::wstring sharedBy;
+ SYSTEMTIME timeShared;
+};
+
+struct Contact {
+ std::wstring name;
+ std::wstring lastMessage;
+ std::vector messages;
+ std::vector sharedFiles;
+ std::wstring status;
+ bool isOnline;
+};
+
+// Global data
+extern std::vector contacts;
+extern std::map> chatHistory;
+extern int selectedContactIndex;
+
+// Contact management functions
+void InitializeContacts();
+Contact* GetSelectedContact();
+bool IsValidContactIndex(int index);
\ No newline at end of file
diff --git a/Samples/SampleChatAppWithShare/SampleChatAppWithShare/ContactSelectionDialog.cpp b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/ContactSelectionDialog.cpp
new file mode 100644
index 0000000..ba1aeca
--- /dev/null
+++ b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/ContactSelectionDialog.cpp
@@ -0,0 +1,275 @@
+#include "ContactSelectionDialog.h"
+#include "Resource.h"
+#include "UIConstants.h"
+#include
+
+// Static member initialization
+ContactSelectionDialog::SelectionResult ContactSelectionDialog::s_dialogResult;
+std::wstring ContactSelectionDialog::s_currentFilePath;
+std::wstring ContactSelectionDialog::s_currentFileName;
+
+ContactSelectionDialog::SelectionResult ContactSelectionDialog::ShowContactSelectionDialog(HWND hParent, const std::wstring& filePath, const std::wstring& fileName)
+{
+ // Store the file information for the dialog
+ s_currentFilePath = filePath;
+ s_currentFileName = fileName;
+
+ // Reset the result
+ s_dialogResult = SelectionResult();
+
+ // Show the modal dialog
+ INT_PTR result = DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_CONTACT_SELECTION), hParent, ContactSelectionDlgProc);
+
+ if (result == IDOK)
+ {
+ s_dialogResult.wasSelected = true;
+ s_dialogResult.filePath = s_currentFilePath;
+ s_dialogResult.fileName = s_currentFileName;
+ }
+ else
+ {
+ s_dialogResult.wasSelected = false;
+ }
+
+ return s_dialogResult;
+}
+
+INT_PTR CALLBACK ContactSelectionDialog::ContactSelectionDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message)
+ {
+ case WM_INITDIALOG:
+ {
+ // Set the dialog title with file name
+ std::wstring title = L"Share \"" + s_currentFileName + L"\" - Select Contact";
+ SetWindowText(hDlg, title.c_str());
+
+ // Set up the dialog layout and styling
+ SetupDialogSizing(hDlg);
+
+ // Initialize and populate the contact list
+ HWND hListBox = GetDlgItem(hDlg, IDC_CONTACT_SELECTION_LIST);
+ if (hListBox)
+ {
+ InitializeContactList(hListBox);
+ PopulateContactList(hListBox);
+ }
+
+ // Set up the share message edit control
+ HWND hMessageEdit = GetDlgItem(hDlg, IDC_SHARE_MESSAGE_EDIT);
+ if (hMessageEdit)
+ {
+ std::wstring defaultMessage = L"I'm sharing \"" + s_currentFileName + L"\" with you!";
+ SetWindowText(hMessageEdit, defaultMessage.c_str());
+ }
+
+ // Initially disable the Select button until a contact is chosen
+ EnableWindow(GetDlgItem(hDlg, IDC_SELECT_CONTACT_BUTTON), FALSE);
+
+ // Center the dialog on the parent
+ RECT rcParent, rcDlg;
+ HWND hParent = GetParent(hDlg);
+ if (hParent)
+ {
+ GetWindowRect(hParent, &rcParent);
+ GetWindowRect(hDlg, &rcDlg);
+
+ int x = rcParent.left + (rcParent.right - rcParent.left - (rcDlg.right - rcDlg.left)) / 2;
+ int y = rcParent.top + (rcParent.bottom - rcParent.top - (rcDlg.bottom - rcDlg.top)) / 2;
+
+ SetWindowPos(hDlg, HWND_TOP, x, y, 0, 0, SWP_NOSIZE);
+ }
+
+ return TRUE;
+ }
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDC_CONTACT_SELECTION_LIST:
+ if (HIWORD(wParam) == LBN_SELCHANGE)
+ {
+ int selectedIndex = (int)SendDlgItemMessage(hDlg, IDC_CONTACT_SELECTION_LIST, LB_GETCURSEL, 0, 0);
+ HandleContactSelection(hDlg, selectedIndex);
+ }
+ else if (HIWORD(wParam) == LBN_DBLCLK)
+ {
+ // Double-click selects and closes dialog
+ OnSelectContact(hDlg);
+ }
+ break;
+
+ case IDC_SELECT_CONTACT_BUTTON:
+ OnSelectContact(hDlg);
+ break;
+
+ case IDC_CANCEL_SELECTION_BUTTON:
+ case IDCANCEL:
+ OnCancel(hDlg);
+ break;
+
+ case IDOK:
+ OnSelectContact(hDlg);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ OnCancel(hDlg);
+ break;
+ }
+
+ return FALSE;
+}
+
+void ContactSelectionDialog::InitializeContactList(HWND hListBox)
+{
+ // Set up the list box for contact display
+ SendMessage(hListBox, LB_RESETCONTENT, 0, 0);
+}
+
+void ContactSelectionDialog::PopulateContactList(HWND hListBox)
+{
+ // Clear existing items
+ SendMessage(hListBox, LB_RESETCONTENT, 0, 0);
+
+ // Ensure contacts are initialized
+ if (contacts.empty())
+ {
+ InitializeContacts();
+ }
+
+ // Debug logging
+ OutputDebugStringW((L"ContactSelectionDialog: Populating list with " + std::to_wstring(contacts.size()) + L" contacts\n").c_str());
+
+ // Add all contacts to the list
+ for (size_t i = 0; i < contacts.size(); ++i)
+ {
+ const Contact& contact = contacts[i];
+
+ // Create display text with contact name and status
+ std::wstring displayText = contact.name + L" - " + contact.status;
+ if (!contact.isOnline)
+ {
+ displayText += L" (Offline)";
+ }
+
+ int itemIndex = (int)SendMessage(hListBox, LB_ADDSTRING, 0, (LPARAM)displayText.c_str());
+
+ // Store the contact index as item data
+ SendMessage(hListBox, LB_SETITEMDATA, itemIndex, (LPARAM)i);
+
+ // Debug log each contact being added
+ OutputDebugStringW((L"ContactSelectionDialog: Added contact " + std::to_wstring(i) + L": " + contact.name + L"\n").c_str());
+ }
+
+ // If no contacts were added, add a placeholder
+ if (contacts.empty())
+ {
+ SendMessage(hListBox, LB_ADDSTRING, 0, (LPARAM)L"No contacts available");
+ OutputDebugStringW(L"ContactSelectionDialog: No contacts available - added placeholder\n");
+ }
+ else
+ {
+ OutputDebugStringW((L"ContactSelectionDialog: Successfully populated " + std::to_wstring(contacts.size()) + L" contacts\n").c_str());
+ }
+}
+
+void ContactSelectionDialog::HandleContactSelection(HWND hDlg, int selectedIndex)
+{
+ if (selectedIndex != LB_ERR)
+ {
+ // Enable the Select button when a contact is selected
+ EnableWindow(GetDlgItem(hDlg, IDC_SELECT_CONTACT_BUTTON), TRUE);
+
+ // Get the contact index from item data
+ HWND hListBox = GetDlgItem(hDlg, IDC_CONTACT_SELECTION_LIST);
+ int contactIndex = (int)SendMessage(hListBox, LB_GETITEMDATA, selectedIndex, 0);
+
+ if (contactIndex >= 0 && contactIndex < (int)contacts.size())
+ {
+ // Update the share message with the selected contact's name
+ const Contact& contact = contacts[contactIndex];
+ std::wstring personalizedMessage = L"Hey " + contact.name + L"! I'm sharing \"" + s_currentFileName + L"\" with you.";
+
+ HWND hMessageEdit = GetDlgItem(hDlg, IDC_SHARE_MESSAGE_EDIT);
+ if (hMessageEdit)
+ {
+ SetWindowText(hMessageEdit, personalizedMessage.c_str());
+ }
+ }
+ }
+ else
+ {
+ // Disable the Select button when no contact is selected
+ EnableWindow(GetDlgItem(hDlg, IDC_SELECT_CONTACT_BUTTON), FALSE);
+ }
+}
+
+void ContactSelectionDialog::OnSelectContact(HWND hDlg)
+{
+ HWND hListBox = GetDlgItem(hDlg, IDC_CONTACT_SELECTION_LIST);
+ int selectedIndex = (int)SendMessage(hListBox, LB_GETCURSEL, 0, 0);
+
+ if (selectedIndex == LB_ERR)
+ {
+ MessageBox(hDlg, L"Please select a contact to share with.", L"No Contact Selected", MB_OK | MB_ICONWARNING);
+ return;
+ }
+
+ // Check if contacts are available
+ if (contacts.empty())
+ {
+ MessageBox(hDlg, L"No contacts are available. Please ensure the application is properly initialized.", L"No Contacts Available", MB_OK | MB_ICONWARNING);
+ return;
+ }
+
+ // Get the contact index from item data
+ int contactIndex = (int)SendMessage(hListBox, LB_GETITEMDATA, selectedIndex, 0);
+
+ // Debug logging
+ OutputDebugStringW((L"ContactSelectionDialog: Selected contact index: " + std::to_wstring(contactIndex) + L", total contacts: " + std::to_wstring(contacts.size()) + L"\n").c_str());
+
+ if (contactIndex >= 0 && contactIndex < (int)contacts.size())
+ {
+ // Get the share message
+ HWND hMessageEdit = GetDlgItem(hDlg, IDC_SHARE_MESSAGE_EDIT);
+ WCHAR messageBuffer[512] = {0};
+ if (hMessageEdit)
+ {
+ GetWindowText(hMessageEdit, messageBuffer, 512);
+ }
+
+ // Store the result
+ s_dialogResult.contactIndex = contactIndex;
+ s_dialogResult.shareMessage = messageBuffer;
+
+ // Debug logging
+ OutputDebugStringW((L"ContactSelectionDialog: Contact selected - " + contacts[contactIndex].name + L"\n").c_str());
+
+ // Close dialog with success
+ EndDialog(hDlg, IDOK);
+ }
+ else
+ {
+ MessageBox(hDlg, L"Invalid contact selection. Please try again.", L"Selection Error", MB_OK | MB_ICONERROR);
+ OutputDebugStringW((L"ContactSelectionDialog: Invalid contact index: " + std::to_wstring(contactIndex) + L"\n").c_str());
+ }
+}
+
+void ContactSelectionDialog::OnCancel(HWND hDlg)
+{
+ // Close dialog with cancel
+ EndDialog(hDlg, IDCANCEL);
+}
+
+void ContactSelectionDialog::SetupDialogSizing(HWND hDlg)
+{
+ // Set dialog size (approximately 400x500 pixels)
+ SetWindowPos(hDlg, NULL, 0, 0, 420, 520, SWP_NOMOVE | SWP_NOZORDER);
+}
+
+void ContactSelectionDialog::ApplyModernStyling(HWND hDlg)
+{
+ // Modern styling is optional for now - skip to avoid dependencies
+}
\ No newline at end of file
diff --git a/Samples/SampleChatAppWithShare/SampleChatAppWithShare/ContactSelectionDialog.h b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/ContactSelectionDialog.h
new file mode 100644
index 0000000..fc06ffe
--- /dev/null
+++ b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/ContactSelectionDialog.h
@@ -0,0 +1,45 @@
+#pragma once
+
+#include
+#include
+#include
+#include "ChatModels.h"
+
+// Contact Selection Dialog Manager
+class ContactSelectionDialog
+{
+public:
+ // Structure to hold the result of contact selection
+ struct SelectionResult
+ {
+ bool wasSelected;
+ int contactIndex;
+ std::wstring shareMessage;
+ std::wstring filePath;
+ std::wstring fileName;
+
+ SelectionResult() : wasSelected(false), contactIndex(-1) {}
+ };
+
+ // Show the contact selection dialog
+ static SelectionResult ShowContactSelectionDialog(HWND hParent, const std::wstring& filePath, const std::wstring& fileName);
+
+private:
+ // Dialog procedure for contact selection
+ static INT_PTR CALLBACK ContactSelectionDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
+
+ // Helper functions
+ static void InitializeContactList(HWND hListBox);
+ static void PopulateContactList(HWND hListBox);
+ static void UpdateContactListDisplay(HWND hListBox);
+ static void HandleContactSelection(HWND hDlg, int selectedIndex);
+ static void OnSelectContact(HWND hDlg);
+ static void OnCancel(HWND hDlg);
+ static void SetupDialogSizing(HWND hDlg);
+ static void ApplyModernStyling(HWND hDlg);
+
+ // Static data for dialog communication
+ static SelectionResult s_dialogResult;
+ static std::wstring s_currentFilePath;
+ static std::wstring s_currentFileName;
+};
\ No newline at end of file
diff --git a/Samples/SampleChatAppWithShare/SampleChatAppWithShare/FileManager.cpp b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/FileManager.cpp
new file mode 100644
index 0000000..31ace5f
--- /dev/null
+++ b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/FileManager.cpp
@@ -0,0 +1,154 @@
+#include "FileManager.h"
+#include "ChatModels.h"
+#include "ChatManager.h"
+#include "UIManager.h"
+#include
+#include
+
+#pragma comment(lib, "comdlg32.lib")
+
+// External declarations for UI window handles
+extern HWND hSharedFilesList;
+extern HWND hContactsList;
+
+void ShareFile()
+{
+ // Check if a contact is selected first
+ if (selectedContactIndex < 0) {
+ MessageBox(NULL, L"Please select a contact to share files with.", L"No Contact Selected", MB_OK | MB_ICONWARNING);
+ return;
+ }
+
+ // Get the main window handle (parent of the share file button)
+ HWND hMainWindow = GetParent(hSharedFilesList);
+ while (GetParent(hMainWindow))
+ {
+ hMainWindow = GetParent(hMainWindow);
+ }
+
+ OPENFILENAME ofn;
+ WCHAR szFile[260] = {0};
+
+ ZeroMemory(&ofn, sizeof(ofn));
+ ofn.lStructSize = sizeof(ofn);
+ ofn.hwndOwner = hMainWindow; // Set the main window as owner
+ ofn.lpstrFile = szFile;
+ ofn.nMaxFile = sizeof(szFile);
+ ofn.lpstrFilter = L"All Files\0*.*\0?? Text Files\0*.TXT\0?? Document Files\0*.DOC;*.DOCX\0??? Image Files\0*.BMP;*.JPG;*.PNG;*.GIF\0?? PDF Files\0*.PDF\0?? Excel Files\0*.XLS;*.XLSX\0";
+ ofn.nFilterIndex = 1;
+ ofn.lpstrFileTitle = NULL;
+ ofn.nMaxFileTitle = 0;
+ ofn.lpstrInitialDir = NULL;
+ ofn.lpstrTitle = L"Select File to Share";
+ ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_EXPLORER;
+
+ if (GetOpenFileName(&ofn))
+ {
+ // Extract file name from full path
+ std::wstring fullPath(szFile);
+ size_t lastSlash = fullPath.find_last_of(L"\\");
+ std::wstring fileName;
+ if (lastSlash != std::wstring::npos)
+ {
+ fileName = fullPath.substr(lastSlash + 1);
+ }
+ else
+ {
+ fileName = fullPath;
+ }
+
+ // Create shared file entry
+ SharedFile newFile;
+ newFile.fileName = fileName;
+ newFile.filePath = fullPath;
+ newFile.sharedBy = L"You";
+ GetSystemTime(&newFile.timeShared);
+
+ // Add file to the currently selected contact's shared files
+ if (selectedContactIndex >= 0 && selectedContactIndex < (int)contacts.size())
+ {
+ contacts[selectedContactIndex].sharedFiles.push_back(newFile);
+
+ // Add file sharing notification to chat
+ std::wstring fileShareMsg = L"?? Shared file: " + fileName;
+ AddMessageToChat(fileShareMsg, true);
+
+ // Update UI
+ AddSharedFileToChat(newFile, true);
+
+ // Update contacts list display to show the shared activity
+ InvalidateRect(hContactsList, NULL, TRUE);
+
+ // Show success message with current contact
+ std::wstring successMsg = L"File \"" + fileName + L"\" has been shared with " + contacts[selectedContactIndex].name + L"!";
+ MessageBox(hMainWindow, successMsg.c_str(), L"File Shared Successfully", MB_OK | MB_ICONINFORMATION);
+
+ // Simulate auto-reply from contact acknowledging the file
+ SetTimer(hMainWindow, 2, 2000, NULL);
+ }
+ }
+}
+
+void AddSharedFileToChat(const SharedFile& file, bool isOutgoing)
+{
+ Contact* contact = GetSelectedContact();
+ if (!contact) return;
+
+ std::wstring sharer = isOutgoing ? L"You" : contact->name;
+
+ // Format file sharing message with timestamp
+ SYSTEMTIME st;
+ GetLocalTime(&st);
+ WCHAR timeStr[50];
+ swprintf_s(timeStr, 50, L"[%02d:%02d] ", st.wHour, st.wMinute);
+
+ std::wstring shareMessage = sharer + L" shared: " + file.fileName + L" ??";
+ contact->messages.push_back(shareMessage);
+
+ // Update last message preview
+ contact->lastMessage = L"?? " + file.fileName;
+
+ // Add to shared files list
+ contact->sharedFiles.push_back(file);
+
+ // Refresh UI
+ LoadContactChat(selectedContactIndex);
+ UpdateSharedFilesList();
+}
+
+void OpenSharedFile(int fileIndex)
+{
+ Contact* contact = GetSelectedContact();
+ if (!contact || fileIndex < 0 || fileIndex >= (int)contact->sharedFiles.size()) {
+ return;
+ }
+
+ const SharedFile& file = contact->sharedFiles[fileIndex];
+
+ // Try to open the file with the default application
+ HINSTANCE result = ShellExecute(NULL, L"open", file.filePath.c_str(), NULL, NULL, SW_SHOWNORMAL);
+
+ if ((intptr_t)result <= 32) {
+ // If opening failed, show file location in explorer
+ std::wstring explorerCmd = L"/select,\"" + file.filePath + L"\"";
+ ShellExecute(NULL, L"open", L"explorer.exe", explorerCmd.c_str(), NULL, SW_SHOWNORMAL);
+ }
+}
+
+void UpdateSharedFilesList()
+{
+ if (!hSharedFilesList) return;
+
+ Contact* contact = GetSelectedContact();
+
+ // Clear the list
+ SendMessage(hSharedFilesList, LB_RESETCONTENT, 0, 0);
+
+ if (!contact) return;
+
+ // Add shared files to the list
+ for (const auto& file : contact->sharedFiles) {
+ std::wstring displayText = file.fileName + L" (shared by " + file.sharedBy + L")";
+ SendMessage(hSharedFilesList, LB_ADDSTRING, 0, (LPARAM)displayText.c_str());
+ }
+}
\ No newline at end of file
diff --git a/Samples/SampleChatAppWithShare/SampleChatAppWithShare/FileManager.h b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/FileManager.h
new file mode 100644
index 0000000..e28e4db
--- /dev/null
+++ b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/FileManager.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include
+#include
+#include "ChatModels.h"
+
+// File management functions
+void ShareFile();
+void AddSharedFileToChat(const SharedFile& file, bool isOutgoing);
+void UpdateSharedFilesList();
+void OpenSharedFile(int fileIndex);
+std::wstring GetFileExtensionIcon(const std::wstring& filePath);
+std::wstring FormatFileSize(DWORD fileSize);
\ No newline at end of file
diff --git a/Samples/SampleChatAppWithShare/SampleChatAppWithShare/ModernUI.cpp b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/ModernUI.cpp
new file mode 100644
index 0000000..ca30eb2
--- /dev/null
+++ b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/ModernUI.cpp
@@ -0,0 +1,128 @@
+#include "ModernUI.h"
+#include "UIConstants.h"
+#include
+
+#pragma comment(lib, "gdiplus.lib")
+
+// Modern UI Variables definitions
+HBRUSH hBrushBackground = nullptr;
+HBRUSH hBrushSurface = nullptr;
+HBRUSH hBrushPrimary = nullptr;
+HBRUSH hBrushHover = nullptr;
+HFONT hFontRegular = nullptr;
+HFONT hFontBold = nullptr;
+HFONT hFontTitle = nullptr;
+HPEN hPenBorder = nullptr;
+
+void InitializeModernUI()
+{
+ // Create brushes for modern color scheme
+ hBrushBackground = CreateSolidBrush(COLOR_APP_BACKGROUND);
+ hBrushSurface = CreateSolidBrush(COLOR_SURFACE);
+ hBrushPrimary = CreateSolidBrush(COLOR_PRIMARY);
+ hBrushHover = CreateSolidBrush(COLOR_HOVER);
+
+ // Create modern fonts
+ hFontRegular = CreateFont(16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
+ DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
+ CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Segoe UI");
+
+ hFontBold = CreateFont(16, 0, 0, 0, FW_SEMIBOLD, FALSE, FALSE, FALSE,
+ DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
+ CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Segoe UI");
+
+ hFontTitle = CreateFont(20, 0, 0, 0, FW_SEMIBOLD, FALSE, FALSE, FALSE,
+ DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
+ CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Segoe UI");
+
+ // Create pen for borders
+ hPenBorder = CreatePen(PS_SOLID, 1, COLOR_BORDER);
+
+ // Initialize GDI+
+ Gdiplus::GdiplusStartupInput gdiplusStartupInput;
+ ULONG_PTR gdiplusToken;
+ Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
+}
+
+void CleanupModernUI()
+{
+ // Cleanup GDI objects
+ if (hBrushBackground) DeleteObject(hBrushBackground);
+ if (hBrushSurface) DeleteObject(hBrushSurface);
+ if (hBrushPrimary) DeleteObject(hBrushPrimary);
+ if (hBrushHover) DeleteObject(hBrushHover);
+ if (hFontRegular) DeleteObject(hFontRegular);
+ if (hFontBold) DeleteObject(hFontBold);
+ if (hFontTitle) DeleteObject(hFontTitle);
+ if (hPenBorder) DeleteObject(hPenBorder);
+
+ // Shutdown GDI+
+ Gdiplus::GdiplusShutdown(NULL);
+}
+
+void DrawModernButton(HDC hdc, RECT rect, const std::wstring& text, bool isHovered, bool isPressed)
+{
+ // Create rounded rectangle region
+ HRGN hRgn = CreateRoundRectRgn(rect.left, rect.top, rect.right, rect.bottom, 8, 8);
+
+ // Fill background
+ HBRUSH hBrush = CreateSolidBrush(isPressed ? COLOR_PRIMARY_DARK :
+ isHovered ? COLOR_PRIMARY : COLOR_PRIMARY);
+ FillRgn(hdc, hRgn, hBrush);
+ DeleteObject(hBrush);
+
+ // Draw border with a brush instead of pen
+ HBRUSH borderBrush = CreateSolidBrush(COLOR_BORDER);
+ FrameRgn(hdc, hRgn, borderBrush, 1, 1);
+ DeleteObject(borderBrush);
+ DeleteObject(hRgn);
+
+ // Draw text
+ SetBkMode(hdc, TRANSPARENT);
+ SetTextColor(hdc, RGB(255, 255, 255));
+ SelectObject(hdc, hFontBold);
+
+ DrawText(hdc, text.c_str(), -1, &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
+}
+
+void DrawContactItem(HDC hdc, RECT rect, const Contact& contact, bool isSelected)
+{
+ // Fill background
+ HBRUSH bgBrush = CreateSolidBrush(isSelected ? COLOR_HOVER : COLOR_SURFACE);
+ FillRect(hdc, &rect, bgBrush);
+ DeleteObject(bgBrush);
+
+ // Draw avatar circle
+ int avatarX = rect.left + 12;
+ int avatarY = rect.top + (rect.bottom - rect.top - AVATAR_SIZE) / 2;
+
+ HBRUSH avatarBrush = CreateSolidBrush(COLOR_PRIMARY);
+ HPEN avatarPen = CreatePen(PS_SOLID, 2, contact.isOnline ? RGB(34, 197, 94) : RGB(156, 163, 175));
+
+ SelectObject(hdc, avatarBrush);
+ SelectObject(hdc, avatarPen);
+
+ Ellipse(hdc, avatarX, avatarY, avatarX + AVATAR_SIZE, avatarY + AVATAR_SIZE);
+
+ DeleteObject(avatarBrush);
+ DeleteObject(avatarPen);
+
+ // Draw contact name
+ SetBkMode(hdc, TRANSPARENT);
+ SetTextColor(hdc, COLOR_TEXT_PRIMARY);
+ SelectObject(hdc, hFontBold);
+
+ RECT nameRect = {avatarX + AVATAR_SIZE + 12, rect.top + 8, rect.right - 8, rect.top + 28};
+ DrawText(hdc, contact.name.c_str(), -1, &nameRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
+
+ // Draw status
+ SetTextColor(hdc, COLOR_TEXT_SECONDARY);
+ SelectObject(hdc, hFontRegular);
+
+ RECT statusRect = {avatarX + AVATAR_SIZE + 12, rect.top + 30, rect.right - 8, rect.top + 48};
+ DrawText(hdc, contact.status.c_str(), -1, &statusRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
+
+ // Draw last message preview
+ RECT msgRect = {avatarX + AVATAR_SIZE + 12, rect.top + 50, rect.right - 8, rect.bottom - 8};
+ DrawText(hdc, contact.lastMessage.c_str(), -1, &msgRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
+}
\ No newline at end of file
diff --git a/Samples/SampleChatAppWithShare/SampleChatAppWithShare/ModernUI.h b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/ModernUI.h
new file mode 100644
index 0000000..3cb9ea7
--- /dev/null
+++ b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/ModernUI.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include
+#include
+#include "ChatModels.h"
+
+// Modern UI Variables
+extern HBRUSH hBrushBackground;
+extern HBRUSH hBrushSurface;
+extern HBRUSH hBrushPrimary;
+extern HBRUSH hBrushHover;
+extern HFONT hFontRegular;
+extern HFONT hFontBold;
+extern HFONT hFontTitle;
+extern HPEN hPenBorder;
+
+// Modern UI Functions
+void InitializeModernUI();
+void CleanupModernUI();
+void DrawModernButton(HDC hdc, RECT rect, const std::wstring& text, bool isHovered, bool isPressed);
+void DrawContactItem(HDC hdc, RECT rect, const Contact& contact, bool isSelected);
\ No newline at end of file
diff --git a/Samples/SampleChatAppWithShare/SampleChatAppWithShare/PackageIdentity.cpp b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/PackageIdentity.cpp
new file mode 100644
index 0000000..4f4ace9
--- /dev/null
+++ b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/PackageIdentity.cpp
@@ -0,0 +1,463 @@
+#include "framework.h"
+#include "PackageIdentity.h"
+#include
+#include
+#include
+#include
+#include
+
+// Package Identity Variables
+bool g_isSparsePackageSupported = false;
+bool g_isRunningWithIdentity = false;
+bool g_packageIdentityInitialized = false;
+
+// Initialize package identity management
+bool InitializePackageIdentity()
+{
+ if (g_packageIdentityInitialized)
+ return true;
+
+ OutputDebugStringW(L"ChatApp: Initializing package identity management...\n");
+
+ // Check OS support for sparse packages
+ g_isSparsePackageSupported = IsSparsePackageSupported();
+
+ // Check if already running with identity
+ g_isRunningWithIdentity = IsRunningWithIdentity();
+
+ g_packageIdentityInitialized = true;
+
+ wchar_t statusLog[256];
+ swprintf_s(statusLog, L"ChatApp: Package Identity Status - Sparse supported: %s, Has identity: %s\n",
+ g_isSparsePackageSupported ? L"Yes" : L"No",
+ g_isRunningWithIdentity ? L"Yes" : L"No");
+ OutputDebugStringW(statusLog);
+
+ return true;
+}
+
+// Register package with external location (improved implementation)
+HRESULT RegisterPackageWithExternalLocation(const std::wstring& externalLocation, const std::wstring& packagePath)
+{
+ try
+ {
+ OutputDebugStringW(L"ChatApp: Attempting to register package with external location...\n");
+
+ wchar_t logBuffer[512];
+ swprintf_s(logBuffer, L"ChatApp: External location: %s\n", externalLocation.c_str());
+ OutputDebugStringW(logBuffer);
+ swprintf_s(logBuffer, L"ChatApp: Package path: %s\n", packagePath.c_str());
+ OutputDebugStringW(logBuffer);
+
+ // Check if the package file exists
+ DWORD fileAttributes = GetFileAttributesW(packagePath.c_str());
+ if (fileAttributes == INVALID_FILE_ATTRIBUTES)
+ {
+ OutputDebugStringW(L"ChatApp: Package file not found, trying PowerShell registration method.\n");
+ return RegisterPackageWithExternalLocationPowerShell(externalLocation, packagePath);
+ }
+
+ // Try PowerShell registration first as it's more reliable
+ HRESULT powershellResult = RegisterPackageWithExternalLocationPowerShell(externalLocation, packagePath);
+ if (SUCCEEDED(powershellResult))
+ {
+ OutputDebugStringW(L"ChatApp: Package registration via PowerShell succeeded.\n");
+ return powershellResult;
+ }
+
+ // If PowerShell failed, log the error
+ wchar_t errorLog[256];
+ swprintf_s(errorLog, L"ChatApp: PowerShell registration failed with HRESULT: 0x%08X\n", powershellResult);
+ OutputDebugStringW(errorLog);
+
+ // For now, return the PowerShell result since we don't have other registration methods implemented
+ return powershellResult;
+ }
+ catch (...)
+ {
+ OutputDebugStringW(L"ChatApp: Exception occurred during package registration\n");
+ return E_FAIL;
+ }
+}
+
+// Alternative implementation using PowerShell for package registration
+HRESULT RegisterPackageWithExternalLocationPowerShell(const std::wstring& externalLocation, const std::wstring& packagePath)
+{
+ try
+ {
+ OutputDebugStringW(L"ChatApp: Attempting PowerShell package registration...\n");
+
+ // Check if the package file exists
+ DWORD fileAttributes = GetFileAttributesW(packagePath.c_str());
+ if (fileAttributes == INVALID_FILE_ATTRIBUTES)
+ {
+ wchar_t errorLog[512];
+ swprintf_s(errorLog, L"ChatApp: Package file not found at: %s\n", packagePath.c_str());
+ OutputDebugStringW(errorLog);
+ return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+ }
+
+ // Build PowerShell command for MSIX package registration with external location
+ // Use Add-AppxPackage with -ExternalLocation parameter
+ std::wstring powershellCmd = L"powershell.exe -ExecutionPolicy Bypass -Command \"";
+ powershellCmd += L"try { ";
+ powershellCmd += L"Add-AppxPackage -Path '";
+ powershellCmd += packagePath;
+ powershellCmd += L"' -ExternalLocation '";
+ powershellCmd += externalLocation;
+ powershellCmd += L"' -ForceTargetApplicationShutdown; ";
+ powershellCmd += L"Write-Host 'Package registration successful'; ";
+ powershellCmd += L"exit 0; ";
+ powershellCmd += L"} catch { ";
+ powershellCmd += L"Write-Host ('Package registration failed: ' + $_.Exception.Message); ";
+ powershellCmd += L"exit 1; ";
+ powershellCmd += L"}\"";
+
+ wchar_t logBuffer[1024];
+ swprintf_s(logBuffer, L"ChatApp: PowerShell command: %s\n", powershellCmd.c_str());
+ OutputDebugStringW(logBuffer);
+
+ // Execute PowerShell command
+ STARTUPINFOW si = {};
+ PROCESS_INFORMATION pi = {};
+ si.cb = sizeof(si);
+ si.dwFlags = STARTF_USESHOWWINDOW;
+ si.wShowWindow = SW_HIDE;
+
+ BOOL success = CreateProcessW(
+ nullptr,
+ const_cast(powershellCmd.c_str()),
+ nullptr,
+ nullptr,
+ FALSE,
+ CREATE_NO_WINDOW,
+ nullptr,
+ nullptr,
+ &si,
+ &pi
+ );
+
+ if (success)
+ {
+ OutputDebugStringW(L"ChatApp: PowerShell process started, waiting for completion...\n");
+
+ // Wait for PowerShell to complete (with timeout)
+ DWORD waitResult = WaitForSingleObject(pi.hProcess, 60000); // Increased timeout for package registration
+
+ DWORD exitCode = 0;
+ if (waitResult == WAIT_OBJECT_0)
+ {
+ GetExitCodeProcess(pi.hProcess, &exitCode);
+ wchar_t exitLog[256];
+ swprintf_s(exitLog, L"ChatApp: PowerShell process completed with exit code: %d\n", exitCode);
+ OutputDebugStringW(exitLog);
+ }
+ else if (waitResult == WAIT_TIMEOUT)
+ {
+ OutputDebugStringW(L"ChatApp: PowerShell process timed out. Package registration may still be in progress.\n");
+ TerminateProcess(pi.hProcess, 1);
+ exitCode = 1;
+ }
+ else
+ {
+ DWORD waitError = GetLastError();
+ wchar_t waitLog[256];
+ swprintf_s(waitLog, L"ChatApp: Wait failed with error: %d\n", waitError);
+ OutputDebugStringW(waitLog);
+ exitCode = 1;
+ }
+
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+
+ return (exitCode == 0) ? S_OK : E_FAIL;
+ }
+ else
+ {
+ DWORD error = GetLastError();
+ wchar_t errorLog[256];
+ swprintf_s(errorLog, L"ChatApp: Failed to start PowerShell process. Error: %d\n", error);
+ OutputDebugStringW(errorLog);
+ return HRESULT_FROM_WIN32(error);
+ }
+ }
+ catch (...)
+ {
+ OutputDebugStringW(L"ChatApp: Exception occurred during PowerShell package registration\n");
+ return E_FAIL;
+ }
+}
+
+// Relaunch the current application
+void RelaunchApplication()
+{
+ OutputDebugStringW(L"ChatApp: Attempting to relaunch application...\n");
+
+ wchar_t exePath[MAX_PATH] = {0};
+ DWORD len = GetModuleFileNameW(nullptr, exePath, MAX_PATH);
+ if (len == 0 || len == MAX_PATH)
+ {
+ OutputDebugStringW(L"ChatApp: Failed to get executable path for relaunch.\n");
+ return;
+ }
+
+ // Log the executable path
+ wchar_t logBuffer[512];
+ swprintf_s(logBuffer, L"ChatApp: Relaunching: %s\n", exePath);
+ OutputDebugStringW(logBuffer);
+
+ // Add a small delay to allow package registration to complete
+ Sleep(2000);
+
+ // Use ShellExecuteW to relaunch the current executable
+ HINSTANCE result = ShellExecuteW(nullptr, L"open", exePath, nullptr, nullptr, SW_SHOWNORMAL);
+
+ // Fix: Use proper casting for x64 compatibility
+ INT_PTR resultValue = reinterpret_cast(result);
+ if (resultValue <= 32)
+ {
+ // Log the error
+ wchar_t errorLog[256];
+ swprintf_s(errorLog, L"ChatApp: Failed to relaunch application. ShellExecute error code: %lld\n",
+ static_cast(resultValue));
+ OutputDebugStringW(errorLog);
+
+ // Try alternative relaunch method using CreateProcess
+ OutputDebugStringW(L"ChatApp: Trying alternative relaunch method...\n");
+
+ STARTUPINFOW si = {};
+ PROCESS_INFORMATION pi = {};
+ si.cb = sizeof(si);
+ si.dwFlags = STARTF_USESHOWWINDOW;
+ si.wShowWindow = SW_SHOWNORMAL;
+
+ BOOL createResult = CreateProcessW(
+ exePath,
+ nullptr,
+ nullptr,
+ nullptr,
+ FALSE,
+ 0,
+ nullptr,
+ nullptr,
+ &si,
+ &pi
+ );
+
+ if (createResult)
+ {
+ OutputDebugStringW(L"ChatApp: Alternative relaunch method succeeded.\n");
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ }
+ else
+ {
+ DWORD createError = GetLastError();
+ wchar_t createErrorLog[256];
+ swprintf_s(createErrorLog, L"ChatApp: Alternative relaunch also failed. Error: %d\n", createError);
+ OutputDebugStringW(createErrorLog);
+ }
+ }
+ else
+ {
+ OutputDebugStringW(L"ChatApp: Application relaunch initiated successfully.\n");
+ }
+}
+
+// Checks if the OS version is Windows 10 2004 (build 19041) or later
+bool IsSparsePackageSupported()
+{
+ // Windows 10 2004 is version 10.0.19041
+ OSVERSIONINFOEXW osvi = {};
+ osvi.dwOSVersionInfoSize = sizeof(osvi);
+
+ // Get the actual version using RtlGetVersion (undocumented but reliable)
+ typedef LONG (WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOEXW);
+ HMODULE hMod = ::GetModuleHandleW(L"ntdll.dll");
+ if (hMod) {
+ RtlGetVersionPtr fxPtr = (RtlGetVersionPtr)::GetProcAddress(hMod, "RtlGetVersion");
+ if (fxPtr != nullptr) {
+ fxPtr((PRTL_OSVERSIONINFOEXW)&osvi);
+
+ // Log version information for debugging
+ wchar_t log[256];
+ swprintf_s(log, L"ChatApp: Current OS Version: %u.%u.%u\n",
+ osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber);
+ OutputDebugStringW(log);
+ }
+ }
+
+ // Compare with required version (Windows 10 2004 build 19041)
+ if (osvi.dwMajorVersion > 10 ||
+ (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion > 0) ||
+ (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0 && osvi.dwBuildNumber >= 19041))
+ {
+ OutputDebugStringW(L"ChatApp: Sparse package is supported on this OS.\n");
+ return true;
+ }
+
+ OutputDebugStringW(L"ChatApp: Sparse package is NOT supported on this OS.\n");
+ return false;
+}
+
+// Returns true if the app is running with package identity
+bool IsRunningWithIdentity()
+{
+ UINT32 length = 0;
+ LONG rc = GetCurrentPackageFullName(&length, nullptr);
+
+ if (rc == ERROR_INSUFFICIENT_BUFFER)
+ {
+ std::vector packageFullName(length);
+ rc = GetCurrentPackageFullName(&length, packageFullName.data());
+ if (rc == ERROR_SUCCESS)
+ {
+ OutputDebugStringW(L"ChatApp: Running with package identity.\n");
+ return true;
+ }
+ }
+
+ OutputDebugStringW(L"ChatApp: Not running with package identity.\n");
+ return false;
+}
+
+// Helper to get the directory of the current executable
+std::wstring GetExecutableDirectory()
+{
+ wchar_t exePath[MAX_PATH] = {0};
+ DWORD len = GetModuleFileNameW(nullptr, exePath, MAX_PATH);
+ if (len == 0 || len == MAX_PATH)
+ {
+ OutputDebugStringW(L"ChatApp: Failed to get executable path.\n");
+ return L"";
+ }
+
+ std::wstring path(exePath);
+ size_t pos = path.find_last_of(L"\\/");
+ if (pos != std::wstring::npos)
+ path = path.substr(0, pos);
+
+ return path;
+}
+
+// Initialize package identity-specific flows and features
+void InitializePackageIdentityFlow()
+{
+ OutputDebugStringW(L"ChatApp: Initializing package identity-specific flows...\n");
+
+ if (!g_isRunningWithIdentity) {
+ OutputDebugStringW(L"ChatApp: Not running with package identity - skipping identity-specific flows.\n");
+ return;
+ }
+
+ // TODO: Add package identity-specific initialization here:
+
+ // 1. Single Instance Management
+ // - Check for existing app instances
+ // - Register current instance
+ // - Handle instance redirection
+
+ // 2. Share Target Registration
+ // - Check for share target activation
+ // - Initialize share target handlers
+ // - Set up cross-process communication
+
+ // 3. Enhanced Security Features
+ // - Initialize secure file handling
+ // - Set up identity-based permissions
+ // - Enable enhanced data protection
+
+ // 4. App Model Integration
+ // - Register activation handlers
+ // - Set up background task support
+ // - Initialize notification system
+
+ OutputDebugStringW(L"ChatApp: Package identity flows initialized (placeholder - features to be implemented).\n");
+}
+
+// Helper to validate MSIX package existence and basic properties
+bool ValidateMsixPackage(const std::wstring& packagePath)
+{
+ OutputDebugStringW(L"ChatApp: Validating MSIX package...\n");
+
+ // Check if file exists
+ DWORD fileAttributes = GetFileAttributesW(packagePath.c_str());
+ if (fileAttributes == INVALID_FILE_ATTRIBUTES)
+ {
+ wchar_t errorLog[512];
+ swprintf_s(errorLog, L"ChatApp: MSIX package not found at: %s\n", packagePath.c_str());
+ OutputDebugStringW(errorLog);
+ return false;
+ }
+
+ // Check if it's a file (not a directory)
+ if (fileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ {
+ OutputDebugStringW(L"ChatApp: Package path points to a directory, not a file.\n");
+ return false;
+ }
+
+ // Check file extension
+ size_t dotPos = packagePath.find_last_of(L'.');
+ if (dotPos == std::wstring::npos)
+ {
+ OutputDebugStringW(L"ChatApp: Package file has no extension.\n");
+ return false;
+ }
+
+ std::wstring extension = packagePath.substr(dotPos);
+ std::transform(extension.begin(), extension.end(), extension.begin(), ::towlower);
+
+ if (extension != L".msix" && extension != L".appx")
+ {
+ wchar_t extLog[256];
+ swprintf_s(extLog, L"ChatApp: Package has unexpected extension: %s\n", extension.c_str());
+ OutputDebugStringW(extLog);
+ return false;
+ }
+
+ // Get file size
+ HANDLE hFile = CreateFileW(packagePath.c_str(), GENERIC_READ, FILE_SHARE_READ,
+ nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
+ if (hFile != INVALID_HANDLE_VALUE)
+ {
+ LARGE_INTEGER fileSize;
+ if (GetFileSizeEx(hFile, &fileSize))
+ {
+ wchar_t sizeLog[256];
+ swprintf_s(sizeLog, L"ChatApp: Package size: %lld bytes\n", fileSize.QuadPart);
+ OutputDebugStringW(sizeLog);
+ }
+ CloseHandle(hFile);
+ }
+
+ OutputDebugStringW(L"ChatApp: MSIX package validation passed.\n");
+ return true;
+}
+
+// Get current package identity status as a formatted string
+std::wstring GetPackageIdentityStatus()
+{
+ std::wstring status = L"ChatApp Package Identity Status:\n";
+ status += L"- Sparse package supported: " + std::wstring(g_isSparsePackageSupported ? L"Yes" : L"No") + L"\n";
+ status += L"- Running with identity: " + std::wstring(g_isRunningWithIdentity ? L"Yes" : L"No") + L"\n";
+ status += L"- Initialized: " + std::wstring(g_packageIdentityInitialized ? L"Yes" : L"No") + L"\n";
+
+ if (g_isRunningWithIdentity)
+ {
+ // Try to get package full name
+ UINT32 length = 0;
+ LONG rc = GetCurrentPackageFullName(&length, nullptr);
+ if (rc == ERROR_INSUFFICIENT_BUFFER && length > 0)
+ {
+ std::vector packageFullName(length);
+ rc = GetCurrentPackageFullName(&length, packageFullName.data());
+ if (rc == ERROR_SUCCESS)
+ {
+ status += L"- Package full name: " + std::wstring(packageFullName.data()) + L"\n";
+ }
+ }
+ }
+
+ return status;
+}
\ No newline at end of file
diff --git a/Samples/SampleChatAppWithShare/SampleChatAppWithShare/PackageIdentity.h b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/PackageIdentity.h
new file mode 100644
index 0000000..e97fa85
--- /dev/null
+++ b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/PackageIdentity.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include
+#include
+
+// Package Identity Variables
+extern bool g_isSparsePackageSupported;
+extern bool g_isRunningWithIdentity;
+extern bool g_packageIdentityInitialized;
+
+// Package Identity Management functions
+bool IsSparsePackageSupported();
+bool IsRunningWithIdentity();
+bool InitializePackageIdentity();
+void InitializePackageIdentityFlow();
+std::wstring GetExecutableDirectory();
+HRESULT RegisterPackageWithExternalLocation(const std::wstring& externalLocation, const std::wstring& packagePath);
+HRESULT RegisterPackageWithExternalLocationPowerShell(const std::wstring& externalLocation, const std::wstring& packagePath);
+void RelaunchApplication();
+
+// Helper functions
+bool ValidateMsixPackage(const std::wstring& packagePath);
+std::wstring GetPackageIdentityStatus();
\ No newline at end of file
diff --git a/Samples/SampleChatAppWithShare/SampleChatAppWithShare/Resource.h b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/Resource.h
new file mode 100644
index 0000000..e41d7d3
--- /dev/null
+++ b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/Resource.h
@@ -0,0 +1,48 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by SampleChatAppWithShare.rc
+
+#define IDS_APP_TITLE 103
+
+#define IDR_MAINFRAME 128
+#define IDD_SAMPLECHATAPPWITHSHARE_DIALOG 102
+#define IDD_ABOUTBOX 103
+#define IDD_CONTACT_SELECTION 104
+#define IDM_ABOUT 105
+#define IDM_EXIT 106
+#define IDI_SAMPLECHATAPPWITHSHARE 107
+#define IDI_SMALL 108
+#define IDC_SAMPLECHATAPPWITHSHARE 109
+#define IDC_MYICON 2
+
+// Chat Application Controls
+#define IDC_CONTACTS_LIST 1001
+#define IDC_CHAT_DISPLAY 1002
+#define IDC_MESSAGE_INPUT 1003
+#define IDC_SEND_BUTTON 1004
+#define IDC_CONTACT_NAME 1005
+#define IDC_SHARE_FILE_BUTTON 1006
+#define IDC_SHARED_FILES_LIST 1007
+
+// Contact Selection Dialog Controls
+#define IDC_CONTACT_SELECTION_LIST 1008
+#define IDC_SELECT_CONTACT_BUTTON 1009
+#define IDC_CANCEL_SELECTION_BUTTON 1010
+#define IDC_SHARE_MESSAGE_EDIT 1011
+#define IDC_DIALOG_TITLE 1012
+
+#ifndef IDC_STATIC
+#define IDC_STATIC -1
+#endif
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+
+#define _APS_NO_MFC 130
+#define _APS_NEXT_RESOURCE_VALUE 129
+#define _APS_NEXT_COMMAND_VALUE 32771
+#define _APS_NEXT_CONTROL_VALUE 1013
+#define _APS_NEXT_SYMED_VALUE 110
+#endif
+#endif
diff --git a/Samples/SampleChatAppWithShare/SampleChatAppWithShare/SampleChatAppWithShare.cpp b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/SampleChatAppWithShare.cpp
new file mode 100644
index 0000000..ff6cdcd
--- /dev/null
+++ b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/SampleChatAppWithShare.cpp
@@ -0,0 +1,457 @@
+// SampleChatAppWithShare.cpp : Defines the entry point for the application.
+//
+
+#include "framework.h"
+#include "SampleChatAppWithShare.h"
+#include "UIConstants.h"
+#include "ChatModels.h"
+#include "ModernUI.h"
+#include "ChatManager.h"
+#include "FileManager.h"
+#include "UIManager.h"
+#include "PackageIdentity.h"
+#include "ShareTargetManager.h"
+#include "WindowProcs.h"
+#include
+#include
+#include
+#include
+#include
+
+#pragma comment(lib, "comctl32.lib")
+#pragma comment(lib, "shell32.lib")
+#pragma comment(lib, "uxtheme.lib")
+#pragma comment(lib, "ole32.lib")
+// Add WinRT libraries to fix linking error
+#pragma comment(lib, "windowsapp.lib")
+#pragma comment(lib, "runtimeobject.lib")
+
+using namespace winrt;
+using namespace Windows::Foundation;
+using namespace Windows::ApplicationModel;
+using namespace Windows::ApplicationModel::Activation;
+using namespace Windows::ApplicationModel::DataTransfer;
+using namespace Windows::ApplicationModel::DataTransfer::ShareTarget;
+
+// Global Variables:
+HINSTANCE hInst; // current instance
+WCHAR szTitle[MAX_LOADSTRING]; // The title bar text
+WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
+
+// Global flag to track if we're in share-only mode
+bool g_isShareOnlyMode = false;
+
+// Forward declarations of functions included in this code module:
+ATOM MyRegisterClass(HINSTANCE hInstance);
+BOOL InitInstance(HINSTANCE, int);
+LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
+INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
+
+int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
+ _In_opt_ HINSTANCE hPrevInstance,
+ _In_ LPWSTR lpCmdLine,
+ _In_ int nCmdShow)
+{
+ UNREFERENCED_PARAMETER(hPrevInstance);
+ UNREFERENCED_PARAMETER(lpCmdLine);
+
+ // Init package identity checks
+ InitializePackageIdentity();
+
+ // Initialize WinRT with proper error handling
+ try
+ {
+ winrt::init_apartment();
+ OutputDebugStringW(L"ChatApp: WinRT initialized successfully.\n");
+ }
+ catch (hresult_error const& ex)
+ {
+ std::wstring errorMsg = L"ChatApp: WinRT initialization failed: " + std::wstring(ex.message().c_str()) +
+ L" (HRESULT: 0x" + std::to_wstring(static_cast(ex.code())) + L")\n";
+ OutputDebugStringW(errorMsg.c_str());
+ }
+ catch (...)
+ {
+ OutputDebugStringW(L"ChatApp: WinRT initialization failed with unknown error.\n");
+ }
+
+ // Initialize Share Target Manager
+ ShareTargetManager::Initialize();
+
+ // Note: Don't process share target activation here - UI isn't created yet
+ // This will be handled after UI creation in WndProc WM_CREATE
+
+ // Check if this is a share target activation to determine if we need the main window
+ if (g_isRunningWithIdentity && ShareTargetManager::IsShareTargetActivation())
+ {
+ g_isShareOnlyMode = true;
+ OutputDebugStringW(L"ChatApp: Running in share-only mode - main window will not be created\n");
+ }
+
+ if (g_isSparsePackageSupported && !g_isRunningWithIdentity)
+ {
+ std::wstring executableDir = GetExecutableDirectory();
+ std::wstring packagePath = executableDir + L"\\Weixin_1.0.1.0_x86__v4k3sbdawh17a.msix";
+
+ // Validate the MSIX package before attempting registration
+ if (ValidateMsixPackage(packagePath))
+ {
+ HRESULT result = RegisterPackageWithExternalLocation(executableDir, packagePath);
+ if (SUCCEEDED(result))
+ {
+ OutputDebugStringW(L"ChatApp: Package registration succeeded. Relaunching...\n");
+ RelaunchApplication();
+ return 0; // Exit after relaunch
+ }
+ else
+ {
+ // Log the error but continue without package identity
+ wchar_t errorLog[256];
+ swprintf_s(errorLog, L"ChatApp: Failed to register package. HRESULT: 0x%08X. Continuing without package identity.\n", result);
+ OutputDebugStringW(errorLog);
+ }
+ }
+ else
+ {
+ OutputDebugStringW(L"ChatApp: MSIX package validation failed. Continuing without package identity.\n");
+ }
+ }
+ else if (g_isRunningWithIdentity)
+ {
+ // Process share target activation using the ShareTargetManager
+ ShareTargetManager::ProcessActivationArgs();
+ }
+ else
+ {
+ // Log the current status
+ std::wstring status = GetPackageIdentityStatus();
+ OutputDebugStringW(status.c_str());
+ }
+
+ // Initialize COM for shell operations
+ CoInitialize(NULL);
+
+ // Initialize common controls
+ INITCOMMONCONTROLSEX icex;
+ icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
+ icex.dwICC = ICC_LISTVIEW_CLASSES | ICC_STANDARD_CLASSES;
+ InitCommonControlsEx(&icex);
+
+ // Initialize global strings
+ LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
+ LoadStringW(hInstance, IDC_SAMPLECHATAPPWITHSHARE, szWindowClass, MAX_LOADSTRING);
+
+ if (!g_isShareOnlyMode)
+ {
+ // Only register window class if we're not in share-only mode
+ MyRegisterClass(hInstance);
+
+ // Initialize modern UI
+ InitializeModernUI();
+ }
+
+ // Initialize dummy contacts (needed for share target)
+ InitializeContacts();
+
+ if (g_isShareOnlyMode)
+ {
+ // In share-only mode, process the share target directly without creating a window
+ OutputDebugStringW(L"ChatApp: Processing share target in share-only mode\n");
+ ShareTargetManager::ProcessActivationArgs();
+ }
+ else
+ {
+ // Normal mode: create and show the main window
+ if (!InitInstance(hInstance, nCmdShow))
+ {
+ return FALSE;
+ }
+ }
+
+ HACCEL hAccelTable = nullptr;
+ if (!g_isShareOnlyMode)
+ {
+ hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_SAMPLECHATAPPWITHSHARE));
+ }
+
+ MSG msg;
+
+ // Main message loop:
+ while (GetMessage(&msg, nullptr, 0, 0))
+ {
+ if (!g_isShareOnlyMode && !TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ else if (g_isShareOnlyMode)
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+ CoUninitialize();
+ return (int) msg.wParam;
+}
+
+//
+// FUNCTION: MyRegisterClass()
+//
+// PURPOSE: Registers the window class.
+//
+ATOM MyRegisterClass(HINSTANCE hInstance)
+{
+ WNDCLASSEXW wcex;
+
+ wcex.cbSize = sizeof(WNDCLASSEX);
+
+ wcex.style = CS_HREDRAW | CS_VREDRAW;
+ wcex.lpfnWndProc = WndProc;
+ wcex.cbClsExtra = 0;
+ wcex.cbWndExtra = 0;
+ wcex.hInstance = hInstance;
+ wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_SAMPLECHATAPPWITHSHARE));
+ wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
+ wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
+ wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_SAMPLECHATAPPWITHSHARE);
+ wcex.lpszClassName = szWindowClass;
+ wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
+
+ return RegisterClassExW(&wcex);
+}
+
+//
+// FUNCTION: InitInstance(HINSTANCE, int)
+//
+// PURPOSE: Saves instance handle and creates main window
+//
+// COMMENTS:
+//
+// In this function, we save the instance handle in a global variable and
+// create and display the main program window.
+//
+BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
+{
+ hInst = hInstance; // Store instance handle in our global variable
+
+ HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT, 0, 1200, 700, nullptr, nullptr, hInstance, nullptr);
+
+ if (!hWnd)
+ {
+ return FALSE;
+ }
+
+ ShowWindow(hWnd, nCmdShow);
+ UpdateWindow(hWnd);
+
+ return TRUE;
+}
+
+//
+// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
+//
+// PURPOSE: Processes messages for the main window.
+//
+LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message)
+ {
+ case WM_CREATE:
+ CreateChatUI(hWnd);
+
+ // Process share target activation after UI is created
+ if (g_isRunningWithIdentity)
+ {
+ ShareTargetManager::ProcessActivationArgs();
+ }
+ break;
+
+ case WM_SIZE:
+ ResizeChatUI(hWnd);
+ break;
+
+ case WM_CTLCOLORSTATIC:
+ {
+ HDC hdcStatic = (HDC)wParam;
+ SetTextColor(hdcStatic, COLOR_TEXT_PRIMARY);
+ SetBkColor(hdcStatic, COLOR_APP_BACKGROUND);
+ return (INT_PTR)hBrushBackground;
+ }
+
+ case WM_CTLCOLOREDIT:
+ {
+ HDC hdcEdit = (HDC)wParam;
+ SetTextColor(hdcEdit, COLOR_TEXT_PRIMARY);
+ SetBkColor(hdcEdit, COLOR_SURFACE);
+ return (INT_PTR)hBrushSurface;
+ }
+
+ case WM_CTLCOLORLISTBOX:
+ {
+ HDC hdcList = (HDC)wParam;
+ SetTextColor(hdcList, COLOR_TEXT_PRIMARY);
+ SetBkColor(hdcList, COLOR_SURFACE);
+ return (INT_PTR)hBrushSurface;
+ }
+
+ case WM_PAINT:
+ {
+ PAINTSTRUCT ps;
+ HDC hdc = BeginPaint(hWnd, &ps);
+
+ // Fill the main window background with modern color
+ RECT rect;
+ GetClientRect(hWnd, &rect);
+ FillRect(hdc, &rect, hBrushBackground);
+
+ EndPaint(hWnd, &ps);
+ }
+ break;
+
+ case WM_COMMAND:
+ {
+ int wmId = LOWORD(wParam);
+ int wmEvent = HIWORD(wParam);
+
+ // Parse the menu selections:
+ switch (wmId)
+ {
+ case IDM_ABOUT:
+ DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
+ break;
+ case IDM_EXIT:
+ DestroyWindow(hWnd);
+ break;
+ case IDC_CONTACTS_LIST:
+ if (wmEvent == LBN_SELCHANGE) {
+ int selectedIndex = (int)::SendMessage(hContactsList, LB_GETCURSEL, 0, 0);
+ LoadContactChat(selectedIndex);
+ UpdateSharedFilesList();
+ }
+ break;
+ case IDC_SEND_BUTTON:
+ SendChatMessage();
+ break;
+ case IDC_SHARE_FILE_BUTTON:
+ ShareFile();
+ break;
+ case IDC_SHARED_FILES_LIST:
+ if (wmEvent == LBN_DBLCLK) {
+ int selectedFile = (int)::SendMessage(hSharedFilesList, LB_GETCURSEL, 0, 0);
+ OpenSharedFile(selectedFile);
+ }
+ break;
+ case IDC_MESSAGE_INPUT:
+ if (wmEvent == EN_CHANGE) {
+ // Enable/disable send button based on input with visual feedback
+ WCHAR buffer[1024];
+ GetWindowText(hMessageInput, buffer, 1024);
+ bool hasText = wcslen(buffer) > 0;
+ EnableWindow(hSendButton, hasText);
+ InvalidateRect(hSendButton, NULL, FALSE);
+ }
+ break;
+ case 2000: // Test WinRT Share Target Status
+ {
+ // Use ShareTargetManager to get status
+ std::wstring statusInfo = ShareTargetManager::GetShareTargetStatus();
+ MessageBoxW(hWnd, statusInfo.c_str(), L"WinRT Share Target Status", MB_OK | MB_ICONINFORMATION);
+ }
+ break;
+ default:
+ return DefWindowProc(hWnd, message, wParam, lParam);
+ }
+ }
+ break;
+
+ case WM_TIMER:
+ ProcessAutoReply(hWnd, (int)wParam);
+ break;
+
+ case WM_KEYDOWN:
+ {
+ if (GetFocus() == hMessageInput && wParam == VK_RETURN) {
+ if (!(GetKeyState(VK_SHIFT) & 0x8000)) {
+ // Enter without Shift sends the message
+ SendChatMessage();
+ return 0;
+ }
+ }
+ }
+ break;
+
+ case WM_DESTROY:
+ CleanupModernUI();
+ PostQuitMessage(0);
+ break;
+
+ default:
+ return DefWindowProc(hWnd, message, wParam, lParam);
+ }
+ return 0;
+}
+
+// Message handler for about box.
+INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ UNREFERENCED_PARAMETER(lParam);
+ switch (message)
+ {
+ case WM_INITDIALOG:
+ {
+ // Add WinRT and package identity information to the about dialog
+ std::wstring aboutText = L"Chat Application with WinRT Share Target Support\n\n";
+
+ // Test WinRT status
+ try
+ {
+ winrt::check_hresult(S_OK);
+ aboutText += L"? WinRT Status: ? Initialized and Working\n";
+
+ if (g_isRunningWithIdentity)
+ {
+ if (ShareTargetManager::IsShareTargetActivation())
+ {
+ aboutText += L"?? Share Target: ? Currently Activated via Windows Share Sheet\n";
+ }
+ else
+ {
+ aboutText += L"?? Share Target: ? Ready for Activation\n";
+ }
+ }
+ else
+ {
+ aboutText += L"?? Share Target: ? Package Identity Required\n";
+ }
+ }
+ catch (...)
+ {
+ aboutText += L"?? WinRT Status: ? Error or Not Available\n";
+ }
+
+ aboutText += L"?? Package Identity: " + std::wstring(g_isRunningWithIdentity ? L"? Available" : L"? Not Available") + L"\n";
+ aboutText += L"?? Sparse Package Support: " + std::wstring(g_isSparsePackageSupported ? L"? Supported" : L"? Not Supported") + L"\n\n";
+ aboutText += L"Current Features:\n";
+ aboutText += L"? WinRT Runtime Integration\n";
+ aboutText += L"? Windows Share Target Support\n";
+ aboutText += L"? Package Identity Management\n";
+ aboutText += L"? MSIX Package Registration\n";
+ aboutText += L"? Modern Chat UI\n\n";
+ aboutText += GetPackageIdentityStatus();
+
+ SetDlgItemTextW(hDlg, IDC_STATIC, aboutText.c_str());
+ return (INT_PTR)TRUE;
+ }
+
+ case WM_COMMAND:
+ if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
+ {
+ EndDialog(hDlg, LOWORD(wParam));
+ return (INT_PTR)TRUE;
+ }
+ break;
+ }
+ return (INT_PTR)FALSE;
+}
diff --git a/Samples/SampleChatAppWithShare/SampleChatAppWithShare/SampleChatAppWithShare.exe.manifest b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/SampleChatAppWithShare.exe.manifest
new file mode 100644
index 0000000..92ae86a
--- /dev/null
+++ b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/SampleChatAppWithShare.exe.manifest
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/Samples/SampleChatAppWithShare/SampleChatAppWithShare/SampleChatAppWithShare.h b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/SampleChatAppWithShare.h
new file mode 100644
index 0000000..d00d47e
--- /dev/null
+++ b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/SampleChatAppWithShare.h
@@ -0,0 +1,3 @@
+#pragma once
+
+#include "resource.h"
diff --git a/Samples/SampleChatAppWithShare/SampleChatAppWithShare/SampleChatAppWithShare.ico b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/SampleChatAppWithShare.ico
new file mode 100644
index 0000000..b3ec03b
Binary files /dev/null and b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/SampleChatAppWithShare.ico differ
diff --git a/Samples/SampleChatAppWithShare/SampleChatAppWithShare/SampleChatAppWithShare.rc b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/SampleChatAppWithShare.rc
new file mode 100644
index 0000000..966faca
Binary files /dev/null and b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/SampleChatAppWithShare.rc differ
diff --git a/Samples/SampleChatAppWithShare/SampleChatAppWithShare/SampleChatAppWithShare.vcxproj b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/SampleChatAppWithShare.vcxproj
new file mode 100644
index 0000000..131e855
--- /dev/null
+++ b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/SampleChatAppWithShare.vcxproj
@@ -0,0 +1,234 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+ Debug
+ ARM64
+
+
+ Release
+ ARM64
+
+
+
+ 17.0
+ Win32Proj
+ {dd6ec845-790a-4bd4-b638-af0964704337}
+ SampleChatAppWithShare
+ 10.0
+
+
+
+ Application
+ true
+ v143
+ Unicode
+
+
+ Application
+ false
+ v143
+ true
+ Unicode
+
+
+ Application
+ true
+ v143
+ Unicode
+
+
+ Application
+ false
+ v143
+ true
+ Unicode
+
+
+ Application
+ true
+ v143
+ Unicode
+
+
+ Application
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)
+ true
+ stdcpp17
+
+
+ Windows
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)
+ true
+ stdcpp17
+
+
+ Windows
+ true
+
+
+
+
+ Level3
+ true
+ _DEBUG;_WINDOWS;%(PreprocessorDefinitions)
+ true
+ stdcpp17
+
+
+ Windows
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_WINDOWS;%(PreprocessorDefinitions)
+ true
+ stdcpp17
+
+
+ Windows
+ true
+
+
+
+
+ Level3
+ true
+ _DEBUG;_WINDOWS;%(PreprocessorDefinitions)
+ true
+ stdcpp17
+
+
+ Windows
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_WINDOWS;%(PreprocessorDefinitions)
+ true
+ stdcpp17
+
+
+ Windows
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Samples/SampleChatAppWithShare/SampleChatAppWithShare/SampleChatAppWithShare.vcxproj.filters b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/SampleChatAppWithShare.vcxproj.filters
new file mode 100644
index 0000000..1bc4c91
--- /dev/null
+++ b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/SampleChatAppWithShare.vcxproj.filters
@@ -0,0 +1,97 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Resource Files
+
+
+
+
+ Resource Files
+
+
+ Resource Files
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Samples/SampleChatAppWithShare/SampleChatAppWithShare/ShareTargetManager.cpp b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/ShareTargetManager.cpp
new file mode 100644
index 0000000..82131dc
--- /dev/null
+++ b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/ShareTargetManager.cpp
@@ -0,0 +1,425 @@
+#include "ShareTargetManager.h"
+#include "PackageIdentity.h"
+#include "ContactSelectionDialog.h"
+#include "ChatManager.h"
+#include "ChatModels.h"
+#include "FileManager.h"
+#include "framework.h"
+#include
+
+// Static member initialization
+bool ShareTargetManager::s_initialized = false;
+bool ShareTargetManager::s_shareTargetSupported = false;
+
+void ShareTargetManager::Initialize()
+{
+ if (s_initialized)
+ return;
+
+ LogShareInfo(L"Initializing Share Target Manager...");
+
+ try
+ {
+ // Check if WinRT and package identity are available
+ if (g_isRunningWithIdentity)
+ {
+ s_shareTargetSupported = true;
+ LogShareInfo(L"Share Target support available with package identity.");
+ }
+ else
+ {
+ s_shareTargetSupported = false;
+ LogShareInfo(L"Share Target requires package identity (not available).");
+ }
+ }
+ catch (winrt::hresult_error const& ex)
+ {
+ std::wstring error = L"Share Target initialization error: " + std::wstring(ex.message().c_str());
+ LogShareError(error);
+ s_shareTargetSupported = false;
+ }
+ catch (...)
+ {
+ LogShareError(L"Unknown error during Share Target initialization.");
+ s_shareTargetSupported = false;
+ }
+
+ s_initialized = true;
+ LogShareInfo(L"Share Target Manager initialized successfully.");
+}
+
+bool ShareTargetManager::IsShareTargetAvailable()
+{
+ if (!s_initialized)
+ Initialize();
+
+ return s_shareTargetSupported && g_isRunningWithIdentity;
+}
+
+bool ShareTargetManager::IsShareTargetActivation()
+{
+ if (!IsShareTargetAvailable())
+ return false;
+
+ try
+ {
+ auto activationArgs = winrt::Windows::ApplicationModel::AppInstance::GetActivatedEventArgs();
+ return activationArgs && activationArgs.Kind() == winrt::Windows::ApplicationModel::Activation::ActivationKind::ShareTarget;
+ }
+ catch (...)
+ {
+ LogShareError(L"Error checking share target activation.");
+ return false;
+ }
+}
+
+bool ShareTargetManager::ProcessActivationArgs()
+{
+ if (!IsShareTargetAvailable())
+ return false;
+
+ // Add a static flag to prevent multiple processing
+ static bool s_alreadyProcessed = false;
+ if (s_alreadyProcessed) {
+ LogShareInfo(L"Share target already processed - skipping duplicate call");
+ return false;
+ }
+
+ try
+ {
+ auto activationArgs = winrt::Windows::ApplicationModel::AppInstance::GetActivatedEventArgs();
+ if (activationArgs && activationArgs.Kind() == winrt::Windows::ApplicationModel::Activation::ActivationKind::ShareTarget)
+ {
+ LogShareInfo(L"? Share Target activation detected!");
+ s_alreadyProcessed = true; // Mark as processed
+
+ // Ensure contacts are initialized (critical for share target scenarios)
+ if (contacts.empty())
+ {
+ LogShareInfo(L"Initializing contacts for share target scenario...");
+ InitializeContacts();
+ }
+
+ // Process the share target directly here
+ auto shareArgs = activationArgs.as();
+ auto shareOperation = shareArgs.ShareOperation();
+ auto data = shareOperation.Data();
+
+ // Extract shared content information for the contact selection dialog
+ std::wstring sharedContentSummary = L"Shared Content";
+ std::wstring sharedFiles;
+ bool hasFiles = false;
+
+ // Collect information about what's being shared
+ std::vector sharedItems;
+
+ // Check for different data formats
+ if (data.Contains(winrt::Windows::ApplicationModel::DataTransfer::StandardDataFormats::Text()))
+ {
+ try
+ {
+ auto textAsync = data.GetTextAsync();
+ auto text = textAsync.get();
+ sharedItems.push_back(L"Text: " + std::wstring(text.c_str()));
+ LogShareInfo(L"Received shared text.");
+ }
+ catch (...)
+ {
+ sharedItems.push_back(L"Text: [Error retrieving text]");
+ LogShareError(L"Error retrieving shared text.");
+ }
+ }
+
+ if (data.Contains(winrt::Windows::ApplicationModel::DataTransfer::StandardDataFormats::WebLink()))
+ {
+ try
+ {
+ auto webLinkAsync = data.GetWebLinkAsync();
+ auto webLink = webLinkAsync.get();
+ sharedItems.push_back(L"Web Link: " + std::wstring(webLink.ToString().c_str()));
+ LogShareInfo(L"Received shared web link.");
+ }
+ catch (...)
+ {
+ sharedItems.push_back(L"Web Link: [Error retrieving web link]");
+ LogShareError(L"Error retrieving shared web link.");
+ }
+ }
+
+ if (data.Contains(winrt::Windows::ApplicationModel::DataTransfer::StandardDataFormats::Bitmap()))
+ {
+ try
+ {
+ auto bitmapAsync = data.GetBitmapAsync();
+ auto bitmapRef = bitmapAsync.get();
+ sharedItems.push_back(L"Image/Bitmap content");
+ LogShareInfo(L"Received shared bitmap.");
+ }
+ catch (...)
+ {
+ sharedItems.push_back(L"Image: [Error retrieving image]");
+ LogShareError(L"Error retrieving shared bitmap.");
+ }
+ }
+
+ if (data.Contains(winrt::Windows::ApplicationModel::DataTransfer::StandardDataFormats::StorageItems()))
+ {
+ try
+ {
+ auto storageItemsAsync = data.GetStorageItemsAsync();
+ auto storageItems = storageItemsAsync.get();
+
+ hasFiles = true;
+ std::wstring filesInfo = std::to_wstring(storageItems.Size()) + L" file(s)";
+
+ if (storageItems.Size() == 1)
+ {
+ auto item = storageItems.GetAt(0);
+ sharedFiles = item.Name().c_str();
+ sharedContentSummary = sharedFiles;
+ }
+ else if (storageItems.Size() > 1)
+ {
+ sharedFiles = L"Multiple Files (" + std::to_wstring(storageItems.Size()) + L")";
+ sharedContentSummary = sharedFiles;
+ }
+
+ for (uint32_t i = 0; i < storageItems.Size(); i++)
+ {
+ auto item = storageItems.GetAt(i);
+ filesInfo += L"\n - " + std::wstring(item.Name().c_str());
+ }
+
+ sharedItems.push_back(filesInfo);
+ LogShareInfo(L"Received shared files.");
+ }
+ catch (...)
+ {
+ sharedItems.push_back(L"Files: [Error retrieving files]");
+ LogShareError(L"Error retrieving shared files.");
+ }
+ }
+
+ // If no specific content type found, use generic description
+ if (sharedItems.empty())
+ {
+ sharedContentSummary = L"Shared Content";
+ sharedItems.push_back(L"Unknown content type");
+ }
+
+ // Get the main window handle for dialog parent
+ HWND hMainWindow = GetActiveWindow();
+ if (!hMainWindow)
+ {
+ hMainWindow = GetForegroundWindow();
+ }
+ if (!hMainWindow)
+ {
+ // Try to find the main chat application window
+ hMainWindow = FindWindow(NULL, L"Chat Application");
+ }
+
+ // Log the number of contacts available for debugging
+ LogShareInfo(L"Available contacts: " + std::to_wstring(contacts.size()));
+
+ // Show contact selection dialog for the shared content
+ ContactSelectionDialog::SelectionResult result =
+ ContactSelectionDialog::ShowContactSelectionDialog(hMainWindow, L"", sharedContentSummary);
+
+ if (result.wasSelected)
+ {
+ // User selected a contact - add the shared content to that contact's chat
+ if (result.contactIndex >= 0 && result.contactIndex < (int)contacts.size())
+ {
+ int previousSelection = selectedContactIndex;
+ selectedContactIndex = result.contactIndex;
+
+ LogShareInfo(L"Setting selectedContactIndex to: " + std::to_wstring(result.contactIndex));
+ LogShareInfo(L"Selected contact name: " + contacts[result.contactIndex].name);
+
+ // Add messages directly to the selected contact instead of relying on selectedContactIndex
+ Contact& selectedContact = contacts[result.contactIndex];
+
+ // Add the custom share message if provided
+ if (!result.shareMessage.empty())
+ {
+ std::wstring formattedShareMessage = L"You: " + result.shareMessage + L" ??";
+ selectedContact.messages.push_back(formattedShareMessage);
+ LogShareInfo(L"Added share message: " + result.shareMessage);
+ }
+
+ // Add shared content messages to the chat
+ for (const auto& item : sharedItems)
+ {
+ std::wstring shareMsg = L"?? Received via Share: " + item;
+ std::wstring formattedMessage = selectedContact.name + L": " + shareMsg;
+ selectedContact.messages.push_back(formattedMessage);
+ LogShareInfo(L"Added shared content message: " + shareMsg);
+ }
+
+ // Update the last message preview for this contact
+ if (!sharedItems.empty())
+ {
+ std::wstring lastMsg = L"?? Received via Share: " + sharedItems[0];
+ selectedContact.lastMessage = lastMsg.length() > 50 ? lastMsg.substr(0, 47) + L"..." : lastMsg;
+ }
+
+ // If files were shared, add them to the contact's shared files list
+ if (hasFiles && data.Contains(winrt::Windows::ApplicationModel::DataTransfer::StandardDataFormats::StorageItems()))
+ {
+ try
+ {
+ auto storageItemsAsync = data.GetStorageItemsAsync();
+ auto storageItems = storageItemsAsync.get();
+
+ for (uint32_t i = 0; i < storageItems.Size(); i++)
+ {
+ auto item = storageItems.GetAt(i);
+
+ // Create shared file entry
+ SharedFile newFile;
+ newFile.fileName = item.Name().c_str();
+ newFile.filePath = item.Path().c_str(); // Get full path if available
+ newFile.sharedBy = L"External Share";
+ GetSystemTime(&newFile.timeShared);
+
+ selectedContact.sharedFiles.push_back(newFile);
+ LogShareInfo(L"Added shared file: " + newFile.fileName);
+ }
+ }
+ catch (...)
+ {
+ LogShareError(L"Error adding shared files to contact.");
+ }
+ }
+
+ // Show success message and exit the application
+ std::wstring successMsg = L"Content has been shared successfully with " + contacts[result.contactIndex].name + L"!\n\nThe application will now close.";
+ MessageBoxW(hMainWindow, successMsg.c_str(), L"Sharing Complete", MB_OK | MB_ICONINFORMATION);
+
+ LogShareInfo(L"Share target content added to contact: " + contacts[result.contactIndex].name);
+ LogShareInfo(L"Selected contact index set to: " + std::to_wstring(result.contactIndex));
+ LogShareInfo(L"Contact now has " + std::to_wstring(selectedContact.messages.size()) + L" messages");
+
+ // Report completion to Windows
+ shareOperation.ReportCompleted();
+
+ LogShareInfo(L"Share target processing completed successfully. Exiting application.");
+
+ // Exit the application after successful sharing
+ PostQuitMessage(0);
+ return true;
+ }
+ }
+ else
+ {
+ // User cancelled - show a brief message and exit
+ MessageBoxW(hMainWindow, L"Share operation was cancelled.\n\nThe application will now close.", L"Share Cancelled", MB_OK | MB_ICONINFORMATION);
+ LogShareInfo(L"Share target operation cancelled by user.");
+
+ // Report completion to Windows
+ shareOperation.ReportCompleted();
+
+ LogShareInfo(L"Share target processing cancelled. Exiting application.");
+
+ // Exit the application after cancellation
+ PostQuitMessage(0);
+ return true;
+ }
+
+ // Report completion to Windows
+ shareOperation.ReportCompleted();
+
+ LogShareInfo(L"Share target processing completed successfully.");
+ return true;
+ }
+ else
+ {
+ LogShareInfo(L"Running with package identity but not as share target.");
+ return false;
+ }
+ }
+ catch (winrt::hresult_error const& ex)
+ {
+ s_alreadyProcessed = true; // Mark as processed even on error to prevent retries
+ std::wstring error = L"Error checking activation args: " + std::wstring(ex.message().c_str()) +
+ L" (HRESULT: 0x" + std::to_wstring(static_cast(ex.code())) + L")";
+ LogShareError(error);
+ MessageBoxW(nullptr, L"Error processing shared content", L"Share Target Error", MB_OK | MB_ICONERROR);
+ return false;
+ }
+ catch (...)
+ {
+ s_alreadyProcessed = true; // Mark as processed even on error to prevent retries
+ LogShareError(L"Unknown error checking activation arguments.");
+ MessageBoxW(nullptr, L"Unknown error processing shared content", L"Share Target Error", MB_OK | MB_ICONERROR);
+ return false;
+ }
+}
+
+std::wstring ShareTargetManager::GetShareTargetStatus()
+{
+ if (!s_initialized)
+ Initialize();
+
+ std::wstring status = L"WinRT Share Target Integration Status:\n\n";
+
+ try
+ {
+ winrt::check_hresult(S_OK);
+ status += L"?? WinRT Runtime: ? Available and Working\n";
+ status += L"?? Package Identity: " + std::wstring(g_isRunningWithIdentity ? L"? Available" : L"? Not Available") + L"\n";
+ status += L"?? Sparse Package Support: " + std::wstring(g_isSparsePackageSupported ? L"? Supported" : L"? Not Supported") + L"\n\n";
+
+ // Test activation
+ if (g_isRunningWithIdentity)
+ {
+ try
+ {
+ if (IsShareTargetActivation())
+ {
+ status += L"?? Share Target: ? Currently Activated\n";
+ }
+ else
+ {
+ status += L"?? Share Target: ?? Not Currently Activated\n";
+ }
+ }
+ catch (...)
+ {
+ status += L"?? Share Target: ? Error Checking Activation\n";
+ }
+ }
+ else
+ {
+ status += L"?? Share Target: ? Package Identity Required\n";
+ }
+
+ status += GetPackageIdentityStatus();
+ status += L"\n\n?? WinRT Share Target integration is complete and ready!";
+ }
+ catch (winrt::hresult_error const& ex)
+ {
+ status += L"?? WinRT Runtime: ? Error\n";
+ status += L"Error: " + std::wstring(ex.message().c_str()) + L"\n";
+ status += L"HRESULT: 0x" + std::to_wstring(static_cast(ex.code())) + L"\n";
+ }
+ catch (...)
+ {
+ status += L"?? WinRT Runtime: ? Unknown Error\n";
+ }
+
+ return status;
+}
+
+void ShareTargetManager::LogShareInfo(const std::wstring& message)
+{
+ std::wstring logMessage = L"ChatApp: " + message + L"\n";
+ OutputDebugStringW(logMessage.c_str());
+}
+
+void ShareTargetManager::LogShareError(const std::wstring& error)
+{
+ std::wstring logMessage = L"ChatApp: ShareTarget ERROR - " + error + L"\n";
+ OutputDebugStringW(logMessage.c_str());
+}
\ No newline at end of file
diff --git a/Samples/SampleChatAppWithShare/SampleChatAppWithShare/ShareTargetManager.h b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/ShareTargetManager.h
new file mode 100644
index 0000000..2281410
--- /dev/null
+++ b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/ShareTargetManager.h
@@ -0,0 +1,33 @@
+#pragma once
+
+#include
+#include
+
+// Simple Share Target Manager with minimal dependencies
+class ShareTargetManager
+{
+public:
+ // Initialize the share target manager
+ static void Initialize();
+
+ // Check if the current activation is a share target
+ static bool IsShareTargetActivation();
+
+ // Check activation arguments and process if it's a share target
+ static bool ProcessActivationArgs();
+
+ // Get share target status information
+ static std::wstring GetShareTargetStatus();
+
+ // Check if share target is available (requires package identity)
+ static bool IsShareTargetAvailable();
+
+private:
+ // Logging helpers
+ static void LogShareInfo(const std::wstring& message);
+ static void LogShareError(const std::wstring& error);
+
+private:
+ static bool s_initialized;
+ static bool s_shareTargetSupported;
+};
\ No newline at end of file
diff --git a/Samples/SampleChatAppWithShare/SampleChatAppWithShare/UIConstants.h b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/UIConstants.h
new file mode 100644
index 0000000..ff28af5
--- /dev/null
+++ b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/UIConstants.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include
+
+// Include resource.h for resource constants
+#include "resource.h"
+
+// Modern UI Color Scheme
+#define COLOR_PRIMARY RGB(64, 128, 255) // Modern blue
+#define COLOR_PRIMARY_DARK RGB(45, 100, 220) // Darker blue for hover
+#define COLOR_APP_BACKGROUND RGB(248, 249, 250) // Light gray background
+#define COLOR_SURFACE RGB(255, 255, 255) // White surface
+#define COLOR_TEXT_PRIMARY RGB(33, 37, 41) // Dark text
+#define COLOR_TEXT_SECONDARY RGB(108, 117, 125) // Gray text
+#define COLOR_BORDER RGB(222, 226, 230) // Light border
+#define COLOR_HOVER RGB(248, 249, 250) // Hover background
+#define COLOR_CHAT_BUBBLE_OUT RGB(0, 123, 255) // Outgoing message
+#define COLOR_CHAT_BUBBLE_IN RGB(233, 236, 239) // Incoming message
+
+// UI Constants
+#define MAX_LOADSTRING 100
+#define CONTACT_ITEM_HEIGHT 72
+#define AVATAR_SIZE 40
\ No newline at end of file
diff --git a/Samples/SampleChatAppWithShare/SampleChatAppWithShare/UIManager.cpp b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/UIManager.cpp
new file mode 100644
index 0000000..bdd4808
--- /dev/null
+++ b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/UIManager.cpp
@@ -0,0 +1,142 @@
+#include "UIManager.h"
+#include "UIConstants.h"
+#include "ModernUI.h"
+#include "ChatModels.h"
+#include "FileManager.h"
+#include "WindowProcs.h"
+#include
+
+#pragma comment(lib, "comctl32.lib")
+
+// External declaration - hInst is defined in the main cpp file
+extern HINSTANCE hInst;
+
+// UI Window handles definitions
+HWND hContactsList = nullptr;
+HWND hChatDisplay = nullptr;
+HWND hMessageInput = nullptr;
+HWND hSendButton = nullptr;
+HWND hContactName = nullptr;
+HWND hShareFileButton = nullptr;
+HWND hSharedFilesList = nullptr;
+
+void CreateChatUI(HWND hWnd)
+{
+ RECT rect;
+ GetClientRect(hWnd, &rect);
+
+ int width = rect.right - rect.left;
+ int height = rect.bottom - rect.top;
+
+ // Set window background to modern color
+ SetClassLongPtr(hWnd, GCLP_HBRBACKGROUND, (LONG_PTR)hBrushBackground);
+
+ // Create contacts list (left panel) with modern styling
+ hContactsList = CreateWindowEx(
+ WS_EX_CLIENTEDGE,
+ L"LISTBOX", NULL,
+ WS_CHILD | WS_VISIBLE | WS_VSCROLL | LBS_NOTIFY | LBS_OWNERDRAWFIXED,
+ 20, 20, 280, height - 40,
+ hWnd, (HMENU)IDC_CONTACTS_LIST, hInst, NULL);
+
+ // Set custom item height for contact list
+ ::SendMessage(hContactsList, LB_SETITEMHEIGHT, 0, CONTACT_ITEM_HEIGHT);
+
+ // Create contact name label with modern styling
+ hContactName = CreateWindow(L"STATIC", L"Select a contact to start chatting",
+ WS_CHILD | WS_VISIBLE | SS_LEFT,
+ 320, 20, 300, 30,
+ hWnd, (HMENU)IDC_CONTACT_NAME, hInst, NULL);
+
+ // Create chat display area with modern styling
+ hChatDisplay = CreateWindowEx(
+ WS_EX_CLIENTEDGE,
+ L"EDIT", NULL,
+ WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_MULTILINE | ES_READONLY | ES_AUTOVSCROLL,
+ 320, 60, width - 600, height - 280,
+ hWnd, (HMENU)IDC_CHAT_DISPLAY, hInst, NULL);
+
+ // Create shared files section header
+ CreateWindow(L"STATIC", L"Shared Files",
+ WS_CHILD | WS_VISIBLE | SS_LEFT,
+ width - 260, 20, 120, 30,
+ hWnd, NULL, hInst, NULL);
+
+ // Create shared files list with modern styling
+ hSharedFilesList = CreateWindowEx(
+ WS_EX_CLIENTEDGE,
+ L"LISTBOX", NULL,
+ WS_CHILD | WS_VISIBLE | WS_VSCROLL | LBS_NOTIFY,
+ width - 260, 60, 240, height - 280,
+ hWnd, (HMENU)IDC_SHARED_FILES_LIST, hInst, NULL);
+
+ // Create message input with placeholder styling
+ hMessageInput = CreateWindowEx(
+ WS_EX_CLIENTEDGE,
+ L"EDIT", NULL,
+ WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_AUTOVSCROLL,
+ 320, height - 200, width - 600, 60,
+ hWnd, (HMENU)IDC_MESSAGE_INPUT, hInst, NULL);
+
+ // Create modern styled buttons
+ hSendButton = CreateWindow(L"BUTTON", L"Send",
+ WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_OWNERDRAW,
+ 320, height - 130, 100, 45,
+ hWnd, (HMENU)IDC_SEND_BUTTON, hInst, NULL);
+
+ hShareFileButton = CreateWindow(L"BUTTON", L"Share File",
+ WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_OWNERDRAW,
+ 440, height - 130, 120, 45,
+ hWnd, (HMENU)IDC_SHARE_FILE_BUTTON, hInst, NULL);
+
+ // Populate contacts list
+ for (const auto& contact : contacts) {
+ ::SendMessage(hContactsList, LB_ADDSTRING, 0, (LPARAM)contact.name.c_str());
+ }
+
+ // Apply modern fonts to controls
+ ::SendMessage(hContactName, WM_SETFONT, (WPARAM)hFontTitle, TRUE);
+ ::SendMessage(hChatDisplay, WM_SETFONT, (WPARAM)hFontRegular, TRUE);
+ ::SendMessage(hMessageInput, WM_SETFONT, (WPARAM)hFontRegular, TRUE);
+ ::SendMessage(hSharedFilesList, WM_SETFONT, (WPARAM)hFontRegular, TRUE);
+
+ // Subclass buttons for custom drawing
+ SetupCustomWindowProcs();
+
+ // Set modern background colors
+ SetupWindowColors();
+}
+
+void ResizeChatUI(HWND hWnd)
+{
+ RECT rect;
+ GetClientRect(hWnd, &rect);
+ int width = rect.right - rect.left;
+ int height = rect.bottom - rect.top;
+
+ if (hContactsList) {
+ SetWindowPos(hContactsList, NULL, 20, 20, 280, height - 40, SWP_NOZORDER);
+ }
+ if (hChatDisplay) {
+ SetWindowPos(hChatDisplay, NULL, 320, 60, width - 600, height - 280, SWP_NOZORDER);
+ }
+ if (hSharedFilesList) {
+ SetWindowPos(hSharedFilesList, NULL, width - 260, 60, 240, height - 280, SWP_NOZORDER);
+ }
+ if (hMessageInput) {
+ SetWindowPos(hMessageInput, NULL, 320, height - 200, width - 600, 60, SWP_NOZORDER);
+ }
+ if (hSendButton) {
+ SetWindowPos(hSendButton, NULL, 320, height - 130, 100, 45, SWP_NOZORDER);
+ }
+ if (hShareFileButton) {
+ SetWindowPos(hShareFileButton, NULL, 440, height - 130, 120, 45, SWP_NOZORDER);
+ }
+}
+
+void SetupWindowColors()
+{
+ SetClassLongPtr(hChatDisplay, GCLP_HBRBACKGROUND, (LONG_PTR)hBrushSurface);
+ SetClassLongPtr(hMessageInput, GCLP_HBRBACKGROUND, (LONG_PTR)hBrushSurface);
+ SetClassLongPtr(hSharedFilesList, GCLP_HBRBACKGROUND, (LONG_PTR)hBrushSurface);
+}
\ No newline at end of file
diff --git a/Samples/SampleChatAppWithShare/SampleChatAppWithShare/UIManager.h b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/UIManager.h
new file mode 100644
index 0000000..74c2a14
--- /dev/null
+++ b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/UIManager.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include
+
+// UI Window handles
+extern HWND hContactsList;
+extern HWND hChatDisplay;
+extern HWND hMessageInput;
+extern HWND hSendButton;
+extern HWND hContactName;
+extern HWND hShareFileButton;
+extern HWND hSharedFilesList;
+
+// UI management functions
+void CreateChatUI(HWND hWnd);
+void ResizeChatUI(HWND hWnd);
+void SetupWindowColors();
\ No newline at end of file
diff --git a/Samples/SampleChatAppWithShare/SampleChatAppWithShare/WindowProcs.cpp b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/WindowProcs.cpp
new file mode 100644
index 0000000..ce00862
--- /dev/null
+++ b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/WindowProcs.cpp
@@ -0,0 +1,168 @@
+#include "WindowProcs.h"
+#include "UIConstants.h"
+#include "ModernUI.h"
+#include "ChatModels.h"
+#include "UIManager.h"
+
+// External declarations for UI window handles
+extern HWND hSendButton;
+extern HWND hShareFileButton;
+extern HWND hContactsList;
+
+// Window procedure storage for subclassing
+WNDPROC originalButtonProc = nullptr;
+WNDPROC originalListBoxProc = nullptr;
+
+void SetupCustomWindowProcs()
+{
+ // Subclass buttons for custom drawing
+ originalButtonProc = (WNDPROC)SetWindowLongPtr(hSendButton, GWLP_WNDPROC, (LONG_PTR)ModernButtonProc);
+ SetWindowLongPtr(hShareFileButton, GWLP_WNDPROC, (LONG_PTR)ModernButtonProc);
+
+ // Subclass contact list for custom drawing
+ originalListBoxProc = (WNDPROC)SetWindowLongPtr(hContactsList, GWLP_WNDPROC, (LONG_PTR)ModernListBoxProc);
+}
+
+// Modern button subclass procedure
+LRESULT CALLBACK ModernButtonProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static bool isHovered = false;
+ static bool isPressed = false;
+
+ switch (msg)
+ {
+ case WM_PAINT:
+ {
+ PAINTSTRUCT ps;
+ HDC hdc = BeginPaint(hWnd, &ps);
+
+ RECT rect;
+ GetClientRect(hWnd, &rect);
+
+ WCHAR text[256];
+ GetWindowText(hWnd, text, 256);
+
+ DrawModernButton(hdc, rect, std::wstring(text), isHovered, isPressed);
+
+ EndPaint(hWnd, &ps);
+ return 0;
+ }
+
+ case WM_MOUSEMOVE:
+ if (!isHovered)
+ {
+ isHovered = true;
+ InvalidateRect(hWnd, NULL, FALSE);
+
+ TRACKMOUSEEVENT tme = {};
+ tme.cbSize = sizeof(tme);
+ tme.dwFlags = TME_LEAVE;
+ tme.hwndTrack = hWnd;
+ TrackMouseEvent(&tme);
+ }
+ break;
+
+ case WM_MOUSELEAVE:
+ isHovered = false;
+ InvalidateRect(hWnd, NULL, FALSE);
+ break;
+
+ case WM_LBUTTONDOWN:
+ isPressed = true;
+ InvalidateRect(hWnd, NULL, FALSE);
+ SetCapture(hWnd);
+ break;
+
+ case WM_LBUTTONUP:
+ if (isPressed)
+ {
+ isPressed = false;
+ InvalidateRect(hWnd, NULL, FALSE);
+ ReleaseCapture();
+
+ // Send click notification to parent
+ HWND hParent = GetParent(hWnd);
+ int controlId = GetDlgCtrlID(hWnd);
+ ::SendMessage(hParent, WM_COMMAND, MAKEWPARAM(controlId, BN_CLICKED), (LPARAM)hWnd);
+ }
+ break;
+ }
+
+ return CallWindowProc(originalButtonProc, hWnd, msg, wParam, lParam);
+}
+
+// Modern listbox subclass procedure
+LRESULT CALLBACK ModernListBoxProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg)
+ {
+ case WM_LBUTTONDOWN:
+ if (hWnd == hContactsList)
+ {
+ // Handle mouse click to ensure proper contact selection with scrolling
+ POINT pt = { LOWORD(lParam), HIWORD(lParam) };
+
+ // Calculate which contact was clicked based on the scroll position
+ int topIndex = (int)::SendMessage(hWnd, LB_GETTOPINDEX, 0, 0);
+ int clickedVisiblePos = pt.y / CONTACT_ITEM_HEIGHT;
+ int actualContactIndex = topIndex + clickedVisiblePos;
+
+ // Ensure the clicked contact is valid
+ if (actualContactIndex >= 0 && actualContactIndex < (int)contacts.size())
+ {
+ // Set the correct selection in the listbox
+ ::SendMessage(hWnd, LB_SETCURSEL, actualContactIndex, 0);
+
+ // Trigger the selection change event to update the UI
+ HWND hParent = GetParent(hWnd);
+ int controlId = GetDlgCtrlID(hWnd);
+ ::SendMessage(hParent, WM_COMMAND, MAKEWPARAM(controlId, LBN_SELCHANGE), (LPARAM)hWnd);
+
+ return 0; // We handled the click
+ }
+ }
+ break;
+
+ case WM_PAINT:
+ if (hWnd == hContactsList)
+ {
+ PAINTSTRUCT ps;
+ HDC hdc = BeginPaint(hWnd, &ps);
+
+ RECT clientRect;
+ GetClientRect(hWnd, &clientRect);
+
+ // Fill background
+ FillRect(hdc, &clientRect, hBrushSurface);
+
+ int itemCount = (int)contacts.size();
+ int selectedIndex = (int)::SendMessage(hWnd, LB_GETCURSEL, 0, 0);
+
+ // Get the first visible item index to handle scrolling correctly
+ int topIndex = (int)::SendMessage(hWnd, LB_GETTOPINDEX, 0, 0);
+
+ // Calculate how many items can be visible
+ int visibleItemCount = (clientRect.bottom / CONTACT_ITEM_HEIGHT) + 1;
+
+ // Draw only the visible items
+ for (int visiblePos = 0; visiblePos < visibleItemCount; visiblePos++)
+ {
+ int actualIndex = topIndex + visiblePos;
+
+ // Stop if we've reached the end of the contact list
+ if (actualIndex >= itemCount) break;
+
+ RECT itemRect = {0, visiblePos * CONTACT_ITEM_HEIGHT, clientRect.right, (visiblePos + 1) * CONTACT_ITEM_HEIGHT};
+
+ // Draw the contact that should be visible at this position
+ DrawContactItem(hdc, itemRect, contacts[actualIndex], actualIndex == selectedIndex);
+ }
+
+ EndPaint(hWnd, &ps);
+ return 0;
+ }
+ break;
+ }
+
+ return CallWindowProc(originalListBoxProc, hWnd, msg, wParam, lParam);
+}
\ No newline at end of file
diff --git a/Samples/SampleChatAppWithShare/SampleChatAppWithShare/WindowProcs.h b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/WindowProcs.h
new file mode 100644
index 0000000..97c8623
--- /dev/null
+++ b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/WindowProcs.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include
+
+// Window procedures
+LRESULT CALLBACK ModernButtonProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+LRESULT CALLBACK ModernListBoxProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+// Original window procedures storage
+extern WNDPROC originalButtonProc;
+extern WNDPROC originalListBoxProc;
+
+// Setup functions
+void SetupCustomWindowProcs();
\ No newline at end of file
diff --git a/Samples/SampleChatAppWithShare/SampleChatAppWithShare/framework.h b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/framework.h
new file mode 100644
index 0000000..414c103
--- /dev/null
+++ b/Samples/SampleChatAppWithShare/SampleChatAppWithShare/framework.h
@@ -0,0 +1,29 @@
+// header.h : include file for standard system include files,
+// or project specific include files
+//
+
+#pragma once
+
+#include "targetver.h"
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+
+// Windows Header Files
+#include
+
+// WinRT Headers for Share Target functionality
+#include
+#include
+#include
+#include
+#include
+#include
+#include