mirror of
https://github.com/ZuneDev/ZuneShell.dll.git
synced 2026-07-27 13:11:51 -07:00
Clean slate for Claude
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
# ZuneDBApi — Research Log
|
||||
|
||||
This file is **append-only**. Do not edit or remove previous entries.
|
||||
|
||||
---
|
||||
|
||||
## 2026-07-12 — MicrosoftZuneInterop decompilation
|
||||
|
||||
### Q1: Real GUID for `IQueryPropertyBag`
|
||||
|
||||
**File:** `ZuneDBApi/MicrosoftZuneInterop/IQueryPropertyBag.cs`
|
||||
|
||||
The `[GeneratedComInterface]` attribute requires a GUID. The native binary does not expose this GUID through managed metadata (ILSpy returns no result when searching for `IQueryPropertyBag` as a type). A placeholder GUID `3D8A1F2B-6C4E-4A5D-9B7F-2E0C1A8D3F4E` is currently used.
|
||||
|
||||
The real GUID (if one exists) would need to be recovered from the native binary using Ghidra — look for a `__declspec(uuid(...))` annotation on the `IQueryPropertyBag` class, or a `DEFINE_GUID`/`IID_IQueryPropertyBag` symbol. It is also possible the interface has no GUID and QI is never used by the native callers (the user noted it is not CoCreateInstance-registered), in which case the placeholder is acceptable long-term.
|
||||
|
||||
**Assumption made in code:** placeholder GUID used. Logged per unknowns procedure.
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
## 2026-07-12 — Q1 follow-up: GUID search in managed metadata
|
||||
|
||||
**Task:** Research whether the real GUID for `IQueryPropertyBag` is encoded anywhere accessible to ILSpy (checked `<Module>` and root-namespace types).
|
||||
|
||||
**Findings:**
|
||||
|
||||
1. The global-namespace struct `IQueryPropertyBag` (separate from `MicrosoftZuneInterop.IQueryPropertyBag`) has no `[Guid]` attribute — only `[NativeCppClass]`, `[DebugInfoInPDB]`, `[MiscellaneousBits(65)]`.
|
||||
2. `<Module>` could not be decompiled by ILSpy (tool error); its fields are not inspectable through the managed surface.
|
||||
3. Full decompilation of `MicrosoftZuneInterop.QueryPropertyBag` shows no IID reference anywhere in managed code. `GetIQueryPropertyBag()` simply returns the raw `m_pPropertyBag` pointer with no `QueryInterface` call.
|
||||
4. The destructor (`!QueryPropertyBag`) calls offset 16 on the vtable, confirming IUnknown layout (slot 2 = Release). This does not reveal the IID.
|
||||
|
||||
**Conclusion:** The GUID is not present in managed metadata. If one exists, it lives only in native code (`__declspec(uuid(...))` or `DEFINE_GUID`). Ghidra remains the only path to recovery. Placeholder GUID in `IQueryPropertyBag.cs` stands.
|
||||
|
||||
---
|
||||
|
||||
### Q2: Unknown vtable slots in `IQueryPropertyBag`
|
||||
|
||||
**File:** `ZuneDBApi/MicrosoftZuneInterop/IQueryPropertyBag.cs`
|
||||
|
||||
The vtable offsets observed in `QueryPropertyBag`'s decompiled code (ILSpy) are:
|
||||
- Slot 5 (offset 40): `SetString(prop, wchar_t*) -> HRESULT`
|
||||
- Slot 7 (offset 56): `SetInt(prop, int) -> HRESULT`
|
||||
- Slot 13 (offset 104): `IsSet(prop, int*) -> HRESULT`
|
||||
|
||||
Slots 3, 4, 6, and 8–12 are not observed being called in any managed code that ILSpy can see. Their signatures (return type, parameters) are unknown.
|
||||
|
||||
Placeholder `void _ReservedN()` methods are declared in the interface to preserve vtable ordering. These must not be called. If any of these slots are not HRESULT-returning void methods, the placeholders will be wrong and must be corrected before the CCW/RCW is used by native code.
|
||||
|
||||
**Needs:** Ghidra analysis of the native `IQueryPropertyBag` vtable definition.
|
||||
|
||||
---
|
||||
|
||||
### Q3: `kPropIdMap` — 37-entry property name table
|
||||
|
||||
**File:** `ZuneDBApi/MicrosoftZuneInterop/QueryPropertyBag.cs`, `MapNameToProp`
|
||||
|
||||
`QueryPropertyBag.MapNameToProp` walks a static array `MicrosoftZuneInterop.?A0x52c37a46.kPropIdMap` of 37 `PropIdMapEntry` structs (each 16 bytes: `wchar_t* name` at [0..7], `EQueryPropertyBagProp id` at [8..11], 4 bytes padding at [12..15]). The property name strings and their corresponding `EQueryPropertyBagProp` values are embedded in native data and are not visible through ILSpy.
|
||||
|
||||
Without this table, `MapNameToProp` (and by extension `SetValue` and `IsSet`) cannot be implemented.
|
||||
|
||||
**Needs:** Ghidra analysis of `kPropIdMap` in the native segment of `ZuneDBApi.dll`.
|
||||
|
||||
---
|
||||
|
||||
### Q4: `EQueryPropertyBagProp` enum values
|
||||
|
||||
**File:** `ZuneDBApi/GlobalEnums.cs` (where it will be added)
|
||||
|
||||
`EQueryPropertyBagProp` appears in the assembly listing and in the signatures of `IQueryPropertyBag` methods, but lives in the global (unnamed) namespace like other C++/CLI-compiled native enums. ILSpy queries for it with a namespace prefix fail. It has not yet been queried or added to `GlobalEnums.cs`.
|
||||
|
||||
The 37 entries in `kPropIdMap` (Q3 above) presumably map to values of this enum, so resolving Q3 and Q4 together would be efficient.
|
||||
|
||||
**Needs:** ILSpy query for `EQueryPropertyBagProp` (no namespace prefix), then Ghidra cross-reference against `kPropIdMap`.
|
||||
|
||||
---
|
||||
|
||||
### Q5: `ZuneLibraryExports.CreatePropertyBag` — P/Invoke signature
|
||||
|
||||
**File:** `ZuneDBApi/MicrosoftZuneInterop/QueryPropertyBag.cs`, constructor
|
||||
|
||||
The original constructor calls `global::<Module>.ZuneLibraryExports.CreatePropertyBag(&pPropertyBag)`. In a managed reimplementation this would be a P/Invoke into the native export. The DLL name, exact export symbol, and calling convention are unknown.
|
||||
|
||||
**Assumption made in code:** constructor body is empty with a `// TODO` comment.
|
||||
|
||||
---
|
||||
|
||||
### Q6: Calling convention for `IQueryPropertyBag` vtable methods
|
||||
|
||||
**File:** `ZuneDBApi/MicrosoftZuneInterop/QueryPropertyBag.cs` (previous `IntPtr`-based draft)
|
||||
|
||||
The ILSpy decompilation shows `delegate* unmanaged[Cdecl, Cdecl]` for the vtable dispatch (the double `Cdecl` appears to be an ILSpy artifact of C++/CLI compilation). Standard COM uses `__stdcall` on x86 and the platform ABI on x64 (where Cdecl and Stdcall converge). The current implementation uses `[GeneratedComInterface]` which handles this, but if raw vtable dispatch is ever needed (e.g. for the unknown slots), the calling convention should be verified against the native binary.
|
||||
+177
-40
@@ -1,20 +1,33 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with
|
||||
code in this repository, specifically ZuneDBApi.
|
||||
|
||||
## What this project is
|
||||
|
||||
`ZuneDBApi` is one project inside the larger `ZuneShell.dll` solution (root: `..`), which is a clean-room
|
||||
reimplementation of the original Microsoft Zune desktop software. The dependency chain is:
|
||||
`ZuneDBApi` is one project inside the larger `ZuneShell.dll` solution
|
||||
(root: `..`), which is a reimplementation of the original Microsoft Zune
|
||||
desktop software. The dependency chain is:
|
||||
|
||||
```
|
||||
ZuneDBApi (this project) → ZuneImpl → ZuneShell → ZuneHost / ZuneHost.Wpf (entry points)
|
||||
ZuneDBApi (this project) → ZuneImpl → ZuneShell.dll → ZuneHost / ZuneHost.Wpf (entry points)
|
||||
```
|
||||
|
||||
ZuneDBApi is the lowest layer: it re-creates the public API surface of the original closed-source
|
||||
`Microsoft.Zune.*` / `MicrosoftZuneInterop` / `MicrosoftZuneLibrary` assemblies that shipped with the real
|
||||
Zune software, so the rest of the stack (`ZuneImpl`, `ZuneShell`) can compile and run against a familiar API
|
||||
without bundling Microsoft's original binaries or decompiled source.
|
||||
Note that Iris UI files (both `.uix` and `.uib`) can load arbitrary assemblies.
|
||||
This meaans that `ZuneShell.dll` has a direct dependency on `ZuneDBApi`, even
|
||||
though according to the C# project system, `ZuneDBApi` is only a transitive
|
||||
dependency.
|
||||
|
||||
ZuneDBApi is the lowest layer with managed code: it re-creates the public API
|
||||
surface of the original closed-source `Microsoft.Zune.*` /
|
||||
`MicrosoftZuneInterop` / `MicrosoftZuneLibrary` assemblies that shipped with
|
||||
the real Zune software, so the rest of the stack (`ZuneImpl`, `ZuneShell`) can
|
||||
compile and run against a familiar API without bundling Microsoft's original
|
||||
binaries. It also unlocks modifications and potentially even cross-platform
|
||||
support. When writing new code, make as few assumptions about the platform
|
||||
as possible. If platform-specific code is unavoidable without hacks or relying
|
||||
on fragile behavior, wrap the code with the appropirate `#if PLATFORM` directive
|
||||
and write a `// TODO` comment to implement the other platforms.
|
||||
|
||||
Namespace-to-folder mapping is strict and should be preserved when adding files:
|
||||
- `Microsoft.Zune.Configuration` → `Microsoft.Zune/Configuration/`
|
||||
@@ -25,28 +38,146 @@ Namespace-to-folder mapping is strict and should be preserved when adding files:
|
||||
- `MicrosoftZuneLibrary` → `MicrosoftZuneLibrary/`
|
||||
- `ZuneUI` (HRESULT, attributes) → `ZuneUI/`
|
||||
|
||||
## Critical constraint: no decompiled code
|
||||
## Project goals
|
||||
|
||||
A prior commit (`d0fd93a`, "Added raw ZuneDBApi decomp") added a raw decompilation of the original Microsoft
|
||||
assembly and was immediately reverted (`749a29a`) — verbatim decompiled Microsoft code must not be checked in.
|
||||
Instead, classes here are **clean-room stubs**: same public type/method/property signatures as the original
|
||||
(so dependent code compiles and links correctly), but with placeholder or minimal real bodies, not copied
|
||||
Microsoft implementation logic. The `mcp__ilspy__*` tools (already allowlisted in `.claude/settings.local.json`)
|
||||
are for inspecting the *shape* of the original assembly (type/member lists, signatures) to match the API
|
||||
surface — not for pulling decompiled method bodies into source files.
|
||||
The goal of this project is to revive Zune and make it interoperable with
|
||||
modern tools and platforms. This requires reverse engineering the original
|
||||
software and reimplementing it in a way that is maintainable and makes as few
|
||||
assumptions about the target platform as possible.
|
||||
|
||||
Two stub styles coexist in this codebase, both legitimate:
|
||||
- **Pure no-op stub** — method sets `out` params to defaults and returns `HRESULT._S_OK` (e.g.
|
||||
`Microsoft.Zune/Service/AccountManagement.cs`).
|
||||
- **Real working logic** — e.g. `Microsoft.Zune/Configuration/*Configuration.cs` classes are genuinely
|
||||
backed by `RegistryHive`/`CConfigurationManagedBase` with real default values, and `ZuneUI/HRESULT.cs` is a
|
||||
fully real HRESULT struct with the actual Zune error codes.
|
||||
## Project stages
|
||||
|
||||
When a stub needs to represent an unmanaged COM pointer the original held (e.g. `IPlaylist*`, `IQueryPropertyBag*`),
|
||||
do **not** invent raw C-style pointer types or C++-style destructor syntax (`~Foo()` as an ordinary method, or
|
||||
`!Foo()`) — neither compiles in C#. Use `IntPtr`/`SafeHandle`-style fields and a normal `IDisposable` pattern
|
||||
(`protected virtual void Dispose(bool disposing)` + `~Foo()` as an actual finalizer) instead, matching the
|
||||
pattern already used in `Microsoft.Zune/Configuration/CConfigurationManagedBase.cs`.
|
||||
This revival effort is realized in distinct phases:
|
||||
|
||||
1. **Decompilation:** investigating the original code, understanding how it works
|
||||
and fits into the rest of the stack. High-quality decompilations, such as those
|
||||
produced for pure C# code, may be used as a starting point for future stages.
|
||||
2. **Implementation:** reimplementing the original API surface with code that
|
||||
is maintainable but has the same features. It is imperative that the new
|
||||
implementation is entirely backwards-compatible and can function as a drop-in
|
||||
replacement for the original libraries. The project at this stage is more
|
||||
manageable but naturally has the similar requirements and limitations to the
|
||||
original.
|
||||
3. **Enhancement:** adding new features such as additional platform support
|
||||
or OS intergration. This may require extending existing abstractions or
|
||||
creating new ones for the sake of modularity.
|
||||
|
||||
**Strict adherence to these phases is required**. To ensure stability and
|
||||
quality, each stage is highly dependent on the one before. When decompiling
|
||||
an assembly or type, do not attempt to use new abstractions. Simply write
|
||||
equivalent code, such that the new implementation is a drop-in replacement
|
||||
for the original. Similarly, the enhancement stage must not introduce any new
|
||||
platform-specific code without being gated behind proper conditionals and
|
||||
accessed via suitable abstractions.
|
||||
|
||||
ZuneShell.dll and the Microsoft.Iris libraries are mostly in stage 2, going on
|
||||
stage 3, but ZuneDBApi is currently in stage 1. You first need to decompile
|
||||
the assembly, then implement it using the rules outlined in the rest of this
|
||||
document.
|
||||
|
||||
## Dealing with unknowns and uncertainty
|
||||
|
||||
**Do not make assumptions**. If you have a question about something,
|
||||
follow this procedure:
|
||||
|
||||
1. **Log your question.** Use `LOG.md` in the repo root to log any questions
|
||||
or confusions. This document will be reviewed by the human: provide any
|
||||
useful context for your query. Do not log guesses or hunches; only observations
|
||||
and unknowns. Most importantly, **do not edit previous questions**; the log
|
||||
file is *append-only*.
|
||||
2. **Ask the human.** They've been working on Zune longer than you have. They may
|
||||
have an immediate answer for you, or at least can narrow down your search.
|
||||
3. **Search the Wiki.** Some information has already been documented in the
|
||||
ZuneDev Wiki located in the following repo on GitHub:
|
||||
http://github.com/ZuneDev/Wiki
|
||||
4. **Move on.** If you still haven't gotten a concrete, verifiable answer,
|
||||
you may make whatever assumption is both likely and has the fewest predicates,
|
||||
**if and only if you document this assumption in the code**, using `// TODO`
|
||||
comments. You are also required to log this assumption and its corresponding
|
||||
rationale in `LOG.md`.
|
||||
|
||||
### STAGE 1: Decompilation
|
||||
|
||||
Reliance on the original libraries is a no-go, as these binaries are only
|
||||
available for x86 and x86_64 Windows. Certain components of the Zune software
|
||||
have already been reimplemented (see stage 2 of *Project Goals*), including
|
||||
`ZuneShell.dll` and `Microsoft.Iris`, but all of the original native
|
||||
libraries are stuck at the start of stage 1.
|
||||
|
||||
#### Managed assemblies
|
||||
|
||||
Pure managed assemblies, such as those written in C#, can be inspected using
|
||||
ILSpy or the `mcp__ilspy__*` tools. Reverse engineering these assemblies is
|
||||
typically quite easy, as the decompilation is very accurate. Such
|
||||
decompilations are suitable starting points for stages 2 and 3.
|
||||
|
||||
#### Native assemblies
|
||||
|
||||
Native or unmanaged assemblies, such as those written in C or C++, can be
|
||||
inspected using Ghidra. Decompilations from these assemblies should not be used
|
||||
verbatim, as their outputs are usually low-quality and are not readable.
|
||||
|
||||
#### Mixed-mode assemblies
|
||||
|
||||
Mixed-mode assemblies, such as those written in C++/CLI, contain both managed
|
||||
and unmanaged code. ILSpy and its corresponding MCP tools may be used to
|
||||
inspect the public surface of these assemblies, but implementation details
|
||||
are likely to be missing. A combination of Ghidra and ILSpy may be required
|
||||
to fully reverse engineer such assemblies. Decompilations of mixed-mode
|
||||
aseemblies should only be used as-is if the specific code does not touch any
|
||||
native or unmanaged code, either internally or externally.
|
||||
|
||||
### STAGE 2: Implementation
|
||||
|
||||
All initial implementations must be backwards-compatible with the original
|
||||
API surfaces. This means reimplemented modules must have the same public
|
||||
type/method/property signatures as the original (so dependent code compiles
|
||||
and links correctly). The actual body of these surfaces can follow one of the
|
||||
following conventions:
|
||||
|
||||
- **Pure no-op stub** — method sets `out` params to defaults and returns a
|
||||
success result, typically `HRESULT._S_OK`.
|
||||
- **Real working logic** — logic is implemented and matches the original
|
||||
behavior.
|
||||
|
||||
Whenever possible, the latter is preferred over the former: stubs require
|
||||
more work in the future by a human, which can make the revival effort take
|
||||
longer to become useful. Real, working business logic makes future work much
|
||||
easier because the code is much more self-documenting, requiring less
|
||||
consultation with outputs from previous stages.
|
||||
|
||||
#### COM objects
|
||||
|
||||
When a reimplementation needs to represent an unmanaged COM pointer the
|
||||
original held (e.g. `IPlaylist*`, `IQueryPropertyBag*`), do **not** invent
|
||||
raw C-style pointer types or C++-style destructor syntax (`~Foo()` as an
|
||||
ordinary method, or `!Foo()`) — neither compiles in C#.
|
||||
|
||||
When a class holds a COM pointer, follow these steps in order:
|
||||
|
||||
1. Rewrite the decompiled code using `IntPtr` or `SafeHandle` with proper
|
||||
`IDisposable` and finalizer logic.
|
||||
2. Reconstruct the methods on the corresponding COM interface in such a way
|
||||
that it is compatible with `Marshal.GetObjectForIUnknown`, ideally using
|
||||
source-generated COM. Note that for some Zune-specific interfaces, you may not
|
||||
need to locate a GUID or support `CoCreateInstance`, as some objects are
|
||||
instantiated in the native libraries. Follow the rules in *Dealing with
|
||||
unknowns and uncertainty*.
|
||||
3. Update the initial reimplementation to use the new modern COM structure.
|
||||
Ensure you do not affect the public surface of the class; external code may
|
||||
depend on the exact shape of the original API.
|
||||
|
||||
These steps are the only acceptable "enhancement" for stages 1 and 2.
|
||||
|
||||
### STAGE 3: Enhancement
|
||||
|
||||
Once parity has been restored with the original software, enhancements can be
|
||||
made to the codebase. This may involve creating new abstractions for platform-
|
||||
specific features, or implementing existing interfaces to extend support.
|
||||
|
||||
New features may be added, such as extended support for newer codecs, syncing
|
||||
with other MTP devices like modern smartphones, or integrating new Social
|
||||
features from ActivityPub and ListenBrainz scrobbling.
|
||||
|
||||
## Build
|
||||
|
||||
@@ -54,23 +185,29 @@ pattern already used in `Microsoft.Zune/Configuration/CConfigurationManagedBase.
|
||||
# From repo root or this directory — build just this project:
|
||||
dotnet build ZuneDBApi/ZuneDBApi.csproj
|
||||
|
||||
# Build the whole solution (Windows-only platforms exist in ZuneShell.sln; on Linux only net8.0 TFMs build):
|
||||
# Build the whole solution (Windows-only platforms exist in ZuneShell.sln;
|
||||
# on Linux only net8.0 TFMs build):
|
||||
dotnet build ZuneShell.sln
|
||||
```
|
||||
|
||||
`Directory.Build.props` (repo root) sets `TargetFrameworks` to `net8.0` everywhere, adding `net472` and
|
||||
`net8.0-windows` automatically when building on Windows. There is no test project for ZuneDBApi or the
|
||||
solution as a whole.
|
||||
No test projects are currently available, neither for the entire project or
|
||||
just ZuneDBApi.
|
||||
|
||||
Note: building currently fails on files containing invalid C++-style syntax (see constraint above) —
|
||||
running a build will surface any remaining instances; treat new ones the same way (fix to valid C#, do not
|
||||
silently work around them).
|
||||
Note that building will fail on files containing invalid C++-style syntax
|
||||
(see *COM objects*) — running a build will surface any remaining instances;
|
||||
treat new ones the same way (fix to valid C#, do not silently work
|
||||
around them).
|
||||
|
||||
## Working in this project
|
||||
|
||||
- `Nullable` and `ImplicitUsings` are enabled; `AllowUnsafeBlocks` is true (file-scoped namespaces are fine).
|
||||
- This project only references `UIX.csproj` (from the `MicrosoftIris`/`ZuneUIXTools` submodule) — keep it free
|
||||
of dependencies on `ZuneImpl`/`ZuneShell` to avoid circular references, since those layers depend on it.
|
||||
- `Microsoft.Win32.RegistryHive`/`Registry*` APIs used by the `Configuration` classes are Windows-only; this
|
||||
is expected since the original Zune client was Windows-only, but keep cross-platform buildability in mind
|
||||
for the `net8.0` (non-`-windows`) TFM — avoid adding new Windows-only APIs outside what's already used.
|
||||
- `Nullable` and `ImplicitUsings` are enabled; `AllowUnsafeBlocks` is true
|
||||
(file-scoped namespaces are fine).
|
||||
- This project only references `UIX.csproj` (from the
|
||||
`MicrosoftIris`/`ZuneUIXTools` submodule) — keep it free of dependencies on
|
||||
`ZuneImpl`/`ZuneShell` to avoid circular references, since those layers depend
|
||||
on it.
|
||||
- `Microsoft.Win32.RegistryHive`/`Registry*` APIs used by the `Configuration`
|
||||
classes are Windows-only; this is expected since the original Zune client was
|
||||
Windows-only, but keep cross-platform buildability in mind for the `net8.0`
|
||||
(non-`-windows`) TFM. When working on stage 3, avoid adding new Windows-only
|
||||
APIs outside what's already used.
|
||||
|
||||
@@ -17,11 +17,7 @@ namespace Microsoft.Zune.Configuration
|
||||
|
||||
public string ConfigurationPath => m_basePath != null ? m_basePath + "\\" + m_instance : m_instance;
|
||||
|
||||
public event ConfigurationChangeEventHandler OnConfigurationChanged
|
||||
{
|
||||
add { lock (m_lock) { OnConfigurationChanged += value; } }
|
||||
remove { lock (m_lock) { OnConfigurationChanged -= value; } }
|
||||
}
|
||||
public event ConfigurationChangeEventHandler OnConfigurationChanged;
|
||||
|
||||
public CConfigurationManagedBase(RegistryHive hive, string basePath, string instance)
|
||||
{
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.VisualC;
|
||||
|
||||
namespace Microsoft.Zune.Configuration
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Size = 24)]
|
||||
[MiscellaneousBits(64)]
|
||||
[NativeCppClass]
|
||||
[DebugInfoInPDB]
|
||||
internal struct DeregisterCallback
|
||||
{
|
||||
private long _alignment;
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.VisualC;
|
||||
|
||||
namespace Microsoft.Zune.Configuration
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Size = 24)]
|
||||
[MiscellaneousBits(64)]
|
||||
[NativeCppClass]
|
||||
[DebugInfoInPDB]
|
||||
internal struct NotificationMarshaller
|
||||
{
|
||||
private long _alignment;
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.VisualC;
|
||||
|
||||
namespace Microsoft.Zune.Configuration
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Size = 24)]
|
||||
[MiscellaneousBits(64)]
|
||||
[DebugInfoInPDB]
|
||||
[NativeCppClass]
|
||||
internal struct RefreshCallback
|
||||
{
|
||||
|
||||
@@ -5,11 +5,7 @@ namespace Microsoft.Zune.Configuration
|
||||
{
|
||||
internal class TunerInfoHandler : ITunerInfoHandler, IDisposable
|
||||
{
|
||||
public event EventHandler OnChanged
|
||||
{
|
||||
add { OnChanged += value; }
|
||||
remove { OnChanged -= value; }
|
||||
}
|
||||
public event EventHandler? OnChanged;
|
||||
|
||||
private IList<TunerInfo> m_PCsList = new List<TunerInfo>();
|
||||
private IList<TunerInfo> m_devicesList = new List<TunerInfo>();
|
||||
@@ -18,8 +14,6 @@ namespace Microsoft.Zune.Configuration
|
||||
private DateTime m_nextSubscriptionDeviceDeregistrationDate;
|
||||
private DateTime m_nextAppStoreDeviceDeregistrationDate;
|
||||
|
||||
public TunerInfoHandler() { }
|
||||
~TunerInfoHandler() { }
|
||||
public virtual bool CanQueryTunerList() { throw new NotImplementedException(); }
|
||||
public virtual IList<TunerInfo> GetPCsList() { return m_PCsList; }
|
||||
public virtual IList<TunerInfo> GetDevicesList() { return m_devicesList; }
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.Marshalling;
|
||||
|
||||
namespace MicrosoftZuneInterop;
|
||||
|
||||
// IUnknown slots [0]–[2] are implicit. User-declared methods begin at slot [3].
|
||||
// TODO: replace placeholder GUID with the real one recovered from the native binary.
|
||||
[GeneratedComInterface]
|
||||
[Guid("3D8A1F2B-6C4E-4A5D-9B7F-2E0C1A8D3F4E")]
|
||||
partial interface IQueryPropertyBag
|
||||
{
|
||||
// [3]–[4]: unknown native slots; declared only to preserve vtable ordering.
|
||||
void _Reserved3();
|
||||
void _Reserved4();
|
||||
|
||||
// [5]: SetString(prop, wchar_t*) -> HRESULT
|
||||
[PreserveSig]
|
||||
int SetString(EQueryPropertyBagProp prop, [MarshalAs(UnmanagedType.LPWStr)] string value);
|
||||
|
||||
// [6]: unknown
|
||||
void _Reserved6();
|
||||
|
||||
// [7]: SetInt(prop, int) -> HRESULT [bool uses 1/0]
|
||||
[PreserveSig]
|
||||
int SetInt(EQueryPropertyBagProp prop, int value);
|
||||
|
||||
// [8]–[12]: unknown
|
||||
void _Reserved8();
|
||||
void _Reserved9();
|
||||
void _Reserved10();
|
||||
void _Reserved11();
|
||||
void _Reserved12();
|
||||
|
||||
// [13]: IsSet(prop, int* out) -> HRESULT
|
||||
[PreserveSig]
|
||||
int IsSet(EQueryPropertyBagProp prop, out int result);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace MicrosoftZuneInterop;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Size = 16)]
|
||||
internal struct PropIdMapEntry
|
||||
{
|
||||
private long _alignment;
|
||||
}
|
||||
@@ -1,40 +1,99 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.Marshalling;
|
||||
|
||||
namespace MicrosoftZuneInterop;
|
||||
|
||||
// Native COM interface IMultiSortAttributes — vtable layout (x64, IUnknown = slots 0–2):
|
||||
// [3] GetSortOrders() -> EQuerySortType* (parallel array of sort directions)
|
||||
// [4] GetSortAttributes() -> int* (parallel array of SchemaMap indices)
|
||||
//
|
||||
// Native struct IDList (16 bytes):
|
||||
// int Count
|
||||
// (4 bytes padding)
|
||||
// int* Ids (heap-allocated array of Count media IDs; freed by the native caller)
|
||||
|
||||
public class QueryPropertyBag : IDisposable
|
||||
{
|
||||
private readonly object m_pBag; // Stub for IQueryPropertyBag*
|
||||
private bool _disposed;
|
||||
private IQueryPropertyBag? _bag;
|
||||
|
||||
public IQueryPropertyBag* GetIQueryPropertyBag()
|
||||
public QueryPropertyBag()
|
||||
{
|
||||
return (IQueryPropertyBag*)m_pBag;
|
||||
// TODO: P/Invoke ZuneLibraryExports.CreatePropertyBag to get an IQueryPropertyBag* pointer,
|
||||
// then wrap it:
|
||||
// IntPtr ptr = ...; // from CreatePropertyBag
|
||||
// _bag = (IQueryPropertyBag)StrategyBasedComWrappers.Instance
|
||||
// .GetOrCreateObjectForComInstance(ptr, CreateObjectFlags.None);
|
||||
}
|
||||
|
||||
internal QueryPropertyBag()
|
||||
public void SetValue(string propertyName, object? value)
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual void Dispose([MarshalAs(UnmanagedType.U1)] bool P_0)
|
||||
{
|
||||
if (P_0)
|
||||
{
|
||||
_disposed = true;
|
||||
EQueryPropertyBagProp prop = MapNameToProp(propertyName);
|
||||
if (prop == (EQueryPropertyBagProp)(-1) || value is null)
|
||||
return;
|
||||
}
|
||||
try
|
||||
|
||||
int hr = value switch
|
||||
{
|
||||
_disposed = true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
base.Finalize();
|
||||
}
|
||||
int i => _bag!.SetInt(prop, i),
|
||||
bool b => _bag!.SetInt(prop, b ? 1 : 0),
|
||||
string s => _bag!.SetString(prop, s),
|
||||
_ => throw new ApplicationException($"Unsupported property value type: {value.GetType()}")
|
||||
};
|
||||
|
||||
if (hr < 0)
|
||||
throw new ApplicationException($"SetValue failed: HRESULT 0x{hr:X8}");
|
||||
}
|
||||
|
||||
public virtual sealed void Dispose()
|
||||
public bool IsSet(string propertyName)
|
||||
{
|
||||
EQueryPropertyBagProp prop = MapNameToProp(propertyName);
|
||||
if (prop == (EQueryPropertyBagProp)(-1))
|
||||
return false;
|
||||
|
||||
_bag!.IsSet(prop, out int result);
|
||||
return result == 1;
|
||||
}
|
||||
|
||||
public EQueryPropertyBagProp MapNameToProp(string propertyName)
|
||||
{
|
||||
// TODO: recover the 37-entry kPropIdMap table from the native binary
|
||||
// (case-insensitive wchar_t* → EQueryPropertyBagProp, stored as PropIdMapEntry[37]
|
||||
// at MicrosoftZuneInterop.?A0x52c37a46.kPropIdMap; each entry is 16 bytes:
|
||||
// [0..7] wchar_t* name, [8..11] EQueryPropertyBagProp id, [12..15] padding)
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
// Returns the underlying COM pointer for callers that pass it to native query APIs.
|
||||
public IntPtr GetIQueryPropertyBag()
|
||||
{
|
||||
if (_bag is null) return IntPtr.Zero;
|
||||
return StrategyBasedComWrappers.Instance.GetOrCreateComInterfaceForObject(_bag, CreateComInterfaceFlags.None);
|
||||
}
|
||||
|
||||
// Packs multiIds into a native IDList: { int Count; int* Ids }.
|
||||
// The returned IntPtr is unmanaged heap memory; the native caller is responsible for freeing it.
|
||||
public IntPtr PackIDList(IList multiIds)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
// Packs parallel sort-direction/attribute arrays into a native IMultiSortAttributes COM object.
|
||||
// Requires CSchemaMap.GetIndex to map attribute name strings to schema indices,
|
||||
// and a native ZuneLibraryExports.CreateMultiSortAttributes factory.
|
||||
public IntPtr PackMultiSortAttributes(string[] sortStrings, bool[] sortAscendings)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
(_bag as IDisposable)?.Dispose();
|
||||
_bag = null;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace MicrosoftZuneLibrary;
|
||||
|
||||
public class AppInitializationSequencer
|
||||
{
|
||||
public delegate void Phase3CompleteCallback();
|
||||
|
||||
internal AppInitializationSequencer()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace MicrosoftZuneLibrary;
|
||||
|
||||
public class CallbackOnUIThread : IDisposable
|
||||
{
|
||||
private readonly IRequestCallbackOnUIThread _pUI;
|
||||
private bool _disposed;
|
||||
|
||||
public CallbackOnUIThread(IRequestCallbackOnUIThread pUI)
|
||||
{
|
||||
_pUI = pUI;
|
||||
}
|
||||
|
||||
public void Request(CallbackPriorityManaged priority, int id, IntPtr pv, IntPtr pNativeDeferredCallback)
|
||||
{
|
||||
_pUI.CallbackOnUIThreadRequest(priority, id, pv, pNativeDeferredCallback);
|
||||
}
|
||||
|
||||
protected virtual void Dispose([MarshalAs(UnmanagedType.U1)] bool P_0)
|
||||
{
|
||||
if (P_0)
|
||||
{
|
||||
_disposed = true;
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
_disposed = true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
~CallbackOnUIThread()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace MicrosoftZuneLibrary;
|
||||
|
||||
public class CallbackOnUIThreadPack
|
||||
{
|
||||
private readonly object m_pCallback; // Stub for callback data
|
||||
private readonly int m_id;
|
||||
|
||||
public CallbackOnUIThreadPack(object pCallback, int id)
|
||||
{
|
||||
m_pCallback = pCallback;
|
||||
m_id = id;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
namespace MicrosoftZuneLibrary;
|
||||
|
||||
public enum CallbackPriorityManaged
|
||||
{
|
||||
CPNormal = 0,
|
||||
CPHigh = 1,
|
||||
CPAsync = 2
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
namespace MicrosoftZuneLibrary;
|
||||
|
||||
public delegate void CorePhase2ReadyCallback();
|
||||
@@ -1,17 +0,0 @@
|
||||
namespace MicrosoftZuneLibrary;
|
||||
|
||||
public enum EBurnProgressStatus
|
||||
{
|
||||
ebsUnknown = 0,
|
||||
ebsMediaCheck = 1,
|
||||
ebsPreparerating = 2,
|
||||
ebsPregrooving = 3,
|
||||
ebsWriting = 4,
|
||||
ebsVerifying = 5,
|
||||
ebsFinalizing = 6,
|
||||
ebsCompleted = 7,
|
||||
ebsError = 8,
|
||||
ebsPaused = 9,
|
||||
ebsReady = 10,
|
||||
ebsStopped = 11
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
namespace MicrosoftZuneLibrary;
|
||||
|
||||
public enum EBurnState
|
||||
{
|
||||
ebsUnknown = 0,
|
||||
ebsStopped = 1,
|
||||
ebsPaused = 2,
|
||||
ebsStarting = 3,
|
||||
ebsBurning = 4,
|
||||
ebsVerifying = 5,
|
||||
ebsFinalizing = 6,
|
||||
ebsCompleted = 7,
|
||||
ebsCanceled = 8,
|
||||
ebsFailed = 9,
|
||||
ebsPrepared = 10,
|
||||
ebsIdle = 11,
|
||||
ebsEjecting = 12,
|
||||
ebsEjected = 13,
|
||||
ebsMediaAbsent = 14,
|
||||
ebsMediaPresent = 15,
|
||||
ebsReadyToBurn = 16,
|
||||
ebsNotReady = 17,
|
||||
ebsNoMedia = 18,
|
||||
ebsBlankDisc = 19,
|
||||
ebsPartialDisc = 20,
|
||||
ebsFullDisc = 21,
|
||||
ebsClosedDisc = 22,
|
||||
ebsOpenDisc = 23,
|
||||
ebsRewritable = 24,
|
||||
ebsWriteOnce = 25,
|
||||
ebsDVDPlusR = 26,
|
||||
ebsDVDPlusRW = 27,
|
||||
ebsDVDMinusR = 28,
|
||||
ebsDVDMinusRW = 29,
|
||||
ebsDVDPlusRDualLayer = 30,
|
||||
ebsDVDMinusRDualLayer = 31,
|
||||
ebsHDVDMinusR = 32,
|
||||
ebsHDVDMinusRW = 33,
|
||||
ebsHDVDPlusR = 34,
|
||||
ebsHDVDPlusRW = 35,
|
||||
ebsBluRayR = 36,
|
||||
ebsBluRayRW = 37,
|
||||
ebsArchiveDisc = 38,
|
||||
ebsCDROM = 39,
|
||||
ebsCDDA = 40,
|
||||
ebsCDRW = 41,
|
||||
ebsDVDROM = 42,
|
||||
ebsDVDRAM = 43,
|
||||
ebsMax = 44
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace MicrosoftZuneLibrary;
|
||||
|
||||
public interface INativeDeferredCallback
|
||||
{
|
||||
void Invoke(int hrResult, IntPtr pContext);
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
namespace MicrosoftZuneLibrary;
|
||||
|
||||
public interface IQueryListEvents
|
||||
{
|
||||
void ListBeginBulkEvents();
|
||||
void ListEndBulkEvents();
|
||||
void ListInsert(int index);
|
||||
void ListRemoveAt(int index);
|
||||
void ListModified(int dwItem);
|
||||
void ListNotifyCount(uint ulCount);
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace MicrosoftZuneLibrary;
|
||||
|
||||
public interface IRequestCallbackOnUIThread
|
||||
{
|
||||
void CallbackOnUIThreadRequest(CallbackPriorityManaged priority, int id, IntPtr pv, IntPtr pInterface);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user