Volume Shadow Copy Service (VSS) sample in C? - c

I been trying to read the documentation for the API functions of Volume Shadow Copy Service, for the purpose of copying files that are currently locked (being used) under Windows XP.
Unfortunately I don't seem to get nowhere. Anybody happen to have a code sample of how to interact with the API, for copying such files?
Thanks, Doori Bar

I've had similar troubles, after a lot of hit-and-trials I've managed to get somewhere...
here's a code snippet which may help:
#include <stdio.h>
#include <windows.h>
#include <winbase.h>
#include <Vss.h>
#include <VsWriter.h>
#include <VsBackup.h>
int main()
{
int retCode = 0;
int i=0;
HRESULT hr;
IVssEnumObject *pIEnumSnapshots;
IVssBackupComponents *ab;
VSS_OBJECT_PROP Prop;
VSS_SNAPSHOT_PROP& Snap = Prop.Obj.Snap;
WCHAR existingFilePath[MAX_PATH] = TEXT("\\temp\\PrinterList.txt");
WCHAR newFileLocation[MAX_PATH] = TEXT("c:\\Users\\PrinterList.txt");
TCHAR existingFileLocation[MAX_PATH];
if (CoInitialize(NULL) != S_OK)
{
printf("CoInitialize failed!\n");
return 1;
}
hr = CreateVssBackupComponents(&ab);
if(hr != S_OK)
{
printf("Failed at CreateVssBackupComponents Stage");
return 1;
}
hr = ab->InitializeForBackup();
if(hr != S_OK)
{
printf("Failed at InitializeForBackup Stage");
return 1;
}
hr = ab->SetContext(VSS_CTX_ALL);
if(hr != S_OK)
{
printf("Failed at SetContext Stage");
return 1;
}
hr = ab->Query(GUID_NULL,VSS_OBJECT_NONE, VSS_OBJECT_SNAPSHOT, &pIEnumSnapshots);
if(hr != S_OK){
printf("Failed at Query Stage");
return 1;
}
// Enumerate all shadow copies.
printf("Recursing through snapshots...\n");
while(true)
{
// Get the next element
ULONG ulFetched;
hr = pIEnumSnapshots->Next( 1, &Prop, &ulFetched );
// We reached the end of list
if (ulFetched == 0)
break;
wprintf(L"Snapshot:%s\n", Snap.m_pwszSnapshotDeviceObject);
/*
At this point you have the Snap object with all the information required for copying the file.
example:
Snap.m_pwszSnapshotDeviceObject is the root for snapshot object
(like \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1)
Snap.m_pwszOriginalVolumeName is the full unicode name
(like \\?\Volume{1240872a-88de-11df-a94d-806e6f6e6963}\)
for the original root(c: mostly)
So, you can use CopyFile() to do what you want
*/
wcscpy(existingFileLocation, Snap.m_pwszSnapshotDeviceObject);
wcscat(existingFileLocation, existingFilePath);
CopyFile(existingFileLocation, newFileLocation, false);
//false here will enable over-write
}
return retCode;
}
Note: If your target machine is not the same as build machine, you'll need to include proper definitions and build configurations.
Note: You will have to use the annoying wchars everywhere, because these functions use them.

Related

Recursively get all files in a hard disk

