Commit 5e5a28c9 authored by Callum Prentice's avatar Callum Prentice
Browse files

First checkin

## Dullahan
#### What is it?
A headless browser SDK that uses the [Chromium Embedded Framework]( (CEF). It is designed to make it easier to write applications that render modern web content directly to a memory buffer, inject synthesized mouse and keyboard events and interact with web based features like JavaScript or cookies.
###### <font color="red">Important note</font>:
This is __very__ much an alpha release / first code drop. I have high hopes this will develop into something useful but there is still a lot of work to do first.
#### What could I use it for?
It might be useful in a number of situations - for example:
* Anywhere you want to render web content in a graphics application - e.g. help pages in an OpenGL based game
* VR based video chat and shared environments (I'm working on an app like this now)
* HTML/JavaScript based user interfaces E.G. a tablet based paradigm for VR
* Integration with JavaScript for automated site testing like [PhantomJS]( - not there at all yet but that's one of the main plans for the future
* Web page contents analysis - E.G:
* Capture images the top 500 web pages and count the top 5 colors in each.
* Capture a Google Maps traffic map of your commute for 24 hours and see how bad it is :)
* Web page capture to an image or a PDF file
* Lots more I haven't thought of yet
#### What is CEF?
From the [CEF Wiki]( page: The Chromium Embedded Framework (CEF) is an open source framework for embedding a web browser engine based on the Chromium core.
An essential site to visit when developing a CEF based application is the [CEF forum]( started and run by (I believe) the original author Marshall Greenblatt who is very generous with his time and expertise.
Building CEF locally is quite a task so Adobe kindly host builds for all supported platforms [here](
#### Which version of CEF does Dullahan use?
Dullahan been developed against the [CEF 3.2704]( build of CEF but with some small tweaks to take account of CEF interface changes etc. it should work with slightly older or more recent versions too.
#### What are the origins of this project?
Historically, the first incarnation was [LLCEFLib]( - a [Linden Lab]( internal library to render web content content inside [Second Life]( LLCEFLib had to support the outdated 32bit macOS version as well as many Second Life specific features so things became very disjointed and messy. This effort is an attempt to unburden the API from those requirements and provide a Windows only version that is much more generic and hopefully useful in other applications.
#### Is Windows, 32bit the only support platform?
For the moment yes. The 32bit version for macOS is no longer supported by CEF. One day, there will be a 64bit Windows version as well and ideally, at that point, the 64bit macOs version will be added too. No plans for a Linux version but if you'd like to help, please let me know.
#### Which version of the C++ runtime library does it use?
For historical reasons, both it and the version of CEF in this repository are built with the C++ runtime library set to <tt>Multi-threaded DLL</tt> / <tt>Multi-threaded Debug DLL</tt>.
#### How do I build Dullahan?
* Download or clone the source code here
* Build or grab the version of CEF you want to use (See below)
* Ensure Microsoft Visual Studio 2013 (update 4) is installed (it might work with other versions but that is untested)
* Open <tt>dullahan.sln</tt>.
* Select the Release or Debug configuration and build the solution in the normal fashion.
* If all goes well, you can set one of the example applications as the startup project and try it.
#### Binary distribution of example applications
If you would like to try the Dullahan example applications without having to build them, thee is a zipped binary distribution in the <tt>bin</tt> folder. It contains all the CEF/Chromium runtime files as well as the example executables.
#### Which files do I need in my own project?
The main benefit of using Dullahan vs raw CEF is that you simply include the <tt>dullahan.h</tt> header file in your application and link against the <tt>dullahan.lib</tt> library along with two small CEF ones. Then, copy over the various CEF/Chromium runtime files along side your application - see the post-build step for the examples in Visual Studio for a list - and you are ready to go.
#### How do I use it?
The short answer is look at the code in the <tt>examples</tt> folder and <tt>dullahan.h</tt>. Generally speaking, you create an instance of the library, call <tt>init()</tt> and either (a) regularly call the <tt>update()</tt> function in your own message loop or the <tt>run()</tt> function if you don't have a message loop and want to use CEFs (e.g. a console application to save a web page as a bitmap). You can hook up a callback to be notified when the contents of the page changes and get access to the raw pixels. You can synthesize mouse and keyboard events and send them into the page. Finally, when you want to exit, make sure the <tt>onRequestExit</tt> callback is hooked up and call the <tt>requestExit()</tt> method. When the library and CEF have cleaned everything up, your callback will be triggered and you can call <tt>shutdown()</tt> before exiting normally.
#### Grabbing CEF
* Make sure [CMake]( is installed on your system
* Grab a Windows 32-bit build of CEF from [](
* Extract the 7Zip archive to a folder in an easy to find place - I use the desktop
* Edit the <tt>tools/make_dullahan_cef_pkg.bat</tt> batch file - specifically, the lines at the top of the file that set the CEF folder you just unpacked and the destination folder of the Dullahan compatible package.
* Run the batch file
* If all goes well, you will end up with a Dullahan CEF package in the <tt>DST_DIR</tt> folder you set
* Move that to the <tt>cef</tt> folder in this project, edit the <tt>src/dullahan.props</tt> file and update the <tt>CEF_DIR</tt> variable to point to the folder
* Build Dullahan
If this step failed then you will have to inspect the batch file. Generally speaking, this is what it does:
* Run CMake to generate the solution and projects files for LibCEF DLL wrapper
* Change the <tt>libcef_dll_wrapper -> Properties C++ -> Code Generation</tt> settings to <tt>Multi-threaded DLL</tt> (Release configuration) and <tt>Multi-threaded Debug DLL</tt> (Debug configuration)
* Build everything
* Copy files to the right place
Another option is to build the whole thing from scratch. This is necessary if you want to make changes to the Chromium code or perhaps turn on the proprietary media codecs support which is not available in the [CEF Builds]( versions. For more information on how to do this, look online or inspect the <tt>tools/build_cef.bat</tt> batch file.
#### What is left to do before the first real release?
* Consider using CMake to generate the Dullahan project files
* Add support for 64bit windows, macOS and Linux versions
* Implement proper Dullahan <--> JavaScript interoperability
* Improve the documentation
* Try to find a way to grab CEF builds automagically vs that crazy build steps in the docs
* Make sure all the features are used in the examples to help understand usage
* Unit tests everywhere
* Add support for different pages on each side of the Web Cube example
* Lots and lots more... please help if you can.
#### What is <tt>dullahan_src_hash.hpp</tt>
In an effort to come up with a way to uniquely identify a version, I experimented with taking an MD5 hash of all the source code and using part of that in the version number string. A Pre-Build in the Visual Studio Project file step does this and writes out <tt>dullahan_src_hash.hpp</tt>. The hash in this header file is then combined with the CEF version, the Chrome version it represents as well as a Dullahan version into a single string that uniquely identifies the build. I'm still not sure this is a good idea but I'll leave in there until someone explains to me how stupid it is.
#### Why the name?
[Seemed appropriate](
#### Binary distribution of Dullahan example applications
See [examples source](../examples/ for more details of each app.
#### Put your CEF builds here before you build Dullahan - they are ignored by the repository.
See the main for details on get and build CEF.
\ No newline at end of file

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.31101.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dullahan", "src\dullahan.vcxproj", "{A5779E35-7761-4105-8E1D-42477EEB9503}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dullahan_host", "host\dullahan_host.vcxproj", "{F52DE408-6276-4AAD-AB15-B91090ED6B89}"
ProjectSection(ProjectDependencies) = postProject
{A5779E35-7761-4105-8E1D-42477EEB9503} = {A5779E35-7761-4105-8E1D-42477EEB9503}
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{BABB4740-635A-4608-9AA9-74895E3D8C93}"
ProjectSection(SolutionItems) = preProject
examples\ = examples\
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "console", "examples\console\console.vcxproj", "{C57043FE-CECC-4DDF-AF8A-4D9D3EBB8836}"
ProjectSection(ProjectDependencies) = postProject
{F52DE408-6276-4AAD-AB15-B91090ED6B89} = {F52DE408-6276-4AAD-AB15-B91090ED6B89}
{A5779E35-7761-4105-8E1D-42477EEB9503} = {A5779E35-7761-4105-8E1D-42477EEB9503}
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{4A4120F0-1335-4E61-B7A5-8896242E4B84}"
ProjectSection(SolutionItems) = preProject =
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "webcube", "examples\webcube\webcube.vcxproj", "{0797BC6E-9666-48CB-8605-26AB11801F67}"
ProjectSection(ProjectDependencies) = postProject
{F52DE408-6276-4AAD-AB15-B91090ED6B89} = {F52DE408-6276-4AAD-AB15-B91090ED6B89}
{A5779E35-7761-4105-8E1D-42477EEB9503} = {A5779E35-7761-4105-8E1D-42477EEB9503}
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simplegl", "examples\simplegl\simplegl.vcxproj", "{3F3791D1-A5C4-4141-8C73-C7E44EBA6782}"
ProjectSection(ProjectDependencies) = postProject
{F52DE408-6276-4AAD-AB15-B91090ED6B89} = {F52DE408-6276-4AAD-AB15-B91090ED6B89}
{A5779E35-7761-4105-8E1D-42477EEB9503} = {A5779E35-7761-4105-8E1D-42477EEB9503}
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A5779E35-7761-4105-8E1D-42477EEB9503}.Debug|Win32.ActiveCfg = Debug|Win32
{A5779E35-7761-4105-8E1D-42477EEB9503}.Debug|Win32.Build.0 = Debug|Win32
{A5779E35-7761-4105-8E1D-42477EEB9503}.Release|Win32.ActiveCfg = Release|Win32
{A5779E35-7761-4105-8E1D-42477EEB9503}.Release|Win32.Build.0 = Release|Win32
{F52DE408-6276-4AAD-AB15-B91090ED6B89}.Debug|Win32.ActiveCfg = Debug|Win32
{F52DE408-6276-4AAD-AB15-B91090ED6B89}.Debug|Win32.Build.0 = Debug|Win32
{F52DE408-6276-4AAD-AB15-B91090ED6B89}.Release|Win32.ActiveCfg = Release|Win32
{F52DE408-6276-4AAD-AB15-B91090ED6B89}.Release|Win32.Build.0 = Release|Win32
{C57043FE-CECC-4DDF-AF8A-4D9D3EBB8836}.Debug|Win32.ActiveCfg = Debug|Win32
{C57043FE-CECC-4DDF-AF8A-4D9D3EBB8836}.Debug|Win32.Build.0 = Debug|Win32
{C57043FE-CECC-4DDF-AF8A-4D9D3EBB8836}.Release|Win32.ActiveCfg = Release|Win32
{C57043FE-CECC-4DDF-AF8A-4D9D3EBB8836}.Release|Win32.Build.0 = Release|Win32
{0797BC6E-9666-48CB-8605-26AB11801F67}.Debug|Win32.ActiveCfg = Debug|Win32
{0797BC6E-9666-48CB-8605-26AB11801F67}.Debug|Win32.Build.0 = Debug|Win32
{0797BC6E-9666-48CB-8605-26AB11801F67}.Release|Win32.ActiveCfg = Release|Win32
{0797BC6E-9666-48CB-8605-26AB11801F67}.Release|Win32.Build.0 = Release|Win32
{3F3791D1-A5C4-4141-8C73-C7E44EBA6782}.Debug|Win32.ActiveCfg = Debug|Win32
{3F3791D1-A5C4-4141-8C73-C7E44EBA6782}.Debug|Win32.Build.0 = Debug|Win32
{3F3791D1-A5C4-4141-8C73-C7E44EBA6782}.Release|Win32.ActiveCfg = Release|Win32
{3F3791D1-A5C4-4141-8C73-C7E44EBA6782}.Release|Win32.Build.0 = Release|Win32
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
GlobalSection(NestedProjects) = preSolution
{C57043FE-CECC-4DDF-AF8A-4D9D3EBB8836} = {BABB4740-635A-4608-9AA9-74895E3D8C93}
{0797BC6E-9666-48CB-8605-26AB11801F67} = {BABB4740-635A-4608-9AA9-74895E3D8C93}
{3F3791D1-A5C4-4141-8C73-C7E44EBA6782} = {BABB4740-635A-4608-9AA9-74895E3D8C93}
## Dullahan Examples
Some examples of how you might Dullahan. None of them are meant to be full featured, solid applications - just snippets of how you might do something in your own code.
Contributions showing off different features or ideas would be much appreciated.
## Console
Command line application to render a given URL to a bitmap and save it as a file called <tt>output.bmp</tt> in the current directory when the page finishes loading.
![Screen shot:](../docs/console.png?raw=true "Optional title")
* Pass a URL as command line parameter to render it
* Some sites are not fully complete when they complete loading (when the application saves the bitmap)
## SimpleGL
Super simple OpenGL (via [FreeGLUT]( application to render URLs to a full screen graphics texture.
![Screen shot:](../docs/simplegl.png?raw=true "Optional title")
* Mouse clicks work - keyboard does not
* FreeGLUT doesn't allow us to hook up required Dullahan exit steps so not implemented at all
## Web Cube
Slightly more complex OpenGL application using native Win32 because some of the calls to CEF (and therefore Dullahan) require native Windows messages.
![Screen shot:](../docs/webcube.png?raw=true "Optional title")
* Displays same URL on each side of a cube
* It would be easy to add a different one to each side but make the code longer
* Start page is a local HTML page in <tt>tools</tt> folder
* Move the cube by holding down SHIFT key and using mouse and mouse wheel
* Interact with pages via mouse and keyboard (somewhat) normally
* Press ESC key to exit
* Enter any URL into the top edit control
* Expose some features via menu - e.g. Print to PDF
@brief Dullahan - a headless browser rendering engine
based around the Chromium Embedded Framework
Example: capture a web page to image file with a console app
@author Callum Prentice - September 2016
#include <iostream>
#include <functional>
#include <string>
#include <fstream>
#include "dullahan.h"
dullahan* headless_browser;
unsigned char* gPixels = 0;
int gWidth = 0;
int gHeight = 0;
void writeBMPImage(const std::string& filename,
unsigned char* pixels,
int image_width, int image_height)
std::cout << "Writing output image (BMP) (" << image_width << " x " << image_height << ") to " << filename << std::endl;
std::ofstream img_stream(filename.c_str(), std::ios::binary | std::ios::out);
if (img_stream)
unsigned char file[14] =
'B', 'M', 0, 0, 0, 0, 0, 0, 0, 0, 40 + 14, 0, 0, 0
unsigned char info[40] =
40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x13, 0x0B, 0, 0, 0x13, 0x0B, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
int size_data = image_width * image_height * 3;
int size_all = size_data + sizeof(file) + sizeof(info);
file[2] = (unsigned char)(size_all);
file[3] = (unsigned char)(size_all >> 8);
file[4] = (unsigned char)(size_all >> 16);
file[5] = (unsigned char)(size_all >> 24);
info[4] = (unsigned char)(image_width);
info[5] = (unsigned char)(image_width >> 8);
info[6] = (unsigned char)(image_width >> 16);
info[7] = (unsigned char)(image_width >> 24);
info[8] = (unsigned char)(-image_height);
info[9] = (unsigned char)(-image_height >> 8);
info[10] = (unsigned char)(-image_height >> 16);
info[11] = (unsigned char)(-image_height >> 24);
info[20] = (unsigned char)(size_data);
info[21] = (unsigned char)(size_data >> 8);
info[22] = (unsigned char)(size_data >> 16);
info[23] = (unsigned char)(size_data >> 24);
img_stream.write((char*)file, sizeof(file));
img_stream.write((char*)info, sizeof(info));
const int image_depth = 4;
for (int i = 0; i < image_width * image_height * image_depth; i += image_depth)
const unsigned char red = *(pixels + i + 2);
const unsigned char green = *(pixels + i + 1);
const unsigned char blue = *(pixels + i + 0);
img_stream << blue;
img_stream << green;
img_stream << red;
void onPageChanged(const unsigned char* pixels, int x, int y, int width,
int height, bool is_popup)
std::cout << "Page changed" << std::endl;
gPixels = (unsigned char*)pixels;
gWidth = width;
gHeight = height;
void onLoadStart()
std::cout << "Page load started" << std::endl;
void onLoadEnd(int code)
std::cout << "Page load ended with code " << code << std::endl;
if (code == 200)
writeBMPImage("output.bmp", gPixels, gWidth, gHeight);
void onRequestExit()
std::cout << "Exit requested - shutting down and exiting" << std::endl;
int main(int argc, char* argv[])
std::string url = "";
if (argc == 2)
url = std::string(argv[1]);
headless_browser = new dullahan();
std::cout << "Dullahan console test" << std::endl << std::endl;
std::cout << "Capturing: " << url << std::endl << std::endl;
std::cout << "Dullahan version: " << headless_browser->dullahan_version() << std::endl << std::endl;
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
std::placeholders::_4, std::placeholders::_5, std::placeholders::_6));
dullahan::dullahan_settings settings;
settings.initial_width = 1024;
settings.initial_height = 3072;
settings.javascript_enabled = true;
settings.cookies_enabled = true;
settings.user_agent_substring = "Console Test";
settings.accept_language_list = "en-us";
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<ProjectConfiguration Include="Release|Win32">
<PropertyGroup Label="Globals">
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\..\src\dullahan.props" />
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\..\src\dullahan.props" />
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Command>if not exist $(OutputPath)cef.pak copy $(SolutionDir)$(CEF_DIR)\resources\*.* $(OutputPath)
if not exist $(OutputPath)libcef.dll copy $(SolutionDir)$(CEF_DIR)\bin\release\*.* $(OutputPath)
if not exist $(OutputPath)locales mkdir $(OutputPath)\locales
if not exist $(OutputPath)locales\en-US.pak copy $(SolutionDir)$(CEF_DIR)\resources\locales\*.* $(OutputPath)\locales</Command>
<Message>Copying run time files</Message>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Command>if not exist $(OutputPath)cef.pak copy $(SolutionDir)$(CEF_DIR)\resources\*.* $(OutputPath)
if not exist $(OutputPath)libcef.dll copy $(SolutionDir)$(CEF_DIR)\bin\release\*.* $(OutputPath)
if not exist $(OutputPath)locales mkdir $(OutputPath)\locales
if not exist $(OutputPath)locales\en-US.pak copy $(SolutionDir)$(CEF_DIR)\resources\locales\*.* $(OutputPath)\locales</Command>
<Message>Copying run time files</Message>
<ClCompile Include="console.cpp">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
\ No newline at end of file
Freeglut Copyright
Freeglut code without an explicit copyright is covered by the following
Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies or substantial portions of the Software.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
Except as contained in this notice, the name of Pawel W. Olszta shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Pawel W. Olszta.
freeglut for MSVC
This package contains freeglut import libraries, headers, and Windows DLLs.
These allow 32 and 64 bit GLUT applications to be compiled on Windows using
Microsoft Visual C++.
For more information on freeglut, visit
Create a folder on your PC which is readable by all users, for example
“C:\Program Files\Common Files\MSVC\freeglut\” on a typical Windows system. Copy
the “lib\” and “include\” folders from this zip archive to that location.
The appropriate freeglut DLL can either be placed in the same folder as your
application, or can be installed in a system-wide folder which appears in your
%PATH% environment variable. Be careful not to mix the 32 bit DLL up with the 64
bit DLL, as they are not interchangeable.
Compiling 32 bit Applications
To create a 32 bit freeglut application, create a new Win32 C++ project in MSVC.
From the “Win32 Application Wizard”, choose a “Windows application”, check the
“Empty project” box, and submit.
You’ll now need to configure the compiler and linker settings. Open up the
project properties, and select “All Configurations” (this is necessary to ensure
our changes are applied for both debug and release builds). Open up the
“general” section under “C/C++”, and configure the “include\” folder you created
above as an “Additional Include Directory”. If you have more than one GLUT
package which contains a “glut.h” file, it’s important to ensure that the
freeglut include folder appears above all other GLUT include folders.
Now open up the “general” section under “Linker”, and configure the “lib\”
folder you created above as an “Additional Library Directory”. A freeglut
application depends on the import libraries “freeglut.lib” and “opengl32.lib”,
which can be configured under the “Input” section. However, it shouldn’t be
necessary to explicitly state these dependencies, since the freeglut headers
handle this for you. Now open the “Advanced” section, and enter “mainCRTStartup”
as the “Entry Point” for your application. This is necessary because GLUT
applications use “main” as the application entry point, not “WinMain”—without it
you’ll get an undefined reference when you try to link your application.
That’s all of your project properties configured, so you can now add source
files to your project and build the application. If you want your application to
be compatible with GLUT, you should “#include <GL/glut.h>”. If you want to use
freeglut specific extensions, you should “#include <GL/freeglut.h>” instead.
Don’t forget to either include the freeglut DLL when distributing applications,
or provide your users with some method of obtaining it if they don’t already
have it!
Compiling 64 bit Applications
Building 64 bit applications is almost identical to building 32 bit applications.
When you use the configuration manager to add the x64 platform, it’s easiest to
copy the settings from the Win32 platform. If you do so, it’s then only necessary
to change the “Additional Library Directories” configuration so that it
references the directory containing the 64 bit import library rather
than the 32 bit one.
If you have problems using this package (compiler / linker errors etc.), please
check that you have followed all of the steps in this readme file correctly.
Almost all of the problems which are reported with these packages are due to
missing a step or not doing it correctly, for example trying to build a 32 bit
app against the 64 bit import library. If you have followed all of the steps
correctly but your application still fails to build, try building a very simple
but functional program (the example at works fine
with MSVC). A lot of people try to build very complex applications after
installing these packages, and often the error is with the application code or