Archive: DVD/CD verification


DVD/CD verification
Hi, I've made something for a game but I don't want people to be able to use it unless they have the original DVD/CD in the drive. How can I make the installer check if there is a valid version of the DVD or CD in a drive and if not valid, prevent installation?


This definitely cannot be done easily. There is a reason why companies like Sony have developed so-called "Copy Protection" system like SecuROM, that infect your computer using root-kit techniques. Keep in mind: If people want to copy your software, they can! They will crack it, emulate the original disc or whatever. In the end your legitimate customers will suffer from "Copy Protection" restrictions, while people that downloaded your software illegally from the net get a "clean" copy...


Hm, well I didn't expect to be able to use the actual SecuROM from the DVD. It would be enough I think if I can make the installer search all disk drives for a few specific files on the CD. If it cannot find them it won't install.

To bypass it someone would either have to crack the installer and find out which files are needed or make a copy of the original DVD or CD but that might not work if it has SecuROM and it's a royal pain in the ass. So either way I make it much more difficult and most people will simply buy the CD if they really want to install what I've made.

So would that be possible with NSIS? Scan for a number of files on all disk drives, if found allow installation, if not disallow installation?


The "Copy Protection" you describe makes no sens at all. What is the sens in checking for spcecific files? Even the most simple CD/DVD burning software can create a 1:1 copy of the original disk. This will not only copy ALL files, it will also create an exact copy of the filesystem. So you won't be able to distinguish the copy from the original, even when looking very closely. That's why all "real" copy protection systems put all kinds of crap on the disc: bad sectors, invalid filesystems and so on. They try to make it as hard as possible to read out the disc. And even if you manage to read the disc, your copy won't contain certain "errors" that the original did. So the absence of those "errors" will help to detect a "Copy". But again: This all requires special proprietary software. Also it will require special CD/DVD mastering, which you can't do "at home". And most important: "Copy Protection" systems that work like that are a slap in the face of your customers, because they can't make legitimate backups of the CD/DVD they payed money for. After all, people WILL crack your software, if they really want. No kind of "Protection" can ever prevent that...


Well to get a cracked version of the game, mount it on a drive is a pain and some people don't know how to do that. It will generate some sales for the game. It's the sim racing market too which is a very niche market so I don't think too many will complain about having to buy the DVD/CD.

There isn't any other way I can do it. So please, is it possible and if so how?


You are right, some people won't know how to crack the game. Most probably those are the people that payed money for the game and now can't make a legitimate backup copy and/or have to wait for the "disc verification" every time they run the game. The people that download your game from the net or even make money by selling unauthorized copies will know how to crack it - there is no doubt. But to answer your question: I highly doubt an effective "Copy Protection" can be created with NSIS alone. Of course such software exists and it could be integrated in NSIS via the Plugin interface. But you would have to buy/license that software from a company like Sony or Protection Technology. That won't be cheap...

Why not add a simple serial key to your application? This can be easily implemented in NSIS and it won't need a crappy "Disc Protection" system...


I don't want copy protection, I want it to scan all disk drives for specified files, if found it installs. I have to be "seen" to be using the software fairly and this method is considered fair. It will allow me to host the work on several sites and it will be considered legal.

People won't have to have the CD in the drive to run the game, only once while they install the mod will they need the CD in the drive. A serial key is no good because it doesn't require them to have the original CD. There has to be a connection.

I know this is possible because there is another team who have used NSIS to scan disk drives and verify the presence of specified files but so far they are not willing to tell me how they did it. I don't think they could have done anything more complex than what I'm suggesting here, like you say true copy protection would be far too complex for NSIS to do alone.


Use GetDrives then Locate or a simple IfFileExists/${If} ${FileExists}. It's all in the documentation under scripting reference and useful headers.

Stu


Originally posted by Rich_A
A serial key is no good because it doesn't require them to have the original CD. There has to be a connection.
Your "check for files" method doesn't require them to have the original CD/DVD in the drive either. Even the greatest noob can create a "dumb" copy of your disc. That disc will contain all the files that were on the original disc. Using this "simple" protection is like no protection at all. IMO a serial key would be the better method, because only users that have a VALID key will be able to install and a VALID key is only delivered with the original disc. Furthermore users can create legitimate backup copies of their own disc. And still they can only install with their original keys. If you really want to do the "check for files" method, do it as suggest by Afrow ...

Thanks, well how do I know what someone else's serial key is? Only the developer can give me that kind of information and they would never do it.


Originally posted by Rich_A
Thanks, well how do I know what someone else's serial key is? Only the developer can give me that kind of information and they would never do it.
Wait. I think you are the developer of your product, the product for which you create the installer. Isn't that the case? So you'll have to assign a valid key to every customer and check that key during setup. The easiest way would be some "online" validation, simply ask the server/database if the given key is valid. You could also blacklist compromised keys easily. If you don't want to check the key online, some cryptographic method will be needed to distinguish valid keys from invalid keys.

BTW: I highly doubt many users will give their own key, for which they have spend money, to other users or even share them online. Keys that are shared online will be blacklisted and become useless. So the original owner of the key would have to buy a another copy of the game in order to get a new working key. That definitely is a reason to keep your key private...

I think there is confusion here. I'm no selling anything, my purpose is to enable me to share my work. If I don't add this feature to my installer everyone says it's illegal and so my work cannot be shared easily, becomes an undergroud thing, less publicity etc etc. It's a conversion you see, by adding some kind of "original CD detection" into the installer it means that people have to have the original game before they can install it on the game I'm working on. It's the right thing to do otherwise it's theft, in the eyes of the community it's theft and is not tolerated but with some kind of CD verification it will be accepted. I know someone could easily mount a cracked version onto a virtual drive but that's not my problem or fault.

It's all very fickle but I'm glad NSIS was recommended to me because I'm liking it. Have found it very intuitive so far.

I'm trying to make the Uninstall only installed files work as seen in 2.07 of the manual. I get this error though ..

