Compiling an already written C script. Visual Studios 2017 - c

I have an already written script for C that I want to use to go along with Texmod. There was post about it a long time ago but I can't access it. Basically it lets you use TexMod with arguments for the .exe like -log. I have downloaded Visual Studios 2017 and have tried compiling it using the developers console by cd to the folder than cl 'script.c' to compile it. It makes an .exe and .obj but does nothing past that, even when I double click the .exe The problem is I know java and have never done anything in the C language. Here is the code:
#include <stdio.h>
#include <windows.h>
#include <tlhelp32.h>
UINT WINAPI EzGetPid(LPCSTR procName, UINT *pid, UINT size);
int main(int argc, char *argv[])
{
if (argc < 1) {
puts("You must specifie the arguments");
return 1;
}
UINT pid = 0;
if (!EzGetPid("Texmod.exe", &pid, 1)) {
puts("You must open Texmod first.");
return 1;
}
BYTE shellcode_tramp[] = "\x58\x6A\x00\x6A\x00\x68\x00\x00\x00\x00\xFF\xE0";
UINT size_tramp = 12;
char arguments[0x500] = {0};
strcpy(arguments, argv[1]);
HANDLE proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
LPVOID remote_tramp = VirtualAllocEx(proc, NULL, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
LPVOID remote_args = (LPVOID)((DWORD)remote_tramp + size_tramp);
*(DWORD*)(&shellcode_tramp[6]) = (DWORD)remote_args;
WriteProcessMemory(proc, remote_tramp, shellcode_tramp, size_tramp, NULL); // Write the trampoline
WriteProcessMemory(proc, remote_args, arguments, strlen(arguments), NULL); // Write the arguments
BYTE firstCall[] = "\xE8\x00\x00\x00\x00\x90";
BYTE secondCall[] = "\xE8\x00\x00\x00\x00\x90";
*(DWORD*)(&firstCall[1]) = (DWORD)remote_tramp - 0x4012E1 - 5;
*(DWORD*)(&secondCall[1]) = (DWORD)remote_tramp - 0x40145B - 5;
WriteProcessMemory(proc, (LPVOID)0x4012E1, firstCall, 6, NULL); // Write first detour call
WriteProcessMemory(proc, (LPVOID)0x40145B, secondCall, 6, NULL); // Write second detour call
CloseHandle(proc);
return 0;
}
UINT WINAPI EzGetPid(LPCSTR procName, UINT *pid, UINT size)
{
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 buffer = {0};
buffer.dwSize = sizeof(PROCESSENTRY32);
UINT count = 0;
while (Process32Next(hSnap, &buffer) && count < size) {
if (!strcmp(buffer.szExeFile, procName))
pid[count++] = buffer.th32ProcessID;
}
CloseHandle(hSnap);
return count;
}
p.s. I added the last closed bracket as I thought I may have copied it wrong when I copied it long ago.
Do I need to use the Visual Studios interface to do this? I was wondering if someone that knows C could look at the code I'm trying to compile and help explain anything I am missing or any special instructions as to how to run it.
Thank you very much for all help.

Your program requires arguments in order to run correctly. The reason you're program doesn't do anything is because when double clicking it, you're not passing any arguments. The console is closing before you see the debug message "You must specifie the arguments".
Typically it's much easier to deal with trampoline hooks using an internal injected DLL method rather than this external method. You could start the process in a suspended state then inject your DLL to perform the trampoline hook. Then you can easily modify the function arguments of the function you're hooking.
Here is the code I use for x86 trampoline hooks
bool Detour32(BYTE* src, BYTE* dst, const uintptr_t len)
{
if (len < 5) return false;
DWORD curProtection;
VirtualProtect(src, len, PAGE_EXECUTE_READWRITE, &curProtection);
uintptr_t relativeAddress = dst - src - 5;
*src = 0xE9;
*(uintptr_t*)(src + 1) = relativeAddress;
VirtualProtect(src, len, curProtection, &curProtection);
return true;
}
BYTE* TrampHook32(BYTE* src, BYTE* dst, const uintptr_t len)
{
if (len < 5) return 0;
//Create Gateway
BYTE* gateway = (BYTE*)VirtualAlloc(0, len, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
//write the stolen bytes to the gateway
memcpy_s(gateway, len, src, len);
//Get the gateway to destination address
uintptr_t gatewayRelativeAddr = src - gateway - 5;
// add the jmp opcode to the end of the gateway
*(gateway + len) = 0xE9;
//Write the address of the gateway to the jmp
*(uintptr_t*)((uintptr_t)gateway + len + 1) = gatewayRelativeAddr;
//Perform the detour
Detour32(src, dst, len);
return gateway;
}
Here is an example of how I use it to took OpenGL's SwapBuffers function, in this example we will change the hDc argument to 1337.
typedef BOOL(__stdcall* twglSwapBuffers) (HDC hDc);
twglSwapBuffers owglSwapBuffers;
BOOL __stdcall hkwglSwapBuffers(HDC hDc)
{
hDc = 1337;
return owglSwapBuffers(hDc);
}
owglSwapBuffers = (twglSwapBuffers)mem::TrampHook32((BYTE*)owglSwapBuffers, (BYTE*)hkwglSwapBuffers, 5);

Related

C library works by itself in executable form, but when used as Rust library using CC, it no longer works

I am trying to inject a dll into a specific application in rust. I gave up trying to do so in pure rust, as it was not working no matter what. So, I used a C injector and compiled it and it worked perfectly. However, when I use the CC crate to compile it and use the function, it no longer works at all. In this case, I was simply trying to inject a dll I made.
The code for the C is:
// test.c
#include <windows.h>
#include <TlHelp32.h>
#include <stdio.h>
#pragma comment(lib, "ntdll.lib")
EXTERN_C NTSYSAPI NTSTATUS NTAPI NtCreateThreadEx(PHANDLE,
ACCESS_MASK, LPVOID, HANDLE, LPTHREAD_START_ROUTINE, LPVOID,
BOOL, SIZE_T, SIZE_T, SIZE_T, LPVOID);
struct NtCreateThreadExBuffer
{
SIZE_T Size;
SIZE_T Unknown1;
SIZE_T Unknown2;
PULONG Unknown3;
SIZE_T Unknown4;
SIZE_T Unknown5;
SIZE_T Unknown6;
PULONG Unknown7;
SIZE_T Unknown8;
};
DWORD GetPid(const wchar_t *targetProcess)
{
HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 procEntry;
procEntry.dwSize = sizeof(procEntry);
if (snap && snap != INVALID_HANDLE_VALUE && Process32First(snap, &procEntry))
{
do
{
if (!wcscmp(procEntry.szExeFile, targetProcess))
{
break;
}
} while (Process32Next(snap, &procEntry));
}
CloseHandle(snap);
return procEntry.th32ProcessID;
}
void injectAmongUs()
{
DWORD dwPid = GetPid(L"Among Us.exe");
struct NtCreateThreadExBuffer ntbuffer;
memset(&ntbuffer, 0, sizeof(struct NtCreateThreadExBuffer));
DWORD temp1 = 0;
DWORD temp2 = 0;
ntbuffer.Size = sizeof(struct NtCreateThreadExBuffer);
ntbuffer.Unknown1 = 0x10003;
ntbuffer.Unknown2 = 0x8;
ntbuffer.Unknown3 = (DWORD *)&temp2;
ntbuffer.Unknown4 = 0;
ntbuffer.Unknown5 = 0x10004;
ntbuffer.Unknown6 = 4;
ntbuffer.Unknown7 = &temp1;
ntbuffer.Unknown8 = 0;
HANDLE proc = OpenProcess(GENERIC_ALL, 0, dwPid);
HANDLE hThread;
wchar_t path[] = L"path/to/dll";
LPVOID allocAddr = VirtualAllocEx(proc, 0, sizeof(path), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(proc, allocAddr, path, sizeof(path), NULL);
NTSTATUS status = NtCreateThreadEx(&hThread, GENERIC_ALL, NULL, proc,
(LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryW"), allocAddr,
FALSE, NULL, NULL, NULL, &ntbuffer);
}
If I compile this file exactly the way it is but add a main method:
int main()
{
injectAmongUs();
return 1;
}
It works perfectly as intended. However, if I remove the main method and use CC with this build script:
// build.rs
fn main() {
cc::Build::new()
.file("test.c")
.compile("injector.dll");
}
and then call it in main with
//main.rs
extern "C" {
fn injectAmongUs();
}
fn main() {
unsafe {
injectAmongUs();;
}
}
which results in (exit code: 0xc0000005, STATUS_ACCESS_VIOLATION).
How can I get it to successfully inject as if I just ran the .exe normally? Currently I just put the .exe with it, but that is not desirable and would rather it be built and used as a library. Note, I am trying to inject Among Us, and so I am running this as 32 bit with cargo run --target i686-pc-windows-msvc.

Getting volume value from pulseaudio

I've written this code by looking at various examples: Python pulseaudio monitor, Pavumeter source, async playback example, and Pacat source.
I have successfully connected to a sink and am able to record it, but my problem is, I'm stuck at getting the volume value out. If I try printing value from the read function, I just get a bunch of random numbers at a second's interval.
Now I'm not asking for someone to finish writing the code for me, I'd just like some tips, help so that I could head towards the right direction. How do I retrieve the volume value?
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <pulse/pulseaudio.h>
static int latency = 20000; // start latency in micro seconds
static int sampleoffs = 0;
static short sampledata[300000];
static pa_buffer_attr bufattr;
static int underflows = 0;
static pa_sample_spec ss;
// This callback gets called when our context changes state. We really only
// care about when it's ready or if it has failed
void pa_state_cb(pa_context *c, void *userdata) {
pa_context_state_t state;
int *pa_ready = userdata;
state = pa_context_get_state(c);
switch (state) {
// These are just here for reference
case PA_CONTEXT_UNCONNECTED:
case PA_CONTEXT_CONNECTING:
case PA_CONTEXT_AUTHORIZING:
case PA_CONTEXT_SETTING_NAME:
default:
break;
case PA_CONTEXT_FAILED:
case PA_CONTEXT_TERMINATED:
*pa_ready = 2;
break;
case PA_CONTEXT_READY:
*pa_ready = 1;
break;
}
}
static void stream_read_cb(pa_stream *s, size_t length, void *userdata) {
const void *data;
pa_stream_peek(s, &data, &length);
data = (const unsigned char*) data;
printf("%u", data);
pa_stream_drop(s);
}
int main(int argc, char *argv[]) {
pa_mainloop *pa_ml;
pa_mainloop_api *pa_mlapi;
pa_context *pa_ctx;
pa_stream *recordstream;
int r;
int pa_ready = 0;
int retval = 0;
unsigned int a;
double amp;
int test = 0;
// Create a mainloop API and connection to the default server
pa_ml = pa_mainloop_new();
pa_mlapi = pa_mainloop_get_api(pa_ml);
pa_ctx = pa_context_new(pa_mlapi, "Simple PA test application");
pa_context_connect(pa_ctx, NULL, 0, NULL);
// This function defines a callback so the server will tell us it's state.
// Our callback will wait for the state to be ready. The callback will
// modify the variable to 1 so we know when we have a connection and it's
// ready.
// If there's an error, the callback will set pa_ready to 2
pa_context_set_state_callback(pa_ctx, pa_state_cb, &pa_ready);
// We can't do anything until PA is ready, so just iterate the mainloop
// and continue
while (pa_ready == 0) {
pa_mainloop_iterate(pa_ml, 1, NULL);
}
if (pa_ready == 2) {
retval = -1;
goto exit;
}
ss.rate = 44100;
ss.channels = 2;
ss.format = PA_SAMPLE_U8;
recordstream = pa_stream_new(pa_ctx, "Record", &ss, NULL);
if (!recordstream) {
printf("pa_stream_new failed\n");
}
pa_stream_set_read_callback(recordstream, stream_read_cb, NULL);
r = pa_stream_connect_record(recordstream, NULL, NULL, PA_STREAM_PEAK_DETECT);
if (r < 0) {
printf("pa_stream_connect_playback failed\n");
retval = -1;
goto exit;
}
// Run the mainloop until pa_mainloop_quit() is called
// (this example never calls it, so the mainloop runs forever).
// printf("%s", "Running Loop");
pa_mainloop_run(pa_ml, NULL);
exit:
// clean up and disconnect
pa_context_disconnect(pa_ctx);
pa_context_unref(pa_ctx);
pa_mainloop_free(pa_ml);
return retval;
}
Looking at the original question from UNIX.StackExchange, it looks like you're trying to create a VU meter. It can be done using an envelope detector. You have to read the input values and then average their rectified value. A simple envelope detector can be done as an exponential moving average filter.
float level = 0; // Init time
const float alpha = COEFFICIENT; // See below
...
// Inside sample loop
float input_signal = fabsf(get_current_sample());
level = level + alpha * (input_signal - level);
Here, alpha is the filter coefficient, which can be calculated as:
const float alpha = 1.0 - expf( (-2.0 * M_PI) / (TC * SAMPLE_RATE) );
Where TC is known as the "time constant" parameter, measured in seconds, which defines how fast you want to "follow" the signal. Setting it too short makes the VU meter very "bumpy" and setting it too long will miss transients in the signal. 10 mS is a good value to start from.

Shared library function does working correctly after first dlopen

I am creating a websocket server in C. Since taking a server down, recompiling it, and running it again is counterproductive to what a server app should do, I am looking for ways to dynamically load in my functions so that I can keep the main server app running while being able to alter / create new functions that will be used in it. I created a function that allows me to call a function by name with correct arguments like you would a normal function call, but when I go to call it the second time it does not do the same thing the second time I call it dynamically. To lay out my problem by steps, consider the following situations:
Situation 1
Start server application without calling sendMessage dynamically.
Connect to the websocket server via browser.
After successful connection send a message to the server (I use Hello World)
Server will echo the message the client sent.
Send the same message to the server again.
Server will echo message again. (this is when the server sendMessage function is not loaded dynamically
Repeating steps 5 and 6 will not cause the client to disconnect.
Now for the situation using a dynamic version of the servers sendMessage function to echo the client message.
Situation 2
Start server application while allowing sendMessage to be called using loadFunction.
Connect to the websocket server via browser.
After successful connection send a message to the server (again I use Hello World)
Server will echo the message the client sent like it should.
Send the same message to the server again.
This time the server does not echo the message the client sent.
Sending more messages after the first will eventually cause the connection to end (This is where I am having a problem
Situation 1 is when my function sendMessage is called normally (not through loadFunction) while situation 2 is where I replace sendMessage with my loadFunction call that loads the library holding sendMessage, assigns it to a location function variable (see code) and call the function like it would normally.
I am thinking that the problem lies with the write function in sendMessage when I dynamically load it. But the function works perfectly when I don't load it dynamically which is odd to me.
My question is why is why would my sendMessage function operate differently from when I call it normally and when I call it dynamically? Below is some code and output from both situations
sendMessage.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <unistd.h>
#include "include/structs.h"
//#include "include/functions.h"
/*
* sendMessage: this function is used then we want to send message (s)
* of length (len) from the server to a client (sock)
*
* ARGUMENTS
* sock: the socket where we want the message to go
* s: A string containing the message we want to send
* len: the length of the string s
*/
void *sendMessage(int sock, char *s, int len) {
int frameCount;
uint16_t len16;
char frame[10];
char *reply = malloc(sizeof(char) * (len + 8));
frame[0] = '\x81';
if (len <= 125) {
frame[1] = len;
frameCount = 2;
} else if (len >= 126 && len <= 65535) {
frame[1] = 126;
len16 = htons(len);
memcpy(frame + 2, &len16, 2);
frameCount = 4;
} else {
frame[1] = 127;
//NOTE: HAVE NOT FULLY CONFIGURED A MESSAGE OF THIS LENGTH (TODO)
//frame[2] = (char)( ((char)len >> 56) & (char)255 );
//frame[3] = (char)( ((char)len >> 48) & (char)255 );
//frame[4] = (char)( ((char)len >> 40) & (char)255 );
//frame[5] = (char)( ((char)len >> 32) & (char)255 );
//frame[6] = (char)( ((char)len >> 24) & (char)255 );
frame[7] = (char)( ((char)len >> 16) & (char)255 );
frame[8] = (char)( ((char)len >> 8) & (char)255 );
frame[9] = (char)( ((char)len) & (char)255 );
frameCount = 10;
}//END IF
memcpy(reply, frame, frameCount);
memcpy(reply + frameCount, s, len);
//printf("sock: %d\ts: %s\tlen: %d\n", sock, s, len);
if (write(sock, reply, strlen(reply)) <= 0) {
printf("\n\nWE ARE NOT WRITING!!\n\n");
} else {
//printf("we did write\n");
}//END IF
free(reply);
reply = NULL;
return NULL;
}//END FUNCTION
loadFunction.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
#include "include/functions.h"
int checkForError(char *error) {
if (error != NULL) {
printf("ERROR: %s\n", error);
exit(EXIT_FAILURE);
}//END IF
return 0;
}//END IF
void * loadFunction(char *func, void ** args) {
void *handle;
//void * (*alterStruct)(int sock, char *action);
int filenameLength;
char * filename;
//void *(*funcPtr);
filenameLength = strlen("lib/lib") + strlen(func) + strlen(".dll");
filename = malloc(sizeof(char) * (filenameLength + 1));
strcpy(filename, "lib/lib");
strcat(filename, func);
strcat(filename, ".dll");
handle = dlopen(filename, RTLD_LAZY);
free(filename);
if (!handle) {
checkForError(dlerror());
}//END IF
dlerror();
if (strncmp(func, "sendMessage", strlen(func)) == 0) {
void * (*funcPtr)(int, char *, int);
//*(void **) (&funcPtr) = dlsym(handle, func);
funcPtr = (void *)dlsym(handle, func);
checkForError(dlerror());
(*funcPtr)((int)args[0], (char *)args[1], (int)args[2]);
//free(*(void **)(&funcPtr));
//*(void **) (&funcPtr) = NULL;
}// else if (strncmp(func, "alterStruct", strlen(func)) == 0) {
//void * (*funcPtr)(int sock, char *action);
//} else if (strncmp(func, "execute", strlen(func)) == 0) {
//void * (*funcPtr)(const char *command, clientStruct s, FILE **in, FILE **out, FILE **err);
//} else {
//void * (*funcPtr)(int sock, char *s, int len);
//}//END IF
dlclose(handle);
handle = NULL;
return NULL;
return NULL;
}//END loadFunction
If you need more code to solve this problem I have it accessable on GitHub here (the dynamic branch is where the problem can be found)
Also, I am using Cygwins' GNU gcc compiler (which I have never have a problem compiling on) to compile my application and libraries so I may not have access to certain Linux commands (for example dlmopen). That said, please do not say use a different compiler because I've had no other problems thus far and I do not intend on changing how I compile my code.
I did not document the command I use to compile just the libsendMessage.dll used in loadFunction. you can obtain it using the following
gcc -c -fPIC sendMessage.c
mv sendMessage.o objects/sendMessage.o
gcc -shared -o lib/libsendMessage.dll objects/sendMessage.o libfunctions.c
Thank you in advance.
I have figured out my problem and it is quite an odd one.
When i was testing the sendMessage function using my dynamic method i printf exactly what was being sent through the socket and apparently it was sending the correct message. However, it was also sending the characters from my filename variable in the loadFunction function which to me is strange that the memory address was accessable to sendMessage when it was malloced, freed and set to NULL way before the function call to the dynamic sendMessage was called.
Solution
After I opened my library with dlopen(filename, RTLD_LAZY) I used memset(filename, '\0', filenameLength) to write null characters to the memory address of filename making the string contain all null characters which when accessed as a character counts as a end of string.
I'm not sure why I am having to use memset so much in this application but i know that it has fixed string bugs for me multiple times.

Working example of substitution using PCRS

I need to to substitution in a string in C. It was recommended in one of the answers here How to do regex string replacements in pure C? to use the PCRS library. I downloaded PCRS from here ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/Contrib/ but I'm confused as to how to use it. Below is my code (taken from another SE post)
const char *error;
int erroffset;
pcre *re;
int rc;
int i;
int ovector[100];
char *regex = "From:([^#]+).*";
char str[] = "From:regular.expressions#example.com\r\n";
char stringToBeSubstituted[] = "gmail.com";
re = pcre_compile (regex, /* the pattern */
PCRE_MULTILINE,
&error, /* for error message */
&erroffset, /* for error offset */
0); /* use default character tables */
if (!re)
{
printf("pcre_compile failed (offset: %d), %s\n", erroffset, error);
return -1;
}
unsigned int offset = 0;
unsigned int len = strlen(str);
while (offset < len && (rc = pcre_exec(re, 0, str, len, offset, 0, ovector, sizeof(ovector))) >= 0)
{
for(int i = 0; i < rc; ++i)
{
printf("%2d: %.*s\n", i, ovector[2*i+1] - ovector[2*i], str + ovector[2*i]);
}
offset = ovector[1];
}
As opposed to 'pcre_compile' and 'pcre_exec' what functions do I need to use from PCRS?
Thanks.
Simply follow the instructions in the INSTALL file:
To build PCRS, you will need pcre 3.0 or later and gcc.
Installation is easy: ./configure && make && make install
Debug mode can be enabled with --enable-debug.
There is a simple demo application (pcrsed) included.
PCRS provides the following functions documented in the man page pcrs.3:
pcrs_compile
pcrs_compile_command
pcrs_execute
pcrs_execute_list
pcrs_free_job
pcrs_free_joblist
pcrs_strerror
Here's an online version of the man page. To use these functions, include the header file pcrs.h and link your program against the PCRS library using the linker flag -lpcrs.

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