Skip to content

Nest manifest resources into namespace directories (fixes #3717)#3735

Closed
OpenSourcereR-dev wants to merge 1 commit into
icsharpcode:masterfrom
OpenSourcereR-dev:fix-3717-resource-nesting
Closed

Nest manifest resources into namespace directories (fixes #3717)#3735
OpenSourcereR-dev wants to merge 1 commit into
icsharpcode:masterfrom
OpenSourcereR-dev:fix-3717-resource-nesting

Conversation

@OpenSourcereR-dev
Copy link
Copy Markdown

@OpenSourcereR-dev OpenSourcereR-dev commented May 13, 2026

Fixes #3717.

When decompiling an assembly as a project, manifest resources with dot-separated names (e.g. MyApp.images.CopyHS.png) were emitted flat in the project root next to the namespace directory containing the matching .cs files. This PR places them inside that directory.

# before
out/Be.Windows.Forms.HexBox.bmp
out/Be.Windows.Forms/HexBox.cs

# after (default)
out/Be.Windows.Forms/HexBox.bmp
out/Be.Windows.Forms/HexBox.cs

# after (with --nested-directories)
out/Be/Windows/Forms/HexBox.bmp
out/Be/Windows/Forms/HexBox.cs

The csproj's <EmbeddedResource ... LogicalName="..." /> value is unchanged, so the produced manifest resource name is byte-identical to before.

Changes (all in WholeProjectDecompiler.cs)

  1. DecompileProject: pre-populate directories with the namespace folders of all top-level types before calling WriteResourceFilesInProject. Resources are written before code files, so directories was always empty during the resource walk and GetFileNameForResource's prefix-match loop never matched anything.

  2. GetFileNameForResource: when input has no path separators, split on . (keeping the extension on the last segment) and match against both slash- and dot-joined directory entries.

  3. WriteResourceToFile + flat-resource branch: create the chosen directory before opening the FileStream.

Testing

Verified on a ~3 MB assembly with 19 embedded resources: all 19 are now placed inside the matching namespace directory. Existing WholeProjectDecompilerTests unaffected (it mocks WriteResourceFilesInProject). Happy to add a regression test if you'd like.

Three changes to WholeProjectDecompiler.cs so that 'ilspycmd -p' (and
WholeProjectDecompiler in general) places manifest resources inside the
namespace directory that matches their dotted prefix, instead of leaving
them flat at the project root.

Before: 'Be.Windows.Forms.HexBox.bmp' written as a flat file next to a
directory 'Be.Windows.Forms/' (which contains the matching HexBox.cs etc).
After: 'Be.Windows.Forms.HexBox.bmp' written as 'Be/Windows/Forms/HexBox.bmp'
(with --nested-directories) or 'Be.Windows.Forms/HexBox.bmp' (default flat-
dotted dirs), alongside the matching HexBox.cs. The csproj's LogicalName
attribute is unchanged, so the produced .resources manifest entry name is
identical to the original input -- no runtime behavior changes.

1. DecompileProject: pre-populate 'directories' with the namespace folders
   of all types BEFORE calling WriteResourceFilesInProject. The original
   code cleared 'directories' on entry then ran resource-writing first
   while 'directories' was still empty, then ran code-file writing (which
   is what populates 'directories'). As a result GetFileNameForResource's
   match loop couldn't ever find an existing namespace directory and
   emitted every resource flat at the project root. The pre-pass also
   physically creates each directory (CreateDirectory) so subsequent
   code-file writes find them already there (the existing 'directories.Add
   returned true -> CreateDirectory' branch in WriteCodeFilesInProject is
   a no-op when the directory is already in the set).

2. GetFileNameForResource: when the input has no path separators (the
   common case for dotted manifest resource names) split on '.' keeping
   the file extension on the last segment, and try matching the prefix
   against BOTH slash-joined and dot-joined directory entries -- handles
   both UseNestedDirectoriesForNamespaces=true and the default false.

3. WriteResourceToFile and the flat-resource branch in
   WriteResourceFilesInProject: create the chosen directory on disk
   before opening the FileStream, since resources are written before
   code-files and the namespace directory the resource was placed in
   may not exist yet (when the pre-pass added the dotted-namespace dir
   but the resource's destination needs a different layout, e.g.
   slash-joined when --nested-directories is set).
@siegfriedpammer
Copy link
Copy Markdown
Member

Can you please mention in your PR description if you used AI? This is definitely AI-generated.

@siegfriedpammer
Copy link
Copy Markdown
Member

Also I think this needs a setting on WholeProjectDecompiler

@OpenSourcereR-dev
Copy link
Copy Markdown
Author

Can you please mention in your PR description if you used AI? This is definitely AI-generated.

Hi. AI-Assisted (Claude Opus 4.7). Fully reviewed and tested by me. Why?

Also I think this needs a setting on WholeProjectDecompiler

Can add it if you want me to. :-)

@OpenSourcereR-dev OpenSourcereR-dev closed this by deleting the head repository May 14, 2026
@siegfriedpammer
Copy link
Copy Markdown
Member

So you no longer need this? It's not like we don't accept AI contributions, it's just that we want the author to disclose whether they used AI and to what extent. It's only about disclosure.

@OpenSourcereR-dev
Copy link
Copy Markdown
Author

So you no longer need this?

@siegfriedpammer I already have it implemented and working beautifully on my local build,
It's for the community. I think the community needs it. Dotpeek does it out of the box for ages.
btw, I didn't intend to close the PR tho. I just needed to delete the forked repo and forgot it will end up closing the PR as well.

Also I think this needs a setting on WholeProjectDecompiler

Still can do that if you want me to, just say the word :-)

p.s.

It's not like we don't accept AI contributions, it's just that we want the author to disclose whether they used AI and to what extent. It's only about disclosure.

Honestly, just let a good enough model go through that long pile of open issues and it will help you get most if not all of them resolved in no time. AI helps us being extra productive. I know you don't object, saw you use Claude too. :-)

@siegfriedpammer
Copy link
Copy Markdown
Member

Honestly, just let a good enough model go through that long pile of open issues and it will help you get most if not all of them resolved in no time.

That's actually what I have planned for the near future :) Altough, I don't really like code review, but now's the time the industriy changes, so improving that skill is certainly valuable.

@siegfriedpammer
Copy link
Copy Markdown
Member

Still can do that if you want me to, just say the word :-)

Yes, please do it. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

csproj export emits embedded resources flat instead of restoring folder structure from dotted LogicalName

2 participants