Usage: File [/nonfatal] [/a] ([/r] [/x filespec [...]] filespec [...] |
/oname=outfile one_file_only)
Error in macro File on macroline 3
Error in script "D:\Program Files\NSIS\Examples\EOAA GT 2.nsi" on line 115 -- aborting creation process


Line 115 which is ${File} /r D:\EOAA\Installer\Test .. why doesn't it work?

Section "Install Main"
SectionIn RO

; Set output path to the installation directory.
${SetOutPath} $INSTDIR

; Put file there
${File} /r D:\EOAA\Installer\Test

SectionEnd

SetOutPath and File are "native" instructions, they are not makros. So try like this:

Section "Install Main"

SectionIn RO

; Set output path to the installation directory.
SetOutPath "$INSTDIR"

; Put file there
File /r "D:\EOAA\Installer\Test\*.*"

SectionEnd


And please have a look in your "NSIS\Examples" folder :p

I'm working from the examples folder. If you search 2.07 in manual that's what I'm trying to do and it says File and other stuff needs to be makros. Here it is http://nsis.sourceforge.net/Uninstall_only_installed_files

Using what you suggests works but no uninstaller is created. I think this is the problem.

!insertmacro: macro "File" requires 2 parameter(s), passed 3!.


You must use the command WriteUninstaller in an install section to create an uninstaller! Also your installer must contain a section called "uninstaller", which will perform the uninstall. Last but not least using the File command in an uninstaller sections sounds bizarre. Using Delete makes more sens to get an application removed...

Please look at "NSIS\Examples\example2.nsi" ;)

Also use native native commands (File, Delete and so on) as they are provided by NSIS. Using makros is not required and should only be done, if there is a good reason. See the manual at "NSIS\NSIS.chm" for a scripting reference...


Yes I've worked with example2, the problem is I'm installing into another program or game and so I don't want the uninstaller to delete the folders which are part of the game's file structure, need it to delete only files which are installed which is what led me to this above URL, took some finding I can tell you but can't get it working ATM.


Originally posted by Rich_A
Yes I've worked with example2, the problem is I'm installing into another program or game and so I don't want the uninstaller to delete the folders which are part of the game's file structure, need it to delete only files which are installed which is what led me to this above URL, took some finding I can tell you but can't get it working ATM.
There is noting that prevents you from using the Delete command to only delete specific files, instead of entire directories...

Well it's prbably going to be over 500mb. No way I'm willing to put all files in manually. Unless there's a way to generate the code by pointing to a directory?


Originally posted by Rich_A
Well it's prbably going to be over 500mb. No way I'm willing to put all files in manually. Unless there's a way to generate the code by pointing to a directory?
What about creating a new subfolder and install all your files to that subfolder? Then you could simply remove the entire subfolder at uninstall, not touching anything else...

Yea it works, can use Delete $INSTDIR\Test\*.* .. thanks.

So, time to see if I can do the CD thing.


The most simple way would be checking all drives, from A to Z ;)

Section
IfFileExists "A:\Some Folder\Some File.foo" ItWasFound
IfFileExists "B:\Some Folder\Some File.foo" ItWasFound
IfFileExists "C:\Some Folder\Some File.foo" ItWasFound
...
IfFileExists "Z:\Some Folder\Some File.foo" ItWasFound

Abort "Origianl disc (or copy of it) was not found!"

ItWasFound:
; Put your install code here
...
SectionEnd


You could also use GetDriveType to check whether the drive is of type DRIVE_CDROM or not. Then you would accept the file only from a CD/DVD drive.

Yea that works a real treat. It's pointing to a 800mb file so they'll have to download the full crack to make it work and some I'm sure will buy the original game. Only problem I have now is language differences.

EDIT : I think they released the same version all across the world with English words on the box but the autorun asks you to choose one of five laguages. I very much doubt they renamed a few files only for the sake of exploration.


I still don't see the point in what you are doing. But be aware that "IfFileExists" only checks for the existence of the file, not for the size! So even a 0 byte dummy file would be accepted, as long as the name is correct. Furthermore you said that you want to check for files on the disc. Those files cannot be "renamed" for obvious reasons, no matter which language the user selects during install! In theory there might be differences between different language editions of the game, but most likely they use English filenames for all editions...


Yea I thought of the filesize issue too. Ideally I need to make it scan disk drives only and then look for a single file of specified size.


The point is unless I do this I'm breaking the law. By doing this I prove that I own a copy of the original game and so it is considered fair use.

I've read up on getdrives and locate. Is it possible to abort installation if locate fails? What's the code for that?

I've put locate in the function of getdrives and it seems to work but the installation continues regardless of the outcome. So if it can abort installation if locate file is not found I think it might work. This code makes an installer but it don't work.

${GetDrives} "CDROM" "scandisk"

Function scandisk

${Locate} ":\" "/L=F /M=x.x /S=1K" "Example1"

IfErrors 0 +2
MessageBox MB_OK "Error" IDOK +2
MessageBox MB_OK "$$R0=$R0"

FunctionEnd

Function Example1
StrCpy $R0 $R9
; $R0=":\x.x"

IfFileExists ":\x.x" ItWasFound

Abort "Origianl disc (or copy of it) was not found!"

ItWasFound:

FunctionEnd

Seems NSIS cannot do this, there needs to be some code which is a combination of Locate and GetDrives. Please help, otherwise I cannot release my work because I'm dead against free conversions. Another team has done this and people are buying the original CD to make it work. To be more specific, I'm using GTR2 as a platform to work from and I've converted it to rFactor because it has features I'm more interested in. They use the exact same engine.