Please I am finding it hard to recursively get all files in a directory. My code works fine, just that it only get files in current directory. Please anyone should help me view my code to check what i have done wrong.
Here is my code:
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
int list2() {
TCHAR currentdir[MAX_PATH];
WIN32_FIND_DATA findDat2;
GetCurrentDirectory(MAX_PATH, currentdir);
strcat_s(currentdir, strlen(currentdir)+strlen("\\*")+1, "\\*");
HANDLE hFind2 = FindFirstFile(currentdir, &findDat2);
if (hFind2 == INVALID_HANDLE_VALUE) {
printf("INVALID HANDLE VALUE");
}
else {
INT dot1 = strncmp(".", findDat2.cFileName, strlen("."));
INT dot2 = strncmp("..", findDat2.cFileName, strlen(".."));
do {
if (dot1 !=0 && dot2 != 0) {
if (findDat2.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
SetCurrentDirectory(findDat2.cFileName);
list2();
}
else {
printf("%s\n", findDat2.cFileName);
}
}
} while (FindNextFile(hFind2, &findDat2));
}
}
int list(CHAR *startDir) {
WIN32_FIND_DATA findDat;
TCHAR path[MAX_PATH];
TCHAR cpstartDir[MAX_PATH];
strcpy_s(cpstartDir, sizeof(cpstartDir), startDir);
HANDLE hFind = FindFirstFile(startDir, &findDat);
if (hFind == INVALID_HANDLE_VALUE) {
printf("INVALID_HANDLE_VALUE with finding file\n");
return 0;
}
else {
INT dot1 = strncmp(".", findDat.cFileName, strlen("."));
INT dot2 = strncmp("..", findDat.cFileName, strlen(".."));
do {
if (dot1 !=0 && dot2 != 0) {
if (findDat.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
SetCurrentDirectory(findDat.cFileName);
list2();
}
else {
printf("%s\n", findDat.cFileName);
}
}
} while (FindNextFile(hFind, &findDat));
}
}
int main() {
list("C:\\*.*");
return 0;
}
This only get files in a current directory
What you need is a recursive function that recurses into each directory found (except for . and ..).
I don't see the point in using SetCurrentDirectory. You don't want to change your working directory, but instead you just want the contents of the lower level path.
So list should call itself for each subdirectory with the argument being: the parent path + \ + the name of the subfolder.
I created a cross platform open source library to traverse an entire tree: https://github.com/brechtsanders/libdirtrav
Maybe this is useful for you so that you wouldn't have to reinvent everything.

Trouble with implementing a Direct Module Method in Azure IoT Edge Module using azure-iot-sdk-c SDK

