Can Win32 applications open the system's settings from code? - c

Is it possible to open Windows' settings dialogs using Win32 API calls from C? Such as the monitor settings (the one that allows you to set the monitor's resolution), and the network settings (the one that allows you to set the Wifi settings).
If it is possible, how to do that?
Or, is this not possible at all, and the user has to manually open them?

Launch the Windows Settings app explains how to pull up the Windows Settings app using the ms-settings: URI scheme. It also lists the supported URIs, including the ones this question is asking for (ms-settings:network-wifi and ms-settings:display).
While the documentation proposes using the Windows Runtime API Launcher.LaunchUriAsync this is a fair bit complex with C (as opposed to C++). Since the URIs can be invoked from the command prompt using the start command (e.g. start ms-settings:display), it's reasonable to assume that ShellExecuteExW can handle the ms-settings: URI scheme as well.
And indeed, this does appear to work:
#include <Windows.h>
#include <stdio.h>
int main() {
SHELLEXECUTEINFOW sei = {
.cbSize = sizeof(sei),
.hwnd = NULL,
.lpVerb = L"open",
.lpFile = L"ms-settings:display",
//.lpFile = L"ms-settings:network-wifi",
.nShow = SW_SHOWNORMAL,
};
if (!ShellExecuteExW(&sei))
{
printf("Failed with error code %d", GetLastError());
}
}
I wasn't able to find any documentation that specifies this behavior, so this may well be an unsupported implementation detail. I will also mention that while SHELLEXECUTEINFOW has an lpClass field that can be used to specify a URI protocol scheme, none of my iterations to use it worked for the ms-settings: URI scheme.

Related

How do I get a list of available wifi-connections? [duplicate]

I would like to get a list of the wireless networks available. Ideally this would be via some C call, but I don't mind if I have to kludge it with a system call. Even better if the required C call or program doesn't require some exotic 3rd party package.
The internet seems to suggest I use sudo iwlist <interface> scan which does seem to do the trick from the command line, but I'd rather not require root permissions. I only want to see the basics, not change anything.
It's pretty easy to do a scan in the command line. The man pages are your friend here (check out iwconfig and iwlist). But using the C interface is a little more difficult so I'll focus on that.
First of all, as other people have mentioned, definitely download out the wireless tools source code. All the documentation for the programming interface is in the .c files. As far as I can tell, there is no web documentation for the api. However, the source code is pretty easy to read through. You pretty much only need iwlib.h and iwlib.c for this question.
While you can use iw_set_ext and iw_get_ext, the libiw implements a basic scanning function iw_scan, from which you can extract most of the information that you need.
Here is a simple program to get the ESSID for all available wireless networks. Compile with -liw and run with sudo.
#include <stdio.h>
#include <time.h>
#include <iwlib.h>
int main(void) {
wireless_scan_head head;
wireless_scan *result;
iwrange range;
int sock;
/* Open socket to kernel */
sock = iw_sockets_open();
/* Get some metadata to use for scanning */
if (iw_get_range_info(sock, "wlan0", &range) < 0) {
printf("Error during iw_get_range_info. Aborting.\n");
exit(2);
}
/* Perform the scan */
if (iw_scan(sock, "wlan0", range.we_version_compiled, &head) < 0) {
printf("Error during iw_scan. Aborting.\n");
exit(2);
}
/* Traverse the results */
result = head.result;
while (NULL != result) {
printf("%s\n", result->b.essid);
result = result->next;
}
exit(0);
}
DISCLAIMER: This is just a demonstration program. It's possible for some results to not have an essid. In addition, this assumes your wireless interface is "wlan0". You get the idea.
Read the iwlib source code!
The Wireless Tools package -- of which iwlist is a part -- also contains a Wireless Tools Helper Library. You need to include iwlib.h and link with libiw.a (i.e. add -liw). Then look up the documentation for the iw_set_ext function. The SIOCSIWSCAN parameter will be of most use. For an example of how to use this interface, take a look at the KWifiManager source in the KDE library (see: Interface_wireless_wirelessextensions::get_available_networks method). Alternatively, you can also download the Wireless Tools source code and take a look at how the iwlib iw_set_ext function is also used for scanning in iwlist.c.
As for privileges, I imagine the process will need to run as root to perform the scan. I'd love to know if this could be done otherwise as well.
Since you are using Ubuntu 8.04 the libiw-dev package should be of use.
You can use nmcli which does not require root permissions or name of WIFI interface.
nmcli -t -f ssid dev wifi