If you have a donation system (can't see one) I'll donate some money if you can help me.


Kichik is the main developer of NSIS at this time. He receives the donations people give on the main NSIS page (bottom left corner has a donate button).

I don't understand the legality issue you are worried about. Does your software 'unlock' a game so it can be played without the original developer's restrictions (keyword/disc in drive/etc)? That's the only thing that I can think would make your software legally questionable. Even then, one could argue that you aren't violating the game copyright, the people that might misuse your software would do that. Your software (arguably) has non-violating uses (eg, reduce wear-and-tear on the original CD and the CDROM drive).

Don


Thanks. The reason is because I have to be seen to be doing the right thing, otherwise the community will not accept my work and also it makes me feel better, in fact I won't release anything if I cannot do this. The conversion consists of a lot of work from GTR2 and so without this verification people would be getting it for free. It's not a straight copy and I have updated and improved many aspects of the original work. It's a partial conversion. My main reason is so that the work is accepted by the community, it is not really a means of preventing cracks. In that sense I could use the ifFileExists but specifying a single file on a DVD or CD of specific size would be far better.


Let me get this straight here. You're porting content from one game to another and distributing copyrighted content with your work? There might be a few legal implications to that.

(First the disclaimer. I am not a lawyer and if you have doubts, see a qualified legal expert for further advice. This advice is not intended to replace advice from a real lawyer, and should not be treated as such. In no way will I be held responsible for actions recommended within this post.)

If you're making sure that the user owns a legal copy of the game, why not just search through the registry for an installed copy of the game, and then use CopyFiles to transfer files from that installation to your own installation directory and then patch things as necessary using VPatch? That will take care of two things, Fair Use and bandwidth.

Even if you take measures to ensure that the user has a legal copy of copyrighted content, you can't distribute that content without written permission from the publisher - Atari in this case. Distributing instructions to modify it through patches will be OK though, since none of the actual content is included, only a few checksums and offset values.

Also, using a patch-based approach will save you bandwidth. You probably did modify the game's files quite heavily, but how much of that 800MB is textures, models, sprites, etc. that is unmodified? Distributing patches will let you share your changes without having redundancy in there.

The approach I'd recommend is to search the Registry for an installation of GTR2 and use the data files from that. If it's not found, prompt the user for a directory containing the GTR2 data files. Then use CopyFiles and VPatch to perform the bulk of the installation. This way you're safely within legal bounds, but you don't have to take exhaustive measures to ensure that a user is properly licensed. If their cracked GTR2 data files got corrupted by a LimeWire virus then VPatch will fail with a checksum error anyway. Sure you can still use a cracked copy of GTR2, but this way you're ensuring that you can't be held responsible for distributing what Atari will consider "cracked" content. Hope that helps. And if I was way wrong and failed miserably at interpreting your goals, forgive me :)

--Dan


Well here's what someone else said about the legal matters ..

The reason for this is that RSC is a european corporation and legal decisions in the EU have declared that converting the content of games that you own to other games falls under the classification of fair use which means it is allowed. The DVD check verifies that you own the content in question.

By distribution I think you mean selling the installer, well I won't be doing that. It's for free except for the verification.

I'll look into what you've said but I'd really prefer DVD or CD verification because for all the people who have downloaded the crack, well it's a pain for them to burn it to a CD and I like that fact. Also it will generate more sales of the original game and I want that too so that it might help develop the genre further.

So I take it you don't think the code exists to do what I'm attempting? I think others would like to do it too.


Of course this code can be written for NSIS.

At worst, you write your own C Plugin that does what you are looking to do, and passes back "PASS" or "FAIL" to your Installer.

But personally, I think you won't even need to write a plugin. All the things you need are already in NSIS, you just need to experiment and figure out which ones work for you.

I think probably a combination of GetDrives, and then a combination of "${If} ${FileExists}" and a function to get the file size if the file exists.

To get the filesize, I bummed this code from some article/wiki/faq awhile ago (I can't remember the location right now...):

Function FileSize
Exch $R0 ;Grab the Inputed path file
System::Call 'kernel32::_lopen(t "$R0", i 0) i .r0' ; Call the API to open the file
System::Call 'kernel32::GetFileSize(i $0, i) i .r1' ; Call API to read file size
System::Call 'kernel32::_lclose(i $0) i' ; API to close the opened file
Push $1
FunctionEnd


Finally, I agree with most others here, what you are trying to do is kind of silly, there are so many ways to defeat what you are doing, that its almost laughable.


you don't need the system plugin to do that, just use FileSeek to the end and store the new location


I'm lost now! BTW this is not silly! How can generating more sales for the original title be silly!? If the game was uncrackable and it could not be copied this would work fine. Again it's not my fault that games get hacked, my problem is obeying the law and getting the work accepted by the community. If I don't do this, well several sites simply won't have anything to do with it and so not as many people will use it. Anyway this is another debate. I really need help with the code.

I don't know what I'm doing and it seems I need a degree to understand it. If someone could give me some code to work from that would be great. If it's as easy as you say it ought to be then it shouldn't take more than a few minutes of your time. I really would appreciate it and I'll donate some money to NSIS.


I have never used GetDrives, but presumably, your code would look something like:


!define FILE1_YOU_CARE_ABOUT "FILE1.exe"
!define FILE1_YOU_CARE_ABOUTSIZE "123456789"

${GetDrives} "CDROM" "CheckDrive"


Function CheckDrive
${If} ${FileExists} "$9\${FILE1_YOU_CARE_ABOUT}"
Push "$9\${FILE1_YOU_CARE_ABOUT}"
Call FileSize
Pop $R0
${If} $R0 == ${FILE1_YOU_CARE_ABOUTSIZE}
MessageBox MB_OK "PASSED!"
# Set some Global variable here as "passed".
${Endif}
${Endif}
FunctionEnd


Hm thanks Sheik, this is what I'm using ..

  !include "FileFunc.nsh"
!insertmacro Locate
!insertmacro GetDrives

Section "Example2 (required)"

!define FILE1_YOU_CARE_ABOUT "FILE1.exe"
!define FILE1_YOU_CARE_ABOUTSIZE "123456789"

${GetDrives} "CDROM" "CheckDrive"

SectionIn RO

; Set output path to the installation directory.
SetOutPath $INSTDIR

; Put file there
File "example2.nsi"
File /r D:\Test\*.*

; Write the installation path into the registry
WriteRegStr HKLM SOFTWARE\NSIS_Example2 "Install_Dir" "$INSTDIR"

; Write the uninstall keys for Windows
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Example2" "DisplayName" "NSIS Example2"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Example2" "UninstallString" '"$INSTDIR\uninstall.exe"'
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Example2" "NoModify" 1
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Example2" "NoRepair" 1
WriteUninstaller "uninstall.exe"

SectionEnd

Function CheckDrive
${If} ${FileExists} "$9\${FILE1_YOU_CARE_ABOUT}"
Push "$9\${FILE1_YOU_CARE_ABOUT}"
Call FileSize
Pop $R0
${If} $R0 == ${FILE1_YOU_CARE_ABOUTSIZE}
MessageBox MB_OK "PASSED!"
# Set some Global variable here as "passed".
${Endif}
${Endif}
FunctionEnd


But it fails to make an installer, says ..

Invalid command: ${If}

Invalid command: ${If} == You haven't included logiclib.nsh

I have a question dudes, what if there are more than one cd-rom drives on a system? And what if it is virtual cd-rom like daemon tools?


It would be great if I could prevent NSIS scanning virtual drives.

It's now saying this ..

Error: resolving install function "FileSize" in function "CheckDrive"
Note: uninstall functions must begin with "un.", and install functions must not


Originally posted by Red Wine
I have a question dudes, what if there are more than one cd-rom drives on a system? And what if it is virtual cd-rom like daemon tools?
It would accept the virtual disc, of course

As said before: This "Copy Protection" is a farce :rolleyes:

RedWine, Oh, I am not suggesting that this code is in any way smart... See my comment above about it being "silly" =)

