none
Помогите программно создать ярлык в windows forms c++. RRS feed

  • Вопрос

  • Уважаемые форморчане прошу помощи, нужно создать программно ярлык из папки "сетевые подключения", рылся по темам на форуме понял что нужно использовать ishell нашел тему на форуме http://social.msdn.microsoft.com/Forums/ru-RU/fordesktopru/thread/c7e25337-21e4-4767-a233-2b756548b435/#9c69339d-60e1-4f6b-a467-d3712358f051 тут подробно расписано как создать ярлык и он создается но в консольном приложении, но код ругается если его использовать его в win forms, подскажите что исправить нужно. Вот подправленный код.

    #include "stdafx.h"
    #include <stdio.h>
    #include <shlobj.h>
    #include <shlwapi.h>
    #include <tchar.h>
    #include <Objbase.h>
    #pragma comment(lib,"Shlwapi.lib")
    #pragma comment(lib,"Shell32.lib")
    #pragma comment(lib,"Ole32.lib")
    
    bool __fastcall CreateShortCut(LPWSTR pwzShortCutFileName,  LPCITEMIDLIST pidl,
    LPTSTR pszWorkingDirectory, WORD wHotKey, int iCmdShow);
    int short_cut_startup(TCHAR *connection_name, LPWSTR link_name);
    LPITEMIDLIST GetNextItemID(LPCITEMIDLIST pidl);
    UINT GetSize(LPCITEMIDLIST pidl);
    LPITEMIDLIST Append(LPCITEMIDLIST pidlBase, LPCITEMIDLIST pidlAdd);
    
    LPMALLOC pMalloc;
    
    void main()//(void)
    {
      short_cut_startup(L"имя-соединения", L"имя-соединения.lnk");
          // printf("Success!\n");
      //  else printf("Can't create shortcut!\n");
       // return 0;
    }
    
    /* Main function which creating shortcut on desktop */
    int short_cut_startup(TCHAR *connection_name, LPWSTR link_name)
    {
        LPITEMIDLIST pidConnections = NULL;
        LPITEMIDLIST pidlItems = NULL;
        LPITEMIDLIST pidlDesk = NULL;
        IShellFolder *psfFirstFolder = NULL;
        IShellFolder *psfDeskTop = NULL;
        IShellFolder *pConnections = NULL;
        LPENUMIDLIST ppenum = NULL;
        ULONG celtFetched;
        HRESULT hr;
        STRRET str_curr_connection_name;
        TCHAR curr_connection_name[MAX_PATH] = L"имя-соединения";    /* Connection point name */
        TCHAR desktop_path[MAX_PATH]=L"";            /* Path to desktop */
        TCHAR full_link_name[MAX_PATH]=L"имя-соединения.lnk";            /* Full shortcut name */
        LPITEMIDLIST full_pid;                        /* Full shortcut pid */
    
       
        CoInitialize( NULL );
        /* Allocating memory for Namespace objects */
        hr = SHGetMalloc(&pMalloc);
        hr = SHGetFolderLocation(NULL, CSIDL_CONNECTIONS, NULL, NULL, &pidConnections);
    
        /* Get full path to desktop */
        SHGetFolderPath(NULL, CSIDL_DESKTOP, NULL, 0, desktop_path);
    
        hr = SHGetDesktopFolder(&psfDeskTop);
        hr = psfDeskTop->BindToObject(pidConnections, NULL, IID_IShellFolder, (LPVOID *) &pConnections);
        hr = pConnections->EnumObjects(NULL,SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &ppenum);
    
        /* Loop for searching our connection */
        while(hr = ppenum->Next(1,&pidlItems, &celtFetched) == S_OK && (celtFetched) == 1)
        {
            pConnections->GetDisplayNameOf(pidlItems, SHGDN_INFOLDER, &str_curr_connection_name);
            StrRetToBuf(&str_curr_connection_name, pidlItems, curr_connection_name, MAX_PATH);
            if(!_tcscmp(curr_connection_name,connection_name))
                goto found;
        }
        printf("Connection not found in \"Network connections\" folder.\n");
        return 0;
    found:
        /* Append PIDLs */
        full_pid=Append(pidConnections,pidlItems);
        SetCurrentDirectory(desktop_path);
        if(!CreateShortCut(link_name, full_pid, L"C:\\windows", 0, SW_SHOWNORMAL))
            return 0;
    
        ppenum->Release();
        pMalloc->Free(pidlItems);
        pMalloc->Free(pidConnections);
        pMalloc->Release();
        pConnections->Release();
        CoUninitialize();
        return 1;
    }
    
    bool __fastcall CreateShortCut(LPWSTR pwzShortCutFileName,  LPCITEMIDLIST pidl,
                                   LPTSTR pszWorkingDirectory, WORD wHotKey, int iCmdShow)
    { 
        IShellLink * pSL; 
        IPersistFile * pPF; 
        HRESULT hRes; 
        hRes = CoCreateInstance(CLSID_ShellLink, 0,CLSCTX_INPROC_SERVER, 
                                IID_IShellLink, (LPVOID *)&pSL); 
        if( SUCCEEDED(hRes) ) 
        { 
            hRes=pSL->SetIDList(pidl);
            if(SUCCEEDED(hRes))
            { 
                hRes = pSL->SetHotkey(wHotKey); 
                if( SUCCEEDED(hRes) ) 
                { 
                    hRes = pSL->SetShowCmd(iCmdShow); 
                    if( SUCCEEDED(hRes) ) 
                    { 
                        hRes = pSL->QueryInterface(IID_IPersistFile,(LPVOID *)&pPF); 
                        if( SUCCEEDED(hRes) ) 
                        { 
                            hRes = pPF->Save(pwzShortCutFileName,TRUE); 
                            pPF->Release(); 
                        }
                    }
                }
            }
            pSL->Release(); 
        }
        return SUCCEEDED(hRes); 
    }
    
    
    /******************************************************************************/
    /* Functions copied from http://msdn.microsoft.com */
    
    LPITEMIDLIST GetNextItemID(LPCITEMIDLIST pidl) 
    { 
       // Check for valid pidl.
       if(pidl == NULL)
          return NULL;
    
       // Get the size of the specified item identifier. 
       int cb = pidl->mkid.cb; 
    
       // If the size is zero, it is the end of the list. 
    
       if (cb == 0) 
          return NULL; 
    
       // Add cb to pidl (casting to increment by bytes). 
       pidl = (LPITEMIDLIST) (((LPBYTE) pidl) + cb); 
    
       // Return NULL if it is null-terminating, or a pidl otherwise. 
       return (pidl->mkid.cb == 0) ? NULL : (LPITEMIDLIST) pidl; 
    } 
    
    /* Get size of PIDL */
    UINT GetSize(LPCITEMIDLIST pidl)
    {
        UINT cbTotal = 0;
        if (pidl)
        {
            cbTotal += sizeof(pidl->mkid.cb);    // Terminating null character
            while (pidl)
            {
                cbTotal += pidl->mkid.cb;
                pidl = GetNextItemID(pidl);
            }
        }
        return cbTotal;
    }
    
    /* Appending PIDLs */
    LPITEMIDLIST Append(LPCITEMIDLIST pidlBase, LPCITEMIDLIST pidlAdd)
    {
        if(pidlBase == NULL)
            return NULL;
        if(pidlAdd == NULL)
            return (LPITEMIDLIST)pidlBase;
        
        LPITEMIDLIST pidlNew;
    
        UINT cb1 = GetSize(pidlBase) - sizeof(pidlBase->mkid.cb);
        UINT cb2 = GetSize(pidlAdd);
    
        pidlNew = (LPITEMIDLIST)pMalloc->Alloc(cb1 + cb2);
        if (pidlNew)
        {
            CopyMemory(pidlNew, pidlBase, cb1);
            CopyMemory(((LPSTR)pidlNew) + cb1, pidlAdd, cb2);
        }
        return pidlNew;
    }


    • Изменено Shipilov 3 мая 2012 г. 16:29

