Граф коммитов

3 Коммитов

Автор SHA1 Сообщение Дата
Howard Kapustein bdafab1cf0
Add initial Protobuf support (#3448)
**Add support for Google's [Protocol Buffers](https://protobuf.dev/) (aka protobuf)**

Using protobuf requires 3 components:

1. protoc.exe -- 'Compiles' *.proto files generating *.pb.cc and *.pb.h code
2. headers -- Needed to compile generated *.pb.cc
3. libs -- Needed to link compiled bits from 2

Google provides a nuget containing a compiled protoc.exe but doesn't make headers or libs available via nuget. TL;DR we create a nuget for our use (Microsoft.WindowsAppSDK.Protobuf.3.21.12.nupkg). Details of what, why and how are in `tools\nuget\protobuf\README.md`.

TL;DR Developers working in WinAppSDK only need to know there's a nuget providing protobuf support. The messy details how to create that are only relevant to the developer creating the nuget (moi) or future devs if/when a new version is needed.

**Added `KozaniProtocol`** containing Kozani's protobuf messages and related definitions. The purpose of KozaniManageProtocol project is to contain all of Kozani's protobuf definitions and compile them to produce the generated code for use by other projects.

**Updated `KozaniManager`** to consume the protobuf code from KozaniProtocol and added wrappers showing how to use it.

**Updated `KozaniRemoteManager`** to reference to consume the protobuf code from KozaniProtocol.

General structure of our protobuf usage:

1. **Define a message in KozaniProtocol**. 
 * Split up by functional roles across *.proto files e.g. Kozani.Activation.proto for activation, Kozani.Process.proto for process management (e.g. if TaskManager kills local KozaniHostRuntime.exe we need to send message to server to terminate the associated back end process), etc.
  * Any sort of 'synchronous communication' would involve a pair of request+response messages. KozaniManager sends 'request' to server and KozaniRemoteManager sends a related 'response'.
  * The 'cookie' field is an example of a correlating id to match a request with a response. A 'conversionid', 'channelid', etc are other examples how to xref 2+ messages together into a larger context.
2. **Define a namespace with functions that internally use protobuf messages**
  * Keep all protobuf usage internal to code using them. Protobuf is an implementation detail. Provide appropriate strongly typed functions for callers to drive activity which internally happen to use the protobuf generated code.
  * If you need context spanning multiple messages you can create a class with methods which internally use protobuf messages, plus additional attributes for any additional data needed for the context.
3. Serialize messages to `std::string`
  * Protobuf can serialize messages to `std::string` or `std::ostream`. NOTE: The serialized data's just bytes, `string` is just a convenient container to pass the data around.
  * `std::string` is recommend when serializing a message to bytes.
  * `std::string` or `std::istream` is recommended when deserializing a message from bytes. Large messages may be more efficient via `std::istream`; either works well enough for small messages so use whichever is more convenient.
4. Always encode strings as UTF8 before serialization.
  * Protobuf expresses message `string` fields as `std::string`. It does not do wide<->narrow conversions for you (unlike, say, SQLite) - that's the developer's responsibility. If you have a wide string (`std::wstring`, `PCWSTR`, `HSTRING`, etc) convert it to a UTF-8 string before assigning it to a protobuf field. Use functions in `\dev\common\Microsoft.Utf8.h` to convert wide->utf8 e.g.

```c++
PCWSTR appUserModelId{ L"LolzCatzVidz" };
const std::string appUserModelIdUtf8{ ::Microsoft::Utf8::ToUtf8(appUserModelId) };
```

  * When deserializing wide strings from protobuf serialized bytes don't forget to convert the UTF-8 bytes to a wide string. Use functions in `\dev\common\Microsoft.Utf8.h` to do this e.g.

```
Some::Protobuf::Message::Kitteh kitteh;
kitteh.ParseFromString(stream_containing_serialized_bytes);
const std::wstring name{ kitten.get_name() };
```

5. Avoid making classes inherit from protobuf's generated classes.
  * Protobuf docs counsel against against inheriting and extending the generated classes. Treat protobuf's generated classes as structs of data you can access but not extend (use composition esp private composition, not inheritance).

6. We use protobuf as a static library.
  * Protobuf can provide support code via libprotobuf.dll but recommends against it as that must have a compatible version as the generated code. To minimize complications we use protobuf as a static lib. This may be revisited in the future.


Everything compiles and links. `dev\Kozani\KozaniManager\main.cpp` has an example serializing a protobuf message to bytes (as a `std::string`). Changing and extending that for all the rest of our functionality and likewise parsing bytes to protobuf messages in KozaniRemoteManager (or vice versa) is left as an exercise for the reader :-)
2023-02-17 15:38:25 -08:00
Scott Jones 34cf5fb8d2
removed OS CRT/STL leftovers and added CX considerations to Hybrid CRT doc (#1440)
* removed OS CRT/STL leftovers and added CX considerations to Hybrid CRT doc

* PR feedback
2021-10-04 13:22:21 -07:00
Howard Kapustein af506d64e4
Commonize Hybrid CRT support (#1026)
* Move Hybrid CRT support out of individual project files up to the project level as a whole

* Remove unnecesasry Store-app-ness that fails the Hybrid CRT support

* Stop enabling DebugLibraries to avoid bringing in debug VC CRT DLL dependencies (violating the Hybrid CRT rules)

* Add DesktopCompatible to MrtCoreManagedTest for future reference - it doesn't hurt, but it doesn't help (at least, not this issue). Also added Win32Proj keyword to M.AM.Resources project. We now have 1 root issue

* Removed MrtCoreManagedTest from the build due to a fundamental incompatibility (ut's a Universal Windows project referencing Microsoft.ApplicationModel.Resources (the WinRT dll) which isn't, and VS doesn't like crossing streams. Even worse, VS and msbuild produce different results!).

* Revert "Removed MrtCoreManagedTest from the build due to a fundamental incompatibility (ut's a Universal Windows project referencing Microsoft.ApplicationModel.Resources (the WinRT dll) which isn't, and VS doesn't like crossing streams. Even worse, VS and msbuild produce different results!)."

This reverts commit 6f4b23dd10.

* Doing things to workaround MrtCoreManagedTest is a Univesal Windows project. Epic Failure. Because it's a Universal Windows project MSTest is creating $(OutDir)AppX subdir and copying files ***it knows about*** to the subdir. This brutal hack fails because File.Exists() for files in the parent directory fails, and that's because the last var pc = ... tries to access the AppX directory's parent ***and fails because Access Denied***. Previously doing the copy in the .csproj fails because the AppX directory doesn't necesarily exist before the test runs, and MD $(OutDir)AppX before copying files is pointless because MSTest is deleting all the files (if any) in the AppX directory when the test starts. So dead end upon dead end. Only way is to find a way to bench the Universal Windows .props logic to understand the files it doesn't want to allow through the ...Transitive... copy rules. Or just rewrite the project as a non-Universal Windows project. Or rewrite the test using TAEF instead of MSTest. Or... drink heavily. Hunting up Scott tomorrow hoping he has an idea

* Hah! Thank you ScottJ! ReferenceCopyLocalPaths does the right thing, copying the needed DLLs into $(OutDir) *and* $(OutDir)AppX and the tests now find the dll and pass

* Remove debugging hackery
2021-08-17 13:17:35 -07:00