Compare commits

..

555 Commits

Author SHA1 Message Date
f254bd4966
Merge pull request #370 from gnh1201/dev
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Blocked by required conditions
Change the project name to WelsonJS.Toolkit to WelsonJS.Augmented
2025-12-14 21:08:51 +09:00
f49f847cb1
Update WelsonJS.Augmented/Catswords.Phantomizer/AssemblyLoader.cs
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-12-14 21:02:07 +09:00
Namhyeon, Go
5665de20cf Update AssemblyLoader.cs (Catswords.Phantomizer)
Update AssemblyLoader.cs (Catswords.Phantomizer)
2025-12-14 20:45:59 +09:00
Namhyeon, Go
17e3c8df46 Add TryVerifyUrl method (Catswords.Phantomizer)
Add TryVerifyUrl method (Catswords.Phantomizer)
2025-12-14 20:40:10 +09:00
Namhyeon, Go
52ea58ce49 Update AssemblyLoader.cs (Catswords.Phantomizer)
Update AssemblyLoader.cs (Catswords.Phantomizer)
2025-12-14 20:12:52 +09:00
Namhyeon, Go
7d5c60d0a3 Update AssemblyLoader.cs and examples (Catswords.Phantomizer)
Update AssemblyLoader.cs and examples (Catswords.Phantomizer)
2025-12-14 19:15:51 +09:00
Namhyeon, Go
c96100b716 Update .appveyor.yml 2025-12-14 18:57:54 +09:00
Namhyeon, Go
d5a6812456 Update .appveyor.yml 2025-12-14 18:55:59 +09:00
Namhyeon, Go
fdabeab54f Change the project name to WelsonJS.Toolkit to WelsonJS.Augmented
Change the project name to WelsonJS.Toolkit to WelsonJS.Augmented
2025-12-14 18:54:32 +09:00
Namhyeon, Go
25aaff14f2 Revert "Remove the native components"
This reverts commit a763e63459.
2025-12-14 18:48:12 +09:00
Namhyeon, Go
2f3761891b Revert "Update .submodules"
This reverts commit 02d17ee47f.
2025-12-14 18:47:57 +09:00
Namhyeon, Go
f91295bb83 Revert "Update .appveyor.yml"
This reverts commit c4efccef6e.
2025-12-14 18:47:50 +09:00
Namhyeon, Go
c4efccef6e Update .appveyor.yml 2025-12-14 18:43:32 +09:00
Namhyeon, Go
02d17ee47f Update .submodules
Update .submodules
2025-12-14 18:27:06 +09:00
Namhyeon, Go
a763e63459 Remove the native components
Remove the native components
2025-12-14 18:23:30 +09:00
Namhyeon, Go
ab2df37bef Add the flexible scheme #368 (Catswords.Phantomizer)
Add the flexible scheme #368 (Catswords.Phantomizer)
2025-12-14 16:46:07 +09:00
Namhyeon, Go
b5271c529c Add the flexible scheme #368 (Catswords.Phantomizer)
Add the flexible scheme #368 (Catswords.Phantomizer)
2025-12-14 16:42:06 +09:00
8d4a90c0e1
Merge pull request #366 from gnh1201/dev
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Has been cancelled
Fix some bugs (Catswords.Phantomizer)
2025-12-11 17:43:28 +09:00
5fa99240bd Update README.md (Catswords.Phantomizer)
Update README.md (Catswords.Phantomizer)
2025-12-11 17:34:40 +09:00
495a3b8b93 Update Catswords.Phantomizer.dll.gz
Update the Catswords.Phantomizer embedded assembly
2025-12-11 17:31:59 +09:00
aeeeb253fb Update version to 1.0.0.1 (Catswords.Phantomizer)
Update version to 1.0.0.1 (Catswords.Phantomizer)
2025-12-11 17:18:09 +09:00
b0dac00af7 Update README.md (Catswords.Phantomizer)
Update README.md (Catswords.Phantomizer)
2025-12-11 17:16:02 +09:00
48f1f66fa2 Fix some bugs (Catswords.Phantomizer)
Fix some bugs (Catswords.Phantomizer)
2025-12-11 17:13:31 +09:00
2cb422d075
Merge pull request #365 from gnh1201/dev
Update the integrity check (Catswords.Phantomizer)
2025-12-11 15:16:21 +09:00
2b3a80bf98 Update README.md (Catswords.Phantomizer)
Update README.md (Catswords.Phantomizer)
2025-12-10 15:32:39 +09:00
14cb0670f2 Update README.md (Catswords.Phantomizer)
Update README.md (Catswords.Phantomizer)
2025-12-10 15:29:01 +09:00
f57c99df9f Update README.md (Catswords.Phantomizer)
Update README.md (Catswords.Phantomizer)
2025-12-10 15:23:27 +09:00
f86305b33f Update README.md (Catswords.Phantomizer)
Update README.md (Catswords.Phantomizer)
2025-12-10 15:05:45 +09:00
145547b6d8 Update README.md (Catswords.Phantomizer)
Update README.md (Catswords.Phantomizer)
2025-12-10 15:03:50 +09:00
97f4020af2 Update README.md (Catswords.Phantomizer)
Update README.md (Catswords.Phantomizer)
2025-12-10 14:55:51 +09:00
0e15aa2b1f Add hash-based assembly integrity check
Add hash-based assembly integrity check
2025-12-10 14:36:59 +09:00
668d2000d3
Create cats.txt
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Has been cancelled
Inspired by the i83 cats.txt draft format, integrated within the IETF cats.txt structure.
2025-12-10 10:41:12 +09:00
40dd2c1b8a
Create AGENTS.md
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Blocked by required conditions
2025-12-09 17:42:46 +09:00
b75166aa05
Merge pull request #364 from gnh1201/dev
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Has been cancelled
Update README.md (Catswords.Phantomizer)
2025-12-08 13:30:02 +09:00
dfb821d1d7
Update README.md 2025-12-08 11:41:40 +09:00
37ed467384
Update README.md 2025-12-08 11:40:36 +09:00
a023ee9d3e
Merge pull request #363 from gnh1201/dev
Update README.md (Catswords.Phantomizer)
2025-12-08 11:39:04 +09:00
0e23c4c1db
Update README.md 2025-12-08 11:34:25 +09:00
94f397eb46
Update README.md 2025-12-08 11:31:29 +09:00
386c7ca7a1
Merge pull request #362 from gnh1201/dev
Edit README.md (Catswords.Phantomizer)
2025-12-08 11:09:55 +09:00
ec4b3b2d7d
Add the Catswords.Phantomizer Structure Overview
Add the Catswords.Phantomizer Structure Overview
2025-12-08 10:49:18 +09:00
e3562856b0
Update README.md 2025-12-08 10:39:53 +09:00
cfc7dbf144
Update README.md 2025-12-08 10:39:04 +09:00
f24375797c
Update README.md 2025-12-08 10:37:37 +09:00
e9cc0cde13
Update README.md 2025-12-08 10:22:46 +09:00
8623cb315d
Update README.md 2025-12-08 10:22:11 +09:00
2040a02628
Merge pull request #361 from gnh1201/dev
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Blocked by required conditions
Introduce the Catswords.Phantomizer to load DLL files via network
2025-12-08 02:19:02 +09:00
Namhyeon, Go
037e692432 Update README.md 2025-12-08 02:13:16 +09:00
Namhyeon, Go
ac6df725f4 Update README.md 2025-12-08 02:06:17 +09:00
Namhyeon, Go
ec79f1ab06 Update README.md 2025-12-08 01:55:10 +09:00
Namhyeon, Go
6839b8edd1 Fix namespace bug when use the assembly loader
Fix namespace bug when use the assembly loader
2025-12-08 01:53:49 +09:00
Namhyeon, Go
28776d7cad Update Catswords.Phantomizer.dll.gz 2025-12-08 01:34:49 +09:00
Namhyeon, Go
c1448ead32 Update README.md 2025-12-08 01:33:33 +09:00
Namhyeon, Go
aafab2032c Update README.md 2025-12-08 01:31:37 +09:00
Namhyeon, Go
c68b73ce7b Update Catswords.Phantomizer.csproj 2025-12-08 01:20:37 +09:00
Namhyeon, Go
3b588c3446 Update .appveyor.yml 2025-12-08 01:15:25 +09:00
Namhyeon, Go
c357d6f944 Add description: Catswords.Phantomizer
Add description: Catswords.Phantomizer
2025-12-08 01:13:08 +09:00
Namhyeon, Go
1366931273 Update README.md 2025-12-08 01:00:23 +09:00
Namhyeon, Go
f30e43c2e3 Introduce new package Catswords.Phantomizer
Introduce new package `Catswords.Phantomizer`

**Catswords.Phantomizer** is an HTTP-based dynamic-link library (DLL) loader designed for .NET applications.
It allows your application to fetch and load assemblies directly from your CDN (Azure Blob, S3, Cloudflare R2, etc.) at runtime, with optional GZip compression support.
2025-12-08 00:49:10 +09:00
f23705240d
Merge pull request #360 from gnh1201/dev
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Blocked by required conditions
Separate HttpClient instances for raw and compressed HTTP transfer modes
2025-12-07 02:49:41 +09:00
Namhyeon, Go
e8dbf69491 Clearify an exceptions
Clearify an exceptions
2025-12-07 02:42:26 +09:00
Namhyeon, Go
b3416f9a5f Dual HttpClient setup matches intent; make Legacy behavior explicitly “no decompression”
Dual HttpClient setup matches intent; make Legacy behavior explicitly “no decompression”
2025-12-07 02:26:45 +09:00
Namhyeon, Go
e90808e517 Null-check logger before use
Null-check logger before use
2025-12-07 02:22:44 +09:00
Namhyeon, Go
5747713f99 ntroduce separate HttpClient instances for raw and compressed HTTP transfer modes
Added two HttpClient instances to distinguish between legacy (no
Accept-Encoding) and modern compressed HTTP transfer behaviors.

- LegacyHttp:
  Sends no Accept-Encoding header.
  Used when requesting .dll.gz files, ensuring that the server delivers
  the file exactly as-is without applying HTTP-level compression.

- Http:
  Enables AutomaticDecompression and advertises Accept-Encoding
  (gzip, deflate).
  When the server supports HTTP content compression, even a regular .dll
  file can be transmitted in compressed form and transparently
  decompressed by the client.

This separation prevents ambiguities between:
  - File-level compression (.dll.gz)
  - Transport-level compression (Content-Encoding: gzip/deflate)

and ensures predictable behavior when downloading assemblies depending on
server capabilities.
2025-12-07 00:23:51 +09:00
e5dd13fd1b
Merge pull request #359 from gnh1201/dev
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Blocked by required conditions
Add support *.dll.gz file in Assembly Loader
2025-12-06 00:46:24 +09:00
Namhyeon, Go
5b86a88111 Use a temporary file for download, An exception clearify
To prevent partial or corrupt files on download failure, write the decompressed
stream to a temporary file first, and then atomically move it to the final
destination upon success.

In TryDownloadGzipToFile, modify the catch block to log the exception details
before returning false, instead of silently swallowing the error.
2025-12-06 00:23:58 +09:00
Namhyeon, Go
4e3c2bc52c Add support *.dll.gz file in Assembly Loader
Add support for *.dll.gz files in Assembly Loader to make downloads faster.
2025-12-06 00:01:50 +09:00
79d83f4346
Merge pull request #358 from gnh1201/dev
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Has been cancelled
Added the assembly loader with Azure Blob Storage
2025-12-04 18:23:01 +09:00
7abf705c6e Improve the loader policy
Improve the loader policy
2025-12-04 18:19:30 +09:00
cb41c92eab Improve the loader policy
Improve the loader policy
2025-12-04 18:06:47 +09:00
d2be6b116d Improve the loader policy
Improve the loader policy
2025-12-04 16:21:47 +09:00
eae040530e Code signing is required
Code signing is required
2025-12-04 16:12:47 +09:00
6d3fb3db0e Update AssemblyLoader.cs
comment an unused variables
2025-12-04 16:08:25 +09:00
07e47338cb Added the assembly loader with Azure Blob Storage
Added the assembly loader with Azure Blob Storage
2025-12-04 14:54:21 +09:00
5c41a4bf72
Merge pull request #357 from gnh1201/dev
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Blocked by required conditions
Add a telemetry to WelsonJS Launcher
2025-12-03 17:05:28 +09:00
e84a69d929 Add null-check for Assembly Version property.
The code properly checks if _telemetryClient is null before tracking the event and uses the assembly version dynamically. However, the Version property of AssemblyName can be null, which would cause a NullReferenceException when calling .ToString().
2025-12-03 16:59:41 +09:00
1d4b7af5b3 Fix the logger for telemetry
Fix the logger for telemetry
2025-12-03 16:54:19 +09:00
3188317bf6 Fix the TelemetryClient
Fix the TelemetryClient
2025-12-03 16:45:31 +09:00
2db2e7b91a Create TelemetryIdentity.cs and more fixes
Create TelemetryIdentity.cs and more fixes
2025-12-03 16:34:41 +09:00
78bcae182e Update telemetryEnabled configuration key
Update telemetryEnabled configuration key
2025-12-03 14:57:59 +09:00
c4e6acc8cd Add a telemetry to WelsonJS Launcher
Add a telemetry to WelsonJS Launcher, To improve debugging experience.
2025-12-03 14:48:30 +09:00
734acb380d
Merge pull request #356 from gnh1201/dev
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Blocked by required conditions
Add an architecture, and fixed a comment on the telemetry section.
2025-12-02 15:28:03 +09:00
Namhyeon, Go
bf4b2214bc Update postInstall.ps1
Remove the architecture numbers comment (duplicated)
2025-12-02 15:21:32 +09:00
Namhyeon, Go
c240f8dfa8 Update postInstall.ps1
Improve a distinct ID fallback
2025-12-02 15:16:29 +09:00
Namhyeon, Go
77ef5b2270 Merge branch 'dev' of https://github.com/gnh1201/welsonjs into dev 2025-12-02 15:04:00 +09:00
Namhyeon, Go
778cc0641b Update postInstall.ps1
Add an architecture, and fixed a comment on the telemetry section.
2025-12-02 15:03:54 +09:00
4445e86ecb
Merge pull request #355 from gnh1201/dev
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Blocked by required conditions
Update DownloadUrls.psd1
2025-12-02 10:35:44 +09:00
996cc898ff Update DownloadUrls.psd1
Fix parse error
2025-12-02 10:32:38 +09:00
313e2dd275 Update DownloadUrls.psd1
added more download links
2025-12-02 10:29:17 +09:00
db5887535f
Merge pull request #354 from gnh1201/dev
added more download URLs
2025-12-02 10:11:41 +09:00
6b6ac32111 Update DownloadUrls.psd1
Fix a download links from SourceForge
2025-12-02 10:02:54 +09:00
a7db8a59bd Update DownloadUrls.psd1
added more downoad URLs
2025-12-02 09:52:06 +09:00
19f6bd1552
Merge pull request #353 from gnh1201/dev
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Blocked by required conditions
Improve the post-install script
2025-12-01 17:37:16 +09:00
Namhyeon, Go
046bb146a9 Fix the architecture number
Fix the architecture number
2025-12-01 17:25:40 +09:00
Namhyeon, Go
e3ec367390 Add logo to postInstall.ps1
Add logo to postInstall.ps1
2025-12-01 17:20:38 +09:00
Namhyeon, Go
c37d42418d Fix mistypos in the post-install script
Fix mistypos in the post-install script, Fix decompression process when the file contains single root
2025-12-01 17:14:28 +09:00
Namhyeon, Go
3058d6c190 Delete binaries_meta.json
Use the `DownloadUrls.psd1` file instead of binaries_meta.json
2025-12-01 16:46:55 +09:00
Namhyeon, Go
95235d4e5f Fix the file path in adb.js
Fix the file path in adb.js
2025-12-01 16:44:03 +09:00
Namhyeon, Go
fc7a13ceba Update adb binary path and contributor info
Changed the default adb binary path to use the app data directory for improved portability. Updated copyright and contributor information. Bumped VERSIONINFO to 0.2.3.
2025-12-01 16:35:54 +09:00
Namhyeon, Go
3e82eeeb4b Add extraction steps for WinDivert and Android Platform Tools
Introduces extraction and installation logic for WinDivert and Android Platform Tools components in postInstall.ps1. Also updates log messages for consistency and clarity.
2025-12-01 16:33:05 +09:00
Namhyeon, Go
0be5bd031d Update installer process handling and cleanup arguments
Removed unnecessary installer arguments and ensured installers run with process waiting for completion in postInstall.ps1. Cleaned up setup.iss to remove redundant 'Components' field for PowerShell execution. Minor formatting fix in DownloadUrls.psd1.
2025-12-01 16:16:43 +09:00
Namhyeon, Go
6b5a5ea08e Rename android_tools component to android_platform_tools
Updated the component name from 'android_tools' to 'android_platform_tools' in setup.iss for consistency and clarity.
2025-12-01 15:47:06 +09:00
Namhyeon, Go
137537d5ca Rename android_tools to android_platform_tools
Updated the component name from 'android_tools' to 'android_platform_tools' in DownloadUrls.psd1 and postInstall.ps1 for consistency and clarity. Adjusted variable names and references accordingly.
2025-12-01 15:46:31 +09:00
Namhyeon, Go
dec8817a32 Add WinDivert and Android Tools components
Introduces WinDivert and Android Platform Tools as selectable components in the installer. Updates DownloadUrls.psd1 with their download URLs, adds their handling in postInstall.ps1, and registers them in setup.iss for installation.
2025-12-01 15:44:36 +09:00
Namhyeon, Go
b95de25502 Update telemetry event properties in postInstall.ps1
Replaces the $process_person_profile property with a product property set to 'welsonjs' in the telemetry event payload for PostHog. This clarifies the product being tracked during installation.
2025-12-01 15:12:08 +09:00
Namhyeon, Go
1c7d9e3b32 Remove tessdata submodules and update install scripts
Deleted tessdata, tessdata_best, and tessdata_fast submodules. Updated DownloadUrls.psd1 to fix Python x86 URL and set gtk3runtime arm64 to null. Improved architecture detection in postInstall.ps1 and cleaned up component selection logic. Modified setup.iss to remove exclusions for tessdata assets and cleaned up run/uninstall sections.
2025-12-01 15:02:40 +09:00
Namhyeon, Go
fc4a238569 Fix component names and update installer script
Corrected syntax errors in component definitions and registry entries, updated post-install PowerShell command formatting, added AppVersion custom message, and implemented GetSelectedComponents function for improved component selection handling.
2025-12-01 14:30:44 +09:00
a709031761 Refactor post-install script for modular component downloads
Introduces a DownloadUrls.psd1 manifest for component URLs and refactors postInstall.ps1 to support modular, architecture-aware downloads and installations. Adds selection logic for components, improves error handling, and updates setup.iss to support new GTK3 and GTK-server options. This change enables easier maintenance and extensibility for future components.
2025-12-01 14:17:03 +09:00
505801664a Refactor installer scripts and update components
Renamed afterInstall.ps1 to postInstall.ps1 and added telemetry support for PostHog. Updated Python embeddable package URLs to version 3.14.0. Revised setup.iss to improve component granularity, update author info, and integrate the new post-install script and telemetry parameters.
2025-12-01 12:29:46 +09:00
35fefc99e3
Merge pull request #352 from gnh1201/dev
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Has been cancelled
Update special channels section in README
2025-11-26 13:22:40 +09:00
6bbfa23946 Merge branch 'dev' of https://github.com/gnh1201/welsonjs into dev 2025-11-26 10:23:16 +09:00
24bb524910 Update special channels section in README
Clarified the paid consultation channel is for Korean customers and added a paid mentorship program for Korean students or beginners.
2025-11-26 10:23:12 +09:00
28b6c094d3
Merge pull request #351 from gnh1201/dev
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Blocked by required conditions
Update README links and sponsor image URLs
2025-11-25 14:47:50 +09:00
58ff280bdf
Update README.md
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
2025-11-25 14:07:05 +09:00
5c7a83b1b3
Update README.md
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
2025-11-25 14:06:21 +09:00
3c9ba38242
Merge branch 'master' into dev 2025-11-25 14:06:04 +09:00
83c81c6bc5 Update README links and sponsor image URLs
Changed download and sponsor image URLs from ics.catswords.net to catswords.blob.core.windows.net. Updated HTTP client and AI integration descriptions for clarity and accuracy.
2025-11-25 14:04:54 +09:00
2056a59739
Merge pull request #350 from gnh1201/dev
Change the Image CDN
2025-11-25 11:31:27 +09:00
631757d9d9 Merge branch 'dev' of https://github.com/gnh1201/welsonjs into dev 2025-11-25 11:09:00 +09:00
3c1098bb7d Add alt text to WelsonJS logo in README
Improved accessibility by providing a descriptive alt attribute for the WelsonJS logo image in the README file.
2025-11-25 11:07:59 +09:00
830de5bb1d
Update README.md
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
2025-11-25 11:04:03 +09:00
84231aad7d Update document links in SECURITY.MD
Changed URLs for certificate and escrow documents to point to the Azure Blob Storage location instead of the previous ics.catswords.net domain.
2025-11-25 11:03:34 +09:00
671c70a9a8 Update GUI screenshot image in README
Replaces the cover image link with a more specific screenshot for the GUI environment section in the README.
2025-11-25 10:55:51 +09:00
40d7dfb704 Update image URLs in README to new CDN
Replaced local and ics.catswords.net image links with catswords.blob.core.windows.net CDN URLs for logo, cover, and screenshots. Added a new screenshot for running .js files as executables.
2025-11-25 10:55:03 +09:00
efdce27b26
Merge pull request #349 from gnh1201/dev
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Has been cancelled
Refactor installer components and registry handling
2025-11-24 00:44:46 +09:00
Namhyeon, Go
342e5f4423 Update description for addtools component
Revised the description of the 'addtools' installation component to clarify that it includes additional tools and a Windows service for WelsonJS.
2025-11-24 00:39:44 +09:00
Namhyeon, Go
0dec23bc65 Refactor installer components and registry handling
Renamed 'downloadtools' and 'winservice' components to 'addtools' in setup.iss and updated related registry and icon entries to use the new component. Registry entries for script execution are now conditional on the 'addtools' component. Removed unnecessary 'pause' from uninstallService.bat for streamlined service removal.
2025-11-24 00:34:10 +09:00
28d66fd30f
Merge pull request #348 from gnh1201/dev
Release 0.2.7.56 Ready
2025-11-24 00:05:12 +09:00
4e25e13f35
Update lib/std.js
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-11-23 23:59:20 +09:00
Namhyeon, Go
11fba0e3d0 Add WelsonJS JCTG feature to README
Documented the new WelsonJS JCTG (JavaScript-Click-To-Go) feature, allowing users to run WelsonJS scripts directly from Windows File Explorer by double-clicking, similar to `.exe` files.
2025-11-23 23:55:33 +09:00
Namhyeon, Go
bc686476b0 Merge branch 'dev' of https://github.com/gnh1201/welsonjs into dev 2025-11-23 23:46:41 +09:00
Namhyeon, Go
f43217e0b1 Add optional components to installer script
Introduces selectable components for file association, Windows Service module, and additional tool downloads in the installation process. Registry and install/uninstall actions are now conditioned on component selection, improving customization for users.
2025-11-23 23:46:07 +09:00
5dd68d8992
Update lib/std.js
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
2025-11-23 23:32:27 +09:00
Namhyeon, Go
c4aed231da Update setup script metadata date
Changed the @updated_on field in setup.iss from 2025-11-21 to 2025-11-23 to reflect the latest modification.
2025-11-23 23:23:09 +09:00
Namhyeon, Go
84fd011e26 Revise test descriptions and tags for clarity
Improved the descriptions and tags for multiple test cases in test-oss-korea-2023.json to enhance clarity, consistency, and readability. Changes include standardizing terminology, correcting capitalization, and providing more precise explanations for each test.
2025-11-23 23:19:52 +09:00
227cd0f6d4 Deprecate Enumerator.toArray and update WMI version
Marked Enumerator.toArray as deprecated in favor of Array.from and updated its fallback implementation. Refactored lib/wmi.js to use Array.from instead of toArray, and bumped VERSIONINFO to 0.1.4. Modified setup.iss to add ScriptEngine and ScriptHostEncode registry entries and removed file associations for several script extensions.
2025-11-23 23:06:19 +09:00
6af55ec007
Merge pull request #347 from gnh1201/dev
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Has been cancelled
Refactor install script and add websocat support
2025-11-21 19:29:35 +09:00
a51e9ff1b4 Update launcher path in registry command
Changed the registry command for opening scripts to reference WelsonJS.Launcher.exe in the 'bin' subdirectory instead of the root application directory. This ensures the correct executable path is used after installation.
2025-11-21 19:17:05 +09:00
77dc2b88c5 Update user data directory logic and version info
Replaced usage of SYS.getEnvString("APPDATA") with SYS.getAppDataDir() for determining the user data directory. Updated VERSIONINFO to 0.5.4 to reflect the change.
2025-11-21 19:11:08 +09:00
5d907e3869 Update app data directory path and version info
Changed the app data directory from 'WelsonJS' to 'welsonjs' for consistency. Bumped VERSIONINFO to 0.1.7 to reflect the update.
2025-11-21 19:07:02 +09:00
fd3a34fc20 Update websocket.js for improved path handling
Refactored default WebSocket executable path selection to check for a user-specific installation before falling back to architecture-based defaults. Updated comments for clarity and incremented version to 0.2.4.
2025-11-21 18:57:23 +09:00
49ebde6835 Improve error handling in afterInstall.ps1
Enhanced error reporting by checking if caught errors are System.Exception and printing the appropriate message. This provides clearer output for both exception and non-exception error types during file download, extraction, and main script execution.
2025-11-21 17:57:18 +09:00
9b6fa4d233
Update afterInstall.ps1
Co-authored-by: qodo-merge-pro[bot] <151058649+qodo-merge-pro[bot]@users.noreply.github.com>
2025-11-21 16:55:27 +09:00
f2f16d7488
Update afterInstall.ps1
Co-authored-by: qodo-merge-pro[bot] <151058649+qodo-merge-pro[bot]@users.noreply.github.com>
2025-11-21 16:52:16 +09:00
ef966dfe1d Refactor install script and add websocat support
Refactored helper functions for clarity and consistency, including renaming and parameter changes. Added support for downloading and installing websocat, updated artifact URLs and extraction logic, and improved architecture-specific handling for optional tools. Enhanced output messages and error handling throughout the script.
2025-11-21 16:05:39 +09:00
4f6040d260
Merge pull request #346 from gnh1201/dev
Some checks failed
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Blocked by required conditions
CodeQL / Analyze (javascript) (push) Has been cancelled
Improve the installation process
2025-11-21 12:00:40 +09:00
cc86267471 Update launcher path in registry and shortcut
Changed the registry command and Start Menu shortcut to reference WelsonJS.Launcher.exe in the user app data directory, ensuring correct file location and execution.
2025-11-21 11:53:25 +09:00
Namhyeon, Go
c75859b350 Enable registry section in setup script
Uncommented the [Registry] section in setup.iss to allow registry entries to be created during installation. This change is necessary for proper file association and protocol handling.
2025-11-21 11:31:00 +09:00
15e6596285 Fix EXE_PATH case in service scripts
Updated the EXE_PATH variable in both installService.bat and uninstallService.bat to use 'welsonjs' instead of 'WelsonJS' for consistency and to avoid potential path issues.
2025-11-21 11:01:10 +09:00
ca8bd275bf Update service paths and installer registry keys
Service executable paths in installService.bat and uninstallService.bat now use %APPDATA% for improved portability. The setup.iss installer script updates registry keys to use the application name macro, adjusts file and icon paths to user appdata, and changes PowerShell execution flags. afterInstall.ps1 now downloads and extracts WelsonJS binary artifacts from a remote URL.
2025-11-21 10:50:31 +09:00
8e1ef781e7
Merge pull request #345 from gnh1201/dev
Add afterInstall.ps1 to installer sources
2025-11-21 10:11:44 +09:00
54a76f7078 Add afterInstall.ps1 to installer sources
Included afterInstall.ps1 in the setup script to ensure it is copied to the application directory during installation.
2025-11-20 17:34:24 +09:00
2317be5c49
Merge pull request #343 from gnh1201/dev
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Blocked by required conditions
Support the file association registration for WelsonJS supported file types
2025-11-20 17:32:57 +09:00
2e92255a3c Use 'using' statement for InstancesForm disposal
Replaces manual disposal of InstancesForm with a 'using' statement to ensure proper resource management and exception safety when recording to the metadata database.
2025-11-20 17:31:50 +09:00
4bd05fd2a2
Update afterInstall.ps1
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-11-20 17:26:11 +09:00
186561639e Add FILE module import and init PythonObject
Imported the FILE module in python3.js and updated PythonObject to initialize the default Python binary path upon creation. Also removed the copyright year range from the file header.
2025-11-20 17:24:26 +09:00
1a75388a69 Fix relative path calculation in file copy loop
Normalizes source directory path before calculating relative file paths to ensure correct substring indexing and prevent off-by-one errors when copying files.
2025-11-20 17:21:47 +09:00
b3b00771c5 Refactor zip file run logic in MainForm
Removed the _filePath field and refactored zip file handling to pass file paths directly as parameters. Simplified the RunAppPackageFile workflow and eliminated redundant methods for improved clarity and maintainability.
2025-11-20 17:14:49 +09:00
afe7d6213a Refactor deploy time recording and improve instance setup
Moved RecordFirstDeployTime from MainForm to Program for better separation of concerns. Updated instance directory creation and asset copying logic in Program.cs to support JS entrypoints, including library copying and first deploy time recording. Added a sleep call to helloworld.js for demonstration purposes.
2025-11-20 17:09:43 +09:00
33c64d50c9 Add afterInstall.ps1 and update tool paths to APPDATA
Introduces afterInstall.ps1 for post-install setup, downloading and extracting required tools to the APPDATA\WelsonJS directory. Updates code in http.js, python3.js, ovftool.js, wamr.js, and system.js to reference binaries from the new APPDATA location. Modifies setup.iss to run the PowerShell script after installation.
2025-11-20 16:44:20 +09:00
6f172aafe1 Revert "Enable COM interop registration in project config"
This reverts commit 4fb7b95c0e.
2025-11-20 14:56:59 +09:00
ce2e6fe103
Merge pull request #344 from gnh1201/dependabot/npm_and_yarn/js-yaml-4.1.1
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Blocked by required conditions
Bump js-yaml from 4.1.0 to 4.1.1
2025-11-20 09:39:31 +09:00
54293b89b6
Update README.md
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Blocked by required conditions
2025-11-19 14:34:31 +09:00
7a49694ff7
Update README.md 2025-11-19 14:33:10 +09:00
d156e40e6b Add Korea business area code checker example
Refactored korea_business_areacode.json to include metadata and expanded area code data. Added korea_biz_area_checker.js example script to read Excel files and match business numbers to area names using the updated area code data.
2025-11-19 12:23:22 +09:00
f86ea078c6 Add new file to .gitignore
Added do_not_push_production_on_friday.js to .gitignore to prevent accidental commits of this file.
2025-11-19 10:26:53 +09:00
9c9f865026 Add Korea business area code JSON data
Introduces a new data file containing business area codes for various regions in Korea. This will be used for region-based business logic or lookups.
2025-11-19 10:19:57 +09:00
0e40d890bf Merge branch 'dev' of https://github.com/gnh1201/welsonjs into dev 2025-11-19 09:52:37 +09:00
daea458f64
Update WelsonJS.Toolkit/WelsonJS.Launcher/Program.cs
Co-authored-by: qodo-merge-pro[bot] <151058649+qodo-merge-pro[bot]@users.noreply.github.com>
2025-11-16 18:58:48 +09:00
c392b6a08a
Update WelsonJS.Toolkit/WelsonJS.Launcher/MainForm.cs
Co-authored-by: qodo-merge-pro[bot] <151058649+qodo-merge-pro[bot]@users.noreply.github.com>
2025-11-15 20:39:11 +09:00
dependabot[bot]
bf3e6ebcf2
Bump js-yaml from 4.1.0 to 4.1.1
Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 4.1.0 to 4.1.1.
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/4.1.0...4.1.1)

---
updated-dependencies:
- dependency-name: js-yaml
  dependency-version: 4.1.1
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-15 10:58:07 +00:00
a03ea7f3b3
Update WelsonJS.Toolkit/WelsonJS.Launcher/Program.cs
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
2025-11-15 18:23:02 +09:00
c677c6907a Add CLI support for running script and zip files
Launcher now accepts a --file argument to run .js or .zip files directly from the command line. MainForm and Program.cs were refactored to support this, including new registry entries in setup.iss for file associations with WelsonJS Script extensions.
2025-11-15 18:08:47 +09:00
4fb7b95c0e Enable COM interop registration in project config
Added <RegisterForComInterop>True</RegisterForComInterop> to all build configurations in WelsonJS.Cryptography.vbproj to support COM interop registration for both Debug and Release builds.
2025-11-10 09:47:17 +09:00
Namhyeon, Go
ba7b3e3685 Revert "Merge pull request #340 from gnh1201/codex/create-winforms-for-websocket-management"
This reverts commit d71adb8001, reversing
changes made to 83b8e453f0.
2025-11-02 18:17:59 +09:00
d71adb8001
Merge pull request #340 from gnh1201/codex/create-winforms-for-websocket-management
Add WinForms interface for WebSocket management
2025-11-02 18:12:37 +09:00
Namhyeon, Go
cfcfaf3e1f Add WinForms interface for WebSocket management 2025-11-02 18:09:59 +09:00
Namhyeon, Go
e9cc898608 Revert "Merge pull request #339 from gnh1201/codex/abstract-connection-management-for-serial-port"
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Has been cancelled
This reverts commit a638a7a6e9, reversing
changes made to cab9013f18.
2025-11-02 17:59:10 +09:00
a638a7a6e9
Merge pull request #339 from gnh1201/codex/abstract-connection-management-for-serial-port
Abstract connection management and add serial port support
2025-11-02 17:36:39 +09:00
Namhyeon, Go
4489c31509 Guard serial reads with timeout-based termination and cap 2025-10-28 16:36:58 +09:00
Namhyeon, Go
9f4219e971 Make serial buffer resets optional and improve receive loop 2025-10-28 14:12:44 +09:00
Namhyeon, Go
3ce8d12628 Include timeouts in serial connection key 2025-10-28 14:12:37 +09:00
Namhyeon, Go
7795946f9f Serialize per-key operations 2025-10-28 14:12:31 +09:00
Namhyeon, Go
c7890aaadb Serialize connection creation per key 2025-10-28 14:12:25 +09:00
Namhyeon, Go
b8362e570c Add connection monitor for managed transports 2025-10-28 13:42:35 +09:00
Namhyeon, Go
6e759008dd Abstract connection management and add serial port support 2025-10-28 13:30:48 +09:00
cab9013f18
Merge pull request #337 from gnh1201/dev
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Has been cancelled
Rename getFilesFromFolder to getFiles and deprecate old name
2025-10-15 17:38:03 +09:00
83b8e453f0 Rename getFilesFromFolder to getFiles and deprecate old name
Renamed the getFilesFromFolder function to getFiles for clarity. The original getFilesFromFolder is now marked as deprecated and calls the new function, with a warning. Updated exports to reflect the change and bumped version to 0.2.17.
2025-10-13 16:23:03 +09:00
de08a5c527
Merge pull request #336 from gnh1201/dev
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Has been cancelled
Add isAbsolutePath utility and update path handling
2025-10-13 15:17:55 +09:00
b6a95a7c50 Refactor path normalization and absolute path check
Introduced a new normalizePath function in file.js to handle path trimming and BOM removal. Updated isAbsolutePath to use normalizePath for more robust path checking. Modified msoffice.js to use isAbsolutePath instead of manual string checks for determining absolute paths.
2025-10-13 15:12:52 +09:00
7cba7895fd Add isAbsolutePath utility and update path handling
Introduced isAbsolutePath function in file.js to robustly check for absolute paths. Updated msoffice.js to use this utility for file path resolution in Excel.open, improving cross-platform compatibility and reliability. Version numbers incremented in both files.
2025-10-13 14:55:10 +09:00
065f59eb4e
Merge pull request #335 from gnh1201/dev
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Has been cancelled
Add editor and community buttons with icons to MainForm
2025-10-10 13:52:18 +09:00
90806493ed Refactor code editor launch logic
Extracted the code editor launch logic into a new LaunchEditor() method to reduce duplication. Both the button and menu item now use this method, and error handling for resource server startup is centralized.
2025-10-10 12:18:47 +09:00
a77c83736c Add editor and community buttons with icons to MainForm
Replaced the community link label with a button featuring an icon, and added a new button to start the editor with its own icon. Updated resource files and designer code to support these changes, and adjusted related event handlers and UI text for clarity.
2025-10-10 12:07:16 +09:00
deefa25ada
Update README.md
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Blocked by required conditions
2025-10-10 09:45:49 +09:00
a4eff4a1fa
Update README.md 2025-10-10 09:45:00 +09:00
4239353a44
Update README.md 2025-10-10 09:43:24 +09:00
93b12d2134
Merge pull request #334 from gnh1201/dev
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Blocked by required conditions
Add CORS support to ResourceServer
2025-10-10 01:25:29 +09:00
ebe7b605cb Add Vary: Origin header and use Response.Close
Sets the 'Vary' header to 'Origin' for CORS responses to improve cache behavior. Replaces OutputStream.Close with Response.Close for proper response handling.
2025-10-09 22:04:27 +09:00
b32801c1c9 clean up the code
clean up the code
2025-10-09 21:14:41 +09:00
33d8fadc8f
Update WelsonJS.Toolkit/WelsonJS.Launcher/ResourceServer.cs
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-10-04 19:39:58 +09:00
cd3e18a4c1 Merge branch 'dev' of https://github.com/gnh1201/welsonjs into dev 2025-10-04 18:11:15 +09:00
49263bb0ac Refactor CORS allowed origins initialization
Replaces GetAllowedOrigins with TryParseAllowedOrigins to initialize allowed origins once during static construction. Adds logging for invalid ResourceServerPrefix values and stores allowed origins in a static field for improved efficiency.
2025-10-04 18:09:03 +09:00
6e499bcedf
Update WelsonJS.Toolkit/WelsonJS.Launcher/ResourceServer.cs
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
2025-10-03 17:49:10 +09:00
8ab70208d0
Update WelsonJS.Toolkit/WelsonJS.Launcher/ResourceServer.cs
Co-authored-by: qodo-merge-pro[bot] <151058649+qodo-merge-pro[bot]@users.noreply.github.com>
2025-10-03 17:48:25 +09:00
a745b6d0a7
Update WelsonJS.Toolkit/WelsonJS.Launcher/ResourceServer.cs
Co-authored-by: qodo-merge-pro[bot] <151058649+qodo-merge-pro[bot]@users.noreply.github.com>
2025-10-03 17:47:01 +09:00
b9e39dd9c7 Add CORS support to ResourceServer
Implemented CORS handling in ResourceServer, including preflight (OPTIONS) request handling and configurable allowed origins via the new ResourceServerAllowOrigins app setting. Updated resources and configuration files to support the new setting.
2025-10-03 17:35:34 +09:00
3542dc24b4
Merge pull request #333 from gnh1201/dev
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Has been cancelled
Refactor IP query to support multiple providers
2025-10-02 14:46:37 +09:00
8cfff666e4
Update WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/IpQuery.cs
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
2025-10-02 14:44:22 +09:00
5fb255e1e3 Refactor IP query to support multiple providers
Replaces the single CriminalIP API integration with a new IP query system supporting both CriminalIP and AbuseIPDB providers. Updates configuration keys, resource files, and the editor UI to handle multiple API endpoints and keys. Refactors backend logic to aggregate and return results from both providers in a unified XML format, and updates the frontend to parse and display these results. Adds improved error handling and logging for IP query and WHOIS operations.
2025-10-02 14:39:50 +09:00
cded75e491
Merge pull request #331 from gnh1201/dev
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Blocked by required conditions
Add Chromium app mode and update executable config keys
2025-10-01 13:27:03 +09:00
a3e00d1762 Add Chromium app mode and update executable config keys
Introduces a new 'ChromiumAppMode' configuration option to launch Chromium in app mode when enabled. Renames 'ChromiumFileName' to 'ChromiumExecutablePath' in both code and configuration for clarity and consistency.
2025-10-01 13:23:27 +09:00
058edb28eb
Merge pull request #330 from gnh1201/dev
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Has been cancelled
Improve TraceLogger with file-based logging and fallback
2025-09-28 21:38:49 +09:00
a35e101f23 Refactor log file naming and improve Format method
Changed log file naming to use <Namespace>.<random-6>.<PID>.log instead of including 'pid' in the filename. Moved file stream creation inside the Trace listener check. Reformatted and clarified the Format method for better readability and error handling.
2025-09-28 20:14:00 +09:00
ce84aab861 Improve TraceLogger with file-based logging and fallback
TraceLogger now writes logs to a file in %APPDATA%\WelsonJS\Logs with a randomized suffix and process ID. If the log directory cannot be created, it falls back to the current directory. The logger also improves formatting and random suffix generation for log file names.
2025-09-28 19:59:45 +09:00
a0360c3d06
Fix broken "rdbl.io" links
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Blocked by required conditions
Fix broken "rdbl.io" links
2025-09-28 15:24:28 +09:00
2b286aaea0
Merge pull request #329 from gnh1201/dev
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Blocked by required conditions
Add ImageColorPicker tool and async resource serving
2025-09-28 03:22:22 +09:00
676f791fab Add ImageColorPicker tool and async resource serving
Introduces the ImageColorPicker resource tool for extracting color information from images via a POST API. Refactors ResourceServer and all resource tools to use async ServeResource methods, improving scalability and consistency. Updates JsSerializer with an engine-backed document store for efficient repeated JSON extraction.
2025-09-28 03:03:19 +09:00
ccfd8c37ea
Merge pull request #328 from gnh1201/dev
ChakraCore and JS (like a JSON) serialization
2025-09-28 01:43:08 +09:00
b1b36744cf
Merge branch 'master' into dev 2025-09-28 01:31:11 +09:00
9547d245b7
Update WelsonJS.Toolkit/WelsonJS.Launcher/JsSerializer.cs
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-09-28 01:06:40 +09:00
91f19bc148
Update WelsonJS.Toolkit/WelsonJS.Launcher/Program.cs
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-09-28 01:02:35 +09:00
2db47bca9a Add optional Authenticode signature validation for native DLLs
Enhanced NativeBootstrap to support optional Authenticode signature validation and custom certificate validators when loading native libraries. Added 'NativeRequireSigned' configuration to app.config and resources, allowing signature enforcement to be toggled. Updated Program.cs to use the new option during initialization.
2025-09-28 00:48:58 +09:00
87020d35ac Refactor logger interface and add JsNative interop layer
Updated ICompatibleLogger to accept params object[] for flexible logging. Refactored TraceLogger to support the new interface and improved formatting. Added JsNative.cs to encapsulate ChakraCore P/Invoke interop, and updated JsCore to use JsNative for all native calls. Modified all resource tools to accept and use ICompatibleLogger for consistent logging. Updated project file to include new and updated sources.
2025-09-28 00:07:41 +09:00
83a037dfa2 Download setup and ChakraCore in AppVeyor build
Added PowerShell steps to download the unsigned setup executable and ChakraCore.dll into the artifacts directory during the AppVeyor after_build phase.
2025-09-27 22:52:13 +09:00
3fe04d1113 Fix submodule gitlink for ChakraCore 2025-09-27 13:01:18 +09:00
4af01706de Add .gitmodules for ChakraCore submodule
Introduces a .gitmodules file to track the ChakraCore submodule under WelsonJS.Toolkit/ChakraCore, referencing the official ChakraCore repository.
2025-09-26 17:13:39 +09:00
130a6fd767 Add ChakraCore integration and native bootstrap logic
Introduces JsCore for ChakraCore P/Invoke, JsSerializer for JSON utilities via JS, and NativeBootstrap for robust native DLL loading. Updates Program.cs to initialize native dependencies at startup and registers new source files in the project file.
2025-09-26 17:04:14 +09:00
376fd8f852
Merge pull request #327 from gnh1201/dev
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Has been cancelled
Rename CitiQuery to IpQuery and update API references
2025-09-25 15:39:15 +09:00
849470555a
Update WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/IpQuery.cs
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-09-25 15:37:16 +09:00
90d623be95 Rename CitiQuery to IpQuery and update API references
Renamed the CitiQuery tool and related files to IpQuery for clarity. Updated all references from CitiApiKey and CitiApiPrefix to CriminalIpApiKey and CriminalIpApiPrefix in code, resources, and UI. Adjusted the editor UI and backend to use the new naming and API configuration.
2025-09-25 15:26:24 +09:00
2f399d0557
Merge pull request #323 from gnh1201/dev
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Has been cancelled
Refactor logging and resource server initialization
2025-08-26 13:07:20 +09:00
e9d475ba4c Improve resource server initialization and mutex handling
Adds a null check for the resource server after initialization and logs an error if it fails. Changes duplicate launcher instance log from error to info, and wraps mutex release in a try-catch to prevent exceptions if not owned.
2025-08-26 13:02:32 +09:00
f3db44d8e3 Fix mutex variable naming in Program.cs
Renamed the out variable from '_createdNew' to 'createdNew' for clarity and updated its usage in the mutex check. This improves code readability and consistency.
2025-08-26 12:55:39 +09:00
ecbe55cf80 Rename mutex out parameter for clarity
Changed the out parameter name from 'mutexNotExists' to '_createdNew' in the Mutex constructor for improved readability and clarity in the Main method.
2025-08-26 12:55:07 +09:00
d3ecbd7ebe Fix mutex logic for single instance check
Renamed variable to clarify mutex existence and corrected the condition to properly detect if the launcher is already running.
2025-08-26 12:53:48 +09:00
57d0454051 Refactor logging and resource server initialization
Introduces ICompatibleLogger for improved logging, replaces Trace.TraceError and Trace.TraceInformation calls with logger methods, and standardizes ResourceServer instance naming to _resourceServer. Passes logger instances to MainForm and ResourceServer for consistent logging. Also refactors mutex handling and initialization logic for clarity.
2025-08-26 12:49:37 +09:00
3865f3216f
Merge pull request #322 from gnh1201/dev
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Blocked by required conditions
Add abnormal case check to clusteredCellsDensity
2025-08-26 10:07:51 +09:00
78ab8d839f Add abnormal case check to clusteredCellsDensity
Returns false if more than one third of the grid is selected, treating it as an abnormal case. Also updates VERSIONINFO to 1.0.4.
2025-08-25 01:39:42 +09:00
cc08f7b362
Merge pull request #321 from gnh1201/dev
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Has been cancelled
TOTP (Time-based OTP) with 32 characters key
2025-08-22 23:28:01 +09:00
d443f6270c Update OTP endpoint and version info in totp.js
Changed the OTP API endpoint from '/tfa/otp' to '/otp' and updated VERSIONINFO to 1.0.1. Improved example comments to clarify key formats and OTP code usage.
2025-08-22 17:59:32 +09:00
dfc18cfd7d Refactor TFA tool to TwoFactorAuth and update TOTP client
Renamed ResourceTools/Tfa.cs to ResourceTools/TwoFactorAuth.cs and updated all references accordingly. Enhanced TwoFactorAuth with improved key handling, error responses, and form parsing. Updated totp.js to use the new local HTTP API endpoints for key generation and OTP calculation, removing legacy JSON-RPC code.
2025-08-22 17:21:31 +09:00
d3a122029d
Merge pull request #320 from gnh1201/dev
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Has been cancelled
Some bug fixes, and enhance ExtraMath module
2025-08-20 17:33:53 +09:00
8ff12c9883
Update lib/extramath.js
Co-authored-by: qodo-merge-pro[bot] <151058649+qodo-merge-pro[bot]@users.noreply.github.com>
2025-08-20 17:29:44 +09:00
1dd02f7a75
Update lib/extramath.js
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
2025-08-20 17:25:51 +09:00
83b022bf6f Refactor grid functions and update exports in extramath.js
Improved clusteredCellsDensity to validate cell indices and refactored coordinate calculation to be 1-based. Replaced tileStartPos with estimateTileStartPosition for more flexible tile positioning, updated exports accordingly, and bumped VERSIONINFO to 1.0.3.
2025-08-20 17:10:58 +09:00
ab869556c4 Add tileStartPos function and update version
Introduced tileStartPos to calculate tile coordinates based on index, size, and columns. Updated VERSIONINFO to 1.0.1 and exported the new function.
2025-08-18 07:20:01 +09:00
717b141cb7 Add clusteredCellsDensity function to extramath.js
Introduces clusteredCellsDensity to evaluate density of selected cells within a grid. Updates module version to 1.0.0 and exports the new function for external use.
2025-08-18 04:16:52 +09:00
83fb136957 Remove redundant error handling in ChromeObject
Eliminated duplicate error response handling logic in ChromeObject and updated the version info to 0.5.3. Error messages are now handled solely by the catch block for cleaner code.
2025-08-18 03:26:27 +09:00
8da63c08ca Add setup file download to AppVeyor build
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Has been cancelled
A PowerShell command was added to download the unsigned setup executable from Azure Blob Storage during the after_build step, saving it to the artifacts directory.
2025-08-18 01:47:36 +09:00
df393ed251
Merge pull request #318 from gnh1201/dev
Improve logging and async handling in ResourceServer
2025-08-17 23:33:35 +09:00
a022383d63 Improve error handling for FetchBlobConfig
Replaces fire-and-forget async call to FetchBlobConfig with a safe pattern that logs errors if the task fails. This ensures exceptions are not silently ignored and improves reliability.
2025-08-17 22:34:31 +09:00
d0c031fe32 Fix async context handling in blob config loading
Added ConfigureAwait(false) to async HTTP call and moved Compile() invocation to immediately after deserialization. This improves async context handling and ensures blob config is compiled before assignment.
2025-08-17 21:22:17 +09:00
6896c272ef
Update WelsonJS.Toolkit/WelsonJS.Launcher/TraceLogger.cs
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-08-17 20:58:08 +09:00
f44f56ea2c Refactor HTTP client usage in ResourceServer
Replaced local HttpClient instantiation with the class-level _httpClient for sending requests. This improves resource management and consistency in HTTP operations.
2025-08-17 20:43:33 +09:00
cc08c46886 Improve logging and async handling in ResourceServer
ResourceServer now defaults to using TraceLogger if no logger is provided and properly awaits FetchBlobConfig. FetchBlobConfig is refactored to return a Task and handle missing configuration more gracefully. TraceLogger now writes logs to a file named after its namespace and sets up a TextWriterTraceListener for persistent logging.
2025-08-17 20:12:38 +09:00
f413a5c4fa
Merge pull request #317 from gnh1201/dev
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Blocked by required conditions
Add ICompatibleLogger interface and integrate logging
2025-08-17 11:24:05 +09:00
8ecdf99d78 Add ICompatibleLogger interface and integrate logging
Introduced ICompatibleLogger interface and TraceLogger implementation to enable flexible logging. ResourceServer now uses ICompatibleLogger for error reporting instead of Trace, improving testability and future extensibility. Updated project file to include new logger classes.
2025-08-16 21:23:16 +09:00
43ff486049
Merge pull request #316 from gnh1201/dev
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Has been cancelled
Refactor WebSocket communication logic
2025-08-14 04:44:48 +09:00
2068cdfeb3 Refactor WebSocket communication logic
Replaces manual WebSocket send/receive code with a single call to _wsManager.SendAndReceiveAsync for improved clarity and maintainability. Updates comments for better readability and removes redundant exception handling for OperationCanceledException.
2025-08-14 04:43:13 +09:00
0aa3b06e42
Merge pull request #315 from gnh1201/dev
Improve WebSocket receive buffer handling
2025-08-14 04:22:26 +09:00
6893eadd04 Improve WebSocket receive buffer handling
Refactored TrySendAndReceiveAsync to use a fixed-size buffer for I/O and dynamically accumulate received data chunks until EndOfMessage. This prevents truncation of large messages and ensures the entire payload is received before decoding.
2025-08-14 04:21:02 +09:00
d2069962bb
Merge pull request #314 from gnh1201/dev
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Blocked by required conditions
Improve WebSocket receive to handle multi-frame messages
2025-08-14 04:02:23 +09:00
e1d90cde18 Improve WebSocket receive to handle multi-frame messages
The receive logic now accumulates all frames until EndOfMessage, ensuring complete messages are read even if fragmented. This change improves reliability when handling large or fragmented WebSocket messages.
2025-08-14 04:01:02 +09:00
6bf280d38f
Merge pull request #313 from gnh1201/revert-310-dev
Revert "Update WebSocketManager.cs"
2025-08-14 03:35:50 +09:00
Namhyeon, Go
c4582b651c
Revert "Update WebSocketManager.cs" 2025-08-14 03:35:41 +09:00
309217994e
Merge pull request #312 from gnh1201/revert-311-dev
Revert "Update WebSocketManager.cs (Urgent)"
2025-08-14 03:35:26 +09:00
Namhyeon, Go
3962e7a04b
Revert "Update WebSocketManager.cs (Urgent)" 2025-08-14 03:35:12 +09:00
b0cd9598eb
Merge pull request #311 from gnh1201/dev
Update WebSocketManager.cs (Urgent)
2025-08-14 03:19:52 +09:00
8bca089976
Update WebSocketManager.cs 2025-08-14 03:18:14 +09:00
e1a9c79a75
Merge pull request #310 from gnh1201/dev
Update WebSocketManager.cs
2025-08-14 03:13:53 +09:00
f1af7029fa
Update WebSocketManager.cs 2025-08-14 03:11:44 +09:00
bb1078dca8
Merge pull request #309 from gnh1201/dev
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Has been cancelled
Improve error handling in sendPageRPC and getEvaluatedValue
2025-08-11 04:58:36 +09:00
7a05916319 Improve error handling in ChromeObject
Enhanced error handling by returning a structured error object when exceptions occur in ChromeObject. Also updated the version info to 0.5.2.
2025-08-11 04:52:38 +09:00
1533059e44 Improve error handling in sendPageRPC and getEvaluatedValue
Refactored sendPageRPC to better handle error responses and log error descriptions from the response object. Updated getEvaluatedValue to safely access the evaluated value, returning an empty string if not present. Bumped VERSIONINFO to 0.5.1.
2025-08-11 02:58:33 +09:00
1b0f529f74
Update SECURITY.MD
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Has been cancelled
2025-08-08 08:38:53 +09:00
c58fe7e35c
Update README.md
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Has been cancelled
2025-08-05 18:14:02 +09:00
9e3b4f1c3c
Merge pull request #307 from gnh1201/dev
Introduce `UseObject(progId, callback)` and more fixes
2025-08-05 17:51:47 +09:00
665642586b
Fix indentation on lib/pipe-ipc.js
Fix indentation on lib/pipe-ipc.js
2025-08-05 17:48:13 +09:00
444b80e3b5
Update file.js 2025-08-05 17:45:46 +09:00
68a57f15fb
Update app.js 2025-08-05 17:44:34 +09:00
0ab35aab7c
Enable the worksheet activation on the screen
Enable the worksheet activation on the screen
2025-08-05 17:33:43 +09:00
6e89bda453
Remove makeInterface(<number>) and replace to UseObject(<string>)
Remove makeInterface(<number>) and replace to UseObject(<string>)
2025-08-05 17:31:48 +09:00
3de5b618db
Introduce getFilesFromFolder() and clean the code
Introduce getFilesFromFolder() and clean the code
2025-08-05 17:30:20 +09:00
1398c1b359
Intoduce UseObject(<string>, <function>) in app.js
Intoduce UseObject(<string>, <function>) in app.js
2025-08-05 17:28:38 +09:00
fe74f360d9
Introduce Array.form(<Enumerator>) polyfills
Introduce Array.form(<Enumerator>) polyfills
2025-08-05 16:39:44 +09:00
129a61299c
Merge pull request #306 from gnh1201/dev
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Blocked by required conditions
Switch Chrome RPC from WebSocket to HTTP gateway
2025-08-05 05:37:22 +09:00
3f376d29c3 Switch Chrome RPC from WebSocket to HTTP gateway
Replaces WebSocket-based RPC communication with HTTP POST requests to a gateway for Chrome debugging. Updates documentation to clarify the need for a protocol conversion gateway and refactors related methods for compatibility. Bumps version to 0.5.
2025-08-05 05:34:22 +09:00
737ad97eff
Merge pull request #305 from gnh1201/dev
Update WebSocketManager.cs (Urgent fix)
2025-08-05 05:05:43 +09:00
ae7f79aeb8 Update WebSocketManager.cs 2025-08-05 05:01:54 +09:00
13cc674433
Merge pull request #304 from gnh1201/dev
Refactor WebSocketManager for improved clarity and reliability
2025-08-05 04:46:17 +09:00
57fae72f42 Refactor WebSocketManager for improved clarity and reliability
Renamed internal classes and fields for clarity, added comments, and refactored SendAndReceiveAsync to use a helper method and a retry mechanism. Improved resource cleanup and error handling for stale sockets. These changes enhance code readability and robustness in WebSocket connection management.
2025-08-05 04:33:18 +09:00
b33069fc9e Update WebSocketManager.cs 2025-08-05 04:26:30 +09:00
147ef3c21b
Merge pull request #303 from gnh1201/dev
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Has been cancelled
WebSocket support for DevTools protocol, and minor fixes
2025-07-31 17:35:02 +09:00
f9c265b08a Use MD5 hash for WebSocket connection keys
Replaces the plain concatenation of host, port, and path with an MD5 hash to generate unique keys for WebSocket connections. This improves key uniqueness and prevents potential issues with special characters in the key string.
2025-07-31 17:28:26 +09:00
92a35606ed Improve XML escaping, WebSocket buffer, and editor style
Replaced HTML encoding with SecurityElement.Escape for XML escaping in ChromiumDevTools. Made WebSocketManager's receive buffer size configurable with a default of 65536 bytes. Updated editor.html to use 'color: inherit' for banner link hover to maintain contrast.
2025-07-31 17:23:11 +09:00
837ab036a8 Enhance banner link style and text in editor.html
Added custom CSS for the banner link to improve appearance and hover effect. Updated the banner link text to include a heart emoji for better visual appeal.
2025-07-31 17:13:45 +09:00
14da9f90da Update editor.html 2025-07-31 17:08:29 +09:00
ed0a7eed3f Update banner link text in editor.html
Changed the banner text from 'WelsonJS Editor powered by Metro UI, Monaco Editor, and JSONEditor.' to 'Contribute this project' with a link to the project's GitHub repository.
2025-07-31 17:05:44 +09:00
7b49817182 Add WebSocket support for Chromium DevTools endpoints
Implemented WebSocket communication in ChromiumDevTools to support 'page/' endpoints, allowing bidirectional messaging with Chromium DevTools Protocol. Added timeout configuration, improved error handling, and refactored WebSocketManager for connection pooling and reconnection. Updated resources and configuration files to support new timeout settings. Also fixed editor.html to handle direct JSON responses for citi-query.
2025-07-31 16:59:03 +09:00
f9becf2c6d
Update README.md
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Has been cancelled
2025-07-29 11:15:25 +09:00
e28ed16494
Update SECURITY.MD 2025-07-29 11:12:49 +09:00
a7b4243aa9
Update SECURITY.MD 2025-07-29 11:08:12 +09:00
fb99c634e3
Update SECURITY.MD 2025-07-29 11:07:55 +09:00
db0174337c
Update README.md 2025-07-29 09:37:39 +09:00
a5ea9a69bd
Update SECURITY.MD
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Blocked by required conditions
2025-07-28 11:20:37 +09:00
15f8cd6790
Update SECURITY.MD 2025-07-28 11:20:17 +09:00
e12f90b8bb
Merge pull request #302 from gnh1201/dev
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Blocked by required conditions
Fix build error in AppVeyor
2025-07-27 23:19:49 +09:00
2b30e864f0 Update WelsonJS.Cryptography.Test.vbproj 2025-07-27 22:45:56 +09:00
6f3e4342fb Update .appveyor.yml 2025-07-27 22:30:25 +09:00
e579a341a4 Add WebSocketManager.cs and more
Add WebSocketManager.cs and more
2025-07-27 22:25:48 +09:00
782f1ebb28
Merge pull request #301 from gnh1201/master
Merge master to dev branch
2025-07-27 16:22:03 +09:00
9a328bff0b
Merge pull request #300 from gnh1201/cryptography
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Blocked by required conditions
Add resource server autostart and Chromium config options
2025-07-27 16:17:10 +09:00
c3d68e1d2f Fix typo
Fix typo
2025-07-27 16:12:55 +09:00
2b4814ecb5 Add resource server autostart and Chromium config options
Introduces ResourceServerAutoStart and ChromiumFileName/ChromiumDevToolsPrefix settings to app.config and resources. Refactors resource server startup logic to support autostart and configurable browser launch. Cleans up related code in MainForm and Program for improved flexibility and maintainability.
2025-07-27 15:57:05 +09:00
bc43302e14
Merge pull request #299 from gnh1201/dev
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Waiting to run
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Blocked by required conditions
Update file headers to reflect .vb extensions
2025-07-27 00:38:29 +09:00
5ee4a1f7b6
Merge pull request #298 from gnh1201/cryptography
Update file headers to reflect .vb extensions
2025-07-27 00:34:44 +09:00
3583415ee2 Update file headers to reflect .vb extensions
Changed file header comments in cryptography-related modules from '.cs' to '.vb' to accurately reflect the file types. This improves clarity and consistency in source file documentation.
2025-07-27 00:31:49 +09:00
786e4661a0
Merge pull request #297 from gnh1201/dev
Add WelsonJS.Cryptography package (SEED, ARIA, HIGHT algoritm)
2025-07-26 23:30:09 +09:00
453fc231d0
Merge pull request #296 from gnh1201/cryptography
Add `WelsonJS.Cryptography` package (SEED, ARIA, HIGHT algoritm)
2025-07-26 23:21:48 +09:00
5c1ffff822 Add license headers to cryptography classes
Added SPDX license and copyright headers to AriaCore and HightAlgorithm classes for compliance and documentation. Minor formatting adjustments in AriaAlgorithm and AriaEcbTransform to improve consistency.
2025-07-26 23:19:48 +09:00
0b73fe8b60 Offical test vector ALL PASSED: SEED, ARIA, HIGHT
Offical test vector ALL PASSED: SEED, ARIA, HIGHT algorithm
2025-07-26 23:12:31 +09:00
9d234e82dc Fix ARIA algorithm has failed #295 (TEST PASSED)
Fix ARIA algorithm has failed #295 (TEST PASSED)
2025-07-26 23:06:36 +09:00
76ebdbb7a8 try fix #295 (TEST FAILED)
try fix #295 (TEST FAILED)
2025-07-26 18:09:11 +09:00
3498f27619 Implement HIGHT algorithm with official test vector (TEST PASSED) #293
Implement HIGHT algorithm with official test vector (TEST PASSED) #293
2025-07-25 00:06:40 +09:00
2a8c4d196c Add HIGHT block cipher implementation #293
Implemented the HIGHT block cipher with ECB mode support, including HightAlgorithm, HightCore, and HightEcbTransform classes. Updated the test program to include HIGHT encryption/decryption tests and added support for PaddingMode.None in ARIA and SEED ECB transforms.
2025-07-20 19:49:52 +09:00
ec03bf415d Add ARIA cryptography algorithm
Add ARIA cryptography algorithm
2025-07-19 19:07:05 +09:00
90e0caf8d6
Merge pull request #292 from gnh1201/dev
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Has been cancelled
Update the contacts
2025-07-16 15:11:26 +09:00
2688765f84 Update the contacts 2025-07-16 13:57:04 +09:00
87f25b2d44
Create jekyll-gh-pages.yml
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / build (push) Has been cancelled
Deploy Jekyll with GitHub Pages dependencies preinstalled / deploy (push) Has been cancelled
2025-07-15 09:33:42 +09:00
db5607320a
Delete .github/workflows/static.yml 2025-07-15 09:32:01 +09:00
9337084fe4
Create static.yml 2025-07-15 09:29:17 +09:00
8bcbbbae4f
Merge pull request #291 from gnh1201/dev
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
Update README.md
2025-07-14 16:06:43 +09:00
0cc3f30044 Update README.md 2025-07-14 15:48:33 +09:00
727c17576c
Create CNAME
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
2025-07-14 09:38:10 +09:00
f9952000b4
Update README.md
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
2025-07-13 15:01:38 +09:00
747d614da6
Merge pull request #288 from gnh1201/dev
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Update README.md
2025-07-11 09:30:32 +09:00
93d273ed54 Update README.md 2025-07-11 09:27:23 +09:00
7237b47703
Merge pull request #287 from gnh1201/dev
Replace the default SERP provider to SerpApi - Update README.md
2025-07-11 08:58:59 +09:00
f1188a32bb Replace the default SERP provider to SerpApi - Update README.md
Replace the default SERP provider to SerpApi - Update README.md
2025-07-11 08:55:49 +09:00
93228103e6
Merge pull request #286 from gnh1201/dev
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
Replace the default SERP provider to SerpApi - Update README.md
2025-07-10 15:07:33 +09:00
be1f0e8e2d Replace the default SERP provider to SerpApi - Update README.md
Replace the default SERP provider to SerpApi - Update README.md
2025-07-10 15:04:25 +09:00
9424ec3427
Merge pull request #285 from gnh1201/dev
Replace the default SERP provider to SerpApi - Update README.md
2025-07-10 14:05:10 +09:00
23b82d953d Replace the default SERP provider to SerpApi - Update README.md
Replace the default SERP provider to SerpApi - Update README.md
2025-07-10 14:04:07 +09:00
0df87cda96
Merge pull request #284 from gnh1201/dev
Replace the default SERP provider to SerpApi
2025-07-10 14:00:50 +09:00
3f8a301680 Update apikey.json 2025-07-10 13:58:23 +09:00
01230745ed Update aviation.js 2025-07-10 13:57:19 +09:00
5ccba3b107 Replace the default SERP provider to SerpApi
Updated all references from the previous default SERP provider to SerpApi, including API keys, proxy configuration, and documentation links. Adjusted aviation.js to use SerpApi endpoints and parameters, and updated testloader.js to reflect the new provider. This change standardizes the search engine scraping integration to use SerpApi.
2025-07-10 13:54:53 +09:00
461e868c07
Delete .gitmodules #283 2025-07-10 13:00:35 +09:00
848a4359fa Fix SEED cryptography algorithm
Fix SEED cryptography algorithm
2025-07-09 11:20:54 +09:00
cb649c88ed Update SEED algorithm 2025-07-05 13:24:10 +09:00
63f009fb73 Add SEED algorithm test project for WelsonJS.Cryptography
Introduced a new test project 'WelsonJS.Cryptography.Test' with a Program.vb that tests SEED encryption and decryption. Updated the solution file to include both the cryptography library and its test project, and configured build settings for all platforms.
2025-07-04 23:53:03 +09:00
014c1eaa59
Update .appveyor.yml 2025-07-04 23:52:20 +09:00
9afb64a997 Add package WelsonJS.Cryptography
Add package `WelsonJS.Cryptography`
2025-07-04 23:43:09 +09:00
ea2c71a53d
Update .appveyor.yml 2025-07-04 10:21:27 +09:00
f227ce9f60
Update README.md 2025-07-03 09:49:19 +09:00
031a26ced6
Merge pull request #280 from gnh1201/dev
Update README.md (WelsonJS.Esent)
2025-06-26 10:57:03 +09:00
21f2187d17 Delete WelsonJS - Backup.Esent.csproj 2025-06-26 10:50:34 +09:00
cc31e9383e Update README.md (WelsonJS.Esent) 2025-06-26 10:49:40 +09:00
509eaac28c
Merge pull request #279 from gnh1201/dev
Update EsentDatabase specs
2025-06-26 10:32:03 +09:00
dcf966b2c5 Fix the null check for schema should occur before accessing schema.PrimaryKey 2025-06-26 10:26:59 +09:00
82df8c5605 Update EsentDatabase specs 2025-06-26 10:22:07 +09:00
c6f546778f
Merge pull request #278 from gnh1201/dev
Introduce ESENT database to WelsonJS Launcher
2025-06-25 15:43:55 +09:00
91ce125c7f Update MainForm.cs 2025-06-25 15:38:26 +09:00
aacc2414f2 ESENT completed #277 2025-06-25 00:19:56 +09:00
9d2fb432f7 Add the package ManagedEsent, and WelsonJS.Esent
Add the package ManagedEsent (microsoft/ManagedEsent@d358c07), and WelsonJS.Esent
2025-06-24 17:55:34 +09:00
62d219f443 ESENT: Add method CreateIndex
The index creation process has been separated into a dedicated method to improve readability and stability.
2025-06-24 11:30:27 +09:00
3e4b6a73b5 Fix the index creation failure 2025-06-23 18:15:37 +09:00
ece369f8f0 Revert "Update MetadataStore.cs"
This reverts commit ba3e21feca.
2025-06-23 18:04:39 +09:00
ba3e21feca Update MetadataStore.cs 2025-06-23 17:40:02 +09:00
0cb0f9303d ESENT: fix the index creation failure #277 2025-06-23 17:36:03 +09:00
dfef7a622f ESENT: try 2 2025-06-22 22:27:42 +09:00
7aa70a2eeb Try to apply ESENT database #277 2025-06-21 18:33:38 +09:00
b4773646c2
Update README.md 2025-06-20 15:58:32 +09:00
0499a126d9
Merge pull request #276 from gnh1201/dev
[lib/chrome] Update the `--disabled-features` flag
2025-06-19 09:41:16 +09:00
2aa6fdc256 Update chrome.js 2025-06-18 15:25:32 +09:00
9b6270ff72 Update chrome.js 2025-06-18 14:56:20 +09:00
2ee3a2f55a
Merge pull request #275 from gnh1201/dev
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Fix #274
2025-06-13 23:16:40 +09:00
526eb92e61 Update chrome.js 2025-06-13 22:16:43 +09:00
670f82fc05
Merge pull request #272 from gnh1201/dev
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Fix #271
2025-06-08 18:00:31 +09:00
cace5c60b3 Update chrome.js 2025-06-08 17:57:58 +09:00
044ab2fb24 Update std.js 2025-06-08 17:47:52 +09:00
f2de8bc141 Fix #271 2025-06-08 17:43:25 +09:00
f37516e4ae
Merge pull request #270 from gnh1201/dev
Update chrome.js
2025-06-08 16:48:26 +09:00
bbc3aa9a6e Update chrome.js 2025-06-07 18:10:29 +09:00
3e4bf1d1ed
Merge pull request #269 from gnh1201/dev
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
Update license headers, contact email, and fix broken files
2025-06-07 17:04:19 +09:00
f911e34c16 Update license headers, contact email, and fix broken files 2025-06-07 16:57:09 +09:00
a1eeb31070
Merge pull request #268 from gnh1201/dev
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
Introduce the accessor and improve the CDP protocol interface
2025-06-07 04:47:19 +09:00
de41c115cd Update std.js 2025-06-07 04:46:28 +09:00
b168b57de8 Update chrome.js 2025-06-07 04:26:33 +09:00
0de9edc83c Update chrome.js 2025-06-07 04:18:20 +09:00
13839a1fc3 Update chrome.js 2025-06-06 19:40:46 +09:00
9def5b996e Update chrome.js, std.js 2025-06-06 19:35:21 +09:00
5c83c086ac Update chrome.js 2025-06-06 13:01:53 +09:00
1591f46ea5
Merge pull request #267 from gnh1201/dev
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Add more Chromium-based browsers
2025-06-06 12:20:11 +09:00
8d8284ecbe Update chrome.js 2025-06-06 12:12:55 +09:00
69c58e0e96
Merge pull request #266 from gnh1201/dev
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Fix #251 #246
2025-06-01 22:41:05 +09:00
19d4cdce6c Update chrome.js 2025-06-01 21:39:13 +09:00
821b3748df Update chrome.js 2025-06-01 21:32:46 +09:00
d88132da05 Update chrome.js 2025-06-01 15:17:19 +09:00
f22a11c246 Update chrome.js 2025-06-01 14:48:46 +09:00
f2fe919ed0 Fix #251 #246 2025-06-01 14:44:07 +09:00
9a9805ce6a
Update issue templates
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
2025-05-30 17:09:11 +09:00
0e8fd4e8e4
Merge pull request #265 from gnh1201/dev
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Fix typo of the license and contributing files
2025-05-26 00:41:07 +09:00
1a670b12c7 Update CONTRIBUTING.md 2025-05-26 00:36:21 +09:00
260292a873 Fix typo of the license and contributing files 2025-05-26 00:10:26 +09:00
6278a76df7
Update LICENSE
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
2025-05-25 19:11:44 +09:00
68aaf07744
Merge pull request #264 from gnh1201/dev
Add LICENSE to each sub-project
2025-05-25 19:10:45 +09:00
a0e29aa491 Add SPDX headers and references to all source files 2025-05-25 15:52:46 +09:00
ec2681b43e Add SPDX and references to all source files 2025-05-25 15:47:19 +09:00
e4e96d566d Add SPDX headers to all source files 2025-05-25 14:56:37 +09:00
bd66105504 Add LICENSE to each project 2025-05-25 13:56:44 +09:00
ceb8c51cf1
Merge pull request #263 from gnh1201/dev
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
Fix issue with file executable path auto-completion
2025-05-24 16:25:37 +09:00
2b9a406805 Update Completion.cs 2025-05-24 16:23:01 +09:00
cb6e25eaa9 Make traceable tasks 2025-05-24 16:18:43 +09:00
c9b6c6a117 Add the SearchMaxResults const 2025-05-24 16:09:33 +09:00
9b64204771 Fix thread-safety issue with concurrent list access. 2025-05-24 15:51:37 +09:00
d9f9d3e38b Fix issue with file executable path auto-completion 2025-05-24 15:33:07 +09:00
365f0ddbdf
Merge pull request #262 from gnh1201/dev
Merge to main branch #261
2025-05-24 12:56:46 +09:00
7e29cc649f Fix mistypo 2025-05-24 12:53:38 +09:00
bee2be97a9 Add the link text 2025-05-24 12:49:37 +09:00
f1a6ef4435 Fix UI management flow issue. 2025-05-24 12:39:58 +09:00
4deddfd8c9
Merge pull request #261 from gnh1201/bcl-zipfile
Use BCL ZipFile class on Launcher, Add deep inspection for ShadowRoot elements
2025-05-24 12:25:40 +09:00
d214a8d749 Fix issues and PR #254 #260 2025-05-24 12:16:11 +09:00
dcdf79dc3a
Merge pull request #260 from teo-tsirpanis/zip-file
Revert to using the BCL `ZipFile` class, without any NuGet package dependencies.
2025-05-24 11:02:05 +09:00
Theodore Tsirpanis
e74b7b8b73 Remove dependency to System.IO.Compression.ZipFile package. 2025-05-22 03:00:34 +03:00
Theodore Tsirpanis
4d9427f514 Revert "Merge pull request #255 from gnh1201/dev"
This reverts commit 4d37a3eb4a, reversing
changes made to fc31b528da.
2025-05-22 02:54:55 +03:00
Theodore Tsirpanis
ea3e70ab24 Revert "Merge pull request #256 from gnh1201/dev"
This reverts commit 26bc061819, reversing
changes made to 4d37a3eb4a.
2025-05-22 02:54:47 +03:00
Theodore Tsirpanis
f2dc0a3904 Revert "Merge pull request #257 from gnh1201/dev"
This reverts commit 308fccf165, reversing
changes made to 26bc061819.
2025-05-22 02:54:35 +03:00
8eb450c9d9
Fix getDeepElementPosition() couldn't get an element position
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
2025-05-21 20:41:58 +09:00
a81ccc0efa
Improve getElementPosition() for handling elements within a shadow root
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
2025-05-21 15:48:19 +09:00
710acc4bbd
Merge pull request #258 from gnh1201/dev
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Criminal IP (criminalip.io) integration to WelsonJS Editor
2025-05-17 16:49:11 +09:00
4ece9636cc
Update README.md 2025-05-17 16:48:32 +09:00
6637ebde11 Criminal IP (criminalip.io) integration to WelsonJS Editor 2025-05-17 16:36:49 +09:00
308fccf165
Merge pull request #257 from gnh1201/dev
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
One more fix #254
2025-05-17 14:24:47 +09:00
b2db6a4b0a One more fix #254 2025-05-17 14:14:15 +09:00
f60754d9d4 One more fix #254 2025-05-17 12:54:07 +09:00
ca9caef94e One more fix #254 2025-05-17 11:50:27 +09:00
c2f578a1c8 Remove the unnecessary line 2025-05-17 11:32:13 +09:00
32a261963a One more fix #254 2025-05-17 11:26:46 +09:00
26bc061819
Merge pull request #256 from gnh1201/dev
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
One more fix #255
2025-05-17 04:01:37 +09:00
1c678ba7ae Update ZipExtractor.cs 2025-05-17 03:56:45 +09:00
4d37a3eb4a
Merge pull request #255 from gnh1201/dev
Remove the dependency `System.IO.Compression.ZipFile` #254
2025-05-17 03:35:58 +09:00
753ef4c6e5 Fix performance issue when initial start 2025-05-17 03:29:36 +09:00
e454c22053 Adopt the code review 2025-05-17 02:46:48 +09:00
db3f0eae0c
Update WelsonJS.Toolkit/WelsonJS.Launcher/ZipExtractor.cs
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-05-17 02:43:34 +09:00
3361fc1270 Adopt the code review 2025-05-17 02:39:42 +09:00
d9721bdb5a Adopt the code review 2025-05-17 02:32:27 +09:00
edd36c3344 Remove the dependency System.IO.Compression.ZipFile #254
Remove the dependency `System.IO.Compression.ZipFile`

It will be fix the potentially license conflct issue from the `System.IO.Compression.ZipFile` package.
2025-05-17 01:54:51 +09:00
fc31b528da
Merge pull request #253 from gnh1201/dev
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Merge pull request #252 from gnh1201/master
2025-05-12 02:31:38 +09:00
718dd77c1b
Merge pull request #252 from gnh1201/master
Update commit history to the dev branch
2025-05-12 02:30:34 +09:00
e1cb460649
Merge pull request #248 from baramofme/master
Fix Gemini llm call
2025-05-12 02:25:56 +09:00
Jihoon Yi
99dc2d321c
Merge branch 'gnh1201:master' into master 2025-05-11 14:28:09 +09:00
0ccddd4e75
Merge pull request #249 from gnh1201/dev
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
Improve the concept to access a blob sources
2025-05-11 01:30:30 +09:00
5087359ac3 Revert "Replace the keyword void to Task for async method"
This reverts commit 0ad978bb6b.
2025-05-11 01:21:08 +09:00
1ab70d7cd7 Revert "Update CDN servers list"
This reverts commit 0438ee9a50.
2025-05-11 01:05:09 +09:00
0438ee9a50 Update CDN servers list 2025-05-10 21:31:49 +09:00
Jihoon Yi
90ea515f41
Update winservice.js
fix wrong typo
2025-05-10 20:51:17 +09:00
Jihoon Yi
2bff4df4be
Update security.js
fix wrong typo
2025-05-10 20:50:24 +09:00
Jihoon Yi
10606532cb
Update testloader.js
Add missing closing brackets in test_implementsobject
2025-05-10 18:38:45 +09:00
0ad978bb6b Replace the keyword void to Task for async method 2025-05-10 16:53:47 +09:00
Jihoon Yi
452675273b
Update language-inference-engine.js 2025-05-10 16:36:53 +09:00
Jihoon Yi
d8a29eaeee
Update language-inference-engine.js
- Add response type check before parsing
- Wrap JSON.parse in a try/catch to handle potential malformed responses.
- Use “system” role for the initial bias message on gemini model object's wrap
2025-05-10 16:30:46 +09:00
Jihoon Yi
b1078cd36c
Add missing model selection in honoai_gemini.ai.js
Add missing model selection
2025-05-10 16:22:08 +09:00
a001471451 Improve the concept to access a blob sources 2025-05-10 16:07:36 +09:00
Jihoon Yi
bcdfef3f6f
Create honoai_gemini.ai.js
Add honoi ai call with gemini
2025-05-10 15:54:04 +09:00
Jihoon Yi
ef23e41e3a
Update language-inference-engine.js
Fix gemini call broken
2025-05-10 15:50:55 +09:00
5f10d50a3c
Create clean_chrome_pup.bat
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
2025-05-08 22:31:55 +09:00
aee5fb22d0
Merge pull request #245 from gnh1201/dev
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Add JavaScript CDN servers
2025-05-05 23:44:59 +09:00
14c8b12df7 Add a CDN servers 2025-05-05 23:32:41 +09:00
deed89560b Update ResourceServer.cs 2025-05-05 23:22:02 +09:00
eb32437f96 Update ResourceServer.cs 2025-05-05 21:34:50 +09:00
c95b7a373b Update ResourceServer.cs 2025-05-05 21:33:06 +09:00
302e7ce4fc Add an available CDN servers 2025-05-05 19:13:41 +09:00
a5fc5de78f Update ResourceServer.cs 2025-05-05 17:47:50 +09:00
d362d852ad Add JavaScript CDN servers 2025-05-05 17:38:48 +09:00
2a3f9fb4fa
Update README.md
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
2025-05-01 14:32:48 +09:00
944751121c
Merge pull request #243 from gnh1201/dev
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Add the example to use function calling on LLM
2025-04-27 13:14:27 +09:00
fb420d1116 Add the example to use function calling on LLM 2025-04-27 13:09:03 +09:00
26af578178
Merge pull request #242 from gnh1201/dev
Set throttle to the prompt context
2025-04-27 11:43:52 +09:00
245dd85341 Update editor.html 2025-04-27 11:39:43 +09:00
fb6596fe64 Update editor.html 2025-04-27 11:10:00 +09:00
a42180d244 Set throttle to the prompt context 2025-04-27 10:50:52 +09:00
73b24f9a56
Merge pull request #240 from gnh1201/dev
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Fix bug when use DevTools CORS policy (WebSocket error)
2025-04-22 21:31:37 +09:00
eae2795bbf Update Program.cs 2025-04-22 21:27:23 +09:00
98e73b2372 Fix bug when use the devtools protocol with the remote allow origins (Fix WebSocket error) 2025-04-22 21:26:42 +09:00
2225ab9011
Merge pull request #239 from gnh1201/dev
Improve WelsonJS Editor with React framework
2025-04-18 19:51:56 +09:00
4c0895850b Update the integrity attributes 2025-04-18 19:48:41 +09:00
ea412908ef Update editor.html 2025-04-18 19:31:23 +09:00
05ea48a0be some updates 2025-04-18 19:22:25 +09:00
243ff95198 Migrate to React framework 2025-04-18 01:06:27 +09:00
8341394912
Merge pull request #238 from gnh1201/dev
Forward Whois and DNS query data to LLM services
2025-04-12 14:34:59 +09:00
e5a89c9182 Forward Whois and DNS query data to LLM services
Forward Whois and DNS query data to LLM services (e.g. Server configuration assistant)
2025-04-12 14:24:59 +09:00
df5b8cd9f0
Merge pull request #237 from gnh1201/dev
Add support the Azure AI, Optimize the HTTPClient object uses.
2025-04-11 14:19:55 +09:00
e7b6a87175 Reduce code complexity 2025-04-11 14:15:03 +09:00
5b2863058a Add support the Azure AI, Optimize the HTTPClient object uses. 2025-04-11 13:44:21 +09:00
cd8844afef
Merge pull request #236 from gnh1201/dev
Update the markdown files
2025-04-10 16:34:47 +09:00
b26d979b8d Update the markdown files 2025-04-10 16:12:43 +09:00
5446a1bee0
Update README.md
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
2025-04-10 15:56:18 +09:00
10101986be
Update README.md
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
2025-04-10 15:56:09 +09:00
47a5f50712
Update README.md
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
2025-04-10 15:56:01 +09:00
86517f313c
Update README.md
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
2025-04-10 15:55:48 +09:00
b6d34404b5 Update README.md 2025-04-10 13:50:37 +09:00
88ac0cd31e Update README.md 2025-04-10 13:41:57 +09:00
3e0fd7c532 Update README.md, SECURITY.MD 2025-04-10 13:39:23 +09:00
22d10cd28b
Merge pull request #235 from gnh1201/dev
Update SECURITY.MD
2025-04-10 13:29:19 +09:00
0e95b72b21 Update SECURITY.MD 2025-04-10 13:23:16 +09:00
426a9d7721
Merge pull request #234 from gnh1201/dev
Update 2025-04-10
2025-04-10 02:29:10 +09:00
d42210f922
Update WelsonJS.Toolkit/WelsonJS.Launcher/Program.cs
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-04-10 02:27:42 +09:00
e853003bda
Merge branch 'master' into dev 2025-04-10 02:26:21 +09:00
8ca4faa88a
Update README.md
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
2025-04-10 02:23:24 +09:00
f84f2195c3 Revert Cache Compression 2025-04-10 02:12:28 +09:00
1742ca385b Update AzureAi.cs 2025-04-10 02:00:18 +09:00
2a9ebaff51 Update AzureAi.cs 2025-04-10 01:48:33 +09:00
916154499c Some updates 2025-04-09 19:58:41 +09:00
53a84b2349 Update README.md 2025-04-07 14:45:25 +09:00
6e3eb5c1d3 Update README.md 2025-04-07 14:44:03 +09:00
4b4754ae16 Update README.md 2025-04-07 14:43:27 +09:00
a273d6aac6 Update README.md 2025-04-07 14:41:56 +09:00
9e1878628b Update README.md 2025-04-07 14:33:47 +09:00
04ce7fdae5 Update README.md, SECURITY.MD 2025-04-07 14:31:11 +09:00
f7de7bd430 Add Cache Compression 2025-04-06 15:23:19 +09:00
ab8a864519
Update README.md 2025-04-05 23:32:10 +09:00
427f8dded0
Update README.md 2025-04-05 23:24:54 +09:00
a96764f725
Update README.md 2025-04-05 23:24:17 +09:00
46d0244c34
Merge pull request #221 from gnh1201/dev
Add the cached blob #220
2025-04-05 20:13:40 +09:00
2cb3c1c331 Add the cached blob 2025-04-05 20:05:23 +09:00
231e6a56bd
Merge pull request #219 from gnh1201/dev
Change the remote blob server to localhost
2025-04-05 17:47:25 +09:00
295ad2fca8 Update ResourceServer.cs 2025-04-05 17:43:34 +09:00
9ecc93a399 Update ResourceServer.cs 2025-04-05 17:42:44 +09:00
2896cc6bf1 Some updates 2025-04-05 17:27:38 +09:00
be37951807 Add the blob server gateway 2025-04-05 17:10:19 +09:00
d38e26ba67
Merge pull request #218 from gnh1201/dev
Refactor an endpoints of the web based editor
2025-04-05 15:24:50 +09:00
dd85e98c9a Some updates 2025-04-05 15:16:15 +09:00
d8fa8779de Refactor an endpoints of the web based editor 2025-04-05 12:53:28 +09:00
f6fd43ae50
Merge pull request #214 from gnh1201/dev
Add Azure AI service (Azure AI Foundry), Add the AppConfig manager
2025-04-02 11:34:00 +09:00
96dbe7b2cd Add Azure AI service (Azure AI Foundry), Add the AppConfig manager 2025-04-02 11:25:23 +09:00
c1fe39d3cc
Merge pull request #213 from gnh1201/dev
Adapt a code review, SRI, CORS, etc.
2025-03-31 17:41:01 +09:00
56ee12741c some updates 2025-03-31 17:09:28 +09:00
4372bdb09d some updates 2025-03-31 16:59:56 +09:00
b21f967a6a Update bootstrap.bat 2025-03-31 16:31:07 +09:00
40b0b704e3 some updates 2025-03-31 15:06:03 +09:00
9a8ee4d7f9 some updates 2025-03-31 14:50:02 +09:00
4f319d474f some updates 2025-03-31 14:18:03 +09:00
93ed60bcf7 some updates 2025-03-31 14:16:35 +09:00
5d717505f4 Edit the codes from code review result 2025-03-30 22:24:35 +09:00
b0e50d33bc Merge branch 'dev' of https://github.com/gnh1201/welsonjs into dev 2025-03-30 21:12:10 +09:00
c0f9816000 Update editor.html 2025-03-30 20:50:54 +09:00
00ea473683 set SRI and CORS policy strictly to editor.html 2025-03-30 20:48:03 +09:00
7e9054fb8f
Merge pull request #203 from gnh1201/dev
Revert "Reduce SAS token period to 2 years"
2025-03-27 18:02:51 +09:00
f29a63027f Revert "Reduce SAS token period to 2 years"
This reverts commit e930cf86fd.
2025-03-27 17:55:13 +09:00
3419e62c6a
Merge pull request #202 from gnh1201/dev
Change the blob download server
2025-03-27 17:50:53 +09:00
e930cf86fd Reduce SAS token period to 2 years 2025-03-27 17:42:58 +09:00
c0a27efd8d Update bootstrap.bat 2025-03-27 17:35:10 +09:00
d42539c0a8
Update README.md 2025-03-26 11:44:37 +09:00
475 changed files with 81705 additions and 4797 deletions

View File

@ -15,22 +15,25 @@ environment:
SIGNING_POLICY_SLUG: release-signing SIGNING_POLICY_SLUG: release-signing
before_build: before_build:
- nuget restore WelsonJS.Toolkit - nuget restore WelsonJS.Augmented
build_script: build_script:
- msbuild "C:\projects\welsonjs\WelsonJS.Toolkit\WelsonJS.Toolkit.sln" /verbosity:minimal /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" /p:Configuration=%CONFIGURATION% /p:Platform="x86" - msbuild "C:\projects\welsonjs\WelsonJS.Augmented\WelsonJS.Augmented.sln" /verbosity:minimal /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" /p:Configuration=%CONFIGURATION% /p:Platform="x86"
after_build: after_build:
- cmd: mkdir artifacts - cmd: mkdir artifacts
#- cmd: xcopy /s /y WelsonJS.Toolkit\WelsonJS.Toolkit\bin\x86\%CONFIGURATION%\* artifacts\ #- cmd: xcopy /s /y WelsonJS.Augmented\WelsonJS.Toolkit\bin\x86\%CONFIGURATION%\* artifacts\
- cmd: xcopy /s /y WelsonJS.Toolkit\WelsonJS.Service\bin\x86\%CONFIGURATION%\* artifacts\ - cmd: xcopy /s /y WelsonJS.Augmented\WelsonJS.Service\bin\x86\%CONFIGURATION%\* artifacts\
- cmd: xcopy /s /y WelsonJS.Toolkit\WelsonJS.Launcher\bin\x86\%CONFIGURATION%\* artifacts\ - cmd: xcopy /s /y WelsonJS.Augmented\WelsonJS.Launcher\bin\x86\%CONFIGURATION%\* artifacts\
- cmd: nuget pack WelsonJS.Toolkit\WelsonJS.Toolkit\ -properties Configuration=%CONFIGURATION% -properties Platform=x86 -OutputDirectory artifacts\ - cmd: xcopy /s /y WelsonJS.Augmented\Catswords.Phantomizer\bin\%CONFIGURATION%\netstandard2.0\* artifacts\
- cmd: nuget pack WelsonJS.Augmented\WelsonJS.Toolkit\ -properties Configuration=%CONFIGURATION% -properties Platform=x86 -OutputDirectory artifacts\
- ps: Start-BitsTransfer -Source "https://catswords.blob.core.windows.net/welsonjs/welsonjs_setup_unsigned.exe" -Destination "artifacts\welsonjs_setup.exe"
- ps: Start-BitsTransfer -Source "https://catswords.blob.core.windows.net/welsonjs/chakracore-build/x86_release/ChakraCore.dll" -Destination "artifacts\ChakraCore.dll"
- cmd: 7z a artifacts.zip artifacts\* - cmd: 7z a artifacts.zip artifacts\*
artifacts: artifacts:
- path: artifacts.zip - path: artifacts.zip
name: WelsonJS.Toolkit name: WelsonJS.Augmented
deploy: deploy:
- provider: Webhook - provider: Webhook
@ -41,7 +44,7 @@ deploy:
notifications: notifications:
- provider: Email - provider: Email
to: to:
- abuse@catswords.net - gnh1201@catswords.re.kr
subject: 'Build #{{build}} {{status}}' subject: "Build {{status}}: {{projectName}} {{buildVersion}}"
on_build_success: false on_build_success: false
on_build_failure: true on_build_failure: true

38
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,38 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.

View File

@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

51
.github/workflows/jekyll-gh-pages.yml vendored Normal file
View File

@ -0,0 +1,51 @@
# Sample workflow for building and deploying a Jekyll site to GitHub Pages
name: Deploy Jekyll with GitHub Pages dependencies preinstalled
on:
# Runs on pushes targeting the default branch
push:
branches: ["master"]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
concurrency:
group: "pages"
cancel-in-progress: false
jobs:
# Build job
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Pages
uses: actions/configure-pages@v5
- name: Build with Jekyll
uses: actions/jekyll-build-pages@v1
with:
source: ./
destination: ./_site
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
# Deployment job
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4

453
.gitignore vendored
View File

@ -1,3 +1,7 @@
# Created by https://www.toptal.com/developers/gitignore/api/visualstudio,node
# Edit at https://www.toptal.com/developers/gitignore?templates=visualstudio,node
### Node ###
# Logs # Logs
logs logs
*.log *.log
@ -5,6 +9,7 @@ npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*
lerna-debug.log* lerna-debug.log*
.pnpm-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html) # Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
@ -41,8 +46,8 @@ build/Release
node_modules/ node_modules/
jspm_packages/ jspm_packages/
# TypeScript v1 declaration files # Snowpack dependency directory (https://snowpack.dev/)
typings/ web_modules/
# TypeScript cache # TypeScript cache
*.tsbuildinfo *.tsbuildinfo
@ -53,11 +58,14 @@ typings/
# Optional eslint cache # Optional eslint cache
.eslintcache .eslintcache
# Optional stylelint cache
.stylelintcache
# Microbundle cache # Microbundle cache
.rpt2_cache/ .rpt2_cache/
.rts2_cache_cjs/ .rts2_cache_cjs/
.rts2_cache_es/ .rts2_cache_es/
.rts2_cache_umd/package .rts2_cache_umd/
# Optional REPL history # Optional REPL history
.node_repl_history .node_repl_history
@ -68,15 +76,20 @@ typings/
# Yarn Integrity file # Yarn Integrity file
.yarn-integrity .yarn-integrity
# dotenv environment variables file # dotenv environment variable files
.env .env
.env.test .env.development.local
.env.test.local
.env.production.local
.env.local
# parcel-bundler cache (https://parceljs.org/) # parcel-bundler cache (https://parceljs.org/)
.cache .cache
.parcel-cache
# Next.js build output # Next.js build output
.next .next
out
# Nuxt.js build / generate output # Nuxt.js build / generate output
.nuxt .nuxt
@ -84,13 +97,19 @@ dist
# Gatsby files # Gatsby files
.cache/ .cache/
# Comment in the public line in if your project uses Gatsby and *not* Next.js # Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support # https://nextjs.org/blog/next-9-1#public-directory-support
# public # public
# vuepress build output # vuepress build output
.vuepress/dist .vuepress/dist
# vuepress v2.x temp and cache directory
.temp
# Docusaurus cache and generated files
.docusaurus
# Serverless directories # Serverless directories
.serverless/ .serverless/
@ -103,7 +122,426 @@ dist
# TernJS port file # TernJS port file
.tern-port .tern-port
# user private assets # Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
### Node Patch ###
# Serverless Webpack directories
.webpack/
# Optional stylelint cache
# SvelteKit build / generate output
.svelte-kit
### VisualStudio ###
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.tlog
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
*.vbp
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
*.dsw
*.dsp
# Visual Studio 6 technical files
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# Visual Studio History (VSHistory) files
.vshistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd
# VS Code files for those working on multiple tools
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace
# Local History for Visual Studio Code
.history/
# Windows Installer files from build outputs
*.cab
*.msi
*.msix
*.msm
*.msp
# JetBrains Rider
*.sln.iml
### VisualStudio Patch ###
# Additional files built by Visual Studio
# End of https://www.toptal.com/developers/gitignore/api/visualstudio,node
bin bin
data/*-apikey.txt data/*-apikey.txt
data/*.nomedia.txt data/*.nomedia.txt
@ -113,3 +551,4 @@ settings.ini
defaultService.js defaultService.js
lib/*.private.js lib/*.private.js
data/python313.zip data/python313.zip
do_not_push_production_on_friday.js

12
.gitmodules vendored
View File

@ -1,9 +1,3 @@
[submodule "app/assets/tessdata"] [submodule "WelsonJS.NET/ChakraCore"]
path = app/assets/tessdata path = WelsonJS.NET/ChakraCore
url = https://github.com/tesseract-ocr/tessdata url = https://github.com/chakra-core/ChakraCore
[submodule "app/assets/tessdata_best"]
path = app/assets/tessdata_best
url = https://github.com/tesseract-ocr/tessdata_best
[submodule "app/assets/tessdata_fast"]
path = app/assets/tessdata_fast
url = https://github.com/tesseract-ocr/tessdata_fast

57
.well-known/cats.txt Normal file
View File

@ -0,0 +1,57 @@
## Website-Name
WelsonJS
## Website-Purpose
WelsonJS is an open-source runtime and tooling ecosystem built on the Windows built-in ECMAScript engine (WSH/HTA). It enables desktop, console, service, and automation applications to run reliably, even under constrained or adverse environments, with minimal external dependencies.
## Contact
* [https://github.com/gnh1201/welsonjs/issues](https://github.com/gnh1201/welsonjs/issues)
* mailto:gnh1201@catswords.re.kr
* [https://catswords.social/@catswords_oss](https://catswords.social/@catswords_oss)
## Important-Links
* [https://github.com/gnh1201/welsonjs](https://github.com/gnh1201/welsonjs)
* [https://catswords.com/](https://catswords.com/)
* [https://signpath.org/projects/welsonjs/](https://signpath.org/projects/welsonjs/)
## Validation-Image
/_/
( =^.^= )
(")(")
## Feline-Registry
The following feline records describe symbolic agents associated with the WelsonJS ecosystem.
This section is inspired by the i83 cats.txt draft format, integrated within the IETF cats.txt structure.
### Cat
Name: WelCat
Role: Runtime Guardian
Breed: Digital Tabby
Location: Seoul, KR
PurrLevel: 9
Description: Represents the resilience of the WelsonJS runtime, which ensures execution stability across legacy and modern Windows environments.
### Cat
Name: ScriptTail
Role: JavaScript Debug Assistant
Breed: British Shorthair (Virtual)
Location: Code Editor
PurrLevel: 8
Description: Helps developers detect subtle logic issues within HTA/WSH scripts and WelsonJS Agent pipelines.
### Cat
Name: PhantomPaws
Role: Assembly Retrieval Agent
Breed: Midnight Black
Location: CDN Edge
PurrLevel: 10
Description: Symbolic cat for Catswords.Phantomizer, responsible for quietly fetching managed and native DLLs from the CDN and preparing them for runtime activation.

450
AGENTS.md Normal file
View File

@ -0,0 +1,450 @@
# AGENTS.md
*WelsonJS Agent Architecture Guide*
WelsonJS consists of two major execution layers:
1. **JavaScript execution environment** based on Windows Script Host (WSH) with `core-js` polyfills
2. **Native/Managed module environment** provided through the `WelsonJS.Toolkit` suite
This document defines the agents that operate inside WelsonJS, including their responsibilities, interaction boundaries, and design principles.
---
## **1. Overview & Design Principles**
WelsonJS aims to enable Windows application development using JavaScript on top of the legacy WSH engine while safely extending system-level functionality through .NET modules.
All agents follow these principles:
* **Single responsibility** — each agent performs one well-defined task
* **Minimal & explicit interfaces**
* **Security & integrity first**
* **Polyfill-based compatibility** (ES3 → ES5)
* **Graceful degradation when native modules are unavailable**
---
## **2. Agent Types**
WelsonJS defines two main categories of agents:
| Category | Description |
| -------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| **JavaScript Runtime Agent** | Executes user scripts in a WSH + polyfill environment. Provides compatibility up to ES5 using `core-js` and related shims. |
| **Native/Managed Module Agents** | Extensions written in C# or VB.NET under the `WelsonJS.Toolkit` solution that provide system-level capabilities. |
---
## **3. JavaScript Runtime Agent**
### **3.1 Description**
The JavaScript Runtime Agent executes scripts using the Windows Script Host engine (JScript).
Although the engine itself is **ES3-level**, WelsonJS uses **core-js polyfills** to emulate many **ES5 features**, allowing more modern syntax and APIs.
### **3.2 Responsibilities**
* Load and initialize polyfills (`core-js`, `JSON2.js`, additional shims)
* Provide CommonJS-style module system (`require`, `exports`, caching, resolution)
* Execute user scripts in a controlled environment
* Provide bound APIs that connect to native agents
* Ensure minimal pollution of the global scope
* Provide compatibility with classical WSH functions and COM interoperability
* Handle script errors and propagate exceptions with useful metadata
### **3.3 Execution Constraints**
* Must assume an **ES3 core** with **ES5 via polyfills**
* Features requiring ES6+ must be explicitly shimmed or avoided
* All host-bound functionality must route through defined native agents
---
## **4. Native/Managed Module Agents (Toolkit Agents)**
The **WelsonJS.Toolkit** solution provides several functional agents designed as modular .NET libraries.
Each project acts as a distinct agent with its own role and responsibility.
---
### **4.1 Catswords.Phantomizer — Assembly Loading Agent**
**Purpose:**
Dynamic loading and resolution of native/managed assemblies.
**Responsibilities:**
* Load DLLs from disk or remote CDN
* Support `.dll.gz` compressed downloads for performance
* Perform integrity/signed verification
* Cache resolved versions locally
* Provide fallback when assemblies fail to load
**Notes:**
This agent enables WelsonJS to remain lightweight while extending capabilities dynamically.
---
### **4.2 WelsonJS.Esent — Database Access Agent**
**Purpose:**
Expose Windows native **ESENT** database engine to JavaScript.
**Responsibilities:**
* Create, open, and manage ESENT databases
* Provide JS-friendly abstraction for tables, cursors, and transactions
* Perform safe parameter marshaling
* Ensure proper disposal of unmanaged resources
* Support transactional metadata operations (e.g., metadata store, instance tracking)
---
### **4.3 WelsonJS.Cryptography — Cryptography Agent**
**Purpose:**
Provide cryptographic functions not available in WSH/JS.
**Responsibilities:**
* Expose symmetric/legacy/industrial cryptographic algorithms
* Bridge specialized Korean algorithms (SEED, ARIA, HIGHT, LEA) where required
* Provide secure random generation utilities
* Ensure compliance with expected test vectors
* Offer safe JS bindings that validate parameters and reject unsafe operations
**Additional:**
`WelsonJS.Cryptography.Test` provides validation and regression testing for algorithm correctness.
---
### **4.4 WelsonJS.Launcher — Bootstrap Agent**
**Purpose:**
Serve as the entry point of a WelsonJS application.
**Responsibilities:**
* Initialize environment
* Load Phantomizer & toolkit modules
* Load and execute the main JavaScript script
* Handle configuration (AppName, BaseUrl, service mode, etc.)
* Provide safe-mode and fallback execution
* Manage initial logging and diagnostics
**Notes:**
Launcher must start with only .NET BCL dependencies to ensure predictable initialization.
---
### **4.5 WelsonJS.Service — Windows Service Agent**
**Purpose:**
Allow WelsonJS applications to run as Windows services.
**Responsibilities:**
* Install/uninstall service
* Run JavaScript scripts in service context
* Manage service lifecycle events (start, stop)
* Provide safe shutdown & worker loop management
---
### **4.6 WelsonJS.Toolkit — General Utility Agent**
**Purpose:**
A shared utility library providing cross-cutting functionality.
Typical responsibilities include:
* IO helpers
* Reflection helpers
* JSNative bridging utilities
* Shared types and error-handling helpers
* Logging abstractions
It acts as the common foundation for other Toolkit modules.
---
## **5. Optional & Internal Agents**
### **5.1 Interop / Binding Agent**
Acts as a transport layer between JS Runtime Agent and Toolkit Agents.
Responsibilities:
* Marshal parameters and return values
* Validate type compatibility
* Protect against injection or malformed input
* Normalize exceptions into JS-friendly error objects
* Enforce version negotiation and capability detection
Often implemented inside each Toolkit module but may be abstracted.
---
### **5.2 Security / Policy Agent**
Provides security boundaries.
Responsibilities:
* Module integrity verification
* Allowed module list management
* Restricting file system or registry access
* Enforcing sandbox policies for script execution
* Logging suspicious activity
---
### **5.3 Fallback / Compatibility Agent**
Ensures application execution even without native modules.
Responsibilities:
* JS-only polyfill alternatives
* Reduced functionality mode
* Diagnostics for missing dependencies
---
## **6. Agent Interaction Model**
```text
[WelsonJS.Launcher]
↓ Initialization + Configuration
[JavaScript Runtime Agent] ←→ [Toolkit Agents]
↑ ↑
(Interop Layer) (Security/Policy)
```
* **Launcher** bootstraps the system.
* **JS Runtime Agent** handles all user logic.
* **Toolkit Agents** provide extended OS-level capabilities.
* **Interop Layer** ensures safe crossing between JS and .NET worlds.
* **Security Agent** governs what is allowed.
---
## **7. Implementation Guidelines**
* Follow "least-privilege" principles for all native module operations.
* All JS ↔ Native APIs must be explicit and documented.
* Native agents must degrade gracefully when unavailable.
* Polyfills must not assume ES6+ features unless explicitly shimmed.
* Fallback behaviors must be deterministic and logged.
* All agents must respect long-term compatibility from Windows XP → Windows 10/11.
---
## **8. Purpose of This Document**
AGENTS.md provides a shared understanding across contributors so that:
* New toolkit modules follow consistent architecture.
* JS runtime bindings remain predictable and safe.
* Extension developers can easily understand boundaries and responsibilities.
* The ecosystem grows without introducing breaking or conflicting functionality.
---
## **9. Test Structure (Test Plan)**
WelsonJS uses **JSON-based test profiles** plus a script runner (`testloader.js`) to verify both the JavaScript Runtime Agent and the Toolkit Agents.
A representative profile is `test-oss-korea-2023.json`, used in the 2023 South Korea OSS Contest to validate the WelsonJS environment.
---
### **9.1 Testing Approach**
* Tests are grouped into **profiles** (single JSON file per profile).
* Each profile describes:
* Test **metadata** (description, updated date, dependencies, authors, references, tags)
* **Schema version**
* An array of **test entries**, each with `id`, `description`, and `tags`
* `testloader.js`:
* Loads a given profile JSON
* Interprets each test `id` as a runnable unit (usually bound to a script or implementation defined inside WelsonJS)
* Executes them in the same WSH + polyfill environment that real users will use
* Aggregates pass/fail status and reports the result
This keeps tests:
* Close to **real execution** (same engine, same polyfills)
* Capable of testing **JS-only behavior** and **JS ↔ native agent integration**
* Easy to extend by just adding new entries into JSON
---
### **9.2 Test Layers Mapped to Existing IDs**
The existing test profile covers multiple layers of the system.
1. **JavaScript Runtime / Polyfill Layer**
* `es5_polyfills` checks whether polyfills above ES5 level run successfully on the built-in engine.
* These tests verify `core-js`, JSON handling, and basic language/runtime correctness.
2. **Windows Systems & Toolkit Integration**
* Registry: `registry_find_provider`, `registry_write`, `registry_read`
* WMI: `wmi_create_object`, `wmi_execute_query`, `wmi_result_query`
* Shell: `shell_create_object`, `shell_build_command_line`, `shell_set_charset`, `shell_working_directory`, `shell_create_process`, `shell_execute`, `shell_run`, `shell_run_as`, `shell_find_my_documents`, `shell_release`
* PowerShell: `powershell_set_command`, `powershell_set_file`, `powershell_set_uri`, `powershell_execute`, `powershell_run_as`
* System information: `system_resolve_env`, `system_check_as`, `system_get_os_version`, `system_get_architecture`, `system_get_uuid`, `system_get_working_directory`, `system_get_script_directory`, `system_get_network_interfaces`, `system_get_process_list`, `system_get_process_list_by_name`, `system_register_uri`, `system_pipe_ipc`
These exercise the **Interop/Binding Agent** and various **Toolkit Agents** that expose Windows APIs.
3. **Human Interface / Virtual Input (VHID)**
* `vhid_find_window`, `vhid_send_click`, `vhid_send_keys`, `vhid_send_key_enter`, `vhid_send_key_functions`, `vhid_alert`, `vhid_confirm`, `vhid_prompt`
These validate keyboard/mouse simulation and dialog APIs, ensuring the Virtual Human Interface agent behaves as expected.
4. **Network & HTTP Layer**
* `network_http_get`, `network_http_post`, `network_http_extended`, `network_attach_debugger`, `network_detect_charset`, `network_detect_http_ssl`, `network_send_icmp`
These tests exercise HTTP/ICMP functionality and optional debugger integration (e.g., Fiddler) via Toolkit Agents.
5. **Advanced String / NLP / Utility**
* `extramath_dtm`, `extramath_cosine_similarity`, `base64_encode`, `base64_decode`
These validate extra math/string/NLP-style helpers that may be implemented in JS or as native helpers.
6. **Chromium / Browser Control**
* `chromium_run`, `chromium_create_profile`, `chromium_run_incognito`, `chromium_navigate`, `chromium_get_active_pages`, `chromium_find_page_by_id`, `chromium_find_pages_by_title`, `chromium_move_focused`, `chromium_adjust_window_size`, `chromium_get_element_position`, `chromium_get_mapreduced_element_position`, `chromium_set_value_to_textbox`, `chromium_send_click`, `chromium_send_keys`, `chromium_auto_scroll_until_end`
These test the ChromiumDevTools-related agent responsible for controlling a Chromium-based browser.
7. **gRPC & GUI Integration**
* gRPC: `grpc_run_server`, `grpc_receive_command`
* WebView: `gui_check`
These validate that **network service agents** (gRPC) and **GUI/WebView integration** work correctly in real environments.
---
### **9.3 Test Profile Schema**
A test profile JSON follows this general schema:
* **description**: Human-readable description of the profile
* **updated_on**: Last update date (string, e.g. `"2023-10-30"`)
* **dependencies**: Object listing required WelsonJS version or other requirements
* **authors**: Array of strings identifying authors
* **references**: Array of related URLs (repository, social, external descriptions)
* **tags**: Profile-wide tags (technologies, platforms, etc.)
* **schema**:
* `version`: Schema version used by `testloader.js` (e.g. `"0.2"`)
* **tests**:
* Array of test objects, each having:
* `id`: Unique test identifier (string)
* `description`: What the test checks (string)
* `tags`: Array of tags describing category and domain
Example (simplified):
```json
{
"description": "2023 South Korea OSS Contest Test Profile for WelsonJS",
"updated_on": "2023-10-30",
"dependencies": {
"welsonjs": "0.2.7"
},
"schema": {
"version": "0.2"
},
"tests": [
{
"id": "es5_polyfills",
"description": "Checks whether polyfills above the ES5 level run successfully (using Windows' built-in engine).",
"tags": ["JavaScript Engine", "ECMAScript Polyfills"]
}
]
}
```
> The exact semantics for how each `id` maps to a concrete script or implementation are defined in `testloader.js` and the surrounding WelsonJS test harness.
---
### **9.4 Using `testloader.js`**
`testloader.js` is the standard runner that:
1. Accepts one or more **profile JSON** paths (e.g., `test-oss-korea-2023.json`).
2. Parses the profile according to the schema version.
3. Iterates over `tests[]`, and for each `id`:
* Resolves the underlying implementation (JS file, bound function, etc.)
* Executes the test logic in the WSH + polyfill environment
* Captures success/failure and any diagnostic output
4. Produces a summary result (per test and overall).
When adding or modifying tests:
* Prefer **extending existing profiles** rather than inventing new formats.
* Keep `id` stable once published, so existing CI or documentation references do not break.
* Use `tags` to reflect which agent(s) a test touches (e.g., `"Windows Systems"`, `"Chromium-Based Browser"`, `"gRPC"`).
---
### **9.5 Naming & Organization**
Recommended file organization:
```text
/tests
test-oss-korea-2023.json # Contest profile (broad coverage)
... # Future profiles (e.g., cryptography-only, ESENT-only)
testloader.js
```
Guidelines:
* Use **profile-level tags** to describe the scope (`"windows"`, `"wsh"`, `"chromium"`, `"grpc"`, etc.).
* Keep large, real-world coverage (like the OSS contest profile) but also allow smaller focused profiles for specific agents (e.g., ESENT regression suite, Cryptography regression suite).
* For new features or agents, introduce corresponding `tests[]` entries with descriptive `id` and `description`, and appropriate `tags`.
---
### **9.6 Regression & Compatibility**
Because WelsonJS targets a wide range of Windows environments:
* Use the existing wide-coverage profile (like the OSS contest profile) as a **baseline regression suite**.
* When fixing a bug in any agent (e.g., ESENT, Chromium control, VHID input, HTTP stack):
* Add or update a test entry in a JSON profile.
* Ensure `testloader.js` can run it in automated environments.
* Keep compatibility in mind: if behavior must differ by OS version, reflect that in tests or tags (e.g., Windows XP vs Windows 10).
---
### **9.7 CI / Automation (Optional)**
If a CI pipeline is configured:
* Add a step that:
* Invokes `testloader.js` on one or more profiles
* Fails the build if any test in the profile fails
* Optionally support:
* Running a **quick subset** (e.g., only `es5_polyfills` + core system tests)
* Running the full OSS profile for release candidates or nightly builds

1
CNAME Normal file
View File

@ -0,0 +1 @@
welson.js.org

View File

@ -28,21 +28,18 @@ All types of contributions are encouraged and valued. See the [Table of Contents
## Code of Conduct ## Code of Conduct
This project and everyone participating in it is governed by the This project and everyone participating in it is governed by the [WelsonJS Code of Conduct](https://github.com/gnh1201/welsonjs/blob/master/CODE_OF_CONDUCT.md).
[WelsonJS Code of Conduct](https://github.com/gnh1201/welsonjs/blob/master/CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to <abuse@catswords.net>.
By participating, you are expected to uphold this code. Please report unacceptable behavior
to <abuse@catswords.net>.
## I Have a Question ## I Have a Question
> If you want to ask a question, we assume that you have read the available [Documentation](https://catswords.social/@catswords_oss). > If you want to ask a question, we assume that you have read the available [Documentation](https://catswords-oss.rdbl.io/5719744820/5330609327).
Before you ask a question, it is best to search for existing [Issues](https://github.com/gnh1201/welsonjs//issues) that might help you. In case you have found a suitable issue and still need clarification, you can write your question in this issue. It is also advisable to search the internet for answers first. Before you ask a question, it is best to search for existing [Issues](https://github.com/gnh1201/welsonjs/issues) that might help you. In case you have found a suitable issue and still need clarification, you can write your question in this issue. It is also advisable to search the internet for answers first.
If you then still feel the need to ask a question and need clarification, we recommend the following: If you then still feel the need to ask a question and need clarification, we recommend the following:
- Open an [Issue](https://github.com/gnh1201/welsonjs//issues/new). - Open an [Issue](https://github.com/gnh1201/welsonjs/issues/new).
- Provide as much context as you can about what you're running into. - Provide as much context as you can about what you're running into.
- Provide project and platform versions (nodejs, npm, etc), depending on what seems relevant. - Provide project and platform versions (nodejs, npm, etc), depending on what seems relevant.
@ -82,12 +79,12 @@ A good bug report shouldn't leave others needing to chase you up for more inform
<!-- omit in toc --> <!-- omit in toc -->
#### How Do I Submit a Good Bug Report? #### How Do I Submit a Good Bug Report?
> You must never report security related issues, vulnerabilities or bugs including sensitive information to the issue tracker, or elsewhere in public. Instead sensitive bugs must be sent by email to <abuse@catswords.net>. > You must never report security related issues, vulnerabilities or bugs including sensitive information to the issue tracker, or elsewhere in public. Instead sensitive bugs must be sent by email to <abuse@catswords.re.kr>.
<!-- You may add a PGP key to allow the messages to be sent encrypted as well. --> <!-- You may add a PGP key to allow the messages to be sent encrypted as well. -->
We use GitHub issues to track bugs and errors. If you run into an issue with the project: We use GitHub issues to track bugs and errors. If you run into an issue with the project:
- Open an [Issue](https://github.com/gnh1201/welsonjs//issues/new). (Since we can't be sure at this point whether it is a bug or not, we ask you not to talk about a bug yet and not to label the issue.) - Open an [Issue](https://github.com/gnh1201/welsonjs/issues/new). (Since we can't be sure at this point whether it is a bug or not, we ask you not to talk about a bug yet and not to label the issue.)
- Explain the behavior you would expect and the actual behavior. - Explain the behavior you would expect and the actual behavior.
- Please provide as much context as possible and describe the *reproduction steps* that someone else can follow to recreate the issue on their own. This usually includes your code. For good bug reports you should isolate the problem and create a reduced test case. - Please provide as much context as possible and describe the *reproduction steps* that someone else can follow to recreate the issue on their own. This usually includes your code. For good bug reports you should isolate the problem and create a reduced test case.
- Provide the information you collected in the previous section. - Provide the information you collected in the previous section.
@ -109,14 +106,14 @@ This section guides you through submitting an enhancement suggestion for WelsonJ
#### Before Submitting an Enhancement #### Before Submitting an Enhancement
- Make sure that you are using the latest version. - Make sure that you are using the latest version.
- Read the [documentation](https://catswords.social/@catswords_oss) carefully and find out if the functionality is already covered, maybe by an individual configuration. - Read the [documentation](https://catswords-oss.rdbl.io/5719744820/5330609327) carefully and find out if the functionality is already covered, maybe by an individual configuration.
- Perform a [search](https://github.com/gnh1201/welsonjs/issues) to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one. - Perform a [search](https://github.com/gnh1201/welsonjs/issues) to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one.
- Find out whether your idea fits with the scope and aims of the project. It's up to you to make a strong case to convince the project's developers of the merits of this feature. Keep in mind that we want features that will be useful to the majority of our users and not just a small subset. If you're just targeting a minority of users, consider writing an add-on/plugin library. - Find out whether your idea fits with the scope and aims of the project. It's up to you to make a strong case to convince the project's developers of the merits of this feature. Keep in mind that we want features that will be useful to the majority of our users and not just a small subset. If you're just targeting a minority of users, consider writing an add-on/plugin library.
<!-- omit in toc --> <!-- omit in toc -->
#### How Do I Submit a Good Enhancement Suggestion? #### How Do I Submit a Good Enhancement Suggestion?
Enhancement suggestions are tracked as [GitHub issues](https://github.com/gnh1201/welsonjs//issues). Enhancement suggestions are tracked as [GitHub issues](https://github.com/gnh1201/welsonjs/issues).
- Use a **clear and descriptive title** for the issue to identify the suggestion. - Use a **clear and descriptive title** for the issue to identify the suggestion.
- Provide a **step-by-step description of the suggested enhancement** in as many details as possible. - Provide a **step-by-step description of the suggested enhancement** in as many details as possible.
@ -141,7 +138,9 @@ Flexible. We will respect your style.
Contact us: Contact us:
* ActivityPub [@catswords_oss@catswords.social](https://catswords.social/@catswords_oss) * ActivityPub [@catswords_oss@catswords.social](https://catswords.social/@catswords_oss)
* abuse@catswords.net * XMPP [catswords@conference.omemo.id](xmpp:catswords@conference.omemo.id?join)
* [Join Catswords OSS on Microsoft Teams (teams.live.com)](https://teams.live.com/l/community/FEACHncAhq8ldnojAI)
* [Join Catswords OSS #welsonjs on Discord (discord.gg)](https://discord.gg/XKG5CjtXEj)
## Attribution ## Attribution
This guide is based on the **contributing-gen**. [Make your own](https://github.com/bttger/contributing-gen)! This guide is based on the **contributing-gen**. [Make your own](https://github.com/bttger/contributing-gen)!

View File

@ -1,5 +1,4 @@
Microsoft Reciprocal License (MS-RL) Microsoft Reciprocal License (Ms-RL)
SPDX Short identifier: MS-RL
This license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software. This license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software.
@ -29,35 +28,3 @@ A "contributor" is any person that distributes its contribution under this licen
(E) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license. (E) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license.
(F) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement. (F) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement.
Microsoft 상호 라이선스(MS-RL)
SPDX 짧은 식별자: MS-RL
이 라이센스는 함께 제공되는 소프트웨어의 사용에 적용됩니다. 소프트웨어를 사용하는 경우 이 라이센스에 동의하는 것입니다. 라이센스에 동의하지 않으면 소프트웨어를 사용하지 마십시오.
1. 정의
"복제", "복제물", "파생 저작물" 및 "배포"라는 용어는 여기에서 미국 저작권법과 동일한 의미를 갖습니다.
"기여"은 원본 소프트웨어 또는 소프트웨어에 대한 추가 또는 변경 사항입니다.
"기여자"는 이 라이선스에 따라 기여를 배포하는 모든 사람입니다.
"라이선스 지적재산권"은 기여에 대해 직접 읽는 기여자의 지적재산권 주장입니다.
2. 권리 부여
(A) 저작권 부여 - 섹션 3의 라이선스 조건 및 제한 사항을 포함하여 이 라이선스의 조건에 따라 각 기여자는 자신의 기여를 복제하고 파생 작업을 준비할 수 있는 비독점적이고 전세계적인 로열티 없는 저작권 라이선스를 부여합니다. 기여 및 귀하가 만든 기여 또는 파생 작업을 배포합니다.
(B) 지적재산권 부여 - 섹션 3의 라이선스 조건 및 제한 사항을 포함하여 이 라이선스의 조건에 따라 각 기여자는 라이선스가 부여된 지적재산권에 따라 귀하에게 비독점적이고 전 세계적으로 사용료가 없는 라이선스를 부여합니다. 여기에는 판매, 판매 제안, 수입 및 또는 소프트웨어에 대한 기여 또는 소프트웨어 기여의 파생물을 처분하는 행위를 포함합니다.
3. 조건 및 제한
(A) 상호 부여 - 소프트웨어의 코드(소스코드 또는 바이너리 형식)가 포함된 배포하는 모든 파일의 경우 해당 파일에 적용되는 라이선스의 사본과 함께 해당 파일의 소스코드를 수신자에게 제공해야 합니다. . 귀하는 전적으로 귀하의 저작물이며 귀하가 선택한 조건에 따라 소프트웨어의 코드를 포함하지 않는 다른 파일에 라이선스를 부여할 수 있습니다.
(B) 상표 사용권 없음 - 이 사용권은 기여자의 이름, 로고 또는 상표를 사용할 수 있는 권한을 부여하지 않습니다.
(C) 귀하가 소프트웨어에 의해 침해되었다고 주장하는 지적재산권에 대해 기여자에 대해 지적재산권 청구를 제기하는 경우 해당 기여자의 소프트웨어에 대한 귀하의 지적재산권 라이선스는 자동으로 종료됩니다.
(D) 소프트웨어의 일부를 배포하는 경우 소프트웨어에 있는 모든 저작권, 지적재산권, 상표 및 귀속 고지를 보유해야 합니다.
(E) 소프트웨어의 일부를 소스코드 형식으로 배포하는 경우 배포와 함께 이 라이센스의 전체 사본을 포함하여 이 라이센스 하에서만 그렇게 할 수 있습니다. 소프트웨어의 일부를 컴파일된 또는 개체 코드 형식으로 배포하는 경우 이 라이센스를 준수하는 라이센스 하에서만 배포할 수 있습니다.
(F) 소프트웨어는 "있는 그대로" 사용이 허가됩니다. 당신은 그것을 사용할 위험을 감수합니다. 기여자는 명시적 보증, 보증 또는 조건을 제공하지 않습니다. 귀하는 현지 법률에 따라 이 라이선스가 변경할 수 없는 추가적인 소비자 권리를 가질 수 있습니다. 현지 법률에서 허용하는 범위 내에서 기여자는 상품성, 특정 목적에의 적합성 및 비침해성에 대한 묵시적 보증을 배제합니다.

143
README.md
View File

@ -3,38 +3,40 @@
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fgnh1201%2Fwelsonjs.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fgnh1201%2Fwelsonjs?ref=badge_shield) [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fgnh1201%2Fwelsonjs.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fgnh1201%2Fwelsonjs?ref=badge_shield)
[![AppVeyor Status](https://ci.appveyor.com/api/projects/status/github/gnh1201/welsonjs?svg=true)](https://ci.appveyor.com/project/gnh1201/welsonjs) [![AppVeyor Status](https://ci.appveyor.com/api/projects/status/github/gnh1201/welsonjs?svg=true)](https://ci.appveyor.com/project/gnh1201/welsonjs)
[![DOI 10.5281/zenodo.11382384](https://zenodo.org/badge/DOI/10.5281/zenodo.11382384.svg)](https://doi.org/10.5281/zenodo.11382384) [![DOI 10.5281/zenodo.11382384](https://zenodo.org/badge/DOI/10.5281/zenodo.11382384.svg)](https://doi.org/10.5281/zenodo.11382384)
[![ChatGPT available](https://img.shields.io/badge/ChatGPT-74aa9c?logo=openai&logoColor=white)](https://catswords-oss.rdbl.io/5719744820/5510319392) [![ChatGPT available](https://img.shields.io/badge/ChatGPT-74aa9c?logo=openai&logoColor=white)](#)
[![Anthropic available](https://img.shields.io/badge/Anthropic-000000?logo=Anthropic&logoColor=white)](https://catswords-oss.rdbl.io/5719744820/5510319392) [![Google Gemini available](https://img.shields.io/badge/Gemini-886FBF?logo=googlegemini&logoColor=fff)](#)
[![Grok available](https://img.shields.io/badge/Grok-000000?logo=x&logoColor=white)](https://catswords-oss.rdbl.io/5719744820/5510319392)
[![Google Gemini available](https://img.shields.io/badge/Google%20Gemini-886FBF?logo=googlegemini&logoColor=fff)](https://catswords-oss.rdbl.io/5719744820/5510319392)
[![slideshare.net presentation](https://img.shields.io/badge/SlideShare-black?logo=slideshare)](https://www.slideshare.net/slideshow/welsonjs-javascript-framework-presentation-2024/276005486) [![slideshare.net presentation](https://img.shields.io/badge/SlideShare-black?logo=slideshare)](https://www.slideshare.net/slideshow/welsonjs-javascript-framework-presentation-2024/276005486)
[![YouTube promotion video](https://img.shields.io/badge/YouTube-red?logo=youtube)](https://youtu.be/JavH7Dms8-U) [![YouTube promotion video](https://img.shields.io/badge/YouTube-red?logo=youtube)](https://youtu.be/JavH7Dms8-U)
[![Discord chat](https://img.shields.io/discord/359930650330923008?logo=discord)](https://discord.gg/XKG5CjtXEj) [![Discord chat](https://img.shields.io/discord/359930650330923008?logo=discord)](https://discord.gg/XKG5CjtXEj)
[![Trustpilot](https://img.shields.io/badge/Trustpilot-00B67A?logo=trustpilot&logoColor=fff)](https://www.trustpilot.com/review/catswords.com)
[![Open to work](https://img.shields.io/badge/%23-OPENTOWORK-green)](https://github.com/gnh1201/welsonjs/discussions/167) [![Open to work](https://img.shields.io/badge/%23-OPENTOWORK-green)](https://github.com/gnh1201/welsonjs/discussions/167)
[![DeepWiki](https://img.shields.io/badge/DeepWiki-gnh1201%2Fwelsonjs-blue.svg?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAyCAYAAAAnWDnqAAAAAXNSR0IArs4c6QAAA05JREFUaEPtmUtyEzEQhtWTQyQLHNak2AB7ZnyXZMEjXMGeK/AIi+QuHrMnbChYY7MIh8g01fJoopFb0uhhEqqcbWTp06/uv1saEDv4O3n3dV60RfP947Mm9/SQc0ICFQgzfc4CYZoTPAswgSJCCUJUnAAoRHOAUOcATwbmVLWdGoH//PB8mnKqScAhsD0kYP3j/Yt5LPQe2KvcXmGvRHcDnpxfL2zOYJ1mFwrryWTz0advv1Ut4CJgf5uhDuDj5eUcAUoahrdY/56ebRWeraTjMt/00Sh3UDtjgHtQNHwcRGOC98BJEAEymycmYcWwOprTgcB6VZ5JK5TAJ+fXGLBm3FDAmn6oPPjR4rKCAoJCal2eAiQp2x0vxTPB3ALO2CRkwmDy5WohzBDwSEFKRwPbknEggCPB/imwrycgxX2NzoMCHhPkDwqYMr9tRcP5qNrMZHkVnOjRMWwLCcr8ohBVb1OMjxLwGCvjTikrsBOiA6fNyCrm8V1rP93iVPpwaE+gO0SsWmPiXB+jikdf6SizrT5qKasx5j8ABbHpFTx+vFXp9EnYQmLx02h1QTTrl6eDqxLnGjporxl3NL3agEvXdT0WmEost648sQOYAeJS9Q7bfUVoMGnjo4AZdUMQku50McDcMWcBPvr0SzbTAFDfvJqwLzgxwATnCgnp4wDl6Aa+Ax283gghmj+vj7feE2KBBRMW3FzOpLOADl0Isb5587h/U4gGvkt5v60Z1VLG8BhYjbzRwyQZemwAd6cCR5/XFWLYZRIMpX39AR0tjaGGiGzLVyhse5C9RKC6ai42ppWPKiBagOvaYk8lO7DajerabOZP46Lby5wKjw1HCRx7p9sVMOWGzb/vA1hwiWc6jm3MvQDTogQkiqIhJV0nBQBTU+3okKCFDy9WwferkHjtxib7t3xIUQtHxnIwtx4mpg26/HfwVNVDb4oI9RHmx5WGelRVlrtiw43zboCLaxv46AZeB3IlTkwouebTr1y2NjSpHz68WNFjHvupy3q8TFn3Hos2IAk4Ju5dCo8B3wP7VPr/FGaKiG+T+v+TQqIrOqMTL1VdWV1DdmcbO8KXBz6esmYWYKPwDL5b5FA1a0hwapHiom0r/cKaoqr+27/XcrS5UwSMbQAAAABJRU5ErkJggg==)](https://deepwiki.com/gnh1201/welsonjs)
<img src="app/assets/img/logo.svg" height="32" alt=""/> WelsonJS - Build a Windows app on the Windows built-in JavaScript engine. <img src="https://catswords.blob.core.windows.net/welsonjs/images/logo.svg" height="32" alt="WelsonJS logo with four diagonal stripes in red, green, blue, and yellow, overlaid with the letters JS."/> WelsonJS - Build a Windows app on the Windows built-in JavaScript engine.
![A Cover Image: Windows in 1999](https://ics.catswords.net/cover.png) ![A Cover Image: Windows in 1999](https://catswords.blob.core.windows.net/welsonjs/images/cover.png)
Now, You can build a Windows desktop app with JavaScript, TypeScript, CoffeeScript, ReScript, and HTML/CSS on Windows built-in ECMAScript engine. Now, You can build a Windows desktop app with JavaScript, TypeScript, CoffeeScript, ReScript, and HTML/CSS on Windows built-in ECMAScript engine.
WelsonJS = ***W***indows + ***El***ectr***on***-like + ***Javascript(JS)*** + :heart:[Contributions](https://github.com/sponsors/gnh1201) WelsonJS = ***W***indows + ***El***ectr***on***-like + ***Javascript(JS)*** + :heart:[Contributions](https://github.com/sponsors/gnh1201)
:kissing_cat: [Download Latest WelsonJS Launcher (ics.catswords.net)](https://ics.catswords.net/welsonjs_launcher_latest.zip) * :kissing_cat: [Download Latest WelsonJS Launcher (catswords.blob.core.windows.net)](https://catswords.blob.core.windows.net/welsonjs/welsonjs_launcher_latest.zip)
* :rocket: [Launch the WelsonJS environment on Microsoft Azure (azuremarketplace.microsoft.com)](https://azuremarketplace.microsoft.com/en-us/marketplace/apps/catswords.catswords-welsonjs-feb2025-02?tab=Overview)
**Note**: The default license for this project is GPL 3.0. However, if the GPL 3.0 license is not compatible with Microsoft products, it is subject to the MS-RL license. **Note**: The default license for this project is GPL 3.0. However, if the GPL 3.0 license is not compatible with Microsoft products, it is subject to the MS-RL license.
## Sponsors ## Sponsors
- :octocat: [GitHub Sponsors](https://github.com/sponsors/gnh1201) * :octocat: [GitHub Sponsors](https://github.com/sponsors/gnh1201), :coffee: [Buy me a coffee](https://buymeacoffee.com/catswords)
- <img src="https://ics.catswords.net/logo_oss.gif" height="32" alt=""/> [Open Software Portal](https://oss.kr), Korea National Industry Promotion Agency - Awarded Prize * <img src="https://catswords.blob.core.windows.net/welsonjs/images/serpapi_logo_32.png" height="32" alt=""/> [SerpApi: Search API](https://serpapi.com/?utm_source=welsonjs) - Scrape search engines results with simple API.
- <img src="https://ics.catswords.net/signpath_logo.png" height="32" alt=""/> Free code signing provided by [SignPath.io](https://signpath.io), certificate by [SignPath Foundation](https://signpath.org/) * <img src="https://catswords.blob.core.windows.net/welsonjs/images/logo_oss.gif" height="32" alt=""/> [Open SW Portal](https://oss.kr), NIPA National IT Industry Promotion Agency<sup>(정보통신산업진흥원)</sup>
- <img src="https://ics.catswords.net/f1security_logo.png" height="32" alt=""/> [F1Security](https://azuremarketplace.microsoft.com/ko-kr/marketplace/apps/1599123192819.uwss?tab=overview) provides web security services designed by [industry-leading experts](https://www.ksecurity.or.kr/kisis/subIndex/469.do). * <img src="https://catswords.blob.core.windows.net/welsonjs/images/signpath_logo.png" height="32" alt=""/> Free code signing provided by [SignPath.io](https://signpath.io), certificate by [SignPath Foundation](https://signpath.org/)
- <img src="https://ics.catswords.net/microsoft_logo.png" height="32" alt=""/> [Microsoft ISV Success Program](https://www.microsoft.com/en-us/isv/isv-success), Grow your business with powerful tools. * <img src="https://catswords.blob.core.windows.net/welsonjs/images/f1security_logo.png" height="32" alt=""/> [F1Security<sup>(에프원시큐리티)</sup>](https://f1security.co.kr/) provides [industry-leading](https://www.ksecurity.or.kr/kisis/subIndex/469.do) web security services.
- :zap: [Integrations](https://catswords-oss.rdbl.io/5719744820/8278298336) ([ScrapeOps](https://scrapeops.io?fpr=namhyeon75), [SearchApi](https://www.searchapi.io/?via=namhyeon), [AviationStack](https://aviationstack.com?utm_source=FirstPromoter&utm_medium=Affiliate&fpr=namhyeon71), [Coupang](https://link.coupang.com/a/b7HV3V)...) * <img src="https://catswords.blob.core.windows.net/welsonjs/images/microsoft_logo.png" height="32" alt=""/> [Microsoft ISV Success Program](https://www.microsoft.com/en-us/isv/isv-success), Grow your business with powerful tools.
* :zap: Integrations (e.g., Aviation, Shopping)...
## System Requirements ## System Requirements
- **Operating Systems**: Windows XP SP3 or later (Currently, Windows 11 24H2) * **Operating Systems**: Windows XP SP3 or later (Currently, Windows 11 24H2)
- For systems running Windows 2000 or earlier versions (e.g., 95, 98, Me), please contact us separately. * For systems running Windows 2000 or earlier versions (e.g., 95, 98, Me), please contact us separately.
## Why Choose WelsonJS? ## Why Choose WelsonJS?
WelsonJS is an advanced JavaScript framework designed to operate in extreme conditions where conventional solutions may fail. Unlike traditional JavaScript frameworks, WelsonJS focuses on executing scripts in constrained environments, ensuring reliable performance even with minimal system resources. WelsonJS is an advanced JavaScript framework designed to operate in extreme conditions where conventional solutions may fail. Unlike traditional JavaScript frameworks, WelsonJS focuses on executing scripts in constrained environments, ensuring reliable performance even with minimal system resources.
@ -59,23 +61,25 @@ WelsonJS is tailored for developers who need a reliable, lightweight JavaScript
![The structure of the WelsonJS framework can be extended based on whether it operates in a console (command prompt) environment, a GUI (with HTML/CSS) environment, or a service environment, with the `app.js` file at its core.](https://ics.catswords.net/structure.png) ![The structure of the WelsonJS framework can be extended based on whether it operates in a console (command prompt) environment, a GUI (with HTML/CSS) environment, or a service environment, with the `app.js` file at its core.](https://ics.catswords.net/structure.png)
## Specifications ## Specifications
- Built-in transpilers: [TypeScript](https://www.typescriptlang.org/), [Rescript](https://rescript-lang.org/), [CoffeeScript 2](https://coffeescript.org/), [LiveScript](https://livescript.net/) * Built-in transpilers: [TypeScript](https://www.typescriptlang.org/), [Rescript](https://rescript-lang.org/), [CoffeeScript 2](https://coffeescript.org/), [LiveScript](https://livescript.net/)
- **Ready to use on Windows machine immediately. No require additional software installation.** * **Ready to use on Windows machine immediately. No additional software installation is required.**
- **WelsonJS Launcher**: Instance management (You can manage previously run apps), User-defined variable editor (You can pass user-defined variables if needed), [Microsoft Monaco Editor](https://github.com/microsoft/monaco-editor) (You can edit code without installing an additional editor). * **WelsonJS Launcher**: Manage instances (Like a container), User-defined variable editor, [Microsoft Monaco Editor](https://github.com/microsoft/monaco-editor) and [React](https://react.dev/) (Pre-embedded rich code editor), [Microsoft Copilot](https://copilot.microsoft.com), and [Azure AI Services](https://azure.microsoft.com/en-us/products/ai-services), Network tools (Whois, DNS Query, [Criminal IP CTI](https://www.criminalip.io/)) on the code editor.
- ES5(ECMAScript 5), XML, JSON, YAML compatibility: [core-js](https://github.com/zloirock/core-js), [JSON2.js](https://github.com/douglascrockford/JSON-js), [js-yaml](https://github.com/nodeca/js-yaml) * ES5(ECMAScript 5), XML, JSON, YAML compatibility: [core-js](https://github.com/zloirock/core-js), [JSON2.js](https://github.com/douglascrockford/JSON-js), [js-yaml](https://github.com/nodeca/js-yaml)
- HTML5, CSS3 compatibility: [html5shiv](https://github.com/aFarkas/html5shiv), [jquery-html5-placeholder-shim](https://github.com/parndt/jquery-html5-placeholder-shim), [Respond](https://github.com/scottjehl/Respond), [selectivizr](https://github.com/keithclark/selectivizr), [ExplorerCanvas](https://github.com/arv/ExplorerCanvas), [Modernizr](https://github.com/Modernizr/Modernizr) * HTML5 compatibility on the built-in HTML rendering engine: [html5shiv](https://github.com/aFarkas/html5shiv), [jquery-html5-placeholder-shim](https://github.com/parndt/jquery-html5-placeholder-shim), [Respond](https://github.com/scottjehl/Respond), [selectivizr](https://github.com/keithclark/selectivizr), [ExplorerCanvas](https://github.com/arv/ExplorerCanvas), [Modernizr](https://github.com/Modernizr/Modernizr)
- Classical CSS Frameworks: [cascadeframework](https://github.com/jslegers/cascadeframework), [golden-layout](https://github.com/golden-layout/golden-layout) * Classical CSS Frameworks: [cascadeframework](https://github.com/jslegers/cascadeframework), [golden-layout](https://github.com/golden-layout/golden-layout)
- WYSIWYG HTML Editor: [summernote](https://github.com/summernote/summernote) * WYSIWYG HTML Editor: [summernote](https://github.com/summernote/summernote)
- Included libraries: [jQuery](https://jquery.com/), [jQuery UI](https://jqueryui.com/), [jquery-toast-plugin](https://github.com/kamranahmedse/jquery-toast-plugin), [squel](https://github.com/hiddentao/squel), [jsrender](https://github.com/BorisMoore/jsrender), [linq](https://github.com/mihaifm/linq), [pegjs](https://github.com/pegjs/pegjs), [numbers.js](https://github.com/numbers/numbers.js) * Included libraries: [jQuery](https://jquery.com/), [jQuery UI](https://jqueryui.com/), [jquery-toast-plugin](https://github.com/kamranahmedse/jquery-toast-plugin), [squel](https://github.com/hiddentao/squel), [jsrender](https://github.com/BorisMoore/jsrender), [linq](https://github.com/mihaifm/linq), [pegjs](https://github.com/pegjs/pegjs), [numbers.js](https://github.com/numbers/numbers.js)
- Compatible with modern JavaScript specifications: [module.exports](https://nodejs.org/api/modules.html#moduleexports), CommonJS, UMD compatibility, [NPM(Node Pacakge Manager)](https://www.npmjs.com/) compatibility * Compatible with modern JavaScript specifications: [module.exports](https://nodejs.org/api/modules.html#moduleexports), CommonJS, UMD compatibility, [NPM(Node Package Manager)](https://www.npmjs.com/) compatibility
- Support a device debugging protocol clients: [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/), [ADB(Android Debug Bridge)](https://source.android.com/docs/setup/build/adb) * Support a device debugging protocol clients: [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/), [ADB(Android Debug Bridge)](https://source.android.com/docs/setup/build/adb)
- RPC(Remote Procedure Call) protocol clients: [gRPC](https://grpc.io/), [JSON-RPC 2.0](https://www.jsonrpc.org/specification) * RPC(Remote Procedure Call) protocol clients: [gRPC](https://grpc.io/), [JSON-RPC 2.0](https://www.jsonrpc.org/specification)
- Various types of HTTP clients: [XHR(MSXML)](https://developer.mozilla.org/docs/Glossary/XMLHttpRequest), [cURL](https://curl.se/), [BITS](https://en.m.wikipedia.org/w/index.php?title=Background_Intelligent_Transfer_Service), [CERT](https://github.com/MicrosoftDocs/windowsserverdocs/blob/main/WindowsServerDocs/administration/windows-commands/certutil.md), [Web Proxy, SEO/SERP](https://catswords-oss.rdbl.io/5719744820/1706431912) * Various types of HTTP clients: [XHR(MSXML)](https://developer.mozilla.org/docs/Glossary/XMLHttpRequest), [cURL](https://curl.se/), [BITS](https://en.m.wikipedia.org/w/index.php?title=Background_Intelligent_Transfer_Service), [CERT](https://github.com/MicrosoftDocs/windowsserverdocs/blob/main/WindowsServerDocs/administration/windows-commands/certutil.md), Web Proxy, SEO/SERP
- The native toolkit for Windows environments: Write a Windows Service Application with JavaScript, Control a window handle, Cryptography (e.g., [ISO/IEC 18033-3:2010](https://www.iso.org/standard/54531.html) aka. [HIGHT](https://seed.kisa.or.kr/kisa/algorithm/EgovHightInfo.do)), [Named Shared Memory](https://learn.microsoft.com/en-us/windows/win32/memory/creating-named-shared-memory) based [IPC](https://qiita.com/gnh1201/items/4e70dccdb7adacf0ace5), [NuGet package](https://www.nuget.org/packages/WelsonJS.Toolkit) * The native toolkit for Windows environments: Write a Windows Service Application with JavaScript, Control a window handle, Cryptography (e.g., [ISO/IEC 18033-3:2010](https://www.iso.org/standard/54531.html) aka. [HIGHT](https://seed.kisa.or.kr/kisa/algorithm/EgovHightInfo.do)), [Named Shared Memory](https://learn.microsoft.com/en-us/windows/win32/memory/creating-named-shared-memory) based [IPC](https://qiita.com/gnh1201/items/4e70dccdb7adacf0ace5), [NuGet package](https://www.nuget.org/packages/WelsonJS.Toolkit)
- Generative AI integrations: [Multiple LLM and sLLM](https://catswords-oss.rdbl.io/5719744820/5510319392) (e.g., ChatGPT, Claude, ...) * AI integrations: LLM-based (generative) AI services (e.g., ChatGPT, Google Gemini).
- Aviation Data integrations: [AviationStack](https://aviationstack.com?utm_source=FirstPromoter&utm_medium=Affiliate&fpr=namhyeon71), [SearchApi Google Flight](https://www.searchapi.io/?via=namhyeon) * Aviation Data integrations: [AviationStack](https://aviationstack.com?utm_source=FirstPromoter&utm_medium=Affiliate&fpr=namhyeon71), [SerpApi Google Flights API](https://serpapi.com/google-flights-api?utm_source=welsonjs)
- VM infrastucture tool integrations: [OVFTool for Broadcom/VMware infrastructures](https://developer.broadcom.com/tools/open-virtualization-format-ovf-tool/latest) * OVFTool (VMware) integration: [OVFTool for Broadcom/VMware infrastructures](https://developer.broadcom.com/tools/open-virtualization-format-ovf-tool/latest)
- Everything you can imagine. * ***:fire: NEW!*** Windows built-in database engine AKA. [ESENT (ESE) database](https://learn.microsoft.com/en-us/windows/win32/extensible-storage-engine/database-overview) interface library (WelsonJS.Esent)
* ***:fire: NEW!*** WelsonJS JCTG(JavaScript-Click-To-Go): Run WelsonJS script files written in JavaScript directly from Windows File Explorer with a (double) click. Just like an `.exe` file.
* Everything you can imagine.
## Quick start ## Quick start
@ -89,7 +93,7 @@ function say() {
exports.say = say; exports.say = say;
exports.VERSIONINFO = "SayHello (sayhello.js) version 0.1"; exports.VERSIONINFO = "SayHello (sayhello.js) version 0.1";
exports.AUTHOR = "abuse@catswords.net"; exports.AUTHOR = "gnh1201@catswords.re.kr";
exports.global = global; exports.global = global;
exports.require = global.require; exports.require = global.require;
``` ```
@ -119,61 +123,60 @@ ended say()
## How to release my application? ## How to release my application?
The WelsonJS framework suggests the following application release methods: The WelsonJS framework suggests the following application release methods:
- **Compress to Zip, and use the launcher**: Compress the files and directories necessary for running the project into a Zip file, and distribute it along with the [WelsonJS Launcher](https://catswords-oss.rdbl.io/5719744820/4131485779). * **Compress to Zip, and use the launcher**: Compress the files and directories necessary for running the project into a Zip file, and distribute it along with the WelsonJS Launcher.
- **Build a setup file**: Use [Inno Setup](https://jrsoftware.org/isinfo.php). The setup profile (the `setup.iss` file) is already included. * **Build a setup file**: Use [Inno Setup](https://jrsoftware.org/isinfo.php). The setup profile (the `setup.iss` file) is already included.
- **Copy all directories and files**: This is the simplest and most straightforward method. * **Copy all directories and files**: This is the simplest and most straightforward method.
## Screenshots ## Screenshots
![(Screenshot 1) GUI environment](https://ics.catswords.net/screenshot.png) ![(Screenshot 1) GUI environment](https://catswords.blob.core.windows.net/welsonjs/images/screenshot.png)
![(Screenshot 2) Command-line environment](https://ics.catswords.net/screenshot2.png) ![(Screenshot 2) Command-line environment](https://catswords.blob.core.windows.net/welsonjs/images/screenshot2.png)
![(Screenshot 3) WelsonJS with Microsoft Excel](https://ics.catswords.net/screenshot3.png) ![(Screenshot 3) WelsonJS with Microsoft Excel](https://catswords.blob.core.windows.net/welsonjs/images/screenshot3.png)
![(Screenshot 4) Write a Windows Services with JavaScript](https://ics.catswords.net/screenshot4.png) ![(Screenshot 4) Write a Windows Service with JavaScript](https://catswords.blob.core.windows.net/welsonjs/images/screenshot4.png)
![(Screenshot 5) Template Matching on the computer screen](https://ics.catswords.net/screenshot5.png) ![(Screenshot 5) Template Matching on the computer screen](https://catswords.blob.core.windows.net/welsonjs/images/screenshot5.png)
![(Screenshot 6) The Launcher for WelsonJS Application Packages](https://ics.catswords.net/screenshot6.png) ![(Screenshot 6) The Launcher for WelsonJS Application Packages](https://catswords.blob.core.windows.net/welsonjs/images/screenshot6.png)
![(Screenshot 7) Microsoft Monaco Editor on WelsonJS Launcher](https://ics.catswords.net/screenshot7.png) ![(Screenshot 7) Microsoft Monaco Editor on WelsonJS Launcher](https://catswords.blob.core.windows.net/welsonjs/images/screenshot7.png)
![(Screenshot 8) You can run a .js file just like an executable by simply double-clicking it.](https://catswords.blob.core.windows.net/welsonjs/images/screenshot8.png)
## Thanks to ## Thanks to
- :heart: Artwork (Logo image): [@druidesse](https://github.com/druidesse) * :heart: Artwork (Logo image): [@druidesse](https://github.com/druidesse)
- :heart: Artwork (Cover image): [@_bag0@x.com](https://x.com/_bag0) * :heart: Artwork (Cover image): [@_bag0@x.com](https://x.com/_bag0)
- :sunglasses: Heavy-industry specialized CSP(Cloud Service Provider) in Republic of Korea - Use case establishment * :heart: Special Contributors: [@hcho3](https://github.com/hcho3), :octocat: [GitHub Sponsors](https://github.com/sponsors/gnh1201)
- :sunglasses: Live-commerce specialized online advertisement companies in Republic of Korea - Use case establishment * :sunglasses: Heavy-industry specialized CSP(Cloud Service Provider) in Republic of Korea - Use case development
- :sunglasses: Information security companies in Republic of Korea - Use case establishment * :sunglasses: Live-commerce specialized online advertisement companies in Republic of Korea - Use case development
- :eyes: [Facebook Group "Javascript Programming"(javascript4u)](https://www.facebook.com/javascript4u/posts/build-a-windows-desktop-apps-with-javascript-html-and-cssmorioh-javascript-html-/1484014618472735/) * :sunglasses: Information security companies in Republic of Korea - Use case development
- :eyes: [morioh.com](https://morioh.com/a/23c427a82bf1/build-a-windows-desktop-apps-with-javascript-html-and-css) * :sunglasses: Travel planning(e.g., Airlines, Hotels, Ticketing) related companies - Use case development
- :eyes: CSDN * :sunglasses: Probability-based game prediction in a data analytics company - Use case development
- :eyes: Qiita - Knowledge-base about WSH environment * :sunglasses: Qiita - Knowledge-base about WSH environment
- :sunglasses: Redsky Software - PoC(Proof of Concept) of the CommonJS on WSH environment * :sunglasses: Redsky Software - PoC(Proof of Concept) of the CommonJS on WSH environment
- :sunglasses: Inspired by a small-sized JavaScript payload demonstrated by a cybersecurity related group. * :sunglasses: Inspired by a small-sized JavaScript payload demonstrated by a cybersecurity related group.
- :sunglasses: Inspired by the use of Named Shared Memory in an inter-language IPC implementation devised by an unidentified developer. * :sunglasses: Inspired by the use of Named Shared Memory in a cross-runtime IPC implementation written by the unidentified developer.
- :eyes: Fediverse * :eyes: [Hacker News](https://news.ycombinator.com/item?id=41316782), [Node Weekly (#582 - June 17, 2025)](https://nodeweekly.com/issues/582), [WebToolsWeekly](https://webtoolsweekly.com/archives/issue-585/), [GeekNews in GeekNews Weekly (2024-09-30 ~ 2024-10-06)](https://news.hada.io/weekly/202441), [Facebook Group "Javascript Programming"(javascript4u)](https://www.facebook.com/javascript4u/posts/build-a-windows-desktop-apps-with-javascript-html-and-cssmorioh-javascript-html-/1484014618472735/), [morioh.com](https://morioh.com/a/23c427a82bf1/build-a-windows-desktop-apps-with-javascript-html-and-css), CSDN, Fediverse, [daily.dev](https://app.daily.dev/posts/js-libraries-svg-tools-json-databases-8quregz3a), [PitchHut](https://www.pitchhut.com/project/proj_Ya136OLSW5at), [Disquiet](https://dis.qa/nv6T6), [Zhouexin (周e信)](https://www.zhouexin.com/issues/321), [Echo JS](https://www.echojs.com/news/43008), [Telegram Channel @front_end_dev](https://t.me/front_end_dev/9376?ysclid=mgk4a9hqf0853890652)
- :eyes: [Hacker News](https://news.ycombinator.com/item?id=41316782)
- :eyes: [WebToolsWeekly](https://webtoolsweekly.com/archives/issue-585/)
- :eyes: [GeekNews](https://news.hada.io/weekly/202441) in GeekNews Weekly (2024-09-30 ~ 2024-10-06)
- :eyes: [daily.dev](https://app.daily.dev/posts/js-libraries-svg-tools-json-databases-8quregz3a)
- :eyes: [PitchHut](https://www.pitchhut.com/project/proj_Ya136OLSW5at)
- :eyes: [Disquiet](https://dis.qa/nv6T6)
## Report abuse ## Report abuse
- [GitHub Security Advisories (gnh1201/welsonjs)](https://github.com/gnh1201/welsonjs/security) * [GitHub Security Advisories (gnh1201/welsonjs)](https://github.com/gnh1201/welsonjs/security)
- abuse@catswords.net * [abuse@catswords.net](mailto:abuse@catswords.net)
## Join the community ## Join the community
I am always open. Collaboration, opportunities, and community activities are all welcome. I am always open. Collaboration, opportunities, and community activities are all welcome.
- ActivityPub [@catswords_oss@catswords.social](https://catswords.social/@catswords_oss) * ActivityPub [@catswords_oss@catswords.social](https://catswords.social/@catswords_oss)
- XMPP [catswords@conference.omemo.id](xmpp:catswords@conference.omemo.id?join) * XMPP [catswords@conference.omemo.id](xmpp:catswords@conference.omemo.id?join)
- [Join Catswords OSS on Microsoft Teams (teams.live.com)](https://teams.live.com/l/community/FEACHncAhq8ldnojAI) * [Join Catswords OSS on Microsoft Teams (teams.live.com)](https://teams.live.com/l/community/FEACHncAhq8ldnojAI)
- [Join Catswords OSS #welsonjs on Discord (discord.gg)](https://discord.gg/XKG5CjtXEj) * [Join Catswords OSS #welsonjs on Discord (discord.gg)](https://discord.gg/XKG5CjtXEj)
## Offline Distribution
You may [request offline distribution](https://forms.gle/4WCnJmnFNDzubUmk7) if you are in a restricted environment, such as one without internet access or with specific security requirements.
## Special channels ## Special channels
- [A paid consultation channel (m.expert.naver.com)](https://m.expert.naver.com/mobile/expert/product/detail?storeId=100051156&productId=100144540) is available for Korean (한국어) region. * [A paid consultation channel (m.expert.naver.com)](https://m.expert.naver.com/mobile/expert/product/detail?storeId=100051156&productId=100144540) is available for Korean<sup>(한국어)</sup> customers.
- [Join the private operations channel (forms.gle)](https://forms.gle/ZKAAaGTiGamksHoo8) is available for all regions. * [A paid mentorship program (inflearn.com)](https://mentoring.inflearn.com/mentors/5353) is available for Korean<sup>(한국어)</sup> students or beginners.
## License ## License
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fgnh1201%2Fwelsonjs.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fgnh1201%2Fwelsonjs?ref=badge_large) [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fgnh1201%2Fwelsonjs.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fgnh1201%2Fwelsonjs?ref=badge_large)

View File

@ -41,22 +41,28 @@ WelsonJS is a project inspired by the requirements of a cloud service provider t
## Alternative Names ## Alternative Names
This program is also known by the following names. These names are used solely for the purpose of identifying the work and do not impact the license: This program is also known by the following names. These names are used solely for the purpose of identifying the work and do not impact the license:
- DOI [10.5281/zenodo.11382384](https://zenodo.org/doi/10.5281/zenodo.11382384) (CERN/OpenAIRE Zenodo) * DOI [10.5281/zenodo.11382384](https://zenodo.org/doi/10.5281/zenodo.11382384)(2024) (CERN/OpenAIRE Zenodo)
- ["284757291"](https://ics.catswords.net/1494315-Certificate%2BSoR-284757291.pdf) (Registered with the [UK Copyright Service](https://copyrightservice.co.uk/)) * ["284757291"](https://catswords.blob.core.windows.net/welsonjs/images/1494315-Certificate+SoR-284757291.pdf)(2024) (Registered with the [UK Copyright Service](https://copyrightservice.co.uk/))
- ["A0562"](https://www.oss.kr/dev_competition_activities/show/544723e6-850a-4956-9194-79640420c19a)(2023) (2023 Open-source Development Contest, NIPA National IT Industry Promotion Agency, Republic of Korea) * ["A0562"](https://www.oss.kr/dev_competition_activities/show/544723e6-850a-4956-9194-79640420c19a)(2023) (2023 Open-source Development Contest, NIPA National IT Industry Promotion Agency<sup>(정보통신산업진흥원)</sup>, Republic of Korea)
- "C-2021-000237"(2021) (Copyright Registration Online System, Korea Copyright Commission, Republic of Korea) * ["2025-02-08-1952"](https://catswords.blob.core.windows.net/welsonjs/images/20250410092300005.pdf)(2025) (Technical Data Bailment System (Technology Escrow), "Korea Foundation for Cooperation of Large & Small Business, Rural Affairs"<sup>(대·중소기업·농어업협력재단)</sup>, Republic of Korea)
- "Codename Macadamia"(2020) (Heavy industry specialized CSP in the Republic of Korea) * "C-2021-000237"(2021) (Copyright Registration Online System, Korea Copyright Commission<sup>(한국저작권위원회)</sup>, Republic of Korea)
* "Codename Macadamia"(2020) (Heavy industry specialized CSP in the Republic of Korea)
## We use AI assistance in our development
This project may include code developed with the support of LLM-based AI services, including the paid version of [ChatGPT](https://chatgpt.com/), AI-powered code review tools such as [CodeRabbit](https://www.coderabbit.ai/), [Sourcery](https://sourcery.ai/), and [Qodo](https://www.qodo.ai/), as well as LLM models provided through [Microsoft Azure AI Foundry](https://ai.azure.com/).
## Offline Distribution
You may [request offline distribution](https://forms.gle/4WCnJmnFNDzubUmk7) if you are in a restricted environment, such as one without internet access or with specific security requirements.
## Report abuse ## Report abuse
- [GitHub Security Advisories](https://github.com/gnh1201/welsonjs/security) * [GitHub Security Advisories (gnh1201/welsonjs)](https://github.com/gnh1201/welsonjs/security)
- abuse@catswords.net * [abuse@catswords.re.kr](mailto:abuse@catswords.re.kr)
## Join the community ## Join the community
- ActivityPub [@catswords_oss@catswords.social](https://catswords.social/@catswords_oss) * ActivityPub [@catswords_oss@catswords.social](https://catswords.social/@catswords_oss)
- XMPP [catswords@conference.omemo.id](xmpp:catswords@conference.omemo.id?join) * XMPP [catswords@conference.omemo.id](xmpp:catswords@conference.omemo.id?join)
- [Join Catswords OSS on Microsoft Teams (teams.live.com)](https://teams.live.com/l/community/FEACHncAhq8ldnojAI) * [Join Catswords OSS on Microsoft Teams (teams.live.com)](https://teams.live.com/l/community/FEACHncAhq8ldnojAI)
- [Join Catswords OSS #welsonjs on Discord (discord.gg)](https://discord.gg/XKG5CjtXEj) * [Join Catswords OSS #welsonjs on Discord (discord.gg)](https://discord.gg/XKG5CjtXEj)
## Special channels ## Special channels
- [A paid consultation channel (m.expert.naver.com)](https://m.expert.naver.com/mobile/expert/product/detail?storeId=100051156&productId=100144540) is available for Korean (한국어) region. * [A paid consultation channel (m.expert.naver.com)](https://m.expert.naver.com/mobile/expert/product/detail?storeId=100051156&productId=100144540) is available for Korean<sup>(한국어)</sup> region.
- [Join the private operations channel (forms.gle)](https://forms.gle/ZKAAaGTiGamksHoo8) is available for all regions.

View File

@ -0,0 +1,720 @@
// AssemblyLoader.cs (Catswords.Phantomizer)
// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: Namhyeon Go <gnh1201@catswords.re.kr>, 2025 Catswords OSS and WelsonJS Contributors
// https://github.com/gnh1201/welsonjs
//
using System.Security.Cryptography;
using System.Text;
using System.Xml.Linq;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Runtime.InteropServices;
namespace Catswords.Phantomizer
{
/// <summary>
/// Network-aware loader for managed (.NET) and native (C/C++) binaries.
/// - Managed assemblies resolve via AssemblyResolve
/// - Native modules explicitly loaded via LoadNativeModules(...)
/// - All DLLs must have valid Authenticode signatures
/// - Cached at: %APPDATA%\Catswords\assembly\{Name}\{Version}\
/// - BaseUrl must be set by Main() before calling Register()
/// </summary>
public static class AssemblyLoader
{
/// <summary>
/// Base URL for downloading managed/native binaries.
/// Example: https://catswords.blob.core.windows.net/welsonjs/packages
/// Must be set before Register() or LoadNativeModules().
/// </summary>
public static string BaseUrl { get; set; } = null;
public static string LoaderNamespace { get; set; } = typeof(AssemblyLoader).Namespace;
public static string AppName { get; set; } = "Catswords";
public static string IntegrityUrl { get; set; } = null;
private static HashSet<string> _integrityHashes = null;
private static bool _integrityLoaded = false;
private static bool _registered;
private static readonly object AllowSchemesSyncRoot = new object();
private static readonly object IntegritySyncRoot = new object();
private static readonly object SyncRoot = new object();
private static readonly HashSet<string> _allowSchemes = new HashSet<string>(StringComparer.OrdinalIgnoreCase) {
Uri.UriSchemeHttps
};
private static readonly HttpClientHandler LegacyHttpHandler = new HttpClientHandler
{
AutomaticDecompression = DecompressionMethods.None
};
private static readonly HttpClientHandler HttpHandler = new HttpClientHandler
{
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
};
private static readonly HttpClient LegacyHttp = CreateClient(LegacyHttpHandler); // Does not send Accept-Encoding (gzip, deflate)
private static readonly HttpClient Http = CreateClient(HttpHandler); // Sends Accept-Encoding (gzip, deflate) and auto-decompresses
private static HttpClient CreateClient(HttpMessageHandler handler)
{
var client = new HttpClient(handler, disposeHandler: false)
{
Timeout = TimeSpan.FromSeconds(300) // 5 minutes
};
return client;
}
// -------------------- kernel32 native loading --------------------
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern IntPtr LoadLibrary(string lpFileName);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern bool SetDllDirectory(string lpPathName);
// -------------------- WinVerifyTrust (signature verification) --------------------
private const uint ERROR_SUCCESS = 0x00000000;
private const uint TRUST_E_NOSIGNATURE = 0x800B0100;
//private const uint TRUST_E_EXPLICIT_DISTRUST = 0x800B0111;
//private const uint TRUST_E_SUBJECT_NOT_TRUSTED = 0x800B0004;
//private const uint CRYPT_E_SECURITY_SETTINGS = 0x80092026;
private static readonly Guid WINTRUST_ACTION =
new Guid("00aac56b-cd44-11d0-8cc2-00c04fc295ee");
[DllImport("wintrust.dll", CharSet = CharSet.Unicode)]
private static extern uint WinVerifyTrust(
IntPtr hwnd,
[MarshalAs(UnmanagedType.LPStruct)] Guid pgActionID,
ref WINTRUST_DATA pWVTData);
private enum FileSignatureStatus { Valid, NoSignature, Invalid }
// -------------------- WinTrust Structures --------------------
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct WINTRUST_FILE_INFO
{
public uint cbStruct;
[MarshalAs(UnmanagedType.LPWStr)] public string pcwszFilePath;
public IntPtr hFile;
public IntPtr pgKnownSubject;
public WINTRUST_FILE_INFO(string filePath)
{
cbStruct = (uint)Marshal.SizeOf(typeof(WINTRUST_FILE_INFO));
pcwszFilePath = filePath;
hFile = IntPtr.Zero;
pgKnownSubject = IntPtr.Zero;
}
}
private enum WinTrustDataUIChoice : uint { None = 2 }
private enum WinTrustDataRevocationChecks : uint { None = 0 }
private enum WinTrustDataChoice : uint { File = 1 }
private enum WinTrustDataStateAction : uint { Ignore = 0 }
private enum WinTrustDataUIContext : uint { Execute = 0 }
[Flags]
private enum WinTrustDataProvFlags : uint
{
RevocationCheckNone = 0x00000010,
DisableMD2andMD4 = 0x00002000
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct WINTRUST_DATA
{
public uint cbStruct;
public IntPtr pPolicyCallbackData;
public IntPtr pSIPClientData;
public WinTrustDataUIChoice dwUIChoice;
public WinTrustDataRevocationChecks dwRevocationChecks;
public WinTrustDataChoice dwUnionChoice;
public IntPtr pFile;
public WinTrustDataStateAction dwStateAction;
public IntPtr hWVTStateData;
public string pwszURLReference;
public WinTrustDataProvFlags dwProvFlags;
public WinTrustDataUIContext dwUIContext;
public WINTRUST_DATA(IntPtr pFileInfo)
{
cbStruct = (uint)Marshal.SizeOf(typeof(WINTRUST_DATA));
pPolicyCallbackData = IntPtr.Zero;
pSIPClientData = IntPtr.Zero;
dwUIChoice = WinTrustDataUIChoice.None;
dwRevocationChecks = WinTrustDataRevocationChecks.None;
dwUnionChoice = WinTrustDataChoice.File;
pFile = pFileInfo;
dwStateAction = WinTrustDataStateAction.Ignore;
hWVTStateData = IntPtr.Zero;
pwszURLReference = null;
dwProvFlags = WinTrustDataProvFlags.RevocationCheckNone |
WinTrustDataProvFlags.DisableMD2andMD4;
dwUIContext = WinTrustDataUIContext.Execute;
}
}
// ========================================================================
// PUBLIC API
// ========================================================================
/// <summary>
/// Registers AssemblyResolve to download and validate .NET assemblies.
/// </summary>
public static void Register()
{
lock (SyncRoot)
{
if (_registered)
return;
try
{
if (!_integrityLoaded)
LoadIntegrityManifest();
if (string.IsNullOrWhiteSpace(BaseUrl))
throw new InvalidOperationException("BaseUrl must be configured before Register().");
TryVerifyUrl(BaseUrl, out bool verified);
if (!verified)
throw new InvalidOperationException("BaseUrl verification failed.");
}
catch (Exception ex)
{
Trace.TraceError("AssemblyLoader: failed to initialize: {0}", ex.Message);
throw;
}
AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve;
_registered = true;
Trace.TraceInformation("AssemblyLoader: AssemblyResolve handler registered.");
}
}
/// <summary>
/// Loads native modules associated with an assembly (explicit).
/// </summary>
public static void LoadNativeModules(string ownerAssemblyName, Version version, IList<string> fileNames)
{
TryVerifyUrl(BaseUrl, out bool verified);
if (!verified)
throw new InvalidOperationException("BaseUrl verification failed.");
if (ownerAssemblyName == null) throw new ArgumentNullException("ownerAssemblyName");
if (version == null) throw new ArgumentNullException("version");
if (fileNames == null) throw new ArgumentNullException("fileNames");
string versionString = version.ToString();
lock (SyncRoot)
{
string appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
string cacheDir = Path.Combine(appData, AppName, "assembly", ownerAssemblyName, versionString);
Directory.CreateDirectory(cacheDir);
try
{
if (!SetDllDirectory(cacheDir))
Trace.TraceWarning("SetDllDirectory failed for: {0}", cacheDir);
}
catch (Exception ex)
{
Trace.TraceWarning("SetDllDirectory threw exception: {0}", ex.Message);
}
foreach (string raw in fileNames)
{
if (string.IsNullOrWhiteSpace(raw))
continue;
string fileName = raw.Trim();
string localPath = Path.Combine(cacheDir, fileName);
if (!File.Exists(localPath))
{
string url = $"{BaseUrl.TrimEnd('/')}/native/{ownerAssemblyName}/{versionString}/{fileName}";
DownloadFile(url, localPath);
Trace.TraceInformation("Downloaded native module: {0}", fileName);
}
else
{
Trace.TraceInformation("Using cached native module: {0}", localPath);
}
EnsureIntegrityOrThrow(localPath);
EnsureSignedFileOrThrow(localPath, fileName);
IntPtr h = LoadLibrary(localPath);
if (h == IntPtr.Zero)
{
int errorCode = Marshal.GetLastWin32Error();
Trace.TraceError("LoadLibrary failed for {0} with error code {1}", localPath, errorCode);
throw new InvalidOperationException($"Failed to load native module: {fileName} (error: {errorCode})");
}
else
{
Trace.TraceInformation("Loaded native module: {0}", fileName);
}
}
}
}
/// <summary>
/// Adds an allowed URI scheme for assembly and module loading.
/// Only HTTP and HTTPS schemes are supported. HTTPS is the default.
/// Adding HTTP reduces security and will log a warning.
/// </summary>
/// <param name="scheme">The URI scheme to allow (e.g., "http" or "https"). Trailing colons are automatically removed.</param>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="scheme"/> is null or whitespace.</exception>
/// <exception cref="ArgumentException">Thrown when the scheme is invalid or not HTTP/HTTPS.</exception>
/// <remarks>
/// This method is thread-safe and can be called before Register() or LoadNativeModules().
/// </remarks>
public static void AddAllowedUriScheme(string scheme)
{
if (string.IsNullOrWhiteSpace(scheme))
throw new ArgumentNullException(nameof(scheme));
int colonIndex = scheme.IndexOf(':');
if (colonIndex > -1)
scheme = scheme.Substring(0, colonIndex);
scheme = scheme.ToLowerInvariant();
if (!Uri.CheckSchemeName(scheme))
throw new ArgumentException("Invalid URI scheme name.", nameof(scheme));
if (!scheme.Equals(Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase) &&
!scheme.Equals(Uri.UriSchemeHttp, StringComparison.OrdinalIgnoreCase))
throw new ArgumentException("Only HTTPS or HTTP schemes are supported.", nameof(scheme));
if (scheme.Equals(Uri.UriSchemeHttp, StringComparison.OrdinalIgnoreCase))
Trace.TraceWarning("Warning: Adding 'http' to allowed URI schemes reduces security.");
lock (AllowSchemesSyncRoot)
{
_allowSchemes.Add(scheme);
}
}
public static void LoadNativeModules(Assembly asm, IList<string> fileNames)
{
if (asm == null)
throw new ArgumentNullException(nameof(asm));
if (fileNames == null)
throw new ArgumentNullException(nameof(fileNames));
AssemblyName an = asm.GetName();
if (an == null)
throw new InvalidOperationException("Assembly.GetName() returned null.");
if (an.Name == null || an.Version == null)
throw new InvalidOperationException("Assembly name or version is missing.");
LoadNativeModules(an.Name, an.Version, fileNames);
}
// ========================================================================
// ASSEMBLY RESOLVE HANDLER (MANAGED)
// ========================================================================
private static Assembly OnAssemblyResolve(object sender, ResolveEventArgs args)
{
Trace.TraceInformation("AssemblyResolve: {0}", args.Name);
AssemblyName req = new AssemblyName(args.Name);
string simpleName = req.Name;
if (IsFrameworkAssembly(simpleName))
return null;
var entry = Assembly.GetEntryAssembly();
if (entry != null)
{
var entryName = entry.GetName().Name;
if (string.Equals(simpleName, entryName, StringComparison.OrdinalIgnoreCase))
{
Trace.TraceInformation("AssemblyResolve: skipping entry assembly {0}", simpleName);
return null;
}
}
Version version = req.Version ?? new Version(0, 0, 0, 0);
string versionStr = version.ToString();
lock (SyncRoot)
{
string appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
string cacheDir = Path.Combine(appData, AppName, "assembly", simpleName, versionStr);
string dllPath = Path.Combine(cacheDir, simpleName + ".dll");
Directory.CreateDirectory(cacheDir);
if (!File.Exists(dllPath))
{
string url = $"{BaseUrl.TrimEnd('/')}/managed/{simpleName}/{versionStr}/{simpleName}.dll";
DownloadFile(url, dllPath);
Trace.TraceInformation("Downloaded managed assembly: {0}", simpleName);
}
else
{
Trace.TraceInformation("Using cached managed assembly: {0}", dllPath);
}
if (!File.Exists(dllPath))
{
Trace.TraceWarning("AssemblyResolve: managed assembly not found after download attempt: {0}", simpleName);
return null;
}
EnsureIntegrityOrThrow(dllPath);
EnsureSignedFileOrThrow(dllPath, simpleName);
return Assembly.LoadFrom(dllPath);
}
}
// ========================================================================
// HELPERS
// ========================================================================
private static void DownloadFile(string url, string dest)
{
HttpResponseMessage res = null;
try
{
string gzUrl = url + ".gz";
bool isDll = url.EndsWith(".dll", StringComparison.OrdinalIgnoreCase); // *.dll.gz
bool downloaded = false;
if (isDll && TryDownloadCompressedFile(gzUrl, dest))
{
Trace.TraceInformation("Downloaded and decompressed file to: {0}", dest);
downloaded = true;
}
if (!downloaded)
{
Trace.TraceInformation("Downloading file from: {0}", url);
res = Http.GetAsync(url).GetAwaiter().GetResult();
res.EnsureSuccessStatusCode();
using (Stream s = res.Content.ReadAsStreamAsync().GetAwaiter().GetResult())
using (var fs = new FileStream(dest, FileMode.Create, FileAccess.Write))
{
s.CopyTo(fs);
}
Trace.TraceInformation("Downloaded file to: {0}", dest);
}
if (!File.Exists(dest))
{
throw new FileNotFoundException("File not found after download", dest);
}
}
catch (HttpRequestException ex)
{
Trace.TraceError("Network or I/O error downloading {0}: {1}", url, ex.Message);
throw;
}
catch (Exception ex)
{
Trace.TraceError("Unexpected error downloading {0}: {1}", url, ex.Message);
throw;
}
finally
{
res?.Dispose();
}
}
private static bool TryDownloadCompressedFile(string gzUrl, string dest)
{
string tempFile = dest + ".tmp";
try
{
using (var res = LegacyHttp.GetAsync(gzUrl).GetAwaiter().GetResult())
{
if (res.StatusCode == HttpStatusCode.NotFound)
{
Trace.TraceInformation("No gzipped variant at {0}; falling back to uncompressed URL.", gzUrl);
return false;
}
res.EnsureSuccessStatusCode();
using (Stream s = res.Content.ReadAsStreamAsync().GetAwaiter().GetResult())
using (var gz = new GZipStream(s, CompressionMode.Decompress))
using (var fs = new FileStream(tempFile, FileMode.Create, FileAccess.Write))
{
gz.CopyTo(fs);
}
if (File.Exists(dest))
File.Delete(dest);
File.Move(tempFile, dest);
return true;
}
}
catch (HttpRequestException ex)
{
Trace.TraceWarning("Network or I/O error downloading compressed file from {0}: {1}", gzUrl, ex.Message);
throw;
}
catch (Exception ex)
{
Trace.TraceError("Unexpected error downloading compressed file from {0}: {1}", gzUrl, ex.Message);
throw;
}
finally
{
if (File.Exists(tempFile))
{
try
{
File.Delete(tempFile);
}
catch (Exception ex)
{
Trace.TraceInformation("Failed to delete temporary file {0}: {1}", tempFile, ex.Message);
}
}
}
}
private static bool IsFrameworkAssembly(string name)
{
return name.StartsWith("System.", StringComparison.OrdinalIgnoreCase) ||
name.StartsWith("Microsoft.", StringComparison.OrdinalIgnoreCase) ||
name == "mscorlib" ||
name == "netstandard" ||
name == "WindowsBase" ||
name == "PresentationCore" ||
name == "PresentationFramework" ||
name.StartsWith($"{LoaderNamespace}.", StringComparison.OrdinalIgnoreCase);
}
private static void LoadIntegrityManifest()
{
lock (IntegritySyncRoot)
{
if (_integrityLoaded)
return;
_integrityHashes = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
if (string.IsNullOrWhiteSpace(IntegrityUrl))
{
_integrityLoaded = true;
return; // integrity disabled
}
XDocument doc;
try
{
TryVerifyUrl(IntegrityUrl, out bool verified);
if (!verified)
throw new InvalidOperationException("IntegrityUrl verification failed.");
using (var res = Http.GetAsync(IntegrityUrl).GetAwaiter().GetResult())
{
res.EnsureSuccessStatusCode();
using (var stream = res.Content.ReadAsStreamAsync().GetAwaiter().GetResult())
{
doc = XDocument.Load(stream);
}
}
}
catch (Exception ex)
{
Trace.TraceError("AssemblyIntegrity: failed to load manifest: {0}", ex.Message);
throw new InvalidOperationException("Failed to load AssemblyIntegrity manifest.", ex);
}
XElement hashes = doc.Root?.Element("Hashes");
if (hashes == null)
{
Trace.TraceWarning("AssemblyIntegrity: <Hashes> not found. Integrity disabled.");
_integrityLoaded = true;
return;
}
foreach (var h in hashes.Elements("Hash"))
{
var algorithm = h.Attribute("algorithm")?.Value?.Trim();
if (!string.Equals(algorithm, "SHA256", StringComparison.OrdinalIgnoreCase))
continue; // only SHA256 supported
string val = h.Attribute("value")?.Value?.Trim();
if (string.IsNullOrWhiteSpace(val))
continue;
_integrityHashes.Add(val);
}
_integrityLoaded = true;
Trace.TraceInformation("AssemblyIntegrity: loaded {0} allowed hashes.", _integrityHashes.Count);
}
}
private static void EnsureSignedFileOrThrow(string path, string logicalName)
{
if (!File.Exists(path))
{
Trace.TraceError("File does not exist for signature verification: {0}", logicalName);
throw new FileNotFoundException("File not found for signature verification: " + logicalName, path);
}
FileSignatureStatus status = VerifySignature(path);
if (status == FileSignatureStatus.Valid)
{
Trace.TraceInformation("Signature OK: {0}", logicalName);
return;
}
if (status == FileSignatureStatus.NoSignature)
{
Trace.TraceError("BLOCKED unsigned binary: {0}", logicalName);
throw new InvalidOperationException("Unsigned binary blocked: " + logicalName);
}
Trace.TraceError("BLOCKED invalid signature: {0}", logicalName);
throw new InvalidOperationException("Invalid signature: " + logicalName);
}
private static void EnsureIntegrityOrThrow(string path)
{
if (string.IsNullOrWhiteSpace(IntegrityUrl))
return; // disabled
if (_integrityHashes == null || _integrityHashes.Count == 0)
{
Trace.TraceWarning("AssemblyIntegrity: no hashes loaded → skipping check.");
return;
}
byte[] bytes = File.ReadAllBytes(path);
// Compute hashes
string sha256 = ComputeHashHex(bytes, SHA256.Create());
// Check match
if (_integrityHashes.Contains(sha256))
{
Trace.TraceInformation("AssemblyIntegrity: hash OK for {0}", Path.GetFileName(path));
return;
}
Trace.TraceError("AssemblyIntegrity: hash mismatch! SHA256={0}", sha256);
// Delete corrupted file so the next run can re-download a clean copy.
if (File.Exists(path))
{
try
{
File.Delete(path);
Trace.TraceInformation("AssemblyIntegrity: deleted corrupted file {0}", path);
}
catch (Exception ex)
{
Trace.TraceWarning("AssemblyIntegrity: failed to delete corrupted file {0}: {1}", path, ex.Message);
}
}
throw new InvalidOperationException("AssemblyIntegrity check failed for: " + path);
}
private static FileSignatureStatus VerifySignature(string file)
{
WINTRUST_FILE_INFO fileInfo = new WINTRUST_FILE_INFO(file);
IntPtr pFile = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(WINTRUST_FILE_INFO)));
Marshal.StructureToPtr(fileInfo, pFile, false);
WINTRUST_DATA data = new WINTRUST_DATA(pFile);
uint result = WinVerifyTrust(IntPtr.Zero, WINTRUST_ACTION, ref data);
Marshal.FreeCoTaskMem(pFile);
if (result == ERROR_SUCCESS) return FileSignatureStatus.Valid;
if (result == TRUST_E_NOSIGNATURE) return FileSignatureStatus.NoSignature;
return FileSignatureStatus.Invalid;
}
private static string ComputeHashHex(byte[] data, HashAlgorithm algorithm)
{
using (algorithm)
{
var hash = algorithm.ComputeHash(data);
var sb = new StringBuilder(hash.Length * 2);
foreach (var b in hash)
sb.Append(b.ToString("x2"));
return sb.ToString();
}
}
private static bool IsValidUriScheme(Uri uri)
{
if (uri == null)
return false;
lock (AllowSchemesSyncRoot)
{
return _allowSchemes.Contains(uri.Scheme);
}
}
private static void TryVerifyUrl(string url, out bool verified)
{
try
{
if (string.IsNullOrWhiteSpace(url))
throw new InvalidOperationException("URL is null or empty.");
if (Uri.TryCreate(url, UriKind.Absolute, out Uri uri))
{
if (!IsValidUriScheme(uri))
throw new InvalidOperationException(
$"URI scheme '{uri.Scheme}' is not allowed. Use AddAllowedUriScheme() to permit additional schemes.");
}
else
{
throw new InvalidOperationException("Not a valid absolute URI.");
}
verified = true;
}
catch (Exception ex)
{
Trace.TraceError("URL verification failed for {0}: {1}", url, ex.Message);
verified = false;
}
}
}
}

View File

@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<Company>Catswords Research</Company>
<Authors>Namhyeon Go, 2025 Catswords OSS and WelsonJS Contributors</Authors>
<PackageProjectUrl>https://github.com/gnh1201/welsonjs</PackageProjectUrl>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/gnh1201/welsonjs</RepositoryUrl>
<PackageTags>loader</PackageTags>
<Description>Catswords.Phantomizer is an HTTP-based dynamic-link library (DLL) loader designed for .NET applications. It allows your application to fetch and load assemblies directly from your CDN (Azure Blob, S3, Cloudflare R2, etc.) at runtime, with optional GZip compression support.</Description>
<Copyright>Namhyeon Go, 2025 Catswords OSS and WelsonJS Contributors</Copyright>
<Version>1.0.0.2</Version>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) Namhyeon Go <gnh1201@catswords.re.kr>, 2025 Catswords OSS and WelsonJS Contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,197 @@
# Catswords.Phantomizer
**Catswords.Phantomizer** is an HTTP-based dynamic-link library (DLL) loader designed for .NET applications.
It allows your application to fetch and load assemblies directly from your CDN (Azure Blob, S3, Cloudflare R2, etc.) at runtime, with optional GZip compression support.
![Catswords.Phantomizer Structure Overview](https://catswords.blob.core.windows.net/welsonjs/images/phantomizer_cover.png)
---
## 🚀 Features
* Load managed (`*.dll`) and native (`*.dll`) assemblies over **HTTPS only**
* Optional `.dll.gz` decompression for faster network delivery
* CDN-friendly URL structure
* Easy bootstrap through a small embedded loader
* Loader is implemented using **pure .NET BCL only** without external dependencies (.NET Fx/Core fully supported)
* Built-in **code-signing verification** support to ensure assemblies are trusted and tamper-free
* An efficient integrity verification process based on an integrity manifest (NFT-grade immutability)
---
## 📦 How to Use
### 1. Embed Phantomizer into your project
You can include **Catswords.Phantomizer** in your project using one of the following methods:
| Method | Description | When to Use | Setup Steps |
|-------|-------------|--------------|-------------|
| **Resources.resx Embedded File** | Stores `Catswords.Phantomizer.dll.gz` inside `Resources.resx` and loads it at runtime. | Recommended when you want the loader fully self-contained inside your executable. | Add file to `Resources.resx` → Access via `Properties.Resources.Phantomizer`. |
| **Embedded Resource** | Embeds `Catswords.Phantomizer.dll.gz` directly into the assembly manifest (outside of `resx`). | Useful when you prefer not to maintain `.resx` files but still want Phantomizer embedded. | Add file to project → Set *Build Action* = `Embedded Resource` → Load via `GetManifestResourceStream()`. |
| **Normal Assembly Reference (no embedding)** | References `Catswords.Phantomizer.dll` normally through project references. | Use this when you distribute Phantomizer as a standalone DLL instead of embedding it. | Add Phantomizer DLL to your project references → `using Catswords.Phantomizer;`. |
---
### 2. Initialize Phantomizer at application startup
Place the following code inside your `Main` method, static constructor, or any early entry point:
```csharp
static Program() {
InitializeAssemblyLoader();
}
private static void InitializeAssemblyLoader()
{
/*
// Example for Embedded Resource:
var asm = Assembly.GetExecutingAssembly();
using (var stream = asm.GetManifestResourceStream(typeof(Program).Namespace + ".Resources.Catswords.Phantomizer.dll.gz"))
{
// decompress and load...
}
*/
byte[] gzBytes = Properties.Resources.Phantomizer;
byte[] dllBytes;
using (var input = new MemoryStream(gzBytes))
using (var gz = new GZipStream(input, CompressionMode.Decompress))
using (var output = new MemoryStream())
{
gz.CopyTo(output);
dllBytes = output.ToArray();
}
Assembly phantomAsm = Assembly.Load(dllBytes);
Type loaderType = phantomAsm.GetType("Catswords.Phantomizer.AssemblyLoader", true);
loaderType.GetProperty("BaseUrl")?.SetValue(null, GetAppConfig("AssemblyBaseUrl")); // Set the CDN base URL
//loaderType.GetProperty("IntegrityUrl")?.SetValue(null, GetAppConfig("IntegrityUrl")); // (Optional) Set the integrity URL
loaderType.GetProperty("LoaderNamespace")?.SetValue(null, typeof(Program).Namespace);
loaderType.GetProperty("AppName")?.SetValue(null, "WelsonJS"); // Application name
//loaderType.GetMethod("AddAllowedUriScheme")?.Invoke(null, new object[] { Uri.UriSchemeHttp }); // (Optional) Allow insecure HTTP (not recommended)
loaderType.GetMethod("Register")?.Invoke(null, null);
var loadNativeModulesMethod = loaderType.GetMethod(
"LoadNativeModules",
BindingFlags.Public | BindingFlags.Static,
binder: null,
types: new[] { typeof(string), typeof(Version), typeof(string[]) },
modifiers: null
);
if (loadNativeModulesMethod == null)
throw new InvalidOperationException("LoadNativeModules(string, Version, string[]) method not found.");
loadNativeModulesMethod.Invoke(null, new object[]
{
"ChakraCore",
new Version(1, 13, 0, 0),
new[] { "ChakraCore.dll" }
});
}
```
If embedding is not required, you can reference Phantomizer directly:
```csharp
using Catswords.Phantomizer;
static void Main(string[] args)
{
AssemblyLoader.BaseUrl = GetAppConfig("AssemblyBaseUrl"); // Configure CDN base URL
//AssemblyLoader.IntegrityUrl = GetAppConfig("AssemblyIntegrityUrl"); // (Optional) Set the integrity URL
AssemblyLoader.LoaderNamespace = typeof(Program).Namespace;
AssemblyLoader.AppName = "WelsonJS";
//AssemblyLoader.AddAllowedUriScheme(Uri.UriSchemeHttp); // (Optional) Allow insecure HTTP (not recommended)
AssemblyLoader.Register();
AssemblyLoader.LoadNativeModules(
"ChakraCore",
new Version(1, 13, 0, 0),
new[] { "ChakraCore.dll" }
);
}
```
---
### 3. Upload your DLL files to a CDN
Upload your managed and native assemblies to your CDN following the URL pattern below.
#### 📁 URL Rules
| Type | Example URL | Description |
| ------------------ | ----------------------------------------------------------------------------------- | ------------------------------- |
| Managed DLL | `https://example.cdn.tld/packages/managed/MyManagedLib/1.0.0.0/MyManagedLib.dll` | Normal .NET assembly |
| Managed DLL (GZip) | `https://example.cdn.tld/packages/managed/MyManagedLib/1.0.0.0/MyManagedLib.dll.gz` | GZip-compressed .NET assembly |
| Native DLL | `https://example.cdn.tld/packages/native/MyNativeLib/1.0.0.0/MyNativeLib.dll` | Native assembly |
| Native DLL (GZip) | `https://example.cdn.tld/packages/native/MyNativeLib/1.0.0.0/MyNativeLib.dll.gz` | GZip-compressed native assembly |
---
### 4. 🎉 Start loading assemblies over HTTP
Once Phantomizer is initialized, your application will automatically fetch missing assemblies from your CDN.
---
## 🛡 Integrity Manifest (Integrity URL)
Phantomizer can verify assemblies before loading them by downloading an integrity manifest (XML).
You can host this integrity file anywhere — **preferably separate from your main CDN**, to prevent tampering and ensure independent verification of assembly integrity.
### 🔒 Why separate Integrity URL and main CDN?
Separating them prevents a compromised CDN bucket from serving malicious DLLs **and falsifying the integrity file**. Phantomizer can **trust the integrity manifest**, even if the main CDN is partially compromised.
### ✔ Recommended: Filebase (IPFS-pinning, NFT-grade immutability)
Filebase provides **immutable IPFS-based storage**, which is widely used in blockchain ecosystems — including **NFT metadata storage** — due to its strong guarantees of *content-addressing* and *tamper resistance*.
Once uploaded and pinned, the file cannot be silently modified without changing its IPFS hash (CID), making it ideal for hosting integrity manifests.
👉 **Recommended signup (with pinning support):** [Filebase](https://console.filebase.com/signup?ref=d44f5cc9cff7)
### ✔ Integrity Manifest Example (from `integrity.xml`)
```xml
<AssemblyIntegrity schemaVersion="1" generatedAt="2025-12-10T00:00:00Z">
<Hashes>
<Hash
value="5e274b47fc60c74159b4d1e21e70c0edf8e0936bdabc46b632525d09ca2fbae8"
algorithm="SHA256"
assemblyName="ChakraCore"
assemblyType="native"
version="1.13.0.0"
platform="x86"
compression="none"
fileName="ChakraCore.dll" />
<!-- ... more entries ... -->
</Hashes>
</AssemblyIntegrity>
```
---
## 📥 Download the pre-compiled file
* [Download Catswords.Phantomizer.dll.gz (catswords.blob.core.windows.net)](https://catswords.blob.core.windows.net/welsonjs/packages/managed/Catswords.Phantomizer/1.0.0.1/Catswords.Phantomizer.dll.gz)
---
## Report abuse
* [GitHub Security Advisories (gnh1201/welsonjs)](https://github.com/gnh1201/welsonjs/security)
* [abuse@catswords.re.kr](mailto:abuse@catswords.re.kr)
## Join the community
I am always open. Collaboration, opportunities, and community activities are all welcome.
* ActivityPub [@catswords_oss@catswords.social](https://catswords.social/@catswords_oss)
* XMPP [catswords@conference.omemo.id](xmpp:catswords@conference.omemo.id?join)
* [Join Catswords OSS on Microsoft Teams (teams.live.com)](https://teams.live.com/l/community/FEACHncAhq8ldnojAI)
* [Join Catswords OSS #welsonjs on Discord (discord.gg)](https://discord.gg/XKG5CjtXEj)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,64 @@
//-----------------------------------------------------------------------
// <copyright file="ApiConstants.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
/// <summary>
/// Constants for the ESENT API. These don't have to be looked up via
/// system parameters.
/// </summary>
public static partial class SystemParameters
{
/// <summary>
/// The length of the prefix used to name files used by the database
/// engine.
/// </summary>
public const int BaseNameLength = 3;
/// <summary>
/// Maximum size of a table/column/index name.
/// </summary>
public const int NameMost = 64;
/// <summary>
/// Maximum size for columns which are not JET_coltyp.LongBinary
/// or JET_coltyp.LongText.
/// </summary>
public const int ColumnMost = 255;
/// <summary>
/// Maximum number of columns allowed in a table.
/// </summary>
public const int ColumnsMost = 65248;
/// <summary>
/// Maximum number of fixed columns allowed in a table.
/// </summary>
public const int ColumnsFixedMost = 127;
/// <summary>
/// Maximum number of variable-length columns allowed
/// in a table.
/// </summary>
public const int ColumnsVarMost = 128;
/// <summary>
/// Maximum number of tagged columns allowed in a table.
/// </summary>
public const int ColumnsTaggedMost = 64993;
/// <summary>
/// The number of pages that gives the smallest possible
/// temporary database.
/// </summary>
public const int PageTempDBSmallest = 14;
/// <summary>
/// The maximum length of a locale name (LOCALE_NAME_MAX_LENGTH from winnt.h).
/// </summary>
public const int LocaleNameMaxLength = 85;
}
}

View File

@ -0,0 +1,96 @@
//-----------------------------------------------------------------------
// <copyright file="BoolColumnValue.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
using System.Diagnostics;
/// <summary>
/// A <see cref="bool"/> column value.
/// </summary>
public class BoolColumnValue : ColumnValueOfStruct<bool>
{
/// <summary>
/// A boxed true value that can be used by ValueAsObject.
/// </summary>
private static readonly object BoxedTrue = true;
/// <summary>
/// A boxed false value that can be used by ValueAsObject.
/// </summary>
private static readonly object BoxedFalse = false;
/// <summary>
/// Gets the last set or retrieved value of the column. The
/// value is returned as a generic object.
/// </summary>
public override object ValueAsObject
{
get
{
if (!this.Value.HasValue)
{
return null;
}
return this.Value.Value ? BoxedTrue : BoxedFalse;
}
}
/// <summary>
/// Gets the size of the value in the column. This returns 0 for
/// variable sized columns (i.e. binary and string).
/// </summary>
protected override int Size
{
[DebuggerStepThrough]
get { return sizeof(bool); }
}
/// <summary>
/// Recursive SetColumns method for data pinning. This populates the buffer and
/// calls the inherited SetColumns method.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">
/// The table to set the columns in. An update should be prepared.
/// </param>
/// <param name="columnValues">
/// Column values to set.
/// </param>
/// <param name="nativeColumns">
/// Structures to put the pinned data in.
/// </param>
/// <param name="i">Offset of this object in the array.</param>
/// <returns>An error code.</returns>
internal override unsafe int SetColumns(JET_SESID sesid, JET_TABLEID tableid, ColumnValue[] columnValues, NATIVE_SETCOLUMN* nativeColumns, int i)
{
byte data = this.Value.GetValueOrDefault() ? (byte)0xFF : (byte)0x00;
return this.SetColumns(sesid, tableid, columnValues, nativeColumns, i, &data, sizeof(byte), this.Value.HasValue);
}
/// <summary>
/// Given data retrieved from ESENT, decode the data and set the value in the ColumnValue object.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within the bytes.</param>
/// <param name="count">The number of bytes to decode.</param>
/// <param name="err">The error returned from ESENT.</param>
protected override void GetValueFromBytes(byte[] value, int startIndex, int count, int err)
{
if (JET_wrn.ColumnNull == (JET_wrn)err)
{
this.Value = null;
}
else
{
this.CheckDataCount(count);
this.Value = BitConverter.ToBoolean(value, startIndex);
}
}
}
}

View File

@ -0,0 +1,51 @@
//-----------------------------------------------------------------------
// <copyright file="BoxedValueCache.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
/// <summary>
/// A cache for boxed values.
/// </summary>
/// <typeparam name="T">The type of object to cache.</typeparam>
internal static class BoxedValueCache<T> where T : struct, IEquatable<T>
{
/// <summary>
/// Number of boxed values to cache.
/// </summary>
private const int NumCachedBoxedValues = 257;
/// <summary>
/// Cached boxed values.
/// </summary>
private static readonly object[] BoxedValues = new object[NumCachedBoxedValues];
/// <summary>
/// Gets a boxed version of the value. A cached copy is used if possible.
/// </summary>
/// <param name="value">The value to box.</param>
/// <returns>A boxed version of the value.</returns>
public static object GetBoxedValue(T? value)
{
if (!value.HasValue)
{
return null;
}
T valueToBox = value.Value;
int index = (valueToBox.GetHashCode() & 0x7fffffff) % NumCachedBoxedValues;
object boxedValue = BoxedValues[index];
if (null == boxedValue || !((T)boxedValue).Equals(valueToBox))
{
boxedValue = valueToBox;
BoxedValues[index] = boxedValue;
}
return boxedValue;
}
}
}

View File

@ -0,0 +1,68 @@
//-----------------------------------------------------------------------
// <copyright file="ByteColumnValue.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System.Diagnostics;
/// <summary>
/// A <see cref="byte"/> column value.
/// </summary>
public class ByteColumnValue : ColumnValueOfStruct<byte>
{
/// <summary>
/// Gets the size of the value in the column. This returns 0 for
/// variable sized columns (i.e. binary and string).
/// </summary>
protected override int Size
{
[DebuggerStepThrough]
get { return sizeof(byte); }
}
/// <summary>
/// Recursive SetColumns method for data pinning. This populates the buffer and
/// calls the inherited SetColumns method.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">
/// The table to set the columns in. An update should be prepared.
/// </param>
/// <param name="columnValues">
/// Column values to set.
/// </param>
/// <param name="nativeColumns">
/// Structures to put the pinned data in.
/// </param>
/// <param name="i">Offset of this object in the array.</param>
/// <returns>An error code.</returns>
internal override unsafe int SetColumns(JET_SESID sesid, JET_TABLEID tableid, ColumnValue[] columnValues, NATIVE_SETCOLUMN* nativeColumns, int i)
{
var data = this.Value.GetValueOrDefault();
return this.SetColumns(sesid, tableid, columnValues, nativeColumns, i, &data, sizeof(byte), this.Value.HasValue);
}
/// <summary>
/// Given data retrieved from ESENT, decode the data and set the value in the ColumnValue object.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within the bytes.</param>
/// <param name="count">The number of bytes to decode.</param>
/// <param name="err">The error returned from ESENT.</param>
protected override void GetValueFromBytes(byte[] value, int startIndex, int count, int err)
{
if (JET_wrn.ColumnNull == (JET_wrn)err)
{
this.Value = null;
}
else
{
this.CheckDataCount(count);
this.Value = value[startIndex];
}
}
}
}

View File

@ -0,0 +1,136 @@
//-----------------------------------------------------------------------
// <copyright file="BytesColumnValue.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
using System.Diagnostics;
/// <summary>
/// A byte array column value.
/// </summary>
public class BytesColumnValue : ColumnValue
{
/// <summary>
/// Internal value.
/// </summary>
private byte[] internalValue;
/// <summary>
/// Gets the last set or retrieved value of the column. The
/// value is returned as a generic object.
/// </summary>
public override object ValueAsObject
{
[DebuggerStepThrough]
get { return this.Value; }
}
/// <summary>
/// Gets or sets the value of the column. Use <see cref="Api.SetColumns"/> to update a
/// record with the column value.
/// </summary>
public byte[] Value
{
get
{
return this.internalValue;
}
set
{
this.internalValue = value;
this.Error = value == null ? JET_wrn.ColumnNull : JET_wrn.Success;
}
}
/// <summary>
/// Gets the byte length of a column value, which is zero if column is null, otherwise
/// matches the actual length of the byte array.
/// </summary>
public override int Length
{
get { return this.Value != null ? this.Value.Length : 0; }
}
/// <summary>
/// Gets the size of the value in the column. This returns 0 for
/// variable sized columns (i.e. binary and string).
/// </summary>
protected override int Size
{
[DebuggerStepThrough]
get { return 0; }
}
/// <summary>
/// Returns a <see cref="T:System.String"/> that represents the current <see cref="BytesColumnValue"/>.
/// </summary>
/// <returns>
/// A <see cref="T:System.String"/> that represents the current <see cref="BytesColumnValue"/>.
/// </returns>
public override string ToString()
{
if (null == this.Value)
{
return string.Empty;
}
return BitConverter.ToString(this.Value, 0, Math.Min(this.Value.Length, 16));
}
/// <summary>
/// Recursive SetColumns method for data pinning. This populates the buffer and
/// calls the inherited SetColumns method.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">
/// The table to set the columns in. An update should be prepared.
/// </param>
/// <param name="columnValues">
/// Column values to set.
/// </param>
/// <param name="nativeColumns">
/// Structures to put the pinned data in.
/// </param>
/// <param name="i">Offset of this object in the array.</param>
/// <returns>An error code.</returns>
internal override unsafe int SetColumns(JET_SESID sesid, JET_TABLEID tableid, ColumnValue[] columnValues, NATIVE_SETCOLUMN* nativeColumns, int i)
{
if (null != this.Value)
{
fixed (void* buffer = this.Value)
{
return this.SetColumns(
sesid, tableid, columnValues, nativeColumns, i, buffer, this.Value.Length, true);
}
}
return this.SetColumns(sesid, tableid, columnValues, nativeColumns, i, null, 0, false);
}
/// <summary>
/// Given data retrieved from ESENT, decode the data and set the value in the ColumnValue object.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within the bytes.</param>
/// <param name="count">The number of bytes to decode.</param>
/// <param name="err">The error returned from ESENT.</param>
protected override void GetValueFromBytes(byte[] value, int startIndex, int count, int err)
{
if (JET_wrn.ColumnNull == (JET_wrn)err)
{
this.Value = null;
}
else
{
var copiedValue = new byte[count];
Buffer.BlockCopy(value, startIndex, copiedValue, 0, count);
this.Value = copiedValue;
}
}
}
}

View File

@ -0,0 +1,79 @@
//-----------------------------------------------------------------------
// <copyright file="Caches.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System.Diagnostics;
/// <summary>
/// Static class containing MemoryCaches for different ESENT buffers.
/// Use these to avoid memory allocations when the memory will be
/// used for a brief time.
/// </summary>
internal static class Caches
{
/// <summary>
/// The maximum key size that any version of ESENT can have for
/// any page size. This is also the maximum bookmark size.
/// </summary>
private const int KeyMostMost = 2000;
/// <summary>
/// Reserve 1 extra space for keys made with prefix or wildcard.
/// </summary>
private const int LimitKeyMostMost = KeyMostMost + 1;
/// <summary>
/// The maximum number of buffers we want in a cache.
/// </summary>
private const int MaxBuffers = 16;
/// <summary>
/// Cached buffers for columns.
/// </summary>
private static readonly MemoryCache TheColumnCache = new MemoryCache(128 * 1024, MaxBuffers);
/// <summary>
/// Cached buffers for keys and bookmarks.
/// </summary>
private static readonly MemoryCache TheBookmarkCache = new MemoryCache(LimitKeyMostMost, MaxBuffers);
/// <summary>
/// Cached buffers for keys and bookmarks.
/// </summary>
private static readonly MemoryCache TheSecondaryBookmarkCache = new MemoryCache(LimitKeyMostMost, MaxBuffers);
/// <summary>
/// Gets the cached buffers for columns.
/// </summary>
public static MemoryCache ColumnCache
{
[DebuggerStepThrough]
get { return TheColumnCache; }
}
/// <summary>
/// Gets the cached buffers for keys and bookmarks.
/// </summary>
public static MemoryCache BookmarkCache
{
[DebuggerStepThrough]
get { return TheBookmarkCache; }
}
/// <summary>
/// Gets the cached buffers for keys and secondary bookmarks.
/// </summary>
public static MemoryCache SecondaryBookmarkCache
{
[DebuggerStepThrough]
get
{
return TheSecondaryBookmarkCache;
}
}
}
}

View File

@ -0,0 +1,98 @@
//-----------------------------------------------------------------------
// <copyright file="CallbackWrappers.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System.Collections.Generic;
/// <summary>
/// <para>
/// A collection of wrapped callbacks. This is used when the wrapped callback
/// can be garbage collected. The wrappers should be removed from the collection
/// when the callback is collected.
/// </para>
/// <para>
/// Removing the wrappers can lead to crashes. In this case we trust
/// the client code to keep its callback alive until ESENT doesn't need it any
/// more. Once the wrapped callback is garbage collected we allow the wrapper
/// to be collected as well. If ESENT subsequently uses the callback there will
/// be a crash.
/// </para>
/// <para>
/// The reason this is hard to deal with is that the lifetime of a JET_CALLBACK
/// isn't very clear. Table callbacks can stick around until the table meta-data
/// is purged, while a JetDefragment callback can be used until defrag ends. On
/// the other hand, keeping the callback wrapper alive indefinitely would lead
/// to unbounded memory use.
/// </para>
/// </summary>
internal sealed class CallbackWrappers
{
/// <summary>
/// Used to synchronize access to this object.
/// </summary>
private readonly object lockObject = new object();
/// <summary>
/// A list of the wrapped callbacks.
/// </summary>
private readonly List<JetCallbackWrapper> callbackWrappers = new List<JetCallbackWrapper>();
/// <summary>
/// Wrap a callback and returns its wrapper. If the callback is
/// already wrapped then the existing wrapper is returned.
/// </summary>
/// <param name="callback">The callback to add.</param>
/// <returns>The callback wrapper for the callback.</returns>
public JetCallbackWrapper Add(JET_CALLBACK callback)
{
lock (this.lockObject)
{
JetCallbackWrapper wrapper;
if (!this.TryFindWrapperFor(callback, out wrapper))
{
wrapper = new JetCallbackWrapper(callback);
this.callbackWrappers.Add(wrapper);
}
return wrapper;
}
}
/// <summary>
/// Go through the collection of callback wrappers and remove any dead callbacks.
/// </summary>
public void Collect()
{
lock (this.lockObject)
{
this.callbackWrappers.RemoveAll(wrapper => !wrapper.IsAlive);
}
}
/// <summary>
/// Look in the list of callback wrappers to see if there is already an entry for
/// this callback.
/// </summary>
/// <param name="callback">The callback to look for.</param>
/// <param name="wrapper">Returns the wrapper, if found.</param>
/// <returns>True if a wrapper was found, false otherwise.</returns>
private bool TryFindWrapperFor(JET_CALLBACK callback, out JetCallbackWrapper wrapper)
{
foreach (JetCallbackWrapper w in this.callbackWrappers)
{
if (w.IsWrapping(callback))
{
wrapper = w;
return true;
}
}
wrapper = null;
return false;
}
}
}

View File

@ -0,0 +1,101 @@
//-----------------------------------------------------------------------
// <copyright file="ColumnInfo.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
/// <summary>
/// Information about one Esent column. This is not an interop
/// class, but is used by the meta-data helper methods.
/// </summary>
public sealed class ColumnInfo
{
/// <summary>
/// The default value of the column.
/// </summary>
private readonly ReadOnlyCollection<byte> defaultValue;
/// <summary>
/// Initializes a new instance of the ColumnInfo class.
/// </summary>
/// <param name="name">Name of the column.</param>
/// <param name="columnid">ID of the column.</param>
/// <param name="coltyp">Type of the column.</param>
/// <param name="cp">Codepage of the column.</param>
/// <param name="maxLength">Maximum length of the column.</param>
/// <param name="defaultValue">Column default value.</param>
/// <param name="grbit">Column option.</param>
internal ColumnInfo(
string name,
JET_COLUMNID columnid,
JET_coltyp coltyp,
JET_CP cp,
int maxLength,
byte[] defaultValue,
ColumndefGrbit grbit)
{
this.Name = name;
this.Columnid = columnid;
this.Coltyp = coltyp;
this.Cp = cp;
this.MaxLength = maxLength;
this.defaultValue = (null == defaultValue) ? null : new ReadOnlyCollection<byte>(defaultValue);
this.Grbit = grbit;
}
/// <summary>
/// Gets the name of the column.
/// </summary>
public string Name { get; private set; }
/// <summary>
/// Gets the ID of the column.
/// </summary>
public JET_COLUMNID Columnid { get; private set; }
/// <summary>
/// Gets the type of the column.
/// </summary>
public JET_coltyp Coltyp { get; private set; }
/// <summary>
/// Gets the code page of the column.
/// </summary>
public JET_CP Cp { get; private set; }
/// <summary>
/// Gets the maximum length of the column.
/// </summary>
public int MaxLength { get; private set; }
/// <summary>
/// Gets the default value of the column.
/// </summary>
public IList<byte> DefaultValue
{
get { return this.defaultValue; }
}
/// <summary>
/// Gets the column options.
/// </summary>
public ColumndefGrbit Grbit { get; private set; }
/// <summary>
/// Returns a <see cref="T:System.String"/> that represents the current <see cref="ColumnInfo"/>.
/// </summary>
/// <returns>
/// A <see cref="T:System.String"/> that represents the current <see cref="ColumnInfo"/>.
/// </returns>
public override string ToString()
{
return this.Name;
}
}
}

View File

@ -0,0 +1,78 @@
//-----------------------------------------------------------------------
// <copyright file="ColumnInfoEnumerator.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System.Text;
using Microsoft.Isam.Esent.Interop.Implementation;
/// <summary>
/// Base class for enumerators that return ColumnInfo objects. Subclasses differ
/// by how they open the table.
/// </summary>
internal abstract class ColumnInfoEnumerator : TableEnumerator<ColumnInfo>
{
/// <summary>
/// Initializes a new instance of the <see cref="ColumnInfoEnumerator"/> class.
/// </summary>
/// <param name="sesid">
/// The session to use.
/// </param>
protected ColumnInfoEnumerator(JET_SESID sesid) : base(sesid)
{
}
/// <summary>
/// Gets or sets the columnlist used to retrieve data.
/// </summary>
protected JET_COLUMNLIST Columnlist { get; set; }
/// <summary>
/// Gets the entry the cursor is currently positioned on.
/// </summary>
/// <returns>The entry the cursor is currently positioned on.</returns>
protected override ColumnInfo GetCurrent()
{
return GetColumnInfoFromColumnlist(this.Sesid, this.Columnlist);
}
/// <summary>
/// Create a ColumnInfo object from the data in the current JET_COLUMNLIST entry.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="columnlist">The columnlist to take the data from.</param>
/// <returns>A ColumnInfo object containing the information from that record.</returns>
private static ColumnInfo GetColumnInfoFromColumnlist(JET_SESID sesid, JET_COLUMNLIST columnlist)
{
// As of Sep 2015, JetGetColumnInfoW is only called for Win8+. Even though Unicode should have
// worked in Win7, it wasn't reliable until Win8.
Encoding encodingOfTextColumns = EsentVersion.SupportsWindows8Features ? Encoding.Unicode : LibraryHelpers.EncodingASCII;
string name = Api.RetrieveColumnAsString(
sesid,
columnlist.tableid,
columnlist.columnidcolumnname,
encodingOfTextColumns,
RetrieveColumnGrbit.None);
name = StringCache.TryToIntern(name);
var columnidValue = (uint)Api.RetrieveColumnAsUInt32(sesid, columnlist.tableid, columnlist.columnidcolumnid);
var coltypValue = (uint)Api.RetrieveColumnAsUInt32(sesid, columnlist.tableid, columnlist.columnidcoltyp);
uint codepageValue = (ushort)Api.RetrieveColumnAsUInt16(sesid, columnlist.tableid, columnlist.columnidCp);
var maxLength = (uint)Api.RetrieveColumnAsUInt32(sesid, columnlist.tableid, columnlist.columnidcbMax);
byte[] defaultValue = Api.RetrieveColumn(sesid, columnlist.tableid, columnlist.columnidDefault);
var grbitValue = (uint)Api.RetrieveColumnAsUInt32(sesid, columnlist.tableid, columnlist.columnidgrbit);
return new ColumnInfo(
name,
new JET_COLUMNID { Value = columnidValue },
(JET_coltyp)coltypValue,
(JET_CP)codepageValue,
unchecked((int)maxLength),
defaultValue,
(ColumndefGrbit)grbitValue);
}
}
}

View File

@ -0,0 +1,357 @@
//-----------------------------------------------------------------------
// <copyright file="ColumnStream.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
/// <summary>
/// This class provides a streaming interface to a long-value column
/// (i.e. a column of type <see cref="JET_coltyp.LongBinary"/> or
/// <see cref="JET_coltyp.LongText"/>).
/// </summary>
[SuppressMessage("Microsoft.StyleCop.CSharp.NamingRules",
"SA1305:FieldNamesMustNotUseHungarianNotation",
Justification = "This should match the unmanaged API, which isn't capitalized.")]
public class ColumnStream : Stream
{
/// <summary>
/// The size of the biggest long-value column ESENT supports.
/// </summary>
private const int MaxLongValueSize = 0x7fffffff;
/// <summary>
/// Session to use.
/// </summary>
private readonly JET_SESID sesid;
/// <summary>
/// Cursor to use.
/// </summary>
private readonly JET_TABLEID tableid;
/// <summary>
/// Columnid to use.
/// </summary>
private readonly JET_COLUMNID columnid;
/// <summary>
/// Current LV offset.
/// </summary>
private int ibLongValue;
/// <summary>
/// Initializes a new instance of the ColumnStream class.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to use.</param>
/// <param name="columnid">The columnid of the column to set/retrieve data from.</param>
public ColumnStream(JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid)
{
// In some cases we rely on Int32 arithmetic overflow checking to catch
// errors, which assumes that a long-value can store Int32.MaxValue bytes.
Debug.Assert(MaxLongValueSize == int.MaxValue, "Expected maximum long value size to be Int32.MaxValue");
this.sesid = sesid;
this.tableid = tableid;
this.columnid = columnid;
this.Itag = 1;
}
/// <summary>
/// Gets or sets the itag of the column.
/// </summary>
public int Itag { get; set; }
/// <summary>
/// Gets a value indicating whether the stream supports reading.
/// </summary>
public override bool CanRead
{
[DebuggerStepThrough]
get { return true; }
}
/// <summary>
/// Gets a value indicating whether the stream supports writing.
/// </summary>
public override bool CanWrite
{
[DebuggerStepThrough]
get { return true; }
}
/// <summary>
/// Gets a value indicating whether the stream supports seeking.
/// </summary>
public override bool CanSeek
{
[DebuggerStepThrough]
get { return true; }
}
/// <summary>
/// Gets or sets the current position in the stream.
/// </summary>
public override long Position
{
[DebuggerStepThrough]
get
{
return this.ibLongValue;
}
set
{
if (value < 0 || value > MaxLongValueSize)
{
throw new ArgumentOutOfRangeException("value", value, "A long-value offset has to be between 0 and 0x7fffffff bytes");
}
this.ibLongValue = checked((int)value);
}
}
/// <summary>
/// Gets the current length of the stream.
/// </summary>
public override long Length
{
get
{
int size;
var retinfo = new JET_RETINFO { itagSequence = this.Itag, ibLongValue = 0 };
Api.JetRetrieveColumn(this.sesid, this.tableid, this.columnid, null, 0, out size, RetrieveGrbit, retinfo);
return size;
}
}
/// <summary>
/// Gets the options that should be used with JetRetrieveColumn.
/// </summary>
private static RetrieveColumnGrbit RetrieveGrbit
{
[DebuggerStepThrough]
get
{
// Always use the RetrieveCopy options. This makes the ColumnStream work
// well when setting a column. If we don't always use RetrieveCopy then
// things like seeking from the end of a column might not work properly.
return RetrieveColumnGrbit.RetrieveCopy;
}
}
/// <summary>
/// Returns a <see cref="T:System.String"/> that represents the current <see cref="ColumnStream"/>.
/// </summary>
/// <returns>
/// A <see cref="T:System.String"/> that represents the current <see cref="ColumnStream"/>.
/// </returns>
public override string ToString()
{
return string.Format(CultureInfo.InvariantCulture, "ColumnStream(0x{0:x}:{1})", this.columnid.Value, this.Itag);
}
/// <summary>
/// Flush the stream.
/// </summary>
public override void Flush()
{
// nothing is required
}
/// <summary>
/// Writes a sequence of bytes to the current stream and advances the current
/// position within this stream by the number of bytes written.
/// </summary>
/// <param name="buffer">The buffer to write from.</param>
/// <param name="offset">The offset in the buffer to write.</param>
/// <param name="count">The number of bytes to write.</param>
public override void Write(byte[] buffer, int offset, int count)
{
CheckBufferArguments(buffer, offset, count);
int length = checked((int)this.Length);
JET_SETINFO setinfo;
int newIbLongValue = checked(this.ibLongValue + count);
// If our current position is beyond the end of the LV extend
// the LV to the write point
if (this.ibLongValue > length)
{
setinfo = new JET_SETINFO { itagSequence = this.Itag };
Api.JetSetColumn(this.sesid, this.tableid, this.columnid, null, this.ibLongValue, SetColumnGrbit.SizeLV, setinfo);
length = this.ibLongValue;
}
SetColumnGrbit grbit;
if (this.ibLongValue == length)
{
grbit = SetColumnGrbit.AppendLV;
}
else if (newIbLongValue >= length)
{
grbit = SetColumnGrbit.OverwriteLV | SetColumnGrbit.SizeLV;
}
else
{
grbit = SetColumnGrbit.OverwriteLV;
}
setinfo = new JET_SETINFO { itagSequence = this.Itag, ibLongValue = this.ibLongValue };
Api.JetSetColumn(this.sesid, this.tableid, this.columnid, buffer, count, offset, grbit, setinfo);
checked
{
this.ibLongValue += count;
}
}
/// <summary>
/// Reads a sequence of bytes from the current stream and advances the
/// position within the stream by the number of bytes read.
/// </summary>
/// <param name="buffer">The buffer to read into.</param>
/// <param name="offset">The offset in the buffer to read into.</param>
/// <param name="count">The number of bytes to read.</param>
/// <returns>The number of bytes read into the buffer.</returns>
public override int Read(byte[] buffer, int offset, int count)
{
CheckBufferArguments(buffer, offset, count);
if (this.ibLongValue >= this.Length)
{
return 0;
}
int length;
var retinfo = new JET_RETINFO { itagSequence = this.Itag, ibLongValue = this.ibLongValue };
Api.JetRetrieveColumn(this.sesid, this.tableid, this.columnid, buffer, count, offset, out length, RetrieveGrbit, retinfo);
int bytesRead = Math.Min(length, count);
checked
{
this.ibLongValue += bytesRead;
}
return bytesRead;
}
/// <summary>
/// Sets the length of the stream.
/// </summary>
/// <param name="value">The desired length, in bytes.</param>
public override void SetLength(long value)
{
if (value > MaxLongValueSize || value < 0)
{
throw new ArgumentOutOfRangeException("value", value, "A LongValueStream cannot be longer than 0x7FFFFFF or less than 0 bytes");
}
if (value < this.Length && value > 0)
{
// BUG: Shrinking the column multiple times and then growing it can sometimes hit an unpleasant
// ESENT defect which causes a hang. To make sure we never have that problem we read out the data,
// and insert into a new long-value. This is not efficient.
var data = new byte[value];
var retinfo = new JET_RETINFO { itagSequence = this.Itag, ibLongValue = 0 };
int actualDataSize;
Api.JetRetrieveColumn(
this.sesid,
this.tableid,
this.columnid,
data,
data.Length,
out actualDataSize,
RetrieveGrbit,
retinfo);
var setinfo = new JET_SETINFO { itagSequence = this.Itag };
Api.JetSetColumn(this.sesid, this.tableid, this.columnid, data, data.Length, SetColumnGrbit.None, setinfo);
}
else
{
var setinfo = new JET_SETINFO { itagSequence = this.Itag };
SetColumnGrbit grbit = (0 == value) ? SetColumnGrbit.ZeroLength : SetColumnGrbit.SizeLV;
Api.JetSetColumn(this.sesid, this.tableid, this.columnid, null, checked((int)value), grbit, setinfo);
}
// Setting the length moves the offset back to the end of the data
if (this.ibLongValue > value)
{
this.ibLongValue = checked((int)value);
}
}
/// <summary>
/// Sets the position in the current stream.
/// </summary>
/// <param name="offset">Byte offset relative to the origin parameter.</param>
/// <param name="origin">A SeekOrigin indicating the reference point for the new position.</param>
/// <returns>The new position in the current stream.</returns>
public override long Seek(long offset, SeekOrigin origin)
{
long newOffset;
switch (origin)
{
case SeekOrigin.Begin:
newOffset = offset;
break;
case SeekOrigin.End:
newOffset = checked(this.Length + offset);
break;
case SeekOrigin.Current:
newOffset = checked(this.ibLongValue + offset);
break;
default:
throw new ArgumentOutOfRangeException("origin", origin, "Unknown origin");
}
if (newOffset < 0 || newOffset > MaxLongValueSize)
{
throw new ArgumentOutOfRangeException("offset", offset, "invalid offset/origin combination");
}
this.ibLongValue = checked((int)newOffset);
return this.ibLongValue;
}
/// <summary>
/// Check the buffer arguments given to Read/Write .
/// </summary>
/// <param name="buffer">The buffer.</param>
/// <param name="offset">The offset in the buffer to read/write to.</param>
/// <param name="count">The number of bytes to read/write.</param>
private static void CheckBufferArguments(ICollection<byte> buffer, int offset, int count)
{
if (null == buffer)
{
throw new ArgumentNullException("buffer");
}
if (offset < 0)
{
throw new ArgumentOutOfRangeException("offset", offset, "cannot be negative");
}
if (count < 0)
{
throw new ArgumentOutOfRangeException("count", count, "cannot be negative");
}
if (checked(buffer.Count - offset) < count)
{
throw new ArgumentOutOfRangeException("count", count, "cannot be larger than the size of the buffer");
}
}
}
}

View File

@ -0,0 +1,382 @@
//-----------------------------------------------------------------------
// <copyright file="ColumnValue.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
/// <summary>
/// Base class for objects that represent a column value to be set.
/// </summary>
public abstract partial class ColumnValue
{
/// <summary>
/// Internal grbit.
/// </summary>
private RetrieveColumnGrbit grbit;
/// <summary>
/// Initializes a new instance of the ColumnValue class.
/// </summary>
protected ColumnValue()
{
this.ItagSequence = 1;
}
/// <summary>
/// Gets or sets the columnid to be set or retrieved.
/// </summary>
public JET_COLUMNID Columnid { get; set; }
/// <summary>
/// Gets the last set or retrieved value of the column. The
/// value is returned as a generic object.
/// </summary>
public abstract object ValueAsObject { get; }
/// <summary>
/// Gets or sets column update options.
/// </summary>
public SetColumnGrbit SetGrbit { get; set; }
/// <summary>
/// Gets or sets column retrieval options.
/// </summary>
public RetrieveColumnGrbit RetrieveGrbit
{
get
{
return this.grbit;
}
set
{
this.ValidateRetrieveGrbit(value);
this.grbit = value;
}
}
/// <summary>
/// Gets or sets the column itag sequence.
/// </summary>
public int ItagSequence { get; set; }
/// <summary>
/// Gets the warning generated by retrieving or setting this column.
/// </summary>
public JET_wrn Error { get; internal set; }
/// <summary>
/// Gets the byte length of a column value, which is zero if column is null, otherwise
/// it matches the Size for fixed-size columns and represent the actual value byte
/// length for variable sized columns (i.e. binary and string). For strings the length
/// is determined in assumption two bytes per character.
/// </summary>
public abstract int Length { get; }
/// <summary>
/// Gets the size of the value in the column. This returns 0 for
/// variable sized columns (i.e. binary and string).
/// </summary>
protected abstract int Size { get; }
/// <summary>
/// Returns a <see cref="T:System.String"/> that represents the current <see cref="ColumnValue"/>.
/// </summary>
/// <returns>
/// A <see cref="T:System.String"/> that represents the current <see cref="ColumnValue"/>.
/// </returns>
public abstract override string ToString();
/// <summary>
/// Recursive RetrieveColumns method for data pinning. This should pin a buffer and
/// call the inherited RetrieveColumns method.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">
/// The table to retrieve the columns from.
/// </param>
/// <param name="columnValues">
/// Column values to retrieve.
/// </param>
internal static void RetrieveColumns(JET_SESID sesid, JET_TABLEID tableid, ColumnValue[] columnValues)
{
const int MaxColumnValues = 1024;
if (columnValues.Length > MaxColumnValues)
{
throw new ArgumentOutOfRangeException("columnValues", columnValues.Length, "Too many column values");
}
unsafe
{
byte[] buffer = null;
NATIVE_RETRIEVECOLUMN* nativeRetrievecolumns = stackalloc NATIVE_RETRIEVECOLUMN[columnValues.Length];
try
{
buffer = Caches.ColumnCache.Allocate();
Debug.Assert(MaxColumnValues * 16 < buffer.Length, "Maximum size of fixed columns could exceed buffer size");
fixed (byte* pinnedBuffer = buffer)
{
byte* currentBuffer = pinnedBuffer;
int numVariableLengthColumns = columnValues.Length;
// First the fixed-size columns
for (int i = 0; i < columnValues.Length; ++i)
{
if (0 != columnValues[i].Size)
{
columnValues[i].MakeNativeRetrieveColumn(ref nativeRetrievecolumns[i]);
nativeRetrievecolumns[i].pvData = new IntPtr(currentBuffer);
nativeRetrievecolumns[i].cbData = checked((uint)columnValues[i].Size);
currentBuffer += nativeRetrievecolumns[i].cbData;
Debug.Assert(currentBuffer <= pinnedBuffer + buffer.Length, "Moved past end of pinned buffer");
numVariableLengthColumns--;
}
}
// Now the variable-length columns
if (numVariableLengthColumns > 0)
{
int bufferUsed = checked((int)(currentBuffer - pinnedBuffer));
int bufferRemaining = checked(buffer.Length - bufferUsed);
int bufferPerColumn = bufferRemaining / numVariableLengthColumns;
Debug.Assert(bufferPerColumn > 0, "Not enough buffer left to retrieve variable length columns");
// Now the variable-size columns
for (int i = 0; i < columnValues.Length; ++i)
{
if (0 == columnValues[i].Size)
{
columnValues[i].MakeNativeRetrieveColumn(ref nativeRetrievecolumns[i]);
nativeRetrievecolumns[i].pvData = new IntPtr(currentBuffer);
nativeRetrievecolumns[i].cbData = checked((uint)bufferPerColumn);
currentBuffer += nativeRetrievecolumns[i].cbData;
Debug.Assert(currentBuffer <= pinnedBuffer + buffer.Length, "Moved past end of pinned buffer");
}
}
}
// Retrieve the columns
Api.Check(Api.Impl.JetRetrieveColumns(sesid, tableid, nativeRetrievecolumns, columnValues.Length));
// Propagate the warnings and output.
for (int i = 0; i < columnValues.Length; ++i)
{
columnValues[i].Error = (JET_wrn)nativeRetrievecolumns[i].err;
columnValues[i].ItagSequence = (int)nativeRetrievecolumns[i].itagSequence;
}
// Now parse out the columns that were retrieved successfully
for (int i = 0; i < columnValues.Length; ++i)
{
if (nativeRetrievecolumns[i].err != (int)JET_wrn.BufferTruncated)
{
byte* columnBuffer = (byte*)nativeRetrievecolumns[i].pvData;
int startIndex = checked((int)(columnBuffer - pinnedBuffer));
columnValues[i].GetValueFromBytes(
buffer,
startIndex,
checked((int)nativeRetrievecolumns[i].cbActual),
nativeRetrievecolumns[i].err);
}
}
}
// Finally retrieve the buffers where the columns weren't large enough.
RetrieveTruncatedBuffers(sesid, tableid, columnValues, nativeRetrievecolumns);
}
finally
{
if (buffer != null)
{
Caches.ColumnCache.Free(ref buffer);
}
}
}
}
/// <summary>
/// Recursive SetColumns method for data pinning. This should populate the buffer and
/// call the inherited SetColumns method.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">
/// The table to set the columns in. An update should be prepared.
/// </param>
/// <param name="columnValues">
/// Column values to set.
/// </param>
/// <param name="nativeColumns">
/// Structures to put the pinned data in.
/// </param>
/// <param name="i">Offset of this object in the array.</param>
/// <returns>An error code.</returns>
internal abstract unsafe int SetColumns(JET_SESID sesid, JET_TABLEID tableid, ColumnValue[] columnValues, NATIVE_SETCOLUMN* nativeColumns, int i);
/// <summary>
/// Recursive SetColumns function used to pin data.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">
/// The table to set the columns in. An update should be prepared.
/// </param>
/// <param name="columnValues">
/// Column values to set.
/// </param>
/// <param name="nativeColumns">
/// Structures to put the pinned data in.
/// </param>
/// <param name="i">Offset of this object in the array.</param>
/// <param name="buffer">The buffer for this object.</param>
/// <param name="bufferSize">Size of the buffer for ths object.</param>
/// <param name="hasValue">True if this object is non null.</param>
/// <returns>An error code.</returns>
/// <remarks>
/// This is marked as internal because it uses the NATIVE_SETCOLUMN type
/// which is also marked as internal. It should be treated as a protected
/// method though.
/// </remarks>
internal unsafe int SetColumns(
JET_SESID sesid,
JET_TABLEID tableid,
ColumnValue[] columnValues,
NATIVE_SETCOLUMN* nativeColumns,
int i,
void* buffer,
int bufferSize,
bool hasValue)
{
Debug.Assert(this == columnValues[i], "SetColumns should be called on the current object");
this.MakeNativeSetColumn(ref nativeColumns[i]);
if (hasValue)
{
nativeColumns[i].cbData = checked((uint)bufferSize);
nativeColumns[i].pvData = new IntPtr(buffer);
if (0 == bufferSize)
{
nativeColumns[i].grbit |= (uint)SetColumnGrbit.ZeroLength;
}
}
int err = i == columnValues.Length - 1
? Api.Impl.JetSetColumns(sesid, tableid, nativeColumns, columnValues.Length)
: columnValues[i + 1].SetColumns(sesid, tableid, columnValues, nativeColumns, i + 1);
this.Error = (JET_wrn)nativeColumns[i].err;
return err;
}
/// <summary>
/// Given data retrieved from ESENT, decode the data and set the value in the ColumnValue object.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within the bytes.</param>
/// <param name="count">The number of bytes to decode.</param>
/// <param name="err">The error returned from ESENT.</param>
protected abstract void GetValueFromBytes(byte[] value, int startIndex, int count, int err);
/// <summary>
/// Validation for the requested retrieve options for the column.
/// </summary>
/// <param name="grbit">The retrieve options to validate.</param>
protected virtual void ValidateRetrieveGrbit(RetrieveColumnGrbit grbit)
{
// We cannot support this request when there is no way to indicate that a column reference is returned.
if ((grbit & (RetrieveColumnGrbit)0x00020000) != 0) // UnpublishedGrbits.RetrieveAsRefIfNotInRecord
{
throw new EsentInvalidGrbitException();
}
}
/// <summary>
/// Retrieve the value for columns whose buffers were truncated.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The table to use.</param>
/// <param name="columnValues">The column values.</param>
/// <param name="nativeRetrievecolumns">
/// The native retrieve columns that match the column values.
/// </param>
private static unsafe void RetrieveTruncatedBuffers(JET_SESID sesid, JET_TABLEID tableid, ColumnValue[] columnValues, NATIVE_RETRIEVECOLUMN* nativeRetrievecolumns)
{
for (int i = 0; i < columnValues.Length; ++i)
{
if (nativeRetrievecolumns[i].err == (int)JET_wrn.BufferTruncated)
{
var buffer = new byte[nativeRetrievecolumns[i].cbActual];
int actualSize;
int err;
var retinfo = new JET_RETINFO { itagSequence = columnValues[i].ItagSequence };
// Pin the buffer and retrieve the data
fixed (byte* pinnedBuffer = buffer)
{
err = Api.Impl.JetRetrieveColumn(
sesid,
tableid,
columnValues[i].Columnid,
new IntPtr(pinnedBuffer),
buffer.Length,
out actualSize,
columnValues[i].RetrieveGrbit,
retinfo);
}
if (JET_wrn.BufferTruncated == (JET_wrn)err)
{
string error = string.Format(
CultureInfo.CurrentCulture,
"Column size changed from {0} to {1}. The record was probably updated by another thread.",
buffer.Length,
actualSize);
Trace.TraceError(error);
throw new InvalidOperationException(error);
}
// Throw errors, but put warnings in the structure
Api.Check(err);
columnValues[i].Error = (JET_wrn)err;
// For BytesColumnValue this will copy the data to a new array.
// If this situation becomes common we should simply use the array.
columnValues[i].GetValueFromBytes(buffer, 0, actualSize, err);
}
}
}
/// <summary>
/// Create a native SetColumn from this object.
/// </summary>
/// <param name="setcolumn">The native setcolumn structure to fill in.</param>
private void MakeNativeSetColumn(ref NATIVE_SETCOLUMN setcolumn)
{
setcolumn.columnid = this.Columnid.Value;
setcolumn.grbit = (uint)this.SetGrbit;
setcolumn.itagSequence = checked((uint)this.ItagSequence);
}
/// <summary>
/// Create a native RetrieveColumn from this object.
/// </summary>
/// <param name="retrievecolumn">
/// The retrieve column structure to fill in.
/// </param>
private void MakeNativeRetrieveColumn(ref NATIVE_RETRIEVECOLUMN retrievecolumn)
{
retrievecolumn.columnid = this.Columnid.Value;
retrievecolumn.grbit = (uint)this.RetrieveGrbit;
retrievecolumn.itagSequence = checked((uint)this.ItagSequence);
}
}
}

View File

@ -0,0 +1,82 @@
//-----------------------------------------------------------------------
// <copyright file="ColumnValueOfStruct.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
/// <summary>
/// Set a column of a struct type (e.g. <see cref="Int32"/>/<see cref="Guid"/>).
/// </summary>
/// <typeparam name="T">Type to set.</typeparam>
public abstract class ColumnValueOfStruct<T> : ColumnValue where T : struct, IEquatable<T>
{
/// <summary>
/// Internal value.
/// </summary>
private T? internalValue;
/// <summary>
/// Gets the last set or retrieved value of the column. The
/// value is returned as a generic object.
/// </summary>
public override object ValueAsObject
{
get
{
return BoxedValueCache<T>.GetBoxedValue(this.Value);
}
}
/// <summary>
/// Gets or sets the value in the struct.
/// </summary>
public T? Value
{
get
{
return this.internalValue;
}
set
{
this.internalValue = value;
this.Error = value == null ? JET_wrn.ColumnNull : JET_wrn.Success;
}
}
/// <summary>
/// Gets the byte length of a column value, which is zero if column is null, otherwise
/// it matches the Size for this fixed-size column.
/// </summary>
public override int Length
{
get { return this.Value.HasValue ? this.Size : 0; }
}
/// <summary>
/// Gets a string representation of this object.
/// </summary>
/// <returns>A string representation of this object.</returns>
public override string ToString()
{
return this.Value.ToString();
}
/// <summary>
/// Make sure the retrieved data is exactly the size needed for
/// the structure. An exception is thrown if there is a mismatch.
/// </summary>
/// <param name="count">The size of the retrieved data.</param>
protected void CheckDataCount(int count)
{
if (this.Size != count)
{
throw new EsentInvalidColumnException();
}
}
}
}

View File

@ -0,0 +1,175 @@
//-----------------------------------------------------------------------
// <copyright file="Conversions.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
using System.Collections.Generic;
using System.Globalization;
/// <summary>
/// Provide methods to convert data and flags between
/// Win32 and the .NET Framework.
/// </summary>
public static class Conversions
{
/// <summary>
/// Maps a CompareOption enumeration to the corresponding LCMapString flag.
/// </summary>
private static readonly IDictionary<CompareOptions, uint> CompareOptionsToLcmapFlags;
/// <summary>
/// Maps an LCMapString flag to the corresponding CompareOption enumeration.
/// </summary>
private static readonly IDictionary<uint, CompareOptions> LcmapFlagsToCompareOptions;
/// <summary>
/// Initializes static members of the Conversions class. This sets up the
/// conversion mapping dictionaries.
/// </summary>
static Conversions()
{
// Rather than creating both dictionaries, define one as the inverse of the other.
CompareOptionsToLcmapFlags = new Dictionary<CompareOptions, uint>
{
{ CompareOptions.IgnoreCase, NativeMethods.NORM_IGNORECASE },
{ CompareOptions.IgnoreKanaType, NativeMethods.NORM_IGNOREKANATYPE },
{ CompareOptions.IgnoreNonSpace, NativeMethods.NORM_IGNORENONSPACE },
{ CompareOptions.IgnoreSymbols, NativeMethods.NORM_IGNORESYMBOLS },
{ CompareOptions.IgnoreWidth, NativeMethods.NORM_IGNOREWIDTH },
{ CompareOptions.StringSort, NativeMethods.SORT_STRINGSORT }
};
LcmapFlagsToCompareOptions = InvertDictionary(CompareOptionsToLcmapFlags);
}
/// <summary>
/// Convert a double (OA date time format) to a DateTime. Unlike DateTime.FromOADate
/// this doesn't throw exceptions.
/// </summary>
/// <param name="d">The double value.</param>
/// <returns>A DateTime.</returns>
public static DateTime ConvertDoubleToDateTime(double d)
{
try
{
return LibraryHelpers.FromOADate(d);
}
catch (ArgumentException)
{
// Not all double values are valid OADates. We deal with out-of-range values
// by returning either min or max
return d < 0 ? DateTime.MinValue : DateTime.MaxValue;
}
}
/// <summary>
/// Given flags for LCMapFlags, turn them into compare options. Unknown options
/// are ignored.
/// </summary>
/// <param name="lcmapFlags">LCMapString flags.</param>
/// <returns>CompareOptions describing the (known) flags.</returns>
[CLSCompliant(false)]
public static CompareOptions CompareOptionsFromLCMapFlags(uint lcmapFlags)
{
// This should be a template, but there isn't an elegant way to express than with C# generics
CompareOptions options = CompareOptions.None;
foreach (uint flag in LcmapFlagsToCompareOptions.Keys)
{
if (flag == (lcmapFlags & flag))
{
options |= LcmapFlagsToCompareOptions[flag];
}
}
return options;
}
/// <summary>
/// Give CompareOptions, turn them into flags from LCMapString. Unknown options are ignored.
/// </summary>
/// <param name="compareOptions">The options to convert.</param>
/// <returns>The LCMapString flags that match the compare options. Unsupported options are ignored.</returns>
[CLSCompliant(false)]
public static uint LCMapFlagsFromCompareOptions(CompareOptions compareOptions)
{
// This should be a template, but there isn't an elegant way to express than with C# generics
uint flags = 0;
foreach (CompareOptions option in CompareOptionsToLcmapFlags.Keys)
{
if (option == (compareOptions & option))
{
flags |= CompareOptionsToLcmapFlags[option];
}
}
return flags;
}
/// <summary>
/// Given a Key=>Value dictionary create an inverted dictionary that maps Value=>Key.
/// </summary>
/// <typeparam name="TValue">The new value type (the key of the current dictionary).</typeparam>
/// <typeparam name="TKey">The new key type (the value if the current dictionary).</typeparam>
/// <param name="dict">The dictionary to invert.</param>
/// <returns>An inverted dictionary.</returns>
private static IDictionary<TKey, TValue> InvertDictionary<TValue, TKey>(ICollection<KeyValuePair<TValue, TKey>> dict)
{
var invertedDict = new Dictionary<TKey, TValue>(dict.Count);
foreach (KeyValuePair<TValue, TKey> entry in dict)
{
invertedDict.Add(entry.Value, entry.Key);
}
return invertedDict;
}
/// <summary>
/// This class contains the unmanaged constants used in the conversion.
/// </summary>
internal static class NativeMethods
{
#region Win32 Constants
/// <summary>
/// Ignore case.
/// </summary>
public const uint NORM_IGNORECASE = 0x00000001;
/// <summary>
/// Ignore nonspacing chars.
/// </summary>
public const uint NORM_IGNORENONSPACE = 0x00000002;
/// <summary>
/// Ignore symbols.
/// </summary>
public const uint NORM_IGNORESYMBOLS = 0x00000004;
/// <summary>
/// Ignore kanatype.
/// </summary>
public const uint NORM_IGNOREKANATYPE = 0x00010000;
/// <summary>
/// Ignore width.
/// </summary>
public const uint NORM_IGNOREWIDTH = 0x00020000;
/// <summary>
/// Treat punctuation the same as symbols.
/// </summary>
public const uint SORT_STRINGSORT = 0x00001000;
/// <summary>
/// Produce a normalized wide-character sort key.
/// </summary>
public const uint LCMAP_SORTKEY = 0x00000400;
#endregion Win32 Constants
}
}
}

View File

@ -0,0 +1,70 @@
//-----------------------------------------------------------------------
// <copyright file="DateTimeColumnValue.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
using System.Diagnostics;
/// <summary>
/// A <see cref="Guid"/> column value.
/// </summary>
public class DateTimeColumnValue : ColumnValueOfStruct<DateTime>
{
/// <summary>
/// Gets the size of the value in the column. This returns 0 for
/// variable sized columns (i.e. binary and string).
/// </summary>
protected override int Size
{
[DebuggerStepThrough]
get { return sizeof(double); }
}
/// <summary>
/// Recursive SetColumns method for data pinning. This populates the buffer and
/// calls the inherited SetColumns method.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">
/// The table to set the columns in. An update should be prepared.
/// </param>
/// <param name="columnValues">
/// Column values to set.
/// </param>
/// <param name="nativeColumns">
/// Structures to put the pinned data in.
/// </param>
/// <param name="i">Offset of this object in the array.</param>
/// <returns>An error code.</returns>
internal override unsafe int SetColumns(JET_SESID sesid, JET_TABLEID tableid, ColumnValue[] columnValues, NATIVE_SETCOLUMN* nativeColumns, int i)
{
var data = this.Value.GetValueOrDefault().ToOADate();
return this.SetColumns(sesid, tableid, columnValues, nativeColumns, i, &data, sizeof(double), this.Value.HasValue);
}
/// <summary>
/// Given data retrieved from ESENT, decode the data and set the value in the ColumnValue object.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within the bytes.</param>
/// <param name="count">The number of bytes to decode.</param>
/// <param name="err">The error returned from ESENT.</param>
protected override void GetValueFromBytes(byte[] value, int startIndex, int count, int err)
{
if (JET_wrn.ColumnNull == (JET_wrn)err)
{
this.Value = null;
}
else
{
this.CheckDataCount(count);
double d = BitConverter.ToDouble(value, startIndex);
this.Value = Conversions.ConvertDoubleToDateTime(d);
}
}
}
}

View File

@ -0,0 +1,69 @@
//-----------------------------------------------------------------------
// <copyright file="DoubleColumnValue.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
using System.Diagnostics;
/// <summary>
/// A <see cref="double"/> column value.
/// </summary>
public class DoubleColumnValue : ColumnValueOfStruct<double>
{
/// <summary>
/// Gets the size of the value in the column. This returns 0 for
/// variable sized columns (i.e. binary and string).
/// </summary>
protected override int Size
{
[DebuggerStepThrough]
get { return sizeof(double); }
}
/// <summary>
/// Recursive SetColumns method for data pinning. This populates the buffer and
/// calls the inherited SetColumns method.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">
/// The table to set the columns in. An update should be prepared.
/// </param>
/// <param name="columnValues">
/// Column values to set.
/// </param>
/// <param name="nativeColumns">
/// Structures to put the pinned data in.
/// </param>
/// <param name="i">Offset of this object in the array.</param>
/// <returns>An error code.</returns>
internal override unsafe int SetColumns(JET_SESID sesid, JET_TABLEID tableid, ColumnValue[] columnValues, NATIVE_SETCOLUMN* nativeColumns, int i)
{
var data = this.Value.GetValueOrDefault();
return this.SetColumns(sesid, tableid, columnValues, nativeColumns, i, &data, sizeof(double), this.Value.HasValue);
}
/// <summary>
/// Given data retrieved from ESENT, decode the data and set the value in the ColumnValue object.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within the bytes.</param>
/// <param name="count">The number of bytes to decode.</param>
/// <param name="err">The error returned from ESENT.</param>
protected override void GetValueFromBytes(byte[] value, int startIndex, int count, int err)
{
if (JET_wrn.ColumnNull == (JET_wrn)err)
{
this.Value = null;
}
else
{
this.CheckDataCount(count);
this.Value = BitConverter.ToDouble(value, startIndex);
}
}
}
}

View File

@ -0,0 +1,172 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="DurableCommitCallback.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
// <summary>
// Callback for JET_param JET_paramDurableCommitCallback.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop.Windows8
{
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Reflection;
#if !MANAGEDESENT_ON_CORECLR
using System.Runtime.CompilerServices;
#endif
using Microsoft.Isam.Esent.Interop.Implementation;
/// <summary>
/// A class which wraps the callback dealing with durable commits.
/// </summary>
public class DurableCommitCallback : EsentResource
{
/// <summary>
/// API call tracing.
/// </summary>
private static readonly TraceSwitch TraceSwitch = new TraceSwitch("ESENT DurableCommitCallback", "Wrapper around unmanaged ESENT durable commit callback");
/// <summary>
/// Instance associated with this callback.
/// </summary>
private JET_INSTANCE instance;
/// <summary>
/// Hold a reference to the delegate so that it doesn't get garbage-collected.
/// </summary>
private JET_PFNDURABLECOMMITCALLBACK wrappedCallback;
/// <summary>
/// Hold a reference to the delegate so that it doesn't get garbage-collected.
/// </summary>
[SuppressMessage("Exchange.Performance", "EX0023:DeadVariableDetector", Justification = "Need to hold on to a reference to the callback, so that it does not get garbage collected.")]
private NATIVE_JET_PFNDURABLECOMMITCALLBACK wrapperCallback;
/// <summary>
/// Initializes a new instance of the <see cref="DurableCommitCallback"/> class.
/// The constructor.
/// </summary>
/// <param name="instance">
/// The instance with which to associate the callback.
/// </param>
/// <param name="wrappedCallback">
/// The managed code callback to call.
/// </param>
public DurableCommitCallback(
JET_INSTANCE instance,
JET_PFNDURABLECOMMITCALLBACK wrappedCallback)
{
this.instance = instance;
this.wrappedCallback = wrappedCallback;
this.wrapperCallback = this.NativeDurableCommitCallback;
#if !MANAGEDESENT_ON_WSA // RuntimeHelpers works differently in Windows Store Apps.
if (this.wrappedCallback != null)
{
RuntimeHelpers.PrepareMethod(this.wrappedCallback.Method.MethodHandle);
}
RuntimeHelpers.PrepareMethod(typeof(DurableCommitCallback).GetMethod("NativeDurableCommitCallback", BindingFlags.NonPublic | BindingFlags.Instance).MethodHandle);
#endif
InstanceParameters instanceParameters = new InstanceParameters(this.instance);
// This might be null.
instanceParameters.SetDurableCommitCallback(this.wrapperCallback);
this.ResourceWasAllocated();
}
/// <summary>
/// Generate a string representation of the structure.
/// </summary>
/// <returns>The structure as a string.</returns>
public override string ToString()
{
return string.Format(
CultureInfo.InvariantCulture,
"DurableCommitCallback({0})",
this.instance.ToString());
}
/// <summary>
/// Terminate the durable commit session.
/// </summary>
public void End()
{
this.CheckObjectIsNotDisposed();
this.ReleaseResource();
}
/// <summary>
/// Free the durable commit session.
/// We do not try to set the instance parameter to null, since the callback is disposed after JetTerm and
/// the callback cannot be set after JetTerm.
/// </summary>
protected override void ReleaseResource()
{
this.instance = JET_INSTANCE.Nil;
this.wrappedCallback = null;
this.wrapperCallback = null;
this.ResourceWasReleased();
}
/// <summary>
/// The proxy callback function to call the user-defined managed delegate.
/// </summary>
/// <param name="instance">
/// The instance.
/// </param>
/// <param name="commitIdSeen">
/// The commit-id flushed.
/// </param>
/// <param name="grbit">
/// Reserved currently.
/// </param>
/// <returns>
/// An error code.
/// </returns>
private JET_err NativeDurableCommitCallback(
IntPtr instance,
ref NATIVE_COMMIT_ID commitIdSeen,
uint grbit)
{
RuntimeHelpers.PrepareConstrainedRegions();
try
{
JET_INSTANCE jetInstance = new JET_INSTANCE()
{
Value = instance
};
if (this.instance != jetInstance)
{
// We assume it's only called on one instance at a time. The only thing
// we really care about is serialization of the byte array.
//
// It would be nice to throw an error, but we're going back to real
// code, which doesn't deal with managed exceptions well.
return JET_err.CallbackFailed;
}
JET_COMMIT_ID commitId = new JET_COMMIT_ID(commitIdSeen);
return this.wrappedCallback(jetInstance, commitId, (DurableCommitCallbackGrbit)grbit);
}
catch (Exception ex)
{
Trace.WriteLineIf(
TraceSwitch.TraceWarning, string.Format(CultureInfo.InvariantCulture, "Caught Exception {0}", ex));
JetApi.ReportUnhandledException(ex, "Unhandled exception during NativeDurableCommitCallback");
// This should never be executed, but the compiler doesn't know it.
return JET_err.CallbackFailed;
}
}
}
}

View File

@ -0,0 +1,121 @@
//-----------------------------------------------------------------------
// <copyright file="EnumeratedColumn.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
using System.Globalization;
/// <summary>
/// The values for a given column as generated by Api.EnumerateColumns.
/// </summary>
public class EnumeratedColumn
{
/// <summary>
/// Gets or sets the column ID of this set of column values.
/// </summary>
public JET_COLUMNID Id { get; set; }
/// <summary>
/// Gets or sets the status of this column id.
/// </summary>
/// <seealso cref="JET_err.Success"/>
/// <seealso cref="JET_err.BadColumnId"/>
/// <seealso cref="JET_err.ColumnNotFound"/>
public JET_err Error { get; set; }
/// <summary>
/// Gets or sets the status of this set of column values.
/// </summary>
/// <seealso cref="JET_wrn.Success"/>
/// <seealso cref="JET_wrn.ColumnDefault"/>
/// <seealso cref="JET_wrn.ColumnNull"/>
/// <seealso cref="JET_wrn.ColumnPresent"/>
/// <seealso cref="JET_wrn.ColumnSkipped"/>
public JET_wrn Warning { get; set; }
/// <summary>
/// Gets or sets the column values enumerated.
/// </summary>
/// <remarks>
/// This will be null if the column is null or the column values were not provided.
/// </remarks>
public Value[] Values { get; set; }
/// <summary>
/// Returns a <see cref="T:System.String"/> that represents the current <see cref="EnumeratedColumn"/>.
/// </summary>
/// <returns>
/// A <see cref="T:System.String"/> that represents the current <see cref="EnumeratedColumn"/>.
/// </returns>
public override string ToString()
{
return string.Format(
CultureInfo.InvariantCulture,
"EnumeratedColumn(0x{0:x}: {1} Values[{2}])",
this.Id,
this.Error != JET_err.Success ? this.Error.ToString() : this.Warning.ToString(),
this.Values.Length);
}
/// <summary>
/// A single column value.
/// </summary>
public class Value
{
/// <summary>
/// Gets or sets the ordinal of this column value.
/// </summary>
/// <remarks>
/// The lowest valid ordinal is one.
/// This is the same as the "itagSequence" of the column value.
/// </remarks>
public int Ordinal { get; set; }
/// <summary>
/// Gets or sets the status of this column value.
/// </summary>
/// <seealso cref="JET_wrn.Success"/>
/// <seealso cref="JET_wrn.ColumnDefault"/>
/// <seealso cref="JET_wrn.ColumnNotInRecord"/>
/// <seealso cref="JET_wrn.ColumnNull"/>
/// <seealso cref="JET_wrn.ColumnPresent"/>
/// <seealso cref="JET_wrn.ColumnSkipped"/>
/// <seealso cref="JET_wrn.ColumnTruncated"/>
public JET_wrn Warning { get; set; }
/// <summary>
/// Gets or sets the column value as bytes.
/// </summary>
/// <remarks>
/// This will be null if the column is null or the column values were not provided.
/// This will be truncated if Warning is <see cref="JET_wrn.ColumnTruncated"/>.
/// </remarks>
public byte[] Bytes { get; set; }
/// <summary>
/// Returns a <see cref="T:System.String"/> that represents the current <see cref="EnumeratedColumn.Value"/>.
/// </summary>
/// <returns>
/// A <see cref="T:System.String"/> that represents the current <see cref="EnumeratedColumn.Value"/>.
/// </returns>
public override string ToString()
{
const int MaxLength = 16;
return string.Format(
CultureInfo.InvariantCulture,
"EnumeratedColumn.Value({0}: {1} Bytes[{2}] = {3}{4}{5}{6})",
this.Ordinal,
this.Warning,
this.Bytes.Length,
'{',
BitConverter.ToString(this.Bytes, 0, Math.Min(this.Bytes.Length, MaxLength)),
this.Bytes.Length > MaxLength ? "..." : string.Empty,
'}');
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,351 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.10.35122.118
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{18B3E50E-454E-49DB-A92F-E1D7DAD2AF7D}"
ProjectSection(SolutionItems) = preProject
CodeCoverage.testrunconfig = CodeCoverage.testrunconfig
esent.vsmdi = esent.vsmdi
Normal.testrunconfig = Normal.testrunconfig
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EsentInterop", "EsentInterop.csproj", "{E929E163-52A0-4AAC-917B-6D7FAF70C45E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DbUtil", "..\EsentInteropSamples\DbUtil\DbUtil.csproj", "{E0B163B0-5AC6-4304-B932-BFC1F6A2A4EB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "isam", "..\isam\isam.csproj", "{21CC632C-B09A-4DB7-BD6E-7F7D2716F58F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StockSample", "..\EsentInteropSamples\StockSample\StockSample.csproj", "{B0E6D3AB-26F8-4A77-A7E1-D8024B8FFFCF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EsentCollections", "..\EsentCollections\EsentCollections.csproj", "{CF2D4EE4-0D11-404D-B800-C4DCFEC42588}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HelloWorld", "..\EsentCollectionsSamples\HelloWorld\HelloWorld.csproj", "{8341DE8C-5BC7-461F-B42D-AA2B72586A5C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RssDictionarySample", "..\EsentCollectionsSamples\RssDictionarySample\RssDictionarySample.csproj", "{134FBC80-2E23-451B-A6B3-72B0AA2234F9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EsentInteropTests", "..\EsentInteropTests\EsentInteropTests.csproj", "{85B2B7BB-BF95-42DF-8CBF-348AEF63BD1F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EsentCollectionsTests", "..\EsentCollectionsTests\EsentCollectionsTests.csproj", "{D3A1C1C8-6119-4827-AC24-1FF49FACFD4D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IsamUnitTests", "..\isamunittests\IsamUnitTests.csproj", "{6AC9C0BE-6BCE-493F-BD80-6F2247CB669D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DbUtilTests", "..\EsentInteropSamples\DbUtilTests\DbUtilTests.csproj", "{C9B82A4F-8306-41A9-91DA-1BA5080F1DB0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EsentSample", "..\EsentInteropSamples\EsentSample\EsentSample.csproj", "{44D46916-891F-435F-B914-AE8AC80613FD}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BasicTest", "..\EsentInteropSamples\BasicTest\BasicTest.csproj", "{08819B49-02B8-4F93-A143-F9B0461CEA64}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UWPSample", "..\UWPSample\UWPSample.csproj", "{B1427E8D-9175-42BE-8B90-A5A9CB4AAD51}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|ARM = Debug|ARM
Debug|ARM64 = Debug|ARM64
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|ARM = Release|ARM
Release|ARM64 = Release|ARM64
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{E929E163-52A0-4AAC-917B-6D7FAF70C45E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E929E163-52A0-4AAC-917B-6D7FAF70C45E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E929E163-52A0-4AAC-917B-6D7FAF70C45E}.Debug|ARM.ActiveCfg = Debug|Any CPU
{E929E163-52A0-4AAC-917B-6D7FAF70C45E}.Debug|ARM.Build.0 = Debug|Any CPU
{E929E163-52A0-4AAC-917B-6D7FAF70C45E}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{E929E163-52A0-4AAC-917B-6D7FAF70C45E}.Debug|ARM64.Build.0 = Debug|Any CPU
{E929E163-52A0-4AAC-917B-6D7FAF70C45E}.Debug|x64.ActiveCfg = Debug|Any CPU
{E929E163-52A0-4AAC-917B-6D7FAF70C45E}.Debug|x64.Build.0 = Debug|Any CPU
{E929E163-52A0-4AAC-917B-6D7FAF70C45E}.Debug|x86.ActiveCfg = Debug|Any CPU
{E929E163-52A0-4AAC-917B-6D7FAF70C45E}.Debug|x86.Build.0 = Debug|Any CPU
{E929E163-52A0-4AAC-917B-6D7FAF70C45E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E929E163-52A0-4AAC-917B-6D7FAF70C45E}.Release|Any CPU.Build.0 = Release|Any CPU
{E929E163-52A0-4AAC-917B-6D7FAF70C45E}.Release|ARM.ActiveCfg = Release|Any CPU
{E929E163-52A0-4AAC-917B-6D7FAF70C45E}.Release|ARM.Build.0 = Release|Any CPU
{E929E163-52A0-4AAC-917B-6D7FAF70C45E}.Release|ARM64.ActiveCfg = Release|Any CPU
{E929E163-52A0-4AAC-917B-6D7FAF70C45E}.Release|ARM64.Build.0 = Release|Any CPU
{E929E163-52A0-4AAC-917B-6D7FAF70C45E}.Release|x64.ActiveCfg = Release|Any CPU
{E929E163-52A0-4AAC-917B-6D7FAF70C45E}.Release|x64.Build.0 = Release|Any CPU
{E929E163-52A0-4AAC-917B-6D7FAF70C45E}.Release|x86.ActiveCfg = Release|x86
{E929E163-52A0-4AAC-917B-6D7FAF70C45E}.Release|x86.Build.0 = Release|x86
{E0B163B0-5AC6-4304-B932-BFC1F6A2A4EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E0B163B0-5AC6-4304-B932-BFC1F6A2A4EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E0B163B0-5AC6-4304-B932-BFC1F6A2A4EB}.Debug|ARM.ActiveCfg = Debug|Any CPU
{E0B163B0-5AC6-4304-B932-BFC1F6A2A4EB}.Debug|ARM.Build.0 = Debug|Any CPU
{E0B163B0-5AC6-4304-B932-BFC1F6A2A4EB}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{E0B163B0-5AC6-4304-B932-BFC1F6A2A4EB}.Debug|ARM64.Build.0 = Debug|Any CPU
{E0B163B0-5AC6-4304-B932-BFC1F6A2A4EB}.Debug|x64.ActiveCfg = Debug|Any CPU
{E0B163B0-5AC6-4304-B932-BFC1F6A2A4EB}.Debug|x64.Build.0 = Debug|Any CPU
{E0B163B0-5AC6-4304-B932-BFC1F6A2A4EB}.Debug|x86.ActiveCfg = Debug|Any CPU
{E0B163B0-5AC6-4304-B932-BFC1F6A2A4EB}.Debug|x86.Build.0 = Debug|Any CPU
{E0B163B0-5AC6-4304-B932-BFC1F6A2A4EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E0B163B0-5AC6-4304-B932-BFC1F6A2A4EB}.Release|Any CPU.Build.0 = Release|Any CPU
{E0B163B0-5AC6-4304-B932-BFC1F6A2A4EB}.Release|ARM.ActiveCfg = Release|Any CPU
{E0B163B0-5AC6-4304-B932-BFC1F6A2A4EB}.Release|ARM.Build.0 = Release|Any CPU
{E0B163B0-5AC6-4304-B932-BFC1F6A2A4EB}.Release|ARM64.ActiveCfg = Release|Any CPU
{E0B163B0-5AC6-4304-B932-BFC1F6A2A4EB}.Release|ARM64.Build.0 = Release|Any CPU
{E0B163B0-5AC6-4304-B932-BFC1F6A2A4EB}.Release|x64.ActiveCfg = Release|Any CPU
{E0B163B0-5AC6-4304-B932-BFC1F6A2A4EB}.Release|x64.Build.0 = Release|Any CPU
{E0B163B0-5AC6-4304-B932-BFC1F6A2A4EB}.Release|x86.ActiveCfg = Release|x86
{E0B163B0-5AC6-4304-B932-BFC1F6A2A4EB}.Release|x86.Build.0 = Release|x86
{21CC632C-B09A-4DB7-BD6E-7F7D2716F58F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{21CC632C-B09A-4DB7-BD6E-7F7D2716F58F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{21CC632C-B09A-4DB7-BD6E-7F7D2716F58F}.Debug|ARM.ActiveCfg = Debug|Any CPU
{21CC632C-B09A-4DB7-BD6E-7F7D2716F58F}.Debug|ARM.Build.0 = Debug|Any CPU
{21CC632C-B09A-4DB7-BD6E-7F7D2716F58F}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{21CC632C-B09A-4DB7-BD6E-7F7D2716F58F}.Debug|ARM64.Build.0 = Debug|Any CPU
{21CC632C-B09A-4DB7-BD6E-7F7D2716F58F}.Debug|x64.ActiveCfg = Debug|Any CPU
{21CC632C-B09A-4DB7-BD6E-7F7D2716F58F}.Debug|x64.Build.0 = Debug|Any CPU
{21CC632C-B09A-4DB7-BD6E-7F7D2716F58F}.Debug|x86.ActiveCfg = Debug|Any CPU
{21CC632C-B09A-4DB7-BD6E-7F7D2716F58F}.Debug|x86.Build.0 = Debug|Any CPU
{21CC632C-B09A-4DB7-BD6E-7F7D2716F58F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{21CC632C-B09A-4DB7-BD6E-7F7D2716F58F}.Release|Any CPU.Build.0 = Release|Any CPU
{21CC632C-B09A-4DB7-BD6E-7F7D2716F58F}.Release|ARM.ActiveCfg = Release|Any CPU
{21CC632C-B09A-4DB7-BD6E-7F7D2716F58F}.Release|ARM.Build.0 = Release|Any CPU
{21CC632C-B09A-4DB7-BD6E-7F7D2716F58F}.Release|ARM64.ActiveCfg = Release|Any CPU
{21CC632C-B09A-4DB7-BD6E-7F7D2716F58F}.Release|ARM64.Build.0 = Release|Any CPU
{21CC632C-B09A-4DB7-BD6E-7F7D2716F58F}.Release|x64.ActiveCfg = Release|Any CPU
{21CC632C-B09A-4DB7-BD6E-7F7D2716F58F}.Release|x64.Build.0 = Release|Any CPU
{21CC632C-B09A-4DB7-BD6E-7F7D2716F58F}.Release|x86.ActiveCfg = Release|x86
{21CC632C-B09A-4DB7-BD6E-7F7D2716F58F}.Release|x86.Build.0 = Release|x86
{B0E6D3AB-26F8-4A77-A7E1-D8024B8FFFCF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B0E6D3AB-26F8-4A77-A7E1-D8024B8FFFCF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B0E6D3AB-26F8-4A77-A7E1-D8024B8FFFCF}.Debug|ARM.ActiveCfg = Debug|Any CPU
{B0E6D3AB-26F8-4A77-A7E1-D8024B8FFFCF}.Debug|ARM.Build.0 = Debug|Any CPU
{B0E6D3AB-26F8-4A77-A7E1-D8024B8FFFCF}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{B0E6D3AB-26F8-4A77-A7E1-D8024B8FFFCF}.Debug|ARM64.Build.0 = Debug|Any CPU
{B0E6D3AB-26F8-4A77-A7E1-D8024B8FFFCF}.Debug|x64.ActiveCfg = Debug|Any CPU
{B0E6D3AB-26F8-4A77-A7E1-D8024B8FFFCF}.Debug|x64.Build.0 = Debug|Any CPU
{B0E6D3AB-26F8-4A77-A7E1-D8024B8FFFCF}.Debug|x86.ActiveCfg = Debug|Any CPU
{B0E6D3AB-26F8-4A77-A7E1-D8024B8FFFCF}.Debug|x86.Build.0 = Debug|Any CPU
{B0E6D3AB-26F8-4A77-A7E1-D8024B8FFFCF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B0E6D3AB-26F8-4A77-A7E1-D8024B8FFFCF}.Release|Any CPU.Build.0 = Release|Any CPU
{B0E6D3AB-26F8-4A77-A7E1-D8024B8FFFCF}.Release|ARM.ActiveCfg = Release|Any CPU
{B0E6D3AB-26F8-4A77-A7E1-D8024B8FFFCF}.Release|ARM.Build.0 = Release|Any CPU
{B0E6D3AB-26F8-4A77-A7E1-D8024B8FFFCF}.Release|ARM64.ActiveCfg = Release|Any CPU
{B0E6D3AB-26F8-4A77-A7E1-D8024B8FFFCF}.Release|ARM64.Build.0 = Release|Any CPU
{B0E6D3AB-26F8-4A77-A7E1-D8024B8FFFCF}.Release|x64.ActiveCfg = Release|Any CPU
{B0E6D3AB-26F8-4A77-A7E1-D8024B8FFFCF}.Release|x64.Build.0 = Release|Any CPU
{B0E6D3AB-26F8-4A77-A7E1-D8024B8FFFCF}.Release|x86.ActiveCfg = Release|x86
{B0E6D3AB-26F8-4A77-A7E1-D8024B8FFFCF}.Release|x86.Build.0 = Release|x86
{CF2D4EE4-0D11-404D-B800-C4DCFEC42588}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CF2D4EE4-0D11-404D-B800-C4DCFEC42588}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CF2D4EE4-0D11-404D-B800-C4DCFEC42588}.Debug|ARM.ActiveCfg = Debug|Any CPU
{CF2D4EE4-0D11-404D-B800-C4DCFEC42588}.Debug|ARM.Build.0 = Debug|Any CPU
{CF2D4EE4-0D11-404D-B800-C4DCFEC42588}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{CF2D4EE4-0D11-404D-B800-C4DCFEC42588}.Debug|ARM64.Build.0 = Debug|Any CPU
{CF2D4EE4-0D11-404D-B800-C4DCFEC42588}.Debug|x64.ActiveCfg = Debug|Any CPU
{CF2D4EE4-0D11-404D-B800-C4DCFEC42588}.Debug|x64.Build.0 = Debug|Any CPU
{CF2D4EE4-0D11-404D-B800-C4DCFEC42588}.Debug|x86.ActiveCfg = Debug|Any CPU
{CF2D4EE4-0D11-404D-B800-C4DCFEC42588}.Debug|x86.Build.0 = Debug|Any CPU
{CF2D4EE4-0D11-404D-B800-C4DCFEC42588}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CF2D4EE4-0D11-404D-B800-C4DCFEC42588}.Release|Any CPU.Build.0 = Release|Any CPU
{CF2D4EE4-0D11-404D-B800-C4DCFEC42588}.Release|ARM.ActiveCfg = Release|Any CPU
{CF2D4EE4-0D11-404D-B800-C4DCFEC42588}.Release|ARM.Build.0 = Release|Any CPU
{CF2D4EE4-0D11-404D-B800-C4DCFEC42588}.Release|ARM64.ActiveCfg = Release|Any CPU
{CF2D4EE4-0D11-404D-B800-C4DCFEC42588}.Release|ARM64.Build.0 = Release|Any CPU
{CF2D4EE4-0D11-404D-B800-C4DCFEC42588}.Release|x64.ActiveCfg = Release|Any CPU
{CF2D4EE4-0D11-404D-B800-C4DCFEC42588}.Release|x64.Build.0 = Release|Any CPU
{CF2D4EE4-0D11-404D-B800-C4DCFEC42588}.Release|x86.ActiveCfg = Release|x86
{CF2D4EE4-0D11-404D-B800-C4DCFEC42588}.Release|x86.Build.0 = Release|x86
{8341DE8C-5BC7-461F-B42D-AA2B72586A5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8341DE8C-5BC7-461F-B42D-AA2B72586A5C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8341DE8C-5BC7-461F-B42D-AA2B72586A5C}.Debug|ARM.ActiveCfg = Debug|Any CPU
{8341DE8C-5BC7-461F-B42D-AA2B72586A5C}.Debug|ARM.Build.0 = Debug|Any CPU
{8341DE8C-5BC7-461F-B42D-AA2B72586A5C}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{8341DE8C-5BC7-461F-B42D-AA2B72586A5C}.Debug|ARM64.Build.0 = Debug|Any CPU
{8341DE8C-5BC7-461F-B42D-AA2B72586A5C}.Debug|x64.ActiveCfg = Debug|Any CPU
{8341DE8C-5BC7-461F-B42D-AA2B72586A5C}.Debug|x64.Build.0 = Debug|Any CPU
{8341DE8C-5BC7-461F-B42D-AA2B72586A5C}.Debug|x86.ActiveCfg = Debug|Any CPU
{8341DE8C-5BC7-461F-B42D-AA2B72586A5C}.Debug|x86.Build.0 = Debug|Any CPU
{8341DE8C-5BC7-461F-B42D-AA2B72586A5C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8341DE8C-5BC7-461F-B42D-AA2B72586A5C}.Release|Any CPU.Build.0 = Release|Any CPU
{8341DE8C-5BC7-461F-B42D-AA2B72586A5C}.Release|ARM.ActiveCfg = Release|Any CPU
{8341DE8C-5BC7-461F-B42D-AA2B72586A5C}.Release|ARM.Build.0 = Release|Any CPU
{8341DE8C-5BC7-461F-B42D-AA2B72586A5C}.Release|ARM64.ActiveCfg = Release|Any CPU
{8341DE8C-5BC7-461F-B42D-AA2B72586A5C}.Release|ARM64.Build.0 = Release|Any CPU
{8341DE8C-5BC7-461F-B42D-AA2B72586A5C}.Release|x64.ActiveCfg = Release|Any CPU
{8341DE8C-5BC7-461F-B42D-AA2B72586A5C}.Release|x64.Build.0 = Release|Any CPU
{8341DE8C-5BC7-461F-B42D-AA2B72586A5C}.Release|x86.ActiveCfg = Release|x86
{8341DE8C-5BC7-461F-B42D-AA2B72586A5C}.Release|x86.Build.0 = Release|x86
{134FBC80-2E23-451B-A6B3-72B0AA2234F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{134FBC80-2E23-451B-A6B3-72B0AA2234F9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{134FBC80-2E23-451B-A6B3-72B0AA2234F9}.Debug|ARM.ActiveCfg = Debug|Any CPU
{134FBC80-2E23-451B-A6B3-72B0AA2234F9}.Debug|ARM.Build.0 = Debug|Any CPU
{134FBC80-2E23-451B-A6B3-72B0AA2234F9}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{134FBC80-2E23-451B-A6B3-72B0AA2234F9}.Debug|ARM64.Build.0 = Debug|Any CPU
{134FBC80-2E23-451B-A6B3-72B0AA2234F9}.Debug|x64.ActiveCfg = Debug|Any CPU
{134FBC80-2E23-451B-A6B3-72B0AA2234F9}.Debug|x64.Build.0 = Debug|Any CPU
{134FBC80-2E23-451B-A6B3-72B0AA2234F9}.Debug|x86.ActiveCfg = Debug|Any CPU
{134FBC80-2E23-451B-A6B3-72B0AA2234F9}.Debug|x86.Build.0 = Debug|Any CPU
{134FBC80-2E23-451B-A6B3-72B0AA2234F9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{134FBC80-2E23-451B-A6B3-72B0AA2234F9}.Release|Any CPU.Build.0 = Release|Any CPU
{134FBC80-2E23-451B-A6B3-72B0AA2234F9}.Release|ARM.ActiveCfg = Release|Any CPU
{134FBC80-2E23-451B-A6B3-72B0AA2234F9}.Release|ARM.Build.0 = Release|Any CPU
{134FBC80-2E23-451B-A6B3-72B0AA2234F9}.Release|ARM64.ActiveCfg = Release|Any CPU
{134FBC80-2E23-451B-A6B3-72B0AA2234F9}.Release|ARM64.Build.0 = Release|Any CPU
{134FBC80-2E23-451B-A6B3-72B0AA2234F9}.Release|x64.ActiveCfg = Release|Any CPU
{134FBC80-2E23-451B-A6B3-72B0AA2234F9}.Release|x64.Build.0 = Release|Any CPU
{134FBC80-2E23-451B-A6B3-72B0AA2234F9}.Release|x86.ActiveCfg = Release|x86
{134FBC80-2E23-451B-A6B3-72B0AA2234F9}.Release|x86.Build.0 = Release|x86
{85B2B7BB-BF95-42DF-8CBF-348AEF63BD1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{85B2B7BB-BF95-42DF-8CBF-348AEF63BD1F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{85B2B7BB-BF95-42DF-8CBF-348AEF63BD1F}.Debug|ARM.ActiveCfg = Debug|Any CPU
{85B2B7BB-BF95-42DF-8CBF-348AEF63BD1F}.Debug|ARM.Build.0 = Debug|Any CPU
{85B2B7BB-BF95-42DF-8CBF-348AEF63BD1F}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{85B2B7BB-BF95-42DF-8CBF-348AEF63BD1F}.Debug|ARM64.Build.0 = Debug|Any CPU
{85B2B7BB-BF95-42DF-8CBF-348AEF63BD1F}.Debug|x64.ActiveCfg = Debug|Any CPU
{85B2B7BB-BF95-42DF-8CBF-348AEF63BD1F}.Debug|x64.Build.0 = Debug|Any CPU
{85B2B7BB-BF95-42DF-8CBF-348AEF63BD1F}.Debug|x86.ActiveCfg = Debug|Any CPU
{85B2B7BB-BF95-42DF-8CBF-348AEF63BD1F}.Debug|x86.Build.0 = Debug|Any CPU
{85B2B7BB-BF95-42DF-8CBF-348AEF63BD1F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{85B2B7BB-BF95-42DF-8CBF-348AEF63BD1F}.Release|Any CPU.Build.0 = Release|Any CPU
{85B2B7BB-BF95-42DF-8CBF-348AEF63BD1F}.Release|ARM.ActiveCfg = Release|Any CPU
{85B2B7BB-BF95-42DF-8CBF-348AEF63BD1F}.Release|ARM.Build.0 = Release|Any CPU
{85B2B7BB-BF95-42DF-8CBF-348AEF63BD1F}.Release|ARM64.ActiveCfg = Release|Any CPU
{85B2B7BB-BF95-42DF-8CBF-348AEF63BD1F}.Release|ARM64.Build.0 = Release|Any CPU
{85B2B7BB-BF95-42DF-8CBF-348AEF63BD1F}.Release|x64.ActiveCfg = Release|Any CPU
{85B2B7BB-BF95-42DF-8CBF-348AEF63BD1F}.Release|x64.Build.0 = Release|Any CPU
{85B2B7BB-BF95-42DF-8CBF-348AEF63BD1F}.Release|x86.ActiveCfg = Release|x86
{85B2B7BB-BF95-42DF-8CBF-348AEF63BD1F}.Release|x86.Build.0 = Release|x86
{D3A1C1C8-6119-4827-AC24-1FF49FACFD4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D3A1C1C8-6119-4827-AC24-1FF49FACFD4D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D3A1C1C8-6119-4827-AC24-1FF49FACFD4D}.Debug|ARM.ActiveCfg = Debug|Any CPU
{D3A1C1C8-6119-4827-AC24-1FF49FACFD4D}.Debug|ARM.Build.0 = Debug|Any CPU
{D3A1C1C8-6119-4827-AC24-1FF49FACFD4D}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{D3A1C1C8-6119-4827-AC24-1FF49FACFD4D}.Debug|ARM64.Build.0 = Debug|Any CPU
{D3A1C1C8-6119-4827-AC24-1FF49FACFD4D}.Debug|x64.ActiveCfg = Debug|Any CPU
{D3A1C1C8-6119-4827-AC24-1FF49FACFD4D}.Debug|x64.Build.0 = Debug|Any CPU
{D3A1C1C8-6119-4827-AC24-1FF49FACFD4D}.Debug|x86.ActiveCfg = Debug|Any CPU
{D3A1C1C8-6119-4827-AC24-1FF49FACFD4D}.Debug|x86.Build.0 = Debug|Any CPU
{D3A1C1C8-6119-4827-AC24-1FF49FACFD4D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D3A1C1C8-6119-4827-AC24-1FF49FACFD4D}.Release|Any CPU.Build.0 = Release|Any CPU
{D3A1C1C8-6119-4827-AC24-1FF49FACFD4D}.Release|ARM.ActiveCfg = Release|Any CPU
{D3A1C1C8-6119-4827-AC24-1FF49FACFD4D}.Release|ARM.Build.0 = Release|Any CPU
{D3A1C1C8-6119-4827-AC24-1FF49FACFD4D}.Release|ARM64.ActiveCfg = Release|Any CPU
{D3A1C1C8-6119-4827-AC24-1FF49FACFD4D}.Release|ARM64.Build.0 = Release|Any CPU
{D3A1C1C8-6119-4827-AC24-1FF49FACFD4D}.Release|x64.ActiveCfg = Release|Any CPU
{D3A1C1C8-6119-4827-AC24-1FF49FACFD4D}.Release|x64.Build.0 = Release|Any CPU
{D3A1C1C8-6119-4827-AC24-1FF49FACFD4D}.Release|x86.ActiveCfg = Release|x86
{D3A1C1C8-6119-4827-AC24-1FF49FACFD4D}.Release|x86.Build.0 = Release|x86
{6AC9C0BE-6BCE-493F-BD80-6F2247CB669D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6AC9C0BE-6BCE-493F-BD80-6F2247CB669D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6AC9C0BE-6BCE-493F-BD80-6F2247CB669D}.Debug|ARM.ActiveCfg = Debug|Any CPU
{6AC9C0BE-6BCE-493F-BD80-6F2247CB669D}.Debug|ARM.Build.0 = Debug|Any CPU
{6AC9C0BE-6BCE-493F-BD80-6F2247CB669D}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{6AC9C0BE-6BCE-493F-BD80-6F2247CB669D}.Debug|ARM64.Build.0 = Debug|Any CPU
{6AC9C0BE-6BCE-493F-BD80-6F2247CB669D}.Debug|x64.ActiveCfg = Debug|Any CPU
{6AC9C0BE-6BCE-493F-BD80-6F2247CB669D}.Debug|x64.Build.0 = Debug|Any CPU
{6AC9C0BE-6BCE-493F-BD80-6F2247CB669D}.Debug|x86.ActiveCfg = Debug|Any CPU
{6AC9C0BE-6BCE-493F-BD80-6F2247CB669D}.Debug|x86.Build.0 = Debug|Any CPU
{6AC9C0BE-6BCE-493F-BD80-6F2247CB669D}.Release|Any CPU.ActiveCfg = Debug|Any CPU
{6AC9C0BE-6BCE-493F-BD80-6F2247CB669D}.Release|Any CPU.Build.0 = Debug|Any CPU
{6AC9C0BE-6BCE-493F-BD80-6F2247CB669D}.Release|ARM.ActiveCfg = Release|Any CPU
{6AC9C0BE-6BCE-493F-BD80-6F2247CB669D}.Release|ARM.Build.0 = Release|Any CPU
{6AC9C0BE-6BCE-493F-BD80-6F2247CB669D}.Release|ARM64.ActiveCfg = Release|Any CPU
{6AC9C0BE-6BCE-493F-BD80-6F2247CB669D}.Release|ARM64.Build.0 = Release|Any CPU
{6AC9C0BE-6BCE-493F-BD80-6F2247CB669D}.Release|x64.ActiveCfg = Release|Any CPU
{6AC9C0BE-6BCE-493F-BD80-6F2247CB669D}.Release|x64.Build.0 = Release|Any CPU
{6AC9C0BE-6BCE-493F-BD80-6F2247CB669D}.Release|x86.ActiveCfg = Release|x86
{6AC9C0BE-6BCE-493F-BD80-6F2247CB669D}.Release|x86.Build.0 = Release|x86
{C9B82A4F-8306-41A9-91DA-1BA5080F1DB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C9B82A4F-8306-41A9-91DA-1BA5080F1DB0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C9B82A4F-8306-41A9-91DA-1BA5080F1DB0}.Debug|ARM.ActiveCfg = Debug|Any CPU
{C9B82A4F-8306-41A9-91DA-1BA5080F1DB0}.Debug|ARM.Build.0 = Debug|Any CPU
{C9B82A4F-8306-41A9-91DA-1BA5080F1DB0}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{C9B82A4F-8306-41A9-91DA-1BA5080F1DB0}.Debug|ARM64.Build.0 = Debug|Any CPU
{C9B82A4F-8306-41A9-91DA-1BA5080F1DB0}.Debug|x64.ActiveCfg = Debug|Any CPU
{C9B82A4F-8306-41A9-91DA-1BA5080F1DB0}.Debug|x64.Build.0 = Debug|Any CPU
{C9B82A4F-8306-41A9-91DA-1BA5080F1DB0}.Debug|x86.ActiveCfg = Debug|Any CPU
{C9B82A4F-8306-41A9-91DA-1BA5080F1DB0}.Debug|x86.Build.0 = Debug|Any CPU
{C9B82A4F-8306-41A9-91DA-1BA5080F1DB0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C9B82A4F-8306-41A9-91DA-1BA5080F1DB0}.Release|Any CPU.Build.0 = Release|Any CPU
{C9B82A4F-8306-41A9-91DA-1BA5080F1DB0}.Release|ARM.ActiveCfg = Release|Any CPU
{C9B82A4F-8306-41A9-91DA-1BA5080F1DB0}.Release|ARM.Build.0 = Release|Any CPU
{C9B82A4F-8306-41A9-91DA-1BA5080F1DB0}.Release|ARM64.ActiveCfg = Release|Any CPU
{C9B82A4F-8306-41A9-91DA-1BA5080F1DB0}.Release|ARM64.Build.0 = Release|Any CPU
{C9B82A4F-8306-41A9-91DA-1BA5080F1DB0}.Release|x64.ActiveCfg = Release|Any CPU
{C9B82A4F-8306-41A9-91DA-1BA5080F1DB0}.Release|x64.Build.0 = Release|Any CPU
{C9B82A4F-8306-41A9-91DA-1BA5080F1DB0}.Release|x86.ActiveCfg = Release|x86
{C9B82A4F-8306-41A9-91DA-1BA5080F1DB0}.Release|x86.Build.0 = Release|x86
{44D46916-891F-435F-B914-AE8AC80613FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{44D46916-891F-435F-B914-AE8AC80613FD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{44D46916-891F-435F-B914-AE8AC80613FD}.Debug|ARM.ActiveCfg = Debug|Any CPU
{44D46916-891F-435F-B914-AE8AC80613FD}.Debug|ARM.Build.0 = Debug|Any CPU
{44D46916-891F-435F-B914-AE8AC80613FD}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{44D46916-891F-435F-B914-AE8AC80613FD}.Debug|ARM64.Build.0 = Debug|Any CPU
{44D46916-891F-435F-B914-AE8AC80613FD}.Debug|x64.ActiveCfg = Debug|Any CPU
{44D46916-891F-435F-B914-AE8AC80613FD}.Debug|x64.Build.0 = Debug|Any CPU
{44D46916-891F-435F-B914-AE8AC80613FD}.Debug|x86.ActiveCfg = Debug|Any CPU
{44D46916-891F-435F-B914-AE8AC80613FD}.Debug|x86.Build.0 = Debug|Any CPU
{44D46916-891F-435F-B914-AE8AC80613FD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{44D46916-891F-435F-B914-AE8AC80613FD}.Release|Any CPU.Build.0 = Release|Any CPU
{44D46916-891F-435F-B914-AE8AC80613FD}.Release|ARM.ActiveCfg = Release|Any CPU
{44D46916-891F-435F-B914-AE8AC80613FD}.Release|ARM.Build.0 = Release|Any CPU
{44D46916-891F-435F-B914-AE8AC80613FD}.Release|ARM64.ActiveCfg = Release|Any CPU
{44D46916-891F-435F-B914-AE8AC80613FD}.Release|ARM64.Build.0 = Release|Any CPU
{44D46916-891F-435F-B914-AE8AC80613FD}.Release|x64.ActiveCfg = Release|Any CPU
{44D46916-891F-435F-B914-AE8AC80613FD}.Release|x64.Build.0 = Release|Any CPU
{44D46916-891F-435F-B914-AE8AC80613FD}.Release|x86.ActiveCfg = Release|x86
{44D46916-891F-435F-B914-AE8AC80613FD}.Release|x86.Build.0 = Release|x86
{08819B49-02B8-4F93-A143-F9B0461CEA64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{08819B49-02B8-4F93-A143-F9B0461CEA64}.Debug|Any CPU.Build.0 = Debug|Any CPU
{08819B49-02B8-4F93-A143-F9B0461CEA64}.Debug|ARM.ActiveCfg = Debug|Any CPU
{08819B49-02B8-4F93-A143-F9B0461CEA64}.Debug|ARM.Build.0 = Debug|Any CPU
{08819B49-02B8-4F93-A143-F9B0461CEA64}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{08819B49-02B8-4F93-A143-F9B0461CEA64}.Debug|ARM64.Build.0 = Debug|Any CPU
{08819B49-02B8-4F93-A143-F9B0461CEA64}.Debug|x64.ActiveCfg = Debug|Any CPU
{08819B49-02B8-4F93-A143-F9B0461CEA64}.Debug|x64.Build.0 = Debug|Any CPU
{08819B49-02B8-4F93-A143-F9B0461CEA64}.Debug|x86.ActiveCfg = Debug|Any CPU
{08819B49-02B8-4F93-A143-F9B0461CEA64}.Debug|x86.Build.0 = Debug|Any CPU
{08819B49-02B8-4F93-A143-F9B0461CEA64}.Release|Any CPU.ActiveCfg = Release|Any CPU
{08819B49-02B8-4F93-A143-F9B0461CEA64}.Release|Any CPU.Build.0 = Release|Any CPU
{08819B49-02B8-4F93-A143-F9B0461CEA64}.Release|ARM.ActiveCfg = Release|Any CPU
{08819B49-02B8-4F93-A143-F9B0461CEA64}.Release|ARM.Build.0 = Release|Any CPU
{08819B49-02B8-4F93-A143-F9B0461CEA64}.Release|ARM64.ActiveCfg = Release|Any CPU
{08819B49-02B8-4F93-A143-F9B0461CEA64}.Release|ARM64.Build.0 = Release|Any CPU
{08819B49-02B8-4F93-A143-F9B0461CEA64}.Release|x64.ActiveCfg = Release|Any CPU
{08819B49-02B8-4F93-A143-F9B0461CEA64}.Release|x64.Build.0 = Release|Any CPU
{08819B49-02B8-4F93-A143-F9B0461CEA64}.Release|x86.ActiveCfg = Release|x86
{08819B49-02B8-4F93-A143-F9B0461CEA64}.Release|x86.Build.0 = Release|x86
{B1427E8D-9175-42BE-8B90-A5A9CB4AAD51}.Debug|Any CPU.ActiveCfg = Debug|x86
{B1427E8D-9175-42BE-8B90-A5A9CB4AAD51}.Debug|ARM.ActiveCfg = Debug|ARM
{B1427E8D-9175-42BE-8B90-A5A9CB4AAD51}.Debug|ARM.Build.0 = Debug|ARM
{B1427E8D-9175-42BE-8B90-A5A9CB4AAD51}.Debug|ARM.Deploy.0 = Debug|ARM
{B1427E8D-9175-42BE-8B90-A5A9CB4AAD51}.Debug|ARM64.ActiveCfg = Debug|ARM64
{B1427E8D-9175-42BE-8B90-A5A9CB4AAD51}.Debug|ARM64.Build.0 = Debug|ARM64
{B1427E8D-9175-42BE-8B90-A5A9CB4AAD51}.Debug|ARM64.Deploy.0 = Debug|ARM64
{B1427E8D-9175-42BE-8B90-A5A9CB4AAD51}.Debug|x64.ActiveCfg = Debug|x64
{B1427E8D-9175-42BE-8B90-A5A9CB4AAD51}.Debug|x64.Build.0 = Debug|x64
{B1427E8D-9175-42BE-8B90-A5A9CB4AAD51}.Debug|x64.Deploy.0 = Debug|x64
{B1427E8D-9175-42BE-8B90-A5A9CB4AAD51}.Debug|x86.ActiveCfg = Debug|x86
{B1427E8D-9175-42BE-8B90-A5A9CB4AAD51}.Debug|x86.Build.0 = Debug|x86
{B1427E8D-9175-42BE-8B90-A5A9CB4AAD51}.Debug|x86.Deploy.0 = Debug|x86
{B1427E8D-9175-42BE-8B90-A5A9CB4AAD51}.Release|Any CPU.ActiveCfg = Release|x86
{B1427E8D-9175-42BE-8B90-A5A9CB4AAD51}.Release|ARM.ActiveCfg = Release|ARM
{B1427E8D-9175-42BE-8B90-A5A9CB4AAD51}.Release|ARM.Build.0 = Release|ARM
{B1427E8D-9175-42BE-8B90-A5A9CB4AAD51}.Release|ARM.Deploy.0 = Release|ARM
{B1427E8D-9175-42BE-8B90-A5A9CB4AAD51}.Release|ARM64.ActiveCfg = Release|ARM64
{B1427E8D-9175-42BE-8B90-A5A9CB4AAD51}.Release|ARM64.Build.0 = Release|ARM64
{B1427E8D-9175-42BE-8B90-A5A9CB4AAD51}.Release|ARM64.Deploy.0 = Release|ARM64
{B1427E8D-9175-42BE-8B90-A5A9CB4AAD51}.Release|x64.ActiveCfg = Release|x64
{B1427E8D-9175-42BE-8B90-A5A9CB4AAD51}.Release|x64.Build.0 = Release|x64
{B1427E8D-9175-42BE-8B90-A5A9CB4AAD51}.Release|x64.Deploy.0 = Release|x64
{B1427E8D-9175-42BE-8B90-A5A9CB4AAD51}.Release|x86.ActiveCfg = Release|x86
{B1427E8D-9175-42BE-8B90-A5A9CB4AAD51}.Release|x86.Build.0 = Release|x86
{B1427E8D-9175-42BE-8B90-A5A9CB4AAD51}.Release|x86.Deploy.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {6A6764EF-3A8F-46BF-8CC8-C07DE889160A}
EndGlobalSection
GlobalSection(TestCaseManagementSettings) = postSolution
CategoryFile = Esent.vsmdi
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<TestLists xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010">
<TestList name="Lists of Tests" id="8c43106b-9dc1-4907-a29f-aa66a61bf5b6">
<RunConfiguration id="6c3d561f-b13d-4563-9e69-90f00c61747b" name="Normal" storage="normal.testrunconfig" type="Microsoft.VisualStudio.TestTools.Common.TestRunConfiguration, Microsoft.VisualStudio.QualityTools.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</TestList>
</TestLists>

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="utf-8"?><ItemProperties xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><Properties><Property><Name>svn:mime-type</Name><Value>application/octet-stream</Value></Property></Properties></ItemProperties>

View File

@ -0,0 +1,82 @@
//-----------------------------------------------------------------------
// <copyright file="AssemblyInfo.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
using System;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("EsentInterop")]
[assembly: AssemblyDescription("Managed interop code for esent.dll")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Microsoft")]
[assembly: AssemblyProduct("EsentInterop")]
[assembly: AssemblyCopyright("Copyright (c) Microsoft")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
[assembly: CLSCompliant(true)]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
//
// Version history:
// 1.6.0.0
// 1.7.0.0
// 1.8.0.0 Support new Windows user interface (As of Win8 Beta build).
// 1.8.1.0 2012.11.18. Some minor updates, including some perf updates.
// 1.8.2.0 2012.11.19. Signed.
// 1.8.3.0 2013.03.25. Signed and Strong Named. Renamed 'Metro' to 'Wsa' (Windows Store App)
// 1.8.4.0 2013.12.23. Updated for Windows 8.1.
// 1.9.0.0 2013.12.23. Go back to targetting framework 4.0.
// 1.9.1.0 2014.07.18. PersistentDictionary gets binary blobs; added Isam layer.
// 1.9.2.0 2014.09.11. Isam is placed in the Microsoft.Database namespace.
// 1.9.3.0 2015.08.11. Dependence added from Collections to Isam dll for configsets.
// 1.9.3.2 2015.09.02. Some bug fixes; go back to Framework 4.0
// 1.9.3.3 2016.03.01. Some bug and perf fixes.
// 1.9.4 2016.06.28. Some bug fixes.
// 1.9.4.1 2017.08.30. Adding JetGetIndexInfo that returns JET_INDEXCREATE.
[assembly: AssemblyVersion("1.9.4.1")]
[assembly: AssemblyFileVersion("1.9.4.1")]
#if STRONG_NAMED
[assembly: InternalsVisibleTo("EsentInteropWsaTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100B5FC90E7027F67871E773A8FDE8938C81DD402BA65B9201D60593E96C492651E889CC13F1415EBB53FAC1131AE0BD333C5EE6021672D9718EA31A8AEBD0DA0072F25D87DBA6FC90FFD598ED4DA35E44C398C454307E8E33B8426143DAEC9F596836F97C8F74750E5975C64E2189F45DEF46B2A2B1247ADC3652BF5C308055DA9")]
[assembly: InternalsVisibleTo("Esent.Isam, PublicKey=0024000004800000940000000602000000240000525341310004000001000100B5FC90E7027F67871E773A8FDE8938C81DD402BA65B9201D60593E96C492651E889CC13F1415EBB53FAC1131AE0BD333C5EE6021672D9718EA31A8AEBD0DA0072F25D87DBA6FC90FFD598ED4DA35E44C398C454307E8E33B8426143DAEC9F596836F97C8F74750E5975C64E2189F45DEF46B2A2B1247ADC3652BF5C308055DA9")]
[assembly: InternalsVisibleTo("InteropApiTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100B5FC90E7027F67871E773A8FDE8938C81DD402BA65B9201D60593E96C492651E889CC13F1415EBB53FAC1131AE0BD333C5EE6021672D9718EA31A8AEBD0DA0072F25D87DBA6FC90FFD598ED4DA35E44C398C454307E8E33B8426143DAEC9F596836F97C8F74750E5975C64E2189F45DEF46B2A2B1247ADC3652BF5C308055DA9")]
[assembly: InternalsVisibleTo("IsamUnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100B5FC90E7027F67871E773A8FDE8938C81DD402BA65B9201D60593E96C492651E889CC13F1415EBB53FAC1131AE0BD333C5EE6021672D9718EA31A8AEBD0DA0072F25D87DBA6FC90FFD598ED4DA35E44C398C454307E8E33B8426143DAEC9F596836F97C8F74750E5975C64E2189F45DEF46B2A2B1247ADC3652BF5C308055DA9")]
[assembly: InternalsVisibleTo("Pixie, PublicKey=0024000004800000940000000602000000240000525341310004000001000100B5FC90E7027F67871E773A8FDE8938C81DD402BA65B9201D60593E96C492651E889CC13F1415EBB53FAC1131AE0BD333C5EE6021672D9718EA31A8AEBD0DA0072F25D87DBA6FC90FFD598ED4DA35E44C398C454307E8E33B8426143DAEC9F596836F97C8F74750E5975C64E2189F45DEF46B2A2B1247ADC3652BF5C308055DA9")]
[assembly: InternalsVisibleTo("PixieTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100B5FC90E7027F67871E773A8FDE8938C81DD402BA65B9201D60593E96C492651E889CC13F1415EBB53FAC1131AE0BD333C5EE6021672D9718EA31A8AEBD0DA0072F25D87DBA6FC90FFD598ED4DA35E44C398C454307E8E33B8426143DAEC9F596836F97C8F74750E5975C64E2189F45DEF46B2A2B1247ADC3652BF5C308055DA9")]
// This assembly is generated by Rhino.Mocks
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2,PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
#else
[assembly: InternalsVisibleTo("InteropApiTests")]
[assembly: InternalsVisibleTo("IsamUnitTests")]
[assembly: InternalsVisibleTo("EsentInteropTestsImmersive")]
[assembly: InternalsVisibleTo("EsentInteropWsaTests")]
[assembly: InternalsVisibleTo("Esent.Isam")]
[assembly: InternalsVisibleTo("Pixie")]
[assembly: InternalsVisibleTo("PixieTests")]
// This assembly is generated by Rhino.Mocks
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
#endif

View File

@ -0,0 +1,37 @@
//-----------------------------------------------------------------------
// <copyright file="CallbackDataConverter.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// Methods to convert data objects used in callbacks.
/// </summary>
internal static class CallbackDataConverter
{
/// <summary>
/// Get the managed data object from the unmanaged data.
/// </summary>
/// <param name="nativeData">The native data.</param>
/// <param name="snp">The SNP (used to determine the type of object).</param>
/// <param name="snt">The SNT (used to determine the type of object).</param>
/// <returns>The managed data object.</returns>
public static object GetManagedData(IntPtr nativeData, JET_SNP snp, JET_SNT snt)
{
if (IntPtr.Zero != nativeData && JET_SNT.Progress == snt)
{
NATIVE_SNPROG native = (NATIVE_SNPROG)Marshal.PtrToStructure(nativeData, typeof(NATIVE_SNPROG));
JET_SNPROG managed = new JET_SNPROG();
managed.SetFromNative(native);
return managed;
}
return null;
}
}
}

View File

@ -0,0 +1,263 @@
//-----------------------------------------------------------------------
// <copyright file="EsentImplementationStubs.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
// <summary>
// Class stubs to allow compiling on CoreClr.
// </summary>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop.Implementation
{
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Text;
/// <summary>
/// A fake class to allow compilation on platforms that lack this functionality.
/// </summary>
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:FileMayOnlyContainASingleClass",
Justification = "Reviewed. Suppression is OK here because it's a collection of trivial classes.")]
public class Trace
{
/// <summary>
/// A fake function to allow compilation on platforms that lack this functionality.
/// </summary>
/// <param name="condition">
/// The condition.
/// </param>
/// <param name="message">
/// The message.
/// </param>
[ConditionalAttribute("TRACE")]
public static void WriteLineIf(bool condition, string message)
{
}
/// <summary>
/// A fake function to allow compilation on platforms that lack this functionality.
/// </summary>
/// <param name="condition">
/// The condition.
/// </param>
/// <param name="message">
/// The message.
/// </param>
[ConditionalAttribute("TRACE")]
public static void WriteLineIf(bool condition, object message)
{
}
/// <summary>
/// Prints out the object's contents.
/// </summary>
/// <returns>A string represenetation or the object.</returns>
public override string ToString()
{
return base.ToString();
}
}
/// <summary>
/// A fake class to allow compilation on platforms that lack this class.
/// </summary>
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:FileMayOnlyContainASingleClass",
Justification = "Reviewed. Suppression is OK here because it's a collection of trivial classes.")]
internal static class RuntimeHelpers
{
/// <summary>
/// A fake function to allow compilation on platforms that lack this functionality.
/// </summary>
public static void PrepareConstrainedRegions()
{
}
/// <summary>
/// A fake function to allow compilation on platforms that lack this functionality.
/// </summary>
/// <param name="method">
/// The method.
/// </param>
public static void PrepareMethod(RuntimeMethodHandle method)
{
}
}
/// <summary>
/// Ascii encoding is not available on Core Clr. But UTF-8 is.
/// This class will reject any character that results in an
/// extended value.
/// </summary>
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:FileMayOnlyContainASingleClass",
Justification = "Reviewed. Suppression is OK here because it's a collection of trivial classes.")]
internal class SlowAsciiEncoding : UTF8Encoding
{
/// <summary>
/// The standard encoding object.
/// </summary>
private static SlowAsciiEncoding slowAsciiEncoding = new SlowAsciiEncoding();
/// <summary>
/// Gets an Encoding object.
/// </summary>
public static Encoding Encoding
{
get
{
return slowAsciiEncoding;
}
}
#if !MANAGEDESENT_ON_WSA
/// <summary>
/// Converts a string to the byte representation.
/// </summary>
/// <param name="chars">
/// The chars.
/// </param>
/// <param name="charCount">
/// The char count.
/// </param>
/// <param name="bytes">
/// The bytes.
/// </param>
/// <param name="byteCount">
/// The byte count.
/// </param>
/// <returns>
/// A count of bytes stored.
/// </returns>
public override unsafe int GetBytes(char* chars, int charCount, byte* bytes, int byteCount)
{
IntPtr toFree;
char* charsToTranslate = this.SanitizeString(chars, charCount, out toFree);
int toReturn = base.GetBytes(charsToTranslate, charCount, bytes, byteCount);
LibraryHelpers.MarshalFreeHGlobal(toFree);
return toReturn;
}
#endif
/// <summary>
/// Converts a string to the byte representation.
/// </summary>
/// <param name="inputString">
/// The input string.
/// </param>
/// <returns>
/// The byte representation of the string.
/// </returns>
public override byte[] GetBytes(string inputString)
{
string stringToTranslate = this.SanitizeString(inputString);
return base.GetBytes(stringToTranslate);
}
/// <summary>
/// Converts a string to the byte representation.
/// </summary>
/// <param name="inputString">
/// The input string.
/// </param>
/// <param name="charIndex">
/// The char index.
/// </param>
/// <param name="charCount">
/// The char count.
/// </param>
/// <param name="bytes">
/// The bytes.
/// </param>
/// <param name="byteIndex">
/// The byte index.
/// </param>
/// <returns>
/// The byte representation of the string.
/// </returns>
public override int GetBytes(string inputString, int charIndex, int charCount, byte[] bytes, int byteIndex)
{
string stringToTranslate = this.SanitizeString(inputString);
return base.GetBytes(stringToTranslate, charIndex, charCount, bytes, byteIndex);
}
/// <summary>
/// Scans the string looking for unmappable characters in the ASCII set, and replaces
/// them with '?'.
/// </summary>
/// <param name="inputString">A unicode string with unknown characters.</param>
/// <returns>A string that has all legal ASCII characters.</returns>
private string SanitizeString(string inputString)
{
bool needToDuplicate = false;
string returnString = inputString;
foreach (char ch in inputString)
{
if (ch > 127)
{
needToDuplicate = true;
break;
}
}
if (needToDuplicate)
{
StringBuilder sb = new StringBuilder(inputString.Length);
foreach (char ch in inputString)
{
sb.Append(ch > 127 ? '?' : ch);
}
returnString = sb.ToString();
}
return returnString;
}
#if !MANAGEDESENT_ON_WSA
/// <summary>
/// Scans the string looking for unmappable characters in the ASCII set, and replaces
/// them with '?'.
/// </summary>
/// <param name="inputString">A unicode string with unknown characters.</param>
/// <param name="charCount">The length of the string to sanitize.</param>
/// <param name="allocedMemory">On output, a value that needs to be freed. Only used
/// if there are any untranslaable characters.</param>
/// <returns>A string that has all legal ASCII characters.</returns>
private unsafe char* SanitizeString(char* inputString, int charCount, out IntPtr allocedMemory)
{
allocedMemory = IntPtr.Zero;
bool needToDuplicate = false;
char* returnString = inputString;
for (int i = 0; i < charCount; ++i)
{
if (inputString[i] > 127)
{
needToDuplicate = true;
break;
}
}
if (needToDuplicate)
{
allocedMemory = LibraryHelpers.MarshalAllocHGlobal(charCount);
returnString = (char*)allocedMemory;
char* dest = returnString;
for (int i = 0; i < charCount; ++i)
{
dest[i] = inputString[i] > 127 ? '?' : inputString[i];
}
}
return returnString;
}
#endif
}
}

View File

@ -0,0 +1,157 @@
//-----------------------------------------------------------------------
// <copyright file="EsentJetApi.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
// <summary>
// JetApi code that is specific to ESENT.
// </summary>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop.Implementation
{
using System;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Threading;
/// <summary>
/// JetApi code that is specific to ESENT.
/// </summary>
internal sealed partial class JetApi
{
/// <summary>
/// Reports the exception to a central authority.
/// </summary>
/// <param name="exception">An unhandled exception.</param>
/// <param name="description">A string description of the scenario.</param>
internal static void ReportUnhandledException(
Exception exception,
string description)
{
}
/// <summary>
/// Calculates the capabilities of the current Esent version.
/// </summary>
private void DetermineCapabilities()
{
const int Server2003BuildNumber = 2700;
const int VistaBuildNumber = 6000;
const int Windows7BuildNumber = 7000; // includes beta as well as RTM (RTM is 7600)
const int Windows8BuildNumber = 8000; // includes beta as well as RTM (RTM is 9200)
const int Windows81BuildNumber = 9300; // includes beta as well as RTM (RTM is 9600)
const int Windows10BuildNumber = 9900; // includes beta as well as RTM (RTM is 10240)
// Create new capabilities, set as all false. This will allow
// us to call into Esent.
this.Capabilities = new JetCapabilities { ColumnsKeyMost = 12 };
var version = this.versionOverride;
if (version == 0)
{
version = this.GetVersionFromEsent();
}
var buildNumber = (int)((version & 0xFFFFFF) >> 8);
Trace.WriteLineIf(
TraceSwitch.TraceVerbose,
string.Format(CultureInfo.InvariantCulture, "Version = {0}, BuildNumber = {1}", version, buildNumber));
if (buildNumber >= Server2003BuildNumber)
{
Trace.WriteLineIf(TraceSwitch.TraceVerbose, "Supports Server 2003 features");
this.Capabilities.SupportsServer2003Features = true;
}
if (buildNumber >= VistaBuildNumber)
{
Trace.WriteLineIf(TraceSwitch.TraceVerbose, "Supports Vista features");
this.Capabilities.SupportsVistaFeatures = true;
Trace.WriteLineIf(TraceSwitch.TraceVerbose, "Supports Unicode paths");
this.Capabilities.SupportsUnicodePaths = true;
Trace.WriteLineIf(TraceSwitch.TraceVerbose, "Supports large keys");
this.Capabilities.SupportsLargeKeys = true;
Trace.WriteLineIf(TraceSwitch.TraceVerbose, "Supports 16-column keys");
this.Capabilities.ColumnsKeyMost = 16;
}
if (buildNumber >= Windows7BuildNumber)
{
Trace.WriteLineIf(TraceSwitch.TraceVerbose, "Supports Windows 7 features");
this.Capabilities.SupportsWindows7Features = true;
}
if (buildNumber >= Windows8BuildNumber)
{
Trace.WriteLineIf(TraceSwitch.TraceVerbose, "Supports Windows 8 features");
this.Capabilities.SupportsWindows8Features = true;
}
if (buildNumber >= Windows81BuildNumber)
{
Trace.WriteLineIf(TraceSwitch.TraceVerbose, "Supports Windows 8.1 features");
this.Capabilities.SupportsWindows81Features = true;
}
if (buildNumber >= Windows10BuildNumber)
{
Trace.WriteLineIf(TraceSwitch.TraceVerbose, "Supports Windows 10 features");
this.Capabilities.SupportsWindows10Features = true;
}
}
/// <summary>
/// Create an instance and get the current version of Esent.
/// </summary>
/// <returns>The current version of Esent.</returns>
private uint GetVersionFromEsent()
{
#if MANAGEDESENT_ON_WSA
// JetGetVersion isn't available in new Windows user interface, so we'll pretend it's always Win8:
return 8250 << 8;
#else
// Create a unique name so that multiple threads can call this simultaneously.
// This can happen if there are multiple AppDomains.
string instanceName = string.Format(CultureInfo.InvariantCulture, "GettingEsentVersion{0}", LibraryHelpers.GetCurrentManagedThreadId());
JET_INSTANCE instance = JET_INSTANCE.Nil;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
this.JetCreateInstance(out instance, instanceName);
this.JetSetSystemParameter(instance, JET_SESID.Nil, JET_param.Recovery, new IntPtr(0), "off");
this.JetSetSystemParameter(instance, JET_SESID.Nil, JET_param.NoInformationEvent, new IntPtr(1), null);
this.JetSetSystemParameter(instance, JET_SESID.Nil, JET_param.MaxTemporaryTables, new IntPtr(0), null);
this.JetSetSystemParameter(instance, JET_SESID.Nil, JET_param.MaxCursors, new IntPtr(16), null);
this.JetSetSystemParameter(instance, JET_SESID.Nil, JET_param.MaxOpenTables, new IntPtr(16), null);
this.JetSetSystemParameter(instance, JET_SESID.Nil, JET_param.MaxVerPages, new IntPtr(4), null);
this.JetSetSystemParameter(instance, JET_SESID.Nil, JET_param.MaxSessions, new IntPtr(1), null);
this.JetInit(ref instance);
JET_SESID sesid;
this.JetBeginSession(instance, out sesid, string.Empty, string.Empty);
try
{
uint version;
this.JetGetVersion(sesid, out version);
return version;
}
finally
{
this.JetEndSession(sesid, EndSessionGrbit.None);
}
}
finally
{
if (JET_INSTANCE.Nil != instance)
{
this.JetTerm(instance);
}
}
#endif
}
}
}

View File

@ -0,0 +1,22 @@
//-----------------------------------------------------------------------
// <copyright file="EsentNativeMethods.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
// <summary>
// NativeMethods code that is specific to ESENT.
// </summary>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop.Implementation
{
/// <summary>
/// Configuration for functions in esent.dll.
/// </summary>
internal static partial class NativeMethods
{
/// <summary>
/// The name of the DLL that the methods should be loaded from.
/// </summary>
private const string EsentDll = "esent.dll";
}
}

View File

@ -0,0 +1,325 @@
//-----------------------------------------------------------------------
// <copyright file="EsentStubAttributes.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
// <summary>
// Attribute stubs to allow compiling on CoreClr.
// </summary>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
using System.Diagnostics.CodeAnalysis;
#if !MANAGEDESENT_ON_WSA
This file should only be compiled with MANAGEDESENT_ON_WSA
#endif
/// <summary>
/// A fake enumeration to allow compilation on platforms that lack this enumeration.
/// </summary>
public enum SecurityAction
{
/// <summary>
/// A fake enumeration to allow compilation on platforms that lack this enumeration.
/// </summary>
LinkDemand
}
/// <summary>
/// A fake attribute to allow compilation on platforms that lack this attribute.
/// </summary>
//// The real one inherits from System.Security.Permissions.CodeAccessSecurityAttribute.
[SerializableAttribute]
[ComVisibleAttribute(true)]
[AttributeUsageAttribute(
AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Constructor
| AttributeTargets.Method, AllowMultiple = true, Inherited = false)]
internal sealed class SecurityPermissionAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="SecurityPermissionAttribute"/> class.
/// </summary>
/// <param name="action">
/// The action.
/// </param>
public SecurityPermissionAttribute(
SecurityAction action)
{
}
/// <summary>
/// Prints out the object's contents.
/// </summary>
/// <returns>A string represenetation or the object.</returns>
public override string ToString()
{
return base.ToString();
}
}
/// <summary>
/// A fake attribute to allow compilation on platforms that lack this attribute.
/// </summary>
[ComVisibleAttribute(true)]
[AttributeUsageAttribute(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, Inherited = false)]
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:FileMayOnlyContainASingleClass",
Justification = "Reviewed. Suppression is OK here because it's a collection of trivial classes.")]
[SuppressMessage(
"Microsoft.StyleCop.CSharp.MaintainabilityRules",
"SA1402:FileMayOnlyContainASingleClass",
Justification = "These stub classes are compiled only on some platforms that do not contain the entire framework, e.g. new Windows user interface.")]
internal sealed class BestFitMappingAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="BestFitMappingAttribute"/> class.
/// </summary>
/// <param name="bestFitMapping">
/// The best fit mapping.
/// </param>
public BestFitMappingAttribute(
bool bestFitMapping)
{
}
/// <summary>
/// Gets or sets a value indicating whether ThrowOnUnmappableChar.
/// </summary>
public bool ThrowOnUnmappableChar
{
get;
set;
}
/// <summary>
/// Prints out the object's contents.
/// </summary>
/// <returns>A string represenetation or the object.</returns>
public override string ToString()
{
return base.ToString();
}
}
/// <summary>
/// A fake attribute to allow compilation on platforms that lack this attribute.
/// </summary>
[ComVisibleAttribute(true)]
[AttributeUsageAttribute(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = true,
Inherited = false)]
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:FileMayOnlyContainASingleClass",
Justification = "Reviewed. Suppression is OK here because it's a collection of trivial classes.")]
[SuppressMessage(
"Microsoft.StyleCop.CSharp.MaintainabilityRules",
"SA1402:FileMayOnlyContainASingleClass",
Justification = "These stub classes are compiled only on some platforms that do not contain the entire framework, e.g. new Windows user interface.")]
internal sealed class SuppressUnmanagedCodeSecurityAttribute : Attribute
{
/// <summary>
/// Prints out the object's contents.
/// </summary>
/// <returns>A string represenetation or the object.</returns>
public override string ToString()
{
return base.ToString();
}
}
/// <summary>
/// A fake attribute to allow compilation on platforms that lack this attribute.
/// </summary>
[AttributeUsageAttribute(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)]
[ComVisibleAttribute(true)]
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:FileMayOnlyContainASingleClass",
Justification = "Reviewed. Suppression is OK here because it's a collection of trivial classes.")]
[SuppressMessage(
"Microsoft.StyleCop.CSharp.MaintainabilityRules",
"SA1402:FileMayOnlyContainASingleClass",
Justification = "These stub classes are compiled only on some platforms that do not contain the entire framework, e.g. new Windows user interface.")]
internal sealed class ComVisibleAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="ComVisibleAttribute"/> class.
/// </summary>
/// <param name="comVisible">
/// The com visible.
/// </param>
public ComVisibleAttribute(bool comVisible)
{
}
/// <summary>
/// Prints out the object's contents.
/// </summary>
/// <returns>A string represenetation or the object.</returns>
public override string ToString()
{
return base.ToString();
}
}
/// <summary>
/// Indicates that a class can be serialized. This class cannot be inherited.
/// </summary>
/// <filterpriority>1</filterpriority>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Delegate, Inherited = false), ComVisible(true)]
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:FileMayOnlyContainASingleClass",
Justification = "Reviewed. Suppression is OK here because it's a collection of trivial classes.")]
[SuppressMessage(
"Microsoft.StyleCop.CSharp.MaintainabilityRules",
"SA1402:FileMayOnlyContainASingleClass",
Justification = "These stub classes are compiled only on some platforms that do not contain the entire framework, e.g. new Windows user interface.")]
internal sealed class SerializableAttribute : Attribute
{
/// <summary>
/// Prints out the object's contents.
/// </summary>
/// <returns>A string represenetation or the object.</returns>
public override string ToString()
{
return base.ToString();
}
}
/// <summary>
/// Indicates that a field of a serializable class should not be serialized. This class cannot be inherited.
/// </summary>
/// <filterpriority>1</filterpriority>
[ComVisible(true), AttributeUsage(AttributeTargets.Field, Inherited = false)]
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:FileMayOnlyContainASingleClass",
Justification = "Reviewed. Suppression is OK here because it's a collection of trivial classes.")]
[SuppressMessage(
"Microsoft.StyleCop.CSharp.MaintainabilityRules",
"SA1402:FileMayOnlyContainASingleClass",
Justification = "These stub classes are compiled only on some platforms that do not contain the entire framework, e.g. new Windows user interface.")]
internal sealed class NonSerializedAttribute : Attribute
{
/// <summary>
/// Prints out the object's contents.
/// </summary>
/// <returns>A string represenetation or the object.</returns>
public override string ToString()
{
return base.ToString();
}
}
}
namespace System.Runtime.ConstrainedExecution
{
}
namespace System.Security.Cryptography
{
}
namespace System.Security.Permissions
{
}
namespace Microsoft.Win32.SafeHandles
{
}
namespace System.Runtime.ConstrainedExecution
{
using System;
using Microsoft.Isam.Esent.Interop;
/// <summary>
/// The consistency model. A stub.
/// </summary>
internal enum Consistency
{
/// <summary>
/// Might corrupt the process.
/// </summary>
MayCorruptProcess,
/// <summary>
/// Might corrupt the application domain.
/// </summary>
MayCorruptAppDomain,
/// <summary>
/// Might corrupt the instance.
/// </summary>
MayCorruptInstance,
/// <summary>
/// Will not corrupt the state.
/// </summary>
WillNotCorruptState,
}
/// <summary>
/// The Crticial Execution Region description. A stub.
/// </summary>
internal enum Cer
{
/// <summary>
/// No options.
/// </summary>
None,
/// <summary>
/// This might fail.
/// </summary>
MayFail,
/// <summary>
/// A successful CER.
/// </summary>
Success,
}
/// <summary>
/// The description of the reliability contract. A stub.
/// </summary>
internal sealed class ReliabilityContractAttribute : Attribute
{
/// <summary>
/// The consistency guarantee. A stub.
/// </summary>
private Consistency consistency;
/// <summary>
/// The critical execution region. A stub.
/// </summary>
private Cer cer;
/// <summary>
/// Initializes a new instance of the ReliabilityContractAttribute class. A stub.
/// </summary>
/// <param name="consistencyGuarantee">The guarantee of the consistency.</param>
/// <param name="cer">The critical execution region description.</param>
public ReliabilityContractAttribute(Consistency consistencyGuarantee, Cer cer)
{
this.consistency = consistencyGuarantee;
this.cer = cer;
}
/// <summary>
/// Gets the consistency guarantee. A stub.
/// </summary>
public Consistency ConsistencyGuarantee
{
get
{
return this.consistency;
}
}
/// <summary>
/// Gets the critical execution region. A stub.
/// </summary>
public Cer Cer
{
get
{
return this.cer;
}
}
}
}

View File

@ -0,0 +1,273 @@
//-----------------------------------------------------------------------
// <copyright file="EsentStubs.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
// <summary>
// Class stubs to allow compiling on CoreClr.
// </summary>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
/// <summary>
/// Some useful functionality that was omitted from Core CLR classes.
/// </summary>
[SuppressMessage(
"Microsoft.StyleCop.CSharp.MaintainabilityRules",
"SA1402:FileMayOnlyContainASingleClass",
Justification = "These stub classes are compiled only on some platforms that do not contain the entire framework, e.g. new Windows user interface.")]
public static class ExtensionsToCoreClr
{
/// <summary>Converts the value of this instance to the equivalent OLE Automation date.</summary>
/// <param name="dateTime">A DateTime structure.</param>
/// <returns>A double-precision floating-point number that contains an OLE Automation date equivalent to the value of this instance.</returns>
/// <exception cref="T:System.OverflowException">The value of this instance cannot be represented as an OLE Automation Date. </exception>
/// <filterpriority>2</filterpriority>
public static double ToOADate(this DateTime dateTime)
{
return LibraryHelpers.TicksToOADate(dateTime.Ticks);
}
}
/// <summary>
/// JetApi code that is specific to ESENT.
/// </summary>
[SuppressMessage(
"Microsoft.StyleCop.CSharp.MaintainabilityRules",
"SA1402:FileMayOnlyContainASingleClass",
Justification = "These stub classes are compiled only on some platforms that do not contain the entire framework, e.g. new Windows user interface.")]
public class SerializationInfo
{
/// <summary>
/// Prints out the object's contents.
/// </summary>
/// <returns>A string represenetation or the object.</returns>
public override string ToString()
{
return base.ToString();
}
/// <summary>
/// Deserializes an integer.
/// </summary>
/// <param name="propName">The name of the field to retrieve.</param>
/// <returns>An integer.</returns>
public int GetInt32(string propName)
{
return 0;
}
}
/// <summary>
/// A fake class to allow compilation on platforms that lack this class.
/// </summary>
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:FileMayOnlyContainASingleClass",
Justification = "Reviewed. Suppression is OK here because it's a collection of trivial classes.")]
[SuppressMessage(
"Microsoft.StyleCop.CSharp.MaintainabilityRules",
"SA1402:FileMayOnlyContainASingleClass",
Justification = "These stub classes are compiled only on some platforms that do not contain the entire framework, e.g. new Windows user interface.")]
internal static class RuntimeHelpers
{
/// <summary>
/// A fake function to allow compilation on platforms that lack this functionality.
/// </summary>
public static void PrepareConstrainedRegions()
{
}
/// <summary>
/// A fake function to allow compilation on platforms that lack this functionality.
/// </summary>
/// <param name="method">
/// The method.
/// </param>
public static void PrepareMethod(RuntimeMethodHandle method)
{
}
}
/// <summary>
/// A fake class to allow compilation on platforms that lack this class.
/// </summary>
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:FileMayOnlyContainASingleClass",
Justification = "Reviewed. Suppression is OK here because it's a collection of trivial classes.")]
internal class TraceSwitch
{
/// <summary>
/// Initializes a new instance of the <see cref="TraceSwitch"/> class.
/// </summary>
/// <param name="displayName">
/// The display name.
/// </param>
/// <param name="description">
/// The description.
/// </param>
public TraceSwitch(string displayName, string description)
{
}
/// <summary>
/// Gets a value indicating whether TraceVerbose.
/// </summary>
public bool TraceVerbose { get; private set; }
/// <summary>
/// Gets a value indicating whether TraceWarning.
/// </summary>
public bool TraceWarning { get; private set; }
/// <summary>
/// Gets a value indicating whether TraceError.
/// </summary>
public bool TraceError { get; private set; }
/// <summary>
/// Gets a value indicating whether TraceInfo.
/// </summary>
public bool TraceInfo { get; private set; }
/// <summary>
/// Prints out the object's contents.
/// </summary>
/// <returns>A string represenetation or the object.</returns>
public override string ToString()
{
return base.ToString();
}
}
/// <summary>
/// A fake class to allow compilation on platforms that lack this class.
/// </summary>
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:FileMayOnlyContainASingleClass",
Justification = "Reviewed. Suppression is OK here because it's a collection of trivial classes.")]
internal class Trace
{
/// <summary>
/// A fake function to allow compilation on platforms that lack this functionality.
/// </summary>
/// <param name="condition">
/// The condition.
/// </param>
/// <param name="message">
/// The message.
/// </param>
[ConditionalAttribute("TRACE")]
public static void WriteLineIf(bool condition, string message)
{
}
/// <summary>
/// A fake function to allow compilation on platforms that lack this functionality.
/// </summary>
/// <param name="message">
/// The message.
/// </param>
[ConditionalAttribute("TRACE")]
public static void TraceError(string message)
{
}
/// <summary>
/// A fake function to allow compilation on platforms that lack this functionality.
/// </summary>
/// <param name="message">
/// The message.
/// </param>
/// <param name="args">
/// The arguments.
/// </param>
[ConditionalAttribute("TRACE")]
public static void TraceWarning(string message, params object[] args)
{
}
}
}
#if MANAGEDESENT_ON_WSA
namespace System.ComponentModel
{
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using System.Security;
/// <summary>
/// An exception from a Win32 call.
/// </summary>
//// The original derives from System.Runtime.InteropServices.ExternalException.
internal class Win32Exception : Exception
{
/// <summary>
/// The error code from a Win32 call.
/// </summary>
private readonly int nativeErrorCode;
/// <summary>
/// Initializes a new instance of the Win32Exception class.
/// </summary>
[SecuritySafeCritical]
public Win32Exception() : this(Marshal.GetLastWin32Error())
{
}
/// <summary>
/// Initializes a new instance of the Win32Exception class.
/// </summary>
/// <param name="error">A win32 error code.</param>
[SecuritySafeCritical]
public Win32Exception(int error) : this(error, Win32Exception.GetErrorMessage(error))
{
}
/// <summary>
/// Initializes a new instance of the Win32Exception class.
/// </summary>
/// <param name="error">A win32 error code.</param>
/// <param name="message">The string message.</param>
public Win32Exception(int error, string message)
: base(message)
{
this.nativeErrorCode = error;
}
/// <summary>
/// Initializes a new instance of the Win32Exception class.
/// </summary>
/// <param name="message">The string message.</param>
[SecuritySafeCritical]
public Win32Exception(string message) : this(Marshal.GetLastWin32Error(), message)
{
}
/// <summary>
/// Initializes a new instance of the Win32Exception class.
/// </summary>
/// <param name="message">The string message.</param>
/// <param name="innerException">The nested exception.</param>
[SecuritySafeCritical, SuppressMessage("Microsoft.Interoperability", "CA1404:CallGetLastErrorImmediatelyAfterPInvoke", Justification = "Retuning error codes.")]
public Win32Exception(string message, Exception innerException) : base(message, innerException)
{
this.nativeErrorCode = Marshal.GetLastWin32Error();
}
/// <summary>
/// Returns a string value of the Win32 error code.
/// </summary>
/// <param name="error">The Win32 error code.</param>
/// <returns>A string representation.</returns>
[SecuritySafeCritical]
private static string GetErrorMessage(int error)
{
string result = string.Empty;
result = "Win32 error (0x" + Convert.ToString(error, 16) + ")";
return result;
}
}
}
#endif // MANAGEDESENT_ON_WSA

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,76 @@
//-----------------------------------------------------------------------
// <copyright file="EsentErrorException.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
using System.Runtime.Serialization;
/// <summary>
/// Base class for ESENT error exceptions.
/// </summary>
[Serializable]
public class EsentErrorException : EsentException
{
/// <summary>
/// The error code that was encountered.
/// </summary>
private JET_err errorCode;
/// <summary>
/// Initializes a new instance of the EsentErrorException class.
/// </summary>
/// <param name="message">The description of the error.</param>
/// <param name="err">The error code of the exception.</param>
internal EsentErrorException(string message, JET_err err) : base(message)
{
this.errorCode = err;
}
/// <summary>
/// Initializes a new instance of the EsentErrorException class. This constructor
/// is used to deserialize a serialized exception.
/// </summary>
/// <param name="info">The data needed to deserialize the object.</param>
/// <param name="context">The deserialization context.</param>
protected EsentErrorException(SerializationInfo info, StreamingContext context) :
base(info, context)
{
this.errorCode = (JET_err)info.GetInt32("errorCode");
}
/// <summary>
/// Gets the underlying Esent error for this exception.
/// </summary>
public JET_err Error
{
get
{
return this.errorCode;
}
}
#if !MANAGEDESENT_ON_CORECLR // Serialization does not work in Core CLR.
/// <summary>When overridden in a derived class, sets the <see cref="T:System.Runtime.Serialization.SerializationInfo" /> with information about the exception.</summary>
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo" /> that holds the serialized object data about the exception being thrown. </param>
/// <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext" /> that contains contextual information about the source or destination. </param>
/// <exception cref="T:System.ArgumentNullException">The <paramref name="info" /> parameter is a null reference (Nothing in Visual Basic). </exception>
/// <filterpriority>2</filterpriority>
/// <PermissionSet>
/// <IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Read="*AllFiles*" PathDiscovery="*AllFiles*" />
/// <IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Flags="SerializationFormatter" />
/// </PermissionSet>
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
if (info != null)
{
info.AddValue("errorCode", this.errorCode, typeof(int));
}
}
#endif
}
}

View File

@ -0,0 +1,51 @@
//-----------------------------------------------------------------------
// <copyright file="EsentException.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent
{
using System;
using System.Runtime.Serialization;
#if !MANAGEDESENT_SUPPORTS_SERIALIZATION && MANAGEDESENT_ON_WSA
using Microsoft.Isam.Esent.Interop;
using SerializableAttribute = Microsoft.Isam.Esent.Interop.SerializableAttribute;
#endif
/// <summary>
/// Base class for ESENT exceptions.
/// </summary>
[Serializable]
public abstract class EsentException : Exception
{
/// <summary>
/// Initializes a new instance of the EsentException class.
/// </summary>
protected EsentException()
{
}
/// <summary>
/// Initializes a new instance of the EsentException class with a specified error message.
/// </summary>
/// <param name="message">The message that describes the error.</param>
protected EsentException(string message)
: base(message)
{
}
/// <summary>
/// Initializes a new instance of the EsentException class. This constructor
/// is used to deserialize a serialized exception.
/// </summary>
/// <param name="info">The data needed to deserialize the object.</param>
/// <param name="context">The deserialization context.</param>
protected EsentException(SerializationInfo info, StreamingContext context)
#if MANAGEDESENT_SUPPORTS_SERIALIZATION || !MANAGEDESENT_ON_WSA
: base(info, context)
#endif
{
}
}
}

View File

@ -0,0 +1,108 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{E929E163-52A0-4AAC-917B-6D7FAF70C45E}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Esent.Interop</RootNamespace>
<AssemblyName>Esent.Interop</AssemblyName>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<DefineConstants></DefineConstants>
<FileAlignment>512</FileAlignment>
<SignAssembly>true</SignAssembly>
<PublicKeyFile>..\scripts\internal\35MSSharedLib1024.snk</PublicKeyFile>
<Platforms>AnyCPU;x86</Platforms>
</PropertyGroup>
<!-- The .snk file won't be published to codeplex. -->
<PropertyGroup Condition="Exists('$(PublicKeyFile)')">
<DefineConstants>$(DefineConstants);STRONG_NAMED</DefineConstants>
<DelaySign>true</DelaySign>
<AssemblyOriginatorKeyFile>$(PublicKeyFile)</AssemblyOriginatorKeyFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>$(DefineConstants);DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
<DocumentationFile>$(OutputPath)\$(AssemblyName).xml</DocumentationFile>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>$(DefineConstants);DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
<DocumentationFile>$(OutputPath)\$(AssemblyName).xml</DocumentationFile>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>$(DefineConstants)</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<DocumentationFile>$(OutputPath)\$(AssemblyName).xml</DocumentationFile>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>$(DefineConstants)</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<DocumentationFile>$(OutputPath)\$(AssemblyName).xml</DocumentationFile>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Compile Include="*.cs" />
<Compile Remove="Properties\**" />
<EmbeddedResource Remove="Properties\**" />
<None Remove="Properties\**" />
<Compile Include="Esent\CallbackDataConverter.cs" />
<Compile Include="Esent\EsentJetApi.cs" />
<Compile Include="Esent\EsentNativeMethods.cs" />
<Compile Include="Esent\AssemblyInfo.cs" />
</ItemGroup>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@ -0,0 +1,50 @@
//-----------------------------------------------------------------------
// <copyright file="EsentInvalidColumnException.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
using System.Runtime.Serialization;
/// <summary>
/// Exception thrown when a column conversion fails.
/// </summary>
[Serializable]
public class EsentInvalidColumnException : EsentException
{
/// <summary>
/// Initializes a new instance of the EsentInvalidColumnException class.
/// </summary>
public EsentInvalidColumnException()
{
}
#if MANAGEDESENT_ON_CORECLR
#else
/// <summary>
/// Initializes a new instance of the EsentInvalidColumnException class. This constructor
/// is used to deserialize a serialized exception.
/// </summary>
/// <param name="info">The data needed to deserialize the object.</param>
/// <param name="context">The deserialization context.</param>
protected EsentInvalidColumnException(SerializationInfo info, StreamingContext context) :
base(info, context)
{
}
#endif
/// <summary>
/// Gets a text message describing the exception.
/// </summary>
public override string Message
{
get
{
return "Column is not valid for this operation";
}
}
}
}

View File

@ -0,0 +1,127 @@
//-----------------------------------------------------------------------
// <copyright file="EsentResource.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
using System.Diagnostics;
/// <summary>
/// This is the base class for all esent resource objects.
/// Subclasses of this class can allocate and release unmanaged
/// resources.
/// </summary>
public abstract class EsentResource : IDisposable
{
/// <summary>
/// True if a resource has been allocated.
/// </summary>
private bool hasResource;
/// <summary>
/// True if this object has been disposed.
/// </summary>
private bool isDisposed;
/// <summary>
/// Finalizes an instance of the EsentResource class.
/// </summary>
~EsentResource()
{
this.Dispose(false);
}
/// <summary>
/// Gets a value indicating whether the underlying resource
/// is currently allocated.
/// </summary>
protected bool HasResource
{
get
{
return this.hasResource;
}
}
/// <summary>
/// Dispose of this object, releasing the underlying
/// Esent resource.
/// </summary>
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Called by Dispose and the finalizer.
/// </summary>
/// <param name="isDisposing">
/// True if called from Dispose.
/// </param>
protected virtual void Dispose(bool isDisposing)
{
if (isDisposing)
{
if (this.hasResource)
{
this.ReleaseResource();
Debug.Assert(!this.hasResource, "Resource was not freed");
}
this.isDisposed = true;
}
else
{
if (this.hasResource)
{
// We should not get to this point. The problem is that if
// we use finalizers to free esent resources they may end
// up being freed in the wrong order (e.g. JetEndSession is
// called before JetCloseTable). Freeing esent resources
// in the wrong order will generate EsentExceptions.
Trace.TraceWarning("Non-finalized ESENT resource {0}", this);
}
}
}
/// <summary>
/// Throw an exception if this object has been disposed.
/// </summary>
protected void CheckObjectIsNotDisposed()
{
if (this.isDisposed)
{
throw new ObjectDisposedException("EsentResource");
}
}
/// <summary>
/// Called by a subclass when a resource is allocated.
/// </summary>
protected void ResourceWasAllocated()
{
this.CheckObjectIsNotDisposed();
Debug.Assert(!this.hasResource, "Resource is already allocated");
this.hasResource = true;
}
/// <summary>
/// Called by a subclass when a resource is freed.
/// </summary>
protected void ResourceWasReleased()
{
Debug.Assert(this.hasResource, "Resource is not allocated");
this.CheckObjectIsNotDisposed();
this.hasResource = false;
}
/// <summary>
/// Implemented by the subclass to release a resource.
/// </summary>
protected abstract void ReleaseResource();
}
}

View File

@ -0,0 +1,113 @@
//-----------------------------------------------------------------------
// <copyright file="EsentStopwatch.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
using System.Diagnostics;
using Microsoft.Isam.Esent.Interop.Vista;
/// <summary>
/// Provides a set of methods and properties that you can use to measure
/// ESENT work statistics for a thread. If the current version of ESENT
/// doesn't support <see cref="VistaApi.JetGetThreadStats"/> then all
/// ESENT statistics will be 0.
/// </summary>
public class EsentStopwatch
{
/// <summary>
/// Used to measure how long statistics are collected for.
/// </summary>
private Stopwatch stopwatch;
/// <summary>
/// The stats at the start of our collection.
/// </summary>
private JET_THREADSTATS statsAtStart;
/// <summary>
/// Gets a value indicating whether the EsentStopwatch timer is running.
/// </summary>
public bool IsRunning { get; private set; }
/// <summary>
/// Gets the total ESENT work stats measured by the current instance.
/// </summary>
public JET_THREADSTATS ThreadStats { get; private set; }
/// <summary>
/// Gets the total elapsed time measured by the current instance.
/// </summary>
public TimeSpan Elapsed { get; private set; }
/// <summary>
/// Initializes a new EsentStopwatch instance and starts
/// measuring elapsed time.
/// </summary>
/// <returns>A new, running EsentStopwatch.</returns>
public static EsentStopwatch StartNew()
{
var stopwatch = new EsentStopwatch();
stopwatch.Start();
return stopwatch;
}
/// <summary>
/// Returns a <see cref="T:System.String"/> that represents the current <see cref="Stopwatch"/>.
/// </summary>
/// <returns>
/// A <see cref="T:System.String"/> that represents the current <see cref="Stopwatch"/>.
/// </returns>
public override string ToString()
{
return this.IsRunning ? "EsentStopwatch (running)" : this.Elapsed.ToString();
}
/// <summary>
/// Starts measuring ESENT work.
/// </summary>
public void Start()
{
this.Reset();
this.stopwatch = Stopwatch.StartNew();
this.IsRunning = true;
if (EsentVersion.SupportsVistaFeatures)
{
VistaApi.JetGetThreadStats(out this.statsAtStart);
}
}
/// <summary>
/// Stops measuring ESENT work.
/// </summary>
public void Stop()
{
if (this.IsRunning)
{
this.IsRunning = false;
this.stopwatch.Stop();
this.Elapsed = this.stopwatch.Elapsed;
if (EsentVersion.SupportsVistaFeatures)
{
JET_THREADSTATS statsAtEnd;
VistaApi.JetGetThreadStats(out statsAtEnd);
this.ThreadStats = statsAtEnd - this.statsAtStart;
}
}
}
/// <summary>
/// Stops time interval measurement and resets the thread statistics.
/// </summary>
public void Reset()
{
this.stopwatch = null;
this.ThreadStats = new JET_THREADSTATS();
this.Elapsed = TimeSpan.Zero;
this.IsRunning = false;
}
}
}

View File

@ -0,0 +1,134 @@
//-----------------------------------------------------------------------
// <copyright file="EsentVersion.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using Microsoft.Isam.Esent.Interop.Implementation;
/// <summary>
/// Gives information about the version of esent being used.
/// </summary>
public static class EsentVersion
{
/// <summary>
/// Gets a value indicating whether the current version of esent
/// supports features available in the Windows Server 2003 version of
/// esent.
/// </summary>
public static bool SupportsServer2003Features
{
get
{
return Capabilities.SupportsServer2003Features;
}
}
/// <summary>
/// Gets a value indicating whether the current version of esent
/// supports features available in the Windows Vista version of
/// esent.
/// </summary>
public static bool SupportsVistaFeatures
{
get
{
return Capabilities.SupportsVistaFeatures;
}
}
/// <summary>
/// Gets a value indicating whether the current version of esent
/// supports features available in the Windows 7 version of
/// esent.
/// </summary>
public static bool SupportsWindows7Features
{
get
{
return Capabilities.SupportsWindows7Features;
}
}
/// <summary>
/// Gets a value indicating whether the current version of esent
/// supports features available in the Windows 8 version of
/// esent.
/// </summary>
public static bool SupportsWindows8Features
{
get
{
return Capabilities.SupportsWindows8Features;
}
}
/// <summary>
/// Gets a value indicating whether the current version of esent
/// supports features available in the Windows 8.1 version of
/// esent.
/// </summary>
public static bool SupportsWindows81Features
{
get
{
return Capabilities.SupportsWindows81Features;
}
}
/// <summary>
/// Gets a value indicating whether the current version of esent
/// supports features available in the Windows 10 version of
/// esent.
/// </summary>
public static bool SupportsWindows10Features
{
get
{
return Capabilities.SupportsWindows10Features;
}
}
/// <summary>
/// Gets a value indicating whether the current version of esent
/// can use non-ASCII paths to access databases.
/// </summary>
public static bool SupportsUnicodePaths
{
get
{
return Capabilities.SupportsUnicodePaths;
}
}
/// <summary>
/// Gets a value indicating whether large (> 255 byte) keys are supported.
/// The key size for an index can be specified in the <see cref="JET_INDEXCREATE"/>
/// object.
/// </summary>
public static bool SupportsLargeKeys
{
get
{
return Capabilities.SupportsLargeKeys;
}
}
/// <summary>
/// Gets a description of the current Esent capabilities.
/// </summary>
/// <remarks>
/// We allow this to be set separately so that capabilities can
/// be downgraded for testing.
/// </remarks>
private static JetCapabilities Capabilities
{
get
{
return Api.Impl.Capabilities;
}
}
}
}

View File

@ -0,0 +1,69 @@
//-----------------------------------------------------------------------
// <copyright file="FloatColumnValue.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
using System.Diagnostics;
/// <summary>
/// A <see cref="float"/> column value.
/// </summary>
public class FloatColumnValue : ColumnValueOfStruct<float>
{
/// <summary>
/// Gets the size of the value in the column. This returns 0 for
/// variable sized columns (i.e. binary and string).
/// </summary>
protected override int Size
{
[DebuggerStepThrough]
get { return sizeof(float); }
}
/// <summary>
/// Recursive SetColumns method for data pinning. This populates the buffer and
/// calls the inherited SetColumns method.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">
/// The table to set the columns in. An update should be prepared.
/// </param>
/// <param name="columnValues">
/// Column values to set.
/// </param>
/// <param name="nativeColumns">
/// Structures to put the pinned data in.
/// </param>
/// <param name="i">Offset of this object in the array.</param>
/// <returns>An error code.</returns>
internal override unsafe int SetColumns(JET_SESID sesid, JET_TABLEID tableid, ColumnValue[] columnValues, NATIVE_SETCOLUMN* nativeColumns, int i)
{
var data = this.Value.GetValueOrDefault();
return this.SetColumns(sesid, tableid, columnValues, nativeColumns, i, &data, sizeof(float), this.Value.HasValue);
}
/// <summary>
/// Given data retrieved from ESENT, decode the data and set the value in the ColumnValue object.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within the bytes.</param>
/// <param name="count">The number of bytes to decode.</param>
/// <param name="err">The error returned from ESENT.</param>
protected override void GetValueFromBytes(byte[] value, int startIndex, int count, int err)
{
if (JET_wrn.ColumnNull == (JET_wrn)err)
{
this.Value = null;
}
else
{
this.CheckDataCount(count);
this.Value = BitConverter.ToSingle(value, startIndex);
}
}
}
}

View File

@ -0,0 +1,94 @@
//-----------------------------------------------------------------------
// <copyright file="GCHandleCollection.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop.Implementation
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
/// <summary>
/// A collection of GCHandles for pinned objects. The handles
/// are freed when this object is disposed.
/// </summary>
[StructLayout(LayoutKind.Auto)]
internal struct GCHandleCollection : IDisposable
{
/// <summary>
/// The handles of the objects being pinned.
/// </summary>
private GCHandle[] handles;
/// <summary>
/// Handle count.
/// </summary>
private int count;
/// <summary>
/// Disposes of the object.
/// </summary>
public void Dispose()
{
if (null != this.handles)
{
for (int i = 0; i < this.count; i++)
{
this.handles[i].Free();
}
this.handles = null;
}
}
/// <summary>
/// Add an object to the handle collection. This automatically
/// pins the object.
/// </summary>
/// <param name="value">The object to pin.</param>
/// <returns>
/// The address of the pinned object. This is valid until the
/// GCHandleCollection is disposed.
/// </returns>
public IntPtr Add(object value)
{
if (null == value)
{
return IntPtr.Zero;
}
if (null == this.handles)
{
this.handles = new GCHandle[4]; // same as List<T>
}
else if (this.count == this.handles.Length)
{
Array.Resize(ref this.handles, this.count * 2);
}
Debug.Assert(this.count < this.handles.Length, "Index out of bound");
GCHandle handle = GCHandle.Alloc(value, GCHandleType.Pinned);
this.handles[this.count++] = handle;
IntPtr pinned = handle.AddrOfPinnedObject();
Debug.Assert(IntPtr.Zero != pinned, "Pinned object has null address");
return pinned;
}
/// <summary>
/// Set handle array capacity.
/// </summary>
/// <param name="capacity">Estimated handle count</param>
public void SetCapacity(int capacity)
{
if (null == this.handles)
{
this.handles = new GCHandle[capacity];
}
}
}
}

View File

@ -0,0 +1,64 @@
//-----------------------------------------------------------------------
// <copyright file="GenericEnumerable.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System.Collections;
using System.Collections.Generic;
/// <summary>
/// IEnumerable class that takes a delegate to create the enumerator it returns.
/// </summary>
/// <typeparam name="T">The type returned by the enumerator.</typeparam>
internal class GenericEnumerable<T> : IEnumerable<T>
{
/// <summary>
/// The delegate used to create the enumerator.
/// </summary>
private readonly CreateEnumerator enumeratorCreator;
/// <summary>
/// Initializes a new instance of the <see cref="GenericEnumerable{T}"/> class.
/// </summary>
/// <param name="enumeratorCreator">
/// The enumerator creator.
/// </param>
public GenericEnumerable(CreateEnumerator enumeratorCreator)
{
this.enumeratorCreator = enumeratorCreator;
}
/// <summary>
/// IEnumerator creating delegate.
/// </summary>
/// <returns>A new enumerator.</returns>
public delegate IEnumerator<T> CreateEnumerator();
/// <summary>
/// Returns an enumerator that iterates through the collection.
/// </summary>
/// <returns>
/// A <see cref="T:System.Collections.Generic.IEnumerator`1"/>
/// that can be used to iterate through the collection.
/// </returns>
public IEnumerator<T> GetEnumerator()
{
return this.enumeratorCreator();
}
/// <summary>
/// Returns an enumerator that iterates through a collection.
/// </summary>
/// <returns>
/// A <see cref="T:System.Collections.IEnumerator"/>
/// object that can be used to iterate through the collection.
/// </returns>
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
}

View File

@ -0,0 +1,48 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="GetLockHelpers.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
// <summary>
// Helper methods for JetMakeKey.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
#if !MANAGEDESENT_ON_WSA // Not exposed in MSDK
namespace Microsoft.Isam.Esent.Interop
{
using System.Diagnostics;
/// <summary>
/// Helper methods for the ESENT API. These wrap JetMakeKey.
/// </summary>
public static partial class Api
{
/// <summary>
/// Explicitly reserve the ability to update a row, write lock, or to explicitly prevent a row from
/// being updated by any other session, read lock. Normally, row write locks are acquired implicitly as a
/// result of updating rows. Read locks are usually not required because of record versioning. However,
/// in some cases a transaction may desire to explicitly lock a row to enforce serialization, or to ensure
/// that a subsequent operation will succeed.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to use. A lock will be acquired on the current record.</param>
/// <param name="grbit">Lock options, use this to specify which type of lock to obtain.</param>
/// <returns>
/// True if the lock was obtained, false otherwise. An exception is thrown if an unexpected
/// error is encountered.
/// </returns>
public static bool TryGetLock(JET_SESID sesid, JET_TABLEID tableid, GetLockGrbit grbit)
{
var err = (JET_err)Impl.JetGetLock(sesid, tableid, grbit);
if (JET_err.WriteConflict == err)
{
return false;
}
Api.Check((int)err);
Debug.Assert(err >= JET_err.Success, "Exception should have been thrown in case of error");
return true;
}
}
}
#endif // !MANAGEDESENT_ON_WSA

View File

@ -0,0 +1,82 @@
//-----------------------------------------------------------------------
// <copyright file="GuidColumnValue.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
using System.Diagnostics;
/// <summary>
/// A <see cref="Guid"/> column value.
/// </summary>
public class GuidColumnValue : ColumnValueOfStruct<Guid>
{
/// <summary>
/// Gets the size of the value in the column. This returns 0 for
/// variable sized columns (i.e. binary and string).
/// </summary>
protected override int Size
{
[DebuggerStepThrough]
get { return 16; /* sizeof(Guid) */ }
}
/// <summary>
/// Recursive SetColumns method for data pinning. This populates the buffer and
/// calls the inherited SetColumns method.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">
/// The table to set the columns in. An update should be prepared.
/// </param>
/// <param name="columnValues">
/// Column values to set.
/// </param>
/// <param name="nativeColumns">
/// Structures to put the pinned data in.
/// </param>
/// <param name="i">Offset of this object in the array.</param>
/// <returns>An error code.</returns>
internal override unsafe int SetColumns(JET_SESID sesid, JET_TABLEID tableid, ColumnValue[] columnValues, NATIVE_SETCOLUMN* nativeColumns, int i)
{
Guid data = this.Value.GetValueOrDefault();
return this.SetColumns(sesid, tableid, columnValues, nativeColumns, i, &data, this.Size, this.Value.HasValue);
}
/// <summary>
/// Given data retrieved from ESENT, decode the data and set the value in the ColumnValue object.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within the bytes.</param>
/// <param name="count">The number of bytes to decode.</param>
/// <param name="err">The error returned from ESENT.</param>
protected override void GetValueFromBytes(byte[] value, int startIndex, int count, int err)
{
if (JET_wrn.ColumnNull == (JET_wrn)err)
{
this.Value = null;
}
else
{
this.CheckDataCount(count);
unsafe
{
// There isn't a convenient Guid constructor for this case, so
// we copy the data manually.
Guid guid;
void* guidBuffer = &guid;
byte* buffer = (byte*)guidBuffer;
for (int i = 0; i < this.Size; ++i)
{
buffer[i] = value[startIndex + i];
}
this.Value = guid;
}
}
}
}
}

View File

@ -0,0 +1,26 @@
//-----------------------------------------------------------------------
// <copyright file="IContentEquatable.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
/// <summary>
/// Interface for objects that can have their contents compared against
/// each other. This should be used for equality comparisons on mutable
/// reference objects where overriding Equals() and GetHashCode() isn't a
/// good idea.
/// </summary>
/// <typeparam name="T">The type of objects to compare.</typeparam>
public interface IContentEquatable<T>
{
/// <summary>
/// Returns a value indicating whether this instance is equal
/// to another instance.
/// </summary>
/// <param name="other">An instance to compare with this instance.</param>
/// <returns>True if the two instances are equal.</returns>
bool ContentEquals(T other);
}
}

View File

@ -0,0 +1,22 @@
//-----------------------------------------------------------------------
// <copyright file="IDeepCloneable.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
/// <summary>
/// Interface for objects that can be cloned. This creates a deep copy of
/// the object. It is used for cloning meta-data objects.
/// </summary>
/// <typeparam name="T">The type of object.</typeparam>
public interface IDeepCloneable<T>
{
/// <summary>
/// Returns a deep copy of the object.
/// </summary>
/// <returns>A deep copy of the object.</returns>
T DeepClone();
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,19 @@
//-----------------------------------------------------------------------
// <copyright file="INullableJetStruct.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
/// <summary>
/// Interface for Jet structures that are nullable (can have null values).
/// </summary>
public interface INullableJetStruct
{
/// <summary>
/// Gets a value indicating whether the structure has a null value.
/// </summary>
bool HasValue { get; }
}
}

View File

@ -0,0 +1,189 @@
//-----------------------------------------------------------------------
// <copyright file="IndexInfo.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.Text;
/// <summary>
/// Information about one esent index. This is not an interop
/// class, but is used by the meta-data helper methods.
/// </summary>
[Serializable]
public class IndexInfo
{
/// <summary>
/// The name of the index.
/// </summary>
private readonly string name;
/// <summary>
/// The culture info of the index.
/// </summary>
private readonly CultureInfo cultureInfo;
/// <summary>
/// Index comparison options.
/// </summary>
private readonly CompareOptions compareOptions;
/// <summary>
/// Index segments.
/// </summary>
private readonly ReadOnlyCollection<IndexSegment> indexSegments;
/// <summary>
/// Index options.
/// </summary>
private readonly CreateIndexGrbit grbit;
/// <summary>
/// Number of unique keys in the index.
/// </summary>
private readonly int keys;
/// <summary>
/// Number of entries in the index.
/// </summary>
private readonly int entries;
/// <summary>
/// Number of pages in the index.
/// </summary>
private readonly int pages;
/// <summary>
/// Initializes a new instance of the IndexInfo class.
/// </summary>
/// <param name="name">Name of the index.</param>
/// <param name="cultureInfo">CultureInfo for string sorting.</param>
/// <param name="compareOptions">String comparison options.</param>
/// <param name="indexSegments">Array of index segment descriptions.</param>
/// <param name="grbit">Index options.</param>
/// <param name="keys">Number of unique keys in the index.</param>
/// <param name="entries">Number of entries in the index.</param>
/// <param name="pages">Number of pages in the index.</param>
internal IndexInfo(
string name,
CultureInfo cultureInfo,
CompareOptions compareOptions,
IndexSegment[] indexSegments,
CreateIndexGrbit grbit,
int keys,
int entries,
int pages)
{
this.name = name;
this.cultureInfo = cultureInfo;
this.compareOptions = compareOptions;
this.indexSegments = new ReadOnlyCollection<IndexSegment>(indexSegments);
this.grbit = grbit;
this.keys = keys;
this.entries = entries;
this.pages = pages;
}
/// <summary>
/// Gets the name of the index.
/// </summary>
public string Name
{
[DebuggerStepThrough]
get { return this.name; }
}
/// <summary>
/// Gets the CultureInfo the index is sorted by.
/// </summary>
public CultureInfo CultureInfo
{
[DebuggerStepThrough]
get { return this.cultureInfo; }
}
/// <summary>
/// Gets the CompareOptions for the index.
/// </summary>
public CompareOptions CompareOptions
{
[DebuggerStepThrough]
get { return this.compareOptions; }
}
/// <summary>
/// Gets the segments of the index.
/// </summary>
public IList<IndexSegment> IndexSegments
{
[DebuggerStepThrough]
get { return this.indexSegments; }
}
/// <summary>
/// Gets the index options.
/// </summary>
public CreateIndexGrbit Grbit
{
[DebuggerStepThrough]
get { return this.grbit; }
}
/// <summary>
/// Gets the number of unique keys in the index.
/// This value is not current and is only is updated by Api.JetComputeStats.
/// </summary>
public int Keys
{
[DebuggerStepThrough]
get { return this.keys; }
}
/// <summary>
/// Gets the number of entries in the index.
/// This value is not current and is only is updated by Api.JetComputeStats.
/// </summary>
public int Entries
{
[DebuggerStepThrough]
get { return this.entries; }
}
/// <summary>
/// Gets the number of pages in the index.
/// This value is not current and is only is updated by Api.JetComputeStats.
/// </summary>
public int Pages
{
[DebuggerStepThrough]
get { return this.pages; }
}
/// <summary>
/// Returns a <see cref="T:System.String"/> that represents the current <see cref="IndexInfo"/>.
/// </summary>
/// <returns>
/// A <see cref="T:System.String"/> that represents the current <see cref="IndexInfo"/>.
/// </returns>
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.Append(this.Name);
sb.Append(" (");
foreach (var segment in this.IndexSegments)
{
sb.Append(segment.ToString());
}
sb.Append(")");
return sb.ToString();
}
}
}

View File

@ -0,0 +1,153 @@
//-----------------------------------------------------------------------
// <copyright file="IndexInfoEnumerator.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System.Diagnostics;
using System.Globalization;
using System.Text;
using Microsoft.Isam.Esent.Interop.Windows8;
/// <summary>
/// Base class for enumerators that return IndexInfo objects. Subclasses differ
/// by how they open the table.
/// </summary>
internal abstract class IndexInfoEnumerator : TableEnumerator<IndexInfo>
{
/// <summary>
/// Initializes a new instance of the <see cref="IndexInfoEnumerator"/> class.
/// </summary>
/// <param name="sesid">
/// The session to use.
/// </param>
protected IndexInfoEnumerator(JET_SESID sesid) : base(sesid)
{
}
/// <summary>
/// Gets or sets the indexlist used to retrieve data.
/// </summary>
protected JET_INDEXLIST Indexlist { get; set; }
/// <summary>
/// Gets the entry the cursor is currently positioned on.
/// </summary>
/// <returns>The entry the cursor is currently positioned on.</returns>
protected override IndexInfo GetCurrent()
{
return this.GetIndexInfoFromIndexlist(this.Sesid, this.Indexlist);
}
/// <summary>
/// Retrieves information about indexes on a table.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="indexname">The name of the index.</param>
/// <param name="result">Filled in with information about indexes on the table.</param>
/// <param name="infoLevel">The type of information to retrieve.</param>
protected abstract void GetIndexInfo(
JET_SESID sesid,
string indexname,
out string result,
JET_IdxInfo infoLevel);
/// <summary>
/// Create an array of IndexSegment objects from the data in the current JET_INDEXLIST entry.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="indexlist">The indexlist to take the data from.</param>
/// <returns>An array of IndexSegment objects containing the information for the current index.</returns>
private static IndexSegment[] GetIndexSegmentsFromIndexlist(JET_SESID sesid, JET_INDEXLIST indexlist)
{
var numSegments = (int)Api.RetrieveColumnAsInt32(sesid, indexlist.tableid, indexlist.columnidcColumn);
Debug.Assert(numSegments > 0, "Index has zero index segments");
// If we use the wide API (Vista+), then the temp table will be in UTF-16.
Encoding encodingOfTextColumns = EsentVersion.SupportsVistaFeatures ? Encoding.Unicode : LibraryHelpers.EncodingASCII;
var segments = new IndexSegment[numSegments];
for (int i = 0; i < numSegments; ++i)
{
string columnName = Api.RetrieveColumnAsString(
sesid,
indexlist.tableid,
indexlist.columnidcolumnname,
encodingOfTextColumns,
RetrieveColumnGrbit.None);
columnName = StringCache.TryToIntern(columnName);
var coltyp = (JET_coltyp)Api.RetrieveColumnAsInt32(sesid, indexlist.tableid, indexlist.columnidcoltyp);
var grbit =
(IndexKeyGrbit)Api.RetrieveColumnAsInt32(sesid, indexlist.tableid, indexlist.columnidgrbitColumn);
bool isAscending = IndexKeyGrbit.Ascending == grbit;
var cp = (JET_CP)Api.RetrieveColumnAsInt16(sesid, indexlist.tableid, indexlist.columnidCp);
bool isASCII = JET_CP.ASCII == cp;
segments[i] = new IndexSegment(columnName, coltyp, isAscending, isASCII);
if (i < numSegments - 1)
{
Api.JetMove(sesid, indexlist.tableid, JET_Move.Next, MoveGrbit.None);
}
}
return segments;
}
/// <summary>
/// Create an IndexInfo object from the data in the current JET_INDEXLIST entry.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="indexlist">The indexlist to take the data from.</param>
/// <returns>An IndexInfo object containing the information from that record.</returns>
private IndexInfo GetIndexInfoFromIndexlist(JET_SESID sesid, JET_INDEXLIST indexlist)
{
// If we use the wide API (Vista+), then the temp table will be in UTF-16.
Encoding encodingOfTextColumns = EsentVersion.SupportsVistaFeatures ? Encoding.Unicode : LibraryHelpers.EncodingASCII;
string name = Api.RetrieveColumnAsString(
sesid, indexlist.tableid, indexlist.columnidindexname, encodingOfTextColumns, RetrieveColumnGrbit.None);
name = StringCache.TryToIntern(name);
CultureInfo cultureInfo = null;
if (EsentVersion.SupportsWindows8Features)
{
string localeName;
this.GetIndexInfo(sesid, name, out localeName, Windows8IdxInfo.LocaleName);
cultureInfo = new CultureInfo(localeName);
}
else
{
#if !MANAGEDESENT_ON_CORECLR
// This probably won't work on platforms that don't support LCIDs. Newer environments have dropped
// LCIDs in favour of locale names. But currently JET_INDEXLIST doesn't expose columnidLocale.
int lcid = (int)Api.RetrieveColumnAsInt16(sesid, indexlist.tableid, indexlist.columnidLangid);
cultureInfo = LibraryHelpers.CreateCultureInfoByLcid(lcid);
#endif // !MANAGEDESENT_ON_CORECLR
}
uint lcmapFlags = (uint)Api.RetrieveColumnAsUInt32(sesid, indexlist.tableid, indexlist.columnidLCMapFlags);
CompareOptions compareOptions = Conversions.CompareOptionsFromLCMapFlags(lcmapFlags);
uint grbit = (uint)Api.RetrieveColumnAsUInt32(sesid, indexlist.tableid, indexlist.columnidgrbitIndex);
int keys = (int)Api.RetrieveColumnAsInt32(sesid, indexlist.tableid, indexlist.columnidcKey);
int entries = (int)Api.RetrieveColumnAsInt32(sesid, indexlist.tableid, indexlist.columnidcEntry);
int pages = (int)Api.RetrieveColumnAsInt32(sesid, indexlist.tableid, indexlist.columnidcPage);
IndexSegment[] segments = GetIndexSegmentsFromIndexlist(sesid, indexlist);
return new IndexInfo(
name,
cultureInfo,
compareOptions,
segments,
(CreateIndexGrbit)grbit,
keys,
entries,
pages);
}
}
}

View File

@ -0,0 +1,152 @@
//-----------------------------------------------------------------------
// <copyright file="IndexSegment.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
using System.Diagnostics;
using System.Globalization;
/// <summary>
/// Describes one segment of an index.
/// </summary>
[Serializable]
public class IndexSegment : IEquatable<IndexSegment>
{
/// <summary>
/// The name of the column.
/// </summary>
private readonly string columnName;
/// <summary>
/// The type of the column.
/// </summary>
private readonly JET_coltyp coltyp;
/// <summary>
/// True if the column is sorted in ascending order.
/// </summary>
private readonly bool isAscending;
/// <summary>
/// True if the column is an ASCII column.
/// </summary>
private readonly bool isASCII;
/// <summary>
/// Initializes a new instance of the IndexSegment class.
/// </summary>
/// <param name="name">The name of the indexed column.</param>
/// <param name="coltyp">The type of the column.</param>
/// <param name="isAscending">True if the column is ascending.</param>
/// <param name="isASCII">True if the column is over an ASCII column.</param>
internal IndexSegment(
string name,
JET_coltyp coltyp,
bool isAscending,
bool isASCII)
{
this.columnName = name;
this.coltyp = coltyp;
this.isAscending = isAscending;
this.isASCII = isASCII;
}
/// <summary>
/// Gets name of the column being indexed.
/// </summary>
public string ColumnName
{
[DebuggerStepThrough]
get { return this.columnName; }
}
/// <summary>
/// Gets the type of the column being indexed.
/// </summary>
public JET_coltyp Coltyp
{
[DebuggerStepThrough]
get { return this.coltyp; }
}
/// <summary>
/// Gets a value indicating whether the index segment is ascending.
/// </summary>
public bool IsAscending
{
[DebuggerStepThrough]
get { return this.isAscending; }
}
/// <summary>
/// Gets a value indicating whether the index segment is over an ASCII text
/// column. This value is only meaningful for text column segments.
/// </summary>
public bool IsASCII
{
[DebuggerStepThrough]
get { return this.isASCII; }
}
/// <summary>
/// Returns a value indicating whether this instance is equal
/// to another instance.
/// </summary>
/// <param name="obj">An object to compare with this instance.</param>
/// <returns>True if the two instances are equal.</returns>
public override bool Equals(object obj)
{
if (obj == null || this.GetType() != obj.GetType())
{
return false;
}
return this.Equals((IndexSegment)obj);
}
/// <summary>
/// Generate a string representation of the instance.
/// </summary>
/// <returns>The structure as a string.</returns>
public override string ToString()
{
return string.Format(
CultureInfo.InvariantCulture, "{0}{1}({2})", this.isAscending ? "+" : "-", this.columnName, this.coltyp);
}
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <returns>The hash code for this instance.</returns>
public override int GetHashCode()
{
return this.columnName.GetHashCode()
^ (int)this.coltyp * 31
^ (this.isAscending ? 0x10000 : 0x20000)
^ (this.isASCII ? 0x40000 : 0x80000);
}
/// <summary>
/// Returns a value indicating whether this instance is equal
/// to another instance.
/// </summary>
/// <param name="other">An instance to compare with this instance.</param>
/// <returns>True if the two instances are equal.</returns>
public bool Equals(IndexSegment other)
{
if (null == other)
{
return false;
}
return this.columnName.Equals(other.columnName, StringComparison.OrdinalIgnoreCase)
&& this.coltyp == other.coltyp
&& this.isAscending == other.isAscending
&& this.isASCII == other.isASCII;
}
}
}

View File

@ -0,0 +1,337 @@
//-----------------------------------------------------------------------
// <copyright file="Instance.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Security.Permissions;
using Microsoft.Isam.Esent.Interop.Vista;
using Microsoft.Win32.SafeHandles;
/// <summary>
/// A class that encapsulates a <see cref="JET_INSTANCE"/> in a disposable object. The
/// instance must be closed last and closing the instance releases all other
/// resources for the instance.
/// </summary>
public class Instance : SafeHandleZeroOrMinusOneIsInvalid
{
/// <summary>
/// Parameters for the instance.
/// </summary>
private readonly InstanceParameters parameters;
/// <summary>
/// The name of the instance.
/// </summary>
private readonly string name;
/// <summary>
/// The display name of the instance.
/// </summary>
private readonly string displayName;
/// <summary>
/// The TermGrbit to be used at JetTerm time.
/// </summary>
private TermGrbit termGrbit;
/// <summary>
/// Initializes a new instance of the Instance class. The underlying
/// JET_INSTANCE is allocated, but not initialized.
/// </summary>
/// <param name="name">
/// The name of the instance. This string must be unique within a
/// given process hosting the database engine.
/// </param>
[SecurityPermissionAttribute(SecurityAction.LinkDemand)]
public Instance(string name) : this(name, name, TermGrbit.None)
{
}
/// <summary>
/// Initializes a new instance of the Instance class. The underlying
/// JET_INSTANCE is allocated, but not initialized.
/// </summary>
/// <param name="name">
/// The name of the instance. This string must be unique within a
/// given process hosting the database engine.
/// </param>
/// <param name="displayName">
/// A display name for the instance. This will be used in eventlog
/// entries.
/// </param>
[SecurityPermissionAttribute(SecurityAction.LinkDemand)]
public Instance(string name, string displayName) : this(name, displayName, TermGrbit.None)
{
}
/// <summary>
/// Initializes a new instance of the Instance class. The underlying
/// JET_INSTANCE is allocated, but not initialized.
/// </summary>
/// <param name="name">
/// The name of the instance. This string must be unique within a
/// given process hosting the database engine.
/// </param>
/// <param name="displayName">
/// A display name for the instance. This will be used in eventlog
/// entries.
/// </param>
/// <param name="termGrbit">
/// The TermGrbit to be used at JetTerm time.
/// </param>
[SecurityPermissionAttribute(SecurityAction.LinkDemand)]
public Instance(string name, string displayName, TermGrbit termGrbit) : base(true)
{
this.name = name;
this.displayName = displayName;
this.termGrbit = termGrbit;
JET_INSTANCE instance;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
this.SetHandle(JET_INSTANCE.Nil.Value);
}
finally
{
// This is the code that we want in a constrained execution region.
// We need to avoid the situation where JetCreateInstance2 is called
// but the handle isn't set, so the instance is never terminated.
// This would happen, for example, if there was a ThreadAbortException
// between the call to JetCreateInstance2 and the call to SetHandle.
//
// If an Esent exception is generated we do not want to call SetHandle
// because the instance isn't valid. On the other hand if a different
// exception (out of memory or thread abort) is generated we still need
// to set the handle to avoid losing track of the instance. The call to
// JetCreateInstance2 is in the CER to make sure that the only exceptions
// which can be generated are from ESENT failures.
Api.JetCreateInstance2(out instance, this.name, this.displayName, CreateInstanceGrbit.None);
this.SetHandle(instance.Value);
}
this.parameters = new InstanceParameters(instance);
}
/// <summary>
/// Gets the JET_INSTANCE that this instance contains.
/// </summary>
public JET_INSTANCE JetInstance
{
[SecurityPermissionAttribute(SecurityAction.LinkDemand)]
get
{
this.CheckObjectIsNotDisposed();
return this.CreateInstanceFromHandle();
}
}
/// <summary>
/// Gets the InstanceParameters for this instance.
/// </summary>
public InstanceParameters Parameters
{
[SecurityPermissionAttribute(SecurityAction.LinkDemand)]
get
{
this.CheckObjectIsNotDisposed();
return this.parameters;
}
}
/// <summary>
/// Gets or sets the TermGrbit for this instance.
/// </summary>
public TermGrbit TermGrbit
{
[SecurityPermissionAttribute(SecurityAction.LinkDemand)]
get
{
this.CheckObjectIsNotDisposed();
return this.termGrbit;
}
[SecurityPermissionAttribute(SecurityAction.LinkDemand)]
set
{
this.CheckObjectIsNotDisposed();
this.termGrbit = value;
}
}
/// <summary>
/// Provide implicit conversion of an Instance object to a JET_INSTANCE
/// structure. This is done so that an Instance can be used anywhere a
/// JET_INSTANCE is required.
/// </summary>
/// <param name="instance">The instance to convert.</param>
/// <returns>The JET_INSTANCE wrapped by the instance.</returns>
[SecurityPermissionAttribute(SecurityAction.LinkDemand)]
public static implicit operator JET_INSTANCE(Instance instance)
{
return instance.JetInstance;
}
/// <summary>
/// Returns a <see cref="T:System.String"/> that represents the current <see cref="Instance"/>.
/// </summary>
/// <returns>
/// A <see cref="T:System.String"/> that represents the current <see cref="Instance"/>.
/// </returns>
public override string ToString()
{
return string.Format(CultureInfo.InvariantCulture, "{0} ({1})", this.displayName, this.name);
}
/// <summary>
/// Initialize the JET_INSTANCE.
/// </summary>
[SecurityPermissionAttribute(SecurityAction.LinkDemand)]
public void Init()
{
this.Init(InitGrbit.None);
}
/// <summary>
/// Initialize the JET_INSTANCE.
/// </summary>
/// <param name="grbit">
/// Initialization options.
/// </param>
[SecurityPermissionAttribute(SecurityAction.LinkDemand)]
public void Init(InitGrbit grbit)
{
this.CheckObjectIsNotDisposed();
JET_INSTANCE instance = this.JetInstance;
// Use a constrained region so that the handle is
// always set after JetInit2 is called.
RuntimeHelpers.PrepareConstrainedRegions();
try
{
// Remember that a failure in JetInit can zero the handle
// and that JetTerm should not be called in that case.
Api.JetInit2(ref instance, grbit);
}
finally
{
this.SetHandle(instance.Value);
}
}
/// <summary>
/// Initialize the JET_INSTANCE. This API requires at least the
/// Vista version of ESENT.
/// </summary>
/// <param name="recoveryOptions">
/// Additional recovery parameters for remapping databases during
/// recovery, position where to stop recovery at, or recovery status.
/// </param>
/// <param name="grbit">
/// Initialization options.
/// </param>
[SecurityPermissionAttribute(SecurityAction.LinkDemand)]
public void Init(JET_RSTINFO recoveryOptions, InitGrbit grbit)
{
this.CheckObjectIsNotDisposed();
JET_INSTANCE instance = this.JetInstance;
// Use a constrained region so that the handle is
// always set after JetInit3 is called.
RuntimeHelpers.PrepareConstrainedRegions();
try
{
// Remember that a failure in JetInit can zero the handle
// and that JetTerm should not be called in that case.
VistaApi.JetInit3(ref instance, recoveryOptions, grbit);
}
finally
{
this.SetHandle(instance.Value);
}
}
/// <summary>
/// Terminate the JET_INSTANCE.
/// </summary>
[SuppressMessage(
"Microsoft.StyleCop.CSharp.MaintainabilityRules",
"SA1409:RemoveUnnecessaryCode",
Justification = "CER code belongs in the finally block, so the try clause is empty")]
[SecurityPermissionAttribute(SecurityAction.LinkDemand)]
public void Term()
{
// Use a constrained region so that the handle is
// always set as invalid after JetTerm is called.
RuntimeHelpers.PrepareConstrainedRegions();
try
{
// This try block deliberately left blank.
}
finally
{
// This is the code that we want in a constrained execution region.
// We need to avoid the situation where JetTerm is called
// but the handle isn't invalidated, so the instance is terminated again.
// This would happen, for example, if there was a ThreadAbortException
// between the call to JetTerm and the call to SetHandle.
//
// If an Esent exception is generated we do not want to invalidate the handle
// because the instance isn't necessarily terminated. On the other hand if a
// different exception (out of memory or thread abort) is generated we still need
// to invalidate the handle.
try
{
Api.JetTerm2(this.JetInstance, this.termGrbit);
}
catch (EsentDirtyShutdownException)
{
this.SetHandleAsInvalid();
throw;
}
this.SetHandleAsInvalid();
}
}
/// <summary>
/// Release the handle for this instance.
/// </summary>
/// <returns>True if the handle could be released.</returns>
protected override bool ReleaseHandle()
{
// The object is already marked as invalid so don't check
var instance = this.CreateInstanceFromHandle();
return (int)JET_err.Success == Api.Impl.JetTerm2(instance, this.termGrbit);
}
/// <summary>
/// Create a JET_INSTANCE from the internal handle value.
/// </summary>
/// <returns>A JET_INSTANCE containing the internal handle.</returns>
private JET_INSTANCE CreateInstanceFromHandle()
{
return new JET_INSTANCE { Value = this.handle };
}
/// <summary>
/// Check to see if this instance is invalid or closed.
/// </summary>
[SecurityPermissionAttribute(SecurityAction.LinkDemand)]
private void CheckObjectIsNotDisposed()
{
if (this.IsInvalid || this.IsClosed)
{
throw new ObjectDisposedException("Instance");
}
}
}
}

View File

@ -0,0 +1,762 @@
//-----------------------------------------------------------------------
// <copyright file="InstanceParameters.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
using System.Globalization;
using System.IO;
using Microsoft.Isam.Esent.Interop.Server2003;
using Microsoft.Isam.Esent.Interop.Vista;
using Microsoft.Isam.Esent.Interop.Windows7;
/// <summary>
/// This class provides properties to set and get system parameters
/// on an ESENT instance.
/// </summary>
public partial class InstanceParameters
{
/// <summary>
/// The instance to set parameters on.
/// </summary>
private readonly JET_INSTANCE instance;
/// <summary>
/// The session to set parameters with.
/// </summary>
private readonly JET_SESID sesid;
/// <summary>
/// Initializes a new instance of the InstanceParameters class.
/// </summary>
/// <param name="instance">
/// The instance to set parameters on. If this is JET_INSTANCE.Nil,
/// then the settings affect the default settings of future instances.
/// </param>
public InstanceParameters(JET_INSTANCE instance)
{
this.instance = instance;
this.sesid = JET_SESID.Nil;
}
/// <summary>
/// Gets or sets the relative or absolute file system path of the
/// folder that will contain the checkpoint file for the instance.
/// </summary>
public string SystemDirectory
{
get
{
return Util.AddTrailingDirectorySeparator(this.GetStringParameter(JET_param.SystemPath));
}
set
{
this.SetStringParameter(JET_param.SystemPath, Util.AddTrailingDirectorySeparator(value));
}
}
/// <summary>
/// Gets or sets the relative or absolute file system path of
/// the folder that will contain the temporary database for the instance.
/// </summary>
public string TempDirectory
{
get
{
// Older versions of Esent (e.g. Windows XP) will return the
// full path of the temporary database. Extract the directory name.
string path = this.GetStringParameter(JET_param.TempPath);
string dir = Path.GetDirectoryName(path);
return Util.AddTrailingDirectorySeparator(dir);
}
set
{
this.SetStringParameter(JET_param.TempPath, Util.AddTrailingDirectorySeparator(value));
}
}
/// <summary>
/// Gets or sets the relative or absolute file system path of the
/// folder that will contain the transaction logs for the instance.
/// </summary>
public string LogFileDirectory
{
get
{
return Util.AddTrailingDirectorySeparator(this.GetStringParameter(JET_param.LogFilePath));
}
set
{
this.SetStringParameter(JET_param.LogFilePath, Util.AddTrailingDirectorySeparator(value));
}
}
/// <summary>
/// Gets or sets the relative or absolute file system path of the
/// a folder where crash recovery or a restore operation can find
/// the databases referenced in the transaction log in the
/// specified folder.
/// </summary>
/// <remarks>
/// This parameter is ignored on Windows XP.
/// </remarks>
public string AlternateDatabaseRecoveryDirectory
{
get
{
if (EsentVersion.SupportsServer2003Features)
{
return
Util.AddTrailingDirectorySeparator(
this.GetStringParameter(Server2003Param.AlternateDatabaseRecoveryPath));
}
return null;
}
set
{
if (EsentVersion.SupportsServer2003Features)
{
this.SetStringParameter(
Server2003Param.AlternateDatabaseRecoveryPath, Util.AddTrailingDirectorySeparator(value));
}
}
}
/// <summary>
/// Gets or sets the three letter prefix used for many of the files used by
/// the database engine. For example, the checkpoint file is called EDB.CHK by
/// default because EDB is the default base name.
/// </summary>
public string BaseName
{
get
{
return this.GetStringParameter(JET_param.BaseName);
}
set
{
this.SetStringParameter(JET_param.BaseName, value);
}
}
/// <summary>
/// Gets or sets an application specific string that will be added to
/// any event log messages that are emitted by the database engine. This allows
/// easy correlation of event log messages with the source application. By default
/// the host application executable name will be used.
/// </summary>
public string EventSource
{
get
{
return this.GetStringParameter(JET_param.EventSource);
}
set
{
this.SetStringParameter(JET_param.EventSource, value);
}
}
/// <summary>
/// Gets or sets the number of sessions resources reserved for this instance.
/// A session resource directly corresponds to a JET_SESID.
/// </summary>
public int MaxSessions
{
get
{
return this.GetIntegerParameter(JET_param.MaxSessions);
}
set
{
this.SetIntegerParameter(JET_param.MaxSessions, value);
}
}
/// <summary>
/// Gets or sets the number of B+ Tree resources reserved for this instance.
/// </summary>
public int MaxOpenTables
{
get
{
return this.GetIntegerParameter(JET_param.MaxOpenTables);
}
set
{
this.SetIntegerParameter(JET_param.MaxOpenTables, value);
}
}
/// <summary>
/// Gets or sets the number of cursor resources reserved for this instance.
/// A cursor resource directly corresponds to a JET_TABLEID.
/// </summary>
public int MaxCursors
{
get
{
return this.GetIntegerParameter(JET_param.MaxCursors);
}
set
{
this.SetIntegerParameter(JET_param.MaxCursors, value);
}
}
/// <summary>
/// Gets or sets the maximum number of version store pages reserved
/// for this instance.
/// </summary>
public int MaxVerPages
{
get
{
return this.GetIntegerParameter(JET_param.MaxVerPages);
}
set
{
this.SetIntegerParameter(JET_param.MaxVerPages, value);
}
}
/// <summary>
/// Gets or sets the preferred number of version store pages reserved
/// for this instance. If the size of the version store exceeds this
/// threshold then any information that is only used for optional
/// background tasks, such as reclaiming deleted space in the database,
/// is instead sacrificed to preserve room for transactional information.
/// </summary>
public int PreferredVerPages
{
get
{
return this.GetIntegerParameter(JET_param.PreferredVerPages);
}
set
{
this.SetIntegerParameter(JET_param.PreferredVerPages, value);
}
}
/// <summary>
/// Gets or sets the the number of background cleanup work items that
/// can be queued to the database engine thread pool at any one time.
/// </summary>
public int VersionStoreTaskQueueMax
{
get
{
return this.GetIntegerParameter(JET_param.VersionStoreTaskQueueMax);
}
set
{
this.SetIntegerParameter(JET_param.VersionStoreTaskQueueMax, value);
}
}
/// <summary>
/// Gets or sets the number of temporary table resources for use
/// by an instance. This setting will affect how many temporary tables can be used at
/// the same time. If this system parameter is set to zero then no temporary database
/// will be created and any activity that requires use of the temporary database will
/// fail. This setting can be useful to avoid the I/O required to create the temporary
/// database if it is known that it will not be used.
/// </summary>
/// <remarks>
/// The use of a temporary table also requires a cursor resource.
/// </remarks>
public int MaxTemporaryTables
{
get
{
return this.GetIntegerParameter(JET_param.MaxTemporaryTables);
}
set
{
this.SetIntegerParameter(JET_param.MaxTemporaryTables, value);
}
}
/// <summary>
/// Gets or sets the size of the transaction log files. This parameter
/// should be set in units of 1024 bytes (e.g. a setting of 2048 will
/// give 2MB logfiles).
/// </summary>
public int LogFileSize
{
get
{
return this.GetIntegerParameter(JET_param.LogFileSize);
}
set
{
this.SetIntegerParameter(JET_param.LogFileSize, value);
}
}
/// <summary>
/// Gets or sets the amount of memory used to cache log records
/// before they are written to the transaction log file. The unit for this
/// parameter is the sector size of the volume that holds the transaction log files.
/// The sector size is almost always 512 bytes, so it is safe to assume that size
/// for the unit. This parameter has an impact on performance. When the database
/// engine is under heavy update load, this buffer can become full very rapidly.
/// A larger cache size for the transaction log file is critical for good update
/// performance under such a high load condition. The default is known to be too small
/// for this case.
/// Do not set this parameter to a number of buffers that is larger (in bytes) than
/// half the size of a transaction log file.
/// </summary>
public int LogBuffers
{
get
{
return this.GetIntegerParameter(JET_param.LogBuffers);
}
set
{
this.SetIntegerParameter(JET_param.LogBuffers, value);
}
}
/// <summary>
/// Gets or sets a value indicating whether circular logging is on.
/// When circular logging is off, all transaction log files that are generated
/// are retained on disk until they are no longer needed because a full backup of the
/// database has been performed. When circular logging is on, only transaction log files
/// that are younger than the current checkpoint are retained on disk. The benefit of
/// this mode is that backups are not required to retire old transaction log files.
/// </summary>
public bool CircularLog
{
get
{
return this.GetBoolParameter(JET_param.CircularLog);
}
set
{
this.SetBoolParameter(JET_param.CircularLog, value);
}
}
/// <summary>
/// Gets or sets a value indicating whether JetInit fails when the database
/// engine is configured to start using transaction log files on disk
/// that are of a different size than what is configured. Normally,
/// <see cref="Api.JetInit"/> will successfully recover the databases
/// but will fail with <see cref="JET_err.LogFileSizeMismatchDatabasesConsistent"/>
/// to indicate that the log file size is misconfigured. However, when
/// this parameter is set to true then the database engine will silently
/// delete all the old log files, start a new set of transaction log files
/// using the configured log file size. This parameter is useful when the
/// application wishes to transparently change its transaction log file
/// size yet still work transparently in upgrade and restore scenarios.
/// </summary>
public bool CleanupMismatchedLogFiles
{
get
{
return this.GetBoolParameter(JET_param.CleanupMismatchedLogFiles);
}
set
{
this.SetBoolParameter(JET_param.CleanupMismatchedLogFiles, value);
}
}
/// <summary>
/// Gets or sets the initial size of the temporary database. The size is in
/// database pages. A size of zero indicates that the default size of an ordinary
/// database should be used. It is often desirable for small applications to configure
/// the temporary database to be as small as possible. Setting this parameter to
/// <see cref="SystemParameters.PageTempDBSmallest"/> will achieve the smallest
/// temporary database possible.
/// </summary>
public int PageTempDBMin
{
get
{
return this.GetIntegerParameter(JET_param.PageTempDBMin);
}
set
{
this.SetIntegerParameter(JET_param.PageTempDBMin, value);
}
}
/// <summary>
/// Gets or sets the threshold in bytes for about how many transaction log
/// files will need to be replayed after a crash. If circular logging is enabled using
/// CircularLog then this parameter will also control the approximate amount
/// of transaction log files that will be retained on disk.
/// </summary>
public int CheckpointDepthMax
{
get
{
return this.GetIntegerParameter(JET_param.CheckpointDepthMax);
}
set
{
this.SetIntegerParameter(JET_param.CheckpointDepthMax, value);
}
}
/// <summary>
/// Gets or sets the number of pages that are added to a database file each
/// time it needs to grow to accommodate more data.
/// </summary>
public int DbExtensionSize
{
get
{
return this.GetIntegerParameter(JET_param.DbExtensionSize);
}
set
{
this.SetIntegerParameter(JET_param.DbExtensionSize, value);
}
}
/// <summary>
/// Gets or sets a value indicating whether crash recovery is on.
/// </summary>
public bool Recovery
{
get
{
return 0 == string.Compare(this.GetStringParameter(JET_param.Recovery), "on", StringComparison.OrdinalIgnoreCase);
}
set
{
if (value)
{
this.SetStringParameter(JET_param.Recovery, "on");
}
else
{
this.SetStringParameter(JET_param.Recovery, "off");
}
}
}
/// <summary>
/// Gets or sets a value indicating whether online defragmentation is enabled.
/// </summary>
public bool EnableOnlineDefrag
{
get
{
return this.GetBoolParameter(JET_param.EnableOnlineDefrag);
}
set
{
this.SetBoolParameter(JET_param.EnableOnlineDefrag, value);
}
}
/// <summary>
/// Gets or sets a value indicating whether <see cref="Api.JetAttachDatabase"/> will check for
/// indexes that were build using an older version of the NLS library in the
/// operating system.
/// </summary>
public bool EnableIndexChecking
{
get
{
return this.GetBoolParameter(JET_param.EnableIndexChecking);
}
set
{
this.SetBoolParameter(JET_param.EnableIndexChecking, value);
}
}
/// <summary>
/// Gets or sets the name of the event log the database engine uses for its event log
/// messages. By default, all event log messages will go to the Application event log. If the registry
/// key name for another event log is configured then the event log messages will go there instead.
/// </summary>
public string EventSourceKey
{
get
{
return this.GetStringParameter(JET_param.EventSourceKey);
}
set
{
this.SetStringParameter(JET_param.EventSourceKey, value);
}
}
/// <summary>
/// Gets or sets a value indicating whether informational event
/// log messages that would ordinarily be generated by the
/// database engine will be suppressed.
/// </summary>
public bool NoInformationEvent
{
get
{
return this.GetBoolParameter(JET_param.NoInformationEvent);
}
set
{
this.SetBoolParameter(JET_param.NoInformationEvent, value);
}
}
/// <summary>
/// Gets or sets the detail level of eventlog messages that are emitted
/// to the eventlog by the database engine. Higher numbers will result
/// in more detailed eventlog messages.
/// </summary>
public EventLoggingLevels EventLoggingLevel
{
get
{
return (EventLoggingLevels)this.GetIntegerParameter(JET_param.EventLoggingLevel);
}
set
{
this.SetIntegerParameter(JET_param.EventLoggingLevel, (int)value);
}
}
/// <summary>
/// Gets or sets a value indicating whether only one database is allowed to
/// be opened using JetOpenDatabase by a given session at one time.
/// The temporary database is excluded from this restriction.
/// </summary>
public bool OneDatabasePerSession
{
get
{
return this.GetBoolParameter(JET_param.OneDatabasePerSession);
}
set
{
this.SetBoolParameter(JET_param.OneDatabasePerSession, value);
}
}
/// <summary>
/// Gets or sets a value indicating whether ESENT will silently create folders
/// that are missing in its filesystem paths.
/// </summary>
public bool CreatePathIfNotExist
{
get
{
return this.GetBoolParameter(JET_param.CreatePathIfNotExist);
}
set
{
this.SetBoolParameter(JET_param.CreatePathIfNotExist, value);
}
}
/// <summary>
/// Gets or sets a value giving the number of B+ Tree resources cached by
/// the instance after the tables they represent have been closed by
/// the application. Large values for this parameter will cause the
/// database engine to use more memory but will increase the speed
/// with which a large number of tables can be opened randomly by
/// the application. This is useful for applications that have a
/// schema with a very large number of tables.
/// <para>
/// Supported on Windows Vista and up. Ignored on Windows XP and
/// Windows Server 2003.
/// </para>
/// </summary>
public int CachedClosedTables
{
get
{
if (EsentVersion.SupportsVistaFeatures)
{
return this.GetIntegerParameter(VistaParam.CachedClosedTables);
}
return 0;
}
set
{
if (EsentVersion.SupportsVistaFeatures)
{
this.SetIntegerParameter(VistaParam.CachedClosedTables, value);
}
}
}
/// <summary>
/// Gets or sets a the number of logs that esent will defer database
/// flushes for. This can be used to increase database recoverability if
/// failures cause logfiles to be lost.
/// <para>
/// Supported on Windows 7 and up. Ignored on Windows XP,
/// Windows Server 2003, Windows Vista and Windows Server 2008.
/// </para>
/// </summary>
public int WaypointLatency
{
get
{
if (EsentVersion.SupportsWindows7Features)
{
return this.GetIntegerParameter(Windows7Param.WaypointLatency);
}
// older versions have no waypoint
return 0;
}
set
{
if (EsentVersion.SupportsWindows7Features)
{
this.SetIntegerParameter(Windows7Param.WaypointLatency, value);
}
}
}
/// <summary>
/// Gets or sets a value indicating whether <see cref="Api.JetAttachDatabase"/> will
/// delete indexes that were build using an older version of the NLS library in the
/// operating system.
/// </summary>
public bool EnableIndexCleanup
{
get
{
return this.GetBoolParameter(JET_param.EnableIndexCleanup);
}
set
{
this.SetBoolParameter(JET_param.EnableIndexCleanup, value);
}
}
/// <summary>
/// Returns a <see cref="T:System.String"/> that represents the current <see cref="InstanceParameters"/>.
/// </summary>
/// <returns>
/// A <see cref="T:System.String"/> that represents the current <see cref="InstanceParameters"/>.
/// </returns>
public override string ToString()
{
return string.Format(CultureInfo.InvariantCulture, "InstanceParameters (0x{0:x})", this.instance.Value);
}
/// <summary>
/// Set a system parameter which is a string.
/// </summary>
/// <param name="param">The parameter to set.</param>
/// <param name="value">The value to set.</param>
private void SetStringParameter(JET_param param, string value)
{
Api.JetSetSystemParameter(this.instance, this.sesid, param, 0, value);
}
/// <summary>
/// Get a system parameter which is a string.
/// </summary>
/// <param name="param">The parameter to get.</param>
/// <returns>The value of the parameter.</returns>
private string GetStringParameter(JET_param param)
{
int ignored = 0;
string value;
Api.JetGetSystemParameter(this.instance, this.sesid, param, ref ignored, out value, 1024);
return value;
}
/// <summary>
/// Set a system parameter which is an integer.
/// </summary>
/// <param name="param">The parameter to set.</param>
/// <param name="value">The value to set.</param>
private void SetIntegerParameter(JET_param param, int value)
{
Api.JetSetSystemParameter(this.instance, this.sesid, param, value, null);
}
/// <summary>
/// Get a system parameter which is an integer.
/// </summary>
/// <param name="param">The parameter to get.</param>
/// <returns>The value of the parameter.</returns>
private int GetIntegerParameter(JET_param param)
{
int value = 0;
string ignored;
Api.JetGetSystemParameter(this.instance, this.sesid, param, ref value, out ignored, 0);
return value;
}
/// <summary>
/// Set a system parameter which is a boolean.
/// </summary>
/// <param name="param">The parameter to set.</param>
/// <param name="value">The value to set.</param>
private void SetBoolParameter(JET_param param, bool value)
{
if (value)
{
Api.JetSetSystemParameter(this.instance, this.sesid, param, 1, null);
}
else
{
Api.JetSetSystemParameter(this.instance, this.sesid, param, 0, null);
}
}
/// <summary>
/// Get a system parameter which is a boolean.
/// </summary>
/// <param name="param">The parameter to get.</param>
/// <returns>The value of the parameter.</returns>
private bool GetBoolParameter(JET_param param)
{
int value = 0;
string ignored;
Api.JetGetSystemParameter(this.instance, this.sesid, param, ref value, out ignored, 0);
return value != 0;
}
}
}

View File

@ -0,0 +1,69 @@
//-----------------------------------------------------------------------
// <copyright file="Int16ColumnValue.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
using System.Diagnostics;
/// <summary>
/// An <see cref="short"/> column value.
/// </summary>
public class Int16ColumnValue : ColumnValueOfStruct<short>
{
/// <summary>
/// Gets the size of the value in the column. This returns 0 for
/// variable sized columns (i.e. binary and string).
/// </summary>
protected override int Size
{
[DebuggerStepThrough]
get { return sizeof(short); }
}
/// <summary>
/// Recursive SetColumns method for data pinning. This populates the buffer and
/// calls the inherited SetColumns method.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">
/// The table to set the columns in. An update should be prepared.
/// </param>
/// <param name="columnValues">
/// Column values to set.
/// </param>
/// <param name="nativeColumns">
/// Structures to put the pinned data in.
/// </param>
/// <param name="i">Offset of this object in the array.</param>
/// <returns>An error code.</returns>
internal override unsafe int SetColumns(JET_SESID sesid, JET_TABLEID tableid, ColumnValue[] columnValues, NATIVE_SETCOLUMN* nativeColumns, int i)
{
var data = this.Value.GetValueOrDefault();
return this.SetColumns(sesid, tableid, columnValues, nativeColumns, i, &data, sizeof(short), this.Value.HasValue);
}
/// <summary>
/// Given data retrieved from ESENT, decode the data and set the value in the ColumnValue object.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within the bytes.</param>
/// <param name="count">The number of bytes to decode.</param>
/// <param name="err">The error returned from ESENT.</param>
protected override void GetValueFromBytes(byte[] value, int startIndex, int count, int err)
{
if (JET_wrn.ColumnNull == (JET_wrn)err)
{
this.Value = null;
}
else
{
this.CheckDataCount(count);
this.Value = BitConverter.ToInt16(value, startIndex);
}
}
}
}

View File

@ -0,0 +1,69 @@
//-----------------------------------------------------------------------
// <copyright file="Int32ColumnValue.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
using System.Diagnostics;
/// <summary>
/// An <see cref="int"/> column value.
/// </summary>
public class Int32ColumnValue : ColumnValueOfStruct<int>
{
/// <summary>
/// Gets the size of the value in the column. This returns 0 for
/// variable sized columns (i.e. binary and string).
/// </summary>
protected override int Size
{
[DebuggerStepThrough]
get { return sizeof(int); }
}
/// <summary>
/// Recursive SetColumns method for data pinning. This populates the buffer and
/// calls the inherited SetColumns method.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">
/// The table to set the columns in. An update should be prepared.
/// </param>
/// <param name="columnValues">
/// Column values to set.
/// </param>
/// <param name="nativeColumns">
/// Structures to put the pinned data in.
/// </param>
/// <param name="i">Offset of this object in the array.</param>
/// <returns>An error code.</returns>
internal override unsafe int SetColumns(JET_SESID sesid, JET_TABLEID tableid, ColumnValue[] columnValues, NATIVE_SETCOLUMN* nativeColumns, int i)
{
var data = this.Value.GetValueOrDefault();
return this.SetColumns(sesid, tableid, columnValues, nativeColumns, i, &data, sizeof(int), this.Value.HasValue);
}
/// <summary>
/// Given data retrieved from ESENT, decode the data and set the value in the ColumnValue object.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within the bytes.</param>
/// <param name="count">The number of bytes to decode.</param>
/// <param name="err">The error returned from ESENT.</param>
protected override void GetValueFromBytes(byte[] value, int startIndex, int count, int err)
{
if (JET_wrn.ColumnNull == (JET_wrn)err)
{
this.Value = null;
}
else
{
this.CheckDataCount(count);
this.Value = BitConverter.ToInt32(value, startIndex);
}
}
}
}

View File

@ -0,0 +1,69 @@
//-----------------------------------------------------------------------
// <copyright file="Int64ColumnValue.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
using System.Diagnostics;
/// <summary>
/// An <see cref="long"/> column value.
/// </summary>
public class Int64ColumnValue : ColumnValueOfStruct<long>
{
/// <summary>
/// Gets the size of the value in the column. This returns 0 for
/// variable sized columns (i.e. binary and string).
/// </summary>
protected override int Size
{
[DebuggerStepThrough]
get { return sizeof(long); }
}
/// <summary>
/// Recursive SetColumns method for data pinning. This populates the buffer and
/// calls the inherited SetColumns method.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">
/// The table to set the columns in. An update should be prepared.
/// </param>
/// <param name="columnValues">
/// Column values to set.
/// </param>
/// <param name="nativeColumns">
/// Structures to put the pinned data in.
/// </param>
/// <param name="i">Offset of this object in the array.</param>
/// <returns>An error code.</returns>
internal override unsafe int SetColumns(JET_SESID sesid, JET_TABLEID tableid, ColumnValue[] columnValues, NATIVE_SETCOLUMN* nativeColumns, int i)
{
var data = this.Value.GetValueOrDefault();
return this.SetColumns(sesid, tableid, columnValues, nativeColumns, i, &data, sizeof(long), this.Value.HasValue);
}
/// <summary>
/// Given data retrieved from ESENT, decode the data and set the value in the ColumnValue object.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within the bytes.</param>
/// <param name="count">The number of bytes to decode.</param>
/// <param name="err">The error returned from ESENT.</param>
protected override void GetValueFromBytes(byte[] value, int startIndex, int count, int err)
{
if (JET_wrn.ColumnNull == (JET_wrn)err)
{
this.Value = null;
}
else
{
this.CheckDataCount(count);
this.Value = BitConverter.ToInt64(value, startIndex);
}
}
}
}

View File

@ -0,0 +1,192 @@
//-----------------------------------------------------------------------
// <copyright file="InternalApi.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
/// <summary>
/// Internal-only methods of the Api.
/// </summary>
public static partial class Api
{
/// <summary>
/// The JetSetColumn function modifies a single column value in a modified record to be inserted or to
/// update the current record. It can overwrite an existing value, add a new value to a sequence of
/// values in a multi-valued column, remove a value from a sequence of values in a multi-valued column,
/// or update all or part of a long value (a column of type <see cref="JET_coltyp.LongText"/>
/// or <see cref="JET_coltyp.LongBinary"/>).
/// </summary>
/// <remarks>
/// This is an internal-only version of the API that takes a data buffer and an offset into the buffer.
/// </remarks>
/// <param name="sesid">The session which is performing the update.</param>
/// <param name="tableid">The cursor to update. An update should be prepared.</param>
/// <param name="columnid">The columnid to set.</param>
/// <param name="data">The data to set.</param>
/// <param name="dataSize">The size of data to set.</param>
/// <param name="dataOffset">The offset in the data buffer to set data from.</param>
/// <param name="grbit">SetColumn options.</param>
/// <param name="setinfo">Used to specify itag or long-value offset.</param>
/// <returns>A warning value.</returns>
public static JET_wrn JetSetColumn(JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, byte[] data, int dataSize, int dataOffset, SetColumnGrbit grbit, JET_SETINFO setinfo)
{
if (dataOffset < 0
|| (null != data && 0 != dataSize && dataOffset >= data.Length)
|| (null == data && dataOffset != 0))
{
throw new ArgumentOutOfRangeException(
"dataOffset",
dataOffset,
"must be inside the data buffer");
}
if (null != data && dataSize > checked(data.Length - dataOffset) && (SetColumnGrbit.SizeLV != (grbit & SetColumnGrbit.SizeLV)))
{
throw new ArgumentOutOfRangeException(
"dataSize",
dataSize,
"cannot be greater than the length of the data (unless the SizeLV option is used)");
}
unsafe
{
fixed (byte* pointer = data)
{
return Api.JetSetColumn(sesid, tableid, columnid, new IntPtr(pointer + dataOffset), dataSize, grbit, setinfo);
}
}
}
/// <summary>
/// Retrieves a single column value from the current record. The record is that
/// record associated with the index entry at the current position of the cursor.
/// Alternatively, this function can retrieve a column from a record being created
/// in the cursor copy buffer. This function can also retrieve column data from an
/// index entry that references the current record. In addition to retrieving the
/// actual column value, JetRetrieveColumn can also be used to retrieve the size
/// of a column, before retrieving the column data itself so that application
/// buffers can be sized appropriately.
/// </summary>
/// <remarks>
/// This is an internal method that takes a buffer offset as well as size.
/// </remarks>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to retrieve the column from.</param>
/// <param name="columnid">The columnid to retrieve.</param>
/// <param name="data">The data buffer to be retrieved into.</param>
/// <param name="dataSize">The size of the data buffer.</param>
/// <param name="dataOffset">Offset into the data buffer to read data into.</param>
/// <param name="actualDataSize">Returns the actual size of the data buffer.</param>
/// <param name="grbit">Retrieve column options.</param>
/// <param name="retinfo">
/// If pretinfo is give as NULL then the function behaves as though an itagSequence
/// of 1 and an ibLongValue of 0 (zero) were given. This causes column retrieval to
/// retrieve the first value of a multi-valued column, and to retrieve long data at
/// offset 0 (zero).
/// </param>
/// <returns>An ESENT warning code.</returns>
public static JET_wrn JetRetrieveColumn(JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, byte[] data, int dataSize, int dataOffset, out int actualDataSize, RetrieveColumnGrbit grbit, JET_RETINFO retinfo)
{
if (dataOffset < 0
|| (null != data && 0 != dataSize && dataOffset >= data.Length)
|| (null == data && dataOffset != 0))
{
throw new ArgumentOutOfRangeException(
"dataOffset",
dataOffset,
"must be inside the data buffer");
}
if ((null == data && dataSize > 0) || (null != data && dataSize > data.Length))
{
throw new ArgumentOutOfRangeException(
"dataSize",
dataSize,
"cannot be greater than the length of the data");
}
unsafe
{
fixed (byte* pointer = data)
{
return Api.JetRetrieveColumn(
sesid, tableid, columnid, new IntPtr(pointer + dataOffset), dataSize, out actualDataSize, grbit, retinfo);
}
}
}
/// <summary>
/// Retrieves a single column value from the current record. The record is that
/// record associated with the index entry at the current position of the cursor.
/// Alternatively, this function can retrieve a column from a record being created
/// in the cursor copy buffer. This function can also retrieve column data from an
/// index entry that references the current record. In addition to retrieving the
/// actual column value, JetRetrieveColumn can also be used to retrieve the size
/// of a column, before retrieving the column data itself so that application
/// buffers can be sized appropriately.
/// </summary>
/// <remarks>
/// This is an internal-use version that takes an IntPtr.
/// </remarks>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to retrieve the column from.</param>
/// <param name="columnid">The columnid to retrieve.</param>
/// <param name="data">The data buffer to be retrieved into.</param>
/// <param name="dataSize">The size of the data buffer.</param>
/// <param name="actualDataSize">Returns the actual size of the data buffer.</param>
/// <param name="grbit">Retrieve column options.</param>
/// <param name="retinfo">
/// If pretinfo is give as NULL then the function behaves as though an itagSequence
/// of 1 and an ibLongValue of 0 (zero) were given. This causes column retrieval to
/// retrieve the first value of a multi-valued column, and to retrieve long data at
/// offset 0 (zero).
/// </param>
/// <returns>An ESENT warning code.</returns>
internal static JET_wrn JetRetrieveColumn(JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, IntPtr data, int dataSize, out int actualDataSize, RetrieveColumnGrbit grbit, JET_RETINFO retinfo)
{
return Api.Check(Impl.JetRetrieveColumn(sesid, tableid, columnid, data, dataSize, out actualDataSize, grbit, retinfo));
}
/// <summary>
/// Constructs search keys that may then be used by JetSeek and JetSetIndexRange.
/// </summary>
/// <remarks>
/// This is an internal (unsafe) version that takes an IntPtr.
/// </remarks>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to create the key on.</param>
/// <param name="data">Column data for the current key column of the current index.</param>
/// <param name="dataSize">Size of the data.</param>
/// <param name="grbit">Key options.</param>
internal static void JetMakeKey(JET_SESID sesid, JET_TABLEID tableid, IntPtr data, int dataSize, MakeKeyGrbit grbit)
{
Api.Check(Impl.JetMakeKey(sesid, tableid, data, dataSize, grbit));
}
/// <summary>
/// The JetSetColumn function modifies a single column value in a modified record to be inserted or to
/// update the current record. It can overwrite an existing value, add a new value to a sequence of
/// values in a multi-valued column, remove a value from a sequence of values in a multi-valued column,
/// or update all or part of a long value, a column of type JET_coltyp.LongText or JET_coltyp.LongBinary.
/// </summary>
/// <remarks>
/// This method takes an IntPtr and is intended for internal use only.
/// </remarks>
/// <param name="sesid">The session which is performing the update.</param>
/// <param name="tableid">The cursor to update. An update should be prepared.</param>
/// <param name="columnid">The columnid to set.</param>
/// <param name="data">The data to set.</param>
/// <param name="dataSize">The size of data to set.</param>
/// <param name="grbit">SetColumn options.</param>
/// <param name="setinfo">Used to specify itag or long-value offset.</param>
/// <returns>A warning value.</returns>
internal static JET_wrn JetSetColumn(JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, IntPtr data, int dataSize, SetColumnGrbit grbit, JET_SETINFO setinfo)
{
return Api.Check(Impl.JetSetColumn(sesid, tableid, columnid, data, dataSize, grbit, setinfo));
}
}
}

View File

@ -0,0 +1,56 @@
//-----------------------------------------------------------------------
// <copyright file="IntersectIndexesEnumerator.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
/// <summary>
/// Enumerator that can intersect indexes and return the intersected bookmarks.
/// </summary>
internal sealed class IntersectIndexesEnumerator : TableEnumerator<byte[]>
{
/// <summary>
/// The ranges to intersect.
/// </summary>
private readonly JET_INDEXRANGE[] ranges;
/// <summary>
/// The recordlist containing the result of the intersection.
/// </summary>
private JET_RECORDLIST recordlist;
/// <summary>
/// Initializes a new instance of the <see cref="IntersectIndexesEnumerator"/> class.
/// </summary>
/// <param name="sesid">
/// The session to use.
/// </param>
/// <param name="ranges">
/// The ranges to intersect.
/// </param>
public IntersectIndexesEnumerator(JET_SESID sesid, JET_INDEXRANGE[] ranges) : base(sesid)
{
this.ranges = ranges;
}
/// <summary>
/// Open the table to be enumerated. This should set <see cref="TableEnumerator{T}.TableidToEnumerate"/>.
/// </summary>
protected override void OpenTable()
{
Api.JetIntersectIndexes(this.Sesid, this.ranges, this.ranges.Length, out this.recordlist, IntersectIndexesGrbit.None);
this.TableidToEnumerate = this.recordlist.tableid;
}
/// <summary>
/// Gets the entry the cursor is currently positioned on.
/// </summary>
/// <returns>The entry the cursor is currently positioned on.</returns>
protected override byte[] GetCurrent()
{
return Api.RetrieveColumn(this.Sesid, this.TableidToEnumerate, this.recordlist.columnidBookmark);
}
}
}

View File

@ -0,0 +1,44 @@
//-----------------------------------------------------------------------
// <copyright file="JET_eventlogginglevel.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
/// <summary>
/// Options for EventLoggingLevel.
/// </summary>
public enum EventLoggingLevels
{
/// <summary>
/// Disable all events.
/// </summary>
Disable = 0,
/// <summary>
/// Default level. Windows 7 and later.
/// </summary>
Min = 1,
/// <summary>
/// Low verbosity and lower. Windows 7 and later.
/// </summary>
Low = 25,
/// <summary>
/// Medium verbosity and lower. Windows 7 and later.
/// </summary>
Medium = 50,
/// <summary>
/// High verbosity and lower. Windows 7 and later.
/// </summary>
High = 75,
/// <summary>
/// All events.
/// </summary>
Max = 100,
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,175 @@
//-----------------------------------------------------------------------
// <copyright file="JetCallbackWrapper.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
/// <summary>
/// A multi-purpose callback function used by the database engine to inform
/// the application of an event involving online defragmentation and cursor
/// state notifications.
/// </summary>
/// <param name="sesid">The session for which the callback is being made.</param>
/// <param name="dbid">The database for which the callback is being made.</param>
/// <param name="tableid">The cursor for which the callback is being made.</param>
/// <param name="cbtyp">The operation for which the callback is being made.</param>
/// <param name="arg1">First callback-specific argument.</param>
/// <param name="arg2">Second callback-specific argument.</param>
/// <param name="context">Callback context.</param>
/// <param name="unused">This parameter is not used.</param>
/// <returns>An ESENT error code.</returns>
internal delegate JET_err NATIVE_CALLBACK(
IntPtr sesid,
uint dbid,
IntPtr tableid,
uint cbtyp,
IntPtr arg1,
IntPtr arg2,
IntPtr context,
IntPtr unused);
/// <summary>
/// Wraps a NATIVE_CALLBACK callback around a JET_CALLBACK. This is
/// used to catch exceptions and provide argument conversion.
/// </summary>
internal sealed class JetCallbackWrapper
{
/// <summary>
/// API call tracing.
/// </summary>
private static readonly TraceSwitch TraceSwitch = new TraceSwitch("ESENT JetCallbackWrapper", "Wrapper around unmanaged ESENT callback");
/// <summary>
/// The wrapped status callback.
/// </summary>
private readonly WeakReference wrappedCallback;
/// <summary>
/// The native version of the callback. This will actually be a closure
/// because we are calling a non-static method. Keep track of it here
/// to make sure that it isn't garbage collected.
/// </summary>
private readonly NATIVE_CALLBACK nativeCallback;
#if !MANAGEDESENT_ON_WSA
/// <summary>
/// Initializes static members of the <see cref="JetCallbackWrapper"/> class.
/// </summary>
static JetCallbackWrapper()
{
// We don't want a JIT failure when trying to execute the callback
// because that would throw an exception through ESENT, corrupting it.
// It is fine for the wrapped callback to fail because CallbackImpl
// will catch the exception and deal with it.
RuntimeHelpers.PrepareMethod(typeof(StatusCallbackWrapper).GetMethod(
"CallbackImpl",
BindingFlags.NonPublic | BindingFlags.Instance).MethodHandle);
}
#endif // !MANAGEDESENT_ON_WSA
/// <summary>
/// Initializes a new instance of the JetCallbackWrapper class.
/// </summary>
/// <param name="callback">
/// The managed callback to use.
/// </param>
public JetCallbackWrapper(JET_CALLBACK callback)
{
this.wrappedCallback = new WeakReference(callback);
this.nativeCallback = this.CallbackImpl;
Debug.Assert(this.wrappedCallback.IsAlive, "Callback isn't alive");
}
/// <summary>
/// Gets a value indicating whether the wrapped callback has been garbage
/// collected.
/// </summary>
public bool IsAlive
{
get
{
return this.wrappedCallback.IsAlive;
}
}
/// <summary>
/// Gets a NATIVE_CALLBACK callback that wraps the managed callback.
/// </summary>
public NATIVE_CALLBACK NativeCallback
{
get
{
return this.nativeCallback;
}
}
/// <summary>
/// Determine if the callback is wrapping the specified JET_CALLBACK.
/// </summary>
/// <param name="callback">The callback.</param>
/// <returns>True if this wrapper is wrapping the callback.</returns>
public bool IsWrapping(JET_CALLBACK callback)
{
return callback.Equals(this.wrappedCallback.Target);
}
/// <summary>
/// Callback function for native code. We don't want to throw an exception through
/// unmanaged ESENT because that will corrupt ESENT's internal state. Instead we
/// catch all exceptions and return an error instead. We use a CER to make catching
/// the exceptions as reliable as possible.
/// </summary>
/// <param name="nativeSesid">The session for which the callback is being made.</param>
/// <param name="nativeDbid">The database for which the callback is being made.</param>
/// <param name="nativeTableid">The cursor for which the callback is being made.</param>
/// <param name="nativeCbtyp">The operation for which the callback is being made.</param>
/// <param name="arg1">First callback-specific argument.</param>
/// <param name="arg2">Second callback-specific argument.</param>
/// <param name="nativeContext">Callback context.</param>
/// <param name="unused">This parameter is not used.</param>
/// <returns>An ESENT error code.</returns>
private JET_err CallbackImpl(
IntPtr nativeSesid,
uint nativeDbid,
IntPtr nativeTableid,
uint nativeCbtyp,
IntPtr arg1,
IntPtr arg2,
IntPtr nativeContext,
IntPtr unused)
{
RuntimeHelpers.PrepareConstrainedRegions();
try
{
var sesid = new JET_SESID { Value = nativeSesid };
var dbid = new JET_DBID { Value = nativeDbid };
var tableid = new JET_TABLEID { Value = nativeTableid };
JET_cbtyp cbtyp = (JET_cbtyp)nativeCbtyp;
Debug.Assert(this.wrappedCallback.IsAlive, "Wrapped callback has been garbage collected");
// This will throw an exception if the wrapped callback has been collected. The exception
// will be handled below.
JET_CALLBACK callback = (JET_CALLBACK)this.wrappedCallback.Target;
return callback(sesid, dbid, tableid, cbtyp, null, null, nativeContext, IntPtr.Zero);
}
catch (Exception ex)
{
// Thread aborts aren't handled here. ESENT callbacks can execute on client threads or
// internal ESENT threads so it isn't clear what should be done on an abort.
Trace.WriteLineIf(
TraceSwitch.TraceWarning,
string.Format(CultureInfo.InvariantCulture, "Caught Exception {0}", ex));
return JET_err.CallbackFailed;
}
}
}
}

View File

@ -0,0 +1,67 @@
//-----------------------------------------------------------------------
// <copyright file="JetCapabilities.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop.Implementation
{
/// <summary>
/// Describes the functionality exposed by an object which implements IJetApi.
/// </summary>
internal sealed class JetCapabilities
{
/// <summary>
/// Gets or sets a value indicating whether Windows Server 2003 features
/// (in the Interop.Server2003 namespace) are supported.
/// </summary>
public bool SupportsServer2003Features { get; set; }
/// <summary>
/// Gets or sets a value indicating whether Vista features (in the
/// Interop.Vista namespace) are supported.
/// </summary>
public bool SupportsVistaFeatures { get; set; }
/// <summary>
/// Gets or sets a value indicating whether Win7 features (in the
/// Interop.Windows7 namespace) are supported.
/// </summary>
public bool SupportsWindows7Features { get; set; }
/// <summary>
/// Gets or sets a value indicating whether Win8 features (in the
/// Interop.Windows8 namespace) are supported.
/// </summary>
public bool SupportsWindows8Features { get; set; }
/// <summary>
/// Gets or sets a value indicating whether Win8.1 features (in the
/// Interop.Windows81 namespace) are supported.
/// </summary>
public bool SupportsWindows81Features { get; set; }
/// <summary>
/// Gets or sets a value indicating whether Win10 features (in the
/// Interop.Windows10 namespace) are supported.
/// </summary>
public bool SupportsWindows10Features { get; set; }
/// <summary>
/// Gets or sets a value indicating whether unicode file paths are supported.
/// </summary>
public bool SupportsUnicodePaths { get; set; }
/// <summary>
/// Gets or sets a value indicating whether large (> 255 byte) keys are supported.
/// The key size for an index can be specified in the <see cref="JET_INDEXCREATE"/>
/// object.
/// </summary>
public bool SupportsLargeKeys { get; set; }
/// <summary>
/// Gets or sets the maximum number of components in a sort or index key.
/// </summary>
public int ColumnsKeyMost { get; set; }
}
}

View File

@ -0,0 +1,191 @@
//-----------------------------------------------------------------------
// <copyright file="jet_indexcreate3.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using Microsoft.Isam.Esent.Interop.Vista;
/// <summary>
/// The native version of the JET_INDEXCREATE3 structure.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
[SuppressMessage("Microsoft.StyleCop.CSharp.NamingRules",
"SA1305:FieldNamesMustNotUseHungarianNotation",
Justification = "This should match the unmanaged API, which isn't capitalized.")]
[SuppressMessage(
"Microsoft.StyleCop.CSharp.NamingRules",
"SA1307:AccessibleFieldsMustBeginWithUpperCaseLetter",
Justification = "This should match the unmanaged API, which isn't capitalized.")]
internal unsafe struct NATIVE_INDEXCREATE3
{
/// <summary>
/// Size of the structure.
/// </summary>
public uint cbStruct;
/// <summary>
/// Name of the index.
/// </summary>
public IntPtr szIndexName;
/// <summary>
/// Index key description.
/// </summary>
public IntPtr szKey;
/// <summary>
/// Size of index key description.
/// </summary>
public uint cbKey;
/// <summary>
/// Index options.
/// </summary>
public uint grbit;
/// <summary>
/// Index density.
/// </summary>
public uint ulDensity;
/// <summary>
/// Pointer to unicode sort options.
/// </summary>
public NATIVE_UNICODEINDEX2* pidxUnicode;
/// <summary>
/// Maximum size of column data to index. This can also be
/// a pointer to a JET_TUPLELIMITS structure.
/// </summary>
public IntPtr cbVarSegMac;
/// <summary>
/// Pointer to array of conditional columns.
/// </summary>
public IntPtr rgconditionalcolumn;
/// <summary>
/// Count of conditional columns.
/// </summary>
public uint cConditionalColumn;
/// <summary>
/// Returned error from index creation.
/// </summary>
public int err;
/// <summary>
/// Maximum size of the key.
/// </summary>
public uint cbKeyMost;
/// <summary>
/// A <see cref="NATIVE_SPACEHINTS"/> pointer.
/// </summary>
public IntPtr pSpaceHints;
}
/// <summary>
/// Contains the information needed to create an index over data in an ESE database.
/// </summary>
public sealed partial class JET_INDEXCREATE : IContentEquatable<JET_INDEXCREATE>, IDeepCloneable<JET_INDEXCREATE>
{
/// <summary>
/// Gets the native (interop) version of this object, except for
/// <see cref="szIndexName"/> and <see cref="szKey"/>.
/// </summary>
/// <remarks>The cbKey holds the length of the key in bytes, and does not need to be adjusted.</remarks>
/// <returns>The native (interop) version of this object.</returns>
internal NATIVE_INDEXCREATE3 GetNativeIndexcreate3()
{
this.CheckMembersAreValid();
var native = new NATIVE_INDEXCREATE3();
native.cbStruct = checked((uint)Marshal.SizeOf(typeof(NATIVE_INDEXCREATE3)));
// szIndexName and szKey are converted at pinvoke time.
//
// native.szIndexName = this.szIndexName;
// native.szKey = this.szKey;
native.cbKey = checked((uint)this.cbKey * sizeof(char));
native.grbit = unchecked((uint)this.grbit);
native.ulDensity = checked((uint)this.ulDensity);
native.cbVarSegMac = new IntPtr(this.cbVarSegMac);
native.cConditionalColumn = checked((uint)this.cConditionalColumn);
if (0 != this.cbKeyMost)
{
native.cbKeyMost = checked((uint)this.cbKeyMost);
native.grbit |= unchecked((uint)VistaGrbits.IndexKeyMost);
}
return native;
}
/// <summary>
/// Sets only the output fields of the object from a <see cref="NATIVE_INDEXCREATE3"/> struct,
/// specifically <see cref="err"/>.
/// </summary>
/// <param name="value">
/// The native indexcreate to set the values from.
/// </param>
internal void SetFromNativeIndexCreate(ref NATIVE_INDEXCREATE3 value)
{
this.err = (JET_err)value.err;
}
/// <summary>
/// Sets all of the fields (not just output fields) of the object from a <see cref="NATIVE_INDEXCREATE3"/> struct,
/// specifically <see cref="err"/>.
/// </summary>
/// <param name="value">
/// The native indexcreate to set the values from.
/// </param>
internal void SetAllFromNativeIndexCreate(ref NATIVE_INDEXCREATE3 value)
{
this.szIndexName = Marshal.PtrToStringUni(value.szIndexName);
this.cbKey = unchecked((int)value.cbKey / sizeof(char));
this.szKey = Marshal.PtrToStringUni(value.szKey, this.cbKey);
if (this.cbKey != this.szKey.Length)
{
throw new ArgumentException(string.Format("cbKey {0} != szKey.Length {1}", this.cbKey, this.szKey.Length));
}
this.grbit = unchecked((CreateIndexGrbit)value.grbit);
this.ulDensity = unchecked((int)value.ulDensity);
unsafe
{
this.pidxUnicode = new JET_UNICODEINDEX(ref *value.pidxUnicode);
}
this.cbVarSegMac = (int)value.cbVarSegMac;
this.cConditionalColumn = unchecked((int)value.cConditionalColumn);
this.rgconditionalcolumn = new JET_CONDITIONALCOLUMN[this.cConditionalColumn];
int sizeofConditionalColumn = Marshal.SizeOf(typeof(NATIVE_CONDITIONALCOLUMN));
for (int i = 0; i < this.cConditionalColumn; ++i)
{
IntPtr addressOfElement = value.rgconditionalcolumn + i * sizeofConditionalColumn;
NATIVE_CONDITIONALCOLUMN nativeConditionalColumn =
(NATIVE_CONDITIONALCOLUMN)Marshal.PtrToStructure(addressOfElement, typeof(NATIVE_CONDITIONALCOLUMN));
this.rgconditionalcolumn[i] = new JET_CONDITIONALCOLUMN(ref nativeConditionalColumn);
}
this.err = (JET_err)value.err;
this.cbKeyMost = unchecked((int)value.cbKeyMost);
var nativeSpaceHints = (NATIVE_SPACEHINTS)Marshal.PtrToStructure(value.pSpaceHints, typeof(NATIVE_SPACEHINTS));
this.pSpaceHints = new JET_SPACEHINTS();
this.pSpaceHints.SetFromNativeSpaceHints(nativeSpaceHints);
}
}
}

View File

@ -0,0 +1,97 @@
//-----------------------------------------------------------------------
// <copyright file="jet_opentemporarytable2.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop.Vista
{
using System;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Runtime.InteropServices;
/// <summary>
/// The native version of the JET_OPENTEMPORARYTABLE2 structure.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
[SuppressMessage("Microsoft.StyleCop.CSharp.NamingRules",
"SA1305:FieldNamesMustNotUseHungarianNotation",
Justification = "This should match the unmanaged API, which isn't capitalized.")]
[SuppressMessage(
"Microsoft.StyleCop.CSharp.NamingRules",
"SA1307:AccessibleFieldsMustBeginWithUpperCaseLetter",
Justification = "This should match the unmanaged API, which isn't capitalized.")]
internal unsafe struct NATIVE_OPENTEMPORARYTABLE2
{
/// <summary>
/// Size of the structure.
/// </summary>
public uint cbStruct;
/// <summary>
/// Columns to create.
/// </summary>
public NATIVE_COLUMNDEF* prgcolumndef;
/// <summary>
/// Number of entries in prgcolumndef.
/// </summary>
public uint ccolumn;
/// <summary>
/// Optional pointer to unicode index information.
/// </summary>
public NATIVE_UNICODEINDEX2* pidxunicode;
/// <summary>
/// Table options.
/// </summary>
public uint grbit;
/// <summary>
/// Pointer to array of returned columnids. This
/// should have at least ccolumn entries.
/// </summary>
public uint* rgcolumnid;
/// <summary>
/// Maximum key size.
/// </summary>
public uint cbKeyMost;
/// <summary>
/// Maximum amount of data used to construct a key.
/// </summary>
public uint cbVarSegMac;
/// <summary>
/// Returns the tableid of the new table.
/// </summary>
public IntPtr tableid;
}
/// <summary>
/// A collection of parameters for the JetOpenTemporaryTable method.
/// </summary>
public partial class JET_OPENTEMPORARYTABLE
{
/// <summary>
/// Returns the unmanaged opentemporarytable that represents this managed class.
/// </summary>
/// <returns>
/// A native (interop) version of the JET_OPENTEMPORARYTABLE.
/// </returns>
internal NATIVE_OPENTEMPORARYTABLE2 GetNativeOpenTemporaryTable2()
{
this.CheckDataSize();
var openTemporaryTable = new NATIVE_OPENTEMPORARYTABLE2();
openTemporaryTable.cbStruct = checked((uint)Marshal.SizeOf(typeof(NATIVE_OPENTEMPORARYTABLE2)));
openTemporaryTable.ccolumn = checked((uint)this.ccolumn);
openTemporaryTable.grbit = (uint)this.grbit;
openTemporaryTable.cbKeyMost = checked((uint)this.cbKeyMost);
openTemporaryTable.cbVarSegMac = checked((uint)this.cbVarSegMac);
return openTemporaryTable;
}
}
}

View File

@ -0,0 +1,159 @@
//-----------------------------------------------------------------------
// <copyright file="jet_tablecreate4.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Runtime.InteropServices;
using Microsoft.Isam.Esent.Interop.Implementation;
/// <summary>
/// The native version of the <see cref="JET_TABLECREATE"/> structure. This includes callbacks,
/// space hints, and uses NATIVE_INDEXCREATE4.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
[SuppressMessage("Microsoft.StyleCop.CSharp.NamingRules",
"SA1305:FieldNamesMustNotUseHungarianNotation",
Justification = "This should match the unmanaged API, which isn't capitalized.")]
[SuppressMessage(
"Microsoft.StyleCop.CSharp.NamingRules",
"SA1307:AccessibleFieldsMustBeginWithUpperCaseLetter",
Justification = "This should match the unmanaged API, which isn't capitalized.")]
internal unsafe struct NATIVE_TABLECREATE4
{
/// <summary>
/// Size of the structure.
/// </summary>
public uint cbStruct;
/// <summary>
/// Name of the table to create.
/// </summary>
[MarshalAs(UnmanagedType.LPWStr)]
public string szTableName;
/// <summary>
/// Name of the table from which to inherit base DDL.
/// </summary>
[MarshalAs(UnmanagedType.LPWStr)]
public string szTemplateTableName;
/// <summary>
/// Initial pages to allocate for table.
/// </summary>
public uint ulPages;
/// <summary>
/// Table density.
/// </summary>
public uint ulDensity;
/// <summary>
/// Array of column creation info.
/// </summary>
public NATIVE_COLUMNCREATE* rgcolumncreate;
/// <summary>
/// Number of columns to create.
/// </summary>
public uint cColumns;
/// <summary>
/// Array of indices to create, pointer to <see cref="NATIVE_INDEXCREATE3"/>.
/// </summary>
public IntPtr rgindexcreate;
/// <summary>
/// Number of indices to create.
/// </summary>
public uint cIndexes;
/// <summary>
/// Callback function to use for the table.
/// </summary>
[MarshalAs(UnmanagedType.LPWStr)]
public string szCallback;
/// <summary>
/// Type of the callback function.
/// </summary>
public JET_cbtyp cbtyp;
/// <summary>
/// Table options.
/// </summary>
public uint grbit;
/// <summary>
/// Space allocation, maintenance, and usage hints for default sequential index.
/// </summary>
public NATIVE_SPACEHINTS* pSeqSpacehints;
/// <summary>
/// Space allocation, maintenance, and usage hints for Separated LV tree.
/// </summary>
public NATIVE_SPACEHINTS* pLVSpacehints;
/// <summary>
/// Heuristic size to separate a intrinsic LV from the primary record.
/// </summary>
public uint cbSeparateLV;
/// <summary>
/// Returned tableid.
/// </summary>
public IntPtr tableid;
/// <summary>
/// Count of objects created (columns+table+indexes+callbacks).
/// </summary>
public uint cCreated;
}
/// <summary>
/// Contains the information needed to create a table in an ESE database.
/// </summary>
public partial class JET_TABLECREATE : IContentEquatable<JET_TABLECREATE>, IDeepCloneable<JET_TABLECREATE>
{
/// <summary>
/// Gets the native (interop) version of this object. The following members are
/// NOT converted: <see cref="rgcolumncreate"/>, <see cref="rgindexcreate"/>,
/// <see cref="pSeqSpacehints"/>, and <see cref="pLVSpacehints"/>.
/// </summary>
/// <returns>The native (interop) version of this object.</returns>
internal NATIVE_TABLECREATE4 GetNativeTableCreate4()
{
this.CheckMembersAreValid();
var native = new NATIVE_TABLECREATE4();
native.cbStruct = checked((uint)Marshal.SizeOf(typeof(NATIVE_TABLECREATE4)));
native.szTableName = this.szTableName;
native.szTemplateTableName = this.szTemplateTableName;
native.ulPages = checked((uint)this.ulPages);
native.ulDensity = checked((uint)this.ulDensity);
// native.rgcolumncreate is done at pinvoke time.
native.cColumns = checked((uint)this.cColumns);
// native.rgindexcreate is done at pinvoke time.
native.cIndexes = checked((uint)this.cIndexes);
native.szCallback = this.szCallback;
native.cbtyp = this.cbtyp;
native.grbit = checked((uint)this.grbit);
// native.pSeqSpacehints is done at pinvoke time.
// native.pLVSpacehints is done at pinvoke time.
native.cbSeparateLV = checked((uint)this.cbSeparateLV);
native.tableid = this.tableid.Value;
native.cCreated = checked((uint)this.cCreated);
return native;
}
}
}

View File

@ -0,0 +1,26 @@
//-----------------------------------------------------------------------
// <copyright file="LegacyFileNames.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop.Vista
{
/// <summary>
/// Options for LegacyFileNames.
/// </summary>
public enum LegacyFileNames
{
/// <summary>
/// When this option is present then the database engine will use the following naming conventions for its files:
/// o Transaction Log files will use .LOG for their file extension.
/// o Checkpoint files will use .CHK for their file extension.
/// </summary>
ESE98FileNames = 0x00000001,
/// <summary>
/// Preserve the 8.3 naming syntax for as long as possible. (this should not be changed, w/o ensuring there are no log files).
/// </summary>
EightDotThreeSoftCompat = 0x00000002,
}
}

View File

@ -0,0 +1,273 @@
//-----------------------------------------------------------------------
// <copyright file="LibraryHelpers.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using System.Threading;
using Microsoft.Isam.Esent.Interop.Implementation;
/// <summary>
/// Contains several helper functions that are useful in the test binary.
/// In particular, it contains functionality that is not available in
/// reduced-functionality environments (such as CoreClr).
/// </summary>
internal static class LibraryHelpers
{
/// <summary>Provides a platform-specific character used to separate directory levels in a path string that reflects a hierarchical file system organization.</summary>
/// <filterpriority>1</filterpriority>
public static readonly char DirectorySeparatorChar = '\\';
/// <summary>Provides a platform-specific alternate character used to separate directory levels in a path string that reflects a hierarchical file system organization.</summary>
/// <filterpriority>1</filterpriority>
public static readonly char AltDirectorySeparatorChar = '/';
/// <summary>
/// Gets an ASCII encoder.
/// </summary>
public static Encoding EncodingASCII
{
get
{
#if MANAGEDESENT_ON_CORECLR
return SlowAsciiEncoding.Encoding;
#else
return Encoding.ASCII;
#endif
}
}
/// <summary>
/// Gets a new ASCII encoder. It's preferred to use EncodingASCII, but some applications (e.g. tests)
/// may want a different Encoding object.
/// </summary>
public static Encoding NewEncodingASCII
{
get
{
#if MANAGEDESENT_ON_CORECLR
return new SlowAsciiEncoding();
#else
return new ASCIIEncoding();
#endif
}
}
// This should be dead code when running on Core CLR; This is only called by
// GetIndexInfoFromIndexlist() when called on a pre-Win8 system, and Core CLR
// is only on Win8 anyway.
#if !MANAGEDESENT_ON_CORECLR
/// <summary>
/// Creates a CultureInfo object when given the LCID.
/// </summary>
/// <param name="lcid">
/// The lcid passed in.
/// </param>
/// <returns>
/// A CultureInfo object.
/// </returns>
public static CultureInfo CreateCultureInfoByLcid(int lcid)
{
return new CultureInfo(lcid);
}
#endif // !MANAGEDESENT_ON_CORECLR
/// <summary>
/// Allocates memory on the native heap.
/// </summary>
/// <returns>A pointer to native memory.</returns>
/// <param name="size">The size of the memory desired.</param>
public static IntPtr MarshalAllocHGlobal(int size)
{
#if MANAGEDESENT_ON_CORECLR && !MANAGEDESENT_ON_WSA
return Win32.NativeMethods.LocalAlloc(0, new UIntPtr((uint)size));
#else
return Marshal.AllocHGlobal(size);
#endif
}
/// <summary>
/// Frees memory that was allocated on the native heap.
/// </summary>
/// <param name="buffer">A pointer to native memory.</param>
public static void MarshalFreeHGlobal(IntPtr buffer)
{
#if MANAGEDESENT_ON_CORECLR && !MANAGEDESENT_ON_WSA
Win32.NativeMethods.LocalFree(buffer);
#else
Marshal.FreeHGlobal(buffer);
#endif
}
/// <summary>Copies the contents of a managed <see cref="T:System.String" /> into unmanaged memory.</summary>
/// <returns>The address, in unmanaged memory, to where the <paramref name="managedString" /> was copied, or 0 if <paramref name="managedString" /> is null.</returns>
/// <param name="managedString">A managed string to be copied.</param>
/// <exception cref="T:System.OutOfMemoryException">The method could not allocate enough native heap memory.</exception>
/// <exception cref="T:System.ArgumentOutOfRangeException">The <paramref name="managedString" /> parameter exceeds the maximum length allowed by the operating system.</exception>
public static IntPtr MarshalStringToHGlobalUni(string managedString)
{
#if MANAGEDESENT_ON_CORECLR && !MANAGEDESENT_ON_WSA
return MyStringToHGlobalUni(managedString);
#else
return Marshal.StringToHGlobalUni(managedString);
#endif
}
/// <summary>
/// Retrieves the managed ID of the current thread.
/// </summary>
/// <returns>The ID of the current thread.</returns>
public static int GetCurrentManagedThreadId()
{
#if MANAGEDESENT_ON_CORECLR
return Environment.CurrentManagedThreadId;
#else
return Thread.CurrentThread.ManagedThreadId;
#endif
}
/// <summary>
/// Cancels an <see cref="M:System.Threading.Thread.Abort(System.Object)"/> requested for the current thread.
/// </summary>
/// <exception cref="T:System.Threading.ThreadStateException">Abort was not invoked on the current thread. </exception><exception cref="T:System.Security.SecurityException">The caller does not have the required security permission for the current thread. </exception><filterpriority>2</filterpriority><PermissionSet><IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Flags="ControlThread"/></PermissionSet>
public static void ThreadResetAbort()
{
#if MANAGEDESENT_ON_CORECLR
// Do nothing.
#else
Thread.ResetAbort();
#endif
}
// FUTURE-2013/12/16-martinc. It appears that all of this hacking for running on Core CLR may no longer be necessary.
// We initially ported to an early version of Core CLR that had a lot of functionality missing. By the time
// Windows Store Apps came out in Windows 8, many of these functions were added back.
#if MANAGEDESENT_ON_CORECLR && !MANAGEDESENT_ON_WSA
// System.Runtime.InteropServices.Marshal
/// <summary>Copies the contents of a managed <see cref="T:System.String" /> into unmanaged memory.</summary>
/// <returns>The address, in unmanaged memory, to where the <paramref name="managedString" /> was copied, or 0 if <paramref name="managedString" /> is null.</returns>
/// <param name="managedString">A managed string to be copied.</param>
/// <exception cref="T:System.OutOfMemoryException">The method could not allocate enough native heap memory.</exception>
/// <exception cref="T:System.ArgumentOutOfRangeException">The <paramref name="managedString" /> parameter exceeds the maximum length allowed by the operating system.</exception>
[SecurityCritical]
private static unsafe IntPtr MyStringToHGlobalUni(string managedString)
{
if (managedString == null)
{
return IntPtr.Zero;
}
int charCountWithNull = managedString.Length + 1;
int byteCount = charCountWithNull * sizeof(char);
if (byteCount < managedString.Length)
{
throw new ArgumentOutOfRangeException("managedString");
}
UIntPtr sizetdwBytes = new UIntPtr((uint)byteCount);
IntPtr rawBuffer = Win32.NativeMethods.LocalAlloc(0, sizetdwBytes);
if (rawBuffer == IntPtr.Zero)
{
throw new OutOfMemoryException();
}
fixed (char* sourcePointer = managedString)
{
byte* destPointer = (byte*)rawBuffer;
var unicodeEncoding = new System.Text.UnicodeEncoding();
int bytesWritten = unicodeEncoding.GetBytes(sourcePointer, charCountWithNull, destPointer, byteCount);
}
return rawBuffer;
}
#endif // MANAGEDESENT_ON_CORECLR && !MANAGEDESENT_ON_WSA
/// <summary>Returns a <see cref="T:System.DateTime" /> equivalent to the specified OLE Automation Date.</summary>
/// <returns>A <see cref="T:System.DateTime" /> that represents the same date and time as <paramref name="d" />.</returns>
/// <param name="d">An OLE Automation Date value. </param>
/// <exception cref="T:System.ArgumentException">The date is not a valid OLE Automation Date value. </exception>
/// <filterpriority>1</filterpriority>
public static DateTime FromOADate(double d)
{
#if MANAGEDESENT_ON_CORECLR
return new DateTime(DoubleDateToTicks(d), DateTimeKind.Unspecified);
#else
return DateTime.FromOADate(d);
#endif
}
#if MANAGEDESENT_ON_CORECLR
/// <summary>
/// Copied from the reflected implementation.
/// </summary>
/// <param name="value">The date, as a 64bit integer.</param>
/// <returns>The date, as a double representation.</returns>
internal static double TicksToOADate(long value)
{
if (value == 0L)
{
return 0.0;
}
if (value < 864000000000L)
{
value += 599264352000000000L;
}
if (value < 31241376000000000L)
{
throw new OverflowException();
}
long num = (value - 599264352000000000L) / 10000L;
if (num < 0L)
{
long num2 = num % 86400000L;
if (num2 != 0L)
{
num -= (86400000L + num2) * 2L;
}
}
return (double)num / 86400000.0;
}
/// <summary>
/// Copied from the reflected implementation.
/// </summary>
/// <param name="value">The date, as a double representation.</param>
/// <returns>The date, as a 64bit integer.</returns>
internal static long DoubleDateToTicks(double value)
{
if (value >= 2958466.0 || value <= -657435.0)
{
throw new ArgumentException("value does not represent a valid date", "value");
}
long num = (long)((value * 86400000.0) + ((value >= 0.0) ? 0.5 : -0.5));
if (num < 0L)
{
num -= (num % 86400000L) * 2L;
}
num += 59926435200000L;
if (num < 0L || num >= 315537897600000L)
{
throw new ArgumentException("value does not represent a valid date", "value");
}
return num * 10000L;
}
#endif
}
}

View File

@ -0,0 +1,321 @@
//-----------------------------------------------------------------------
// <copyright file="MakeKeyHelpers.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
using System.Text;
/// <summary>
/// Helper methods for the ESENT API. These do data conversion for
/// JetMakeKey.
/// </summary>
public static partial class Api
{
/// <summary>
/// Constructs a search key that may then be used by <see cref="JetSeek"/>
/// and <see cref="JetSetIndexRange"/>.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to create the key on.</param>
/// <param name="data">Column data for the current key column of the current index.</param>
/// <param name="grbit">Key options.</param>
public static void MakeKey(JET_SESID sesid, JET_TABLEID tableid, byte[] data, MakeKeyGrbit grbit)
{
if (null == data)
{
Api.JetMakeKey(sesid, tableid, null, 0, grbit);
}
else if (0 == data.Length)
{
Api.JetMakeKey(sesid, tableid, data, data.Length, grbit | MakeKeyGrbit.KeyDataZeroLength);
}
else
{
Api.JetMakeKey(sesid, tableid, data, data.Length, grbit);
}
}
/// <summary>
/// Constructs a search key that may then be used by <see cref="JetSeek"/>
/// and <see cref="JetSetIndexRange"/>.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to create the key on.</param>
/// <param name="data">Column data for the current key column of the current index.</param>
/// <param name="encoding">The encoding used to convert the string.</param>
/// <param name="grbit">Key options.</param>
public static void MakeKey(JET_SESID sesid, JET_TABLEID tableid, string data, Encoding encoding, MakeKeyGrbit grbit)
{
CheckEncodingIsValid(encoding);
if (null == data)
{
Api.JetMakeKey(sesid, tableid, null, 0, grbit);
}
else if (0 == data.Length)
{
Api.JetMakeKey(sesid, tableid, null, 0, grbit | MakeKeyGrbit.KeyDataZeroLength);
}
else if (Encoding.Unicode == encoding)
{
// Optimization for Unicode strings
unsafe
{
fixed (char* buffer = data)
{
Api.JetMakeKey(sesid, tableid, new IntPtr(buffer), checked(data.Length * sizeof(char)), grbit);
}
}
}
else
{
#if MANAGEDESENT_ON_WSA
// Encoding.GetBytes(char*, int, byte*, int) overload is missing in new Windows UI.
// So we can't use the ColumnCache. We'll just use a different GetBytes() overload.
byte[] buffer = encoding.GetBytes(data);
Api.JetMakeKey(sesid, tableid, buffer, buffer.Length, grbit);
#else
// Convert the string using a cached column buffer. The column buffer is far larger
// than the maximum key size, so any data truncation here won't matter.
byte[] buffer = null;
try
{
buffer = Caches.ColumnCache.Allocate();
int dataSize;
unsafe
{
fixed (char* chars = data)
fixed (byte* bytes = buffer)
{
dataSize = encoding.GetBytes(chars, data.Length, bytes, buffer.Length);
}
}
JetMakeKey(sesid, tableid, buffer, dataSize, grbit);
}
finally
{
if (buffer != null)
{
Caches.ColumnCache.Free(ref buffer);
}
}
#endif
}
}
/// <summary>
/// Constructs a search key that may then be used by <see cref="JetSeek"/>
/// and <see cref="JetSetIndexRange"/>.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to create the key on.</param>
/// <param name="data">Column data for the current key column of the current index.</param>
/// <param name="grbit">Key options.</param>
public static void MakeKey(JET_SESID sesid, JET_TABLEID tableid, bool data, MakeKeyGrbit grbit)
{
byte b = data ? (byte)0xff : (byte)0x0;
Api.MakeKey(sesid, tableid, b, grbit);
}
/// <summary>
/// Constructs a search key that may then be used by <see cref="JetSeek"/>
/// and <see cref="JetSetIndexRange"/>.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to create the key on.</param>
/// <param name="data">Column data for the current key column of the current index.</param>
/// <param name="grbit">Key options.</param>
public static void MakeKey(JET_SESID sesid, JET_TABLEID tableid, byte data, MakeKeyGrbit grbit)
{
unsafe
{
const int DataSize = sizeof(byte);
var pointer = new IntPtr(&data);
Api.JetMakeKey(sesid, tableid, pointer, DataSize, grbit);
}
}
/// <summary>
/// Constructs a search key that may then be used by <see cref="JetSeek"/>
/// and <see cref="JetSetIndexRange"/>.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to create the key on.</param>
/// <param name="data">Column data for the current key column of the current index.</param>
/// <param name="grbit">Key options.</param>
public static void MakeKey(JET_SESID sesid, JET_TABLEID tableid, short data, MakeKeyGrbit grbit)
{
unsafe
{
const int DataSize = sizeof(short);
var pointer = new IntPtr(&data);
Api.JetMakeKey(sesid, tableid, pointer, DataSize, grbit);
}
}
/// <summary>
/// Constructs a search key that may then be used by <see cref="JetSeek"/>
/// and <see cref="JetSetIndexRange"/>.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to create the key on.</param>
/// <param name="data">Column data for the current key column of the current index.</param>
/// <param name="grbit">Key options.</param>
public static void MakeKey(JET_SESID sesid, JET_TABLEID tableid, int data, MakeKeyGrbit grbit)
{
unsafe
{
const int DataSize = sizeof(int);
var pointer = new IntPtr(&data);
Api.JetMakeKey(sesid, tableid, pointer, DataSize, grbit);
}
}
/// <summary>
/// Constructs a search key that may then be used by <see cref="JetSeek"/>
/// and <see cref="JetSetIndexRange"/>.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to create the key on.</param>
/// <param name="data">Column data for the current key column of the current index.</param>
/// <param name="grbit">Key options.</param>
public static void MakeKey(JET_SESID sesid, JET_TABLEID tableid, long data, MakeKeyGrbit grbit)
{
unsafe
{
const int DataSize = sizeof(long);
var pointer = new IntPtr(&data);
Api.JetMakeKey(sesid, tableid, pointer, DataSize, grbit);
}
}
/// <summary>
/// Constructs a search key that may then be used by <see cref="JetSeek"/>
/// and <see cref="JetSetIndexRange"/>.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to create the key on.</param>
/// <param name="data">Column data for the current key column of the current index.</param>
/// <param name="grbit">Key options.</param>
public static void MakeKey(JET_SESID sesid, JET_TABLEID tableid, Guid data, MakeKeyGrbit grbit)
{
unsafe
{
const int DataSize = 16 /* sizeof(Guid) */;
var pointer = new IntPtr(&data);
Api.JetMakeKey(sesid, tableid, pointer, DataSize, grbit);
}
}
/// <summary>
/// Constructs a search key that may then be used by <see cref="JetSeek"/>
/// and <see cref="JetSetIndexRange"/>.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to create the key on.</param>
/// <param name="data">Column data for the current key column of the current index.</param>
/// <param name="grbit">Key options.</param>
public static void MakeKey(JET_SESID sesid, JET_TABLEID tableid, DateTime data, MakeKeyGrbit grbit)
{
Api.MakeKey(sesid, tableid, data.ToOADate(), grbit);
}
/// <summary>
/// Constructs a search key that may then be used by <see cref="JetSeek"/>
/// and <see cref="JetSetIndexRange"/>.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to create the key on.</param>
/// <param name="data">Column data for the current key column of the current index.</param>
/// <param name="grbit">Key options.</param>
public static void MakeKey(JET_SESID sesid, JET_TABLEID tableid, float data, MakeKeyGrbit grbit)
{
unsafe
{
const int DataSize = sizeof(float);
var pointer = new IntPtr(&data);
Api.JetMakeKey(sesid, tableid, pointer, DataSize, grbit);
}
}
/// <summary>
/// Constructs a search key that may then be used by <see cref="JetSeek"/>
/// and <see cref="JetSetIndexRange"/>.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to create the key on.</param>
/// <param name="data">Column data for the current key column of the current index.</param>
/// <param name="grbit">Key options.</param>
public static void MakeKey(JET_SESID sesid, JET_TABLEID tableid, double data, MakeKeyGrbit grbit)
{
unsafe
{
const int DataSize = sizeof(double);
var pointer = new IntPtr(&data);
Api.JetMakeKey(sesid, tableid, pointer, DataSize, grbit);
}
}
/// <summary>
/// Constructs a search key that may then be used by <see cref="JetSeek"/>
/// and <see cref="JetSetIndexRange"/>.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to create the key on.</param>
/// <param name="data">Column data for the current key column of the current index.</param>
/// <param name="grbit">Key options.</param>
[CLSCompliant(false)]
public static void MakeKey(JET_SESID sesid, JET_TABLEID tableid, ushort data, MakeKeyGrbit grbit)
{
unsafe
{
const int DataSize = sizeof(ushort);
var pointer = new IntPtr(&data);
Api.JetMakeKey(sesid, tableid, pointer, DataSize, grbit);
}
}
/// <summary>
/// Constructs a search key that may then be used by <see cref="JetSeek"/>
/// and <see cref="JetSetIndexRange"/>.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to create the key on.</param>
/// <param name="data">Column data for the current key column of the current index.</param>
/// <param name="grbit">Key options.</param>
[CLSCompliant(false)]
public static void MakeKey(JET_SESID sesid, JET_TABLEID tableid, uint data, MakeKeyGrbit grbit)
{
unsafe
{
const int DataSize = sizeof(uint);
var pointer = new IntPtr(&data);
Api.JetMakeKey(sesid, tableid, pointer, DataSize, grbit);
}
}
/// <summary>
/// Constructs a search key that may then be used by <see cref="JetSeek"/>
/// and <see cref="JetSetIndexRange"/>.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to create the key on.</param>
/// <param name="data">Column data for the current key column of the current index.</param>
/// <param name="grbit">Key options.</param>
[CLSCompliant(false)]
public static void MakeKey(JET_SESID sesid, JET_TABLEID tableid, ulong data, MakeKeyGrbit grbit)
{
unsafe
{
const int DataSize = sizeof(ulong);
var pointer = new IntPtr(&data);
Api.JetMakeKey(sesid, tableid, pointer, DataSize, grbit);
}
}
}
}

View File

@ -0,0 +1,151 @@
//-----------------------------------------------------------------------
// <copyright file="MemoryCache.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
using System.Diagnostics;
using System.Threading;
/// <summary>
/// Cache allocated chunks of memory that are needed for very short periods
/// of time. The memory is not zeroed on allocation.
/// </summary>
internal sealed class MemoryCache
{
/// <summary>
/// A zero-length array that should be used whenever we want to return one.
/// </summary>
private static readonly byte[] ZeroLengthArray = new byte[0];
/// <summary>
/// Default size for newly allocated buffers.
/// </summary>
private readonly int bufferSize;
/// <summary>
/// Currently cached buffers.
/// </summary>
private readonly byte[][] cachedBuffers;
/// <summary>
/// Initializes a new instance of the <see cref="MemoryCache"/> class.
/// </summary>
/// <param name="bufferSize">
/// The size of the buffers to cache.
/// </param>
/// <param name="maxCachedBuffers">
/// The maximum number of buffers to cache.
/// </param>
public MemoryCache(int bufferSize, int maxCachedBuffers)
{
this.bufferSize = bufferSize;
this.cachedBuffers = new byte[maxCachedBuffers][];
}
/// <summary>
/// Gets the size of the buffers that this cache returns.
/// </summary>
public int BufferSize
{
get
{
return this.bufferSize;
}
}
/// <summary>
/// Creates a new array containing a copy of 'length' bytes of data.
/// </summary>
/// <param name="data">The data to copy.</param>
/// <param name="length">The length of data to copy.</param>
/// <returns>An array containing the first length bytes of data.</returns>
public static byte[] Duplicate(byte[] data, int length)
{
Debug.Assert(data.Length >= length, "length parameter is too long");
if (0 == length)
{
return ZeroLengthArray;
}
var output = new byte[length];
Buffer.BlockCopy(data, 0, output, 0, length);
return output;
}
/// <summary>
/// Allocates a chunk of memory. If memory is cached it is returned. If no memory
/// is cached then it is allocated. Check the size of the returned buffer to determine
/// how much memory was allocated.
/// </summary>
/// <returns>A new memory buffer.</returns>
public byte[] Allocate()
{
int offset = this.GetStartingOffset();
for (int i = 0; i < this.cachedBuffers.Length; ++i)
{
int index = (i + offset) % this.cachedBuffers.Length;
byte[] buffer = Interlocked.Exchange(ref this.cachedBuffers[index], null);
if (null != buffer)
{
return buffer;
}
}
return new byte[this.bufferSize];
}
/// <summary>
/// Frees an unused buffer. This may be added to the cache.
/// </summary>
/// <param name="data">The memory to free.</param>
public void Free(ref byte[] data)
{
if (null == data)
{
throw new ArgumentNullException("data");
}
if (data.Length != this.bufferSize)
{
throw new ArgumentOutOfRangeException("data", data.Length, "buffer is not correct size for this MemoryCache");
}
int offset = this.GetStartingOffset();
// The buffers are garbage collected so we don't need to make Free()
// completely safe. In a multi-threaded situation we may see a null
// slot and then overwrite a buffer which was just freed into the slot.
// That will cause us to lose a buffer which could have been placed
// in a different slot, but in return we can do the Free() without
// expensive interlocked operations.
for (int i = 0; i < this.cachedBuffers.Length; ++i)
{
int index = (i + offset) % this.cachedBuffers.Length;
if (null == this.cachedBuffers[index])
{
this.cachedBuffers[index] = data;
break;
}
}
data = null;
}
/// <summary>
/// Get the offset in the cached buffers array to start allocating or freeing
/// buffers to. This is done so that all threads don't start operating on
/// slot zero, which would increase contention.
/// </summary>
/// <returns>The starting offset for Allocate/Free operations.</returns>
private int GetStartingOffset()
{
// Using the current CPU number would be ideal, but there doesn't seem to
// be a cheap way to get that information in managed code.
return LibraryHelpers.GetCurrentManagedThreadId() % this.cachedBuffers.Length;
}
}
}

View File

@ -0,0 +1,294 @@
//-----------------------------------------------------------------------
// <copyright file="MetaDataHelpers.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using Microsoft.Isam.Esent.Interop.Implementation;
/// <summary>
/// Helper methods for the ESENT API. These methods deal with database
/// meta-data.
/// </summary>
public static partial class Api
{
#region Simpler API. Overloads that omit unused/obsolete parameters.
/// <summary>
/// Initialize a new ESENT session.
/// </summary>
/// <param name="instance">The initialized instance to create the session in.</param>
/// <param name="sesid">Returns the created session.</param>
public static void BeginSession(JET_INSTANCE instance, out JET_SESID sesid)
{
Api.JetBeginSession(instance, out sesid, null, null);
}
/// <summary>
/// Creates and attaches a database file.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="database">The path to the database file to create.</param>
/// <param name="dbid">Returns the dbid of the new database.</param>
/// <param name="grbit">Database creation options.</param>
public static void CreateDatabase(JET_SESID sesid, string database, out JET_DBID dbid, CreateDatabaseGrbit grbit)
{
Api.JetCreateDatabase(sesid, database, null, out dbid, grbit);
}
/// <summary>
/// Opens a database previously attached with <see cref="JetAttachDatabase"/>,
/// for use with a database session. This function can be called multiple times
/// for the same database.
/// </summary>
/// <param name="sesid">The session that is opening the database.</param>
/// <param name="database">The database to open.</param>
/// <param name="dbid">Returns the dbid of the attached database.</param>
/// <param name="grbit">Open database options.</param>
/// <returns>An ESENT warning code.</returns>
public static JET_wrn OpenDatabase(
JET_SESID sesid,
string database,
out JET_DBID dbid,
OpenDatabaseGrbit grbit)
{
return Api.JetOpenDatabase(sesid, database, null, out dbid, grbit);
}
/// <summary>
/// Opens a cursor on a previously created table.
/// </summary>
/// <param name="sesid">The database session to use.</param>
/// <param name="dbid">The database to open the table in.</param>
/// <param name="tablename">The name of the table to open.</param>
/// <param name="grbit">Table open options.</param>
/// <param name="tableid">Returns the opened table.</param>
/// <returns>An ESENT warning.</returns>
public static JET_wrn OpenTable(
JET_SESID sesid,
JET_DBID dbid,
string tablename,
OpenTableGrbit grbit,
out JET_TABLEID tableid)
{
return Api.JetOpenTable(sesid, dbid, tablename, null, 0, grbit, out tableid);
}
#endregion
/// <summary>
/// Try to open a table.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="dbid">The database to look for the table in.</param>
/// <param name="tablename">The name of the table.</param>
/// <param name="grbit">Table open options.</param>
/// <param name="tableid">Returns the opened tableid.</param>
/// <returns>True if the table was opened, false if the table doesn't exist.</returns>
public static bool TryOpenTable(
JET_SESID sesid,
JET_DBID dbid,
string tablename,
OpenTableGrbit grbit,
out JET_TABLEID tableid)
{
var err = (JET_err)Impl.JetOpenTable(sesid, dbid, tablename, null, 0, grbit, out tableid);
if (JET_err.ObjectNotFound == err)
{
return false;
}
Api.Check((int)err);
Debug.Assert(err >= JET_err.Success, "Exception should have been thrown in case of error");
return true;
}
/// <summary>
/// Creates a dictionary which maps column names to their column IDs.
/// </summary>
/// <param name="sesid">The sesid to use.</param>
/// <param name="tableid">The table to retrieve the information for.</param>
/// <returns>A dictionary mapping column names to column IDs.</returns>
public static IDictionary<string, JET_COLUMNID> GetColumnDictionary(JET_SESID sesid, JET_TABLEID tableid)
{
JET_COLUMNLIST columnlist;
JetGetTableColumnInfo(sesid, tableid, string.Empty, out columnlist);
// As of Sep 2015, JetGetColumnInfoW is only called for Win8+. Even though Unicode should have
// worked in Win7, it wasn't reliable until Win8.
Encoding encodingOfTextColumns = EsentVersion.SupportsWindows8Features ? Encoding.Unicode : LibraryHelpers.EncodingASCII;
try
{
// esent treats column names as case-insensitive, so we want the dictionary to be case insensitive as well
var dict = new Dictionary<string, JET_COLUMNID>(
columnlist.cRecord, StringComparer.OrdinalIgnoreCase);
if (columnlist.cRecord > 0)
{
if (Api.TryMoveFirst(sesid, columnlist.tableid))
{
do
{
string name = RetrieveColumnAsString(
sesid,
columnlist.tableid,
columnlist.columnidcolumnname,
encodingOfTextColumns,
RetrieveColumnGrbit.None);
name = StringCache.TryToIntern(name);
var columnidValue =
(uint)RetrieveColumnAsUInt32(sesid, columnlist.tableid, columnlist.columnidcolumnid);
var columnid = new JET_COLUMNID { Value = columnidValue };
dict.Add(name, columnid);
}
while (TryMoveNext(sesid, columnlist.tableid));
}
}
return dict;
}
finally
{
// Close the temporary table used to return the results
JetCloseTable(sesid, columnlist.tableid);
}
}
/// <summary>
/// Get the columnid of the specified column.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The table containing the column.</param>
/// <param name="columnName">The name of the column.</param>
/// <returns>The id of the column.</returns>
public static JET_COLUMNID GetTableColumnid(JET_SESID sesid, JET_TABLEID tableid, string columnName)
{
JET_COLUMNDEF columndef;
JetGetTableColumnInfo(sesid, tableid, columnName, out columndef);
return columndef.columnid;
}
/// <summary>
/// Iterates over all the columns in the table, returning information about each one.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The table to retrieve column information for.</param>
/// <returns>An iterator over ColumnInfo for each column in the table.</returns>
public static IEnumerable<ColumnInfo> GetTableColumns(JET_SESID sesid, JET_TABLEID tableid)
{
return new GenericEnumerable<ColumnInfo>(() => new TableidColumnInfoEnumerator(sesid, tableid));
}
/// <summary>
/// Iterates over all the columns in the table, returning information about each one.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="dbid">The database containing the table.</param>
/// <param name="tablename">The name of the table.</param>
/// <returns>An iterator over ColumnInfo for each column in the table.</returns>
public static IEnumerable<ColumnInfo> GetTableColumns(JET_SESID sesid, JET_DBID dbid, string tablename)
{
if (null == tablename)
{
throw new ArgumentNullException("tablename");
}
return new GenericEnumerable<ColumnInfo>(() => new TableColumnInfoEnumerator(sesid, dbid, tablename));
}
/// <summary>
/// Iterates over all the indexes in the table, returning information about each one.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The table to retrieve index information for.</param>
/// <returns>An iterator over an IndexInfo for each index in the table.</returns>
public static IEnumerable<IndexInfo> GetTableIndexes(JET_SESID sesid, JET_TABLEID tableid)
{
return new GenericEnumerable<IndexInfo>(() => new TableidIndexInfoEnumerator(sesid, tableid));
}
/// <summary>
/// Iterates over all the indexs in the table, returning information about each one.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="dbid">The database containing the table.</param>
/// <param name="tablename">The name of the table.</param>
/// <returns>An iterator over an IndexInfo for each index in the table.</returns>
public static IEnumerable<IndexInfo> GetTableIndexes(JET_SESID sesid, JET_DBID dbid, string tablename)
{
if (null == tablename)
{
throw new ArgumentNullException("tablename");
}
return new GenericEnumerable<IndexInfo>(() => new TableIndexInfoEnumerator(sesid, dbid, tablename));
}
/// <summary>
/// Returns the names of the tables in the database.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="dbid">The database containing the table.</param>
/// <returns>An iterator over the names of the tables in the database.</returns>
public static IEnumerable<string> GetTableNames(JET_SESID sesid, JET_DBID dbid)
{
return new GenericEnumerable<string>(() => new TableNameEnumerator(sesid, dbid));
}
/// <summary>
/// Retrieves information about indexes on a table.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The table to retrieve index information about.</param>
/// <param name="indexname">The name of the index.</param>
/// <param name="result">Filled in with information about indexes on the table.</param>
/// <param name="infoLevel">The type of information to retrieve.</param>
/// <returns>true if there was no error, false if the index wasn't found. Throws for other Jet errors.</returns>
public static bool TryJetGetTableIndexInfo(
JET_SESID sesid,
JET_TABLEID tableid,
string indexname,
out JET_INDEXID result,
JET_IdxInfo infoLevel)
{
int err = Impl.JetGetTableIndexInfo(sesid, tableid, indexname, out result, infoLevel);
if ((JET_err)err == JET_err.IndexNotFound)
{
return false;
}
Api.Check(err);
return true;
}
/// <summary>
/// Determines the name of the current index of a given cursor.
/// </summary>
/// <remarks>
/// This name is also used to later re-select that index as the current index using
/// <see cref="JetSetCurrentIndex"/>. It can also be used to discover the properties of that index using
/// JetGetTableIndexInfo.
///
/// The returned name of the index will be null if the current index is the clustered index and no primary
/// index was explicitly defined.
/// </remarks>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to get the index name for.</param>
/// <returns>Returns the name of the index.</returns>
public static string JetGetCurrentIndex(JET_SESID sesid, JET_TABLEID tableid)
{
string indexName;
Api.JetGetCurrentIndex(sesid, tableid, out indexName, SystemParameters.NameMost);
return string.IsNullOrEmpty(indexName) ? null : indexName;
}
}
}

View File

@ -0,0 +1,244 @@
//-----------------------------------------------------------------------
// <copyright file="MoveHelpers.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
/// <summary>
/// Helper methods for the ESENT API. These aren't interop versions
/// of the API, but encapsulate very common uses of the functions.
/// </summary>
public static partial class Api
{
/// <summary>
/// Position the cursor before the first record in the table. A
/// subsequent move next will position the cursor on the first
/// record.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The table to position.</param>
public static void MoveBeforeFirst(JET_SESID sesid, JET_TABLEID tableid)
{
Api.TryMoveFirst(sesid, tableid);
Api.TryMovePrevious(sesid, tableid);
}
/// <summary>
/// Position the cursor after the last record in the table. A
/// subsequent move previous will position the cursor on the
/// last record.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The table to position.</param>
public static void MoveAfterLast(JET_SESID sesid, JET_TABLEID tableid)
{
Api.TryMoveLast(sesid, tableid);
Api.TryMoveNext(sesid, tableid);
}
/// <summary>
/// Try to navigate through an index. If the navigation succeeds this
/// method returns true. If there is no record to navigate to this
/// method returns false; an exception will be thrown for other errors.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to position.</param>
/// <param name="move">The direction to move in.</param>
/// <param name="grbit">Move options.</param>
/// <returns>True if the move was successful.</returns>
public static bool TryMove(JET_SESID sesid, JET_TABLEID tableid, JET_Move move, MoveGrbit grbit)
{
var err = (JET_err)Impl.JetMove(sesid, tableid, (int)move, grbit);
if (JET_err.NoCurrentRecord == err)
{
return false;
}
Api.Check((int)err);
Debug.Assert(err >= JET_err.Success, "Exception should have been thrown in case of error");
return true;
}
/// <summary>
/// Try to move to the first record in the table. If the table is empty this
/// returns false, if a different error is encountered an exception is thrown.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to position.</param>
/// <returns>True if the move was successful.</returns>
public static bool TryMoveFirst(JET_SESID sesid, JET_TABLEID tableid)
{
return TryMove(sesid, tableid, JET_Move.First, MoveGrbit.None);
}
/// <summary>
/// Try to move to the last record in the table. If the table is empty this
/// returns false, if a different error is encountered an exception is thrown.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to position.</param>
/// <returns>True if the move was successful.</returns>
public static bool TryMoveLast(JET_SESID sesid, JET_TABLEID tableid)
{
return TryMove(sesid, tableid, JET_Move.Last, MoveGrbit.None);
}
/// <summary>
/// Try to move to the next record in the table. If there is not a next record
/// this returns false, if a different error is encountered an exception is thrown.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to position.</param>
/// <returns>True if the move was successful.</returns>
public static bool TryMoveNext(JET_SESID sesid, JET_TABLEID tableid)
{
return TryMove(sesid, tableid, JET_Move.Next, MoveGrbit.None);
}
/// <summary>
/// Try to move to the previous record in the table. If there is not a previous record
/// this returns false, if a different error is encountered an exception is thrown.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to position.</param>
/// <returns>True if the move was successful.</returns>
public static bool TryMovePrevious(JET_SESID sesid, JET_TABLEID tableid)
{
return TryMove(sesid, tableid, JET_Move.Previous, MoveGrbit.None);
}
/// <summary>
/// Efficiently positions a cursor to an index entry that matches the search
/// criteria specified by the search key in that cursor and the specified
/// inequality. A search key must have been previously constructed using JetMakeKey.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to position.</param>
/// <param name="grbit">Seek option.</param>
/// <returns>True if a record matching the criteria was found.</returns>
public static bool TrySeek(JET_SESID sesid, JET_TABLEID tableid, SeekGrbit grbit)
{
var err = (JET_err)Impl.JetSeek(sesid, tableid, grbit);
if (JET_err.RecordNotFound == err)
{
return false;
}
Api.Check((int)err);
Debug.Assert(err >= JET_err.Success, "Exception should have been thrown in case of error");
return true;
}
/// <summary>
/// Temporarily limits the set of index entries that the cursor can walk using
/// JetMove to those starting from the current index entry and ending at the index
/// entry that matches the search criteria specified by the search key in that cursor
/// and the specified bound criteria. A search key must have been previously constructed
/// using JetMakeKey. Returns true if the index range is non-empty, false otherwise.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to position.</param>
/// <param name="grbit">Seek option.</param>
/// <returns>True if the seek was successful.</returns>
public static bool TrySetIndexRange(JET_SESID sesid, JET_TABLEID tableid, SetIndexRangeGrbit grbit)
{
var err = (JET_err)Impl.JetSetIndexRange(sesid, tableid, grbit);
if (JET_err.NoCurrentRecord == err)
{
return false;
}
Api.Check((int)err);
Debug.Assert(err >= JET_err.Success, "Exception should have been thrown in case of error");
return true;
}
/// <summary>
/// Removes an index range created with <see cref="JetSetIndexRange"/> or
/// <see cref="TrySetIndexRange"/>. If no index range is present this
/// method does nothing.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to remove the index range on.</param>
public static void ResetIndexRange(JET_SESID sesid, JET_TABLEID tableid)
{
var err = (JET_err)Impl.JetSetIndexRange(sesid, tableid, SetIndexRangeGrbit.RangeRemove);
if (JET_err.InvalidOperation == err)
{
// this error is expected if there isn't currently an index range
return;
}
Api.Check((int)err);
return;
}
/// <summary>
/// Intersect a group of index ranges and return the bookmarks of the records which are found
/// in all the index ranges.
/// Also see <see cref="JetIntersectIndexes"/>.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableids">
/// The tableids to use. Each tableid must be from a different index on the same table and
/// have an active index range. Use <see cref="JetSetIndexRange"/>
/// to create an index range.
/// </param>
/// <returns>
/// The bookmarks of the records which are found in all the index ranges. The bookmarks
/// are returned in primary key order.
/// </returns>
public static IEnumerable<byte[]> IntersectIndexes(JET_SESID sesid, params JET_TABLEID[] tableids)
{
if (null == tableids)
{
throw new ArgumentNullException("tableids");
}
var ranges = new JET_INDEXRANGE[tableids.Length];
for (int i = 0; i < tableids.Length; ++i)
{
ranges[i] = new JET_INDEXRANGE { tableid = tableids[i] };
}
return new GenericEnumerable<byte[]>(() => new IntersectIndexesEnumerator(sesid, ranges));
}
/// <summary>
/// Positions a cursor to an index entry for the record that is associated with
/// the specified bookmark. The bookmark can be used with any index defined over
/// a table. The bookmark for a record can be retrieved using <see cref="JetGetBookmark"/>.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to position.</param>
/// <param name="bookmark">The bookmark used to position the cursor.</param>
/// <param name="bookmarkSize">The size of the bookmark.</param>
/// <returns>True if a record matching the bookmark was found.</returns>
public static bool TryGotoBookmark(JET_SESID sesid, JET_TABLEID tableid, byte[] bookmark, int bookmarkSize)
{
var err = (JET_err)Impl.JetGotoBookmark(sesid, tableid, bookmark, bookmarkSize);
// Return false if the record no longer exists.
if (JET_err.RecordDeleted == err)
{
return false;
}
// Return false if there is no entry for this record on the current (secondary) index.
if (JET_err.NoCurrentRecord == err)
{
return false;
}
Api.Check((int)err);
Debug.Assert(err >= JET_err.Success, "Exception should have been thrown in case of error");
return true;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,53 @@
//-----------------------------------------------------------------------
// <copyright file="ObjectInfoFlags.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
/// <summary>
/// Flags for ESENT objects (tables). Used in <see cref="JET_OBJECTINFO"/>.
/// </summary>
[Flags]
public enum ObjectInfoFlags
{
/// <summary>
/// Default options.
/// </summary>
None = 0,
/// <summary>
/// Object is for internal use only.
/// </summary>
System = -2147483648, // 0x80000000
// It's possible to use bit shift to avoid triggering fxcop CA2217.
// System = (long)0x1L << 31, // 0x80000000;
// (http://social.msdn.microsoft.com/Forums/en-US/vstscode/thread/a44aa5c1-c62a-46b7-8009-dc46ba21ba93)
// But we don't want to change the type of the enum to a long.
/// <summary>
/// Table's DDL is fixed.
/// </summary>
TableFixedDDL = 0x40000000,
/// <summary>
/// Table's DDL is inheritable.
/// </summary>
TableTemplate = 0x20000000,
/// <summary>
/// Table's DDL is inherited from a template table.
/// </summary>
TableDerived = 0x10000000,
/// <summary>
/// Fixed or variable columns in derived tables (so that fixed or variable
/// columns can be added to the template in the future).
/// Used in conjunction with <see cref="TableTemplate"/>.
/// </summary>
TableNoFixedVarColumnsInDerivedTables = 0x04000000,
}
}

View File

@ -0,0 +1,52 @@
//-----------------------------------------------------------------------
// <copyright file="ObsoleteApi.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
/// <summary>
/// API members that are marked as obsolete.
/// </summary>
public static partial class Api
{
/// <summary>
/// Retrieves information about indexes on a table.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="dbid">The database to use.</param>
/// <param name="tablename">The name of the table to retrieve index information about.</param>
/// <param name="ignored">This parameter is ignored.</param>
/// <param name="indexlist">Filled in with information about indexes on the table.</param>
[Obsolete("Use the overload that takes a JET_IdxInfo parameter, passing in JET_IdxInfo.List")]
public static void JetGetIndexInfo(
JET_SESID sesid,
JET_DBID dbid,
string tablename,
string ignored,
out JET_INDEXLIST indexlist)
{
Api.JetGetIndexInfo(sesid, dbid, tablename, ignored, out indexlist, JET_IdxInfo.List);
}
/// <summary>
/// Retrieves information about indexes on a table.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The table to retrieve index information about.</param>
/// <param name="indexname">This parameter is ignored.</param>
/// <param name="indexlist">Filled in with information about indexes on the table.</param>
[Obsolete("Use the overload that takes a JET_IdxInfo parameter, passing in JET_IdxInfo.List")]
public static void JetGetTableIndexInfo(
JET_SESID sesid,
JET_TABLEID tableid,
string indexname,
out JET_INDEXLIST indexlist)
{
Api.JetGetTableIndexInfo(sesid, tableid, indexname, out indexlist, JET_IdxInfo.List);
}
}
}

View File

@ -0,0 +1,44 @@
//-----------------------------------------------------------------------
// <copyright file="OnlineMaintenanceHelpers.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using Microsoft.Isam.Esent.Interop.Implementation;
/// <summary>
/// Helper methods for the ESENT API. These methods deal with database
/// meta-data.
/// </summary>
public static partial class Api
{
/// <summary>
/// Starts and stops database defragmentation tasks that improves data
/// organization within a database.
/// </summary>
/// <param name="sesid">The session to use for the call.</param>
/// <param name="dbid">The database to be defragmented.</param>
/// <param name="tableName">
/// Under some options defragmentation is performed for the entire database described by the given
/// database ID, and other options (such as <see cref="Windows7.Windows7Grbits.DefragmentBTree"/>) require
/// the name of the table to defragment.
/// </param>
/// <param name="grbit">Defragmentation options.</param>
/// <returns>A warning code.</returns>
/// <seealso cref="Api.JetDefragment"/>
public static JET_wrn Defragment(
JET_SESID sesid,
JET_DBID dbid,
string tableName,
DefragGrbit grbit)
{
return Api.Check(Impl.Defragment(sesid, dbid, tableName, grbit));
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,50 @@
//-----------------------------------------------------------------------
// <copyright file="Server2003Api.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop.Server2003
{
/// <summary>
/// APIs that have been added to the Windows Server 2003 version of ESENT.
/// </summary>
public static class Server2003Api
{
#if !MANAGEDESENT_ON_WSA
/// <summary>
/// Notifies the engine that it can resume normal IO operations after a
/// freeze period ended with a failed snapshot.
/// </summary>
/// <param name="snapid">Identifier of the snapshot session.</param>
/// <param name="grbit">Options for this call.</param>
public static void JetOSSnapshotAbort(JET_OSSNAPID snapid, SnapshotAbortGrbit grbit)
{
Api.Check(Api.Impl.JetOSSnapshotAbort(snapid, grbit));
}
#endif // !MANAGEDESENT_ON_WSA
/// <summary>
/// The JetUpdate function performs an update operation including inserting a new row into
/// a table or updating an existing row. Deleting a table row is performed by calling
/// <see cref="Api.JetDelete"/>.
/// </summary>
/// <param name="sesid">The session which started the update.</param>
/// <param name="tableid">The cursor to update. An update should be prepared.</param>
/// <param name="bookmark">Returns the bookmark of the updated record. This can be null.</param>
/// <param name="bookmarkSize">The size of the bookmark buffer.</param>
/// <param name="actualBookmarkSize">Returns the actual size of the bookmark.</param>
/// <param name="grbit">Update options.</param>
/// <remarks>
/// JetUpdate is the final step in performing an insert or an update. The update is begun by
/// calling <see cref="Api.JetPrepareUpdate"/> and then by calling
/// <see cref="Api.JetSetColumn(JET_SESID,JET_TABLEID,JET_COLUMNID,byte[],int,SetColumnGrbit,JET_SETINFO)"/>
/// one or more times to set the record state. Finally, <see cref="JetUpdate2"/>
/// is called to complete the update operation. Indexes are updated only by JetUpdate or and not during JetSetColumn.
/// </remarks>
public static void JetUpdate2(JET_SESID sesid, JET_TABLEID tableid, byte[] bookmark, int bookmarkSize, out int actualBookmarkSize, UpdateGrbit grbit)
{
Api.Check(Api.Impl.JetUpdate2(sesid, tableid, bookmark, bookmarkSize, out actualBookmarkSize, grbit));
}
}
}

View File

@ -0,0 +1,108 @@
//-----------------------------------------------------------------------
// <copyright file="Server2003Grbits.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop.Server2003
{
using System;
#if !MANAGEDESENT_ON_WSA // Not exposed in MSDK
/// <summary>
/// Options for <see cref="Server2003Api.JetOSSnapshotAbort"/>.
/// </summary>
[Flags]
public enum SnapshotAbortGrbit
{
/// <summary>
/// Default options.
/// </summary>
None = 0,
}
#endif // !MANAGEDESENT_ON_WSA
/// <summary>
/// Options for <see cref="Server2003Api.JetUpdate2"/>.
/// </summary>
[Flags]
public enum UpdateGrbit
{
/// <summary>
/// Default options.
/// </summary>
None = 0,
#if !MANAGEDESENT_ON_WSA // Not exposed in MSDK
/// <summary>
/// This flag causes the update to return an error if the update would
/// not have been possible in the Windows 2000 version of ESE, which
/// enforced a smaller maximum number of multi-valued column instances
/// in each record than later versions of ESE. This is important only
/// for applications that wish to replicate data between applications
/// hosted on Windows 2000 and applications hosted on Windows
/// 2003, or later versions of ESE. It should not be necessary for most
/// applications.
/// </summary>
[Obsolete("Only needed for legacy replication applications.")]
CheckESE97Compatibility = 0x1,
#endif // !MANAGEDESENT_ON_WSA
}
/// <summary>
/// Grbits that have been added to the Windows Server 2003 version of ESENT.
/// </summary>
public static class Server2003Grbits
{
/// <summary>
/// Delete all indexes with unicode columns.
/// </summary>
public const AttachDatabaseGrbit DeleteUnicodeIndexes = (AttachDatabaseGrbit)0x400;
/// <summary>
/// When the escrow-update column reaches a value of zero (after all
/// versions are resolve), the record will be deleted. A common use for
/// a column that can be finalized is to use it as a reference count
/// field, and when the field reaches zero the record gets deleted. A
/// Delete-on-zero column must be an escrow update / <see cref="ColumndefGrbit.ColumnEscrowUpdate"/>
/// column. ColumnDeleteOnZero cannot be used with ColumnFinalize.
/// ColumnDeleteOnZero cannot be used with user defined default columns.
/// </summary>
public const ColumndefGrbit ColumnDeleteOnZero = (ColumndefGrbit)0x20000;
/// <summary>
/// This option requests that the temporary table only be created if the
/// temporary table manager can use the implementation optimized for
/// intermediate query results. If any characteristic of the temporary
/// table would prevent the use of this optimization then the operation
/// will fail with JET_errCannotMaterializeForwardOnlySort. A side effect
/// of this option is to allow the temporary table to contain records
/// with duplicate index keys. See <see cref="TempTableGrbit.Unique"/>
/// for more information.
/// </summary>
public const TempTableGrbit ForwardOnly = (TempTableGrbit)0x40;
/// <summary>
/// If a given column is not present in the record and it has a user
/// defined default value then no column value will be returned.
/// This option will prevent the callback that computes the user defined
/// default value for the column from being called when enumerating
/// the values for that column.
/// </summary>
/// <remarks>
/// This option is only available for Windows Server 2003 SP1 and later
/// operating systems.
/// </remarks>
public const EnumerateColumnsGrbit EnumerateIgnoreUserDefinedDefault = (EnumerateColumnsGrbit)0x00100000;
/// <summary>
/// All transactions previously committed by any session that have not
/// yet been flushed to the transaction log file will be flushed immediately.
/// This API will wait until the transactions have been flushed before
/// returning to the caller. This option may be used even if the session
/// is not currently in a transaction. This option cannot be used in
/// combination with any other option.
/// </summary>
public const CommitTransactionGrbit WaitAllLevel0Commit = (CommitTransactionGrbit)0x8;
}
}

View File

@ -0,0 +1,24 @@
//-----------------------------------------------------------------------
// <copyright file="Server2003Param.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop.Server2003
{
/// <summary>
/// System parameters that have been added to the Windows Server 2003 version of ESENT.
/// </summary>
public static class Server2003Param
{
/// <summary>
/// The full path to each database is persisted in the transaction logs
/// at run time. Ordinarily, these databases must remain at the original
/// location for transaction replay to function correctly. This
/// parameter can be used to force crash recovery or a restore operation
/// to look for the databases referenced in the transaction log in the
/// specified folder.
/// </summary>
public const JET_param AlternateDatabaseRecoveryPath = (JET_param)113;
}
}

View File

@ -0,0 +1,89 @@
//-----------------------------------------------------------------------
// <copyright file="Session.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System.Globalization;
/// <summary>
/// A class that encapsulates a JET_SESID in a disposable object.
/// </summary>
public class Session : EsentResource
{
/// <summary>
/// The underlying JET_SESID.
/// </summary>
private JET_SESID sesid;
/// <summary>
/// Initializes a new instance of the Session class. A new
/// JET_SESSION is allocated from the given instance.
/// </summary>
/// <param name="instance">The instance to start the session in.</param>
public Session(JET_INSTANCE instance)
{
Api.JetBeginSession(instance, out this.sesid, null, null);
this.ResourceWasAllocated();
}
/// <summary>
/// Gets the JET_SESID that this session contains.
/// </summary>
public JET_SESID JetSesid
{
get
{
this.CheckObjectIsNotDisposed();
return this.sesid;
}
}
/// <summary>
/// Implicit conversion operator from a Session to a JET_SESID. This
/// allows a Session to be used with APIs which expect a JET_SESID.
/// </summary>
/// <param name="session">The session to convert.</param>
/// <returns>The JET_SESID of the session.</returns>
public static implicit operator JET_SESID(Session session)
{
return session.JetSesid;
}
/// <summary>
/// Returns a <see cref="T:System.String"/> that represents the current <see cref="Session"/>.
/// </summary>
/// <returns>
/// A <see cref="T:System.String"/> that represents the current <see cref="Session"/>.
/// </returns>
public override string ToString()
{
return string.Format(CultureInfo.InvariantCulture, "Session (0x{0:x})", this.sesid.Value);
}
/// <summary>
/// Terminate the session.
/// </summary>
public void End()
{
this.CheckObjectIsNotDisposed();
this.ReleaseResource();
}
/// <summary>
/// Free the underlying JET_SESID.
/// </summary>
protected override void ReleaseResource()
{
if (!this.sesid.IsInvalid)
{
Api.JetEndSession(this.JetSesid, EndSessionGrbit.None);
}
this.sesid = JET_SESID.Nil;
this.ResourceWasReleased();
}
}
}

View File

@ -0,0 +1,544 @@
//-----------------------------------------------------------------------
// <copyright file="SetColumnHelpers.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.Serialization;
#if MANAGEDESENT_SUPPORTS_SERIALIZATION
using System.Runtime.Serialization.Formatters.Binary;
#endif
using System.Text;
using Microsoft.Isam.Esent.Interop.Vista;
using Microsoft.Isam.Esent.Interop.Windows10;
/// <summary>
/// Helper methods for the ESENT API. These do data conversion for
/// setting columns.
/// </summary>
public static partial class Api
{
/// <summary>
/// Modifies a single column value in a modified record to be inserted or to
/// update the current record.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to update. An update should be prepared.</param>
/// <param name="columnid">The columnid to set.</param>
/// <param name="data">The data to set.</param>
/// <param name="encoding">The encoding used to convert the string.</param>
public static void SetColumn(
JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, string data, Encoding encoding)
{
SetColumn(sesid, tableid, columnid, data, encoding, SetColumnGrbit.None);
}
/// <summary>
/// Modifies a single column value in a modified record to be inserted or to
/// update the current record.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to update. An update should be prepared.</param>
/// <param name="columnid">The columnid to set.</param>
/// <param name="data">The data to set.</param>
/// <param name="encoding">The encoding used to convert the string.</param>
/// <param name="grbit">SetColumn options.</param>
public static void SetColumn(
JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, string data, Encoding encoding, SetColumnGrbit grbit)
{
CheckEncodingIsValid(encoding);
if (null == data)
{
JetSetColumn(sesid, tableid, columnid, null, 0, grbit, null);
}
else if (0 == data.Length)
{
JetSetColumn(sesid, tableid, columnid, null, 0, grbit | SetColumnGrbit.ZeroLength, null);
}
else if (Encoding.Unicode == encoding)
{
// Optimization for setting Unicode strings.
unsafe
{
fixed (char* buffer = data)
{
JetSetColumn(
sesid,
tableid,
columnid,
new IntPtr(buffer),
checked(data.Length * sizeof(char)),
grbit,
null);
}
}
}
else if (encoding.GetMaxByteCount(data.Length) <= Caches.ColumnCache.BufferSize)
{
#if MANAGEDESENT_ON_WSA
// Encoding.GetBytes(char*, int, byte*, int) overload is missing in new Windows UI.
// So we can't use the ColumnCache. We'll just use a different GetBytes() overload.
byte[] buffer = encoding.GetBytes(data);
unsafe
{
fixed (byte* bytes = buffer)
{
JetSetColumn(sesid, tableid, columnid, new IntPtr(bytes), buffer.Length, grbit, null);
}
}
#else
// The encoding output will fix in a cached buffer. Get one to avoid
// more memory allocations.
byte[] buffer = null;
try
{
buffer = Caches.ColumnCache.Allocate();
unsafe
{
fixed (char* chars = data)
fixed (byte* bytes = buffer)
{
int dataSize = encoding.GetBytes(chars, data.Length, bytes, buffer.Length);
JetSetColumn(sesid, tableid, columnid, new IntPtr(bytes), dataSize, grbit, null);
}
}
}
finally
{
if (buffer != null)
{
Caches.ColumnCache.Free(ref buffer);
}
}
#endif
}
else
{
byte[] bytes = encoding.GetBytes(data);
JetSetColumn(sesid, tableid, columnid, bytes, bytes.Length, grbit, null);
}
}
/// <summary>
/// Modifies a single column value in a modified record to be inserted or to
/// update the current record.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to update. An update should be prepared.</param>
/// <param name="columnid">The columnid to set.</param>
/// <param name="data">The data to set.</param>
public static void SetColumn(JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, byte[] data)
{
SetColumn(sesid, tableid, columnid, data, SetColumnGrbit.None);
}
/// <summary>
/// Modifies a single column value in a modified record to be inserted or to
/// update the current record.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to update. An update should be prepared.</param>
/// <param name="columnid">The columnid to set.</param>
/// <param name="data">The data to set.</param>
/// <param name="grbit">SetColumn options.</param>
public static void SetColumn(JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, byte[] data, SetColumnGrbit grbit)
{
int dataLength = (null == data) ? 0 : data.Length;
SetColumn(sesid, tableid, columnid, data, dataLength, grbit);
}
/// <summary>
/// Modifies a single column value in a modified record to be inserted or to
/// update the current record.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to update. An update should be prepared.</param>
/// <param name="columnid">The columnid to set.</param>
/// <param name="data">The data to set.</param>
/// <param name="dataSize">The size of data to set.</param>
/// <param name="grbit">SetColumn options.</param>
public static void SetColumn(JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, byte[] data, int dataSize, SetColumnGrbit grbit)
{
if ((null != data) && (0 == data.Length))
{
grbit |= SetColumnGrbit.ZeroLength;
}
if (data == null && dataSize > 0)
{
throw new ArgumentException(string.Format("data is null, but dataSize is: {0}", dataSize));
}
if (data != null && data.Length < dataSize)
{
throw new ArgumentException(string.Format("data.Length is less, than dataSize: data.Length={0}, dataSize={1}", data.Length, dataSize));
}
JetSetColumn(sesid, tableid, columnid, data, dataSize, grbit, null);
}
/// <summary>
/// Modifies a single column value in a modified record to be inserted or to
/// update the current record.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to update. An update should be prepared.</param>
/// <param name="columnid">The columnid to set.</param>
/// <param name="data">The data to set.</param>
public static void SetColumn(JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, bool data)
{
byte b = data ? (byte)0xff : (byte)0x0;
SetColumn(sesid, tableid, columnid, b);
}
/// <summary>
/// Modifies a single column value in a modified record to be inserted or to
/// update the current record.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to update. An update should be prepared.</param>
/// <param name="columnid">The columnid to set.</param>
/// <param name="data">The data to set.</param>
public static void SetColumn(JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, byte data)
{
unsafe
{
const int DataSize = sizeof(byte);
var pointer = new IntPtr(&data);
JetSetColumn(sesid, tableid, columnid, pointer, DataSize, SetColumnGrbit.None, null);
}
}
/// <summary>
/// Modifies a single column value in a modified record to be inserted or to
/// update the current record.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to update. An update should be prepared.</param>
/// <param name="columnid">The columnid to set.</param>
/// <param name="data">The data to set.</param>
public static void SetColumn(JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, short data)
{
unsafe
{
const int DataSize = sizeof(short);
var pointer = new IntPtr(&data);
JetSetColumn(sesid, tableid, columnid, pointer, DataSize, SetColumnGrbit.None, null);
}
}
/// <summary>
/// Modifies a single column value in a modified record to be inserted or to
/// update the current record.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to update. An update should be prepared.</param>
/// <param name="columnid">The columnid to set.</param>
/// <param name="data">The data to set.</param>
public static void SetColumn(JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, int data)
{
unsafe
{
const int DataSize = sizeof(int);
var pointer = new IntPtr(&data);
JetSetColumn(sesid, tableid, columnid, pointer, DataSize, SetColumnGrbit.None, null);
}
}
/// <summary>
/// Modifies a single column value in a modified record to be inserted or to
/// update the current record.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to update. An update should be prepared.</param>
/// <param name="columnid">The columnid to set.</param>
/// <param name="data">The data to set.</param>
public static void SetColumn(JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, long data)
{
unsafe
{
const int DataSize = sizeof(long);
var pointer = new IntPtr(&data);
JetSetColumn(sesid, tableid, columnid, pointer, DataSize, SetColumnGrbit.None, null);
}
}
/// <summary>
/// Modifies a single column value in a modified record to be inserted or to
/// update the current record.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to update. An update should be prepared.</param>
/// <param name="columnid">The columnid to set.</param>
/// <param name="data">The data to set.</param>
public static void SetColumn(JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, Guid data)
{
unsafe
{
const int DataSize = 16; // sizeof(Guid) isn't a compile-time constant
var pointer = new IntPtr(&data);
JetSetColumn(sesid, tableid, columnid, pointer, DataSize, SetColumnGrbit.None, null);
}
}
/// <summary>
/// Modifies a single column value in a modified record to be inserted or to
/// update the current record.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to update. An update should be prepared.</param>
/// <param name="columnid">The columnid to set.</param>
/// <param name="data">The data to set.</param>
public static void SetColumn(JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, DateTime data)
{
SetColumn(sesid, tableid, columnid, data.ToOADate());
}
/// <summary>
/// Modifies a single column value in a modified record to be inserted or to
/// update the current record.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to update. An update should be prepared.</param>
/// <param name="columnid">The columnid to set.</param>
/// <param name="data">The data to set.</param>
public static void SetColumn(JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, float data)
{
unsafe
{
const int DataSize = sizeof(float);
var pointer = new IntPtr(&data);
JetSetColumn(sesid, tableid, columnid, pointer, DataSize, SetColumnGrbit.None, null);
}
}
/// <summary>
/// Modifies a single column value in a modified record to be inserted or to
/// update the current record.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to update. An update should be prepared.</param>
/// <param name="columnid">The columnid to set.</param>
/// <param name="data">The data to set.</param>
public static void SetColumn(JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, double data)
{
unsafe
{
const int DataSize = sizeof(double);
var pointer = new IntPtr(&data);
JetSetColumn(sesid, tableid, columnid, pointer, DataSize, SetColumnGrbit.None, null);
}
}
/// <summary>
/// Perform atomic addition on an Int32 column. The column must be of type
/// <see cref="JET_coltyp.Long"/>. This function allows multiple sessions to update the
/// same record concurrently without conflicts.
/// </summary>
/// <remarks>
/// This method wraps <see cref="JetEscrowUpdate"/>.
/// </remarks>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to update.</param>
/// <param name="columnid">The column to update. This must be an escrow-updatable column.</param>
/// <param name="delta">The delta to apply to the column.</param>
/// <returns>The current value of the column as stored in the database (versioning is ignored).</returns>
public static int EscrowUpdate(JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, int delta)
{
var previousValue = new byte[sizeof(int)];
int actualPreviousValueLength;
JetEscrowUpdate(
sesid,
tableid,
columnid,
BitConverter.GetBytes(delta),
sizeof(int),
previousValue,
previousValue.Length,
out actualPreviousValueLength,
EscrowUpdateGrbit.None);
Debug.Assert(
previousValue.Length == actualPreviousValueLength,
"Unexpected previous value length. Expected an Int32");
return BitConverter.ToInt32(previousValue, 0);
}
/// <summary>
/// Perform atomic addition on an Int64 column. The column must be of type
/// <see cref="VistaColtyp.LongLong"/>. This function allows multiple sessions to update the
/// same record concurrently without conflicts.
/// </summary>
/// <remarks>
/// This method wraps <see cref="JetEscrowUpdate"/>.
/// </remarks>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to update.</param>
/// <param name="columnid">The column to update. This must be an escrow-updatable column.</param>
/// <param name="delta">The delta to apply to the column.</param>
/// <returns>The current value of the column as stored in the database (versioning is ignored).</returns>
public static long EscrowUpdate(JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, long delta)
{
var previousValue = new byte[sizeof(long)];
int actualPreviousValueLength;
JetEscrowUpdate(
sesid,
tableid,
columnid,
BitConverter.GetBytes(delta),
sizeof(long),
previousValue,
previousValue.Length,
out actualPreviousValueLength,
EscrowUpdateGrbit.None);
Debug.Assert(
previousValue.Length == actualPreviousValueLength,
"Unexpected previous value length. Expected an Int64");
return BitConverter.ToInt64(previousValue, 0);
}
/// <summary>
/// Modifies a single column value in a modified record to be inserted or to
/// update the current record.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to update. An update should be prepared.</param>
/// <param name="columnid">The columnid to set.</param>
/// <param name="data">The data to set.</param>
[CLSCompliant(false)]
public static void SetColumn(JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, ushort data)
{
unsafe
{
const int DataSize = sizeof(ushort);
var pointer = new IntPtr(&data);
JetSetColumn(sesid, tableid, columnid, pointer, DataSize, SetColumnGrbit.None, null);
}
}
/// <summary>
/// Modifies a single column value in a modified record to be inserted or to
/// update the current record.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to update. An update should be prepared.</param>
/// <param name="columnid">The columnid to set.</param>
/// <param name="data">The data to set.</param>
[CLSCompliant(false)]
public static void SetColumn(JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, uint data)
{
unsafe
{
const int DataSize = sizeof(uint);
var pointer = new IntPtr(&data);
JetSetColumn(sesid, tableid, columnid, pointer, DataSize, SetColumnGrbit.None, null);
}
}
/// <summary>
/// Modifies a single column value in a modified record to be inserted or to
/// update the current record.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to update. An update should be prepared.</param>
/// <param name="columnid">The columnid to set.</param>
/// <param name="data">The data to set.</param>
[CLSCompliant(false)]
public static void SetColumn(JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, ulong data)
{
unsafe
{
const int DataSize = sizeof(ulong);
var pointer = new IntPtr(&data);
JetSetColumn(sesid, tableid, columnid, pointer, DataSize, SetColumnGrbit.None, null);
}
}
#if MANAGEDESENT_SUPPORTS_SERIALIZATION
/// <summary>
/// Write a serialized form of an object to a column.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The table to write to. An update should be prepared.</param>
/// <param name="columnid">The column to write to.</param>
/// <param name="value">The object to write. The object must be serializable.</param>
[SuppressMessage("Exchange.Security", "EX0043:DoNotUseBinarySoapFormatter", Justification = "Suppress warning in current code base.The usage has already been verified.")]
public static void SerializeObjectToColumn(JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, object value)
{
if (null == value)
{
Api.SetColumn(sesid, tableid, columnid, null);
}
else
{
using (var stream = new ColumnStream(sesid, tableid, columnid))
{
var serializer = new BinaryFormatter
{
Context = new StreamingContext(StreamingContextStates.Persistence)
};
serializer.Serialize(stream, value);
}
}
}
#endif
/// <summary>
/// Sets columns from ColumnValue objects.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">The cursor to update. An update should be prepared.</param>
/// <param name="values">The values to set.</param>
public static void SetColumns(JET_SESID sesid, JET_TABLEID tableid, params ColumnValue[] values)
{
if (null == values)
{
throw new ArgumentNullException("values");
}
if (0 == values.Length)
{
throw new ArgumentOutOfRangeException("values", values.Length, "must have at least one value");
}
unsafe
{
NATIVE_SETCOLUMN* nativeSetcolumns = stackalloc NATIVE_SETCOLUMN[values.Length];
Api.Check(values[0].SetColumns(sesid, tableid, values, nativeSetcolumns, 0));
}
}
/// <summary>
/// Verifies that the given encoding is valid for setting/retrieving data. Only
/// the ASCII and Unicode encodings are allowed. An <see cref="ArgumentOutOfRangeException"/>
/// is thrown if the encoding isn't valid.
/// </summary>
/// <param name="encoding">The encoding to check.</param>
private static void CheckEncodingIsValid(Encoding encoding)
{
#if MANAGEDESENT_ON_CORECLR
string webName = encoding.WebName;
if (webName != "utf-8" && webName != "utf-16")
{
throw new ArgumentOutOfRangeException(
"encoding", webName, "Invalid Encoding type. Only Unicode (utf-8 and utf-16) encodings are allowed.");
}
#else
const int AsciiCodePage = 20127; // from MSDN
const int UnicodeCodePage = 1200; // from MSDN
int codePage = encoding.CodePage;
if ((AsciiCodePage != codePage) && (UnicodeCodePage != codePage))
{
throw new ArgumentOutOfRangeException(
"encoding", codePage, "Invalid Encoding type. Only ASCII and Unicode encodings are allowed");
}
#endif
}
}
}

View File

@ -0,0 +1,78 @@
<StyleCopSettings Version="105">
<GlobalSettings>
<BooleanProperty Name="WriteCache">False</BooleanProperty>
<CollectionProperty Name="RecognizedWords">
<Value>api</Value>
<Value>coltyp</Value>
<Value>columndef</Value>
<Value>columnid</Value>
<Value>dbid</Value>
<Value>dll</Value>
<Value>ese</Value>
<Value>esent</Value>
<Value>grbit</Value>
<Value>grbits</Value>
<Value>interop</Value>
<Value>itag</Value>
<Value>lgpos</Value>
<Value>param</Value>
<Value>preread</Value>
<Value>sesid</Value>
<Value>tableid</Value>
</CollectionProperty>
</GlobalSettings>
<Analyzers>
<Analyzer AnalyzerId="StyleCop.CSharp.NamingRules">
<AnalyzerSettings>
<CollectionProperty Name="Hungarian">
<Value>c</Value>
<Value>cb</Value>
<Value>dw</Value>
<Value>f</Value>
<Value>h</Value>
<Value>ib</Value>
<Value>l</Value>
<Value>p</Value>
<Value>pv</Value>
<Value>rg</Value>
<Value>sz</Value>
<Value>ul</Value>
<Value>w</Value>
</CollectionProperty>
</AnalyzerSettings>
</Analyzer>
<Analyzer AnalyzerId="StyleCop.CSharp.DocumentationRules">
<Rules>
<Rule Name="DocumentationTextMustBeginWithACapitalLetter">
<RuleSettings>
<BooleanProperty Name="Enabled">True</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DocumentationTextMustEndWithAPeriod">
<RuleSettings>
<BooleanProperty Name="Enabled">True</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FileHeaderFileNameDocumentationMustMatchTypeName">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
</Rules>
<AnalyzerSettings>
<StringProperty Name="CompanyName">Microsoft Corporation</StringProperty>
<StringProperty Name="Copyright">Copyright (c) Microsoft Corporation.</StringProperty>
</AnalyzerSettings>
</Analyzer>
<Analyzer AnalyzerId="StyleCop.CSharp.MaintainabilityRules">
<Rules>
<Rule Name="FileMayOnlyContainASingleNamespace">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
</Rules>
<AnalyzerSettings />
</Analyzer>
</Analyzers>
</StyleCopSettings>

View File

@ -0,0 +1,166 @@
//-----------------------------------------------------------------------
// <copyright file="StringCache.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
/// <summary>
/// Class that helps cache strings.
/// </summary>
internal static class StringCache
{
/// <summary>
/// Don't cache strings whose length is longer than this.
/// </summary>
private const int MaxLengthToCache = 128;
/// <summary>
/// Number of converted strings to hash.
/// </summary>
private const int NumCachedBoxedValues = 1031;
/// <summary>
/// Cached string values.
/// </summary>
private static readonly string[] CachedStrings = new string[NumCachedBoxedValues];
/// <summary>
/// Return the interned version of a string, or the original
/// string if it isn't interned.
/// </summary>
/// <param name="s">The string to try to intern.</param>
/// <returns>An interned copy of the string or the original string.</returns>
public static string TryToIntern(string s)
{
#if MANAGEDESENT_ON_WSA
// new Windows UI Core CLR does not support string interning.
return s;
#else
return string.IsInterned(s) ?? s;
#endif
}
/// <summary>
/// Convert a byte array to a string.
/// </summary>
/// <param name="value">The bytes to convert.</param>
/// <param name="startIndex">The starting index of the data to convert.</param>
/// <param name="count">The number of bytes to convert.</param>
/// <returns>A string converted from the data.</returns>
public static string GetString(byte[] value, int startIndex, int count)
{
unsafe
{
fixed (byte* data = value)
{
char* chars = (char*)(data + startIndex);
return GetString(chars, 0, count / sizeof(char));
}
}
}
/// <summary>
/// Convert a char array to a string, using a cached value if possible.
/// </summary>
/// <param name="value">The characters to convert.</param>
/// <param name="startIndex">The starting index of the data to convert.</param>
/// <param name="count">The number of characters to convert.</param>
/// <returns>A string converted from the data.</returns>
private static unsafe string GetString(char* value, int startIndex, int count)
{
string s;
if (0 == count)
{
s = string.Empty;
}
else if (count < MaxLengthToCache)
{
uint hash = CalculateHash(value, startIndex, count);
int index = unchecked((int)(hash % NumCachedBoxedValues));
s = CachedStrings[index];
if (null == s || !AreEqual(s, value, startIndex, count))
{
s = CreateNewString(value, startIndex, count);
CachedStrings[index] = s;
}
}
else
{
s = CreateNewString(value, startIndex, count);
}
return s;
}
/// <summary>
/// Calculate the hash of a string.
/// </summary>
/// <param name="value">The characters to hash.</param>
/// <param name="startIndex">The starting index of the data to hash.</param>
/// <param name="count">The number of characters to hash.</param>
/// <returns>The hash value of the data.</returns>
private static unsafe uint CalculateHash(char* value, int startIndex, int count)
{
uint hash = 0;
unchecked
{
for (int i = 0; i < count; ++i)
{
hash ^= value[startIndex + i];
hash *= 33;
}
}
return hash;
}
/// <summary>
/// Determine if a string matches a char array..
/// </summary>
/// <param name="s">The string to compare against.</param>
/// <param name="value">The characters.</param>
/// <param name="startIndex">The starting index of the data.</param>
/// <param name="count">The number of characters.</param>
/// <returns>True if the string matches the char array.</returns>
private static unsafe bool AreEqual(string s, char* value, int startIndex, int count)
{
if (s.Length != count)
{
return false;
}
unchecked
{
for (int i = 0; i < s.Length; ++i)
{
if (s[i] != value[startIndex + i])
{
return false;
}
}
}
return true;
}
/// <summary>
/// Convert a char array to a string.
/// </summary>
/// <param name="value">The characters to convert.</param>
/// <param name="startIndex">The starting index of the data to convert.</param>
/// <param name="count">The number of characters to convert.</param>
/// <returns>A string converted from the data.</returns>
private static unsafe string CreateNewString(char* value, int startIndex, int count)
{
// Encoding.Unicode.GetString copies the data to an array of chars and then
// makes a string from it, copying the data twice. Use the more efficient
// char* constructor.
return new string(value, startIndex, count);
}
}
}

View File

@ -0,0 +1,128 @@
//-----------------------------------------------------------------------
// <copyright file="StringColumnValue.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
using System.Diagnostics;
/// <summary>
/// A Unicode string column value.
/// </summary>
public class StringColumnValue : ColumnValue
{
/// <summary>
/// Internal value.
/// </summary>
private string internalValue;
/// <summary>
/// Gets the last set or retrieved value of the column. The
/// value is returned as a generic object.
/// </summary>
public override object ValueAsObject
{
[DebuggerStepThrough]
get { return this.Value; }
}
/// <summary>
/// Gets or sets the value of the column. Use <see cref="Api.SetColumns"/> to update a
/// record with the column value.
/// </summary>
public string Value
{
get
{
return this.internalValue;
}
set
{
this.internalValue = value;
this.Error = value == null ? JET_wrn.ColumnNull : JET_wrn.Success;
}
}
/// <summary>
/// Gets the byte length of a column value, which is zero if column is null, otherwise
/// it matches the byte length of the string value. The byte length is determined in
/// assumption of two bytes per character.
/// </summary>
public override int Length
{
get { return this.Value != null ? this.Value.Length * sizeof(char) : 0; }
}
/// <summary>
/// Gets the size of the value in the column. This returns 0 for
/// variable sized columns (i.e. binary and string).
/// </summary>
protected override int Size
{
[DebuggerStepThrough]
get { return 0; }
}
/// <summary>
/// Gets a string representation of this object.
/// </summary>
/// <returns>A string representation of this object.</returns>
public override string ToString()
{
return this.Value;
}
/// <summary>
/// Recursive SetColumns method for data pinning. This populates the buffer and
/// calls the inherited SetColumns method.
/// </summary>
/// <param name="sesid">The session to use.</param>
/// <param name="tableid">
/// The table to set the columns in. An update should be prepared.
/// </param>
/// <param name="columnValues">
/// Column values to set.
/// </param>
/// <param name="nativeColumns">
/// Structures to put the pinned data in.
/// </param>
/// <param name="i">Offset of this object in the array.</param>
/// <returns>An error code.</returns>
internal override unsafe int SetColumns(JET_SESID sesid, JET_TABLEID tableid, ColumnValue[] columnValues, NATIVE_SETCOLUMN* nativeColumns, int i)
{
if (null != this.Value)
{
fixed (void* buffer = this.Value)
{
return this.SetColumns(
sesid, tableid, columnValues, nativeColumns, i, buffer, checked(this.Value.Length * sizeof(char)), true);
}
}
return this.SetColumns(sesid, tableid, columnValues, nativeColumns, i, null, 0, false);
}
/// <summary>
/// Given data retrieved from ESENT, decode the data and set the value in the ColumnValue object.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within the bytes.</param>
/// <param name="count">The number of bytes to decode.</param>
/// <param name="err">The error returned from ESENT.</param>
protected override void GetValueFromBytes(byte[] value, int startIndex, int count, int err)
{
if (JET_wrn.ColumnNull == (JET_wrn)err)
{
this.Value = null;
}
else
{
this.Value = StringCache.GetString(value, startIndex, count);
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More