Ответы

  • Тогда вам нужно вынести c++ код в библиотеку, а эту библиотеку уже подключать в WinForms проекте.

    Пример как создать dll можно посмотреть здесь Пошаговое руководство. Создание и использование библиотеки DLL (C++)

    Создайте неуправляемую dll c++, вставьте в нее весь код, что вы привели в вопросе (без main). Функцию short_cut_startup измените на например

    extern "C" __declspec(dllexport) int CreateShortcut(TCHAR *connection_name, LPWSTR link_name)

    для того, чтобы ее можно было вызвать.

    Далее в WinForms проекте используйте созданную библиотеку:

    	using namespace System::Runtime::InteropServices;
    	[DllImport("CreateShortcutDll.dll", CallingConvention = CallingConvention::Cdecl)]
    	extern int CreateShortcut(String^ connectionName, String^ linkName);

    и вызывайте
    	private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
    				 int error = CreateShortcut("Network", "test.lnk");
    				 MessageBox::Show(error.ToString());
    			 }


    Для связи [mail]

    • Помечено в качестве ответа Abolmasov Dmitry 30 мая 2012 г. 12:35

Все ответы

  • Здравствуйте

    А на что именно ругается, можете привести примеры ошибок? Вам для winforms нужно удалить метода main, а функцию short_cut_startup(L"имя-соединения", L"имя-соединения.lnk");  вызывать там, где нужно, например по клику кнопки.


    Для связи [mail]

  • Ошибка	2	error C3641: CreateShortCut: недопустимое соглашение вызова "__cdecl " для функции, скомпилированной с параметрами /clr:pure или /clr:safe	
    Поместил на кнопку. Вот такое сообщение выдает компилятор может что то нужно сделать в настройках?
    • Изменено Shipilov 6 мая 2012 г. 19:12
  • Попробуйте заменить в определении функции слово __fastcall на __clrcall

    Об этой ошибке на MSDN - Ошибка компилятора C3641


    Для связи [mail]

  • Уже пробовал заменять как на  __clrcall так и на __cdecl

    Листинг ошибок, Блин думал создать ярлык в visual c++, намного легче. Сейчас обложился книгами по com программированию но примеры оттуда  тоже не работают.

    Ошибка	10	error LNK1120: 8 неразрешенных внешних элементов	
    Ошибка	8	error LNK2001: неразрешенный внешний символ "CLSID_ShellLink"	
    Ошибка	6	error LNK2001: неразрешенный внешний символ "IID_IPersistFile"	auto_conn
    Ошибка	9	error LNK2001: неразрешенный внешний символ "IID_IShellFolder"	auto_conn
    Ошибка	7	error LNK2001: неразрешенный внешний символ "IID_IShellLinkW"		auto_conn
    Ошибка	2	error LNK2020: неразрешенная лексема (0A000039) IID_IPersistFile	auto_conn
    Ошибка	3	error LNK2020: неразрешенная лексема (0A00003E) CLSID_ShellLink	
    Ошибка	4	error LNK2020: неразрешенная лексема (0A00003F) IID_IShellLinkW	
    Ошибка	5	error LNK2020: неразрешенная лексема (0A000049) IID_IShellFolder	auto_conn
    Предупреждение	1	warning C4081: требуется 'newline'; обнаружен ';'		5	1	auto_conn
    

  • Проблема все еще не решена, может кто нибудь все таки подскажет?
  • Тогда вам нужно вынести c++ код в библиотеку, а эту библиотеку уже подключать в WinForms проекте.

    Пример как создать dll можно посмотреть здесь Пошаговое руководство. Создание и использование библиотеки DLL (C++)

    Создайте неуправляемую dll c++, вставьте в нее весь код, что вы привели в вопросе (без main). Функцию short_cut_startup измените на например

    extern "C" __declspec(dllexport) int CreateShortcut(TCHAR *connection_name, LPWSTR link_name)

    для того, чтобы ее можно было вызвать.

    Далее в WinForms проекте используйте созданную библиотеку:

    	using namespace System::Runtime::InteropServices;
    	[DllImport("CreateShortcutDll.dll", CallingConvention = CallingConvention::Cdecl)]
    	extern int CreateShortcut(String^ connectionName, String^ linkName);

    и вызывайте
    	private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
    				 int error = CreateShortcut("Network", "test.lnk");
    				 MessageBox::Show(error.ToString());
    			 }


    Для связи [mail]

    • Помечено в качестве ответа Abolmasov Dmitry 30 мая 2012 г. 12:35