ActiveX

웹페이지 바탕화면 바로가기 만들기 - 간단한 activex 이용

디버그정 2008. 8. 30. 08:14

인터넷 바로가기 아이콘 소스를 찾아 헤매다 결국 찾지 못하고
이것 저것 정보를 모아서 나름대로 만들어 봤습니다.
VB로 만든 소스는 있는데 아시다시피 배포시 덩치 문제땜시
결국 VC++를 이용하기로 했습니다.
그러다 보니 ATL도 알아야하고 캐비닛 파일 생성도 알아야 하고
할게 생각보다 많았습니다.

거두절미하고 내가 만든 방식은 이렇습니다.

1. 사용할 아이콘을 특정 디렉토리에 다운받는다.
   - 윈속을 이용하여 http프로토콜로 해결했습니다.
  
2. 시스템에서 바탕화면 정보를 얻는다.
3. 바탕화면에 바로가기.url 파일을 만든다.

vb 소스에서 보니 shell어쩌구 저쩌구 이용해서 바탕화면에 바로가기 아이콘을 만드는 것으로 설명되어 있는데
자세히 보니 궁극적으로 바탕화면에 아래에서 보시는 것과 같은 xxxx.url파일을 만드는 것이였습니다.
따라서 아이콘으로 사용할 .ico만 있으면(여기 소스에서는 웹서버에서 받아옮) xxxx.url파일만 파일 입출력을
통해서 만들기만 하면 됩니다.
이것이 제가 만든 소스의 골격입니다.

웹서버에서 아이콘 파일을 받아오지 않고 소스내에 포함시킬수도 있을 것 같은데
아직 제 VC++ 실력이 미천한 관계로 그냥 웹서버에서 받아오는 것으로 해결했습니다.
비록 소켓 통신을 해야하는 번거러옴이 있긴 하지만 ico파일을 언제든지 바꿀수 있는 장점도 있는 듯(?)

만드는 방법
1. ATL COM AppWizard를 이용해서 ATL Project를 만듭니다.
2. New ATL Object를 사용해서 Simple Object를 insert합니다.(모든 정보를 기본값을 그대로 사용합니다.)
3. 새로 만들어진 ATL Object에 적당한 메서드(예 makeIcon())를 추가합니다.
4. 추가된 makeIcon 메서드에 아래 소스를 추가합니다.
5. dll 파일을 만들고 이것을 가지고 cab 파일을 만듭니다.(물론 cab 파일을 만드는 방법에 따라서)
6. 자바 스크립트를 이용해서 위에서 만든 메서드를 실행하면 바로가기 아이콘이 생깁니다.

<OBJECT ID="xxxshort" WIDTH=60 HEIGHT=30 CLASSID="CLSID:CFACEDC7-45CA-475D-AF64-D135B3C60513"
CODEBASE="http://www.mydomain.com/shortcut/xxxLink.cab#version=1.0.0.1"></OBJECT>

<script language="javascript">
    xxxshort.makeIcon();
</script>

소스를 보시면 금방이해가 갈겁니다.
물론 간단한 예외 처리외에는 아무것도 하지 않았습니다.
(소스중 특정 정보에 관한 부분(파일이름, url등등)은 각자의 해당 정보로 바꾸시면 됩니다.)

보시고 좀더 개선된 방법을 알려주세요.
너무 허접이라...

