C# — Включение сторонних .dll в конечный .exe-файл на C#


Содержание

Работа с нативными dll библиотеками в C#

В процессе разработки программного обеспечения далеко не всегда достаточно собственных наработок. Чаще всего проект содержит те или иные сторонние библиотеки.

Очень многие из них не являются .NET сборками и предназначены для работы непосредственно в среде Windows. Но, к счастью, в .NET Framework существует удобный механизм, который позволяет интегрировать обычные Windows dll библиотеки в программные проекты на .NET языках. При этом C# не исключение.

Рассмотрим простой пример. Подключим библиотеку, написанную на C++, к программе на C#. В качестве примера воспользуемся библиотекой, которая была разработана ранее для работы с Delphi [1].

Вкратце напомним, что эта библиотека содержи одну единственную функцию, которая возвращает целое число, которое было передано ей в качестве аргумента. Ссылка на статью с постановкой задачи и исходным кодом библиотеки приведена в конце данной статьи.

Механизм подключения предельно прост.

Вначале скопируем библиотеку в папку с программой или подключим её к проекту с указанием настройки копирования в выходной каталог «Копировать всегда» (в этом случае файл библиотеки будет добавляться в папку со скомпилированной программой автоматически).

Программирование на C, C# и Java

Уроки программирования, алгоритмы, статьи, исходники, примеры программ и полезные советы

ОСТОРОЖНО МОШЕННИКИ! В последнее время в социальных сетях участились случаи предложения помощи в написании программ от лиц, прикрывающихся сайтом vscode.ru. Мы никогда не пишем первыми и не размещаем никакие материалы в посторонних группах ВК. Для связи с нами используйте исключительно эти контакты: vscoderu@yandex.ru, https://vk.com/vscode

Динамическое подключение dll в C#

Поговорим о динамическом подключении библиотек dll (Dynamic Link Library) к программе, разрабатываемой на языке программирования C#. Рассмотрим пример написания консольного клиента для dll-файла.

Динамическое подключение dll происходит во время выполнения программы, в том месте, в котором действительно необходимо использовать функции из библиотеки. Вызов будет осуществляться явно, при выполнении определенного оператора. Статическое же подключении dll происходит сразу при запуске программы, поэтому, подключая библиотеку dll динамически, мы экономим ресурсы компьютера при выполнении нашей программы.

В статье “Как создать dll в Visual Studio” рассказывалось, как создавать dll-файлы, в частности и на языке C# (если вы не знаете как создавать dll, рекомендуем почитать ту статью). Там мы написали библиотеку dll, содержащую два метода: add и sub, которые складывают и вычитают два целых числа. Теперь разработаем консольный клиент для этой dll, продемонстрируем динамическое подключение этой библиотеки.

Компилятор csc.exe

В действительности необходимость в создании крупных приложений с использованием одного лишь компилятора командной строки C# может никогда не возникнуть, тем не менее, важно понимать в общем, как вручную компилировать файлы кода. Существует несколько причин, по которым освоение этого процесса может оказаться полезным:

Самой очевидной причиной является отсутствие Visual Studio 2010 или какой-то другой графической IDE-среды.

Работа может выполняться в университете, где использование инструментов для генерации кода и IDE-сред обычно запрещено.

Планируется применение автоматизированных средств разработки, таких как msbuild.exe, которые требуют знать опции командной строки для используемых инструментов.

Возникло желание углубить свои познания в C#. В графических IDE-средах в конечном итоге все заканчивается предоставлением компилятору csc.ехе инструкций относительно того, что следует делать с входными файлами кода C#. В этом отношении изучение происходящего «за кулисами» позволяет получить необходимые знания.

Еще одно преимущество подхода с использованием одного лишь компилятора csc.ехе состоит в том, что он позволяет обрести навыки и чувствовать себя более уверенно при работе с другими инструментами командной строки, входящими в состав .NET Framework 4.0 SDK, так как целый ряд важных утилит работает исключительно в режиме командной строки.

Чтобы посмотреть, как создавать .NET-приложение без IDE-среды, давайте построим с помощью компилятора C# и текстового редактора Notepad простую исполняемую сборку по имени TestApplication.exe. Сначала необходимо подготовить исходный код. Откройте программу Notepad (Блокнот), выбрав в меню Start (Пуск) пункт All Programs — Accessories — Notepad (Все программы — Стандартные — Блокнот), и введите следующее типичное определение класса на C#:

После окончания ввода сохраните файл под именем TestApplication.cs. Теперь давайте ознакомимся с ключевыми опциями компилятора C#.

Указание целевых входных и выходных параметров

Первым делом важно разобраться с тем, как указывать имя и тип создаваемой сборки (т.е., например, консольное приложение по имени MyShell.exe, библиотека кода по имени MathLib.dll или приложение Windows Presentation Foundation по имени Halo8.ехе). Каждый из возможных вариантов имеет соответствующий флаг, который нужно передать компилятору csc.ехе в виде параметра командной строки.

Обратите внимание, что параметры, передаваемые компилятору командной строки (а также большинству других утилит командной строки), могут сопровождаться префиксом в виде символа дефиса (-) или слеша (/).

Выходные параметры, которые может принимать компилятор C# приведены в следующей таблице:

Параметры компилятора csc.exe

Параметр Описание
/out Этот параметр применяется для указания имени создаваемой сборки. По умолчанию сборке присваивается то же имя, что у входного файла *.сs
/target:exe Этот параметр позволяет создавать исполняемое консольное приложение. Сборка такого типа генерируется по умолчанию, потому при создании подобного приложения данный параметр можно опускать
/target:library Этот параметр позволяет создавать однофайловую сборку *.dll
/target:module Этот параметр позволяет создавать модуль. Модули являются элементами многофайловых сборок
/target:winexe Хотя приложения с графическим пользовательским интерфейсом можно создавать с применением параметра /target: ехе, параметр /target: winexe позволяет предотвратить открытие окна консоли под остальными окнами

Чтобы скомпилировать TestApplication.cs в консольное приложение TestApplication.exe, перейдите в каталог, в котором был сохранен файл исходного кода (с помощью флага cd) и введите следующую команду:

Обратите внимание, что здесь C:\myProject — это путь к папке, в которой хранится файл TestApplication.cs. Так же обратите внимание, что здесь флаг /out не был указан явным образом, поэтому исполняемым файл получит имя TestApplication.ехе из-за того, что именем входного файла является TestApplication. Кроме того, для почти всех принимаемых компилятором C# флагов поддерживаются сокращенные версии написания, наподобие /t вместо /target (полный список которых можно увидеть, введя в командной строке команду csc -?).

Теперь можно попробовать запустить приложение TestApplication.ехе из командной строки, введя имя его исполняемого файла:

Добавление ссылок на внешние сборки

Давайте посмотрим, как скомпилировать приложение, в котором используются типы, определенные в отдельной сборке .NET. Если осталось неясным, каким образом компилятору C# удалось понять ссылку на тип System.Console, вспомните, что во время процесса компиляции происходит автоматическое добавление ссылки на mscorlib.dll (если по какой-то необычной причине нужно отключить эту функцию, следует передать компилятору csc.exe параметр /nostdlib).

Модифицируем приложение TestApplication так, чтобы в нем открывалось окно сообщения Windows Forms. Для этого откройте файл TestApplication.cs и измените его следующим образом:

