Reputation: 9708
I am working on a project where I need to activate Windows on a Windows 7 PC. I wrote the code below using the Windows Software Licensing API. MSDN says that the three functions used below require Windows 8 or Windows Server 2012 which suggests that these functions aren't available on Windows 7. But if I open slc.dll in depends.exe which is in C:\Windows\System32 on my Windows 7 machine, I do SLOpen and SLClose functions. But not SLActivateProduct.
When I build the program I get linker error:
1> main.cpp
1>main.obj : error LNK2019: unresolved external symbol _SLActivateProduct@28 referenced in function _main
1>activate_windows.exe : fatal error LNK1120: 1 unresolved externals
How does this work at link time? I presume this means that slc.lib (see code below) does not have the SLActivateProduct function?
This program doesn't need to be written in C so I can call anything from a script. Anyone know if there would be any way of doing this on Windows 7? It has to be a programmatic way which can be started by running a script.
code below:
#include <Windows.h>
#include <Slpublic.h>
#include <slerror.h>
#include <stdio.h>
// lib to use
#pragma comment(lib, "slc.lib")
int main() {
// slmgr.vbs has:
// private const WindowsAppId = "55c92734-d682-4d71-983e-d6ec3f16059f"
// Windows AppId for SLID: {55c92734-d682-4d71-983e-d6ec3f16059f} - this is a GUID
const SLID SLID_WINDOWS = {0x55c92734, 0xd682, 0x4d71, 0x98, 0x3e, 0xd6, 0xec, 0x3f, 0x16, 0x05, 0x9f};
HSLC hslc;
HRESULT hr = SLOpen(&hslc);
if (SUCCEEDED(hr))
{
// try to activate windows
hr = SLActivateProduct(hslc, &SLID_WINDOWS, 0, NULL, NULL, NULL, 0);
switch(hr) {
case E_INVALIDARG:
printf("SLActivateProduct - one or more arguments are not valid\n");
break;
case SL_E_PUBLISHING_LICENSE_NOT_INSTALLED:
printf("SLActivateProduct - The license is not installed\n");
break;
case SL_E_PKEY_NOT_INSTALLED:
printf("SLActivateProduct - The product key is not available\n");
break;
case SL_E_PRODUCT_SKU_NOT_INSTALLED:
printf("SLActivateProduct - The license is not installed\n");
break;
case S_OK:
printf("SLActivateProduct - returned S_OK\n");
break;
default:
printf("SLActivateProduct - unknown return code\n");
break;
}
hr=SLClose(hslc);
}
}
Upvotes: 0
Views: 1545
Reputation: 598309
SLActivateProduct()
is simply not available on Windows 7, even if you could link to it at compile-time (which apparently you cannot since your version of slc.lib
is missing that reference).
However, you can load SLActivateProduct()
dynamically at runtime using GetProcAddress()
. That will get you past the linker error (until you update your development environment) and allow your code to work on Windows 8 and later, at least.
And FYI, sliddefs.h
defines a WINDOWS_SLID
constant, so you do not need to define it manually in your code.
Try something more like this:
#include <Windows.h>
#include <Slpublic.h>
#include <slerror.h>
#include <sliddefs.h>
#include <stdio.h>
// lib to use
#pragma comment(lib, "slc.lib")
// if your version of Slpublic.h does not define these then uncomment this...
/*
typedef enum _tagSL_ACTIVATION_TYPE {
SL_ACTIVATION_TYPE_DEFAULT = 0,
SL_ACTIVATION_TYPE_ACTIVE_DIRECTORY = 1
} SL_ACTIVATION_TYPE;
typedef struct _tagSL_ACTIVATION_INFO_HEADER {
DWORD cbSize;
SL_ACTIVATION_TYPE type;
} SL_ACTIVATION_INFO_HEADER;
*/
typedef HRESULT WINAPI (*LPFN_SLActivateProduct)(HSLC, const SLID*, UINT, const PVOID, const SL_ACTIVATION_INFO_HEADER*, PCWSTR, WORD);
int main()
{
LPFN_SLActivateProduct lpSLActivateProduct = (LPFN_SLActivateProduct) GetProcAddress(GetModuleHandle(TEXT("slc.dll")), "SLActivateProduct");
if (!lpSLActivateProduct)
{
printf("SLActivateProduct - The product cannot be activated on this system\n");
return 0;
}
HSLC hslc;
HRESULT hr = SLOpen(&hslc);
if (FAILED(hr))
{
printf("SLOpen - unknown return code 0x%08X\n", hr);
return 0;
}
// try to activate windows
hr = lpSLActivateProduct(hslc, &WINDOWS_SLID, 0, NULL, NULL, NULL, 0);
switch(hr)
{
case E_INVALIDARG:
printf("SLActivateProduct - one or more arguments are not valid\n");
break;
case SL_E_PUBLISHING_LICENSE_NOT_INSTALLED:
printf("SLActivateProduct - The license is not installed\n");
break;
case SL_E_PKEY_NOT_INSTALLED:
printf("SLActivateProduct - The product key is not available\n");
break;
case SL_E_PRODUCT_SKU_NOT_INSTALLED:
printf("SLActivateProduct - The license is not installed\n");
break;
case S_OK:
printf("SLActivateProduct - returned S_OK\n");
break;
default:
printf("SLActivateProduct - unknown return code 0x%08X\n", hr);
break;
}
hr = SLClose(hslc);
return 0;
}
Update: it turns out SLActivateProduct()
IS available on Windows 7, after all. It is simply located in slcext.dll
instead of slc.dll
, like MSDN says. You can adjust the GetProcAddress()
call accordingly:
LPFN_SLActivateProduct lpSLActivateProduct = (LPFN_SLActivateProduct) GetProcAddress(GetModuleHandle(TEXT("slc.dll")), "SLActivateProduct");
if (!lpSLActivateProduct)
{
// TODO: if SLCEXT.DLL is not already loaded, use LoadLibrary() instead of GetModuleHandle()...
lpSLActivateProduct = (LPFN_SLActivateProduct) GetProcAddress(GetModuleHandle(TEXT("slcext.dll")), "SLActivateProduct");
}
if (!lpSLActivateProduct)
{
printf("SLActivateProduct - The product cannot be activated on this system\n");
return 0;
}
Update: if later on down the road, you update to a development environment whose slc.lib
is no longer missing a reference to SLActivateProduct()
, you can remove the explicit call to GetProcAddress()
and instead use the linker's delay loaded DLLs feature. That allows you to write code as-if you were static linking, but then the linker injects special code that will call GetProcAddress()
for you the first time the DLL function is called at runtime. That will allow you to check the OS version before calling the function "statically", allowing your app to still run on older Windows versions but only perform activation on Windows 7+.
#include <Windows.h>
#include <Slpublic.h>
#include <slerror.h>
#include <sliddefs.h>
#include <stdio.h>
// lib to use
#pragma comment(lib, "slc.lib")
// if your version of Slpublic.h does not define these then uncomment this...
/*
typedef enum _tagSL_ACTIVATION_TYPE {
SL_ACTIVATION_TYPE_DEFAULT = 0,
SL_ACTIVATION_TYPE_ACTIVE_DIRECTORY = 1
} SL_ACTIVATION_TYPE;
typedef struct _tagSL_ACTIVATION_INFO_HEADER {
DWORD cbSize;
SL_ACTIVATION_TYPE type;
} SL_ACTIVATION_INFO_HEADER;
*/
int main()
{
OSVERSIONINFO osi = {0};
osi.dwOSVersionInfoSize = sizeof(osi).
GetVersionEx(&osi);
if ((osi.dwMajorVersion < 6) || ((osi.dwMajorVersion == 6) && (dwMinorVersion < 1)))
{
printf("SLActivateProduct - The product cannot be activated on this system\n");
return 0;
}
// alternatively:
/*
#include <VersionHelpers.h>
if (!IsWindows7OrGreater())
{
printf("SLActivateProduct - The product cannot be activated on this system\n");
return 0;
}
*/
HSLC hslc;
HRESULT hr = SLOpen(&hslc);
if (FAILED(hr))
{
printf("SLOpen - unknown return code 0x%08X\n", hr);
return 0;
}
// try to activate windows
hr = SLActivateProduct(hslc, &WINDOWS_SLID, 0, NULL, NULL, NULL, 0);
switch(hr)
{
case E_INVALIDARG:
printf("SLActivateProduct - one or more arguments are not valid\n");
break;
case SL_E_PUBLISHING_LICENSE_NOT_INSTALLED:
printf("SLActivateProduct - The license is not installed\n");
break;
case SL_E_PKEY_NOT_INSTALLED:
printf("SLActivateProduct - The product key is not available\n");
break;
case SL_E_PRODUCT_SKU_NOT_INSTALLED:
printf("SLActivateProduct - The license is not installed\n");
break;
case S_OK:
printf("SLActivateProduct - returned S_OK\n");
break;
default:
printf("SLActivateProduct - unknown return code 0x%08X\n", hr);
break;
}
hr = SLClose(hslc);
return 0;
}
However, to address the slc.dll
vs slcext.dll
issue, you can use a delay-load failure hook to detect when SLActivateProduct()
is not found in slc.dll
, and then load it from slcext.dll
instead.
In fact, this is the preferred option, as it also provides another opportunity - it allows you to remove the OS version check altogether! If SLActivateProduct()
is not found in either DLL, you can return a pointer to a custom user-defined function instead. When the code calls SLActivateProduct()
, and if it calls that function, it could simply return E_NOTIMPL
, which main()
can handle in its switch
statement:
#include <Windows.h>
#include <Slpublic.h>
#include <slerror.h>
#include <sliddefs.h>
#include <stdio.h>
#include <delayimp.h>
// lib to use
#pragma comment(lib, "slc.lib")
// if your version of Slpublic.h does not define these then uncomment this...
/*
typedef enum _tagSL_ACTIVATION_TYPE {
SL_ACTIVATION_TYPE_DEFAULT = 0,
SL_ACTIVATION_TYPE_ACTIVE_DIRECTORY = 1
} SL_ACTIVATION_TYPE;
typedef struct _tagSL_ACTIVATION_INFO_HEADER {
DWORD cbSize;
SL_ACTIVATION_TYPE type;
} SL_ACTIVATION_INFO_HEADER;
*/
HRESULT WINAPI Dummy_SLActivateProduct(HSLC, const SLID*, UINT, const PVOID, const SL_ACTIVATION_INFO_HEADER*, PCWSTR, WORD)
{
return E_NOTIMPL;
}
HMODULE hSlcExtDll = NULL;
FARPROC WINAPI MyDliFailureHook(unsigned dliNotify, PDelayLoadInfo pdli)
{
if ((dliNotify == dliFailGetProc) && (pdli->dlp.fImportByName) && (lstrcmpA(pdli->dlp.szProcName, "SLActivateProduct") == 0))
{
hSlcExtDll = LoadLibrary("slcext.dll");
FARPROC fn = GetProcAddress(hSlcExtDll, "SLActivateProduct");
if (!fn) fn = &Dummy_SLActivateProduct;
return fn;
}
return NULL;
}
int main()
{
__pfnDliFailureHook2 = &MyDliFailureHook;
HSLC hslc;
HRESULT hr = SLOpen(&hslc);
if (FAILED(hr))
{
printf("SLOpen - unknown return code 0x%08X\n", hr);
return 0;
}
// try to activate windows
hr = SLActivateProduct(hslc, &WINDOWS_SLID, 0, NULL, NULL, NULL, 0);
switch(hr)
{
case E_NOTIMPL:
printf("SLActivateProduct - The product cannot be activated on this system\n");
break;
case E_INVALIDARG:
printf("SLActivateProduct - one or more arguments are not valid\n");
break;
case SL_E_PUBLISHING_LICENSE_NOT_INSTALLED:
printf("SLActivateProduct - The license is not installed\n");
break;
case SL_E_PKEY_NOT_INSTALLED:
printf("SLActivateProduct - The product key is not available\n");
break;
case SL_E_PRODUCT_SKU_NOT_INSTALLED:
printf("SLActivateProduct - The license is not installed\n");
break;
case S_OK:
printf("SLActivateProduct - returned S_OK\n");
break;
default:
printf("SLActivateProduct - unknown return code 0x%08X\n", hr);
break;
}
hr = SLClose(hslc);
return 0;
}
Upvotes: 2