Как добавить в свой проект (WPF), библиотеку классов?
Скачал библиотеку классов с GitHub.
Как ее добавить в мой проект WPF, чтобы я мог уже приложение сделать.
А так сама библиотека классов не запускается, пишет:
«Проект, библиотека классов которого имеет тип «Тип выходных данных», нельзя запустить напрямую.
Чтобы выполнить отладку этого проекта, добавьте проект исполняемого файла в это решение, ссылающееся на проект библиотеки. Задайте проект исполняемого файла в качестве запускаемого проект. «.
Напишите по подробнее, что нужно делать. (Я пока новичок в этом, и очень хочу разобраться с этим).
Лучшие ответы ( 3 )
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
Ответы с готовыми решениями:
Как внедрить эту библиотеку в свой проект на Qt?
Вот она: https://github.com/akalend/amqpcpp не понимаю как чего там собрать, если просто.
Как добавить библиотеку в проект?
Здравствуйте! Есть библиотека mscorlib.dll, где есть IReadOnlyList, который добавлен только с.

Как добавить библиотеку в проект?
Возможно, вопрос может показаться банальным, но как импортировать библиотеку в проект? Дело в.
Как добавить ссылку на библиотеку классов в приложении UWP
Здравствуйте. Извините за вопрос. Мне нужно создать приложение с 3х уровневой архитектурой под.
8936 / 4848 / 1886
Регистрация: 11.02.2013
Сообщений: 10,246
Сообщение от weoi 
Скачал библиотеку классов с GitHub.
В виде файла/ов *.dll?
.NET C#,ASP.NET MVC
![]()
593 / 506 / 224
Регистрация: 16.10.2010
Сообщений: 1,902

Сообщение было отмечено weoi как решение
Решение
В Visual Studio в Solution Explorer с вашим проектом, находите «References», вызываете контекстное меню, из которого выбераете «Add reference», в открывшимся окне можно указать путь к библиотеке классов
8936 / 4848 / 1886
Регистрация: 11.02.2013
Сообщений: 10,246

Сообщение было отмечено weoi как решение
Решение
Кажется, я понял. weoi, ты пытаешься запустить на выполнение проект, у которого в качестве выходного файла указана библиотека. Добавь скачанный проект в своё решение и затем добавь с свой проект ссылку на этот скачанный проект через References.
Регистрация: 28.04.2017
Сообщений: 44
Записей в блоге: 2

Сообщение было отмечено weoi как решение
Решение
Если вы скачали простой *.dll файл, то заходим в Менеджер ссылок. Для этого открываем вам проект в VS правой кнопкой мыши в обозревателе решений кликаем по «Ссылки» —>»Добавить ссылку» далее Обзор и перейдя в место хранения файла выбираем его и жмём ОК.
Если это проект, то сперва в обозревателе решений в самом верху находим «Решение» по нему правой кнопкой мыши и в открывшимся контекстном меню выбираем «Добавить» —> «Существующий проект» и выбрав проект нажимаем «Открыть».
Теперь у вас в обозревателе решения под «Решение добавится выбранный вами проект. Далее необходимо в вашем проекте, а не в только что добавленном это важно правой кнопкой мыши в обозревателе решений кликаем по «Ссылки» —>»Добавить ссылку» далее переходим во вкладку «Проекты» и ставим галочку на против добавленного вами проекта. Так мы привязываем проект как библиотеку.
Далее необходимо снова в обозревателе решения выбираем «Решение» по нему правой кнопкой мыши и в открывшимся контекстном меню выбираем «Зависимости проектов» в открывшемся окне во вкладке Зависимости под «Проекты» выбираем ваш проект, а в «Зависит от» ставим галочку на против добавленного вами раннее проекта. Переходим во вкладку «Порядок сборки» и смотрим, что бы добавленный проект был первый, а ваш второй.
Если вы всё сделали правильно, то в вашем приложении можно смело подключать через using добавленный проект и работать с ним словно это библиотека *.dll
Проект библиотека классов которого имеет тип тип выходных данных нельзя запустить напрямую
Нередко различные классы и структуры оформляются в виде отдельных библиотек, которые компилируются в файлы dll и затем могут подключаться в другие проекты. Благодаря этому мы можем определить один и тот же функционал в виде библиотеки классов и подключать в различные проекты или передавать на использование другим разработчикам.
Создадим и подключим библиотеку классов.
Возьмем имеющийся проект консольного приложения C#, например, созданный в прошлых темах. В структуре проекта нажмем правой кнопкой на название решения и далее в появившемся контекстном меню выберем Add -> New Project. (Добавить новый проект):