Full disclosure, I have asked this question on Azure IoT SDK C github project, but since they recommend looking on StackOverflow, I decided to post here as well.
I am having trouble implementing a Direct Module Method handler in my azure-iot-sdk-c based IoT Edge Module. I could not find a documentation page with an example implementation, so I assembled my implementation from various SDK documentation pages and unit test "examples".
To test this, I have a dedicated Linux based PC (Ubuntu 18.04) running iotedge 1.0.8-2. I can see that my module is starting and printing its version and firing the connection status callback message. I even even see that the ModuleTwin callback is firing and printing the payload when I manually edit the module identity twin for my device in the portal.
However, when I try to manually invoke a Direct Method on my module within my device in the portal, I see nothing printed and I get the following error in the portal:
{"message":"GatewayTimeout:{\r\n \"Message\": \"{\\\"errorCode\\\":504101,\\\"trackingId\\\":\\\"8215e001484d41a19245639844f44f78-G:9-TimeStamp:01/14/2020 21:20:42-G:0-TimeStamp:01/14/2020 21:20:42\\\",\\\"message\\\":\\\"Timed out waiting for the response from device.\\\",\\\"info\\\":{},\\\"timestampUtc\\\":\\\"2020-01-14T21:20:42.0556758Z\\\"}\",\r\n \"ExceptionMessage\": \"\"\r\n}"}
The relevant code is below. I looked on StackOverflow but examples there are not C SDK based. Where am I going wrong with Direct Module Methods? Thank you!
Update: An interesting observation is that if I change this code to use MQTT from AMQP, then everything works. Is AMQP not supported for Direct Module Methods?
#include <iothub_module_client_ll.h>
#include <iothub_client_options.h>
#include <iothub_message.h>
#include <azure_c_shared_utility/threadapi.h>
#include <azure_c_shared_utility/crt_abstractions.h>
#include <azure_c_shared_utility/platform.h>
#include <azure_c_shared_utility/shared_util_options.h>
#include <iothubtransportamqp.h>
#include <iothub.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
// Linker defined build information (see Makefile)
extern char __BUILD_DATE;
extern char __BUILD_NUMBER;
// Set the default value for module communication (e.g. AMQP) log tracing, yet
// allow compile time overrides.
#ifndef LOG_TRACE_ENABLED
#define LOG_TRACE_ENABLED 0
#endif
static void moduleTwinCallback(DEVICE_TWIN_UPDATE_STATE update_state, const unsigned char* payLoad, size_t size, void* /*userContextCallback*/)
{
EPRINT("DEBUG: Module Twin callback called with (state=%s)", MU_ENUM_TO_STRING(DEVICE_TWIN_UPDATE_STATE, update_state));
EPRINT("DEBUG: payload=%.*s", (int)size, (const char *)payLoad);
fflush(NULL);
//JSON_Value *root_value = json_parse_string(payLoad);
//JSON_Object *root_object = json_value_get_object(root_value);
//if (json_object_dotget_value(root_object, "desired.TemperatureThreshold") != NULL) {
// temperatureThreshold = json_object_dotget_number(root_object, "desired.TemperatureThreshold");
//}
//if (json_object_get_value(root_object, "TemperatureThreshold") != NULL) {
// temperatureThreshold = json_object_get_number(root_object, "TemperatureThreshold");
//}
}
static int DirectMethodCb(const char* method_name, const unsigned char* payload, size_t size, unsigned char** response, size_t* resp_size, void* /*userContextCallback*/)
{
const char *METHOD_NAME = "TestMethod";
const int METHOD_RESPONSE_SUCCESS = 200;
const int METHOD_RESPONSE_ERROR = 401;
int responseCode;
EPRINT("DEBUG: Method name: %s", method_name);
EPRINT("DEBUG: Method payload: %.*s", (int)size, (const char*)payload);
if (strcmp(METHOD_NAME, method_name))
{
EPRINT("Method name incorrect - expected %s but got %s", METHOD_NAME, method_name);
responseCode = METHOD_RESPONSE_ERROR;
}
/*
else if (size != strlen(expectedMethodPayload))
{
LogError("payload size incorect - expected %zu but got %zu", strlen(expectedMethodPayload), size);
responseCode = METHOD_RESPONSE_ERROR;
}
else if (memcmp(payload, expectedMethodPayload, size))
{
LogError("Payload strings do not match");
responseCode = METHOD_RESPONSE_ERROR;
}
*/
else
{
*resp_size = size;
if (size == 0)
{
*response = NULL;
EPRINT("DEBUG: Empty, but good response");
responseCode = METHOD_RESPONSE_SUCCESS;
}
else
{
if ((*response = (unsigned char*)malloc(*resp_size)) == NULL)
{
EPRINT("allocation failure");
responseCode = METHOD_RESPONSE_ERROR;
}
else
{
(void)memcpy(*response, payload, *resp_size);
EPRINT("DEBUG: All good - echoing back the payload");
responseCode = METHOD_RESPONSE_SUCCESS;
}
}
}
EPRINT("DEBUG: completing with return code %d", responseCode);
fflush(NULL);
return responseCode;
}
static void ConnectionStatusCb(IOTHUB_CLIENT_CONNECTION_STATUS result, IOTHUB_CLIENT_CONNECTION_STATUS_REASON reason, void* /*userContextCallback*/)
{
EPRINT("DEBUG: ConnectionStatusCb(status=%d %s, reason=%d %s",
result, MU_ENUM_TO_STRING(IOTHUB_CLIENT_CONNECTION_STATUS, result),
reason, MU_ENUM_TO_STRING(IOTHUB_CLIENT_CONNECTION_STATUS_REASON, reason)
);
fflush(NULL);
}
int main(void)
{
IOTHUB_MODULE_CLIENT_LL_HANDLE iotHubModuleClientHandle = nullptr;
int retval = 1;
do
{
printf("\n\n=======================\n");
printf("Build date : %lu\n", (unsigned long) &__BUILD_DATE);
printf("Build number: %lu\n", (unsigned long) &__BUILD_NUMBER);
fflush(NULL);
srand((unsigned int)time(NULL));
if (0 != IoTHub_Init())
{
EPRINT("Failed to initialize the platform.");
break;
}
iotHubModuleClientHandle = IoTHubModuleClient_LL_CreateFromEnvironment(AMQP_Protocol);
if (nullptr == iotHubModuleClientHandle)
{
EPRINT("IoTHubModuleClient_LL_CreateFromEnvironment failed");
break;
}
IOTHUB_CLIENT_RESULT result = IoTHubModuleClient_LL_SetModuleMethodCallback(iotHubModuleClientHandle, DirectMethodCb, iotHubModuleClientHandle);
if (IOTHUB_CLIENT_OK != result)
{
EPRINT("IoTHubModuleClient_SetModuleMethodCallback failed: %d", result);
break;
}
result = IoTHubModuleClient_LL_SetConnectionStatusCallback(iotHubModuleClientHandle, ConnectionStatusCb, iotHubModuleClientHandle);
if (IOTHUB_CLIENT_OK != result)
{
EPRINT("IoTHubDeviceClient_SetConnectionStatusCallback failed: %d", result);
break;
}
#if LOG_TRACE_ENABLED
bool traceOn = true;
IoTHubModuleClient_LL_SetOption(iotHubModuleClientHandle, OPTION_LOG_TRACE, &traceOn);
#endif // LOG_TRACE_ENABLED
result = IoTHubModuleClient_LL_SetModuleTwinCallback(iotHubModuleClientHandle, moduleTwinCallback, iotHubModuleClientHandle);
if (IOTHUB_CLIENT_OK != result)
{
EPRINT("IoTHubModuleClient_LL_SetModuleTwinCallback failed: %d", result);
break;
}
while (true)
{
IoTHubModuleClient_LL_DoWork(iotHubModuleClientHandle);
ThreadAPI_Sleep(100);
}
} while(false);
if (nullptr != iotHubModuleClientHandle)
{
IoTHubModuleClient_LL_Destroy(iotHubModuleClientHandle);
}
IoTHub_Deinit();
return retval;
}