FILE *fp;
char crEnVar[MAX_PATH];
char filename[256];

    WSADATA wsaData;            //winsock정보를 담을 구조체
    SOCKET Socket;              //소켓 주소..
    SOCKADDR_IN ServerAddress;    //인터넷소켓주소 구조체
    unsigned short Port = 80;   //포트 번호.
    int ReturnVal;
    int senddata;                    //send()시 실지 보낸 Data 크기
    int recvdata;                    //recv()시 실지 받은 Data 크기
    char szMessage[DEFAULT_BUFFER];  //SendData를 저장하기 위한 Buffer
    char szBuffer[DEFAULT_BUFFER];   //Server측 SendData를 받기 위한 Buffer
    int i, j;
    int start, ContentLength = 0;

    //winsock library initialize
    if (WSAStartup(0x202,&wsaData) == SOCKET_ERROR) {
        WSACleanup();
        return -1;
    }
   
    //socket create
    Socket = socket(AF_INET, SOCK_STREAM,0);
    if( Socket == INVALID_SOCKET ) { //에러 발생시 문구 출력.
        WSACleanup();
        return -1;
    }

    ServerAddress.sin_family = AF_INET;          
    ServerAddress.sin_addr.s_addr = inet_addr("127.0.0.1"); // 여기에 해당 웹서버의 ip를 적는다.
    ServerAddress.sin_port = htons(Port);  //포트번호
    ReturnVal = connect( Socket, (struct sockaddr*)&ServerAddress, sizeof(ServerAddress) );

    //ReturnVal이 0이 아니면, 문제가 있는 경우입니다.
    if (ReturnVal) {
        closesocket( Socket );
        WSACleanup();
        return -1;
    }

    // 아이콘 파일을 요청합니다.
    strcpy(szMessage, "GET /imgs/바로가기.ico HTTP/1.1\r\n"); //물론 해당 웹서버에 바로가기 아이콘으로 사용할 ico파일이 있어야 한다.
    senddata = send(Socket, szMessage, strlen(szMessage), 0);
    strcpy(szMessage, "Host: www.motorshop.com\r\n\r\n");
    senddata = send(Socket, szMessage, strlen(szMessage), 0);

    if(senddata == SOCKET_ERROR) {
        return -1;
    }

    recvdata = recv(Socket, szBuffer, DEFAULT_BUFFER, 0);
    if(recvdata == SOCKET_ERROR) {
        return -1;
    } else {
       
        ::GetEnvironmentVariable("USERPROFILE", crEnVar, MAX_PATH); //사용자 디렉토리를 읽어온다.

        sprintf(filename, "%s\\motorshop.ico", crEnVar);
        fp = fopen(filename, "w");

        // html문서에서 아이콘 파일을 읽어와 내 하드에 저장한다.
        // http프로토콜을 알아야 아래 소스가 이해됩니다. 너무 허접이라서 좋은 방법있으면 알려주세요.

        for (i = 0; i < recvdata; i++) {
           // 받아야할 아이콘 파일의 크기를 알아낸다. Content-Length: 766 이런 형태로 날라옴
            if (szBuffer[i] == 'C') {
                if (szBuffer[i+7] == '-' && szBuffer[i+8] == 'L') {
                    for (j = i + 16; j < recvdata; j++) {
                        if (szBuffer[j] == '\n' || szBuffer[j] == '\r') break;
                        ContentLength = ContentLength * 10 + (szBuffer[j] - '0');
                    }
                }
            }

            // 아이콘 파일의 처음 위치를 알아낸다.
            if (szBuffer[i] == '\r' && szBuffer[i+2] == '\r' && szBuffer[i+3] == '\n') {
                start = i + 4;
                break;
            }
            // '\r\n\r\n' 다음에 데이터가 오는 것으로 알고 있었는데 '\r\r\n\r\r\n' 다음에 오는 경우도 있나?
            if (szBuffer[i] == '\r' && szBuffer[i+3] == '\r' && szBuffer[i+4] == '\n') {
                start = i + 5;
                break;
            }

        }

        for (i = start; i < start + ContentLength; i++)
            fputc(szBuffer[i], fp);
        fclose(fp);

        // 바탕화면에 아이콘 만들기
        sprintf(filename, "%s\\바탕 화면\\바로가기.url", crEnVar);
        //아마도 영문 윈도우에서는 문제가 발생할 겁니다.
        fp = fopen(filename, "w");

        fputs("[InternetShortcut]\n\r", fp);
        fputs("URL=http://www.mydomain.com\n\r", fp); //여기에 해당 도메인을 기록합니다.
        fputs("IconIndex=0\n\r", fp);
        fputs("IconFile=", fp);
        fputs(crEnVar, fp);
        fputs("\\바로가기.ico\n\r", fp); //위에서 다운받은 아이콘 파일의 이름을 적습니다.
        fputs("Modified=0\n\r", fp);

        fclose(fp);

    }
   
    closesocket( Socket ); //소켓을 닫습니다.
    WSACleanup();