He just seems so insistant on doing it, that oh well, what the heck...

Rich_A,
You need to include logiclib.nsh.

Also, my code was just a quasi-example. I literally wrote it while typing a response... I did not attempt to compile it or anything. Also, you need to change:

!define FILE1_YOU_CARE_ABOUT "FILE1.exe"
!define FILE1_YOU_CARE_ABOUTSIZE "123456789"

To be a file name and filesize that you know exists on the cdrom you are checking.


Originally posted by LoRd_MuldeR
It would accept the virtual disc, of course

As said before: This "Copy Protection" is a farce :rolleyes:
No no, the fact that the game can be cracked and copied is a farce but then again perhaps it's intentional.

Archive: DVD/CD verification


You also need to add in the code I gave above:

Function FileSize
Exch $R0 ;Grab the Inputed path file
System::Call 'kernel32::_lopen(t "$R0", i 0) i .r0' ; Call the API to open the file
System::Call 'kernel32::GetFileSize(i $0, i) i .r1' ; Call API to read file size
System::Call 'kernel32::_lclose(i $0) i' ; API to close the opened file
Push $1
FunctionEnd


Originally posted by LoRd_MuldeR
It would accept the virtual disc, of course

As said before: This "Copy Protection" is a farce :rolleyes:
If you ask me, the whole thread is a farce :down:

Originally posted by Sheik
You also need to add in the code I gave above:

Function FileSize
Exch $R0 ;Grab the Inputed path file
System::Call 'kernel32::_lopen(t "$R0", i 0) i .r0' ; Call the API to open the file
System::Call 'kernel32::GetFileSize(i $0, i) i .r1' ; Call API to read file size
System::Call 'kernel32::_lclose(i $0) i' ; API to close the opened file
Push $1
FunctionEnd
Yes it makes an installer now but it installs regardless of the DVD/CD being in the drive. I need it to abort if it cannot find the specified file of specified size.

No point talking about copy protection, that's not what I'm trying to do. I want verification. The fact that the game can be cracked, copied and mounted on virtual drive has nothing to do with me. Are you reading my posts or what?

Sure, the code I gave only does the checking for you.

You still need a "Var" that gets set to 0 or 1, to decide if you want to install or not.

Set it to 0 in the oninit function, then set it to 1 if you come across the file/size you are looking for.

Then before you allow the install, check to see if the variable it set to 1. If it is, install, otherwise bail.


Originally posted by Sheik
RedWine, Oh, I am not suggesting that this code is in any way smart... See my comment above about it being "silly" =)

He just seems so insistant on doing it, that oh well, what the heck...

Rich_A,
You need to include logiclib.nsh.

Also, my code was just a quasi-example. I literally wrote it while typing a response... I did not attempt to compile it or anything. Also, you need to change:

!define FILE1_YOU_CARE_ABOUT "FILE1.exe"
!define FILE1_YOU_CARE_ABOUTSIZE "123456789"

To be a file name and filesize that you know exists on the cdrom you are checking.
Suggesting code that you haven't already test doesn't sound as a good idea to me.

@ Rich_A
You should realize that you can't get some copy protection scheme unless you pay the dedicated designers for this.

Originally posted by Sheik
Sure, the code I gave only does the checking for you.

You still need a "Var" that gets set to 0 or 1, to decide if you want to install or not.

Set it to 0 in the oninit function, then set it to 1 if you come across the file/size you are looking for.

Then before you allow the install, check to see if the variable it set to 1. If it is, install, otherwise bail.
Fffffffffshhhhh, right over my head that one. I know people say, "In English please" but can I have that "In code please".

Here's what it looks like at the moment ..


!include "FileFunc.nsh"
!include "logiclib.nsh"
!insertmacro Locate
!insertmacro GetDrives

!define FILE1_YOU_CARE_ABOUT "FILE1.exe"
!define FILE1_YOU_CARE_ABOUTSIZE "123456789"

Section "Example2 (required)"

${GetDrives} "CDROM" "CheckDrive"

SectionIn RO

; Set output path to the installation directory.
SetOutPath $INSTDIR

; Put file there
File "example2.nsi"
File /r D:\Test\*.*

; Write the installation path into the registry
WriteRegStr HKLM SOFTWARE\NSIS_Example2 "Install_Dir" "$INSTDIR"

