none
Unmanaged TrayIcon in managed app shows wierd text RRS feed

  • Question

  • I have an unmanaged dll which controls the access to some usb devices. Whenever I try to connect to one of the devices an icon is added to the system tray at the right of the taskbar next to the clock and a balloon tooltip pops up containing information about who/which app tries to access which device.

    The problem is, when I try to connect to one of the devices from a managed app (C# .Net 2.0) via interop, from time to time the balloon tooltip shows wierd chinese characters in the tooltip caption althought there is no caption set in the dll.

    From the dll:

    bool CreateSysTray(void)
    {
    	HMODULE module=GetModuleHandle(L"MyUnmanagedDll.dll");
    	TrayWndFunc::m_hIcon = (HICON)LoadImage(module,MAKEINTRESOURCE(IDI_ICON_TRAY),IMAGE_ICON,16,16,0);
    	TrayWndFunc::m_hWnd = NULL;
    	//# Create hidden window
    	WNDCLASSEX wcex;
    	memset(&wcex,0,sizeof WNDCLASSEX);
    	wcex.cbSize = sizeof WNDCLASSEX;
    	wcex.lpfnWndProc	= (WNDPROC)TrayWndFunc::WndProc;
    	wcex.hInstance		= GetModuleHandle(NULL);
    	wcex.lpszClassName	= L"MYTRAY";
    	wcex.hIconSm		= TrayWndFunc::m_hIcon;
    	RegisterClassEx(&wcex);
    
    	TrayWndFunc::m_hWnd = CreateWindow(L"MYTRAY",0,WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,0,CW_USEDEFAULT,0,NULL,NULL,GetModuleHandle(NULL),NULL);
    	if (!TrayWndFunc::m_hWnd)
    		return false;
    
    	memset(&TrayWndFunc::m_cNotifyIcon,0x0,sizeof(TrayWndFunc::m_cNotifyIcon));
    	TrayWndFunc::m_cNotifyIcon.cbSize = sizeof NOTIFYICONDATA;
    	TrayWndFunc::m_cNotifyIcon.hIcon = TrayWndFunc::m_hIcon;
    	TrayWndFunc::m_cNotifyIcon.hWnd = TrayWndFunc::m_hWnd;
    		TrayWndFunc::m_cNotifyIcon.uCallbackMessage = WM_TRAY;
    	TrayWndFunc::m_cNotifyIcon.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP | NIF_INFO;
    	TrayWndFunc::m_cNotifyIcon.uID = ID_TRAY;
    	TrayWndFunc::m_cNotifyIcon.uTimeout = 5000;
    	TrayWndFunc::m_cNotifyIcon.dwInfoFlags = NIIF_INFO;
    	Shell_NotifyIcon(NIM_ADD, &TrayWndFunc::m_cNotifyIcon);// Add icon to tray
    	if (!TrayWndFunc::m_hIcon)
    		return false;
    	return true;
    }
    When I use the dll in an unmanaged app no caption shows up so I think it has something to do with interop and/or managed/unmanaged memory management but I have no clue what causes this issue.

    Maybe someone here can point me into the right direction. Thanks in advance.
    Wednesday, May 20, 2009 11:37 AM

All replies

  • Passing a const char* to a function that expects a Unicode string produces Chinese.  It is not in your code snippet.  I'd guess that the P/Invoke declaration in your managed code is missing the CharSet=Unicode attribute.

    Hans Passant.
    Wednesday, May 20, 2009 12:10 PM
    Moderator
  • Thanks for the hint, nobugz.

    You're right, the dll is Unicode and there is no CharSet=CharSet.Unicode attribute in my P/Invoke declaration but the declaration doesn't contain a string parameter.

    The workflow looks something like this:

    // managed app
    myUnmanagedDllWrapper.Connect(int id); // id: device id
    myUnmanagedDllWrapper.GetData(ref MYSTRUCT data);
    myUnmanagedDllWrapper.Disconnect(int id);

    // unmanaged dll
    Connect(int id)
    {
      // find and connect to the device
      DoSomeDeviceStuff(id);
      CreateSysTray();
      ShowToolTip(id); // loads string resources depending on the device id
    }

    GetData(MYSTRUCT *data)
    {
      // collect data and fill struct
    }

    Disconnect(int id)
    {
      // disconnect from device
      DestroySysTray();
    }

    Even the MYSTRUCT structure only contains bools and ints. So there are no strings passing the interop bounderies.

    Wednesday, May 20, 2009 1:24 PM
  • The balloon tool tip text doesn't fall from the sky.  I suspect chasing ShowToolTip() ought to get you closer.

    Hans Passant.
    Wednesday, May 20, 2009 1:29 PM
    Moderator
  • The balloon tool tip text doesn't fall from the sky. 
    Hans Passant.

    Yes, I know. The ShowTooltip looks like:

    void SetTraySensorMsg(int nID)
    {
    	wstring strDevice(L"");
    	switch (int)
    	{
    	case 1:
    	                strDevice= L"device 1";
    		break;
    	case 2:
    		strDevice= L"device 2";
    		break;
    	default:
    		break;
    	}
    	wstring str(L"Device: ");
    	str += strDevice + L"\r\n" + GetString(IDS_APPLICATION_DE) + L": ";
    	wchar_t szStr[2048];
    	memset(szStr,0x0,2048 * sizeof(wchar_t));
    	if (GetModuleBaseName(GetCurrentProcess(),NULL,szStr,2048))
    	{
    		wstring strProc = szStr;
    		size_t nPos = 0;
    		nPos = strProc.rfind(L"\\");
    		if (wstring::npos != nPos)
    		                 strProc = strProc.substr(nPos + 1,strProc.size() - nPos - 1);
    		str += strProc;
    		wcsncpy_s(TrayWndFunc::m_cNotifyIcon.szTip,str.c_str(),128);
    			wcsncpy_s(TrayWndFunc::m_cNotifyIcon.szInfo,str.c_str(),256);
    	}
    	else
    	{
    		str += GetString(IDS_APP_UNKNOWN_DE);
    			wcsncpy_s(TrayWndFunc::m_cNotifyIcon.szTip,str.c_str(),128);
    			wcsncpy_s(TrayWndFunc::m_cNotifyIcon.szInfo,str.c_str(),256);
    	}
    	TrayWndFunc::m_cNotifyIcon.dwInfoFlags = NIIF_INFO;
    	Shell_NotifyIcon(NIM_MODIFY,&TrayWndFunc::m_cNotifyIcon);
    }
    Maybe I'm blind but it looks fine to me.
    Wednesday, May 20, 2009 1:38 PM
  • The only thing I see wrong is a bad argument to wcsncpy_s() when you copy szTip.  It has 64 chars.  Can't be it.

    Hans Passant.
    Wednesday, May 20, 2009 3:52 PM
    Moderator
  • 128 chars are fine because it only runs on Win2k and greater.
    What I found out is that the NIF_INFO flag sets szInfoTitle and dwInfoFlags to valid. Both are set to zero but maybe there is something wrong with the marshalling.

    Thanks for your help, nobugz.
    Monday, May 25, 2009 9:46 AM