Thread overview
Whats the correct way to pass a D array type to a win32 api function wanting a buffer?
Jul 13, 2017
FoxyBrown
Jul 13, 2017
Nicholas Wilson
Jul 13, 2017
Adam D. Ruppe
Jul 13, 2017
John Chapman
July 13, 2017
Everything I do results in some problem, I've tried malloc but then converting the strings resulted in my program becoming corrupted.


Heres the code:

auto EnumServices()
{

    auto schSCManager = OpenSCManager(null, null, SC_MANAGER_ALL_ACCESS);
    if (NULL == schSCManager)
    {
        print("OpenSCManager failed (%d)\n", GetLastError());
        return null; // Why can't we return a null? Surely we don't have to cast a null in to a typeof null?
    }
	
	import core.stdc.stdlib;
	
	DWORD dwBytesNeeded, dwCount, lpResumeHandle, resume;

	auto servicesType = (SERVICE_DRIVER | SERVICE_FILE_SYSTEM_DRIVER | SERVICE_KERNEL_DRIVER | SERVICE_WIN32 | SERVICE_WIN32_OWN_PROCESS | SERVICE_WIN32_SHARE_PROCESS);


	
	ENUM_SERVICE_STATUS_PROCESS[5000] services;
	auto res = SVC.EnumServicesStatusExA(schSCManager, SC_ENUM_TYPE.SC_ENUM_PROCESS_INFO, servicesType, SERVICE_STATE_ALL, cast(ubyte*)services.ptr, 5000*ENUM_SERVICE_STATUS_PROCESS.sizeof, &dwBytesNeeded, &dwCount, &resume, cast(const(char)*)null);
	
	
	for(int i = 0; i < dwCount; i++)
	{
		auto s = services[i].lpServiceName;
		writeln(*s);				
	}


	return services;
}
July 13, 2017
On Thursday, 13 July 2017 at 01:15:46 UTC, FoxyBrown wrote:
> Everything I do results in some problem, I've tried malloc but then converting the strings resulted in my program becoming corrupted.
>
>
> Heres the code:
>
> auto EnumServices()
> {
>
>     auto schSCManager = OpenSCManager(null, null, SC_MANAGER_ALL_ACCESS);
>     if (NULL == schSCManager)
>     {
>         print("OpenSCManager failed (%d)\n", GetLastError());
>         return null; // Why can't we return a null? Surely we don't have to cast a null in to a typeof null?
>     }
> 	
> 	import core.stdc.stdlib;
> 	
> 	DWORD dwBytesNeeded, dwCount, lpResumeHandle, resume;
>
> 	auto servicesType = (SERVICE_DRIVER | SERVICE_FILE_SYSTEM_DRIVER | SERVICE_KERNEL_DRIVER | SERVICE_WIN32 | SERVICE_WIN32_OWN_PROCESS | SERVICE_WIN32_SHARE_PROCESS);
>
>
> 	
> 	ENUM_SERVICE_STATUS_PROCESS[5000] services;
> 	auto res = SVC.EnumServicesStatusExA(schSCManager, SC_ENUM_TYPE.SC_ENUM_PROCESS_INFO, servicesType, SERVICE_STATE_ALL, cast(ubyte*)services.ptr, 5000*ENUM_SERVICE_STATUS_PROCESS.sizeof, &dwBytesNeeded, &dwCount, &resume, cast(const(char)*)null);
> 	
> 	
> 	for(int i = 0; i < dwCount; i++)
> 	{
> 		auto s = services[i].lpServiceName;
> 		writeln(*s);				
> 	}
>
>
> 	return services;
> }

What is the signature of the function you are trying to call? (make sure its correct :))
Allocating 5000 services may blow your stack.
you can just use `services.sizeof` instead of `5000*ENUM_SERVICE_STATUS_PROCESS.sizeof`.
You are returning that massive static array, remember that static arrays are value types in D so that will get copied. Consider allocating the array and returning a slice of it.

Note also that `lpServiceName` is probably a `char*` so drefferencing will give you a char, not a string. Use std.string.fromStringz(?) for that.
July 13, 2017
On Thursday, 13 July 2017 at 01:15:46 UTC, FoxyBrown wrote:
> auto EnumServices()

I wouldn't use auto here. The reason you get mismatch types on return here since you don't return consistent types inside.


> 	ENUM_SERVICE_STATUS_PROCESS[5000] services;

Are you sure you are getting the same A vs W version there? You explicitly call the A version of the function, but do not specify it here.

> 		auto s = services[i].lpServiceName;
> 		writeln(*s);				

Like the other user above said, you should be treating that like a C string anyway. Use printf or fromStringz or slice it yourself... just make sure you tend to char vs wchar like above.

> 	return services;

That's kinda hideous, returning the entire buffer by value. I do NOT recommend you attempt to slice and dup though, since the win32 function uses space at the end of the buffer to store the strings referenced by the structs.

Ideally, you'd avoid returning this thing at all and just use it locally. Perhaps pass a callback function/delegate that takes each item as you iterate through.
July 13, 2017
On Thursday, 13 July 2017 at 01:15:46 UTC, FoxyBrown wrote:
> 	ENUM_SERVICE_STATUS_PROCESS[5000] services;
> 	auto res = SVC.EnumServicesStatusExA(schSCManager, SC_ENUM_TYPE.SC_ENUM_PROCESS_INFO, servicesType, SERVICE_STATE_ALL, cast(ubyte*)services.ptr, 5000*ENUM_SERVICE_STATUS_PROCESS.sizeof, &dwBytesNeeded, &dwCount, &resume, cast(const(char)*)null);

You need to call EnumServicesStatusEx twice - the first time to get the required size of the buffer. See the docs for the lpServices parameter here https://msdn.microsoft.com/en-us/library/windows/desktop/ms682640(v=vs.85).aspx

Then allocate a buffer using the returned dwBytesNeeded and call the function again with your buffer and its size.