Download Article
Download Article
Most people users will not need to edit DLL files. However, if you are a computer programmer, you may want to edit DLL files to reverse engineer a program, extract icons, hack software, or just see how a program works under the hood. Microsoft Visual Studio allows can open and edit certain sections of a DLL file. If you need to edit the code in a DLL file, you will need to use a decompiler application to extract the code from the file. This wikiHow article teaches you how to open and edit DLL files in Visual Studio.
-
Yes, you can open and edit certain DLL resources within Visual Studio. You can use Visual Studio to add, extract or delete certain graphical or textual resources, but you cannot edit the functions of a DLL file.[1]
Advertisement
-
Not in most cases. Most DLL files do not contain any source code that can be edited. The code contained within most DLL files has already been compiled into binary or machine code.
- If the DLL file contains any intermediate language (IL), you can view the IL code using the IL Disassembler tool, which is installed alongside Visual Studio. You can also use CIL Disassembler to view common intermediate language within a DLL file. CIL Disassembler does not come with Visual Studio, but it is free to download from the Microsoft Store.
- If a DLL file is not functioning correctly and you need to edit it, you can do so by editing the original source code that was used to create the DLL file. This will be on a separate code file. You can use the original source code to create a new DLL file, which can be used to replace the DLL file that isn’t working.
-
You can try to reconstruct it using a decompiler program. A decompiler program can take the machine language within a DLL file and convert it into a high-level language, such as C++ or C#.
- Warning: Any code you extract from a DLL file using a decompiler will be a reconstruction. There is no guarantee that it will match the original source code. If you attempt to replace a DLL file using code extracted from a decompiler program, you will likely need to do lots of testing to make sure all programs that depend on the DLL file still function correctly.
Advertisement
-
You can easily open a DLL file in Visual Studio the same way you would any other file. To do so, click File in the menu bar at the top, followed by Open. Then click File and select the DLL file you want to open and click Open. This will open the DLL file in a new Resource Editor window. Alternatively, you can use the following steps to open a DLL file:[2]
- Make sure you have Visual Studio installed.
- Press Win + E to open File Explorer.
- Navigate to the folder containing the DLL file you want to open.
- Right-click the folder and click Open with Visual Studio.
- Expand the folder in the Solution Explorer window to the right.
- Double-click the DLL file you want to open.
-
You can easily add a new resource to a DLL file in Visual Studio. These resources include keyboard shortcut accelerators, bitmap images, cursors, icons, dialogue boxes, menus, HTML files, audio (.wav) files, string tables, and the version number. Use the following steps to add a new resource to a DLL file.
- Open a DLL file in Visual Studio.
- Right-click the folder you want to add the resource to in the Resource Editor window.
- Click Add Resource.
- Double-click the resource type you want to add or click Import to import an existing file.
- Click File
- Click Save [filename].dll to overwrite the file or click Save [filename].dll as to save a copy.
Advertisement
-
You can easily do so in Visual Studio. Warning: Editing or deleting contents from a DLL file may cause the programs that depend on that file to not function properly. Be sure to save a backup copy of the DLL file you are editing. Use the following steps to delete a resource from a DLL file:
- Open a DLL file in Visual Studio.
- Expand the folder that contains the resource you want to delete in the Resource Editor window.
- Right-click the resource you want to delete and click Delete.
- Click File
- Click Save [filename].dll to overwrite the file or click Save [filename].dll as to save a copy.
-
You can easily use Visual Studio to create new DLL files. You can do so using your own source code, or source code extracted from a decompiler program. Use the following steps to create a new DLL file in Visual Studio:[3]
- Open Visual Studio.
- Click Create New Project.
- Type class in the search bar at the top.
- Scroll down and select Class Library (.NET Framework) and click Next.
- Type a name for your project and click Create.
- Enter the code for your DLL file.
- Click Build in the menu bar at the top.
- Click Build Solution to create a new DLL file.
- Check the Output window at the bottom to see where the DLL file was created.
Advertisement
-
You can do so using the Developer Command Prompt. The IL Disassembler tool allows you to view intermediate language (IL) and assembly language in a DLL file. The IL Disassembler tool is installed alongside Visual Studio. Use the following steps to open a DLL file in IL Disassembler:
- Click the Windows Start menu.
- Type Developer Command Prompt.
- Click Developer Command Prompt for VS 2019 (or whichever version of Visual Studio you are using.)
- Type ILDASM.EXE and press Enter.
- Drag and drop the DLL file into the IL Disassembler window.
- Expand the filename below «MANIFEST’ in the IL Disassembler window.
- Click a class or function to view the assembly code.
-
You will need to use a separate decompiler program outside of Visual Studio. These programs can convert machine code into a high-level language, like C++ or C#. Warning: The code these programs extract is a reconstruction and not guaranteed to match the original source code. Use the following steps to decompile a DLL file:[4]
- Download and install a Decompiler program. Popular programs include Reflector, dotPeek, and JustDecompile.
- Open your decompiler program.
- Drag and drop the DLL file into the Decompiler program window.
- Expand the program or filename in the panel to the right.
- Expand the program name next to the bracket icons.
- Click the function or class name to view the code.
- Copy the code into a Visual Studio file, or click File followed by Export to Project.
Advertisement
-
Some DLL files need to be registered in order to function. You can register a DLL file using the Run program. Use the following steps to register a DLL file in Windows 10:[5]
- Press Win + R to open Run.
- Type regsvr32 next to «Open.»
- Drag and drop the DLL file into the «Open» text box to add the path to the DLL file.
- Put quotations (» «) around the path to the DLL file.
- Click Ok.
Ask a Question
200 characters left
Include your email address to get a message when this question is answered.
Submit
Advertisement
Thanks for submitting a tip for review!
About This Article
Thanks to all authors for creating a page that has been read 48,781 times.
Is this article up to date?
Download Article
Download Article
Most people users will not need to edit DLL files. However, if you are a computer programmer, you may want to edit DLL files to reverse engineer a program, extract icons, hack software, or just see how a program works under the hood. Microsoft Visual Studio allows can open and edit certain sections of a DLL file. If you need to edit the code in a DLL file, you will need to use a decompiler application to extract the code from the file. This wikiHow article teaches you how to open and edit DLL files in Visual Studio.
-
Yes, you can open and edit certain DLL resources within Visual Studio. You can use Visual Studio to add, extract or delete certain graphical or textual resources, but you cannot edit the functions of a DLL file.[1]
Advertisement
-
Not in most cases. Most DLL files do not contain any source code that can be edited. The code contained within most DLL files has already been compiled into binary or machine code.
- If the DLL file contains any intermediate language (IL), you can view the IL code using the IL Disassembler tool, which is installed alongside Visual Studio. You can also use CIL Disassembler to view common intermediate language within a DLL file. CIL Disassembler does not come with Visual Studio, but it is free to download from the Microsoft Store.
- If a DLL file is not functioning correctly and you need to edit it, you can do so by editing the original source code that was used to create the DLL file. This will be on a separate code file. You can use the original source code to create a new DLL file, which can be used to replace the DLL file that isn’t working.
-
You can try to reconstruct it using a decompiler program. A decompiler program can take the machine language within a DLL file and convert it into a high-level language, such as C++ or C#.
- Warning: Any code you extract from a DLL file using a decompiler will be a reconstruction. There is no guarantee that it will match the original source code. If you attempt to replace a DLL file using code extracted from a decompiler program, you will likely need to do lots of testing to make sure all programs that depend on the DLL file still function correctly.
Advertisement
-
You can easily open a DLL file in Visual Studio the same way you would any other file. To do so, click File in the menu bar at the top, followed by Open. Then click File and select the DLL file you want to open and click Open. This will open the DLL file in a new Resource Editor window. Alternatively, you can use the following steps to open a DLL file:[2]
- Make sure you have Visual Studio installed.
- Press Win + E to open File Explorer.
- Navigate to the folder containing the DLL file you want to open.
- Right-click the folder and click Open with Visual Studio.
- Expand the folder in the Solution Explorer window to the right.
- Double-click the DLL file you want to open.
-
You can easily add a new resource to a DLL file in Visual Studio. These resources include keyboard shortcut accelerators, bitmap images, cursors, icons, dialogue boxes, menus, HTML files, audio (.wav) files, string tables, and the version number. Use the following steps to add a new resource to a DLL file.
- Open a DLL file in Visual Studio.
- Right-click the folder you want to add the resource to in the Resource Editor window.
- Click Add Resource.
- Double-click the resource type you want to add or click Import to import an existing file.
- Click File
- Click Save [filename].dll to overwrite the file or click Save [filename].dll as to save a copy.
Advertisement
-
You can easily do so in Visual Studio. Warning: Editing or deleting contents from a DLL file may cause the programs that depend on that file to not function properly. Be sure to save a backup copy of the DLL file you are editing. Use the following steps to delete a resource from a DLL file:
- Open a DLL file in Visual Studio.
- Expand the folder that contains the resource you want to delete in the Resource Editor window.
- Right-click the resource you want to delete and click Delete.
- Click File
- Click Save [filename].dll to overwrite the file or click Save [filename].dll as to save a copy.
-
You can easily use Visual Studio to create new DLL files. You can do so using your own source code, or source code extracted from a decompiler program. Use the following steps to create a new DLL file in Visual Studio:[3]
- Open Visual Studio.
- Click Create New Project.
- Type class in the search bar at the top.
- Scroll down and select Class Library (.NET Framework) and click Next.
- Type a name for your project and click Create.
- Enter the code for your DLL file.
- Click Build in the menu bar at the top.
- Click Build Solution to create a new DLL file.
- Check the Output window at the bottom to see where the DLL file was created.
Advertisement
-
You can do so using the Developer Command Prompt. The IL Disassembler tool allows you to view intermediate language (IL) and assembly language in a DLL file. The IL Disassembler tool is installed alongside Visual Studio. Use the following steps to open a DLL file in IL Disassembler:
- Click the Windows Start menu.
- Type Developer Command Prompt.
- Click Developer Command Prompt for VS 2019 (or whichever version of Visual Studio you are using.)
- Type ILDASM.EXE and press Enter.
- Drag and drop the DLL file into the IL Disassembler window.
- Expand the filename below «MANIFEST’ in the IL Disassembler window.
- Click a class or function to view the assembly code.
-
You will need to use a separate decompiler program outside of Visual Studio. These programs can convert machine code into a high-level language, like C++ or C#. Warning: The code these programs extract is a reconstruction and not guaranteed to match the original source code. Use the following steps to decompile a DLL file:[4]
- Download and install a Decompiler program. Popular programs include Reflector, dotPeek, and JustDecompile.
- Open your decompiler program.
- Drag and drop the DLL file into the Decompiler program window.
- Expand the program or filename in the panel to the right.
- Expand the program name next to the bracket icons.
- Click the function or class name to view the code.
- Copy the code into a Visual Studio file, or click File followed by Export to Project.
Advertisement
-
Some DLL files need to be registered in order to function. You can register a DLL file using the Run program. Use the following steps to register a DLL file in Windows 10:[5]
- Press Win + R to open Run.
- Type regsvr32 next to «Open.»
- Drag and drop the DLL file into the «Open» text box to add the path to the DLL file.
- Put quotations (» «) around the path to the DLL file.
- Click Ok.
Ask a Question
200 characters left
Include your email address to get a message when this question is answered.
Submit
Advertisement
Thanks for submitting a tip for review!
About This Article
Thanks to all authors for creating a page that has been read 48,781 times.
Is this article up to date?
Preface: I haven’t got a chance to work with Windows 8 yet, so the information in this answer might be slightly off. Or completely useless.
I think by write protected you mean read-only. That’s easily corrected. Locate your shsxs.dll
and right-click on it. Select Properties and uncheck the Read-Only checkbox in the Attributes section, if it is checked. Then go to the Security tab, and click edit. Select your username (or the user Everyone if it’s there) and tick the Full access checkbox in the Allow column. Click OK. Click OK again.
Next you want to know how to modify an existing image or add a new image in png format. These are two different things.
Let’s tackle the modifying first.
You can’t do that with 7-Zip. You can only use it to look at the DLL’s content, but you can’t modify it. You need a specialized tool for the job, I recommend the XN Resource Editor, which is basically a better Resource Hacker, which used to be the program to edit already compiled resources. I’m not sure whether they work with Windows 8 modules, though. If they don’t, please link to an alternative which can in the comments, or edit this answer if you can.
After you install the XN Resource Editor, start it, and open your shsxs.dll
. On the left side you have the resource tree. Expand the Bitmap subtree. You should see a bunch of numbers, each one represents one resource in the DLL. Expand each subtree until you find the desired image.
Once you find your image, you can modify it inline using XN Resource Editor’s built-in picture editor. You can also remember the resource’s number, right-click on the Image and select Delete Resource, then go to the Resource menu and select Import Image Resource, find your desired image. Then right-click on the newly imported image in XN Resource Editor, select Properties and enter the old resource’s number (you remembered it, right?) and press OK.
Adding a new Image is not that different.
It’s easy, simply go to the Resource menu and select Import Image Resource, find your desired image and click OK. DONE.
Edit: Since the file came from System32, I added instructions on how to grant the user full access to the file, additionally to removing the read-only flag.
title | description | ms.custom | ms.date | ms.topic | dev_langs | helpviewer_keywords | ms.assetid | author | ms.author | manager | ms.technology | ms.workload | ||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Debug DLL projects | Microsoft Docs |
Debug dynamic-link library (DLL) files in Visual Studio. Use Visual Studio to create, build, configure, and debug DLLs. |
SEO-VS-2020 |
04/18/2022 |
conceptual |
|
|
433cab30-d191-460b-96f7-90d2530ca243 |
mikejo5000 |
mikejo |
jmartens |
vs-ide-debug |
multiple |
Debug DLLs in Visual Studio (C#, C++, Visual Basic, F#)
[!INCLUDE Visual Studio]
A DLL (dynamic-link library) is a library that contains code and data that can be used by more than one app. You can use Visual Studio to create, build, configure, and debug DLLs.
Create a DLL
The following Visual Studio project templates can create DLLs:
- C#, Visual Basic, or F# Class Library
- C# or Visual Basic Windows Forms Control (WCF) Library
- C++ Dynamic-Link Library (DLL)
For more information, see MFC debugging techniques.
Debugging a WCF Library is similar to debugging a Class Library. For details, see Windows Forms Controls.
You usually call a DLL from another project. When you debug the calling project, depending on the DLL configuration, you can step into and debug the DLL code.
DLL debug configuration
When you use a Visual Studio project template to create an app, [!INCLUDEvsprvs] automatically creates required settings for Debug and Release build configurations. You can change these settings if necessary. For more information, see the following articles:
- Project settings for a C++ debug configuration
- Project settings for .NET C# debug configurations
- Project settings for C# debug configurations
- Project settings for a Visual Basic debug configuration
- How to: Set Debug and Release configurations
Set C++ DebuggableAttribute
For the debugger to attach to a C++ DLL, the C++ code must emit DebuggableAttribute
.
To set DebuggableAttribute
:
-
Select the C++ DLL project in Solution Explorer and select the Properties icon, or right-click the project and select Properties.
-
In the Properties pane, under Linker > Debugging, select Yes (/ASSEMBLYDEBUG) for Debuggable Assembly.
For more information, see /ASSEMBLYDEBUG.
Set C/C++ DLL file locations
To debug an external DLL, a calling project must be able to find the DLL, its .pdb file, and any other files the DLL requires. You can create a custom build task to copy these files to your <project folder>Debug output folder, or you can copy the files there manually.
For C/C++ projects, you can set header and LIB file locations in the project property pages, instead of copying them to the output folder.
To set C/C++ header and LIB file locations:
-
Select the C/C++ DLL project in Solution Explorer and select the Properties icon, or right-click the project and select Properties.
-
At the top of the Properties pane, under Configuration, select All Configurations.
-
Under C/C++ > General > Additional Include Directories, specify the folder that has header files.
-
Under Linker > General > Additional Libraries Directories, specify the folder that has LIB files.
-
Under Linker > Input > Additional Dependencies, specify the full path and filename for the LIB files.
-
Select OK.
For more information on C++ project settings, see Windows C++ property page reference.
Build a Debug version
Make sure to build a Debug version of the DLL before you start debugging. To debug a DLL, a calling app must be able to find its .pdb file and any other files the DLL requires.
You can create a custom build task to copy the DLL files to your <calling project folder>Debug output folder, or you can copy the files there manually.
Make sure to call the DLL in its correct location. This may seem obvious, but if a calling app finds and loads a different copy of the DLL, the debugger will never hit the breakpoints you set.
Debug a DLL
You can’t run a DLL directly. It must be called by an app, usually an .exe file. For more information, see Visual Studio projects — C++.
To debug a DLL, you can start debugging from the calling app, or debug from the DLL project by specifying its calling app. You can also use the debugger Immediate window to evaluate DLL functions or methods at design time, without using a calling app.
For more information, see First look at the debugger.
Start debugging from the calling app
The app that calls a DLL can be:
- An app from a [!INCLUDEvsprvs] project in the same or a different solution from the DLL.
- An existing app that is already deployed and running on a test or production computer.
- Located on the web and accessed through a URL.
- A web app with a web page that embeds the DLL.
To debug a DLL from a calling app, you can:
-
Open the project for the calling app, and start debugging by selecting Debug > Start Debugging or pressing F5.
or
-
Attach to an app that is already deployed and running on a test or production computer. Use this method for DLLs on websites or in web apps. For more information, see How to: Attach to a running process.
Before you start debugging the calling app, set a breakpoint in the DLL. See Using breakpoints. When the DLL breakpoint is hit, you can step through the code, observing the action at each line. For more information, see Navigate code in the debugger.
During debugging, you can use the Modules window to verify the DLLs and .exe files the app loads. To open the Modules window, while debugging, select Debug > Windows > Modules. For more information, see How to: Use the Modules window.
Use the Immediate window
You can use the Immediate window to evaluate DLL functions or methods at design time. The Immediate window plays the role of a calling app.
[!NOTE]
You can use the Immediate window at design time with most project types. It’s not supported for SQL, web projects, or script.
For example, to test a method named Test
in class Class1
:
-
With the DLL project open, open the Immediate window by selecting Debug > Windows > Immediate or pressing Ctrl+Alt+I.
-
Instantiate an object of type
Class1
by typing the following C# code in the Immediate window and pressing Enter. This managed code works for C# and Visual Basic, with appropriate syntax changes:Class1 obj = new Class1();
In C#, all names must be fully qualified. Any methods or variables must be in the current scope and context when the language service tries to evaluate the expression.
-
Assuming that
Test
takes oneint
parameter, evaluateTest
using the Immediate window:The result prints in the Immediate window.
-
You can continue to debug
Test
by placing a breakpoint inside it, and then evaluating the function again.The breakpoint will be hit, and you can step through
Test
. After execution has leftTest
, the debugger will be back in design mode.
Mixed-mode debugging
You can write a calling app for a DLL in managed or native code. If your native app calls a managed DLL and you want to debug both, you can enable both the managed and native debuggers in the project properties. The exact process depends on whether you want to start debugging from the DLL project or the calling app project. For more information, see How to: Debug in mixed mode.
You can also debug a native DLL from a managed calling project. For more information, see How to debug managed and native code.
See also
- Debug managed code
- Prepare to debug C++ projects
- C#, F#, and Visual Basic project types
- Project settings for a C++ Debug configuration
- Project settings for .NET C# debug configurations
- Project settings for C# Debug configurations
- Project settings for a Visual Basic Debug configuration
- Debugger security
Современные программы состоят из нескольких модулей, которые включают в себя массивы данных, классы,…
Современные программы состоят из нескольких модулей, которые включают в себя массивы данных, классы, сервисы, требуемые библиотеки. Такой подход разрешает при переписывании ПО не редактировать полностью код, а изменять только необходимые функции, которые заключены в составных частях. Так как открыть DLL файл стандартными средствами Windows невозможно, приходится использовать другие методы.
Файлы с расширением DLL – что это и для чего нужны
Файлы DLL – это динамически подключаемые библиотеки. Установленная в операционную систему программа может не иметь в своем составе всех нужных для работы данных, а использовать те, которые уже присутствуют в ОС. За счет этого также достигается экономия памяти – работающие программы используют одни и те же DLL.
Если же программа (или библиотека) будет повреждена, то это не скажется на работоспособности остального ПО.
Когда и как появились
Библиотеки DLL появились одновременно с ОС Windows. Разработчики предполагали, что это облегчит программирование приложений и поможет упорядочить использование общих ресурсов в течение сеанса работы.
Но со временем выяснилось, что в ряде случаев возникает тупиковая ситуация, которая получила название «DLL hell». Такое случалось, когда два или более приложений требуют доступа к разным (и не совместимым друг с другом) библиотекам. В результате Windows начинала работать нестабильно.
Только в последних версиях ОС удалось создать механизм, предотвращающий возникновения сбоев – технологию Side-by-side assembly, который испытали в XP, но окончательно он стал применяться в Windows Vista.
При помощи каких программ открываются файлы с расширением .dll
Программный код ОС Windows – проприетарный. Это значит, что разработчики не предусмотрели штатных средств, применяя которые, пользователь сможет менять системный код. Для открытия DLL придется использовать специальные программные пакеты. А подключать имеющиеся DLL к разрабатываемой программе можно с применением ПО Microsoft.
В Windows 10
Пользователи, работающие в десятой версии Windows, не всегда знают, чем открыть DLL. Для подключения библиотеки к проекту понадобится либо Visual Studio, либо VisualFoxPro. Эти программные комплексы доступны для скачивания на официальном портале компании Microsoft. Для редактирования допускается использовать ResourceHacker – утилиту для ознакомления и редактирования различных типов файлов.
Чтобы открыть динамически подключаемую библиотеку, следует нажать в главном меню:
- Пункт «Файл».
- «Открыть».
- Выбрать требуемую библиотеку, воспользовавшись проводником.
- После завершения изменений закрыть файл, сохранив изменения.
Из чего состоит рабочая область программы ResHacker:
- верхняя главная панель – для запуска функциональных команд: открыть, скомпилировать, сохранить;
- левое окно – содержит список объектов, которые входят в состав библиотеки;
- центральная часть – текст программного кода.
В Windows 7
Проблема – чем открыть DLL для редактирования в операционной системе Windows 7 решается так же как и для 10 версии. Еще применяется утилита Resource Tuner – редактор ресурсов. Она дает возможность менять код в DLL на свое усмотрение и сохранять библиотеки.
В онлайн-сервисах
Это понадобится, если речь идет о страницах сайта. В DLL содержатся скрипты, которые отвечают за корректную работу сервера.
Открыть библиотеки можно, используя браузеры:
- Firefox;
- Opera;
- Chrome.
Как открыть DLL, используя Visual Studio
Программная среда Visual Studio дает возможность создавать, подключать DLL к текущему проекту и редактировать его. Для этого используется синтаксис языка программирования.
Особенности работы с DLL файлами и возможные проблемы
Некоторые DLL не удастся не только изменить, но даже открыть. Это происходит с защищенными библиотеками и проблема не решается без специальных программ для взлома.
Пользователи также сталкиваются с отсутствием библиотек, необходимых для работы некоторых программ. ОС при этом выдает сообщение о том, что «файл не найден». Для устранения неисправности требуется отыскать недостающие DLL с помощью поисковых систем и скачать. Затем – поместить в требуемую папку.
В редких случаях библиотеки DLL придется зарегистрировать в ОС:
- В Windows 7 (и более поздних версиях) войти в каталог, содержащий требуемый файл.
- Нажать «Shift» + правую клавишу мышки.
- В появившемся меню выбрать строчку: «Открыть окно команд».
- Набрать: regsvr32 dllxxxx.dll, где «dllxxxx.dll» – название регистрируемой библиотеки.
- Нажать «Enter».
В качестве итога
Работой с DLL занимаются программисты, но опытным пользователям также полезно будет знать основы работы с динамически подключаемыми библиотеками. Это может пригодиться для изменения или извлечения данных из файлов прикладных программ.
Загрузить PDF
Загрузить PDF
Динамическая библиотека (или DLL-файлы) является основой традиционного программирования в Windows. Это внешние файлы данных, к которым обращаются различные программы (обращаются без постороннего вмешательства); так отпадает необходимость встраивать такие файлы в каждую программу. DLL-файлы работают в фоновом режиме и обычный пользователь редко сталкивается с ними. Однако, по той или иной причине может возникнуть необходимость открыть один из DLL-файлов. В этой статье мы расскажем вам, как это сделать.
-
1
Знайте, что представляет из себя DLL-файл. Динамическая библиотека (DLL-файлы) — это внешние файлы данных, к которым обращаются программы для их нормального функционирования; так отпадает необходимость встраивать библиотеки в каждую программу.
- Динамическая библиотека является основой традиционного программирования в Windows и позволяет создавать эффективные и небольшие программы.
-
2
Знайте, что обычному пользователю нет необходимости открывать или редактировать DLL-файлы. Для большинства это файлы, которые работают в фоновом режиме. Программы устанавливают и обращаются к DLL-файлам автоматически, а их перемещение или удаление может привести к системным сбоям.
- Иногда при установке программы вам может быть предложено установить дополнительные DLL-файлы. Убедитесь, что программа получена из надежных источников, так как DLL-файлы могут включать вредоносный код.
- Если вы заинтересованы в создании DLL-файлов, обратитесь к следующему разделу.
-
3
Зарегистрируйте новый DLL-файл. Если вы установили DLL-файл вручную (скопировали его в папку программы), возможно, вам потребуется зарегистрировать его, чтобы программа смогла работать с ним. Обратитесь к документации к программе, чтобы определить, нужно ли вам регистрировать DLL-файл (в большинстве случаев этого делать не нужно).[1]
- Откройте командную строку. Нажмите «Пуск» –> «Выполнить» (или нажмите Win + R) и введите cmd. Перейдите в каталог с новым DLL-файлом.
- В Windows 7 или более новой версии этой системы откройте папку, содержащую новый DLL-файл, зажмите Shift, щелкните правой кнопкой мыши в папке и в контекстном меню выберите «Открыть окно команд». Командная строка откроется непосредственно в текущем каталоге.
- Введите regsvr32 dllname.dll и нажмите Enter. Эта команда добавит DLL-файл в реестр Windows.
- Введите regsvr32 -u dllname.dll, чтобы удалить DLL-файл из реестра Windows.
Реклама
-
1
Скачайте и установить декомпилятор. Декомпилятор — это программа, которая позволяет просмотреть исходный код, использованный для создания файла или программы (в нашем случае DLL-файла). Для просмотра DLL-файла вам понадобится декомпилятор, чтобы открыть исходный код файла. Открытие DLL-файла без декомпилятора (например, с помощью блокнота) приведет к отображению нечитаемых символов.
- dotPeek является одним из наиболее популярных бесплатных декомпиляторов. Он доступен по ссылке.
-
2
Откройте DLL-файл в декомпиляторе. Если вы используете dotPeek, нажмите «Файл» –> «Открыть», а затем найдите DLL-файл, который вы хотите декомпилировать. Вы можете просматривать DLL-файлы, не нарушая целостности системы.[2]
-
3
Используйте функцию Assembly Explorer (Просмотр сборки), чтобы открыть узлы DLL-файла. DLL-файлы состоят из «узлов», или модулей кода, которые формируют DLL-файл. Вы можете открыть и просмотреть каждый узел и любые вложенные в него узлы.
-
4
Дважды щелкните по узлу, чтобы просмотреть его код. Код узла отобразится в правом окне dotPeek. dotPeek отображает код в C# , или он может загрузить дополнительные библиотеки для просмотра исходного кода.
- Если для просмотра узла требуются дополнительные библиотеки, dotPeek попытается загрузить их автоматически.
-
5
Если какой-то фрагмент кода вам не понятен, воспользуйтесь функцией Quick Documentation (Быстрая документация), чтобы узнать назначение тех или иных команд.
- Наведите курсор на фрагмент непонятного кода (в окне «Просмотр кода»).
- Нажмите Ctrl + Q, чтобы открыть окно «Быстрая документация».
- Щелкайте по гиперссылкам, чтобы получить информацию о той или иной команде.
-
6
Экспортируйте код в Visual Studio (Визуальная студия). Если вы хотите отредактировать код и создать новый DLL-файл, вы можете экспортировать исходный код в Visual Studio. Экспортированный код будет отображаться в C# (даже если исходный код написан на другом языке).
- Щелкните правой кнопкой мыши по DLL-файлу в Assembly Explorer.
- Выберите «Экспортировать в проект».
- Выберите параметры экспорта. Можете открыть файл непосредственно в Visual Studio, если вы хотите приступить к его редактированию.
-
7
Реклама
Об этой статье
Эту страницу просматривали 310 386 раз.
Была ли эта статья полезной?
Введение
Данная статья является развитием ранее написанной статьи про создание DLL с использованием Visual Studio 2005/2008. Та
«базовая», первоначальная статья, отнюдь не потеряла актуальности и всем
интересующимся данной темой просто необходимо ее прочесть. Но с тех пор
прошло достаточно много времени, сейчас актуален Visual Studio 2017, у
которого изменился, пусть и не значительно, интерфейс, да и сама платформа
MetaTrader 5 развивалась и не стояла на месте. Очевидно, что есть
необходимость обновить сведения, рассмотреть какие-то новые возможности и
уточнить старые. Именно этим мы и займемся сейчас, проделав полностью
весь путь от создания проекта DLL в Visual Studio 2017 до подключения
готовой DLL к терминалу и работе с ней.
Статья рассчитана на
начинающих разработчиков, желающих овладеть созданием и подключением
библиотек, написанных на C++, к терминалу.
Зачем все это нужно
В среде разработчиков бытует мнение, что никаких библиотек к
терминалу подключать вообще не надо. Что задач, требующих такое
подключение, просто нет, что все, что требуется, можно сделать средствами
MQL. В определенной степени такое мнение верно. Действительно, задач,
требующих подключение библиотек мало. И, да — многие из этих
задач можно решить средствами MQL, и примеры этого мы весьма часто видим.
Кроме того, применяя библиотеку, нужно учитывать, что теперь советник,
или индикатор, который станет использовать эту библиотеку, будет
работоспособен только при её наличии. Если разработчик захочет
передать такой инструмент третьему лицу, то передавать придется два
файла — сам инструмент и библиотеку, которую инструмент использует. Это
может оказаться весьма неудобным, а иной раз и просто невозможным. Есть и
еще одна сторона медали — библиотеки могут быть небезопасны и содержать
деструктивный код.
Несмотря на вышесказанное, можно отметить и выгоды применения библиотек, которые определенно перевешивают минусы. Например:
- Только со сторонними библиотеками возможно решить те задачи,
которые MQL решить не сможет. Например, выполнить почтовую рассылку. Да
еще и файл к сообщению присоединить. Написать в Skype. И т.д. - Выполнить
те задачи, которые можно выполнить и средствами MQL, но быстрее и
существенно эффективнее. Например парсинг HTML-страниц, работу с
регулярными выражениями.
Вполне понятно, что если
разработчик желает научиться справляться с подобными сложными задачами,
то ему следует освоить создание, подключение и работу с библиотеками на
необходимом уровне.
Теперь, рассмотрев все «За» и «Против» использования библиотек в
своих проектах, мы начнем проходить этап за этапом процесс создания DLL в
среде Visual Studio 2017.
Создание простой библиотеки DLL
Этот путь уже полностью проделан в первоначальной статье, здесь же мы повторим его, учитывая накопившиеся изменения.
Итак, в среде Visual Studio 2017 выбираем File -> New -> Project.
В появившемся окне, в левой части, раскрываем список Visual C++ и в нем
выбираем Windows Desktop, а в средней части выделяем строку Windows
Desktop Wizard. В нижней части имеются несколько полей ввода, где можно
изменить имя (рекомендуется задать свое и осмысленное) и
месторасположение проекта (лучше оставить так, как предлагается). Всё
готово, нажимаем кнопку «ОК» и переходим в следующее окно:
Здесь в выпадающем списке нужно выбрать Dynamic Link Library (.dll) и
отметить галкой пункт «Export Symbols». На самом деле отмечать галкой
этот пункт необязательно, но желательно начинающим разработчикам. В
этом случае в файлы проекта будет добавлен демонстрационный код, который
можно просмотреть, а затем удалить, либо закомментировать. Нажимаем на
кнопку «ОК», и создаются файлы проекта, которые мы можем затем
редактировать. Однако делать это еще рано, пока разберемся с настройками
проекта. Во первых, нужно помнить, что MetaTrader 5 работает только
с 64-х разрядными библиотеками. Если попытаться присоединить 32-х разрядную, то
мы получим следующие сообщения:
‘E:…MQL5LibrariesProject2.dll’ is not 64-bit version
Cannot load ‘E:MetaTrader 5MQL5LibrariesProject2.dll’ [193]
Соответственно, никакой работы сделать будет нельзя.
То же самое относится и к MetaTrader 4, но там наоборот — нужны 32-х
разрядные библиотеки и невозможно присоединить 64-х разрядные. Об этом
стоит помнить, чтобы не делать лишнюю работу.
Теперь переходим к собственно настройкам проекта. Выбираем в меню
«Project» пункт «Name Properties…», где «Name» — имя проекта,
выбранное разработчиком на этапе создания. В результате получаем окно со
множеством разнообразных настроек. И первое, что следует сделать, это
включить поддержку Юникода. В левой части окна выбираем элемент
«General», а в правой строку с заглавием в первой колонке: «Character
Set». Тогда во второй колонке станет доступен выпадающий список, в
котором следует выбрать «Use Unicode Character Set». В некоторых случаях
без поддержки Юникода можно обойтись, но об этом будет сказано позже.
Еще одно очень полезное (но не необходимое) изменение свойств
проекта: Копирование готовой библиотеки в папку «Library» терминала. В
первоначальной статье для этого рекомендовалось менять параметр «Output
Directory», который находится в том же окне элемента «General» проекта. В
существующем Visual Studio 2017 так делать не нужно. Данный параметр
следует оставить без изменения, а обратить внимание на раскрывающийся
элемент «Build Events» в левом окне и выбрать его подэлемент «Post Build
Events». В первой колонке правого окне появится параметр «Command
Line», выбор которого дает доступ к выпадающему списку во второй
колонке, который можно редактировать. В списке должен содержаться
перечень действий, которые выполнит Visual Studio 2017 после построения
библиотеки. Добавим в этот список такую строку:
xcopy «$(TargetDir)$(TargetFileName)» «E:…MQL5Libraries» /s /i /y
, где на месте многоточия должен быть полный путь к соответствующей
папке терминала. Теперь, в том случае, если построение библиотеки
завершилось успешно, она будет скопирована на указанное место. При этом
все файлы в «Output Directory» останутся на месте, что может быть
важным, если разработчик работает с системами контроля версий, например.
Последний и очень важный этап настройки проекта. Представим себе, что
библиотека уже построена и там находится одна функция, которую сможет
использовать терминал. Пусть эта функция имеет такой прототип:
int fnExport(wchar_t* t);
Из скрипта терминала эту функцию можно будет вызвать так:
#import "Project2.dll" int fnExport(string str); #import
Однако, если попытаться сделать это, то получим следующее сообщение об ошибке:
Что делать в этой ситуации? Обратим внимание на то, что Visual Studio 2017 при генерации кода библиотеки сформировал макрос:
#ifdef PROJECT2_EXPORTS #define PROJECT2_API __declspec(dllexport) #else #define PROJECT2_API __declspec(dllimport) #endif
и прототип нашей функции полностью выглядит так:
PROJECT2_API int fnExport(wchar_t* t);
После компиляции библиотеки посмотрим, как выглядит таблица экспорта:
Для просмотра просто выделим файл с библиотекой в окне «Total
Commander» и нажмем F3. Обратите внимание, как выглядит имя
экспортируемой функции. Теперь отредактируем макрос, который мы привели
выше (именно так сделано в первоначальной статье):
#ifdef PROJECT2_EXPORTS #define PROJECT2_API extern "C" __declspec(dllexport) #else #define PROJECT2_API __declspec(dllimport) #endif
Вставка
extern "C"
обозначает
использование простой генерации
сигнатуры функции (в стиле языка С) при получении
объектных
файлов. В частности, это запрещает компилятору C++
производить «декорацию» (или «украшение») имени функции
дополнительными символами при экспорте в DLL. Повторим
компиляцию и опять посмотрим, как выглядит таблица экспорта:
Изменения в таблице экспорта налицо и ошибка при вызове функции из
скрипта исчезла. Однако, с моей точки зрения, этот способ имеет
недостаток — нужно редактировать скрипт, созданный компилятором. Есть
более безопасный способ добиться тех же результатов, пусть немного более
длинный:
Файл определений
Это обычный текстовый файл, как правило, имеющий имя, совпадающее с
именем проекта и имеющий расширение def. Т.е. в данном случае это будет
файл Project2.def. Создается такой файл в обычном блокноте, ни в коем
случае не в Word и подобных ему редакторах. Содержание файла будет
примерно таким:
; PROJECT2.def : Declares the module parameters for the DLL. LIBRARY "PROJECT2" DESCRIPTION 'PROJECT2 Windows Dynamic Link Library' EXPORTS ; Explicit exports can go here fnExport @1 fnExport2 @2 fnExport3 @3 ....
Сначала заголовок, а потом просто список экспортируемых функций.
Символы вида @1, @2 и т.д. обозначают желательный порядок следования
функций в библиотеки. Сохранить этот файл следует в папке проекта.
Создадим этот файл и подключим к проекту. В окне свойств проекта, в
левом окне выберем раскрывающийся элемент «Linker» и его подэлемент «Input», а в правом параметр
«Module Definition File». Так же, как и в прошлых случаях, получаем
доступ к редактируемому списку, куда добавляем имя файла:
«Project2.def». Нажимаем кнопку «OK» и повторяем компиляцию. Получаем
такой же результат, что и на последнем скриншоте. Имя не задекорировано и
ошибок при вызове функции скриптом нет. Разобравшись с настройками
проекта, можно приступать к написанию кода собственно библиотеки.
Создание библиотеки и DllMain
В первоначальной статье весьма полно освещены вопросы обмена данными и
вызовы различных функций из DLL, поэтому останавливаться опять на этом
мы не станем. Однако нужно обратить внимание на определенные моменты, и
для этого мы создадим в библиотеке такой простой код:
1. Добавим в экспорт функцию (и не забудем отредактировать файл определений):
PROJECT2_API int fnExport1(void) { return GetSomeParam(); }
2. Создадим и добавим в проект заголовочный файл Header1.h и пропишем в него другую функцию:
const int GetSomeParam();
3.Отредактируем файл dllmain.cpp:
#include "stdafx.h" #include "Header1.h" int iParam; BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: iParam = 7; break; case DLL_THREAD_ATTACH: iParam += 1; break; case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } const int GetSomeParam() { return iParam; }
Смысл этого кода должен быть понятен: в библиотеку добавлена
переменная, значение которой вычисляется в функции DllMain и доступно
при помощи функции fnExport1. Вызовем функцию в скрипте:
#import "Project2.dll" int fnExport1(void); #import ... void OnStart() { Print("fnExport1: ",fnExport1() );
Мы получаем следующую запись:
fnExport1: 7
Это говорит о том, что эта часть кода в DllMain не выполняется:
case DLL_THREAD_ATTACH: iParam += 1; break;
Насколько
это важно? С моей точки зрения важно чрезвычайно, т.к, если разработчик
часть кода по инициализации библиотеки разместит в этом ветвлении в
расчете на то, что он выполнится при присоединении библиотеки к потоку,
то его расчеты не оправдаются. При этом никакой ошибки зафиксировано не
будет, что несомненно затруднит ее поиск.
Строки
Как работать со строками говорится в первоначальной статье. Работа
эта не сложна, но есть один момент, который нуждается в пояснениях.
Создадим в библиотеке простую функцию (и отредактируем файл определений):
PROJECT2_API void SamplesW(wchar_t* pChar) { size_t len = wcslen(pChar); wcscpy_s(pChar + len, 255, L" Hello from C++"); }
Вызовем эту функцию в скрипте:
#import "Project2.dll" void SamplesW(string& pChar); #import void OnStart() { string t = "Hello from MQL5"; SamplesW(t); Print("SamplesW(): ", t);
Мы вполне ожидаемо получим такое сообщение:
SamplesW(): Hello from MQL5 Hello from C++
Изменим вызов функции:
#import "Project2.dll" void SamplesW(string& pChar); #import void OnStart() { string t; SamplesW(t); Print("SamplesW(): ", t);
И теперь получим устрашающее сообщение об ошибке:
Access violation at 0x00007FF96B322B1F read to 0x0000000000000008
Проинициализируем строку, которую передаем библиотечной функции и повторим выполнение скрипта:
string t="";
Сообщение об ошибке исчезло, снова получаем ожидаемый вывод:
SamplesW(): Hello from C++
Из всего вышесказанного можно сделать вывод: строки, передаваемые в
экспортируемые библиотекой функции, должны быть обязательно
проинициализированы!
Здесь мы подошли к вопросу, к которому обещали вернуться при
обсуждении использования Юникода. Если в DLL не планируется передавать
строки, как в последнем примере, то можно обойтись и без поддержки
Юникода. Однако, эту поддержку лучше все таки включать в любом случае,
т.к. сигнатуры экспортируемых функций могут измениться, появляться новые,
и разработчик может просто забыть, что поддержки Юникода нет.
Передача и прием массивов символов какими-то особенностями не
обладает, рассмотрена в первоначальной статье и здесь мы на ней
останавливаться не станем.
Структуры
Определим простейшую структуру в библиотеке и скрипте:
typedef struct E_STRUCT { int val1; int val2; }ESTRUCT, *PESTRUCT; struct ESTRUCT { int val1; int val2; };
Добавим функцию для работы с этой структурой в библиотеку:
PROJECT2_API void SamplesStruct(PESTRUCT s) { int t; t = s->val2; s->val2 = s->val1; s->val1 = t; }
Из кода видно, что функция просто выполняет обычный swap собственных полей.
Вызовем функцию из скрипта:
#import "Project2.dll" void SamplesStruct(ESTRUCT& s); #import .... ESTRUCT e; e.val1 = 1; e.val2 = 2; SamplesStruct(e); Print("SamplesStruct: val1: ",e.val1," val2: ",e.val2);
Выполним скрипт и получим предсказуемый результат:
SamplesStruct: val1: 2 val2: 1
Объект был передан в вызываемую функцию по ссылке, функция обработала объект и вернула его вызывающему коду.
Однако, работой с такими простыми структурами удается ограничиться не
часто. Усложним задачу, добавим в структуру еще одно поле, но другого
типа:
typedef struct E_STRUCT1 { int val1; char cval; int val2; }ESTRUCT1, *PESTRUCT1;
… и функцию для работы с ней:
PROJECT2_API void SamplesStruct1(PESTRUCT1 s) { int t; t = s->val2; s->val2 = s->val1; s->val1 = t; s->cval = 'A'; }
Функция, как и предыдущая, делает swap своих полей типа int и
присваивает значение полю типа char. Вызовем эту функцию в скрипте
(точно тем же способом, что и предыдущую функцию). И мы совершено
неожиданно получаем вот такую запись в журнал:
SamplesStruct1: val1: -2144992512 cval: A val2: 33554435
Поля структуры типа int совершенно явно содержат мусор. Мы не получаем исключение, а именно случайный мусор, неверные данные. Что же случилось? Все дело в выравнивании! «Выравнивание», это понятие не самое простое, но и не из сложных. Есть раздел в документации pack, посвященный структурам, там достаточно подробно описано, что это такое. Что касается выравнивания в среде Visual Studio C++, то выравниванию там тоже посвящено достаточно много материала.
В нашем же примере источник ошибки в том, что в данном случае у библиотеки и скрипта разные выравнивания, и поэтому скрипт «зацепляет» мусор. Решить проблему можно двумя способами:
- Указать новое выравнивание в скрипте. Для этого имеется атрибут pack(n). Попытаемся выровнять структуру по полю максимальной величины, т.е. по int:
struct ESTRUCT1 pack(sizeof(int)){ int val1; char cval; int val2; };
И повторим вывод, выполнив скрипт. Теперь запись в журнале изменилась: SamplesStruct1: val1: 3 cval: A val2: 2 . Все в порядке, проблема решена.
- Указать новое выравнивание в библиотеке. По умолчанию структуры в MQL имеют выравнивание pack(1), нужно такое же применить в библиотеке так:
#pragma pack(1) typedef struct E_STRUCT1 { int val1; char cval; int val2; }ESTRUCT1, *PESTRUCT1; #pragma pack()
Собираем библиотеку, снова выполняем скрипт и получаем правильный результат, такой же, что и при использовании 1-го способа.
Проверим еще один момент. Что будет, если кроме полей данных, в структуре окажутся методы? Такое вполне возможно. Разработчик вправе добавить конструктор, например (хотя это не метод, разумеется). Деструктор, еще что-то по своему усмотрению. Проверим это на такой структуре в библиотеке:
#pragma pack(1) typedef struct E_STRUCT2 { E_STRUCT2() { val2 = 15; } int val1; char cval; int val2; }ESTRUCT2, *PESTRUCT2; #pragma pack()
Эту структуру будет использовать следующая функция:
PROJECT2_API void SamplesStruct2(PESTRUCT2 s) { int t; t = s->val2; s->val2 = s->val1; s->val1 = t; s->cval = 'B'; }
Сделаем соответствующие изменения в скрипте:
struct ESTRUCT2 pack(1){ ESTRUCT2 () { val1 = -1; val2 = 10; } int val1; char cval; int f() { int val3 = val1 + val2; return (val3);} int val2; }; #import "Project2.dll" void SamplesStruct2(ESTRUCT2& s); #import ... ESTRUCT2 e2; e2.val1 = 4; e2.val2 = 5; SamplesStruct2(e2); t = CharToString(e2.cval); Print("SamplesStruct2: val1: ",e2.val1," cval: ",t," val2: ",e2.val2);
Обратите внимание, что в структуру добавлен метод f(), чтобы отличий от структуры в библиотеке было еще больше. Выполняем скрипт и получаем такую запись в журнал: SamplesStruct2: val1: 5 cval: B val2: 4 Все в порядке! Наличие конструктора и дополнительного метода в нашей структуре никак не повлияло на результат.
Последний эксперимент. Уберем из структуры в скрипте конструктор и метод, оставим только поля с данными, а структуру в библиотеке оставим без изменений. Опять выполним скрипт и получим тот же самый правильный результат. Теперь уже можно сделать окончательный вывод, что присутствие дополнительных методов в структурах никак не влияет на результат.
Проект данной библиотеки для Visual Studio 2017 и скрипт для MetaTrader 5 находятся в файлах, присоединенных к статье.
О том, чего делать нельзя
При работе с библиотеками dll существует ограничения и они описаны в документации. Повторять написанное в документации мы здесь не будем. Приведем лишь пример:
struct BAD_STRUCT { string simple_str; };
Такую структуру передать в dll нельзя. А ведь мы просто обернули строку (одну строку!) структурой! Тем более нельзя будет передать dll более сложные объекты, не получив при этом исключение.
О том, что делать, когда нельзя
Бывает достаточно много случаев, когда в dll необходимо передать объект, который передавать запрещено. Структуру с динамическими объектами, зубчатый массив и т.д. Что делать в таком случае? Если у разработчика нет доступа к коду библиотеки, то придется отказаться от такого решения. Ситуация совершенно иная, если такой доступ имеется.
Мы не будем рассматривать ситуацию с изменением дизайна данных, нужно постараться решить проблему имеющимися средствами и не получить при этом исключения. Внесу уточнение. Т.к. статья не предназначена для опытных пользователей, то здесь мы наметим только возможные пути решения проблемы, а написание собственно кода оставим для упражнения и самосовершенствования читателей.
- Возможность применения функции StructToCharArray(). Это очень заманчивая возможность, дающая возможность написать примерно такой код в скрипте:
struct Str { ... }; Str s; uchar ch[]; StructToCharArray(s,ch); SomeExportFunc(ch);
И в cpp файле библиотеки:
#pragma pack(1) typedef struct D_a { ... }Da, *PDa; #pragma pack() void SomeExportFunc(char* pA) { PDa = (PDa)pA; ...... }
Оставив за скобками безопасность и качество такого кода, сразу отметим бесполезность самого способа: StructToCharArray() работает только с POD-структурами, а такие структуры можно передавать в библиотеки без дополнительных преобразований. Замечу, что применение данной функции в «реальной» жизни мною не проверялось.
- Написать собственный упаковщик/распаковщик структур в некий объект, который можно будет передавать в библиотеку. Способ возможный, но явно весьма сложный и трудозатратный. Однако это приводит нас к вполне приемлемому решению:
- Все объекты, которые нельзя передать в библиотеку непосредственно, упаковывать в строку формата JSON в скрипте и распаковывать в структуры в библиотеке. И наоборот. Необходимый инструментарий для этого есть. Парсеры для JSON имеются и для C++, и для C#, и для MQL. Такую возможность вполне можно использовать, если пожертвовать временем на упаковку/распаковку. Да, определенные потери времени очевидно будут. Но и преимущества налицо. Можно работать со структурами (и не только со структурами) весьма высокой сложности. И в случае необходимости не писать упаковщик/распаковщик «с нуля», а доработать существующий, что очевидно проще.
Таким образом будем иметь в виду, что возможность передать в (и получить из) библиотеку сложный объект, возможно, все таки имеется.
Практическое применение
Применим полученные знания на практике и создадим полезную библиотеку. Пусть это будет библиотека, отсылающая почту. Сразу отметим некоторые моменты:
- Библиотеку нельзя будет использовать для рассылки спама.
- Библиотека будет отсылать почту не обязательно с того адреса и с того сервера, который указан в настройках терминала. Собственно, в настройках терминала может быть вообще установлен запрет на использование почты, но на работу библиотеки это никак не повлияет.
И последнее. Большая часть кода на C++ принадлежит не мне, а скачана с форумов Microsoft. Это весьма старый, проверенный пример, варианты которого есть в том числе и на VBS.
Начнем. Создадим проект в Visual Studio 2017 и изменим его настройки так, как описано в начале статьи. Создадим файл определений и подключим его к проекту. У нас будет единственная экспортируемая функция:
SENDSOMEMAIL_API bool SendSomeMail(LPCWSTR addr_from,
LPCWSTR addr_to,
LPCWSTR subject,
LPCWSTR text_body,
LPCWSTR smtp_server,
LPCWSTR smtp_user,
LPCWSTR smtp_password);
Смысл её аргументов интуитивно понятен, но все таки кратко поясним:
- addr_from, addr_to — почтовые адреса отправителя и получателя.
- subject, text_body — это тема и собственно письмо.
- smtp_server, smtp_user, smtp_password — адрес SMTP-сервера, логин пользователя на этом сервере и пароль.
Обратим внимание на некоторые моменты:
- Из описания аргументов следует, что для отсылки почты нужно иметь аккаунт на почтовом сервере и знать его адрес. Поэтому ни о какой анонимности отправителя не может быть и речи.
- В коде библиотеки жестко зашит номер порта. Это стандартный порт номер двадцать пять (25).
- Библиотека получает необходимые данные, связывается с сервером и отсылает на него почту. За один вызов можно отправить почту только на один адрес. Если разработчик желает повторить отправку, то вызов функции придется повторить с новым адресом.
Сам код на C++ мы здесь приводить не будем. Его (да и весь проект целиком) можно найти в прилагаемом проекте SendSomeMail.zip. Скажу лишь, что используемый объект CDO обладает множеством возможностей и может (и должен) быть использован для развития и усовершенствования библиотеки.
Кроме этого проекта мы напишем простой скрипт для вызова библиотечной функции (он находится в прилагаемом файле SendSomeMail.mq5):
#import "SendSomeMail.dll" bool SendSomeMail(string addr_from,string addr_to,string subject,string text_body,string smtp_server,string smtp_user,string smtp_password); #import void OnStart() { bool b = SendSomeMail("XXX@XXX.XX", "XXXXXX@XXXXX.XX", "hello", "hello from me to you","smtp.XXX.XX", "XXXX@XXXX.XXX", "XXXXXXXXX"); Print("Send mail: ", b); }
Вместо символов «Х» разработчику придется подставить свои значения, т.к. я не могу приводить данные своего аккаунта. На этом разработка завершена. После подстановки правильных данных и возможного внесения каких либо дополнений в код, библиотеку вполне можно использовать.
Заключение
Таким образом, используя сведения первоначальной статьи и учитывая то новое, что содержится в этой, разработчик может быстро освоить азы и перейти к более сложным и интересным проектам.
Под конец хочется остановиться на одном интересном факте, могущим иметь большое значение в определенных ситуациях. Что, если возникнет необходимость защитить код в dll? Стандартное решение — использовать упаковщик. Различных упаковщиков достаточно много, и многие из них могут обеспечить неплохой уровень защиты. Так вышло, что у меня есть два из них: Themida 2.4.6.0 и VMProtect Ultimate v. 3.0.9 . Применим эти упаковщики и упакуем нашу первую, простейшую Project2.dll в двух вариантах для каждого из упаковщиков. После чего, используя уже имеющийся скрипт, вызовем экспортируемые функции в терминале. Все работает! Терминал может работать с такими библиотеками, что однако не может дать гарантию нормальной работы с библиотеками, накрытыми другими упаковщиками. Упакованная в двух вариантах Project2.dll находится в присоединенном архиве Project2_Pack.zip
На этом все. Успехов и удачи в работе.
Программы, используемые в статье:
# | Имя | Тип | Описание |
---|---|---|---|
1 | Project2.zip | Архив | Проект простой dll. |
2 | Project2.mq5 | Скрипт | Скрипт для работы с dll. |
3 | SendSomeMail.zip | Архив | Проект dll для отсылки почты. |
4 | SendSomeMail.mq5 | Скрипт | Скрипт для работы с библиотекой SendSomeMail. dll |
5 | Project2_Pack.zip | Архив | Project2.dll, упакованная Themida и VMProtect. |
Рассмотрен по шагам процесс создания в Visual Studio файла динамически загружаемой библиотеки *.dll и методы вызова функций из неё. Все описанное далее делается на примере среды разработки Visual Studio 2003 Version 7.1.3088, но также подходит и к Visual Studio 2005. Для простоты папки создаваемых проектов будут находиться в директории C:VSPROJ.
[Создание библиотеки DLL]
1. File -> New -> Project, в дереве Project Types: выбираем Visual C++ Projects -> Win32, в окошке Templates: выбираем Win32 Console Project. В поле Name: вводим имя проекта для DLL, например MyDLL, в поле ввода Location: выбираем путь C:VSPROJ (можно воспользоваться кнопкой Browse…). Жмем ОК.
2. Появится окошко мастера настройки свойств проекта Win32 Application Wizard — MyDLL. Щелкаем на Application Settings, Application type: выбираем DLL, в Additional options: ставим галочку Empty project, жмем Finish.
3. Создадим заголовочный файл для модуля наших функций в создаваемой DLL. В дереве браузера проекта выбираем Header Files -> Add -> Add New Item…, в дереве Categories: выбираем Visual C++ -> Code, в шаблонах Templates: выбираем Header File (.h). В поле Name: вводим любое имя файла, например mydllmodule, жмем Open.
Создастся новый файл, к котором предстоит ввести декларацию класса и методов функций, которые мы хотим добавить в файл DLL. Создадим класс DummyClass, и в нем две функции Beep и Msg. Одна будет выдавать короткий звуковой сигнал, вторая будет выводить окошко с сообщением. Вводим следующий текст:
// mydllmodule.h
namespace dllfuncs
{
class DummyClass
{
public:
// Делаем бип
static __declspec(dllexport) void ShortBeep (void);// Выводим окошко с сообщением
static __declspec(dllexport) void Msg (char* msgstr);
};
}
Вариант без использования классов:
// mydllmodule.h
__declspec(dllexport) void ShortBeep (void);
__declspec(dllexport) void Msg (char* msgstr);
4. Создадим файл для модуля наших функций в создаваемой DLL, в котором будет сам код функций. В дереве браузера проекта выбираем Source Files -> Add -> Add New Item…, в дереве Categories: выбираем Visual C++ -> Code, в шаблонах Templates: выбираем C++ File (.cpp). В поле Name: вводим то же самое имя файла, которое вводили на шаге 3 — mydllmodule, жмем Open.
Создастся новый файл, к котором будет код функций, добавляемых в файл DLL. Вводим в него следующий текст:
// mydllmodule.cpp
// compile with: /EHsc /LD#include "Windows.h"
#include "mydllmodule.h"#include
using namespace std;
namespace dllfuncs
{
void DummyClass::ShortBeep(void)
{
Beep(1000,100); //частота 1000 Гц, длительность 100 мс
}void DummyClass::Msg(char* msgstr)
{
MessageBox(NULL, msgstr, "Message from DLL", MB_OK);
}
}
Вариант без использования классов:
// mydllmodule.cpp
#include "Windows.h"
#include#include "mydllmodule.h"
using namespace std;
void ShortBeep(void)
{
Beep(1000,100); //частота 1000 Гц, длительность 100 мс
}void Msg(char* msgstr)
{
MessageBox(NULL, msgstr, "Message from DLL", MB_OK);
}
После всех этих действий появится папка C:VSPROJMyDLL, в которой будут находиться файлы mydllmodule.cpp и mydllmodule.h, а также конфигурационные файлы проекта MyDLL.
5. Чтобы наш проект скомпилировался в DLL, это должно быть настроено в свойствах проекта. Проверим настройки: MyDLL -> Properties… -> Configuration Properties -> General -> Configuration Type должно быть установлено в Dynamic Library (.dll). Жмем OK.
6. Теперь скомпилируем нашу библиотеку Build -> Build MyDLL. В папке C:VSPROJMyDLLDebug появятся два файла MyDLL.dll и MyDLL.lib. Первый файл MyDLL.dll — динамически загружаемая библиотека наших функций, она должна находится в папке исполняемого файла, который использует эти функции (см. [Создание приложения, которое использует функции из DLL]). Второй файл MyDLL.lib — статическая библиотека, которая может быть присоединена на этапе компиляции к приложению, использующему функции проекта MyDLL (см. [Создание приложения, которое использует функции из статической библиотеки lib]).
[Создание приложения, которое использует функции из загружаемой DLL]
Теперь создадим простую демонстрационную программу, которая будет вызвать функции из нашей DLL.
1. File -> New -> Project, в дереве Project Types: выбираем Visual C++ Projects -> Win32, в окошке Templates: выбираем Win32 Console Project. В поле Name: вводим имя проекта для приложения, использующего загрузку DLL, например DLLtest, в поле ввода Location: выбираем путь C:VSPROJ (можно воспользоваться кнопкой Browse…). Также выберем радиокнопку Add to Solution, это просто добавит в нашу группу проектов (в котором уже есть проект MyDLL) новый проект DLLtest. Жмем ОК.
2. Настроим свойства тестового приложения. Выберите тип приложения Console application и нажмите Finish.
После этого автоматически создастся папка C:VSPROJDLLtest, в ней появится файл DLLtest.cpp, и туда введется пустой код тела функции _tmain. В функцию _tmain мы впоследствии добавим вызовы функций из модуля MyDLL.
3. Нужно настроить в проекте DLLtest ссылки на загружаемую DLL. Щелкаем правой кнопкой на папку DLLtest в дереве Solution Explorer — DLLtest, выберем Add Reference…, откроется окно выбора внешних ссылок на загружаемые библиотеки. На закладке Projects выберите MyDLL c:VsprojMyDLL и нажмите кнопку Select, а затем OK. В проекте DLLtest в дереве проекта появится папка References и подпапка MyDLL, в которой с помощью Object Browser можно просмотреть функции из нашей библиотеки MyDLL.
Весь код для загрузки DLL и инициализации указателей на используемые функции будет сгенерирован автоматически в процессе компиляции приложения.
4. Вставим в приложение вызовы функций Msg и ShortBeep, для этого добавим в модуль DLLtest.cpp включаемый заголовок mydllmodule.h, и установим добавочные пути поиска файлов заголовков проекта DLLtest. Жмем правую кнопку на DLLtest -> выбираем Properties -> Configuration Properties -> C/C++ -> General -> Additional Include Directories -> $(ProjectDir)..MyDLL и жмем OK.
Добавим в модуль DLLtest.cpp вызовы функций ShortBeep и Msg, код модуля DLLtest.cpp получится следующий:
// DLLtest.cpp : здесь определена точка входа для консольного приложения.
//#include "stdafx.h"
#include "mydllmodule.h"using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{dllfuncs::DummyClass::ShortBeep();
dllfuncs::DummyClass::Msg("Hello, world!");
return 0;
}
Вариант без использования классов:
// DLLtest.cpp : Defines the entry point for the console application.
//#include "stdafx.h"
#include "mydllmodule.h"using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
ShortBeep();
Msg("Hello, world!");
return 0;
}
5. Осталось скомпилировать наше приложение (Build -> Build Solution или правой кнопкой на папку DLLtest, выбираем Build), переписать скомпилированную C:VSPROJMyDLLDebugMyDLL.dll в папку C:VSPROJDLLtest (иначе при старте DLLtest.exe будет выдаваться сообщение, что не найден файл библиотеки MyDLL.dll), и запустить приложение DLLtest на выполнение. Щелкаем правой кнопкой в Solution Explorer на DLLtest, выбираем в контекстном меню Set as StartUp Project. Затем выбираем Debug -> Start. Прозвучит короткий звуковой сигнал и появится окно с сообщением «Hello, world!». Отлично — наша DLL загружается и работает!
[Пути поиска библиотек DLL при запуске приложения]
При запуске приложения Windows выполняет поиск библиотек DLL в следующей последовательности:
1. Каталог, в котором находится исполняемый модуль текущего процесса.
2. Текущий каталог.
3. Системный каталог Windows (обычно это папка System32). Путь к этому каталогу извлекается с помощью функции GetSystemDirectory.
4. Каталог Windows. Путь к этому каталогу извлекается с помощью функции GetWindowsDirectory.
5. Каталоги, указанные в переменной среды PATH.
Примечание: переменная среды LIBPATH не используется.
[Ошибки в проектах с DLL]
1. <имя_программы> fatal error LNK1104: cannot open file ‘путь_до_папки_проекта_DLLDebugимя_файла_библиотеки.lib’, например:
DLLtest fatal error LNK1104: cannot open file ‘VsprojMyDLLDebugMyDLL.lib’
Такая ошибка произошла потому, что в модуле кода DLL (в нашем примере это mydllmodule.cpp) забыли подключить заголовок mydllmodule.h (по сообщению об ошибке догадаться невозможно, в чем проблема). Именно в этом заголовке используются атрибуты функций DLL (__declspec(dllexport)). Исправление ошибки: в нашем примере добавить в файл mydllmodule.cpp строчку #include «mydllmodule.h».
2. Не удалось найти компонент — «Приложению не удалось запуститься, поскольку < имя.dll > не был найден. Повторная установка приложения может исправить эту проблему.»
Проблема решается, если положить в путь поиска нужную DLL (для нашего примера файл MyDLL.dll нужно положить в папку C:VSPROJDLLtest). Самое лучшее решение — настроить команду в Post-Build Event, которая будет автоматически выполнить копирование DLL в папку отладки программы, которая использует эту DLL. Настраивается Post-Build Event просто, процесс по шагам, на нашем примере проектов MyDLL и DLLtest (предполагается, что обе папки проектов находятся на одном уровне в файловой системе, и входят в один Solution среды разработки Visual Studio, см. [3]):
1. Сначала нужно настроить порядок компиляции проектов в Solution. DLL должна компилироваться первой. Порядок компиляции настраивается через свойства Solution, контекстное меню Project Build Order…
Порядок проектов в списке можно поменять с помощью закладки Dependencies, которая определяет, какой проект от какого зависит. Первым в списке в нашем примере должен быть проект MyDLL.
2. Теперь осталось в проекте MyDLL настроить Post Build Event, копирующее результат компиляции — файл MyDLL.dll в папку Debug проекта DLLtest. Щелкаем правой кнопкой в Solution Explorer на проекте MyDLL, выбираем Properties -> Configuration Properties -> Build Events -> Post-Build Event -> вставляем в поле Command Line строку cmd /C copy /Y $(TargetPath) $(ProjectDir)..DLLtestDebug$(TargetFileName).
[Как отлаживать код DLL в Visual Studio]
В IDE есть приятная возможность отладки DLL по тексту исходного кода, однако это настраивается не слишком очевидно. Процесс по шагам (на нашем примере проектов MyDLL и DLLtest).
1. Сначала нужно задать при отладке стартовым приложением в Solution проект с DLL.
2. Нужно убедиться, что оба проекта MyDLL и DLLtest скомпилированы в конфигурации для отладки Debug.
3. Нужно настроить в свойствах проекта MyDLL запуск внешнего приложения, вызывающего нашу DLL. Щелкаем правой кнопкой в Solution Explorer на проекте MyDLL, выбираем Properties -> Configuration Properties -> Debugging -> в поле Command вводим строку $(ProjectDir)..DLLtestDebugDLLtest.exe.
Теперь можно ставить точки останова в исходном коде DLL, и отлаживать его, как обычный код. Если у Вас не работает отладка по коду DLL, то возможно, что-то не так с символами отладки (отладочной информацией). Если отладочная информация по коду DLL недоступна, то точки останова в DLL будут в виде коричневых кружков со знаками вопроса. Разобраться с проблемой загрузки символов может помочь просмотр модулей Debug -> Windows -> Modules. На скриншоте показана как раз такая проблема с отладкой.
Напротив модуля MyDLL.dll в столбце Information стоит No Symbols Loaded, что означает, что отладочная информация по коду DLL недоступна или ошибочна. Решить проблему может помочь полная рекомпиляции обоих проектов MyDLL и DLLtest, входящих в Solution. Выбираем в меню Build -> Rebuild Solution, выбираем Debug -> Start, и теперь отладка по исходному коду DLL работает.
[Ссылки]
1. Walkthrough: Creating and Using a Dynamic Link Library.
2. Search Path Used by Windows to Locate a DLL.
3. Исходный код проектов MyDLL и DLLtest .
4. bphelper — мастер поиска ошибок при отладке DLL.