uefi specifications example mentions EfiCoreImageHandle. How to get it?

Quoting the UEFI specifications section about EFI_BOOT_SERVICES.HandleProtocol():
The HandleProtocol() function is still available for use by old EFI
applications and drivers. However, all new applications and drivers
should use EFI_BOOT_SERVICES.OpenProtocol() in place of
HandleProtocol(). The following code fragment shows a possible
implementation of HandleProtocol() using OpenProtocol(). The variable
EfiCoreImageHandle is the image handle of the EFI core.
EFI_STATUS
HandleProtocol (
IN EFI_HANDLE Handle,
IN EFI_GUID *Protocol,
OUT VOID **Interface
)
{
return OpenProtocol (
Handle,
Protocol,
Interface,
EfiCoreImageHandle,
NULL,
EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
);
}
End of quote.
My question is: how to get the value for EfiCoreImageHandle when an EFI application was run by a boot manager, or from a UEFI shell?
Simply put, EfiCoreImageHandle is just a placeholder in the specification. Have a look at how I invoke OpenProtocol in the ShowEDID utility in https://github.com/fpmurphy/UEFI-Utilities-2019.
Also look at the ShowUSB utility where I currently use HandleProtocol, i.e.
Status = gBS->HandleProtocol( HandleBuffer[Index],
&gEfiUsbIoProtocolGuid,
(VOID**)&UsbIo );
I could replace the above code with:
Status = gBS->OpenProtocol( HandleBuffer[Index],
&gEfiUsbIoProtocolGuid,
(VOID **)&UsbIo,
gImageHandle,
NULL,
EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL );
Tested with UDK2018 and Lenovo T480

Close device/socket in VxWorks

Is there a way to close the device/socket in VxWorks programmatically?
Meaning say I have the devices /tyco/0, /tyco/1 and /tyco/2 and I want to close/shutdown /tyco/1 and /tyco/2.
I would like to do something like remove("/tyco/1"). Something that would prevent even an open("/tyco/1") call later on in the code or from an outside source from opening the socket.
All devices available to VxWorks are part of the device list. The device list is accessible using the iosLib.
I've used the following code a lot to remove devices to generate errors in order to test my programs:
DEV_HDR *pDevice;
pDevice = iosDevFind("/xyz", NULL);
if (pDevice != NULL)
{
iosDevDelete(pDevice);
}
This works for all devices listed by the devs command which in your case will also work for "/tyco". I doubt that you can inhibit open calls to "/tyco/1" and "/tyco/2" but allow calls to "/tyco/0" using that method since it works on "devices".
If "/tyco/0" is your serial interface to the VxWorks shell then the method from above will work. Because removing a device from the device list will cause all following open calls to that device to fail but will not close already opened devices...

How to get os name, version in windows?

Which one is better in following aspects to get OS name, OS version in windows -
time in getting information
compatibility in all windows OS like xp, vista and higher
systeminfo or wmic command? I wanted to avoid the use of OSVersionInfoEx in C as one has to hardcode the marketing name detection and will add to maintenance work if new flavour of windows gets introduced. Please share your opinion.
GetVersionEx - You can't get any faster than this for getting a basic os version number. But you are right, you won't be able to map newer versions of the OS to the correct string. Have you considered just doing this:
OSVERSIONINFOEX version = {};
char szOS[MAX_OS_LENGTH];
version.dwOSVersionInfoSize = sizeof(version);
GetVersionEx((OSVERSIONINFO*)&version);
if (MyFunctionToMapVersionToString(&version, szOS) == false)
{
sprintf(szOS, "Microsoft Windows %d.%d", version.dwMajorVersion, version.dwMinorVersion);
}
WMI - A bit more code to write. But you could likely just do this at app startup (or when it's needed) and cache the result if the information is needed again. It's not like the operating system product name will change after the app has queried for it once. :) As to backwards compatibility, I'm sure it work fine on older operating systems... but you are going to test it before shipping it to the customer, right?
If you want an undocumented way, there is a registry key that has exactly what you want in it:
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion ("ProductName")

How can I make the printer work in C in MS VC++ Express edition?

