Main Menu

Visual Studio Runtimes

Most libraries (both static and dynamic) link with the C-runtime. At link-time, all of the dependent libraries (sdk's) need to reference the same runtime, or else you can run into obscure and difficult to debug problems. Visual Studio comes with multiple versions of thestandard library. You can select it under "Properties", "Configuration Properties", "C/C++ code generation", "Runtime Library".

below a screenshot showing the dialog in Visual Studio 2010:

 

 Basically you have the following options:

switchnamestatic or dynamicdebugLinked with.vcxproj <RuntimeLibrary>
/MT Multi-threaded Static (runtime linked statically into exe/lib) No LIBCMT.lib MultiThreaded
/MTd Multi-threaded Debug Static (runtiime linked statically into exe/lib) Yes LIBCMTD.lib  
/MD Multi-threaded DLL Dynamic (load runtime from msvcrt*.dll) No MSVCRT.lib  
/MDd Multi-threaded Debug DLL Dynamic (load runtime from msvcrt*.dll) Yes MSVCRTD.lib  

 

LNK4098: defaultlib "LIBCD" conflicts with use of other libs

Now when one or more of your libraries are linked with a different runtime, the linker will issue a warning: 

"LINK : warning LNK4098: defaultlib "LIBCD" conflicts with use of other libs; use /NODEFAULTLIB:library".

Now you can follow the compiler suggestion and blissfully ignore it - which is the worst way to 'solve' it. To do this, open your project properties, select "linker", "general" and enter the library you want to exclude, for example "libcmt.lib". Alternatively enter /NODEFAULT:lib  in the linker commandline options.

The better alternative is to figure out what the offending library is which is using a different runtime. The most common one used is /MD(d). To determine this you have several approaches. 

First off, you should know which libraries you are actually linking with. 

You can look at the linker-settings to see this. 

<todo: linker-settings screenshot>

Besides these, you should search the code for #pragma comment(lib, "xxx.lib") as these libraries will also be linked into your library/executable.

You can also let the linker tell you which libraries it wants to link. Under "linker" change the "Show Progress" to "/VERBOSE:LIB" and do a (re)build of your solution - then it will show you a list of libraries.

 

Determining offending library

Now to figure out which ones is compiled with the wrong runtime you have several options:

1. Manually open the solutions for your libraries and check the compiler settings

2. Use a "find in files" in *.vcxproj and look for "<RuntimeLibrary>MultiThreaded</RuntimeLibrary>" (for /MT this xml-node will contain "MultiThreaded").

3. Use dumpbin (installed with the visual studio tools) on each library to figure out which runtime it requires. 

<todo: example batch>

Note that for some lib's it doesn't show which runtime they are linked with!

<todo: example output of dumpbin, example of when it doesn't work>

 

Once you figure out the offending library, you will need to set it to the correct runtime and rebuild it from sourcecode. After that, this warning will go away.

 

lnk1169 (multiply defined symbols)
lnk2001 (unresolved external)

 

LNK1169 (multiply defined symbols)

Instructing the linker to link our custom library (which contains overrides for memory management) with #pragma comment(lib, "xxx.lib") we'll end up with a linker warning:

1>xxx.lib(memory.obj) : error LNK2005: "void __cdecl operator delete(void *)" (??3@YAXPAX@Z) already defined in MSVCRT.lib(MSVCR100.dll)
1>fatal error LNK1169: one or more multiply defined symbols found 

The solution is to make sure xxx.lib is linked FIRST, i.e. before the system libraries ( %(AdditionalDependencies). 
Remove the #pragma comment line and add the "xxx.lib" to the project-properties/linker/input/additional dependencies 

linker LNK2001 (unresolved external) 

Linker Errors, due to missing "system" libraries 

Open project-properties / linker / input and click the "Additional Dependencies"-arrow-down, edit,
make sure "inherit from parent ... " is selected"..." for and click "ok" to add it to the system libraries... 

... looking like this:

 

Subversion (svn)


svn repository not valid for xcode
svn revert commit
svn undo revert



svn repository not valid for xcode

When adding a new repository to xcode4, the repository might not be recognized as valid. This can be because the password is not accepted. In this case, whatever password you type in the repository-dialog in xcode will not be accepted (even if it's a valid). You will see the message "unable to load revisions".
What you need to do it force svn to ask you for a password in the terminal.

Use spotlight and open 'terminal' Type 'svn co --username=myname svn://www.mydomain.com:port/svn/myrepository/ . svn will now ask you for the password - enter it. Now switch back to the repository browser in xcode4 and it will be recognized (green little dots instead of red ones)

xcode4 repository svn mac osx

svn revert commit


To revert the changes from one specific (previous) commit:
revision message

100 more final changes

99 final changes

98 some changes which we wanted to test

Right-click in windows-explorer on your repository to open the torsoiseSVN shell select tortoise-svn/show log in the revision-history, right-click on the one you want to revert (in our example, revision '98') select 'revert changes from this revision' This will reverse-merge the changes into your local copy. The repository isn't changed - so to make the revert 'final' you need to commit it back into your repository. This will create a new revision '101' which undoes the changes from '98'.

svn undo revert


Now assume that we come to the conclusion we need to get back the changes from '98' again. How can we do this? Well, we can do this by reversing the commit which reversed commit 98. So effectively, we'll 'reverse commit 101' and then commit this back into the repository as revision 102
revision message

102 reverted commit 101 (so in effect we re-applied commit 98)

101 reverted commit 98

100 more final changes

99 final changes

98 some changes which we wanted to test

diablo3

introduction
models & animations
octree
physics-mesh
navmesh
.obj-exporter

Introduction

Recently I started playing diablo 3. I quickly was curious on how the models looked and googled a bit. It was easy to find an mpq-extractor, but the app2obj-converters didn't work because the fileformat was changed for "reaper of souls". I googled a bit more and found information on the old fileformat and took a look how much different the new format was.  

models & animation

Animation frames calculated in my experimental engine. For quick experimentation I did the calculations in my engine and exported the result to .obj. 

And applying the keyframe to the mesh - also exported to .obj

Next step will be to use the calculated meshes and visualize them inside my engine. 

mesh-octree

Models can store an optional octree. Here an example for one of the gate-meshes.

 

physics mesh

Physics-mesh of the above gate-model. 


navmesh / navgrid

Tristram with nav-cells on the left ( no-go being the ones with an 'x' inside) and with the nav-grid on the right side. 

  

.obj exporter

I had a few requests for an exported and copied & pasted the import/export code from my engine and put it into a separate project. So for people who want to experiment, attached below is the converter for the diablo3 reaper of souls .app format (v260). It was compiled with visual studio 2013. If you run it and get a message about a missing msvcrt*.dll, you need to download the visual studio runtime (for free) from the microsoft website. 

Note that it only supports basic meshes - so no animations or any other of the above stuff like physicsmeshes or the navigation-meshes.

If you - like me - don't like running executables, I would suggest to create a virtual machine, make a snapshot, run the executable to convert whatever models you want and then just revert to the snapshot.

usage: d3rs_app2obj.exe infile.app [outfile.obj]

No warranty is given - use at your own risk!
Enjoy!

SQL database tips

Microsoft SQL-express/SQL-server database tips:

backup database schema
backup database contents
restore database query
restore database with inno-setup
scheduled database backup
Create stored procedures
run stored procedures from command-line


backup database schema

To backup the sql schema (database layout) start "SQL Management Studio". Go to the object-explorer and right-click your database. Select "Tasks/Generate Scripts"

export database schema, sql backup database

Now click through the dialogs (leave settings at default)
  • Select "Script Entire Database and all database objects"
  • Either save to file, clipboard or query window (depending on your needs)
To restore the database schema, open a 'new query', copy & paste the results of the backup in this window and execute it.

backup database contents

To backup the contents of your database to a file, create a batch-file named 'backup.bat' which looks like this:
Note: replace "mydatabase" with the actual name of the database you want to backup!
rem If you get "[SQL Server Native Client 10.0] Named Pipes Provider: Could not open a connection to SQL Server [2]."
rem Run the sql server configuration manager and check that tcp/ip is enabled and assigned to port 1433!
mkdir C:\database\backup
icacls C:\database\backup /GRANT "NETWORK SERVICE":(OI)(CI)(F)
osql -E -r -i backup.sql
and create another script named "backup.sql" which looks like this:
use master
backup database mydatabase to disk = 'C:\Database\backup\mydatabase.db'
go
exit
go
The only thing remaining to is to make the actual database backup by running your script.

restore database query

Execute the following script in sql management studio to restore your database backup:
 Restore FILELISTONLY FROM DISK='C:\database\backup\mydatabase.db'
To restore a database we need to find the "logical name" and "log file" to restore the database to a new path. This query allows us to get these names:
osql -E .\SQLEXPRESS -r -i restore.sql
create a batch-file called "restore.sql" and use the logical name and the log name we got from the above command:
use master
alter database mydatabase set offline with rollback immediate
go
sp_detach_db mydatabase,TRUE,TRUE
go
restore database mydatabase from disk = 'C:\Database\backup\mydatabase.db' with replace, move  to C:\database\db\mydatabase.mdf, move  to c:\database\db\mydatabase.ldf
go
exit
go
With the above back-file, we can restore the database contents.

restore database with inno-setup

If you like convenience, then we can automate the above backup/restore steps a bit futher. When creating a backup, we can additionally create an inno-setup installer. To restore the database you only run the installer and click 'next' a few times - done. Anyone can backup and restore a database with that system!

First we need to add the following line to the 'backup.bat' batch-file:
rem change the path to inno-setup as necessary!
if exist "C:\Program Files\Inno Setup 5\iscc.exe" "C:\Program Files\Inno Setup 5\iscc.exe" restore.iss
Now we need the restore.iss script, which looks like this:
[Setup]
AppId={{D60ABCCF-93DF-4D7C-BCA6-7960578B7D2D}
AppName=Database restore
AppVerName=Database Restore
DefaultDirName={pf}
OutputDir=.
OutputBaseFilename=setup
AppPublisher=Kalmiya
AppCopyright=
AppPublisherURL=http://www.kalmiya.com/
AllowNoIcons=yes
PrivilegesRequired=admin
Compression=lzma
SolidCompression=yes
Uninstallable=false
ShowLanguageDialog=no
LanguageDetectionMethod=none
DisableProgramGroupPage=yes
DisableDirPage=yes
DisableReadyPage=yes
ArchitecturesInstallIn64BitMode=x64 ia64

[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"

[Dirs]
Name: "C:\Databases"; AfterInstall: SetPermissions;

[Files]
Source: "restore.sql"; DestDir: "{tmp}"; AfterInstall: UnpackDB(); Flags: ignoreversion
Source: "C:\Databases\mydatabase.db"; Flags: dontcopy

[Run]
Filename: "OSQL";	StatusMsg: "Installing database..."; Parameters: "-E {code:server} -r -i {tmp}\restore.sql"; Flags: runhidden

[Registry]
Root: HKLM; Subkey: "SOFTWARE\dbconfig"; ValueType: string; ValueName: "dbcfg"; ValueData: "{code:dbcfg}"

[Code]

var
  Page: TInputQueryWizardPage;

procedure InitializeWizard;
begin 
	Page := CreateInputQueryPage(wpWelcome,'Configure SQL Server', 'Please define sql-settings','');
	Page.Add('SQL Server Instance Name (usually . or .\SQLEXPRESS)',False);
	Page.Values[0] := ExpandConstant('{reg:HKLM\SOFTWARE\dbconfig,dbcfg|server=.\SQLEXPRESS;}');
end;

function dbcfg(Param: String): String;
begin
  Result := Page.Values[0];
end;

function server(sx:string):string;
var
 s:string;
 i,j:integer;
begin
  // example regkey contents: datalayer=SqlServer;server=.\SQLEXPRESS; database=mydatabase;user id=sa;password=mypassword;trusted_connection=True
  s := ExpandConstant('{reg:HKLM\Software\dbconfig,dbcfg|;server=.;}');
	s := Copy(s,Pos('server=',s)+7, 1000);
	Delete(s,Pos(';',s),1000);
	Result := '-S' + s;
end;

procedure UnpackDB();
var s: string;
rc : integer;
begin
	ExtractTemporaryFile('mydatabase.db');
	if not Exec('icacls','. /grant "NETWORK SERVICE":(OI)(CI)(F)',ExpandConstant('{tmp}'),SW_HIDE,ewWaitUntilTerminated,rc) then
	begin
	   MsgBox(SysErrorMessage(rc),mbError,MB_OK);
	end;

	// To figure value is needed behind the 'move' parameter look, run the below query in SQL management studio:
	// restore FILELISTONLY FROM DISK='C:\databases\mydatabase.db'

	s := #13#10 + 'restore database mydatabase from disk = ''';
	s := s + ExpandConstant('{tmp}\mydatabase.db');
	s := s + ''' with replace, move ''mydatabase'' to ''c:\Databases\mydatabase.mdf''';
	s := s + ', move ''mydatabase_log'' to ''c:\Databases\mydatabase.ldf''' + #13#10;
	s := s + 'go' + #13#10;
	s := s + 'exit' + #13#10;
	s := s + 'go' + #13#10;

	SaveStringToFile(ExpandConstant('{tmp}\restore.sql'), s, True);
	
end;

procedure SetPermissions();
var
  rc : integer;
begin
	if not Exec('icacls','. /grant "NETWORK SERVICE":(OI)(CI)(F)','C:\Databases',SW_HIDE,ewWaitUntilTerminated,rc) then
	begin
	   MsgBox(SysErrorMessage(rc),mbError,MB_OK);
	end;
end;

function InitializeSetup(): Boolean;
var
	s : string;
begin
	// version checks and such can be done here...
	Result := True;	
end;

If you run the backup.bat now, it will generate an inno-setup installer containing a backup of the database.
To restore, just run the installer.

scheduled database backup (windows)


Use windows 'Scheduled Tasks" and run your batch-file. Now you won't forget to run a regular database backup anymore!

create stored procedures


A store procedure is like a function running on the server, which we can call from the client. So for example, instead of doing a query, receiving results over the network and using these results to execute another query, stored procedures can execute both queries on the server and only return the final result, thus minimizing network load.

Another advantage is that stored procedures give an abstraction between the actual data-layout and the requested queries. If the database layout changes, you can locally go through your stored procedures and adjust them - instead of going through the entire codebase adjusting sql queries (note your compiler will not complain at compile-time about missing columns or tables - but rather at-runtime errors. In other words: you need extensive QA after database changes ).

Creating simple stored procedures for retrieving data.
  • Create a new database named 'mydb'
  • Create a table named 'mytable'
  • Add a solumn 'my_column' of type integer
  • Add a few entries
In the Object explorer, locate your database and browse to ' programmability / stored procedures'. We will create a stored procedures accepting one single parameter of type 'int'.

create stored procedures

After clicking "new stored procedure' remove the predefined text from the script-window and replace it with the sql query below. The "CREATE PROCEDURE" will actually insert the procedure into the sql database. Normally you can then execute it, but since it's a bit inconvenient to develop stored procedures, we will add code which executes the query with a hardcoded constant and then removes the sql stored procedures again. When you are done developing, you can remove everything after the 'test: ...'
-- create stored procedure, with 1 input parameter of type 'int'
USE [mydb]
GO
create PROCEDURE usp_test
@_my_param int 
AS

-- the sql query which should be executed
SELECT * from dbo.mytable where @_my_param=dbo.mytable.my_column;
go

-- test: execute using '1' as value for my_param
exec usp_test @_my_param=1; 
go

-- drop the stored procedure from the database
drop procedure usp_test;
go
Note: 'sp_' is reserved in sql for internal stored procedures, which means that when you prefix it like this you will get a (small) performance penalty. This is why our stored procedure is prefixed with "usp_" (for User-Stored-Procedure).

Running stored procedures from commandline

With SQL express comes a tool named 'bcp' (Bulk Copy Program). This commandline-tool can run your stored procedures
Open a commandprompt and enter the following command:
bcp "EXEC mydb.dbo.sp_test '1' " queryout test.txt -c -T
If you want the output to be in xml, you can change stored procedures like this:
-- the query which should be executed
SELECT * from dbo.mytable where @_my_param=dbo.mytable.my_column FOR XML RAW;

More Articles...

JSN Teki template designed by JoomlaShine.com