# Quick Start — C#

This walkthrough takes about 15 minutes and gets you from a fresh checkout
to extracting files out of a forensic image with the C# example application
**FexViewer**.

FexViewer is a console app at `sdk/examples/csharp/`. It uses direct P/Invoke
into `FEX.Core.dll` — there is no separate managed wrapper assembly, so the
patterns you see in `NativeMethods.cs` and `FexApi.cs` are exactly what
your own integration will look like.

- [Prerequisites](#prerequisites)
- [1. Build FexViewer](#1-build-fexviewer)
- [2. Inspect an image — `info`](#2-inspect-an-image--info)
- [3. List the filesystem — `list`](#3-list-the-filesystem--list)
- [4. Extract files — `extract`](#4-extract-files--extract)
- [5. Multi-segment and encrypted images](#5-multi-segment-and-encrypted-images)
- [Where to go next](#where-to-go-next)

---

## Prerequisites

| Requirement | Notes |
|---|---|
| **.NET 8 SDK** | `dotnet --version` should print `8.x`. Get it from <https://dotnet.microsoft.com/download/dotnet/8.0>. |
| **Windows x64** | The 1.4.x SDK ships Win64 binaries. Linux and macOS are deferred to a follow-up patch. |
| **FEX2 license key** | Set the environment variable `FEX_LICENSE_KEY=FEX2-…`. Contact `sales@getdata.com` for an evaluation key. |
| **A forensic image** | The SDK ships `sdk/sample-data/sample-image.dd` — a 50 MB FAT32 image. Substitute your own E01 / Ex01 / L01 / DD / DMG / AFF4 if you have one. |

The runtime DLLs (`FEX.Core.dll`, `libcrypto-1_1-x64.dll`, `bzip2.dll`) live in
`sdk/bin/Win64/`. The FexViewer csproj copies them next to the executable on
every build, so you don't manage that yourself.

---

## 1. Build FexViewer

From a PowerShell prompt:

```powershell
cd "sdk\examples\csharp"
dotnet build -c Release
```

Output lives at `sdk\examples\csharp\bin\Release\net8.0\FexViewer.exe`. The
build is configured with `TreatWarningsAsErrors=true` and ships clean —
any warnings on your environment indicate something to investigate before
trusting the output.

To verify the binary loads `FEX.Core.dll` and the license is recognised:

```powershell
$env:FEX_LICENSE_KEY = "FEX2-...your-key..."
.\bin\Release\net8.0\FexViewer.exe info --image "..\..\sample-data\sample-image.dd"
```

If you see JSON metadata, you're set.

---

## 2. Inspect an image — `info`

`FexViewer info` calls `GetImageInfoByFilenameAsJSON` and prints the parsed
metadata: image type, device size, segment count, hashes, and any
format-specific blocks (e.g. EnCase case name / examiner).

```powershell
.\FexViewer.exe info --image "C:\evidence\disk.E01"
```

Sample output:

```
Image type:        E01
Filename:          disk.E01
Device size:       250.06 GB
Segments:          12
MD5:               5d41402abc4b2a76b9719d911017c592
SHA1:              aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d
Case name:         OPS-2026-001
Evidence number:   2
Examiner:          L. Investigator
```

The two C# calls behind that output (from `FexApi.GetImageMetadata`):

```csharp
int rc = NativeMethods.GetImageInfoByFilenameAsJSON(
    absolutePath, out IntPtr buffer, out uint size);
// ... check rc, marshal UTF-8 JSON, deserialize into ImageMetadata ...
NativeMethods.FreeAllocatedBuffer(buffer);   // pair every V2 call
```

The buffer-ownership rule applies to every V2 export: the DLL allocates,
your code frees with `FreeAllocatedBuffer` in a `finally` block. See
[memory-management.md](api/memory-management.md) for the full pattern.

---

## 3. List the filesystem — `list`

`FexViewer list` enumerates every record using `GetFileSystemRecords_V2` and
prints them as a table, JSON, or CSV.

```powershell
# Default table format
.\FexViewer.exe list --image "C:\evidence\disk.E01" --limit 20

# JSON to a file (one object per record, no truncation)
.\FexViewer.exe list --image "C:\evidence\disk.E01" --format json --out files.json

# CSV
.\FexViewer.exe list --image "C:\evidence\disk.E01" --format csv --out files.csv
```

The C# pattern looks like this:

```csharp
NativeMethods.ReadFileSystem(imageId, out _);

IntPtr records = IntPtr.Zero;
try
{
    int rc = NativeMethods.GetFileSystemRecords_V2(
        imageId, out uint count, out records, out _);
    if (rc != NativeMethods.RESULT_OK)
        throw new FexCoreException("GetFileSystemRecords_V2", rc);

    int stride = Marshal.SizeOf<FileRecordNative>();
    IntPtr cur = records;
    for (int i = 0; i < count; i++)
    {
        var native = Marshal.PtrToStructure<FileRecordNative>(cur);
        string name = Marshal.PtrToStringUTF8(native.filename) ?? "";
        // ... use whatever fields you need ...
        cur = IntPtr.Add(cur, stride);
    }
}
finally
{
    if (records != IntPtr.Zero)
        NativeMethods.FreeAllocatedBuffer(records);
}
```

Two important details about this pattern:

1. **Resolve every UTF-8 string before the `FreeAllocatedBuffer` call.**
   The `filename` pointer inside each record lives inside the same
   allocation; freeing the buffer invalidates them all.
2. **Use `[StructLayout(LayoutKind.Sequential, Pack = 1)]`** on the C#
   struct that mirrors `TFileRecord` — Pascal records are packed, and any
   alignment mismatch produces silently corrupted reads. The canonical
   layout is `FileRecordNative` in `sdk/examples/csharp/FexApi.cs`.

The status flags on each record (deleted, folder, system, partition,
free-space, …) are documented in
[types-and-constants.md](api/types-and-constants.md#file-status-flags).

### When to switch to V3

`GetFileSystemRecords_V2` materialises every record and every filename in a
single allocation. For datasets with multiple millions of records, that
allocation can hit memory limits and return `RESULT_BUFFER_OVERFLOW`.
At that point switch to V3 windowed extraction —
[v3-api.md](api/v3-api.md) walks through the workflow with a complete C#
example.

---

## 4. Extract files — `extract`

`FexViewer extract` writes selected files from the image to a directory on
your host filesystem.

```powershell
# Extract one folder (recursive)
.\FexViewer.exe extract `
  --image "C:\evidence\disk.E01" `
  --path  "/Users/Alice/Documents" `
  --out   "C:\out\Alice-Documents"

# Extract everything; skip deleted records
.\FexViewer.exe extract `
  --image "C:\evidence\disk.E01" `
  --path  "/" `
  --out   "C:\out\full" `
  --skip-deleted

# Dry run — print what would be written without touching disk
.\FexViewer.exe extract `
  --image "C:\evidence\disk.E01" `
  --path  "/Users" `
  --out   "C:\out\dryrun" `
  --dry-run
```

The output directory is **relativised** to `--path`: with `--path /Users/Alice`
and `--out C:\out`, the children of `Alice` land directly in `C:\out\…`.

Per-file logic mirrors what your own extractor will do:

1. Open the image, read filesystem, get records (as above).
2. For each record you want:
   - Skip system / partition / free-space / device entries (status flags).
   - Use `GetFileSize` *or* the `logicalSize` field from the record.
   - Read in chunks with `ReadFileData`, **truncating the final write to
     `logicalSize`** to strip cluster-slack bytes.
   - Restore timestamps from `createdDate` / `modifiedDate` / `accessedDate`
     (FILETIME `int64`s; convert with `DateTime.FromFileTimeUtc`).
   - Sanitise filenames for Windows (the FexViewer `extract` command
     replaces `\ / : * ? " < > |` with `_`).

The chunked-read pattern in C#:

```csharp
const int CHUNK = 1024 * 1024;
IntPtr scratch = Marshal.AllocHGlobal(CHUNK);
try
{
    long offset = 0;
    while (offset < logicalSize)
    {
        int want = (int)Math.Min(CHUNK, logicalSize - offset);
        int rc = NativeMethods.ReadFileData(
            imageId, fileIndex, offset, scratch, want, out int got);
        if (rc != NativeMethods.RESULT_OK || got <= 0) break;

        var slice = new byte[got];
        Marshal.Copy(scratch, slice, 0, got);
        outputStream.Write(slice, 0, got);

        offset += got;
    }
}
finally
{
    Marshal.FreeHGlobal(scratch);
}
```

`ReadFileData` is a *caller-allocated* function (Pattern 3 in
[memory-management.md](api/memory-management.md)) — `Marshal.AllocHGlobal`
pairs with `Marshal.FreeHGlobal`, and there's no `FreeAllocatedBuffer`
involved.

---

## 5. Multi-segment and encrypted images

FexViewer accepts a JSON manifest in place of `--image <path>`:

```json
{
  "manifest_version": 1,
  "segments": [
    "C:\\evidence\\case123\\disk.E01",
    "C:\\evidence\\case123\\disk.E02",
    "C:\\evidence\\case123\\disk.E03"
  ],
  "passwords": [
    "MyBitLockerPassword",
    "C:\\evidence\\case123\\recovery.bek"
  ]
}
```

```powershell
.\FexViewer.exe info --image "case123.json"
```

Behind the scenes:

- **Multi-segment images** — only the first segment is passed to
  `OpenImage`. The DLL auto-detects companion segments by naming
  convention (`E01`, `E02`, …). The manifest's `segments` list is used to
  validate that companion files exist; missing files are warned about
  rather than silently ignored.
- **Encrypted volumes** — each entry in `passwords` is tried in order. An
  entry that resolves to an existing file path is treated as a key file
  (e.g. a BitLocker `.bek`); everything else is treated as a literal
  password. This lets one manifest carry credentials from multiple
  vendors.

The DLL-level encoding for credentials is the `optionsString` parameter to
`OpenImage`:

```json
{ "Password": "MyVolumePassword" }
```

The `Password` field is overloaded — the DLL recognises the BitLocker key
file format if the value resolves to an existing file. See
[OpenImage in v2-api.md](api/v2-api.md#openimage) for the full
specification.

If you'd rather keep credentials out of the case manifest, FexViewer
accepts a separate `--passwords <file>` argument pointing at a JSON file
with the same shape (just the `passwords` array). That overrides anything
in the case manifest.

---

## Where to go next

| You want to… | Read |
|---|---|
| Understand every V2 export in detail | [api/v2-api.md](api/v2-api.md) |
| Page through a million-record image | [api/v3-api.md](api/v3-api.md) |
| Look up a result code | [api/error-codes.md](api/error-codes.md) |
| See `TFileRecord` / `TPropertySpec` layouts | [api/types-and-constants.md](api/types-and-constants.md) |
| Get the buffer ownership rules right | [api/memory-management.md](api/memory-management.md) |
| Find a function alphabetically | [api/function-index.md](api/function-index.md) |
| Read the FexViewer source | `sdk/examples/csharp/` — `NativeMethods.cs`, `FexApi.cs`, `Commands/`, `Models/` |