Далее в списке шаблонов проекта найдем пункт Class Library :

Затем дадим новому проекту какое-нибудь название, например, MyLib:

После создания этого проекта в решение будет добавлен новый проект, в моем случае с названием MyLib:

По умолчанию новый проект имеет один пустой класс Class1 в файле Class1.cs. Мы можем этот файл удалить или переименовать, как нам больше нравится.
Например, переименуем файл Class1.cs в Person.cs, а класс Class1 в Person. Определим в классе Person простейший код:
namespace MyLib < public class Person < string name; public Person(string name) < this.name = name; >public void Print() => Console.WriteLine($"Name: "); > >

Теперь скомпилируем библиотеку классов. Для этого нажмем правой кнопкой на проект библиотеки классов и в контекстном меню выберем пункт Rebuild :

После компиляции библиотеки классов в папке проекта в каталоге bin/Debug/net6.0 мы сможем найти скомпилированный файл dll (MyLib.dll). Подключим его в основной проект. Для этого в основном проекте нажмем правой кнопкой на узел Dependencies и в контекстном меню выберем пункт Add Project Reference. :

Далее нам откроется окно для добавления библиотек. В этом окне выберем пункт Solution,который позволяет увидеть все библиотеки классов из проектов текущего решения, поставим отметку рядом с нашей библиотекой и нажмем на кнопку OK:

