shdocvw, winemenubuilder: Generate fd.o entries for .url files.
This commit is contained in:
parent
16feb03778
commit
9ff230dcaa
|
@ -20,10 +20,8 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TODO:
|
* TODO:
|
||||||
* fd.o desktop and menu integration
|
|
||||||
* Implement the IShellLinkA/W interfaces
|
* Implement the IShellLinkA/W interfaces
|
||||||
* Handle the SetURL flags
|
* Handle the SetURL flags
|
||||||
* Loading .url files
|
|
||||||
* Implement any other interfaces? Does any software actually use them?
|
* Implement any other interfaces? Does any software actually use them?
|
||||||
*
|
*
|
||||||
* The installer for the Zuma Deluxe Popcap game is good for testing.
|
* The installer for the Zuma Deluxe Popcap game is good for testing.
|
||||||
|
@ -67,6 +65,42 @@ static inline InternetShortcut* impl_from_IPersistFile(IPersistFile *iface)
|
||||||
return (InternetShortcut*)((char*)iface - FIELD_OFFSET(InternetShortcut, persistFile));
|
return (InternetShortcut*)((char*)iface - FIELD_OFFSET(InternetShortcut, persistFile));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static BOOL StartLinkProcessor(LPCOLESTR szLink)
|
||||||
|
{
|
||||||
|
static const WCHAR szFormat[] = {
|
||||||
|
'w','i','n','e','m','e','n','u','b','u','i','l','d','e','r','.','e','x','e',
|
||||||
|
' ','-','w',' ','-','u',' ','"','%','s','"',0 };
|
||||||
|
LONG len;
|
||||||
|
LPWSTR buffer;
|
||||||
|
STARTUPINFOW si;
|
||||||
|
PROCESS_INFORMATION pi;
|
||||||
|
BOOL ret;
|
||||||
|
|
||||||
|
len = sizeof(szFormat) + lstrlenW( szLink ) * sizeof(WCHAR);
|
||||||
|
buffer = heap_alloc( len );
|
||||||
|
if( !buffer )
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
wsprintfW( buffer, szFormat, szLink );
|
||||||
|
|
||||||
|
TRACE("starting %s\n",debugstr_w(buffer));
|
||||||
|
|
||||||
|
memset(&si, 0, sizeof(si));
|
||||||
|
si.cb = sizeof(si);
|
||||||
|
|
||||||
|
ret = CreateProcessW( NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi );
|
||||||
|
|
||||||
|
HeapFree( GetProcessHeap(), 0, buffer );
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
CloseHandle( pi.hProcess );
|
||||||
|
CloseHandle( pi.hThread );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* interface functions */
|
/* interface functions */
|
||||||
|
|
||||||
static HRESULT WINAPI Unknown_QueryInterface(InternetShortcut *This, REFIID riid, PVOID *ppvObject)
|
static HRESULT WINAPI Unknown_QueryInterface(InternetShortcut *This, REFIID riid, PVOID *ppvObject)
|
||||||
|
@ -282,8 +316,54 @@ static HRESULT WINAPI PersistFile_IsDirty(IPersistFile *pFile)
|
||||||
|
|
||||||
static HRESULT WINAPI PersistFile_Load(IPersistFile *pFile, LPCOLESTR pszFileName, DWORD dwMode)
|
static HRESULT WINAPI PersistFile_Load(IPersistFile *pFile, LPCOLESTR pszFileName, DWORD dwMode)
|
||||||
{
|
{
|
||||||
FIXME("(%p, %p, 0x%x): stub\n", pFile, pszFileName, dwMode);
|
WCHAR str_header[] = {'I','n','t','e','r','n','e','t','S','h','o','r','t','c','u','t',0};
|
||||||
return E_NOTIMPL;
|
WCHAR str_URL[] = {'U','R','L',0};
|
||||||
|
WCHAR *filename = NULL;
|
||||||
|
HRESULT hr;
|
||||||
|
InternetShortcut *This = impl_from_IPersistFile(pFile);
|
||||||
|
TRACE("(%p, %s, 0x%x)\n", pFile, debugstr_w(pszFileName), dwMode);
|
||||||
|
if (dwMode != 0)
|
||||||
|
FIXME("ignoring unimplemented mode 0x%x\n", dwMode);
|
||||||
|
filename = co_strdupW(pszFileName);
|
||||||
|
if (filename != NULL)
|
||||||
|
{
|
||||||
|
DWORD len = 128;
|
||||||
|
DWORD r;
|
||||||
|
WCHAR *url = CoTaskMemAlloc(len);
|
||||||
|
if (url != NULL)
|
||||||
|
{
|
||||||
|
r = GetPrivateProfileStringW(str_header, str_URL, NULL, url, len, pszFileName);
|
||||||
|
while (r == len-1)
|
||||||
|
{
|
||||||
|
CoTaskMemFree(url);
|
||||||
|
len *= 2;
|
||||||
|
url = CoTaskMemAlloc(len);
|
||||||
|
if (url == NULL)
|
||||||
|
break;
|
||||||
|
r = GetPrivateProfileStringW(str_header, str_URL, NULL, url, len, pszFileName);
|
||||||
|
}
|
||||||
|
if (r == 0)
|
||||||
|
hr = E_FAIL;
|
||||||
|
else if (url != NULL)
|
||||||
|
{
|
||||||
|
CoTaskMemFree(This->currentFile);
|
||||||
|
This->currentFile = filename;
|
||||||
|
CoTaskMemFree(This->url);
|
||||||
|
This->url = url;
|
||||||
|
This->isDirty = FALSE;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
hr = E_OUTOFMEMORY;
|
||||||
|
CoTaskMemFree(url);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
hr = E_OUTOFMEMORY;
|
||||||
|
CoTaskMemFree(filename);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
hr = E_OUTOFMEMORY;
|
||||||
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT WINAPI PersistFile_Save(IPersistFile *pFile, LPCOLESTR pszFileName, BOOL fRemember)
|
static HRESULT WINAPI PersistFile_Save(IPersistFile *pFile, LPCOLESTR pszFileName, BOOL fRemember)
|
||||||
|
@ -336,6 +416,7 @@ static HRESULT WINAPI PersistFile_Save(IPersistFile *pFile, LPCOLESTR pszFileNam
|
||||||
CloseHandle(file);
|
CloseHandle(file);
|
||||||
if (pszFileName == NULL || fRemember)
|
if (pszFileName == NULL || fRemember)
|
||||||
This->isDirty = FALSE;
|
This->isDirty = FALSE;
|
||||||
|
StartLinkProcessor(pszFileName);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
hr = E_FAIL;
|
hr = E_FAIL;
|
||||||
|
|
|
@ -73,6 +73,7 @@
|
||||||
#include <shlguid.h>
|
#include <shlguid.h>
|
||||||
#include <appmgmt.h>
|
#include <appmgmt.h>
|
||||||
#include <tlhelp32.h>
|
#include <tlhelp32.h>
|
||||||
|
#include <intshcut.h>
|
||||||
|
|
||||||
#include "wine/unicode.h"
|
#include "wine/unicode.h"
|
||||||
#include "wine/debug.h"
|
#include "wine/debug.h"
|
||||||
|
@ -1409,6 +1410,82 @@ cleanup:
|
||||||
return ( r == 0 );
|
return ( r == 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static BOOL InvokeShellLinkerForURL( IUniformResourceLocatorW *url, LPCWSTR link, BOOL bWait )
|
||||||
|
{
|
||||||
|
char *link_name = NULL;
|
||||||
|
DWORD csidl = -1;
|
||||||
|
LPWSTR urlPath;
|
||||||
|
char *escaped_urlPath = NULL;
|
||||||
|
HRESULT hr;
|
||||||
|
HANDLE hSem = NULL;
|
||||||
|
BOOL ret = TRUE;
|
||||||
|
int r = -1;
|
||||||
|
|
||||||
|
if ( !link )
|
||||||
|
{
|
||||||
|
WINE_ERR("Link name is null\n");
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !GetLinkLocation( link, &csidl, &link_name ) )
|
||||||
|
{
|
||||||
|
WINE_WARN("Unknown link location %s. Ignoring.\n",wine_dbgstr_w(link));
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
if (!in_desktop_dir(csidl) && !in_startmenu(csidl))
|
||||||
|
{
|
||||||
|
WINE_WARN("Not under desktop or start menu. Ignoring.\n");
|
||||||
|
ret = TRUE;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
WINE_TRACE("Link : %s\n", wine_dbgstr_a(link_name));
|
||||||
|
|
||||||
|
hr = url->lpVtbl->GetURL(url, &urlPath);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
ret = TRUE;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
WINE_TRACE("path : %s\n", wine_dbgstr_w(urlPath));
|
||||||
|
|
||||||
|
escaped_urlPath = escape(urlPath);
|
||||||
|
|
||||||
|
hSem = CreateSemaphoreA( NULL, 1, 1, "winemenubuilder_semaphore");
|
||||||
|
if( WAIT_OBJECT_0 != MsgWaitForMultipleObjects( 1, &hSem, FALSE, INFINITE, QS_ALLINPUT ) )
|
||||||
|
{
|
||||||
|
WINE_ERR("failed wait for semaphore\n");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
if (in_desktop_dir(csidl))
|
||||||
|
{
|
||||||
|
char *location;
|
||||||
|
const char *lastEntry;
|
||||||
|
lastEntry = strrchr(link_name, '/');
|
||||||
|
if (lastEntry == NULL)
|
||||||
|
lastEntry = link_name;
|
||||||
|
else
|
||||||
|
++lastEntry;
|
||||||
|
location = heap_printf("%s/Desktop/%s.desktop", getenv("HOME"), lastEntry);
|
||||||
|
if (location)
|
||||||
|
{
|
||||||
|
r = !write_desktop_entry(location, lastEntry, "winebrowser", escaped_urlPath, NULL, NULL, NULL);
|
||||||
|
HeapFree(GetProcessHeap(), 0, location);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
r = !write_menu_entry(link_name, "winebrowser", escaped_urlPath, NULL, NULL, NULL);
|
||||||
|
ret = (r != 0);
|
||||||
|
ReleaseSemaphore(hSem, 1, NULL);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (hSem)
|
||||||
|
CloseHandle(hSem);
|
||||||
|
HeapFree(GetProcessHeap(), 0, link_name);
|
||||||
|
CoTaskMemFree( urlPath );
|
||||||
|
HeapFree(GetProcessHeap(), 0, escaped_urlPath);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static BOOL WaitForParentProcess( void )
|
static BOOL WaitForParentProcess( void )
|
||||||
{
|
{
|
||||||
PROCESSENTRY32 procentry;
|
PROCESSENTRY32 procentry;
|
||||||
|
@ -1522,6 +1599,70 @@ static BOOL Process_Link( LPCWSTR linkname, BOOL bWait )
|
||||||
return !r;
|
return !r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static BOOL Process_URL( LPCWSTR urlname, BOOL bWait )
|
||||||
|
{
|
||||||
|
IUniformResourceLocatorW *url;
|
||||||
|
IPersistFile *pf;
|
||||||
|
HRESULT r;
|
||||||
|
WCHAR fullname[MAX_PATH];
|
||||||
|
DWORD len;
|
||||||
|
|
||||||
|
WINE_TRACE("%s, wait %d\n", wine_dbgstr_w(urlname), bWait);
|
||||||
|
|
||||||
|
if( !urlname[0] )
|
||||||
|
{
|
||||||
|
WINE_ERR("URL name missing\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
len=GetFullPathNameW( urlname, MAX_PATH, fullname, NULL );
|
||||||
|
if (len==0 || len>MAX_PATH)
|
||||||
|
{
|
||||||
|
WINE_ERR("couldn't get full path of URL file\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = CoInitialize( NULL );
|
||||||
|
if( FAILED( r ) )
|
||||||
|
{
|
||||||
|
WINE_ERR("CoInitialize failed\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = CoCreateInstance( &CLSID_InternetShortcut, NULL, CLSCTX_INPROC_SERVER,
|
||||||
|
&IID_IUniformResourceLocatorW, (LPVOID *) &url );
|
||||||
|
if( FAILED( r ) )
|
||||||
|
{
|
||||||
|
WINE_ERR("No IID_IUniformResourceLocatorW\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = url->lpVtbl->QueryInterface( url, &IID_IPersistFile, (LPVOID*) &pf );
|
||||||
|
if( FAILED( r ) )
|
||||||
|
{
|
||||||
|
WINE_ERR("No IID_IPersistFile\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
r = IPersistFile_Load( pf, fullname, STGM_READ );
|
||||||
|
if( SUCCEEDED( r ) )
|
||||||
|
{
|
||||||
|
/* If something fails (eg. Couldn't extract icon)
|
||||||
|
* wait for parent process and try again
|
||||||
|
*/
|
||||||
|
if( ! InvokeShellLinkerForURL( url, fullname, bWait ) && bWait )
|
||||||
|
{
|
||||||
|
WaitForParentProcess();
|
||||||
|
InvokeShellLinkerForURL( url, fullname, FALSE );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IPersistFile_Release( pf );
|
||||||
|
url->lpVtbl->Release( url );
|
||||||
|
|
||||||
|
CoUninitialize();
|
||||||
|
|
||||||
|
return !r;
|
||||||
|
}
|
||||||
|
|
||||||
static CHAR *next_token( LPSTR *p )
|
static CHAR *next_token( LPSTR *p )
|
||||||
{
|
{
|
||||||
|
@ -1596,6 +1737,7 @@ int PASCAL WinMain (HINSTANCE hInstance, HINSTANCE prev, LPSTR cmdline, int show
|
||||||
{
|
{
|
||||||
LPSTR token = NULL, p;
|
LPSTR token = NULL, p;
|
||||||
BOOL bWait = FALSE;
|
BOOL bWait = FALSE;
|
||||||
|
BOOL bURL = FALSE;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
init_xdg();
|
init_xdg();
|
||||||
|
@ -1607,6 +1749,8 @@ int PASCAL WinMain (HINSTANCE hInstance, HINSTANCE prev, LPSTR cmdline, int show
|
||||||
break;
|
break;
|
||||||
if( !lstrcmpA( token, "-w" ) )
|
if( !lstrcmpA( token, "-w" ) )
|
||||||
bWait = TRUE;
|
bWait = TRUE;
|
||||||
|
else if ( !lstrcmpA( token, "-u" ) )
|
||||||
|
bURL = TRUE;
|
||||||
else if( token[0] == '-' )
|
else if( token[0] == '-' )
|
||||||
{
|
{
|
||||||
WINE_ERR( "unknown option %s\n",token);
|
WINE_ERR( "unknown option %s\n",token);
|
||||||
|
@ -1614,9 +1758,14 @@ int PASCAL WinMain (HINSTANCE hInstance, HINSTANCE prev, LPSTR cmdline, int show
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WCHAR link[MAX_PATH];
|
WCHAR link[MAX_PATH];
|
||||||
|
BOOL bRet;
|
||||||
|
|
||||||
MultiByteToWideChar( CP_ACP, 0, token, -1, link, sizeof(link)/sizeof(WCHAR) );
|
MultiByteToWideChar( CP_ACP, 0, token, -1, link, sizeof(link)/sizeof(WCHAR) );
|
||||||
if( !Process_Link( link, bWait ) )
|
if (bURL)
|
||||||
|
bRet = Process_URL( link, bWait );
|
||||||
|
else
|
||||||
|
bRet = Process_Link( link, bWait );
|
||||||
|
if (!bRet)
|
||||||
{
|
{
|
||||||
WINE_ERR( "failed to build menu item for %s\n",token);
|
WINE_ERR( "failed to build menu item for %s\n",token);
|
||||||
ret = 1;
|
ret = 1;
|
||||||
|
|
Loading…
Reference in New Issue