;---------------------------------------------------------------------
; MakeLink.asm ActiveX simple client to demonstrate basic concepts
;               written & (c) copyright April 5, 2000 by Ernest Murphy
;
;               contact the author at ernie@surfree.com
;
;               may be reused for any educational or
;               non-commercial application without further license
;---------------------------------------------------------------------
.386
.model flat, stdcall
option casemap:none


include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\ole32.inc

include \masm32\com\include\oaidl.inc
include \masm32\com\include\shlobj.inc

includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\ole32.lib

;---------------------------------------------------------------------
CoCreateLink      PROTO :DWORD, :DWORD

MakeMessage MACRO Text:REQ
    ; macro to display a message box
    ; the text to display is kept local to
    ; this routine for ease of use
    LOCAL lbl
    LOCAL sztext
    jmp lbl
sztext:  
    db Text,0
lbl:
    invoke MessageBox,NULL,sztext,ADDR szAppName,MB_OK
    ENDM

  ; IPersistFile Interface 
  IPersistFile            STRUCT DWORD
       IPersistFile_QueryInterface       comethod3       ?
       IPersistFile_AddRef               comethod1       ?
       IPersistFile_Release              comethod1       ?
       IPersistFile_GetClassID           comethod2       ?
       IPersistFile_IsDirty              comethod1       ?
       IPersistFile_Load                 comethod3       ?
       IPersistFile_Save                 comethod3       ?
       IPersistFile_SaveCompleted        comethod2       ?
       IPersistFile_GetCurFile           comethod2       ?
 IPersistFile            ENDS

;---------------------------------------------------------------------
.data

szAppName         BYTE    	"Shell Link Maker", 0

szLinkName        BYTE    	"Shortcut to MakeLink.lnk", 0
szBKSlash 		BYTE 		"\", 0

hInstance         HINSTANCE   ?
Pos               DWORD       ?

szBuffer1 		BYTE 		MAX_PATH DUP(?)
szBuffer2 		BYTE 		MAX_PATH DUP(?)

;---------------------------------------------------------------------
.code
start:

;---------------------------------------------------------------------
;  this bracketed code is just a 'quick hack'
;  to replace the filename from the filepathname
;  with the 'Shortcut to' title
;
    invoke GetModuleHandle, NULL
    mov hInstance, eax
    invoke GetModuleFileName, NULL, ADDR szBuffer1, MAX_PATH
    invoke lstrcpy, ADDR szBuffer2, ADDR szBuffer1
    ; Find the last backslash '\' and change it to zero
    mov edx, OFFSET szBuffer2
    mov ecx, edx
    .REPEAT
        mov al, BYTE PTR [edx]
        .IF al == 92 ; "\"
            mov ecx, edx
        .ENDIF
        inc edx
    .UNTIL  al == 0
    mov BYTE PTR [ecx+1], 0   
    invoke lstrcpy, ADDR szBuffer2, ADDR szLinkName
;---------------------------------------------------------------------

; here is where we call the proc with the COM methods
    invoke CoInitialize, NULL
    MakeMessage "Let's try our Createlink."
    invoke CoCreateLink, ADDR szBuffer1, ADDR szBuffer2
    MakeMessage "That's all folks !!!"
    invoke CoUninitialize
invoke ExitProcess, NULL

;---------------------------------------------------------------------
CoCreateLink PROC pszPathObj:DWORD, pszPathLink:DWORD
 ; CreateLink - uses the shell's IShellLink and IPersistFile interfaces 
 ;   to create and store a shortcut to the specified object. 
 ; Returns the hresult of calling the member functions of the interfaces. 
 ; pszPathObj - address of a buffer containing the path of the object. 
 ; pszPathLink - address of a buffer containing the path where the 
 ;   shell link is to be stored. 
 ; addapted from MSDN article "Shell Links"
 ;  deleted useless "description" method
 ;  added set icon location method

    LOCAL   pwsz    :DWORD         
    LOCAL   psl     :DWORD         
    LOCAL   ppf     :DWORD       
    LOCAL   hResult :DWORD       
    LOCAL   hHeap   :DWORD       

.data
CLSID_ShellLink     GUID       sCLSID_ShellLink
IID_IShellLink      GUID       sIID_IShellLink
IID_IPersistFile    GUID       {00000010bH, 00000H, 00000H, \
                               {0C0H, 000H, 000H, 000H, 000H, 000H, 000H, 046H}}

.code
    ; first, get some heap for a wide buffer
    invoke GetProcessHeap
    mov hHeap, eax
    invoke HeapAlloc, hHeap, NULL, MAX_PATH * 2
    mov pwsz, eax
    ; Get a pointer to the IShellLink interface. 
    invoke CoCreateInstance, ADDR CLSID_ShellLink, NULL, 
                             CLSCTX_INPROC_SERVER, 
                             ADDR IID_IShellLink, ADDR psl
    mov hResult, eax
    test eax, eax
    .IF SUCCEEDED 
        ; Query IShellLink for the IPersistFile 
        ; interface for saving the shortcut
        coinvoke psl, IShellLink, QueryInterface, ADDR IID_IPersistFile, ADDR ppf
        mov hResult, eax
        test eax, eax
        .IF SUCCEEDED 
            ; Set the path to the shortcut target 
            coinvoke psl, IShellLink, SetPath, pszPathObj
            mov hResult, eax
            ; add the  description, use first icon found
            coinvoke psl, IShellLink, SetIconLocation, pszPathObj, 0 
            mov hResult, eax
            ; change string to Unicode. 
            ; (COM typically expects Unicode strings)
            invoke MultiByteToWideChar, CP_ACP, 0, pszPathLink, 
                                        -1, pwsz, MAX_PATH
            ; Save the link by calling IPersistFile::Save
		coinvoke ppf, IPersistFile, Save, pwsz, TRUE
            mov eax, hResult
            ; release the IPersistFile ppf pointer
            coinvoke ppf, IPersistFile, Release
            mov hResult, eax
        .ENDIF
        ; release the IShellLink psl pointer
        coinvoke psl, IShellLink, Release
        mov hResult, eax
    .ENDIF
    ; free our heap space
    invoke HeapFree, hHeap, NULL, pwsz
    mov eax, hResult    ; since we reuse this variable over and over,
                        ;  it contains the last operations result
    ret
CoCreateLink ENDP
;---------------------------------------------------------------------

end start 