; Write the uninstall keys for Windows
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Example2" "DisplayName" "NSIS Example2"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Example2" "UninstallString" '"$INSTDIR\uninstall.exe"'
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Example2" "NoModify" 1
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Example2" "NoRepair" 1
WriteUninstaller "uninstall.exe"

SectionEnd

Function CheckDrive
${If} ${FileExists} "$9\${FILE1_YOU_CARE_ABOUT}"
Push "$9\${FILE1_YOU_CARE_ABOUT}"
Call FileSize
Pop $R0
${If} $R0 == ${FILE1_YOU_CARE_ABOUTSIZE}
MessageBox MB_OK "PASSED!"
# Set some Global variable here as "passed".
${Endif}
${Endif}
FunctionEnd

Function FileSize
Exch $R0 ;Grab the Inputed path file
System::Call 'kernel32::_lopen(t "$R0", i 0) i .r0' ; Call the API to open the file
System::Call 'kernel32::GetFileSize(i $0, i) i .r1' ; Call API to read file size
System::Call 'kernel32::_lclose(i $0) i' ; API to close the opened file
Push $1
FunctionEnd


It's installing like a normal installer at the moment regardless of DVD/CD being in drive or not.

I see you have a function "CheckDrive" specified, but do you ever call it?

If not, do it like this please:

Section "-CheckDriveSection"
Call CheckDrive
SectionEnd

Section "Example2 (required)"
...
SectionEnd

Function CheckDrive
...
FunctionEnd

Isn't it called on the ${GetDrives} line?


Quite possible. I have no idea what the ${GetDrives} makro does :confused:


Hi Sheik, so do the variable need to go in line

# Set some Global variable here as "passed".

If so how please, it's almost complete except for the abort.

I've also discovered that cracked version cannot be used online i.e. racing online. There is a online serial key and I've found the registry entry which is created after entering a valid online serial key. So is there such a thing as ifRegkeyExists?


Actually I don't think people will like having to have the original game installed. It only needs the CD verification. Sheik can you please give me the code for the variables you're talking about?


Managed to make ifFileExist search CDROM only but it's not checking file size at the moment. How can I do that?

  !include "FileFunc.nsh"
!include "logiclib.nsh"
!insertmacro Locate
!insertmacro GetDrives

!define FILE1_YOU_CARE_ABOUT "Some File.foo"
!define FILE1_YOU_CARE_ABOUTSIZE "123456789"

Section
${GetDrives} "CDROM" "checkdrive"
SectionEnd

Section "Example2 (required)"

SectionIn RO

; Set output path to the installation directory.
SetOutPath $INSTDIR

; Put file there
File "example2.nsi"
File /r D:\Test\*.*

; Write the installation path into the registry
WriteRegStr HKLM SOFTWARE\NSIS_Example2 "Install_Dir" "$INSTDIR"

; Write the uninstall keys for Windows
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Example2" "DisplayName" "NSIS Example2"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Example2" "UninstallString" '"$INSTDIR\uninstall.exe"'
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Example2" "NoModify" 1
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Example2" "NoRepair" 1
WriteUninstaller "uninstall.exe"

SectionEnd

Function checkdrive
IfFileExists "$9\${FILE1_YOU_CARE_ABOUT}" ItWasFound

Abort "Origianl disc (or copy of it) was not found!"

ItWasFound:
FunctionEnd

I'm not going to comment on the legality or ask why... But here's some code for you to try. (I just hacked this together, so you may run into a few syntax errors, but it should give you the basic idea.)

And this *should* work even if you have multiple CD drives.


!include "FileFunc.nsh"
!include "logiclib.nsh"
!insertmacro GetSize
!insertmacro GetDrives

!define FILE1_YOU_CARE_ABOUT "Some File.foo"
!define FILE1_YOU_CARE_ABOUTSIZE "123456789"

var FileDrive ; blank if file not exist

Section
StrCpy $FileDrive ""
${GetDrives} "CDROM" "checkdrive"
${If} "$FileDrive" == ""
Abort "Original disc (or copy of it) was not found!"
${EndIf}
${GetSize} "$FileDrive" "/M=${FILE1_YOU_CARE_ABOUT} /S=0k /G=0" $R1 $R2 $R3
${Unless} $R1 = ${FILE1_YOU_CARE_ABOUT_ABOUTSIZE}
Abort "Invalid file on target disk, $FileDrive!"
${EndUnless}
SectionEnd

Section "Example2 (required)"
; your install code here...
SectionEnd

Function checkdrive
${If} ${FileExists} "$9\${FILE1_YOU_CARE_ABOUT}"
StrCpy $FileDrive "$9"
Push "StopGetDrives"
${Else}
Push "continue"
${EndIf}
FunctionEnd

Thanks Comperio I'll try that later. Why not ask about legal issue, it's important isn't it? Many aren't sure about what is and is not legal. I think this topic has raised some issues for some people regarding the law. Also people don't like to talk about it because they're afraid they might be breaking it, but that's half the problem!

Read my posts here, I've already explained the situation. Conversions of games from one platform to another is not against the law so long as there is proof of purchase and money is not being made. It's considered "fair use". The installer is proof of purchase. I have baught this game and I'm using my own CD to make this installer work. Therefore I'm using it fairly and I'm within my rights. It's the same with any game but many titles have encryted data and I think there are laws against using and cracking encrytped data. But there is no encryption at all in GTR2, that's what's great about it.


Your code detects the file Comperio but the size code seems to error. The compiler says ..

1 warning:
unknown variable/constant "{FILE1_YOU_CARE_ABOUT_ABOUTSIZE}" detected, ignoring (macro:_=:1)

It creates the installer though and searches for the file, passes the file search but not the file size. Any ideas? Also, is size in bytes or .. ?


Looks like you found one of my typos... If that's the only one, consider yourself lucky! :D