Если наша библиотека вдруг представляет файл dll, который не связан ни с каким проектом в нашем решении, то с помощью кнопки Browse мы можем найти местоположение файла dll и также его подключить.
После успешного подключения библиотеки в главном проекте изменим файл Program.cs , чтобы он использовал класс Person из библиотеки классов:
using MyLib; // подключение пространства имен из библиотеки классов Person tom = new("Tom"); tom.Print(); // Name: Tom
Проект с выходным типом библиотеки классов не может быть запущен напрямую (2)
Невозможно запустить проект с видом типа библиотеки классов напрямую. Чтобы отладить этот проект, добавьте исполняемый проект в это решение, которое ссылается на проект библиотеки. Установите исполняемый файл проект как проект запуска.
При запуске программы в Visual Studio 2010 на С# я получаю эту ошибку. Скажите, пожалуйста, как решить эту ошибку?
user1577052 06 сен. 2012, в 16:41
Поделиться
Сообщение об ошибке говорит вам точно, что вам нужно сделать. С чем конкретно вы испытываете трудности?
J. Steen 06 сен. 2012, в 14:02
Проект, который вы попытались отладить, не может быть отлажен, потому что это библиотека классов, поэтому нет точки выполнения. У вас есть другие проекты в вашем решении?
user1017882 06 сен. 2012, в 14:03
Ну, я думаю, вы должны оставить эту ошибку .
RvdK 06 сен. 2012, в 14:03
@PoweRoy в начале это ошибка
Reniuz 06 сен. 2012, в 14:04
@Reniuz: спасибо
RvdK 06 сен. 2012, в 14:14
Можете попробовать этот ответ, он мне помог! stackoverflow.com/questions/11152272/.
Jerric Lyns John 15 сен. 2014, в 07:48
Возможный дубликат «Проект с типом вывода библиотеки классов не может быть запущен напрямую»
kenorb 18 сен. 2018, в 16:07
Возможный дубликат проекта с выходным типом библиотеки классов не может быть запущен напрямую
Nande 22 янв. 2019, в 22:32
Показать ещё 6 комментариев
Поделиться:
7 ответов
Задайте свой startproject в проводнике проекта, щелкнув правой кнопкой мыши в исполняемом проекте и выберите » Установить как начальный проект«
CloudyMarble 06 сен. 2012, в 14:10
Поделиться
Вы создали проект как проект библиотеки классов, а не исполняемую программу. Библиотеки классов скомпилированы, а затем используются другими приложениями для общей функциональности.
Если вы хотите создать библиотеку классов, вам нужно создать тестовое приложение (или, еще лучше, Unit Tests), чтобы проверить функциональность. Если вы хотите создать исполняемое приложение, вам нужно будет изменить проект.
Если у вас есть несколько проектов в одном решении, вам также может потребоваться установить правильный проект как «Запустить проект», а не один из проектов библиотеки классов.
Justin Niessner 06 сен. 2012, в 16:01
Поделиться
Downvote, как только я отправил? Кто-нибудь хочет прокомментировать, почему?
Justin Niessner 06 сен. 2012, в 14:03
То же самое случилось со мной, я думаю, кто-то здесь троллинг 🙂
Bartosz 06 сен. 2012, в 14:05
Кажется, что происходит на ответы на некоторые вопросы. Одеяло подавление без всякой на то причины.
J. Steen 06 сен. 2012, в 14:06
Ответы здесь проголосовали, просто чтобы отогнать тролля.
Bartosz 06 сен. 2012, в 14:07
Показать ещё 2 комментария
что вы сделали, так это то, что вы создали class library со всем своим кодом
каждый проект в .Net нуждается в отправной точке, например, функции Main() в С#, которая, как правило, отсутствует в проекте типа класса libraty что вы можете сделать вместо этого — 1. Создайте консольный проект внутри одного и того же решения. щелкнув правой кнопкой мыши решение и добавьте новый проект
2. Добавьте ссылку на библиотеку классов
3. Доступ к классам/методам библиотеки классов, а затем запуск проекта консоли вместо библиотеки классов
Альтернативно
Если у вас есть проект консоли ИЛИ любой другой проект в решении уже
щелкните правой кнопкой мыши проект в проводнике решений и Установить как проект запуска
Parv Sharma 06 сен. 2012, в 15:07
Поделиться
Я думаю, что он может просто не установить запуск проекта. Это хранится локально, поэтому, если он просто закодирует код Sorce от кого-то другого, он не будет установлен.
AnthonyLambert 06 сен. 2012, в 14:11
@AnthonyLambert-really AnthonyLambert — действительно, ты бы хотел понизить голос за что-то подобное. когда это даже не упоминается в вопросе? так как при предоставлении более (вероятно, правильной) информации является причиной понизить голосование
Parv Sharma 06 сен. 2012, в 14:14
Этот ответ трудно прочитать, и у него много проблем с форматированием. Вероятно, поэтому он получил отрицательный голос.
John Koerner 06 сен. 2012, в 14:29
Попытка установить текущий проект (код, сгенерированный из диаграммы классов) в качестве исполняемого проекта, но безуспешно. Следуйте решению @ParvSharma, и оно отлично работает!
jayko03 12 фев. 2018, в 02:51
Показать ещё 2 комментария
Щелкните правой кнопкой мыши на Solution → Перейти к свойствам → Развернуть вкладку «Общие свойства» → (С правой стороны). Выберите «Радио» с опцией «Проект с одним запуском» → выберите проект из выпадающего списка.
Наслаждайтесь.
Взаимодействие C# и C++ кроссплатформенно
Вам приходилось сталкиваться с необходимостью взаимодействия кода на C# и native-C++ (или скорее С)? Причины могли быть разными: библиотека уже есть, на С/С++ написать проще, разработка частей приложения ведётся разными командами, _______________ (нужное вписать).
Известно, что языки базируются на совершенно разных наборах аксиом.
В С# (CLR, если точнее) вы имеете дело с типами фиксированных размеров (за редкими оговорками), код может быть скомпилирован JIT-компилятором под любую из поддерживаемых целевых платформ (если явно не оговорено иное).
В мире C++ всё совсем иначе: одни и те же типы могут иметь разные размеры при компиляции на разные платформы (привет, size_t), код генерируется по-разному для разных платформ, операционных систем и прочих прелестей.
Под катом будем пробовать их подружить с учётом указанных особенностей.
Для взаимодействия управляемого (managed) с неуправляемым (native, unmanaged) кода, при котором в managed-приложение подключаются unmanaged-библиотеки, существует механизм Platform Invoke (p/Invoke). Такое взаимодействие классифицируется как внутрипроцессное.
Оно имеет следующие ограничения:
- Возможно вызвать только unmanaged-функции, но нельзя обратиться к экспортируемым переменным;
- Импортируемые функции становятся статическими методами классов;
- Импортируемые функции объявляются как extern и маркируются специальным атрибутом DllImport, который указывает компилятору на необходимость генерации специального кода маршализации вызовов;
- В процессе вызова unmanaged-кода поток, который его выполняет, не может быть прерван, в отличие от кода на C#. Так, если на нём вызвать Abort или Interrupt, то подъём исключений будет отложен до возвращения в управляемый контекст;
Мы не будем рассматривать все аспекты работы с p/Invoke, а сосредоточимся только на том, как для p/Invoke решить проблему вызова на разных архитектурах (на примере x86 и x64), и не будем касаться других архитектур и операционных систем, однако того, что будет описано в статье, теоретически достаточно чтобы развить мысль дальше. Будем считать это домашним заданием для тех, кому это нужно.
Итак, давайте раскручивать клубок.
Нам нужно импортировать некоторый набор функций из unmanaged-библиотеки на C++ для вызова их из кода на C#, при этом поддерживать нужно одновременно две архитектуры: x86 и x64, выбирая их в зависимости от того, на какой из платформ работает хост-приложение на C#.
Я использую MS Visual Studio 2015 Community Edition для примера, но всё должно работать и при разработке с использованием других средств. CMake и прочими прелестями (пока) не заморачиваемся.
Исходный код с процессом эволюции доступен на гитхабе по ссылке.
После создания решения с двумя проектам (CrossPlatformInterop типа Console Application на C# и CrossPlatformLibrary типа Win32 Project / DLL) сконфигурируем их так, чтобы выходной каталог был $(SolutionDir)Output\$(Configuration)\, а для C++-проекта имя собираемого файла — $(ProjectName)-$(PlatformShortName).dll для того, чтобы на x86 и x64 получались разные файлы.
Результаты конфигурации можно посмотреть в ветке project-setup в репозитории.
Реализуем простенькую функцию на С++, которая принимает 2 числа и имитирует бурную деятельность в виде форматирования какой-то строки и передачи её в managed-код через функцию обратного вызова:
// header typedef void(__stdcall* Notification)(const char*); int32_t CROSSPLATFORMLIBRARY_API __stdcall ProcessData(int32_t start, int32_t count, Notification notification);
Исходный код
// source int32_t __stdcall ProcessData(int32_t start, int32_t count, Notification notification) < if (notification == nullptr) < return 0; >int32_t result = 0; for (int32_t i = 0; i < count; ++i) < char buffer[64]; result += sprintf_s(buffer, "Notification %d from C++", i + start); notification(buffer); Sleep(rand() % 500 + 500); >return result; >
Обратите внимание, что здесь явно указаны размеры типов данных и конвенции вызовов. Поскольку мы взаимодействуем с другим языком, нам приходится это знать, и правила написания портируемого кода на С++ здесь не работают. Зато, в отличие от типов вроде size_t, мы всегда знаем, какому типу на C# фиксированного размера он соответствует.
Здесь есть одна тонкость: указатель, который в C++ выглядит как void* или T*, имеет разный размер для разных платформ, но при этом со стороны C# он транслируется в специальный тип IntPtr, который также имеет переменный размер. Так что с маршалингом указателей нам помогает сам компилятор.
Когда компилятор оперирует именами, он их преобразует, кодируя в них типы объектов, аргументов, возвращаемых значений, конвенции вызова и много чего ещё. Эта операция называется декорированием (decoration, mangling). Так, имя функции компилятором от Microsoft преобразуется к виду ?ProcessData@@YGHHHP6GXPBD@Z@Z или ?ProcessData@@YAHHHP6AXPEBD@Z@Z (найдите одно отличие — оно зависит от размера указателя). Вы ведь видели что-то подобное, когда ругался линковщик в С++-проектах?
Работать с такими именами неудобно, поэтому мы попросим компилятор во внешнем программном интерфейсе привести их к более читаемому виду, добавив в объявление функции extern «C» . Если использовать конвенцию вызова __cdecl, то вопросов нет, но если использовать __stdcall, то имя всё равно не станет «нормальным», а будет иметь вид _ProcessData@12 для x86 (после собаки указано количество занятых на стеке байтов). Можно, конечно, сделать def-файл в проекте и указать там список функций для экспорта, но мы так не будем делать.
Будем работать с __stdcall, потому как в Windows принято использовать эту конвенцию при работе с библиотеками.
Дальше для того, чтобы импортировать эту функцию, достаточно было бы написать следующий код:
public class LibraryImport
Использование могло бы выглядеть как:
LibraryImport.ProcessData(1, 10, s => Console.WriteLine(s));
Но если у нас код выполняется в 64-битной среде, то при загрузке класса будет поднято исключение BadImageFormatException, то есть попытка загрузить образ библиотеки несовместимого формата. Надеюсь, пояснять, почему образы несовместимы, не нужно. При импорте 64-битной библиотеки из 32-битной среды будет та же проблема.
Конечно, можно было бы сказать, что мы стремительно завершаем второе десятилетие XXI века, и пора хоронить 32-битные системы, но я бы не стал торопиться хотя бы потому, что у меня есть планшет на винде с 32-битной системой, а ещё есть старый парк железа на работе, где тоже 32-битки вертятся. И вообще, подход будем справедлив и переходе на другие архитектуры процессоров (мы же доживём до того счастливого момента, когда ARM-ы и прочие Байкалы будут поддерживаться в дотнере полном объёме?).
В этом коде есть ещё одна проблема, но мы её разберём позже.
Теперь давайте займёмся полноценным импортом. Возьмём на заметку тот факт, что загрузка типов в .NET ленивая, то есть пока какой-то класс не понадобится среде выполнения, он не будет разобран и скомпилирован. То есть если мы не обращаемся к типу, там может быть импорт некорректной библиотеки.
Первое, что нужно сделать — это спрятать импортируемые методы от постороннего взгляда. Вообще, отдавать что-то из внутренней кухни, слишком торчащее наружу — плохо. Импортируемые методы будем делать приватными, а наружу предоставим методы-обёртки. А список методов вынесем в интерфейс.
Исходный код
[UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Ansi)] public delegate void Notification(string value); public interface ILibraryImport < int ProcessData(int start, int count, Notification notification); >internal class LibraryImport_x86 : ILibraryImport < [DllImport("CrossPlatformLibrary-x86", CallingConvention = CallingConvention.StdCall, ExactSpelling = false, EntryPoint = "_ProcessData@12")] private static extern int ProcessDataInternal(int start, int count, Notification notification); public int ProcessData(int start, int count, Notification notification) < return ProcessDataInternal(start, count, notification); >> internal class LibraryImport_x64 : ILibraryImport < [DllImport("CrossPlatformLibrary-x64", CallingConvention = CallingConvention.StdCall, ExactSpelling = false, EntryPoint = "ProcessData")] private static extern int ProcessDataInternal(int start, int count, Notification notification); public int ProcessData(int start, int count, Notification notification) < return ProcessDataInternal(start, count, notification); >>
Обратите внимание, что классы объявлены как внутренние, а интерфейс — публичным. Зря я, конечно, не сделал библиотеку-обёртку отдельно от приложения, ну да ладно: идея должна быть понятной.
Дальше нужно сделать загрузчик, который отдаст экземпляр нужного класса в зависимости от битности текущей среды выполнения.
Исходный код
public static class LibraryImport < public static ILibraryImport Select() < if (IntPtr.Size == 4) // 32-bit application < return new LibraryImport_x86(); >else // 64-bit application < return new LibraryImport_x64(); >> >
Здесь сделано предположение о том, что у нас выбор всего из двух вариантов. В общем случае, именно здесь принимается решение о том, какие классы использовать для какой реализации. А ещё здесь же можно делать много других странных вещей.
Использование уже достаточно простое:
class Program < static void Main(string[] args) < ILibraryImport import = LibraryImport.Select(); import.ProcessData(1, 10, s =>Console.WriteLine(s)); > >
Предложенное решение имеет большой недостаток: достаточно большой объём дублирующегося стереотипного кода: сигнатура каждой импортируемой функции присутствует в пяти местах, и используется тремя разными способами. И ещё пара мест в native-коде. К сожалению, какого-то способа минимизировать количество вариантов, кроме как кодогенерацией, я не придумал. Но если получится сделать что-то более элегантное, я обязательно напишу.
Я обещал указать ещё на одну проблему этого кода. Она не относится напрямую к обсуждаемой теме, но я всё равно хочу её упомянуть. Но под спойлером.
Предположим, что вызов у нас асинхронный, например, при нажатии на кнопку у нас будет выполняться в фоне некоторый код, который генерирует протокол работы и ещё что-нибудь полезное, но обработчик кнопки завершил работу, и, следовательно, все локальные объекты могут быть собраны сборщиком мусора. А у нас есть такой объект и очень важный: делегат, инкапсулирующий функцию обратного вызова. Через произвольный промежуток времени код просто упадёт с непонятной ошибкой обращения либо к нулевому указателю, либо, что ещё хуже, к произвольной области памяти. А всё потому, что указатель на функцию в unmanaged-коде ещё живой, а делегат, на который он ссылается, уже нет, скорее всего, его память очищена и теперь у нас есть висящий указатель.
Чтобы такого не происходило, нужно увеличить время жизни делегата, либо сохранив его как поле в объекте, либо каким-то иным образом, в зависимости от обстоятельств.
А ещё в этом случае следует подумать о том, как unmanaged-поток останавливать.
У меня на сегодня всё. Надеюсь, кому-то это будет полезно.