Enable bypass proxy server and notify IE for the change

I am trying to use the Internet Explorer Options API to set the LAN Settings based on this example from Microsoft.
I was able to set the proxy address and the exception but I want to enable the Bypass proxy server for local addresses checkbox and also notify Internet Explorer for the change so I don't have to close it and open it again.
I suppose I need to use another option from INTERNET_PER_CONN_OPTION structure, but no idea what I should use.
This is my code:
#include <Windows.h>
#include <wininet.h>
#include <wchar.h>
#pragma comment(lib, "Wininet.lib")
int wmain(int argc, wchar_t * argv[])
{
INTERNET_PER_CONN_OPTION_LIST connList;
DWORD bufSize = sizeof(connList);
connList.dwSize = sizeof(connList);
connList.pszConnection = NULL;
connList.dwOptionCount = 3;
connList.pOptions = (INTERNET_PER_CONN_OPTION*)malloc(sizeof(INTERNET_PER_CONN_OPTION) * 3);
if (connList.pOptions == NULL)
{
fwprintf(stderr, L"Memory allocation failed.\n");
return 1;
}
connList.pOptions[0].dwOption = INTERNET_PER_CONN_FLAGS;
connList.pOptions[0].Value.dwValue = PROXY_TYPE_DIRECT |
PROXY_TYPE_PROXY;
connList.pOptions[1].dwOption = INTERNET_PER_CONN_PROXY_SERVER;
connList.pOptions[1].Value.pszValue = L"https://internal.com.co:80";
connList.pOptions[2].dwOption = INTERNET_PER_CONN_PROXY_BYPASS;
connList.pOptions[2].Value.pszValue = L"local";
BOOL internetOption;
internetOption = InternetSetOptionW(NULL,
INTERNET_OPTION_PER_CONNECTION_OPTION,
&connList,
bufSize);
if (internetOption != TRUE)
{
fwprintf(stderr, L"Faile to set the option with code: %u\n", GetLastError());
return 1;
}
free(connList.pOptions);
wprintf(L"Done!\n");
return 0;
}
Can you help me?
Add the string <local> including the < and > signs to the exception list, e.g. <local>;*.microsoft.com.

CreateWellKnownSid says Parameter is incorrect with WinAccountAdministratorSid, but works with WinBuiltAdministratorsSid