I am using VC++ 2008 express edition for C. When I try to run this:
/* Demonstrates printer output. */
#include <stdio.h>
main()
{
float f = 2.0134;
fprintf(stdprn, "This message is printed.\n\n");
fprintf(stdprn, "And now some numbers:\n\n");
fprintf(stdprn, "The square of %f is %f.", f, f*f);
/* Send a form feed */
fprintf(stdprn, "\f");
}
I get four of these errors: error C2065: 'stdprn' : undeclared identifier.
On this forum, they wrote that it works to define the printer as follows:
FILE *printer;
printer = fopen("PRN", "w");
EDIT
It builds with a warning that fopen is unsafe. When it runs the error appears:
Debug Assertion fails.
File: f:\dd\vctools\crt_bld\self_x86\crt\src\fprintf.c
Line: 55
Expression: (str != NULL)
The stdprn stream was an extension provided by Borland compilers - as far as I know, MS have never supported it. Regarding the use of fopen to open the printer device, I don't think this will work with any recent versions of Windows, but a couple of things to try:
use PRN: as the name instead of PRN (note the colon)
try opening the specific device using (for example) LPT1: (once again, note the colon). This will of course not work if you don't have a printer attached.
don't depend on a printer dialog coming up - you are not really using the WIndows printing system when you take this approach (and so it probably won't solve your problem, but is worth a try).
I do not have a printer attached, but I do have the Microsoft XPS document writer installed, s it shoulod at least bring up the standard Windows Print dialog from which one can choose the printer.
No. It wouldn't bring up a dialogue. This is because you are flushing data out to a file. And not going through the circuitous Win32 API.
The print doesn't work because the data is not proper PDL -- something that the printer could understand. For the print to work fine, you need to push in a PDL file, with language specific constructs. This varies from printer to printer, a PS printer will need you to push in a PostScript snippet, a PCL -- a PCL command-set and in case of MXDW you will have to write up XML based page description markup and create a zip file (with all resources embedded in it) i.e. an XPS file to get proper printout.
The PDL constructs are important because otherwise the printer doesn't know where to put the data, which color to print it on, what orientation to use, how many copies to print and so on and so forth.
Edit: I am curious why you are doing this. I understand portability is probably something you are trying to address. But apart from that, I'd like to know, there may be better alternatives available. Win32 Print Subsytem APIs are something that you ought to lookup if you are trying to print programmatically on Windows with any degree of fidelity.
Edit#2:
EDIT It builds with a warning that fopen is unsafe.
This is because MS suggests you use the safer versions nowadays fopen_s . See Security Enhancements in the CRT.
When it runs the error appears:
Debug Assertion fails. File: f:\dd\vctools\crt_bld\self_x86\crt\src\fprintf.c Line: 55
Expression: (str != NULL)
This is because fopen (whose return value you do not check) returns a NULL pointer. The file open failed. Also, if it did succeed a matching fclose call is called for.
There's no such thing as stdprn in ANSI C, it was a nonstandard extension provided by some compilers many years ago.
Today to print you have to use the specific APIs provided on your platform; to print on Windows you have to use the printing APIs to manage the printing of the document and obtain a DC to the printer and the GDI APIs to perform the actual drawing on the DC.
On UNIX-like OSes, instead, usually CUPS is used.
You can substitute the printer using this command with net use, see here on the MSDN kb
NET USE LPT1 \\server_name\printer_name
There is an excellent chapter on printing in DOS using the BIOS, ok, its a bit antiquated but interesting to read purely for nostalgic sake.
Onto your problem, you may need to use CreateFile to open the LPT1 port, see here for an example, I have it duplicated it here, for your benefit.
HANDLE hFile;
hFile = CreateFile("LPT1", GENERIC_WRITE, 0,NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
// handle error
}
OVERLAPPED ov = {};
ov.hEvent = CreateEvent(0, false, false, 0);
char szData[] = "1234567890";
DWORD p;
if (!WriteFile(hFile,szData, 10, &p, &ov))
{
if (GetLastError() != ERROR_IO_PENDING)
{
// handle error
}
}
// Wait for write op to complete (maximum 3 second)
DWORD dwWait = WaitForSingleObject(ov.hEvent, 3000);
if (dwWait == WAIT_TIMEOUT)
{
// it took more than 3 seconds
} else if (dwWait == WAIT_OBJECT_0)
{
// the write op completed,
// call GetOverlappedResult(...)
}
CloseHandle(ov.hEvent);
CloseHandle(hFile);
But if you insist on opening the LPT1 port directly, error checking is omitted...
FILE *prn = fopen("lpt1", "w");
fprintf(prn, "Hello World\n\f");
fclose(prn);
Hope this helps,
Best regards,
Tom.

Resources