Далее в командной строке нужно проинформировать компилятор csc.exe о том, в какой сборке содержатся используемые пространства имен. Поскольку применялся класс MessageBox из пространства имен System.Windows.Forms, значит, нужно указать компилятору на сборку System.Windows.Forms.dll, что делается с помощью флага /reference (или его сокращенной версии /r):

Если теперь снова попробовать запустить приложение, то помимо консольного вывода в нем должно появиться еще и окно с сообщением:

Кстати, как поступить, когда необходимо указать csc.exe несколько внешних сборок? Для этого нужно просто перечислить все сборки через точку с запятой. В рассматриваемом примере ссылаться на несколько сборок не требуется, но ниже приведена команда, которая иллюстрирует перечисление множества сборок:

csc /r:System.Windows.Forms.dll;System.Drawing.dll *.cs

Компиляция нескольких файлов исходного кода

В текущем примере приложение TestApp.exe создавалось с использованием единственного файла исходного кода * . cs. Хотя определять все типы .NET в одном файле *.cs вполне допустимо, в большинстве случаев проекты формируются из нескольких файлов *.cs для придания кодовой базе большей гибкости. Чтобы стало понятнее, давайте создадим новый класс и сохраним его в отдельном файле по имени HelloMessage.cs:

Изменим исходный класс TestApplication так, чтобы в нем использовался класс этого нового типа:

Чтобы скомпилировать файлы исходного кода на C# , необходимо их явно перечислить как входные файлы:

В качестве альтернативного варианта компилятор C# позволяет использовать групповой символ (*) для включения в текущую сборку всех файлов *.cs, которые содержатся в каталоге проекта:

Вывод, получаемый после запуска этой программы, идентичен предыдущей программе. Единственное отличие между этими двумя приложениями связано с разнесением логики по нескольким файлам.

Работа с ответными файлами в C#

Как не трудно догадаться, для создания сложного приложения C# из командной строки потребовалось бы вводить утомительное количество входных параметров для уведомления компилятора о том, как он должен обрабатывать исходный код. Для облегчения этой задачи в компиляторе C# поддерживается использование так называемых .

В ответных файлах C# размещаются все инструкции, которые должны использоваться в процессе компиляции текущей сборки. По соглашению эти файлы имеют расширение *.rsp (сокращение от response — ответ). Чтобы посмотреть на них в действии, давайте создадим ответный файл по имени TestApplication.rsp, содержащей следующие аргументы (комментарии в данном случае обозначаются символом #):

Теперь при условии сохранения данного файла в том же каталоге, где находятся подлежащие компиляции файлы исходного кода на C#, все приложение можно будет создать следующим образом (обратите внимание на применение символа @):

В случае необходимости допускается также указывать и несколько ответных *.rsp файлов в качестве входных параметров (например, csc @FirstFile.rsp @SecondFile.rsp @ThirdFile.rsp). При таком подходе, однако, следует иметь в виду, что компилятор обрабатывает параметры команд по мере их поступления. Следовательно, аргументы командной строки, содержащиеся в поступающем позже файле *.rsp, могут переопределять параметры из предыдущего ответного файла.

Последним моментом, связанным с ответными файлами, о котором необходимо упомянуть, является то, что с компилятором C# ассоциирован ответный файл csc.rsp, который используется по умолчанию и размещен в том же самом каталоге, что и файл csc.ехе (обычно это С:\Windows\Microsoft. NET\Framework\ , где на месте элемента идет номер конкретной версии платформы). Открыв файл csc.rsp в программе Notepad (Блокнот), можно увидеть, что в нем с помощью флага /r: указано множество сборок .NET, в том числе различные библиотеки для разработки веб-приложений, программирования с использованием технологии LINQ и обеспечения доступа к данным и прочие ключевые библиотеки (помимо, конечно же, самой главной библиотеки mscorlib.dll):

При создании программ на C# с применением csc.ехе ссылка на этот ответный файл добавляется автоматически, даже когда указан специальный файл *.rsp. Из-за наличия такого ответного файла по умолчанию, рассматриваемое приложение TestApplication.ехе можно скомпилировать и c помощью следующей команды (поскольку в csc.rsp уже содержится ссылка на System.Windows.Forms.dll):

Стоит отметить, что в случае добавления с помощью опции /r ссылок на сборки, которые на самом деле не используются, компилятор их проигнорирует. Поэтому беспокоиться по поводу «разбухания кода» не нужно.

Как создать свой DLL на C# а потом использовать его

16 ответов

Так бы сразу и говорили.
Для импорта в проект произвольной сборки (будь то dll или exe файл) достаточно в IDE, которой вы пользуетесь (везде одинаково), добавить ссылку (reference) на тот файл. Таким образом все пространства имен, определенные в сборке, станут доступны для конструкции using.
Если в вашем сольюшене два проекта — exe и dll, то можно сделать ссылку из exe-проекта на dll-проект из IDE — делается аналогично.

Цукерберг рекомендует:  Android - как отобразить таблицу в Android

Постарайтесь приобрести толковую книжку по C# — в них эти вещи описаны более подробно.

Как объединить библиотеки DLL с .exe внутри приложения wpf/winforms (с изображениями)

Как объединить несколько DLL в основной файл .exe? (без использования сторонних программ)

Update

если вы хотите, чтобы простой инструмент объединил сборки, не беспокоясь о том, чтобы делать ЛЮБОЙ труд вообще, Fody.Costura — лучший выбор, который вам нужен, поскольку все, что вам нужно сделать, это просто включить DLL файлы и изменить их действие Build на Embedded Resource, и он будет работать сразу.

1 — создайте папку, содержащую все библиотеки Dll, или поместите их отдельно, как вам нравится

2 — Щелкните по каждой DLL из «Обозревателя решений» и убедитесь, что у них есть эти свойства.

Build Action = Embedded Resources

Копировать в каталог вывода = Не копировать

3 — Перейдите в: Проект > Свойствa > Ссылки и убедитесь, что каждый добавленный вами Dll имеет то же имя, что и сборка:

В обозревателе решений: —

Примечание: —

Лучше сделать копию local = True в ссылках, поскольку это даст вы обновляете DLL каждый раз, когда вы публикуете проект

Теперь, когда вы добавили свои DLL файлы в EXE, все осталось теперь, чтобы сообщить программе, как читать эти DLL файлы из EXE (почему мы создали build action = Embedded resources)