Change "${Unless} $R1 = ${FILE1_YOU_CARE_ABOUT_ABOUTSIZE}"
to "${Unless} $R1 = ${FILE1_YOU_CARE_ABOUTSIZE}"

edit: Also, the size should be KB. If you want bytes, then I belive you can change the "k" to a "b". Look up the GetSize header in the appendix section of NSIS help for more info.


Lol so obvious. OK, I'll try it later thanks again.


Fanatastic it works! Even if it's 1 byte out it won't install. Many many thanks Comperio you are a Major Dude, will make donation now.


I know the last post here was a long time ago but I need more help. There are at least three version of this game available and there may be more. The code I have works for one installer only at a time because the different versions frustratingly have different names and different file sizes. Is there a way to list several files and file sizes, if it finds one it will continue installation?


Here is the relevant code ..

!include "FileFunc.nsh"
!include "logiclib.nsh"
!insertmacro GetSize
!insertmacro GetDrives

!define FILE1_YOU_CARE_ABOUT "XXXXXX.XXX"
!define FILE1_YOU_CARE_ABOUTSIZE "XXXXXXX"

var FileDrive ; blank if file not exist

Section
StrCpy $FileDrive ""
${GetDrives} "CDROM" "checkdrive"
${If} "$FileDrive" == ""
Abort "Message."
${EndIf}
${GetSize} "$FileDrive" "/M=${FILE1_YOU_CARE_ABOUT} /S=0B /G=0" $R1 $R2 $R3
${Unless} $R1 = ${FILE1_YOU_CARE_ABOUTSIZE}
Abort "Invalid file on target disk $FileDrive"
${EndUnless}
SectionEnd

Section "EOAA GT V1.00"
SectionIn RO

; Set output path to the installation directory.
SetOutPath $INSTDIR

; Put file there
File /r "X:\X\*.*"

; Write the installation path into the registry
WriteRegStr HKLM "SOFTWARE\EOAA GT" "Install_Dir" "$INSTDIR"

; Write the uninstall keys for Windows
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\EOAA GT" "DisplayName" "EOAA GT V1.00"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\EOAA GT" "UninstallString" '"$INSTDIR\Uninstall EOAA GT.exe"'
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\EOAA GT" "NoModify" 1
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\EOAA GT" "NoRepair" 1
WriteUninstaller "Uninstall EOAA GT.exe"
SectionEnd

Function checkdrive
${If} ${FileExists} "$9\${FILE1_YOU_CARE_ABOUT}"
StrCpy $FileDrive "$9"
Push "StopGetDrives"
${Else}
Push "continue"
${EndIf}
FunctionEnd

I'll make another donation if someone finds a way to do this?


Simply use ${OrUnless} and ${OrIf} where you check for size and file existence to add more cases.


Hi kichik, that's great that it's possible. Could you perhaps use my code and make an example, not sure where to or how to use what you're suggesting, gimme something to try please. I got all this code from this topic, I know the basics but whenever I try something there's always a typo or error.


For example:

${Unless} $R1 = ${FILE1_YOU_CARE_ABOUTSIZE}
${OrUnless} $R1 = ${FILE2_YOU_CARE_ABOUTSIZE}
${If} ${FileExists} "$9\${FILE1_YOU_CARE_ABOUT}"
${OrIf} ${FileExists} "$9\${FILE2_YOU_CARE_ABOUT}"

OK thanks will try some things there.


It's giving invalid file on target disk which means it failing unless all defined files are present I think.

Here's the code I've got ..


!define FILE1_YOU_CARE_ABOUT "x.x"
!define FILE1_YOU_CARE_ABOUTSIZE "123"
!define FILE2_YOU_CARE_ABOUT "x.x"
!define FILE2_YOU_CARE_ABOUTSIZE "123"
!define FILE3_YOU_CARE_ABOUT "x.x"
!define FILE3_YOU_CARE_ABOUTSIZE "123"

var FileDrive ; blank if file not exist

Section
StrCpy $FileDrive ""
${GetDrives} "CDROM" "checkdrive"
${If} "$FileDrive" == ""
Abort "Please insert GTR2 DVD or CD and try again, verification failed."
${EndIf}
${GetSize} "$FileDrive" "/M=${FILE1_YOU_CARE_ABOUT} /S=0B /G=0" $R1 $R2 $R3
${GetSize} "$FileDrive" "/M=${FILE2_YOU_CARE_ABOUT} /S=0B /G=0" $R1 $R2 $R3
${GetSize} "$FileDrive" "/M=${FILE3_YOU_CARE_ABOUT} /S=0B /G=0" $R1 $R2 $R3
${Unless} $R1 = ${FILE1_YOU_CARE_ABOUTSIZE}
${OrUnless} $R1 = ${FILE2_YOU_CARE_ABOUTSIZE}
${OrUnless} $R1 = ${FILE3_YOU_CARE_ABOUTSIZE}
Abort "Invalid file on target disk $FileDrive"
${EndUnless}
SectionEnd

Section "EOAA GT V1.00"
SectionIn RO

; Set output path to the installation directory.
SetOutPath $INSTDIR

; Put file there
File /r "X:\X\*.*"

; Write the installation path into the registry
WriteRegStr HKLM "SOFTWARE\EOAA GT" "Install_Dir" "$INSTDIR"

; Write the uninstall keys for Windows
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\EOAA GT" "DisplayName" "EOAA GT V1.00"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\EOAA GT" "UninstallString" '"$INSTDIR\Uninstall EOAA GT.exe"'
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\EOAA GT" "NoModify" 1
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\EOAA GT" "NoRepair" 1
WriteUninstaller "Uninstall EOAA GT.exe"
SectionEnd

Function checkdrive
${If} ${FileExists} "$9\${FILE1_YOU_CARE_ABOUT}"
${OrIf} ${FileExists} "$9\${FILE2_YOU_CARE_ABOUT}"
${OrIf} ${FileExists} "$9\${FILE3_YOU_CARE_ABOUT}"
StrCpy $FileDrive "$9"
Push "StopGetDrives"
${Else}
Push "continue"
${EndIf}
FunctionEnd

