g_object_new: assert from a call of g_application_send_notification() - c

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.

Related

How to start a self-written driver

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!

Why am I getting Error Code 6 on StartService?

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.

how to debug windows service start-up code in c,not c#

everyone
I want to know how to debug the windows service start-up code in C.there are several questions like this but in C# but they are not what I need.
So far,I can only attach to process to debug.Now I want to debug the main() function,how to do? The more detailed,the better.
Thanks so much.
My codes are below.
main function:
void main()
{
SERVICE_TABLE_ENTRY ServiceTable[2];
ServiceTable[0].lpServiceName = "MemoryStatus";
ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain; //ServiceMain
ServiceTable[1].lpServiceName = NULL;
ServiceTable[1].lpServiceProc = NULL;
StartServiceCtrlDispatcher(ServiceTable);
}
ServiceMain Function:
void ServiceMain(int argc, char** argv)
{
//...some codes....
hStatus = RegisterServiceCtrlHandler("MemoryStatus",(LPHANDLER_FUNCTION)ControlHandler);
//...some codes....
//the worker loop of a service
while(ServiceStatus.dwCurrentState == SERVICE_RUNNING)
{
char buffer[10];
sprintf(buffer,"login...");
int result = WriteToLog(buffer);
if (result)
{
ReportStatus(SERVICE_STOPPED,-1);
return;
}
Sleep(SLEEP_TIME);
}
return;
}
and control handle function:
void ControlHandler(DWORD request)
{
switch(request)
{
case SERVICE_CONTROL_STOP:
WriteToLog("Monitoring stopped.");
//...Report Status to SCM code....
return;
case SERVICE_CONTROL_SHUTDOWN:
WriteToLog("Monitoring stopped.");
//...Report Status to SCM code....
return;
default:
break;
}
//...Report Status to SCM code....
return;
}
There are two different ways to debug a windows service from its start. Both are described here.
My preferred one consists of using a remote debugger session that starts with a service (you may use ntsd from Windows Debugging Tool). There is a special mechanism in Windows that enables you to hijack a process based on its image name (Image File Execution Options). Below you can find a content of a .reg file that will setup this debugger for you (change the path to the one where you have Debugging tools installed):
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\svchost.exe]
"Debugger"="\"C:\\tools\\debugging\\Debugging Tools for Windows (x64)\\ntsd.exe\" -server npipe:pipe=svcpipe -noio"
Next step would be to attach to this session using user-mode debugger:
windbg -remote "npipe:pipe=svcpipe,server=localhost"
and you are ready to debug. Remember to remove the registry settings before you reboot your machine, otherwise windows will hang with a black screen :)
OK,two ways:
First,we can sleep the service process at the beginning of code. like this:
main()
{
sleep(10);
.....
}
and then attach to the service process, the debugger will stop at the position of breakpoint as we have 10 seconds to wait.
Second,we can use _ASSERT(FALSE) or DebugBreak() function at the beginning of code.

GTK+/GCC Crashing On Start

I'm trying to learn how to use GTK in C.
I'm developing using Eclipse CDT. I copied the following code from an examples website:
#include <gtk/gtk.h>
#include <stdlib.h>
void displayUI()
{
GtkWidget* mainWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size(GTK_WINDOW(mainWindow), 400, 300);
gtk_window_set_title(GTK_WINDOW(mainWindow), "GTK Simple Example");
gtk_window_set_position(GTK_WINDOW(mainWindow), GTK_WIN_POS_CENTER_ALWAYS);
gtk_signal_connect(GTK_OBJECT(mainWindow), "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_show_all(mainWindow);
}
int main(int argc, char *argv[]) {
gboolean b = gtk_init_check(&argc, &argv);
if(b == 0) {
puts("Failed to init");
exit(0);
}
gtk_init(&argc, &argv);
displayUI();
gtk_main();
return EXIT_SUCCESS;
}
Every time I try to run this program (or anything else involving GTK, Windows immediately displays a "InsertProgramNameHere.exe has crashed" message.
I have MinGW, MinSYS, PKG-CONFIG and MAKE all properly installed. The program compiles fine... it just won't run.
Any ideas?
UPDATE
I found this error log. There seems to be a dependency problem.
Faulting application TestRun.exe, version 0.0.0.0, time stamp 0x4f839a6a, faulting
module libgtk-win32-2.0-0.dll, version 6.0.6002.18541, time stamp 0x4ec3e39f, exception
code 0xc0000135, fault offset 0x0006f52f, process id 0x1674, application start time
0x01cd16c174d3df90.
exception code 0xc0000135
That is STATUS_DLL_NOT_FOUND. Gtk+ has a large number of dependent DLLs. Probably your best bet to get started is to use the all-in-one bundle and copy the entire content of the bin directory in the archive to your program's EXE directory. Crude but the docs are quite unapologetic about it:
Many of the developer files are relatively irrelevant. If you intend to redistribute the GTK+ run-time, you need to figure out which files you can leave out yourself
Are you sure your GTK installation directory is in your PATH ?
You need to add the path to (MinGW, MinSYS and gtk-dev)'s bin folder in the environment variables.

CustomAction succeeds on development computer, fails on deployment computer

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.

Resources