How to pull Hard Drive Serial number

Is there a way to pull the HD Serial Number and then convert to String for Mac and PC?

Do you want the actual serial number or do you want to create a unique identifier tied to hardware identifiers? This seems to be a good guide to creating the latter: https://oroboro.com/unique-machine-fingerprint

If you’re after actual serial numbers then on Windows you have https://www.codeproject.com/kb/system/gethardwareinformation.aspx and on MacOS I believe you can use the DiskArbitration framework, but I’ve not tried it myself.

Thanks.
I wanted to grab a few things from the user to validate. And pulling a serial from the HD seems more secure than the Network Mac Address as that can change with Virtual Machines. I’ll try the first link you posted.

We do actually support this in juce:
File::getVolumeSerialNumber()

(…ah, but I don’t think it’s implemented for OSX, just for Windows)

Aww! Okay I’ll figure out other ways. Thank you

Yeah, I went round with this for a while and decided to use a directoryID.

String getMachineID() // really directory ID
{
#if JUCE_WINDOWS
    uint64 num = File::getSpecialLocation (File::windowsSystemDirectory).getFileIdentifier();
#elif JUCE_MAC
    uint64 num = File ("/Users").getFileIdentifier();
#endif
    return String(num + magicNumber);   // add some number to obfuscate it a bit
}
2 Likes

I also use directory IDs to create unique machine IDs. Just be aware that

  • directory IDs for some files change under Windows, depending on if your application runs as 32 or 64 bit application.
  • a directory ID might change after a Windows update (only happened to one customer of mine so far).
  • if you create a plugin for macOS, choose a directory that is accessible from a sandboxed application like GarageBand. Otherwise the directory ID will be different in GarageBand than in all other hosts.

IIRC the directories suggested by @pizzafilms are well chosen.

2 Likes

This is a bit of a make your own answer as I haven’t spent the time to make a small test program from this code. I have just picked some bits out of a larger function. But it may help you. Using DiskArbitration on OSX.

DASessionRef session = DASessionCreate(nullptr);
if (session == nullptr)
{
    DBG("ERROR: DASessionCreate failed " << deviceName << "!");
    return;
}

CFDictionaryRef dict = nullptr;
DADiskRef disk = nullptr;

disk = DADiskCreateFromBSDName(NULL, session, deviceName.toUTF8());
if (disk == nullptr)
{
    DBG("ERROR: DADiskCreateFromBSDName failed " << deviceName << "!");
    CFRelease(session);
    return;
}

dict = DADiskCopyDescription(disk);
if (dict == nullptr)
{
    DBG("ERROR: DADiskCopyDescription failed " << deviceName << "!");
    CFRelease(disk);
    CFRelease(session);
    return;
}

CFUUIDRef volumeUUIDKey = (CFUUIDRef) CFDictionaryGetValue(dict, kDADiskDescriptionVolumeUUIDKey);
if(volumeUUIDKey)
{
    CFStringRef uuid = CFUUIDCreateString(NULL, volumeUUIDKey);
    if(uuid==nullptr)
    {
        DBG("WARNING: failed to convert UUID to CFString");
    } else {
        char tmp[256];

        if(!CFStringGetCString(uuid, tmp, sizeof(tmp), kCFStringEncodingUTF8)) {
            DBG("WARNING: failed to convert CFString to UTF8: " << __FILE__ << ":" << __LINE__);
        }
        volumeUUID = tmp;
        CFRelease(uuid);
    }
}

DBG(volumeUUID);

Forgive my ignorance, I considered this myself but discarded this idea because of the following reasoning:

  • the best directory to use for this would be a directory that you are absolutely certain that exist on the system, and that doesn’t get moved/deleted. Choosing a system directory makes a perfect choice for this.

  • BUT, one such system directory, has a greater chance to have an ID that is the duplicate of the one on another system, because system directories are created early during system initialization and thus will tend to be given similar IDs by the copies of operating systems installed there. Or not?

Have you experienced conflicting IDs so far?

1 Like

@yfede, your suspicion is justified. I have indeed users with different computers but identical computer IDs. The last time I checked, the most spread computer ID was used by 0.7% of my user base.

Even though this isn’t an issue, it would be great to have File::getVolumeSerialNumber() work on all platforms.

3 Likes

I agree, having File::getVolumeSerialNumber(), work for all platforms, would be great.
But for now I’ll try what @pizzafilms suggested.

1 Like

Would indeed be a nice to see it implemented on OSX.
For now the getVolumeSerialNumber method should at least throw a jassert when being called on OSX because it just returns 0 without warning.

1 Like

Actually no - the function could return 0 if it fails on any platform (i.e. if you gave it a bogus filename), so you should check the result before using it rather than expecting it to always succeed, which is the situation where an assertion would be appropriate.

Well it will never succeed on OSX, so somehow informing the developer wouldn’t be a bad idea. What about not defining the method altogether on OSX, that would make it very clear.

Are you using only one file id per each computer id, or do you combine many of them?

It would be interesting to know if multiple file ids for system directories are correlated or not. If they aren’t correlated, then probably it is possible to increase the degree of “uniqueness” by combining many of them (for example, taking the id of “C:\Windows”, “C:\Windows\System32”, etc.).

Obviously that is not the case if, for example, when the id for “C:\Windows” is a certain value A, that also implies that the value for the id of “C:\Windows\System32” is fixed and always known to be, let’s say, a different given value B

One file id.

For my next plugin, I’m testing an approach with multiple ids. Don’t have any stats about correlation so far.

1 Like

This has been biting me lately. It seems that after some/all/most Windows updates, the directory ID changes for some reason. Works fine on Mac.

Any newer thinking on this issue?

Apparently this works better:

File::getSpecialLocation(File::globalApplicationsDirectory).getFileIdentifier();

We’re using these powershell commands these days:
(Get-WmiObject -Class Win32_SystemEnclosure).serialNumber
or
Get-WmiObject Win32_ComputerSystemProduct | Select-Object -ExpandProperty UUID