I am trying to get the well known SID for the builtin administrator account using CreateWellKnownSid so I can use it in other functions, but I am getting The parameter is incorrect error message when using WinAccountAdministratorSid as first parameter; however, if I use WinBuiltinAdministratorsSid or WinBuiltinUsersSid it works. No idea what's going on.
Code:
#include <Windows.h>
#include <wchar.h>
#include <LM.h>
#include <locale.h>
#pragma comment(lib, "Netapi32.lib")
#define MAX_NAME 256
VOID ShowError(DWORD errorCode)
{
//FormatMessageW
DWORD flags = FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS;
LPWSTR errorMessage;
DWORD size = 0;
if (!FormatMessageW(flags, NULL, errorCode, 0, (LPWSTR)&errorMessage, size, NULL))
{
fwprintf(stderr, L"Could not get the format message, error code: %u\n", GetLastError());
exit(1);
}
wprintf(L"\n%s", errorMessage);
LocalFree(errorMessage);
}
int wmain(int argc, WCHAR **argv)
{
_wsetlocale(LC_ALL, L"English");
//LocalAlloc
UINT memFlags = LMEM_FIXED; //Allocates fixed memory
DWORD numOfBytes = SECURITY_MAX_SID_SIZE;
PSID builtInAdminSid;
/*Allocating memory to hold the SID for the
built-in administrator user*/
if (!(builtInAdminSid = LocalAlloc(memFlags, numOfBytes)))
{
ShowError(GetLastError());
return 1;
}
//CreateWellKnownSid
WELL_KNOWN_SID_TYPE accountAdminSid = WinAccountAdministratorSid;
PSID domainSid = NULL;
/*We will ask Windows for the well known Admin SID.
If this function fails, we cannot continue*/
if (!CreateWellKnownSid(accountAdminSid, NULL,
builtInAdminSid, &numOfBytes))
{
ShowError(GetLastError());
LocalFree(builtInAdminSid); //Do not forget to free memory!
return 1;
}
return 0;
}
Am I doing something wrong?
EDIT:
Seems like I have to specify the DomainSid parameter, but how do I retrieve it for the local computer?
some time CreateWellKnownSid require DomainSid parameter by very simply reason - it concatenation the DomainSid with well known rid (add one SubAuthority to sid).
for get DomainSid we can use LsaQueryInformationPolicy with PolicyAccountDomainInformation - Retrieves the name and SID of the system's account domain. - this api call return POLICY_ACCOUNT_DOMAIN_INFO structure where exist DomainSid
#include <Ntsecapi.h>
ULONG CreateSid()
{
LSA_HANDLE PolicyHandle;
static LSA_OBJECT_ATTRIBUTES oa = { sizeof(oa) };
NTSTATUS status = LsaOpenPolicy(0, &oa, POLICY_VIEW_LOCAL_INFORMATION, &PolicyHandle);
if (0 <= status)
{
PPOLICY_ACCOUNT_DOMAIN_INFO ppadi;
if (0 <= (status = LsaQueryInformationPolicy(PolicyHandle, PolicyAccountDomainInformation, (void**)&ppadi)))
{
PSID sid = alloca(MAX_SID_SIZE);
ULONG cbSid = MAX_SID_SIZE;
if (!CreateWellKnownSid(::WinAccountAdministratorSid, ppadi->DomainSid, sid, &cbSid))
{
status = GetLastError();
}
LsaFreeMemory(ppadi);
}
LsaClose(PolicyHandle);
}
return status;
}
For those who wonder how I set the RbMm's answer to my code, here it is:
// LsaOpenPolicy
NTSTATUS nOpenPolicy;
LSA_OBJECT_ATTRIBUTES objectAttributes;
LSA_HANDLE policyHandle;
// Fills a block of memory with zeros.
ZeroMemory(&objectAttributes, sizeof(objectAttributes));
nOpenPolicy = LsaOpenPolicy(NULL, &objectAttributes,
POLICY_VIEW_LOCAL_INFORMATION, &policyHandle);
if (nOpenPolicy != STATUS_SUCCESS)
{
ShowError(LsaNtStatusToWinError(nOpenPolicy));
LocalFree(builtInAdminSid);
return 1;
}
// LsaQueryInformationPolicy
NTSTATUS nQueryInfo;
POLICY_INFORMATION_CLASS policyInformation = PolicyAccountDomainInformation;
PPOLICY_ACCOUNT_DOMAIN_INFO pDomainInfo;
nQueryInfo = LsaQueryInformationPolicy(policyHandle, policyInformation, (PVOID *)&pDomainInfo);
if (nQueryInfo != STATUS_SUCCESS)
{
ShowError(LsaNtStatusToWinError(nQueryInfo));
LocalFree(builtInAdminSid);
LsaClose(policyHandle);
return 1;
}
// CreateWellKnownSid
WELL_KNOWN_SID_TYPE accountAdminSid = WinAccountAdministratorSid;
/* We will ask Windows for the well known Admin SID.
If this function fails, we cannot continue */
if (!CreateWellKnownSid(accountAdminSid, pDomainInfo->DomainSid,
builtInAdminSid, &numOfBytes))
{
ShowError(GetLastError());
LocalFree(builtInAdminSid); // Do not forget to free memory!
LsaClose(policyHandle);
return 1;
}
LsaClose(policyHandle);
LsaFreeMemory(pDomainInfo);