4 — В обозревателе решений Откройте файл (Application.xaml.vb) ([App.xaml.cs] в С#)
ИЛИ
Перейти к: Проект > Свойствa > Приложение > Просмотр событий приложения

Теперь на этой странице мы рассмотрим самое первое событие приложения (событие Construction), чтобы сообщить программе, как обрабатывать сборки, которые мы добавляем в виде DLL, перед загрузкой/чтением их с помощью AssemblyResolve Event

5 — Теперь в часть кода:
прежде всего Импорт этого пространства имен

В конструкторе ([Sub New] в vb) добавьте этот код

Затем добавьте функцию OnResolveAssembly vb.net

6 — теперь опубликуйте приложение или создайте его, и все ваши DLL будут встроены в один EXE файл (с некоторой задержкой в ​​миллисекундах для их загрузки)

Обновление библиотек DLL

1 — Просто перетащите новую dll в Обозреватель решений как ту же папку, что и старая dll, затем примите переопределение (убедитесь, что [Build Action = Embedded Resources] И [Copy To Output Directory = Do not копия])

Добавить новые библиотеки DLL

просто повторите шаг 1 = > 3

* Не стесняйтесь спрашивать, есть ли у вас проблемы.

Записная книжка программиста-новичка, C#, SQL, PHP и все-все-все

Я ведь это уже делал, но хрен теперь найдешь тот кусок кода, гуглим снова… Где бы найти простое и понятное руководство для начинающего, а не тонкости для мега-гуру?


Рубрики

Свежие записи

Свежие комментарии

  • Calator prin Romania к записи Как переименовать проект/каталог проекта в Visual Studio?
  • iukovl к записи Как изменить максимальный размер загружаемого файла в php
  • sdfdsgeg к записи Работа с файлом конфигурации (configuration) в C# — читаем и сохраняем
  • iukovl к записи Как изменить максимальный размер загружаемого файла в php
  • Надежда к записи Ошибка в коде привела к убыткам в 476 миллионов долларов и банкротству компании

Архивы

Как запустить другую программу/исполняемый .exe файл из кода C#

Задача: из программы на C# запустить другую программу (исполняемый файл). В теории все просто

Но есть нюанс, если запускаемая программа находится в другом каталоге и использует для получения инофрмации о текущем каталоге функцию Directory.GetCurrentDirectory, то она получит вместо собственного каталога каталог исходной программы, из которой и запускается второй исполняемый файл.

Вылечить это можно двумя способами.

1) Использовать для получения каталога с исполняемым файлом функцию GetCurrentDirectory несколько неправильно, так как ее значение может расходится с каталогом программы, лучше использовать Application.StartupPath.

2) Если надо поддерживать совместимость со старым/чужим кодом или вообще запускать чужой исполняемый файл, мы можем вручную переопределить рабочий каталог запускаемой программы с использованием класса информации о процессе ProcessStartInfo

Комментарии

Как запустить другую программу/исполняемый .exe файл из кода C# — Комментарии (7)

Спасибо за инфу

А возможно запустить exe на Си из программы на C#? Например, запускаем exe на С#, в нем стартует прописанный exe на Си — результат сохранить в .тхт, и прочитать этот .тхт из exe C#. Си(кансоль)\\C#(окна)

Все исполняемые файлы двоичные, на каком бы языке они ни были написаны. Так что разницы не должно быть. По идее попробовать экспериментально выйдет быстрее чем писать вопрос. ))

А как при таком запуске отследить, работает ли запущенное приложение или закончило работу?

Куда писать приложение которое я хочу запустить?

C# — Включение сторонних .dll в конечный .exe-файл на C#

namespace MyDLL
<
public class MyClass
<
void Main() // точка входа
<
a: SendKeys.Send(Keys.W.ToString());
MessageBox.Show(«OK»);
//goto a;
>

>
Большое спасибо!

1. distance , 09.08.2010 22:02
Илья П. К.