LogicLib.nsi has ElseUnless, seems to be working with ElseUnless need to do more testing though.


No ElseUnless allows installation to run regardless of file size has to be OrUnless but it's not working ATM.


This IMO ought to work, if it doesn't find file1, having file2 or file3 present will permit installer to run but for some reason it's giving the "Invalid file on target disk $FileDrive" error, I know file1 is present and of correct size so it can only mean that it's expecting file2 and file3 to be there also. Perhaps it needs OrGetSize?

Section
StrCpy $FileDrive ""
${GetDrives} "CDROM" "checkdrive"
${If} "$FileDrive" == ""
Abort "Please insert GTR2 DVD or CD and try again, verification failed."
${EndIf}
${GetSize} "$FileDrive" "/M=${FILE1_YOU_CARE_ABOUT} /S=0B /G=0" $R1 $R2 $R3
${Unless} $R1 = ${FILE1_YOU_CARE_ABOUTSIZE}
${GetSize} "$FileDrive" "/M=${FILE2_YOU_CARE_ABOUT} /S=0B /G=0" $R1 $R2 $R3
${OrUnless} $R1 = ${FILE2_YOU_CARE_ABOUTSIZE}
${GetSize} "$FileDrive" "/M=${FILE3_YOU_CARE_ABOUT} /S=0B /G=0" $R1 $R2 $R3
${OrUnless} $R1 = ${FILE3_YOU_CARE_ABOUTSIZE}
Abort "Invalid file on target disk $FileDrive"
${EndUnless}
SectionEnd

You can't lace ${GetSize} calls between ${Unless} and ${OrUnless}. Get all the sizes into variables and then compare them all at once, or get the size and compare separately.


I'm sorry I don't know what you mean can I have another example please?


${GetSize} "$FileDrive" "/M=${FILE1_YOU_CARE_ABOUT} /S=0B /G=0" $0 $R2 $R3
${GetSize} "$FileDrive" "/M=${FILE2_YOU_CARE_ABOUT} /S=0B /G=0" $1 $R2 $R3
${GetSize} "$FileDrive" "/M=${FILE3_YOU_CARE_ABOUT} /S=0B /G=0" $2 $R2 $R3
${Unless} $1 = ${FILE1_YOU_CARE_ABOUTSIZE}
${OrUnless} $2 = ${FILE2_YOU_CARE_ABOUTSIZE}
${OrUnless} $3 = ${FILE3_YOU_CARE_ABOUTSIZE}

That's what I tried the first time but it say invalid file on target disk. This code require that all 3 files be present doesn't it, if not present abort. I want it to search for file1 and file2 and file3, if ANY of the files are are found and the size is correct, installation continues. It only needs to find one correct file.


I think I got the LogicLib logic setup correctly. I don't have a computer setup to test it, so try this code on your own to see if it works:

var WhichVersion ; used to keep track of which version you need to install

Function .onInit
${GetDrives} "CDROM" "checkdrive"
${If} $WhichVersion = 0
MessageBox MB_OK "Abort Message"
abort
${EndIf}
; at this point, you could set set section flags based on the value of $WhichVersion

FunctionEnd


Function checkdrive
StrCpy $WhichVersion 0
${If} ${FileExists} "$9\${FILE1_YOU_CARE_ABOUT}"
${GetSize} "$9" "\M=${FILE1_YOU_CARE_ABOUT} /S=0B /G=0" $1 $2 $3
${If} $1 = ${FILE1_YOU_CARE_ABOUTSIZE}
StrCpy $WhichVersion 1
${EndIf}

${OrIf} ${FileExists} "$9\${FILE2_YOU_CARE_ABOUT}"
${GetSize} "$9" "\M=${FILE2_YOU_CARE_ABOUT} /S=0B /G=0" $1 $2 $3
${If} $1 = ${FILE2_YOU_CARE_ABOUTSIZE}
StrCpy $WhichVersion 2
${EndIf}

${OrIf} ${FileExists} "$9\${FILE3_YOU_CARE_ABOUT}"
${GetSize} "$9" "\M=${FILE3_YOU_CARE_ABOUT} /S=0B /G=0" $1 $2 $3
${If} $1 = ${FILE3_YOU_CARE_ABOUTSIZE}
StrCpy $WhichVersion 3
${EndIf}

${EndIf}

; Continue ${GetDrives} if you haven't found what you needed:
${If} $WhichVersion = 0
Push "continue"
${Else}
push "StopGetDrives"
${EndIf}
FunctionEnd

That's great thanks Comperio. I tried it and it aborts even though I'm sure the definitions are correct and CD is in CDROM drive. It needs to continue if WhichVersion(x) is present.

Here is the code, probably not right ..

var WhichVersion ; used to keep track of which version you need to install

Section "EOAA GT V1.00"
SectionIn RO

; Set output path to the installation directory.
SetOutPath $INSTDIR

; Put file there
File /r "x:\x\*.*"

; Write the installation path into the registry
WriteRegStr HKLM "SOFTWARE\EOAA GT" "Install_Dir" "$INSTDIR"

; Write the uninstall keys for Windows
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\EOAA GT" "DisplayName" "EOAA GT V1.00"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\EOAA GT" "UninstallString" '"$INSTDIR\Uninstall EOAA GT.exe"'
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\EOAA GT" "NoModify" 1
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\EOAA GT" "NoRepair" 1
WriteUninstaller "Uninstall EOAA GT.exe"
SectionEnd

Function .onInit
${GetDrives} "CDROM" "checkdrive"
${If} $WhichVersion = 0
MessageBox MB_OK "Abort Message"
abort
${EndIf}
; at this point, you could set set section flags based on the value of $WhichVersion

FunctionEnd

