I am a web developer that decided to venture into kernel mode development. I installed WDK 8.1, Visual Studio Professional 2013 and I set up a Windows 7 VM to debug and test my drivers.
I started with this tutorial
I download the solution and build the driver. I wasn’t able to do the deployment steps described in the tutorial so I tried to install the driver using the OSR Driver Loader
I was able to register the driver but when I try to start it I get the following error.
C:\Windows\system32>sc start KmfSmall
[SC] StartService FAILED 6:
The handle is invalid.
This is the driver's code:
#include <ntddk.h>
#include <wdf.h>
DRIVER_INITIALIZE DriverEntry;
EVT_WDF_DRIVER_DEVICE_ADD KmdfSmallEvtDeviceAdd;
NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
{
NTSTATUS status;
WDF_DRIVER_CONFIG config;
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "KmdfSmall: DriverEntry\n"));
WDF_DRIVER_CONFIG_INIT(&config, KmdfSmallEvtDeviceAdd);
status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, &config, WDF_NO_HANDLE);
return status;
}
NTSTATUS KmdfSmallEvtDeviceAdd(_In_ WDFDRIVER Driver, _Inout_ PWDFDEVICE_INIT DeviceInit)
{
NTSTATUS status;
WDFDEVICE hDevice;
UNREFERENCED_PARAMETER(Driver);
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "KmdfSmall: KmdfSmallEvtDeviceAdd\n"));
status = WdfDeviceCreate(&DeviceInit, WDF_NO_OBJECT_ATTRIBUTES, &hDevice);
return status;
}
I just answered what appears to be the same problem after spending a week or so trying to figure it out.
Basically boils down to the project settings missing the KMDF version.
Question: Why am I getting Error Code 6 on StartService?
Answer: https://stackoverflow.com/a/23705329/2487257
Related
Now I need to develop a plug-in that can take screenshots on Ubuntu, CentOS and fedora. I try to write it in Xlib. It can run on Ubuntu and CentOS, but Fedora uses Wayland, and the plug-in that I developed can't work.
Gnome screenshot can work on these platforms, but after reading his source code, I found that it can achieve screenshots by calling other processes, which is hard for me to learn from.
So is there any way I can take a screenshot on Wayland engine?
I get it in using dbus, here is the light code:
method_name = "Screenshot";
method_params = g_variant_new ("(bbs)",
TRUE,
FALSE, /* flash */
filename);
connection = g_application_get_dbus_connection (g_application_get_default ());
g_dbus_connection_call_sync (connection,
"org.gnome.Shell.Screenshot",
"/org/gnome/Shell/Screenshot",
"org.gnome.Shell.Screenshot",
method_name,
method_params,
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
&error);
I use the newest GTK+ installed with MSYS2 and whenever I attempt to use
g_application_send_notification() it always results in the following
assert:
(Notification Project.exe:27780): GLib-GObject-CRITICAL **: g_object_new:
assertion 'G_TYPE_IS_OBJECT (object_type)' failed
Why I think it is a bug - because I tried many code samples beside mines
(they are all quite like mines anyway), of people who got it working
(including notifaction by Lars Uebernickel) and it all makes the same
lament.
Assert, followed by crash. Now I really don't know what this means, as it
is probably within gtk internals, but I really hope some of you might have
a clue or experience with this.
install (GNU coreutils) 8.25
GIO version 2.52.3
mingw32/mingw-w64-i686-gtk-engine-unico 1.0.2-2 [installed]
mingw32/mingw-w64-i686-gtk3 3.22.16-1 [installed]
mingw32/mingw-w64-i686-gtkmm3 3.22.0-1 [installed]
mingw32/mingw-w64-i686-spice-gtk 0.33-1 [installed]
mingw32/mingw-w64-i686-webkitgtk3 2.4.11-4 [installed]
mingw64/mingw-w64-x86_64-gtk-engine-unico 1.0.2-2 [installed]
mingw64/mingw-w64-x86_64-gtk3 3.22.16-1 [installed]
mingw64/mingw-w64-x86_64-gtkmm3 3.22.0-1 [installed]
mingw64/mingw-w64-x86_64-spice-gtk 0.33-1 [installed]
mingw64/mingw-w64-x86_64-webkitgtk3 2.4.11-4 [installed]
An example of code that generates this assert:
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gtk/gtk.h>
#define ICON_PATH "/path/trash_16x16.gif"
int main (int argc, char *argv[])
{
GApplication *app;
app = g_application_new ("org.one", G_APPLICATION_FLAGS_NONE);
if(!app)
{
g_print ("Error app\n");
}
else
{
if(g_application_register (app, NULL, NULL))
{
GNotification *notification;
GFile *file;
GIcon *icon;
notification = g_notification_new ("one");
g_notification_set_body (notification, "Hello world");
file = g_file_new_for_path (ICON_PATH);
icon = g_file_icon_new (file);
g_notification_set_icon (notification, G_ICON (icon));
g_application_send_notification (app, NULL, notification);
g_object_unref (icon);
g_object_unref (file);
g_object_unref (notification);
g_object_unref (app);
g_print ("yes\n");
}
else
{
g_print ("no\n");
}
}
return 0;
}
Is that anything I can do to bypass this problem, or perhaps even solve it?
There are no notification backends that work on W32, confirmed. Contributors do wanted, once, to create such, but the API (W32 toast notifications) that is needed is COM-only, and MinGW-w64 doesn't have the necessary headers for it, yet.
Looking at the glib gio source code and GNotificationBackend interface specifically, we can see that it is simple.
Now, you could just do it in GTK...OR we could do it the right way (TM) and implement a D-Bus server for it. The good thing about a notification server is that notifications can persist even after an application is terminated. Also, GTK already has backends for talking to a notification server, so you'd only need to enable these backends on W32 (at a glance, the code doesn't use anything that doesn't work on W32 already). Also, that way the server would transparently use Shell_NotifyIcon (on Windows 7 and earlier) or toast notifications (on Windows 8 and later; if you ever get an opportunity to implement these).
Another option if you want to maintain cross-platformability is to create Shell_NotifyIcon implementation in a DLL and if windows is detected use Shell_NotifyIcon if not, GNotification as you would.
I wrote a driver in Visual Studio 2013. The building-Process was successful.
Then I prepared a traget-computer and copied the driver-files to it.
Then I installed the driver:
C:\Windows\system32>pnputil -a "E:\driverZeug\KmdfHelloWorldPackage\KmdfHelloWorld.inf"
Microsoft-PnP-Dienstprogramm
Verarbeitungsinf.: KmdfHelloWorld.inf
Das Treiberpaket wurde erfolgreich hinzugefügt.
Veröffentlichter Name: oem42.inf
Versuche gesamt: 1
Anzahl erfolgreicher Importe: 1
It seems like it was successful.
I ran DebugView on the PC but now I don't know how to start the driver, so that I can see a debug-output. I have a DbgPrintEx()-Statement in my sourcecode.
Can someone tell me how to start this driver so that I can see the output.
This is the sourcecode of the driver:
#include <ntddk.h>
#include <wdf.h>
DRIVER_INITIALIZE DriverEntry;
EVT_WDF_DRIVER_DEVICE_ADD KmdfHelloWorldEvtDeviceAdd;
NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
{
NTSTATUS status;
WDF_DRIVER_CONFIG config;
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "KmdfHelloWorld: DriverEntry\n");
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "KmdfHelloWorld: DriverEntry\n"));
WDF_DRIVER_CONFIG_INIT(&config, KmdfHelloWorldEvtDeviceAdd);
status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, &config, WDF_NO_HANDLE);
return status;
}
NTSTATUS KmdfHelloWorldEvtDeviceAdd(_In_ WDFDRIVER Driver, _Inout_ PWDFDEVICE_INIT DeviceInit)
{
NTSTATUS status;
WDFDEVICE hDevice;
UNREFERENCED_PARAMETER(Driver);
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "KmdfHelloWorld: KmdfHelloWorldEvtDeviceAdd\n"));
status = WdfDeviceCreate(&DeviceInit, WDF_NO_OBJECT_ATTRIBUTES, &hDevice);
return status;
}
You need to make an EXE(testapp) that starts your driver if installation is already done. You can use below code in the application:
SC_HANDLE schService;
SC_HANDLE schSCManager;
schSCManager = OpenSCManager(NULL, // local machine
NULL, // local database
SC_MANAGER_ALL_ACCESS // access required
);
// Open the handle to the existing service.
schService = OpenService(SchSCManager,
DriverName, //name of the driver
SERVICE_ALL_ACCESS
);
StartService(schService, // service identifier
0, // number of arguments
NULL // pointer to arguments
));
You need add code according to your need. Try this.
For more info download the samples drivers and test apps provided by microsoft.
You can use the built-in command line "sc" (service control) tool to start the driver.
The syntax is:
sc start <name>
So if your driver is installed with the name "KmdfHelloWorld" the command should be:
sc start KmdfHelloWorld
Currently, I am writing a GPIO Controller/Driver for Windows 8.1 & Windows 10 and have had similar issues. The easiest way to start your driver is to set up and provision a computer for driver testing and using Visual Studio to deploy, install, and start your driver on a remote machine.
It's good practice to write your driver then deploy and test remotely (either on another computer, or a VM such as VirtualBox), as this decrease your chances of messing up the computer you are writing code on.
To provision a computer, I used the following MSDN page:
https://msdn.microsoft.com/en-us/library/windows/hardware/dn745909?f=255&MSPPError=-2147217396
By running the prepackaged tests, you can actually have VS and Windows report on the status of the driver, get debugging info, and even set breakpoints. Trust me, for starters this is the easiest way to do this.
Also, it wouldn't hurt to register and create the callback function for the default working state, that way your driver actually does something while running. For this, use the EVT_WDF_DEVICE_D0_ENTRY define like you did for the EVT_WDF_DRIVER_DEVICE_ADD.
Happy Coding!
For my purposes, I need to write a kernel mode driver for Windows. Currently I am attempting to make it work under Windows 7 x64.
I created a simple project in Visual Studio 2012 with default code for a KMDF driver. I compiled the code with test-signing on. The driver was compiled and signed.
I also have Test-Signing ON enabled as clearly displayed on the bottom left corner of my Desktop.
Upon trying to start the driver as a service, I always get an Error Code 6: Invalid Handle error.(I have since simplified the code to just try and start it but still did not work;default code did not work either)
Basically, I am having the same problem as the question asked here
https://stackoverflow.com/questions/12080157/startservice-error-6
unfortunately he was never answered. I tried the provided solution, but it didn't help either.
My code that tries to start the driver is
int _cdecl main(void)
{
HANDLE hSCManager;
HANDLE hService;
SERVICE_STATUS ss;
hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
printf("Load Driver\n");
if(hSCManager)
{
printf("Create Service\n");
hService = CreateService(hSCManager, "Example",
"Example Driver",
SERVICE_ALL_ACCESS | SERVICE_START | DELETE | SERVICE_STOP ,
SERVICE_KERNEL_DRIVER,
SERVICE_DEMAND_START,
SERVICE_ERROR_IGNORE,
"\\path\\to\\driver\\KMDFDriver1.sys",
NULL, NULL, NULL, NULL, NULL);
if(!hService)
{
hService = OpenService(hSCManager, "Example",
SERVICE_ALL_ACCESS | SERVICE_START | DELETE | SERVICE_STOP);
if(!hService)
{
// If initial startup of the driver failed, it will fail here.
process_error();
return 0;
}
}
if(hService)
{
printf("Start Service\n");
if(StartService(hService, 0, NULL) == 0)
{
// Start service ALWAYS returns 0. Only when executed for the first time. Next time it fails on OpenService.
process_error();
printf("Did not start!\n");
}
printf("Press Enter to close service\r\n");
getchar();
ControlService(hService, SERVICE_CONTROL_STOP, &ss);
DeleteService(hService);
CloseServiceHandle(hService);
}
CloseServiceHandle(hSCManager);
}
return 0;
}
And this is the driver code
DRIVER_INITIALIZE DriverEntry;
#ifdef ALLOC_PRAGMA
#pragma alloc_text (INIT, DriverEntry)
#endif
NTSTATUS
DriverEntry(
_In_ PDRIVER_OBJECT DriverObject,
_In_ PUNICODE_STRING RegistryPath
)
{
WDF_DRIVER_CONFIG config;
NTSTATUS status;
DbgPrint("Hello World!\n");
WDF_DRIVER_CONFIG_INIT(&config,
NULL
);
config.DriverInitFlags = WdfDriverInitNonPnpDriver;
status = WdfDriverCreate(DriverObject,
RegistryPath,
WDF_NO_OBJECT_ATTRIBUTES,
&config,
WDF_NO_HANDLE
);
if (!NT_SUCCESS(status)) {
KdPrint( ("WdfDriverCreate failed with "
"status 0x%x\n", status));
}
return status;
}
The function process_error() is a wrapper around GetLastError() which in addition to providing the numeric value, displays a text version of the error code.
I have exhausted all options provided to me to solve this issue. A google search revealed only one occurrence of this problem, and the question was asked here.
What could the problem be?
Extra notes: The driver was compiled with Visual Studio 2012 Ultimate, while my startup code was compiled with MinGW-W64(using GCC). But the startup code shouldn't matter as much as the driver.
Extra notes 2: After wondering for a long time what could be wrong I started thinking if it's the test-sign certificate, because I tried driver source code provided from MSDN, and upon successful compilation, I still got ERROR_INVALID_HANDLE(Error Code 6) when trying to start it.
I have still not found a solution.
I tracked this down to the project settings of the driver. The KMDF versions were missing from the project.
Adjust the following (under Driver Model Settings):
- KMDF Version Major = 1
- KMDF Version Minor = 9
Hit OK, recompile, and reinstall. Worked for me!
A few thoughts:
You're using HANDLE hSCManager && HANDLE hService, they should be declared as SC_HANDLE
http://msdn.microsoft.com/en-us/library/windows/desktop/ms682450(v=vs.85).aspx
"lpBinaryPathName [in, optional]
The fully qualified path to the service binary file. If the path contains a space, it must be quoted so that it is correctly interpreted. For example, "d:\my share\myservice.exe" should be specified as "\"d:\my share\myservice.exe\"".
Try using the full path to the driver
I had the same problem with starting my kernel driver:
startservice failed 6:
the handle is invalid
Turned out that the "classID GUID" of the driver was the same as that of an other one (found out through device manager, looking in events showed different driver names).
Used an online generator to make a new GUID and replaced the one that's in the .inf file of the project (in VS, not any texteditor or some).
After a rebuild and deployment on target machine everything worked fine.
Hope this helps...
Run visual studio with admin privilege
Your call to OpenSCManager() is only asking for SC_MANAGER_CREATE_SERVICE permission by itself, which is not enough for OpenService() or StartService() to succeed.
I'm creating a WiX installer to install a program which connects to a database. To help with this, I've created a C dll which checks to see if a certain instance of SQL exists on a server:
extern "C" UINT __stdcall DBConTest(MSIHANDLE hInstaller)
{
FILE *fp;
fp = fopen("dbcontestdll.txt", "w");
_ConnectionPtr pCon;
int iErrCode;
HRESULT hr;
UINT rc;
//init COM
fwprintf(fp, L"entering dbcontest\n");
if(FAILED(hr = CoInitializeEx(NULL,tagCOINIT::COINIT_APARTMENTTHREADED)))
return ERROR_INVALID_DATA;
fwprintf(fp,L"did coinit\n");
if(FAILED(hr = pCon.CreateInstance(__uuidof(Connection))))
return ERROR_INVALID_DATA;
fwprintf(fp,L"created instance of connection\n");
TCHAR constr[1024];
DWORD constrlen = sizeof(constr);
rc=MsiGetProperty(hInstaller,TEXT("DBCONNECTIONSTRING"), constr, &constrlen);
fwprintf(fp, L"dbconstring is: %s\n", constr);
TCHAR serverstr[1024];
DWORD serverstrlen = sizeof(serverstr);
rc = MsiGetProperty(hInstaller,TEXT("SQLINSTANCE"),serverstr,&serverstrlen);
fwprintf(fp, L"SQLINSTANCE is: %sl\n",serverstr);
TCHAR finalconstr[2048];
swprintf(finalconstr,L"%s; Data Source=%s;",constr,serverstr);
try{
hr = pCon->Open(finalconstr,TEXT(""),TEXT(""),adConnectUnspecified);
}
catch(_com_error ce){
fwprintf(fp, L"%s\n", msg);
::MessageBox(NULL,msg,NULL,NULL);
CoUninitialize();
MsiSetProperty(hInstaller,TEXT("DBCONNECTIONVALID"),TEXT("0"));
return ERROR_SUCCESS;
}
if(FAILED(hr)){
MsiSetProperty(hInstaller,TEXT("DBCONNECTIONVALID"),TEXT("0"));
return ERROR_SUCCESS;
}
pCon->Close();
CoUninitialize();
MsiSetProperty(hInstaller,TEXT("DBCONNECTIONVALID"),TEXT("1"));
::MessageBox(NULL,TEXT("Successfully connected to the database!"),NULL,NULL);
fwprintf(fp, L"leaving...\n");
fclose(fp);
return ERROR_SUCCESS;
}
Now, when I build this function into a dll and add it to my WiX project, this code works on my development machine (specifically, the installation successfully finishes and the file "dbcontestdll.txt" exists and has the correct data in it)--but, when I run it on a "fresh install" machine, the installation fails with exit code 2896 and the "dbcontestdll.txt" is not created.
Are there prerequisites to using C-based dlls in a Windows Installer, such as the C++ redistributable?
You probably don't want to get yourself into the situation where you have to bootstrap C++ redists just to run a Custom Action. Have you tried using the File | New | C++ Custom Action probject that comes with WiX? You can use that to stub out your CA and then copy and paste your code into it. That should give you all the compiler and linker settings that you need to avoid this problem.
For custom actions, I highly recommend statically linking to the C run time. The custom aciton DLL ends up a little bigger but you'll have one less dependency on files outside the custom action.
Yes you probably need the visual c runtime. Dependency Walker might assist finding the required dlls.
Look at this example how to use a Bootstrapper. This way you can install the runtime before the msi will be run. I use the following bootstrapper line:
<BootstrapperFile Include="Microsoft.Visual.C++.9.0.x86">
<ProductName>Visual C++ 2008 Runtime Libraries (x86)</ProductName>
</BootstrapperFile>
This package is normally stored in the C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bootstrapper\Packages\vcredist_x86 directory.
I had this problem also. I had an MFC DLL that was dynamically linking by default, and I forgot to include MSVCR100.DLL in the package. Of course it worked fine on the development machine, it even worked on most customers' machines, but it failed on an old Vista PC. I switched to statically linked.