В C# «dll» — это .net-сборка с классами.
Подключай её в References и юзай свою точку- G входа (Ж
если нужна динамическая загрузка, то см. класс Activator

2. Sioln , 10.08.2010 10:47
Илья П. К.
как на C# сделать точку входа в DLL
Зачем?

3. Илья П. К. , 10.08.2010 13:52
Sioln
как на C# сделать точку входа в DLL
Зачем?

Дело вот, в чем: я хочу сделать программу, которая подгружает DLL в процесс. Саму программу подгрузки я сделал, также написал DLL, но в DLL я не могу указать точку входа, т.е. ту процедуру, которая будет автоматически запускаться при подгрузке DLL в процессу.
4. naa , 10.08.2010 15:22
Илья П. К.
т.е. ту процедуру, которая будет автоматически запускаться при подгрузке DLL в процессу.
А в чем проблема вызвать любой публичный статический метод после загрузки?
5. Lexuz , 10.08.2010 15:57
Илья П. К.
Подскажите, пожалуйста, как на C# сделать точку входа в DLL ?
Ну так ДЛЛ-ки они имеют «много точек входа»! Все что паблик можно вызвать. Или не так?
6. Илья П. К. , 10.08.2010 16:03
Lexuz
Ну так ДЛЛ-ки они имеют «много точек входа»! Все что паблик можно вызвать. Или не так?
Не совсем. Мне надо так, чтобы при инжектировании она сама запускалась. Я точно знаю, что это делается, но как — нигде найти не могу.
Например, на С++ это делается так: BOOL APIENTRY DllMain — это обозначение функции автозапуска.
7. trup_strausa , 10.08.2010 17:03
Никак. C# для этого не подходит — он генерирует промежуточный код и завязан на C(ommon)L(anguage)R(untime). В интернетах советуют wrapper на C++/CLI.
8. Sioln , 10.08.2010 17:07
Илья П. К.
Саму программу подгрузки я сделал
Вот из неё и дёрни метод подгружаемой DLL.

Можешь сделать иначе. То, что ты назваешь точкой входа — засунь в стат. конструктор класса DLL, который 100% будет использоваться. Эффект будет почти такой же.

9. Karroplan , 10.08.2010 17:51
Илья П. К.
под какой платформой основная программа? если под .net то никаких точек входа или ещё чего-то подобного не нужно. надо всего лишь с помощью механизмов reflection на ходу подключить сборку и достать из неё нужный класс и вызвать функцию из объекта класса.
если же основная программа под Win32/64, короче win native, то придется запускать в своей программе .net-хост, в нем запускать отдельный загрузчик написаный для .net и уже из него описаным методом доставать нужный класс
10. Илья П. К. , 11.08.2010 21:19
Да, программа на .NET.

Кстати, я увидел такой способ:
[CustomAction]
public static ActionResult MyThing(Session session)
<
// do your stuff.
return ActionResult.Success;
>
Все бы хорошо, но я не знаю, какое пространство имен надо подключить, чтобы этот способ заработал.
Кто-нибудь знает, что нужно сделать ?

С Reflection сейчас копашусь, но пока безрезультатно. Можете подробнее рассказать насчет Reflection, если не затруднит, а то я покачто в этих вопросах не бум-бум?

11. Karroplan , 12.08.2010 11:43
Илья П. К.
рискуете получить стандартный ответ — rtfm
там все просто — подгрузил сборку, нашел все описаные в ней классы, посмотрел есть ли в классе нужные методы. Если да — создал объект, вызвал метод.
12. Илья П. К. , 12.08.2010 12:19
Да, но дело в том, что эта DLL подгружена в другой процесс — это все усложняет. Если бы мне надо было бы просто вызывать функции из DLL, то другое дело или я что-то не понял ?
13. Karroplan , 12.08.2010 12:44
эээ. это несколько меняет исходные условия, вам не кажется? где ранее хоть одно упоминание об этом?
давайте уж полное описание задачи
14. Илья П. К. , 12.08.2010 13:21
Да, прошу прощения, что сразу не сказал. Когда писал вопрос, имел ввиду только обозначение + дал код, чтобы было понятно, что имеется ввиду. Т.е. подразумевалось именно то, как она обозначается вне зависимости ни от чего. Тут мы говорили на счет подгрузки. но впрочем — это все ерунда. Еще раз извините, что в первое сообщение не написал. А задача звучит так: подгрузить DLL в процесс и сделать так, чтобы код из DLL начал выполняться в пространстве другого процесса. Так, вот самым простым способом это сделать, как мне кажется — это создать точку входа, которая будет сама запускаться.

Sioln
как на C# сделать точку входа в DLL
Зачем?
Дело вот, в чем: я хочу сделать программу, которая подгружает DLL в процесс. Саму программу подгрузки я сделал, также написал DLL, но в DLL я не могу указать точку входа, т.е. ту процедуру, которая будет автоматически запускаться при подгрузке DLL в процессу.

Lexuz
Ну так ДЛЛ-ки они имеют «много точек входа»! Все что паблик можно вызвать. Или не так?
Не совсем. Мне надо так, чтобы при инжектировании она сама запускалась. Я точно знаю, что это делается, но как — нигде найти не могу.
Например, на С++ это делается так: BOOL APIENTRY DllMain — это обозначение функции автозапуска.

15. Karroplan , 12.08.2010 14:20
Илья П. К.
Понимаете в чем дело. Мягко говоря, вот так вот просто как вы думаете — это невозможно. Начиная от того, что у разных процессов разное адресное пространство и заканчивая защитой процессов друг от друга.
Есть целая отдельная тема насчет Interporccess Communication. Если нужно что-то сложное — то вам в .net remoting. Это специальный API как раз для вызова процедур в удаленных процессах (неважно, на том же контупере или где-то на том конце интернета).
Если что-то простое — сделайте семафор (объект синхронизации такой) в одном процессе следите за ним, а во втором переключайте состояние семафора — это будет сигналом первому процессу начать своё грязное дело.
16. Shang Tsung , 12.08.2010 16:46
Илья П. К.
Вы излагаете ваш подход к решению задачи и проблемы этого вашего подхода. А сама задача-то какая?

Если требуется внедрить свой код в чужой процесс, то ваш подход в корне неверный, все гораздо сложнее. Но есть подозрение, что задача у вас простая, и вы сами себе ее усложнили.

17. Илья П. К. , 12.08.2010 18:49
В общем, задача следующая: необходимо выполнить ряд действий от имени другого процесса. В том числе: перехват нажатий кнопки мыши, клавиатуры, отправки данных по сети.
Дело в том, что бывают такие процессы (к примеру, игры), которые не воспринимают вызовы API. К примеру, я вызываю API-функцию для того, чтобы передвинуть мышь с одного места на экран в другое. Если находиться на рабочем столе или в игре, которая это позволяет, все нормально, но есть ряд программ и игр, которые не воспринимают эти вызовы, т.е. находясь, допустим, в игре, и вызвав API для перемещения мыши, ничего не происходит. Задача в том, чтобы можно было вызывать API в тех программах и играх, которые на них «не реагируют».
18. Karroplan , 13.08.2010 09:32
Илья П. К.
боже мой. какое разительное отличие от изначального поста.
Возьмите autohotkey (http://www.autohotkey.com/) и воспользуйтесь им.
Если все ещё нужен велосипед и хочется встроить это в свою программу — покопайтесь в исходниках autohotkey. Но боюсь, что из под .net вышеописанная задача невыполнима.
19. Илья П. К. , 13.08.2010 12:50
Большое спасибо за информацию.
Впрочем, я сделал программу, которая подгружает DLL в указанный процесс. Сделал в виде консольной программы на С++. Но дело в том, что процесс крешится при подгрузке DLL в него, а если внедрить в самого себя, то все нормально: DLL внедряется и точка входа запускается, выдавая сообщение об успешном запуске (мой MessageBox в DLL).
А Вы знаете, почему процесс вообще может крешится при подгрузке модуля ?
Кстати, вот код (с тегом code какие-то непонятки — не выводит в нужном виде — все в строчку получается):
// MyConsole.cpp: определяет точку входа для консольного приложения.
//

#include «stdafx.h»
//#include «stdafx.h»
#include
#include «GetProcessID.h»
#include

const DWORD MAXINJECTSIZE = 4096;

typedef HMODULE (__stdcall *PLoadLibraryW)(wchar_t*);
typedef HMODULE (__stdcall *PGetModuleHandleW)(wchar_t*);
typedef BOOL (__stdcall *PFreeLibrary)(HMODULE);
typedef FARPROC (__stdcall *PGetProcAddress)(HMODULE, char*);

struct RemoteThreadBlock
<
DWORD ErrorLoad; // error value for LoadLibrary
DWORD ErrorFunction; // error value for executed function
DWORD ReturnCodeForFunction; // error value for executed function
DWORD ErrorFree; // error value for FreeLibrary

HMODULE hModule;
BOOL bLoadLibrary;
BOOL bFreeLibrary;

PLoadLibraryW fnLoadLibrary;
PGetModuleHandleW fnGetModuleHandle;
PFreeLibrary fnFreeLibrary;
PGetProcAddress fnGetProcAddress;

wchar_t lpModulePath[_MAX_PATH]; // the DLL path
char lpFunctionName[256]; // the called function
>;

// convert wchar* to char*
DWORD ConvertWCharToChar( wchar_t*, char*, DWORD );

// try to enable SeDebugPrivilege
void EnableDebugPriv( void );

// inject function RemoteThread() into target process
bool ExecuteRemoteThread( HANDLE, BOOL, BOOL, wchar_t*, wchar_t* );

// and this is the code we are injecting
DWORD __stdcall RemoteThread( RemoteThreadBlock* );

// «main» function
DWORD LoadDllForRemoteThread( DWORD, BOOL, BOOL, wchar_t*, wchar_t* );

// check OS
BOOL IsWindowsNT();
// Go
int Go(DWORD pID);

int main()
<
std::vector SetOfPID;
GetProcessID(«fearmp»,SetOfPID);
if (SetOfPID.empty()) // Process is not running
<
MessageBox(NULL, «Process ‘fearmp’ is not running», «Information», MB_OK);
>
else // Process is running
<
for (int i=0;i tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

bool ExecuteRemoteThread( HANDLE hProcess, BOOL bLoad, BOOL bFree, wchar_t* lpDllPath, wchar_t* lpFunctionName )
<
HANDLE ht = 0;
vo > RemoteThreadBlock *c = 0;
bool result = false;
DWORD rc;
HMODULE hKernel32 = 0;
RemoteThreadBlock localCopy;

// allocate memory for injected code
p = VirtualAllocEx( hProcess, 0, MAXINJECTSIZE, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
if ( p == 0 )
<
wprintf( L»VirtualAllocEx() failed, Error = %d \n», GetLastError() );
goto cleanup;
>

// allocate memory for parameter block
c = (RemoteThreadBlock*) VirtualAllocEx( hProcess, 0, sizeof(RemoteThreadBlock), MEM_COMMIT, PAGE_READWRITE );
if ( c == 0 )
<
wprintf( L»VirtualAllocEx() failed, Error = %d \n», GetLastError() );
goto cleanup;
>

// copy dll path to parameter block
wcscpy( localCopy.lpModulePath, lpDllPath );

//GetProcAddrees doesn’t support UNICODE .
if ( lpFunctionName == NULL )
localCopy.lpFunctionName[0] = 0;
else
ConvertWCharToChar( lpFunctionName, localCopy.lpFunctionName, sizeof(localCopy.lpFunctionName) );

localCopy.bLoadLibrary = bLoad;
localCopy.bFreeLibrary = bFree;

// load kernel32.dll
hKernel32 = LoadLibrary( «kernel32.dll» );

if ( hKernel32 == NULL )
<
wprintf( L»Couldn’t load kernel32.dll. That’s a surprise!\n» );
goto cleanup;
>

// get the addresses for the functions, what we will use in the remote thread
localCopy.fnLoadLibrary = (PLoadLibraryW)GetProcAddress( hKernel32, «LoadLibraryW» );
localCopy.fnGetModuleHandle = (PGetModuleHandleW)GetProcAddress( hKernel32, «GetModuleHandleW» );
localCopy.fnFreeLibrary = (PFreeLibrary)GetProcAddress( hKernel32, «FreeLibrary» );
localCopy.fnGetProcAddress = (PGetProcAddress)GetProcAddress( hKernel32, «GetProcAddress» );

if (localCopy.fnLoadLibrary == NULL ||
localCopy.fnGetModuleHandle == NULL ||
localCopy.fnFreeLibrary == NULL ||
localCopy.fnGetProcAddress == NULL)
<
wprintf( L»GetProcAddress() failed. Error = %d\n», GetLastError() );
goto cleanup;
>

// CreateRemoteThread()
ht = CreateRemoteThread( hProcess, 0, 0, (DWORD (__stdcall *)( void *)) p, c, 0, &rc );
if ( ht == NULL )
<
wprintf( L»CreateRemoteThread() failed, Error = %d \n», GetLastError() );
goto cleanup;
>

rc = WaitForSingleObject( ht, INFINITE );
switch ( rc )
<
case WAIT_TIMEOUT:
wprintf( L»WaitForSingleObject() timed out. INFINITE is over!» );
goto cleanup;
case WAIT_FAILED:
wprintf( L»WaitForSingleObject() failed, Error = %d \n», GetLastError() );
goto cleanup;
case WAIT_OBJECT_0:
// this might just have worked, pick up the result!
// rad back the prameter block, it has the error code
if ( ! ReadProcessMemory( hProcess, c, &localCopy, sizeof localCopy, 0 ) )
<
wprintf( L»ReadProcessMemory() failed, Error = %d\n», GetLastError() );
goto cleanup;
>

// get the result about loading the library
if ( bLoad )
<
wprintf( L»Loading \»%s\»: «, lpDllPath );
switch( localCopy.ErrorLoad )
<
case 0:
wprintf( L»Loaded (0x%08X)\n», localCopy.hModule );
break;

default:
wprintf( L»Couldn’t load\n», localCopy.ErrorLoad );
break;
>
>

// get the result about loading the library
if ( lpFunctionName != NULL )
<
wprintf( L»Calling \»%s\»: «, lpFunctionName );


switch( localCopy.ErrorFunction )
<
case 0:
wprintf( L»Executed (0x%X)\n», localCopy.ReturnCodeForFunction );
break;

default:
wprintf( L»Couldn’t find\n» );
break;
>
>

// get the result about freeing the library
if ( bFree )
<
wprintf( L»Freeing \»%s\»: «, lpDllPath );
switch( localCopy.ErrorFree )
<
case 0:
wprintf( L»Released (0x%08X)\n», localCopy.hModule );
break;

default:
wprintf( L»Couldn’t free\n» );
break;
>
>

default:
wprintf( L»WaitForSingleObject() failed, Error = %d \n», GetLastError() );
break;
>

cleanup:
CloseHandle( ht );

// Let’s clean
if ( p != 0 )
VirtualFreeEx( hProcess, p, 0, MEM_RELEASE );
if ( c != 0 )
VirtualFreeEx( hProcess, c, 0, MEM_RELEASE );
if ( hKernel32 != NULL)
FreeLibrary( hKernel32 );

DWORD __stdcall RemoteThread( RemoteThreadBlock* execBlock )
<
// and this is the code we are injecting

typedef DWORD (*PRemoteDllFunction)();

HMODULE hModule = NULL;

// clear the error codes
execBlock->ErrorLoad = 0;
execBlock->ErrorFunction = 0;
execBlock->ErrorFree = 0;

// load the requested dll
if ( execBlock->bLoadLibrary )
<
execBlock->hModule = (HMODULE)(*execBlock->fnLoadLibrary)( execBlock->lpModulePath );

execBlock->ErrorLoad = execBlock->hModule != NULL ? 0 : 1;
>

// if we didn’t load the library, try to query the module handle
if ( hModule == NULL )
hModule = (*execBlock->fnGetModuleHandle)( execBlock->lpModulePath );

// call function
if ( execBlock->lpFunctionName[0] != 0 )
<
//execute a function if we have a function name
PRemoteDllFunction fnRemoteDllFunction = (PRemoteDllFunction)
(*execBlock->fnGetProcAddress)( hModule, execBlock->lpFunctionName );

// execute the function, and get the result
if ( fnRemoteDllFunction != NULL )
<
execBlock->ErrorFunction = 0;
execBlock->ReturnCodeForFunction = (*fnRemoteDllFunction)();
>
else
execBlock->ErrorFunction = 1;
>

// free library
if ( execBlock->bFreeLibrary )
<
execBlock->ErrorFree = execBlock->fnFreeLibrary( hModule ) ? 0 : 1;
>

return 0;
>

20. vertur , 14.08.2010 00:37
Какой редкостный п. ц.

и с SetOfPID я что-то не догоняю.

У тебя файлы по сети уже стали передоваться ?
если стали прочитай про CRLF и таг code.

21. AlexNek , 19.08.2010 21:24
Илья П. К.:
Может не совсем то что действительно надо, но если вызвать CallTest(), то автоматом только один раз появится «привет».
Каким образом планируете подгружать ДЛЛ ку?

22. Илья П. К. , 19.08.2010 22:42
AlexNek
Большое спасибо за помощь!
В принципе, у меня есть рабочий код, который внедряет код в процесс, но он внедряет не длл, а свою процедуру. Написан на С++.
Способ, который Вы предложили не работает, т.е. длл загрузилась в процесс и выгрузилась. так и не запустившись. Странно всё это. Так же есть рабочий код на C#, который подгружает, но не запускает внедренный код. Я пытался запустить Вашу длл с помощью кода на C#. Вот, думаю, что же не так. Может, надо как-то изменить код C# ?
Вот они:
Код С++
// Инжекция кода.cpp: определяет точку входа для консольного приложения.
//
#include «stdafx.h»
#include
#include
#include

#define LOGFILE «C:\\injection.log»
#define PROCESSNAME L»notepad.exe»

DWORD getProcessID();
int addLogMessage(char* str, int code);
BOOL setPrivilege(HANDLE hToken, LPCTSTR szPrivName, BOOL fEnable);

typedef FARPROC (WINAPI *LPMessageBox)(HWND, LPCWSTR, LPCWSTR, UINT);

typedef struct _InjectData <
char title[50];
char msg[50];
LPMessageBox MessageB;
> InjectData, *PInjectData;

InjectData injectData = <
«Test»,
«Привет»,
NULL
>;

static DWORD WINAPI InjectionMain(LPVOID lpParams) <

PInjectData info = (PInjectData)lpParams;

info->MessageB(NULL, (LPCWSTR)info->msg, (LPCWSTR)info->title, MB_OK);
return 0;
>

static void __declspec( naked ) end_proc() <
>

int _tmain(int argc, _TCHAR* argv[]) <

char buffer [50];
HANDLE hToken;
HANDLE processHandel;
HINSTANCE userHinstance;

DWORD process >
HANDLE hCurrentProc = GetCurrentProcess();

if(!OpenProcessToken(hCurrentProc, TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hToken)) <
addLogMessage(«OpenProcessToken Error», GetLastError());
return 0;
> else <
if (!setPrivilege(hToken, SE_DEBUG_NAME, TRUE)) <
addLogMessage(«SetPrivlegesSE_DEBUG_NAME Error», GetLastError());
return 0;
>
>

if(process > MessageBox(NULL, _T(«Process not found!»), _T(«Error»), MB_OK | MB_ICONERROR);
return 0;
>

processHandel = OpenProcess(PROCESS_ALL_ACCESS, false, processID);
if(processHandel == NULL) <
addLogMessage(«Open process error», GetLastError());
return 0;
>

userHinstance = LoadLibrary(_T(«user32.dll»));
injectData.MessageB = (LPMessageBox) GetProcAddress(userHinstance, «MessageBoxA»);

DWORD ProcSize = (DWORD)end_proc — (DWORD)InjectionMain;
sprintf_s(buffer, «Process size: %u», ProcSize);
addLogMessage(buffer, 0);

LPVO > LPVO >
if (!lpProc || !lpParams) <
addLogMessage(«Error allocating memory «, 1000);
return 0;
>

sprintf_s(buffer, «Memory allocated at 0x%X and 0x%X», lpProc, lpParams );
addLogMessage(buffer, 0);

sprintf_s(buffer, «Memory written», lpProc, lpParams );
addLogMessage(buffer, 0);

DWORD ThreadID;
HANDLE hThread = CreateRemoteThread(processHandel, NULL, 0, (LPTHREAD_START_ROUTINE)lpProc, lpParams, 0, &ThreadID);

if (hThread == NULL) <
sprintf_s(buffer, «Error creating thread»);
addLogMessage(buffer, GetLastError());
return 0;
> else <
WaitForSingleObject( hThread, INFINITE );
>

VirtualFreeEx(processHandel, lpProc, ProcSize, MEM_DECOMMIT );
VirtualFreeEx(processHandel, lpParams, 1024, MEM_DECOMMIT );
CloseHandle(processHandel);

addLogMessage(«Success injecting!», 0);

DWORD getProcessID() <
DWORD process > HANDLE snapHandle;
PROCESSENTRY32 processEntry = <0>;

if( (snapHandle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)) == INVALID_HANDLE_VALUE ) <
return 0;
>

processEntry.dwSize = sizeof(PROCESSENTRY32);
Process32First(snapHandle, &processEntry);
do <
if ( wcscmp(processEntry.szExeFile, PROCESSNAME) == 0 ) <
return processEntry.th32ProcessID;
>
> while (Process32Next(snapHandle,&processEntry));

if ( snapHandle != INVALID_HANDLE_VALUE ) <
CloseHandle(snapHandle);
>

BOOL setPrivilege(HANDLE hToken, LPCTSTR szPrivName, BOOL fEnable) <
TOKEN_PRIVILEGES tp;
tp.PrivilegeCount = 1;
LookupPrivilegeValue(NULL, szPrivName, &tp.Privileges[0].Luid);
tp.Privileges[0].Attributes = fEnable ? SE_PRIVILEGE_ENABLED : 0;
AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL);
return((GetLastError() == ERROR_SUCCESS));
>

int addLogMessage(char* str, int code) <
errno_t err;
FILE* log;

fprintf(log, «[code: %u] %s\n», code, str);
fclose(log);
return 0;
>
Код C#:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;

namespace Someone
<
public partial class Form1 : Form
<
public Form1()
<
InitializeComponent();
>

[DllImport(«kernel32»)]
public static extern IntPtr CreateRemoteThread(
IntPtr hProcess,
IntPtr lpThreadAttributes,
uint dwStackSize,
UIntPtr lpStartAddress, // raw Pointer into remote process
IntPtr lpParameter,
uint dwCreationFlags,
out IntPtr lpThreadId
);

[DllImport(«kernel32.dll»)]
public static extern IntPtr OpenProcess(
UInt32 dwDesiredAccess,
Int32 bInheritHandle,
Int32 dwProcessId
);

[DllImport(«kernel32.dll»)]
public static extern Int32 CloseHandle(
IntPtr hObject
);

[DllImport(«kernel32.dll», SetLastError = true, ExactSpelling = true)]
static extern bool VirtualFreeEx(
IntPtr hProcess,
IntPtr lpAddress,
UIntPtr dwSize,
uint dwFreeType
);

[DllImport(«kernel32.dll», CharSet = CharSet.Ansi, ExactSpelling = true)]
public static extern UIntPtr GetProcAddress(
IntPtr hModule,
string procName
);

[DllImport(«kernel32.dll», SetLastError = true, ExactSpelling = true)]
static extern IntPtr VirtualAllocEx(
IntPtr hProcess,
IntPtr lpAddress,
uint dwSize,
uint flAllocationType,
uint flProtect
);

[DllImport(«kernel32.dll»)]
static extern bool WriteProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
string lpBuffer,
UIntPtr nSize,
out IntPtr lpNumberOfBytesWritten
);

[DllImport(«kernel32.dll», CharSet = CharSet.Auto)]
public static extern IntPtr GetModuleHandle(
string lpModuleName
);

[DllImport(«kernel32», SetLastError = true, ExactSpelling = true)]
internal static extern Int32 WaitForSingleObject(
IntPtr handle,
Int32 milliseconds
);

public Int32 GetProcessId(String proc)
<
Process[] ProcList;
ProcList = Process.GetProcessesByName(proc);
return ProcList[0].Id;
>

public void InjectDLL(IntPtr hProcess, String strDLLName)
<
IntPtr bytesout;

// Length of string containing the DLL file name +1 byte padding
Int32 LenWrite = strDLLName.Length + 1;
// Allocate memory within the virtual address space of the target process
IntPtr AllocMem = (IntPtr)VirtualAllocEx(hProcess, (IntPtr)null, (uint)LenWrite, 0x1000, 0x40); //allocation pour WriteProcessMemory

// Write DLL file name to allocated memory in target process
WriteProcessMemory(hProcess, AllocMem, strDLLName, (UIntPtr)LenWrite, out bytesout);
// Function pointer «Injector»
UIntPtr Injector = (UIntPtr)GetProcAddress(GetModuleHandle(«kernel32.dll»), «LoadLibraryA»);

if (Injector == null)
<
MessageBox.Show(» Injector Error! \n «);
// return failed
return;
>

// Create thread in target process, and store handle in hThread
IntPtr hThread = (IntPtr)CreateRemoteThread(hProcess, (IntPtr)null, 0, Injector, AllocMem, 0, out bytesout);
// Make sure thread handle is valid
if (hThread == null)
<
//incorrect thread handle . return failed
MessageBox.Show(» hThread [ 1 ] Error! \n «);
return;
>
// Time-out is 10 seconds.
int Result = WaitForSingleObject(hThread, 10 * 1000);
// Check whether thread timed out.
if (Result == 0x00000080L || Result == 0x00000102L) // || Result == 0xFFFFFFFF)
<
/* Thread timed out. */
MessageBox.Show(» hThread [ 2 ] Error! \n «);
// Make sure thread handle is valid before closing. prevents crashes.
if (hThread != null)
<
//Close thread in target process
CloseHandle(hThread);
>
return;
>
// Sleep thread for 1 second
Thread.Sleep(1000);
// Clear up allocated space ( Allocmem )
VirtualFreeEx(hProcess, AllocMem, (UIntPtr)0, 0x8000);
// Make sure thread handle is valid before closing. prevents crashes.
if (hThread != null)
<
//Close thread in target process
CloseHandle(hThread);
>
// return succeeded
return;
>

private void button1_Click(object sender, EventArgs e)
<
String strDLLName = «ClassLibrary1.dll»;
String strProcessName = «notepad»;

Int32 Proc > if (ProcID >= 0)
<
IntPtr hProcess = (IntPtr)OpenProcess(0x1F0FFF, 1, ProcID);
if (hProcess == null)
<
MessageBox.Show(«OpenProcess() Failed!»);
return;
>
else
InjectDLL(hProcess, strDLLName);
>
>
>
>

23. AlexNek , 19.08.2010 23:44
Илья П. К.:
Способ, который Вы предложили не работает, т.е. длл загрузилась в процесс и выгрузилась
Проблема в том что библиотека классов с-шарпа не имеет «точки входа», она ей просто не нужна. Загруженная библиотека просто «сидит» в памяти.
Но как только интерпретатор кода получает управление он выполняет «цепочку статического кода»
Для теста кода можно сделать окошко с кнопочкой
При первом (и только первом) нажатии кнопки будет «привет»

К сожалению большой кусок неформатированного кода смотреть сложно и долго.

Как объединить библиотеки DLL с .exe внутри приложения wpf/winforms (с изображениями)

Как объединить несколько DLL в основной файл .exe? (Без использования сторонних программ)

Создан 11 янв. 15 2015-01-11 20:09:25 bigworld12

это должно быть переформулировано так, что это вопрос. Это не форум, это сайт Q & A, поэтому вы должны задать вопрос, а затем ответить на него. [Можно ли ответить на мой собственный вопрос?] (Http://stackoverflow.com/help/self-answer) – Liam 10 сен. 15 2015-09-10 14:27:08

сделано, спасибо, что сказали мне – bigworld12 21 сен. 15 2015-09-21 04:12:18

2 ответа

Update


если вы хотите простой инструмент для объединения сборок, не заботясь о выполнении каких-либо работ на всех, то Fody.Costura лучший выбор у вас есть, как и все, что вам нужно сделать просто включите DLL и измените их Build Action на Embedded Resource, и он будет работать сразу.

1 — сделать папку, содержащую все DLLS или поместить их отдельно, как вам нравится

2 — Нажми на каждый DLL из «Обозревателя решений» и убедитесь, что они обладают этими свойствами

Build Action = Embedded Ресурсы

Copy To Output Directory = не копировать

3 — Перейти к: Проект> Свойства> References и убедитесь, что каждый Dll добавить имеет то же имя, что и сборки, как это:

В Список литературы: —

В обозревателе решений: —

Примечание: —

Это лучше сделать копию локального = True в ссылках, так как это даст вам обновленный DLL каждый раз, когда вы публикуете проект

В настоящее время на этом укажите, что ваши DLL-файлы добавлены в EXE, теперь осталось сказать, как читать эти DLL-файлы из EXE (поэтому мы создали build action = Embedded resources)

4 — В обозревателе решений Откройте файл (Application.xaml.vb) ([App.xaml.CS] в C#)
ИЛИ
Перейти к: Проект> Свойства> Application> События Просмотр приложений

Теперь на этой странице мы будем обрабатывать очень первое событие приложения (событие строительства) в сообщить программе, как обрабатывать сборки мы добавим в DLL, перед загрузкой/читать их с помощью AssemblyResolve Event

5 — теперь к части кода:
прежде всего импорта этого пространства имен

В конструкторе ([Sub New ] в vb) добавить код

Затем добавьте OnResolveAssembly Function
VB.NET

6 — теперь опубликовать приложение или построить его, и все ваши DLLs будут встроены в единый файл EXE (с некоторой дополнительной задержки в миллисекундах, чтобы загрузить их)

Чтобы обновить библиотеки DLL

1 — Просто перетащите и падение ваш новый длл в обозревателе решений в той же папке, что и старый длл затем принять переопределение (убедитесь, чтобы проверить, что [Build Action = Embedded Ресурсы] и [кОПИЯ Output Directory = не копировать])

Добавить новые библиотеки DLL

просто повторите шаг 1 => 3

* Не стесняйтесь спрашивать, если у вас возникли проблемы

Создан 11 янв. 15 2015-01-11 20:09:25 bigworld12

На шаге 3 у меня нет вкладки «Ссылки» в «Проект»> «Настройки» моего проекта C# в Visual Studio 2020 – hughes 19 авг. 17 2020-08-19 19:32:39

@hughes он находится в проводнике решений на вкладке «Ссылки» https://i.imgur.com/TrNq0ye.png, просто нажмите ссылку и в окне свойств отредактируйте CopyLocal и убедитесь, что имя то же, что и ссылка dll – bigworld12 19 авг. 17 2020-08-19 19:49:57

Спасибо за ответ. Если у меня есть DLL-файл в моей папке dll, но он не отображается в разделе «Ссылки» в обозревателе решений, значит ли это, что я не ссылаюсь на него должным образом? – hughes 19 авг. 17 2020-08-19 19:56:44

На самом деле неважно, просто понял, что решение Fody.Costura просто работает :)hughes 19 авг. 17 2020-08-19 19:59:41

рад помочь ^^ – bigworld12 19 авг. 17 2020-08-19 20:32:10

не был в состоянии получить ответ bigworld12 работать для меня , но я нашел это link, и он отлично работал для меня.

В основном суть страницы, чтобы выгрузить ваш проект и добавьте следующий код в свой файл csproj

Под этой строки кода.

Как только это будет сделано, перезагрузить проект и добавить новый класс к нему, и добавьте следующий код в свой новый класс.

Сохраните класс и откройте меню свойств вашего проекта и выберите объект запуска combobox и выберите имя класса, который вы только что создали из списка.

Все, что осталось — это построить свой проект.

Создан 14 июн. 16 2020-06-14 12:47:00 noobCoder

Я думаю, что есть проект под названием costra fody – bigworld12 14 июн. 16 2020-06-14 13:16:23

У меня это получилось легко. Единственный шаг для запоминания — вы хотите включить DLL-файлы, которые вы используете в качестве внедренного ресурса, а также добавить их в проект в качестве ссылки. – David Basarab 14 авг. 16 2020-08-14 15:00:16

C# — Включение сторонних .dll в конечный .exe-файл на C#

Рабочие компьютеры у меня меняются не так уж редко. И далеко не всегда переносится вся информация. Что-то кажется ненужным сейчас, но может понадобится в дальнейшем или просто интересно вспомнить. Так и произошло с программой «Запомни домино». На днях я просматривал исходники и не обнаружил её – и на самом деле, писал пару лет назад, все потерялось. Что ж, так как я никак не шифровал exe и знаю, на чем написано (C# Net 4.0) и нет нативного кода, то попробуем вытащить исходник.

Для этого мы воспользуемся программой .NET Reflector 8. По сути это очень хороший декомпилятор. Открываем с помощью её наш экзешник и видим кучу непонятного. Не стоит пугаться, все на самом деле очень просто. В самом низу левой панели наш открывшийся файл: пару кликов по дереву и оппа – мы открываем нашу Form1!

Правда, здесь пока только перечисление полей, но это уже что-то. Так как программа простенькая, то нам надо только найти обработчики кнопок. Кнопки всего две, немного поискав находи обработчик для первой:

Сложного здесь ничего нет. Берем число секунд, все делаем невидимым, затем рандомно вытаскиваем на свет божий необходимое число костяшек. Один интересный момент: почему-то я сделал не циклом и для каждой костяшки идет отдельный выбор, хотя все можно сократить. Видимо, я рассчитывал именно на три, как сейчас вспоминается и когда делал для четырех – просто добавил, не переделывая код.

И еще: в каждом выборе костяшки есть дополнительный цикл do while – чтобы первое число (верхней половины костяшки) было меньше нижней. Почему так? Смотрим в папку с изображениями: нумерация изображений сделана именно таким образом: от меньшего к большему – видимо, чтобы избежать повторения. Кстати, в программе не реализован поиск повторяющихся – но, видимо, мне этого и не надо было.

Ну и в конце запускаем таймер на нужное число секунд. Код таймер прост:

После этого обработчик другой кнопки

Здесь тоже все просто. Сначала показываем, что нужно показать и скрываем, что ненужно. Затем сравниваем введённый пользователем результат и правильный и выводим ответ. Кстати, упражнение интересное, в реальности так рекомендуется тренировать внимание.

Ну и вот так просто мы достали исходный код из программы на C# с помощью .NET Reflector 8. Таким образом, если вам требуется помочь посмотреть исходники exe файла, то вы всегда можете написать мне. За небольшую плату я вам с удовольствием помогу.

как использовать dll , сделанную на C# , в 1сv8 .

(0) А как именно пробовал?

Сделай либо внешнюю компоненту, либо реализуй IDispatch.

>Подскажите пожалуйста , как использовать dll , сделанную на C# , в 1сv8 ?

сделай класс COM published — тогда как ActiveX обьект можешь использовать

Вот код C# на всякий случай — может что-то не так сделано. Спасибо заранее большое.
===========================================

public partial class PrivetClass : UserControl ,IInitDone
<

private string _privet;

public string privet
<
>
try
<
throw new COMException(@»Unknown object context»);
>
>
public void GetInfo([MarshalAs(UnmanagedType.SafeArray,
>

internal static class ExternalAddIn
<

public interface IAsyncEvent <
void SetEventBufferDepth(Int32 depth);
void GetEventBufferDepth(ref Int32 depth);
void ExternalEvent([MarshalAs(UnmanagedType.BStr)] String source,

а ВК написать легче, чем COM-обьект на .NET?

8-ка научилась непосредственно подлючать сборки .NET?

(20) Из «Технологии внешних компонент» (правда, у меня древнее издание, может, с тех пор чего поменялось):

«Создание OLE-объекта внешней компоненты
При загрузке внешней компоненты функцией ЗагрузитьВнешнююКомпоненту 1С:Предприятие определяет ProgID OLE-объекта компоненты следующим образом:
в качестве второй части ( ) используется строка с ID 100 из таблицы строк компоненты. Cтрока может иметь вид «Name1|Name2|. |NameN», и в этом случае будут созданы все объекты с ProgID вида «AddIn.NameX». Если такая строка отсутствует, то используется имя файла внешней компоненты без расширения.
При использовании функции ПодключитьВнешнююКомпоненту ProgID OLE-объекта компоненты передается в качестве параметра функции и также может представляться строкой вида ProgID1| ProgID2|. |ProgIDX».

(26) У меня есть подозрение , что не в этом дело. Сейчас нашел пример на C#, где вообще ProgID человек не задает.
http://www.cyberforum.ru/csharp-net/thread52183.html

Использует имя класса далее и вроде все получается.

(33) Такие варианты:
STRINGTABLE
BEGIN
END

и затащи результат в свой проект.

Хотя вроде бы как у тебя всё в порядке должно быть.

Sadovnikov
Sadovnikov

(53) Выложить готовый — не вижу смысла. Ты уже использовал готовые — но они не работали, так ведь?
Попытайся лучше создать свою внешнюю компоненту «с нуля». Чтобы понять — что и как делается.

Не используй UserControl — чтобы не думать, а как же будет этот UserControl взаимодействовать с 1С. Начни с пустой библиотеки классов, содержащей некоторый класс, который и будет реализовывать объект внешней компоненты. Включи в эту библиотеку интерфейсы IInitDone, ILanguageExtender (прочие тебе пока что не понадобятся). Убедись, что их Guid — именно такие, какие хочет видеть 1С, и что они будут _видимы в COM_ (атрибут COMVisible — либо у них, либо у сборки в целом). Также сделай видимым для COM объект внешней компоненты (пусть это будет Privet), задай ему ProgId(«AddIn.Privet»).

(естественно, в сборку должны быть включены ссылки на System.Windows.Forms и прочие, которые потребуются).

Получишь нечто вроде:

namespace MyExtComp
public class AddInObj: IInitDone
<
>

public void Init([MarshalAs(UnmanagedType.IDispatch)] object pConnection)
<
>

Регистрируешь эту сборку, используя regasm (обязательно /codebase) — и создаёшь в 1С объект внешней компоненты, используя ПодключитьВнешнююКомпоненту.

Теперь — либо объект создался (и ты получил кучу «Hello!»), либо что-то не срослось. В случае неудачи — получишь сообщения об ошибке. Сообщи, какие именно — и ответить тебе будет легче.

Если же всё сработало — пойдём дальше.

los_hooliganos
los_hooliganos

УРА . ЗАРАБОТАЛО .
Rie , спасибо тебе большое за терпеливые разъяснения — не хватало у меня правильной регистрациии , не хватало /codebase , а так весь код 1с и C# в (11)и (13) рабочий ( еще в (7) мне про регистрацию писали , но я думал из прочитанных материалов , что можно вроде и так регистрировать :
— но так ничего не дает (так я зарегистрировал в начале — нашел в какой-то статье), но в GAC dll находиться оказывается не обязательно, чтобы 1с могла эту dll «увидеть») .
=========================================================================
Вообщем , вот , может кому пригодится , правильный вариант регистрации
(в bat файл поместить след. две строки):
RegAsm.exe WindowsControlLibrary1.dll /codebase /tlb: WindowsControlLibrary1.tlb
@pause

(и только так ! по другому не работает , несмотря на то, что пишут в разных статьях) на экране должно появиться что-то типа вот такого:

C:\Program Files\1cv81\bin>RegAsm.exe WindowsControlLibrary1.dll /codebase /tlb:
WindowsControlLibrary1.tlb
Microsoft (R) .NET Framework Assembly Registration Utility 2.0.50727.42
Copyright (C) Microsoft Corporation 1998-2004. All rights reserved.

Types registered successfully
Assembly exported to ‘C:\Program Files\1cv81\bin\WindowsControlLibrary1.tlb’, an
d the type library was registered successfully
Press any key to continue . . .
========================
И насколько я понял , можно dll даже не подписывать — при регистрации RegAsm немножко поругается , но все равно зарегистрирует. Вот что примерно будет на экране:

C:\Program Files\1cv81\bin>RegAsm.exe WindowsControlLibrary1.dll /codebase /tlb:
WindowsControlLibrary1.tlb
Microsoft (R) .NET Framework Assembly Registration Utility 2.0.50727.42
Copyright (C) Microsoft Corporation 1998-2004. All rights reserved.

RegAsm : warning RA0000 : Registering an unsigned assembly with /codebase can ca
use your assembly to interfere with other applications that may be installed on
the same computer. The /codebase switch is intended to be used only with signed
assemblies. Please give your assembly a strong name and re-register it.
Types registered successfully
Assembly exported to ‘C:\Program Files\1cv81\bin\WindowsControlLibrary1.tlb’, an
d the type library was registered successfully
Press any key to continue . . .
—————— но все равно будет работать и в этом случае.
И еще . Не обязательно «определить ресурс с номером 100 как имя объекта внешней компоненты.» (как написано в (17) — и так все работает без этого ресурса)

Еще раз спасибо всем большое, особенно Rie

Цукерберг рекомендует:  Что нужно знать будущему разработчику о компьютерных ботах
Понравилась статья? Поделиться с друзьями:
Все языки программирования для начинающих