Function checkdrive
StrCpy $WhichVersion 0
${If} ${FileExists} "$9\${FILE1_YOU_CARE_ABOUT}"
${GetSize} "$9" "\M=${FILE1_YOU_CARE_ABOUT} /S=0B /G=0" $1 $2 $3
${If} $1 = ${FILE1_YOU_CARE_ABOUTSIZE}
StrCpy $WhichVersion 1
${EndIf}

${OrIf} ${FileExists} "$9\${FILE2_YOU_CARE_ABOUT}"
${GetSize} "$9" "\M=${FILE2_YOU_CARE_ABOUT} /S=0B /G=0" $1 $2 $3
${If} $1 = ${FILE2_YOU_CARE_ABOUTSIZE}
StrCpy $WhichVersion 2
${EndIf}

${OrIf} ${FileExists} "$9\${FILE3_YOU_CARE_ABOUT}"
${GetSize} "$9" "\M=${FILE3_YOU_CARE_ABOUT} /S=0B /G=0" $1 $2 $3
${If} $1 = ${FILE3_YOU_CARE_ABOUTSIZE}
StrCpy $WhichVersion 3
${EndIf}

${EndIf}

; Continue ${GetDrives} if you haven't found what you needed:
${If} $WhichVersion = 0
Push "continue"
${Else}
push "StopGetDrives"
${EndIf}
FunctionEnd

Is a typo \M, works with /M. Donation heading NSIS's way, thanks Comperio! :up:

Here's the full code ..

; EOAA GT.nsi

; The name of the installer
Name "EOAA GT V1.00"

; The file to write
OutFile "EOAA GT V1.00.exe"

; The default installation directory
InstallDir $PROGRAMFILES\rFactor

; Registry key to check for directory (so if you install again, it will
; overwrite the old one automatically)
InstallDirRegKey HKLM "Software\EOAA GT" "Install_Dir"

; Request application privileges for Windows Vista
RequestExecutionLevel admin

;--------------------------------

; Pages

Page components
Page directory
Page instfiles

UninstPage uninstConfirm
UninstPage instfiles

;--------------------------------

!include "FileFunc.nsh"
!include "logiclib.nsh"
!insertmacro GetSize
!insertmacro GetDrives

!define FILE1_YOU_CARE_ABOUT "x.x"
!define FILE1_YOU_CARE_ABOUTSIZE "123"
!define FILE2_YOU_CARE_ABOUT "x.x"
!define FILE2_YOU_CARE_ABOUTSIZE "456"
!define FILE3_YOU_CARE_ABOUT "x.x"
!define FILE3_YOU_CARE_ABOUTSIZE "789"

var WhichVersion ; used to keep track of which version you need to install

Function .onInit
${GetDrives} "CDROM" "checkdrive"
${If} $WhichVersion = 0
MessageBox MB_OK "Abort Message"
abort
${EndIf}
; at this point, you could set set section flags based on the value of $WhichVersion

FunctionEnd

Function checkdrive
StrCpy $WhichVersion 0
${If} ${FileExists} "$9\${FILE1_YOU_CARE_ABOUT}"
${GetSize} "$9" "/M=${FILE1_YOU_CARE_ABOUT} /S=0B /G=0" $1 $2 $3
${If} $1 = ${FILE1_YOU_CARE_ABOUTSIZE}
StrCpy $WhichVersion 1
${EndIf}

${OrIf} ${FileExists} "$9\${FILE2_YOU_CARE_ABOUT}"
${GetSize} "$9" "/M=${FILE2_YOU_CARE_ABOUT} /S=0B /G=0" $1 $2 $3
${If} $1 = ${FILE2_YOU_CARE_ABOUTSIZE}
StrCpy $WhichVersion 2
${EndIf}

${OrIf} ${FileExists} "$9\${FILE3_YOU_CARE_ABOUT}"
${GetSize} "$9" "/M=${FILE3_YOU_CARE_ABOUT} /S=0B /G=0" $1 $2 $3
${If} $1 = ${FILE3_YOU_CARE_ABOUTSIZE}
StrCpy $WhichVersion 3
${EndIf}

${EndIf}

; Continue ${GetDrives} if you haven't found what you needed:
${If} $WhichVersion = 0
Push "continue"
${Else}
push "StopGetDrives"
${EndIf}
FunctionEnd

Section "EOAA GT V1.00"
SectionIn RO

; Set output path to the installation directory.
SetOutPath $INSTDIR

; Put file there
File /r "C:\Folder\Folder\*.*"

; Write the installation path into the registry
WriteRegStr HKLM "SOFTWARE\EOAA GT" "Install_Dir" "$INSTDIR"

; Write the uninstall keys for Windows
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\EOAA GT" "DisplayName" "EOAA GT V1.00"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\EOAA GT" "UninstallString" '"$INSTDIR\Uninstall EOAA GT.exe"'
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\EOAA GT" "NoModify" 1
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\EOAA GT" "NoRepair" 1
WriteUninstaller "Uninstall EOAA GT.exe"
SectionEnd

; Uninstaller

Section "Uninstall"

; Remove registry keys
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\EOAA GT"
DeleteRegKey HKLM "SOFTWARE\EOAA GT"

; Remove files and uninstaller
Delete "$INSTDIR\Uninstall EOAA GT.exe"
Delete "$INSTDIR\rFm\EOAA GT.tga"
Delete "$INSTDIR\rFm\EOAA GT_logo.tga"
Delete "$INSTDIR\rFm\EOAA GT.rfm"
Delete "$INSTDIR\rFm\EOAA GT.bik"

; Remove directories used
RMDir /r "$INSTDIR\GameData\Vehicles\EOAA GT"
RMDir /r "$INSTDIR\GameData\Helmets\EOAA GT"
RMDir /r "$INSTDIR\GameData\Sounds\E_GT"
RMDir /r "$INSTDIR\UIData\EOAA GT"
RMDir /r "$INSTDIR\Music\EOAA GT"

SectionEnd

LOL!

I was just trying this again and was getting same result and couldn't figure it out. I didn't see your reply about "\M" until I had already spend about an hour of troubleshooting! :o

I'm glad you figured it out! :up: