www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Whats the correct way to pass a D array type to a win32 api function

reply FoxyBrown <Foxy Brown.IPT> writes:
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;
}
Jul 12
next sibling parent Nicholas Wilson <iamthewilsonator hotmail.com> writes:
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.
Jul 12
prev sibling next sibling parent Adam D. Ruppe <destructionator gmail.com> writes:
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.
Jul 12
prev sibling parent John Chapman <johnch_atms hotmail.com> writes:
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.
Jul 13