Local function definitions are rejected by Visual Studio

I am trying to list all devices attached to my system and after searching found this code which throws up error local function definations are illegal can someone explain what its means please.
Or is my issue because I am trying to use code that was from in C++. Thanks
WORKING CODE
#include <windows.h>
#include <setupapi.h>
#include <stdio.h>
#pragma comment(lib,"SetupAPI")
void print_property
(
__in HDEVINFO hDevInfo,
__in SP_DEVINFO_DATA DeviceInfoData,
__in PCWSTR Label,
__in DWORD Property
)
{
DWORD DataT;
LPTSTR buffer = NULL;
DWORD buffersize = 0;
//
while (!SetupDiGetDeviceRegistryProperty(
hDevInfo,
&DeviceInfoData,
Property,
&DataT,
(PBYTE)buffer,
buffersize,
&buffersize))
{
if (ERROR_INSUFFICIENT_BUFFER == GetLastError())
{
// Change the buffer size.
if (buffer)
{
LocalFree(buffer);
}
// Double the size to avoid problems on
// W2k MBCS systems per KB 888609.
buffer = (LPTSTR)LocalAlloc(LPTR, buffersize * 2);
}
else
{
break;
}
}
wprintf(L"%s %s\n",Label, buffer);
if (buffer)
{
LocalFree(buffer);
}
}
int main()
{
//int setupdi_version()
//{
HDEVINFO hDevInfo;
SP_DEVINFO_DATA DeviceInfoData;
DWORD i;
// Create a HDEVINFO with all present devices.
hDevInfo = SetupDiGetClassDevs(
NULL,
0, // Enumerator
0,
DIGCF_PRESENT | DIGCF_ALLCLASSES);
if (INVALID_HANDLE_VALUE == hDevInfo)
{
// Insert error handling here.
return 1;
}
// Enumerate through all devices in Set.
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
for (i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData); i++)
{
LPTSTR buffer = NULL;
DWORD buffersize = 0;
print_property(hDevInfo, DeviceInfoData, L"Friendly name :", SPDRP_FRIENDLYNAME);
while (!SetupDiGetDeviceInstanceId(
hDevInfo,
&DeviceInfoData,
buffer,
buffersize,
&buffersize))
{
if (buffer)
{
LocalFree(buffer);
}
if (ERROR_INSUFFICIENT_BUFFER == GetLastError())
{
// Change the buffer size.
// Double the size to avoid problems on
// W2k MBCS systems per KB 888609.
buffer = (LPTSTR)LocalAlloc(LPTR, buffersize * 2);
}
else
{
wprintf(L"error: could not get device instance id (0x%x)\n", GetLastError());
break;
}
}
if (buffer)
{
wprintf(L"\tDeviceInstanceId : %s\n", buffer);
}
print_property(hDevInfo, DeviceInfoData, L"\tClass :", SPDRP_CLASS);
print_property(hDevInfo, DeviceInfoData, L"\tClass GUID :", SPDRP_CLASSGUID);
}
if (NO_ERROR != GetLastError() && ERROR_NO_MORE_ITEMS != GetLastError())
{
// Insert error handling here.
return 1;
}
// Cleanup
SetupDiDestroyDeviceInfoList(hDevInfo);
system ("pause");
return 0;
}
You have another function defined inside the body of main; this is invalid C. Move it outside of main.
The code will compile and run if you comment out the following two lines as shown:
// int setupdi_version()
// {
I think the original code is from a function named setupdi_version() and it got mangled a bit when you tried to change it to main(). Note: it looks like the original source code is from here.
To answer your follow-on problem. Those are linker errors. You need to tell Visual Studio which .lib file(s) to link against. You can do that in the Visual Studio project dependencies or just add the following to the top of the source code.
#pragma comment(lib,"SetupAPI")

Resources