멜론 스나이퍼 소스 파일을 공개합니다.

안되신다는분 들이 많지만 원인을 못찾겠네요.. 테스트 환경도 PC 2대고.. 제가 찾지 못하고 있는 버그도 있겠죠..

그래서~~ 소스를 공개하기로 했습니다.

공개하기에는 약간 미흡한 소스들이지만..  누군가에게 도움이 될지 모른다는.. 생각;;;

또한 이 소스 코드를 누군가 보고 버그 및 고쳐야할점을 찾아 알려줄지 모른다는--;; 말도 안되는 생각;;
잘모르겠네요.  누군가 고칠점이나 개선할점 알려줘서 저에게 도움이 될꺼라는--;; 생각;;;

제가 이런 프로그램 만들게 된것도 실력을 쌓고자 한거고. 소스 공개도 비슷한 마음에서 하게 되었네요..

아무튼 소스코드 공개로 더 좋은 프로그램이 될수 있으면 좋겠네요. 그냥 바램입니다..

라이센스
멜론 스나이퍼 제작자 - 신영재

  Copyright 신영재 n e w g i f t e d@ . h o t m a i . c o m
  Copyright Kenneth M. Reed r e e d k @. d a n e e l . m v . c o m

  1. 소스 코드 전체 또는 일부 재배포시 라이센스와 저작권 표시를 유지 해야합니다.
  2. 멜론 DCF컨버팅 관련 프로그램 제작할 경우에 한해서 소스코드를 공개하고, 멜론 스나이퍼 제작자에게 알려야 합니다.
  3. 2번 사항을 제외하고 2차적인 소스코드는 공개 하지 않아도 됩니다.
  4. 2번 사항을 제외하고 2차적인 소스코드의 변경 재배포는 멜론 스나이퍼 제작자에게 알리지 않아도 됩니다.
  5. 소스 코드 중 별도의 저작권 표시가 있을 경우 해당 제작자에게 저작권이 있으며, 별도의 라이센스를 따르게 됩니다.
  6. 위(1~5번) 사항을 제외하고 아무런 제한사항 없이 누구나 참조 및 사용 가능합니다.

  ※ 소스코드중 개선할 내용 및 버그를 발견 하시면 저에게 알려 주십시요. (권장 사항 - 강제사항 아님) 버그 패치 소스 코드를 보내 주시면 감사하겠습니다. 별도의 수정된 소스 코드를 보내 주실 경우 소스코드는 라이센스 4번에따라 패치 제작자에게 저작권이 있습니다.

FoldderDialog 저작권자
// FolderDialog.cpp: implementation of the CFolderDialog class.
// $Copyright ? 1998 Kenneth M. Reed, ALL RIGHTS RESERVED. $
// $Header: FolderDialog.cpp  Revision:1.11  Tue Jun 23 18:00:44 1998  KenReed $


  아래는 핵심 코드 파일입니다.


 
//MelonSniperMacroThread.cpp

//Copyright 신영재

#include "MelOnSniperMacroThread.h"
#include "stdafx.h"
#include "MelOnSniperMacro.h"

#define SLEEP_STEP 100
#define END -1

//멜론 매크로 작업을 수행 쓰레드 함수
UINT macroThread( LPVOID pParam )
{
  CMelOnSniperMacro* cmm = ((CMelOnSniperMacro*)pParam);
  
  if(!cmm->hasMainWindow()) return 0;
  cmm->setStep(0);
  cmm->setTimes(0);

  cmm->commandDCFConverting();
  ::Sleep(SLEEP_STEP);
  
  //파일 리스트의 수만큼 반복
  for(int i = 0; i < cmm->getMP3ListSize(); i++)
  {
    int step=0;
    bool scss= true;
    while(step!=END && cmm->getThreadFlag() == RUN_FLAG){
      switch(step){

        case 0:
        //DCF변환 웹링크 누르기
        scss= cmm->clickGoImage();
        ::Sleep(SLEEP_STEP);
        if(scss) step++;
        break;

        case 1:
        //[DCF 컨버팅] 창에 {선택파일[        ] [찾아보기]} 버튼 누르기
        scss= cmm->clickFindButton();
        ::Sleep(SLEEP_STEP);
        if(scss) step++;
        else step =0;
        break;

        case 2:
        //[열기]다이얼로그 {파일 이름 : [           ] }텍스트 박스에 파일명 입력
        scss= cmm->typeFilePath();
        ::Sleep(SLEEP_STEP);
        if(scss) step++;
        break;

        case 3:
        //파일 [열기(O)]버튼 누르기
        scss= cmm->clickOpenButton();
        ::Sleep(SLEEP_STEP);
        if(scss) step++;
        break;

        case 4:
        //[DCF 컨버팅] 창에 {선택파일[        ] [파일선택] \n [확인] [취소]} 확인버튼 누르기
        scss= cmm->clickSelectOK();
        ::Sleep(SLEEP_STEP);
        if(scss) step++;
        break;

        case 5:
        //[DCF컨버팅]세부정보 입력 창에 리스트 선택 및 [확인] 버튼 누르기
        scss= cmm->clickDetailOK();
        ::Sleep(SLEEP_STEP);
        if(scss) step++;
        break;

        case 6:
        //[DCF 컨버팅] 성공 확인창 확인 버튼 누르기
        scss= cmm->clickSucessOK();
        ::Sleep(SLEEP_STEP);

        if(scss) step= END;
        break;
      }

      //파일이 선택되지 않았음 오류창이 떴을 경우
      if(cmm->cechkNoFileError())
      {
        step = 2;
        break;
      }else if(cmm->checkVbrError()){ //VBR오류가 발생했을 경우
        step = END;
        break;
      }
      //내부 오류가 밸생했을 경우
      cmm->checkError();
    }
    //변환중인 파일 다음번으로 인덱스 증가
    cmm->setTimes(i+1);
  }
  
  return 0;
}
//MelonSniperMacro.cpp

//Copyright 신영재


#include "StdAfx.h"
#include "MelOnSniperMacro.h"
#include "MelOnSniperMacroThread.h"

#define SLEEP_TIME 10
#define SAFE_COUNT 50

//멜론 매크로 클래스 생성자
CMelOnSniperMacro::CMelOnSniperMacro(void)
: m_nSaveList(0)
, m_nStep(0)
, m_nTimes(0)
, m_bUseSpool(FALSE)
, m_threadFlag(STOP_FLAG)
{
}


//멜롬 매크로 클래스 소멸자 
CMelOnSniperMacro::~CMelOnSniperMacro(void)
{
}


//멜론 플레이어 창을 찾는다.
//찾았을 경우 true를 반환 못 찾았을 경우 false를 반환
bool CMelOnSniperMacro::hasMainWindow(void)
{
  //CWnd::FindWindow 
  //Return Value

  //Identifies the window that has the specified class name and window name. It is NULL if no such window is found. 

  //The CWnd* may be temporary and should not be stored for later use.
  CWnd * wMelon = CWnd::FindWindowW(_T("MelOnFrameV30"),NULL);
  if(wMelon == NULL) return false;

  return true;
}

//현재 스텝을 반환
int CMelOnSniperMacro::getStep(void)
{
  return m_nStep;
}

//현재 스텝을 지정
void CMelOnSniperMacro::setStep(int nStep)
{
  m_nStep=nStep;
}

//현재 변환중인 파일 지정
void CMelOnSniperMacro::setTimes(int nTimes)
{
  m_nTimes=nTimes;
}

//현재 변환중인 파일 번호 반환
int CMelOnSniperMacro::getTimes(void)
{
  return m_nTimes;
}

//변환할 MP3목록에 파일 한개를 추가함
void CMelOnSniperMacro::addMP3File(CString strFileName)
{
  m_strMP3List.Add(strFileName);
}

//변환할 파일의 총 갯수를 반환함
int CMelOnSniperMacro::getMP3ListSize(void)
{
  return (int)m_strMP3List.GetSize();
}


//변환할 MP3 리스트를 모두 제거
void CMelOnSniperMacro::removeAllMP3List(void)
{
  m_strMP3List.RemoveAll();
}

// 클래스이름과 캡션명과 창의 크기로 윈도우 CWnd를 찾음
// 반환값을 delete하면 안됨
CWnd* CMelOnSniperMacro::findWindow( CString strClass, CString strWindow, int height, int width)
{
  CWnd* findWindow;
  findWindow = CWnd::FindWindowEx(NULL,NULL,strClass, strWindow);
  do{     
    
    RECT r;
    if(findWindow== NULL) break;
    //창의 크기로 윈도우 판별함
    findWindow->GetWindowRect(&r);
    int thisHeight = r.bottom-r.top;
    int thisWidth = r.right - r.left;
    if(thisHeight == height && thisWidth==width){
      return findWindow;
    }

    findWindow = CWnd::FindWindowEx(NULL,findWindow->m_hWnd,strClass, strWindow);
    
  }while(findWindow != NULL);

  return findWindow;
}

//열기 창을 찾아서 CWnd* 반환
//반환값을 delete하면 안됨
CWnd* CMelOnSniperMacro::findOpenWindow()
{
  CWnd* wOpen = CWnd::FindWindowEx(NULL,NULL ,TEXT("#32770"),TEXT("열기"));
  while(wOpen != NULL){
    if(wOpen !=NULL && wOpen->IsWindowEnabled() && wOpen->IsWindowVisible()) 
      break;
    wOpen = CWnd::FindWindowEx(NULL,wOpen->m_hWnd ,TEXT("#32770"),TEXT("열기"));
  }
  if(wOpen !=NULL ) return wOpen;


  wOpen = CWnd::FindWindowEx(NULL,NULL ,TEXT("#32770"),TEXT("Open"));
  while(wOpen != NULL){
    if(wOpen !=NULL && wOpen->IsWindowEnabled() && wOpen->IsWindowVisible()) 
      break;
    wOpen = CWnd::FindWindowEx(NULL, wOpen->m_hWnd, TEXT("#32770"),TEXT("Open"));
  }

  return wOpen;
}

//저장할 리스트 번호를 지정
void CMelOnSniperMacro::setSaveList(int listNum){
  m_nSaveList = listNum;
}

//저장할 리스트 번호를 반환
int CMelOnSniperMacro::getSaveList(){
  return m_nSaveList;
}


//DCF모으기 사용여부를 지정
void CMelOnSniperMacro::setCollect(BOOL b){
  this->m_bCollect =b;  
}

//DCF를 모을 폴더를 지정
void CMelOnSniperMacro::setCollectFolder(CString s){
  this->m_strCollectFolder = s;
}


//DCF변환 매크로 과정을 수행( 매크로 수행 쓰레드를 시작)
void CMelOnSniperMacro::run(void)
{
  m_threadFlag = RUN_FLAG;
    m_threadMacro = AfxBeginThread (macroThread,&*this);
}

//DCF 변환 매크로 과정을 중지
void CMelOnSniperMacro::stop(void)
{
  m_threadFlag = STOP_FLAG; 
}

//DCF변환하기 버튼 누르기
void CMelOnSniperMacro::commandDCFConverting(void)
{
  CWnd * wMelon = getMainWindow();
  wMelon->SendMessageW(WM_COMMAND,0x8026,0x0);
}

// 메인창의 CWnd값을 구함
// 리턴값 사용후 delete하면 안됨
CWnd * CMelOnSniperMacro::getMainWindow(void)
{
  CWnd * wMelon = CWnd::FindWindowW(_T("MelOnFrameV30"),NULL);
  return wMelon;
}

//DCF변환 웹링크 누르기
bool CMelOnSniperMacro::clickGoImage(void)
{
  CWnd* wMain = getMainWindow();
  CWnd* wIE;
  int cnt=0;
  //제어할 IE창을 찾을 때 까지 반복 수행
  do{ 
    CWnd* wMainPan = CWnd::FindWindowExW(wMain->m_hWnd, NULL, NULL, _T("Main Panel"));
    CWnd* wBack = CWnd::FindWindowExW(wMainPan->m_hWnd, NULL, NULL, _T("Back"));
    CWnd* wRight = CWnd::FindWindowExW(wBack->m_hWnd, NULL, NULL, _T("Right"));
    CWnd* wStatic = CWnd::FindWindowExW(wRight->m_hWnd, NULL, NULL, _T(""));
    CWnd* wShell = CWnd::FindWindowExW(wStatic->m_hWnd, NULL, NULL, NULL);

    CWnd* wIECon= CWnd::FindWindowEx(wShell->m_hWnd, NULL, NULL, NULL);
    //버튼의 클릭위치를 잡기 위해 크기를 변경함
    wIECon->SetWindowPos(NULL,0,0,724,830,NULL);
    wIE = CWnd::FindWindowEx(wIECon->m_hWnd, NULL, NULL, NULL);

    ::Sleep(SLEEP_TIME);

    //무한 루프 방지용 safe count
    cnt++;
    if(cnt >= SAFE_COUNT) return false;
  }while(wIE==NULL);
  
  wIE->PostMessage(WM_LBUTTONDOWN,1,MAKELPARAM(655, 777));
  wIE->PostMessage(WM_LBUTTONUP,1,MAKELPARAM(655, 777));
  m_nStep=0;

  return true;  
}

// [DCF 컨버팅] 창에 {선택파일[        ] [찾아보기]} 버튼 누르기
bool CMelOnSniperMacro::clickFindButton(void)
{
  CWnd* wDCFConverting; 
  int cnt=0;
  do{
    wDCFConverting = findWindow(TEXT("#32770"), _T(""), 530,455);
    ::Sleep(SLEEP_TIME);

    //무한 루프 방지용 safe count
    cnt++;
    if(cnt >= SAFE_COUNT){
      return false;
    }
  }while(wDCFConverting == NULL);
  wDCFConverting->PostMessage(WM_COMMAND,0x836,0x0);
  m_nStep=1;

  return true;
}

// [열기]다이얼로그 {파일 이름 : [           ] }텍스트 박스에 파일명 입력
bool CMelOnSniperMacro::typeFilePath(void)
{
  CString str = m_strMP3List.GetAt(m_nTimes);

  CWnd* wOpen ;
  CWnd* wOpenText;
  int cnt=0;
  do{
    wOpen = findOpenWindow();

    ::Sleep(SLEEP_TIME);
    
    //무한 루프 방지용 safe count
    cnt++;
    if(cnt >= SAFE_COUNT) return false;

  }while(wOpen == NULL );


  do{
    wOpenText = CWnd::FindWindowEx(wOpen->m_hWnd,NULL, TEXT("Edit"), NULL);
    
    ::Sleep(SLEEP_TIME);
    
    //무한 루프 방지용 safe count
    cnt++;
    if(cnt >= SAFE_COUNT) return false;

  }while(wOpenText == NULL);


  wOpenText->SendMessage(WM_SETTEXT,NULL,(LPARAM)(char *)(LPCTSTR)(str) );

  m_nStep=2;

  return true;
}

// 파일 [열기(O)]버튼 누르기
bool CMelOnSniperMacro::clickOpenButton(void)
{
  CWnd* wOpen = findOpenWindow();
  CWnd* wOpenText;

  int cnt =0;
  do
  {
    wOpenText = CWnd::FindWindowEx(wOpen->m_hWnd,NULL, TEXT("Edit"), NULL);
    
    ::Sleep(SLEEP_TIME);

    //무한 루프 방지용 safe count
    cnt++;
    if(cnt >= SAFE_COUNT) return false;

  }while(wOpenText == NULL);

  CWnd* wOpenButton;
  do
  {
    wOpenButton = CWnd::FindWindowEx(wOpen->m_hWnd,NULL, TEXT("Button"), TEXT("열기(&O)"));

    //영문판 윈도우를 위한 코드
    if(wOpenButton== NULL)
    {
      wOpenButton = CWnd::FindWindowEx(wOpen->m_hWnd,NULL, TEXT("Button"), TEXT("Open(&O)"));
    }
    
    ::Sleep(SLEEP_TIME);

    //무한 루프 방지용 safe count
    cnt++;
    if(cnt >= SAFE_COUNT) return false;
  }while(wOpenButton == NULL);

  //열기 버튼 누르기
  
  
  wOpenButton->SendMessage(WM_LBUTTONDOWN,0x1, MAKELPARAM(1, 1));
  ::Sleep(SLEEP_TIME);
  wOpenButton->SendMessage(WM_LBUTTONUP,0x1, MAKELPARAM(1, 1));
  m_nStep=3;

  return true;
}

// [DCF 컨버팅] 창에 {선택파일[        ] [파일선택] \n [확인] [취소]} 확인버튼 누르기
bool CMelOnSniperMacro::clickSelectOK(void)
{
  CWnd * wDCFConvert;
  int cnt=0;
  do
  {
    wDCFConvert = findWindow(TEXT("#32770"), _T(""), 530,455);
    
    ::Sleep(SLEEP_TIME);

    //무한 루프 방지용 safe count
    cnt++;
    if(cnt >= SAFE_COUNT) return false;
  }while(wDCFConvert == NULL);
  
  wDCFConvert->PostMessage(WM_COMMAND,0x7D1,0x0);
  m_nStep=4;

  return true;
}



// [DCF컨버팅]세부정보 입력 창에 리스트 선택 및 [확인] 버튼 누르기
bool CMelOnSniperMacro::clickDetailOK(void)
{
  CWnd* wDCFConvert;
  int cnt=0;
  do
  {
    wDCFConvert =findWindow(TEXT("#32770"), _T(""), 360,440);
    
    ::Sleep(SLEEP_TIME);

    //무한 루프 방지용 safe count
    cnt++;
    if(cnt >= SAFE_COUNT) return false;
  }while(wDCFConvert == NULL);
    
  CWnd* wCombo;
  do
  {
    //리스트 선택하기
    wCombo = CWnd::FindWindowEx(wDCFConvert->m_hWnd,NULL,_T("ComboBox"),NULL);

    cnt++;
    if(cnt >= SAFE_COUNT) return false;
  }while(wCombo == NULL);

  LRESULT total = wCombo->SendMessage(CB_GETCOUNT,0,0);

  if(total < (long)m_nSaveList) m_nSaveList = (int)total-1;

  wCombo->SendMessage(CB_SETCURSEL, m_nSaveList);

  ::Sleep(SLEEP_TIME);
  //[확인] 버튼 누르기
  wDCFConvert->PostMessage(WM_COMMAND,0x7D1,0x0);
  m_nStep=5;

  return TRUE;
}

// [DCF 컨버팅] 성공 확인창 확인 버튼 누르기
bool CMelOnSniperMacro::clickSucessOK(void)
{
  CWnd * wDCFConverting;
  int cnt=0;
  do{
    wDCFConverting=findWindow(TEXT("#32770"), _T(""), 415,403);
    ::Sleep(SLEEP_TIME);

    //무한 루프 방지용 safe count
    cnt++;
    if(cnt >= SAFE_COUNT) return false;
  }while(wDCFConverting == NULL);
  
  wDCFConverting->PostMessage(WM_COMMAND,0x7D1,0x0);
  
  //dcf모으기를 사용할 경우 파일을 옮김
  if(m_bCollect){
    CString strSourceFile = m_strMP3List.GetAt(m_nTimes);
    strSourceFile = strSourceFile.Left(strSourceFile.GetLength()-3);
    strSourceFile += "dcf";

    CString strFileName = strSourceFile.Mid(strSourceFile.ReverseFind(_T('\\')));
    CString strTarget = strFileName = this->m_strCollectFolder+strFileName;
    //루트 폴더 파일 열기 오류 수정용코드
    strTarget.Replace(_T("\\\\"), _T("\\"));
    
    if(m_bUseSpool)
    {
      m_fileSpool.add(strSourceFile,strTarget);
    }else{
      ::MoveFileW(strSourceFile, strTarget );
    }
  }

  m_nStep=6;
  m_nTimes++;

  return true;
}

//변환할 엠피3 리스트를 CStringArray*로 반환
//delete하면 안됨
CFileList * CMelOnSniperMacro::getMP3List()
{
  return & m_strMP3List;
}

//매크로 수행이 끝났는지 여부를 반환
bool CMelOnSniperMacro::isEnd(void)
{
  DWORD dwCodeMacro; 
  ::GetExitCodeThread( m_threadMacro->m_hThread, &dwCodeMacro );
  if(m_fileSpool.getCount() > 0) return false;
  if(dwCodeMacro == STILL_ACTIVE)
    return false;
  return true;
}

//MP3파일을 선택하지 않았습니다. 오류창이 뜬 여부를 반환하고.
//그 대화상자를 닫음
bool CMelOnSniperMacro::cechkNoFileError(void)
{
  
  CWnd* wOpen = findOpenWindow();
  CWnd* wErrorSelect ;
  if(wOpen == NULL)  return false;
  wErrorSelect= CWnd::FindWindowEx(wOpen->m_hWnd, NULL,_T("#32770"), _T("MelOn Player"));
  if(wErrorSelect != NULL){
    wErrorSelect->PostMessage(WM_USER+103,0x0,0x01);
    return true;
  } 

  return false;
}

//VBR오류 여부를 반환하고 오류 발생시 해당파일을 오류리스트에 추가하고 대화상자를 닫음
bool CMelOnSniperMacro::checkVbrError(void)
{
  //만약 가변 파일로 인한 오류시 에러 리스트에 추가
  CWnd* wErrorVBR =findWindow(_T("#32770"), _T("MelOn Player"), 136,523);
  if(wErrorVBR != NULL){
    wErrorVBR->PostMessage(WM_USER+103,0x0,0x01);
    m_strErrorList.Add( m_strMP3List.GetAt(m_nTimes));
    return true;
  } 
  return false;
}


//에러가 발생하였습니다 잠시후 다시 이용해주세요 오류창의 존재 유무를 반환하고 그창을 닫음
bool CMelOnSniperMacro::checkError(void)
{
  //에러가 발생하였습니다 잠시후 다시 이용해주세요 오류창 문제 해결
  CWnd* wErrorSelect =findWindow(TEXT("#32770"), _T("MelOn Player"), 312,136);
  if(wErrorSelect != NULL){
    wErrorSelect->PostMessage(WM_USER+103,0x0,0x01);
    return true;
  } 
  return false;
}

//에러 리스트를 CStringArray로 반환.. 사용후 delete해야 함.
CFileList* CMelOnSniperMacro::getErrorList(void)
{
  CFileList * result = new CFileList();
  result->Copy(m_strErrorList);
  return result;
}

// 해당 인덱스의 mp3파일을 제거합니다.
void CMelOnSniperMacro::removeMP3(int nIndex)
{
  m_strMP3List.RemoveAt(nIndex);
}


//스풀 사용 여부 지정
void CMelOnSniperMacro::setUseSpool(BOOL bUseSpool)
{
  m_bUseSpool = bUseSpool;
}
// 현재 스풀에 의해 이동중인 파일명 반환
CString & CMelOnSniperMacro::getNowSpoolFile(void)
{
  return m_fileSpool.getNowFile();
}


// 스풀 큐크기 반환
int CMelOnSniperMacro::getSpoolCount(void)
{
  return m_fileSpool.getCount();
}

// 에러 리스트를 초기화한다.
void CMelOnSniperMacro::removeErrorList(void)
{
  m_strErrorList.RemoveAll();
}

//쓰레드 제어를 위한 플래그를 반환한다.
int CMelOnSniperMacro::getThreadFlag(void)
{
  return m_threadFlag ;
}
  • 손충호 2007.06.13 03:39

    약간 매크로 형식이지만, 멜론과 연동해서 하는 아이디어가 참 좋았는데, 소스까지 공개해주세요.

  • 아따죽이네 2007.06.21 22:55

    일반인들은 절대 넘볼 수 없는 세계구만..

    같은 컴터 전공하는 사람들이라면 모를까..하하...

  • 멜스사용자 2007.06.27 19:32

    정말 수고하셨습니다. 감사하구요.

  • 멋지십니다 2007.06.28 12:41

    소스는 보니 알긴 하겠는데 감히 수정을 해보려니 엄두가 나질 않네요
    덕분에 잘 사용 하고있습니다 ^^

    • 영재 2007.06.28 15:52

      예~~ㅡㅡ;;

      약간 복잡하긴 하죠?? 어떻게 깔끔하게 만든다고 막 수정했는데도 깔끔하게는 안나오네요...쩝~~

  • 카메스트 2007.07.07 06:26

    늦었지만 소스공개를 닫아주셨으면 하네요. 이거 보고 멜론녀석들이 다 틀어막는것은 아닌지 후덜덜하네요.

    • 영재 2007.07.09 14:45

      멜론 스나이퍼를 막기 위해 --;; 도움이 될수는 있겠지만..

      회사에서 막고자 마음 먹으면 소스 파일을 공개하지 않더라도 손쉽게 막을 수 있을 듯 합니다.. 크게 걱정은 안하고 있습니다..

  • 짤린군종 2007.07.12 00:33

    안녕하세요.
    제가 컴공 3학년 재학중인데...
    이런 프로그램 짜실줄 아시구...부럽습니다.
    지금까지 제가 뭘 공부했는지...부끄럽네요.

    소스보고 공부좀 해보려구 했는데요~.
    컴파일조차 못하고 있네요.
    혹시 컴파일러로 뭐 쓰셨는지 물어봐도 될까요?

    원래 다 되는건데..제가 컴파일을 못하는것인지...--;

    • 영재 2007.07.14 11:05

      VS 2005 SP1으로 작성되었습니다.

      만약 안된다면 Build - Rebuild Solution 으로 다시 빌드하거나, Debug 폴더와 Release폴더 지우고 다시 컴파일 해보세요.. 2003이나 VS6에서는 솔류션 바로 열리지 않을것 같네요.. 새로 프로젝트 만들어서 파일 추가해서 해야 될듯 하네요..

  • 굼벵이 2007.07.13 15:14

    소스 잘 봤습니다.. 잘 만드셨네요..

    저도 한번 써 볼라고 했는데. DCF컨버팅에서 넘어가지 않네요.
    소스 다운 받아서 한번 봤습니다.
    혹시 VS 2005로 만드신 건지..^^;
    제가 가진 컴파일러로는 컴파일이 안되네요... VC 60, VS.NET 2003

    어째거나 소스를 분석 해보니.. 정확 하게 이거다.. 하는 부분은 없으나..
    짐작이 가는 부분이..

    CMelOnSniperMacro 에서 clickFindButton()부분이 문제인것 같습니다.
    즉 프로그램이 DCF컨버팅이라는 Window의 Handle를 찾지를 못하는거 같네요..
    소스상에서 보면.. Class Name인 #32770을 찾아서 창의 크기를 비교 하는 findWindow(...)를 호출해서 "DCF컨버팅"이라는 Window Handle를 찾으려 하신거 같은데요..

    findWindow(...)
    {
    ...
    findWindow = CWnd::FindWindowEx(NULL,findWindow->m_hWnd,strClass, strWindow);
    ...
    }
    에서 보시면 처음 넘어온 Class Name을 findWindow(CWnd 할당된 지역변수)에 넣고.. 처음 Window찾기가 실패하면 처음 저장된 #32770의 Child Windows에서만 다음 윈도우를 찾고 있습니다.

    Spy++로 윈도우를 떠보면.. #32770 Name의 Window가 많이 있는데..(기본 다이얼로그 classname이라서) 현재 소스에서는 제일 상위의 #32770만 뒤지고 다음 #32770을 찾지 않게 되어 있는거 같네요..

    어째거나 그래서 거기서 멈춰 버리는거 같습니다...

    사실 윈도우의 사이즈를 가지고 윈도우 찾는 방법도 조금 위험 하죠..
    멜론제작사에서 이 소스 보고.. 사이즈를 조금만 줄이면 바로 안되니..^^;

    차라리..
    #32770 Name의 Class를 순차적으로 검색 하시면서, 자식 윈도우에서
    찾아보기 버튼 핸들을 찾아서 클릭 하도록 하면 되지 않을 까 하네요..

    시간이 업어 대략 봤더니만.. 이정도 밖에 모르겠네요..
    다른 고수님들 도움좀 받으시면...^^;

    • 영재 2007.07.14 11:27

      HWND FindWindowEx(
      HWND hwndParent,
      HWND hwndChildAfter,
      LPCTSTR lpszClass,
      LPCTSTR lpszWindow
      );

      <hwndParent>
      [in] Handle to the parent window whose child windows are to be searched.
      <If hwndParent is NULL, the function uses the desktop window as the parent window.> The function searches among windows that are child windows of the desktop.

      Microsoft Windows 2000 and Windows XP: If hwndParent is HWND_MESSAGE, the function searches all message-only windows.

      <hwndChildAfter>
      [in] Handle to a child window. The search begins with the next child window in the Z order. The child window must be a direct child window of hwndParent, not just a descendant window.
      If hwndChildAfter is NULL, the search begins with the first child window of hwndParent.

      Note that if both hwndParent and hwndChildAfter are NULL, the function searches all top-level and message-only windows.

      <hwndParent>와 <hwndChildAfter>이 NULL이기 때문에 desktop window(최상위 윈도우)에서 첫번째 핸들을 가져오게됩니다.
      while문에서 desktop의 direct 자식윈도우중 <hwndChildAfter>다음에 위치한 윈도우를 가져오죠. <hwndParent>이 NULL이기 때문에, desktop window(최상위 윈도우)의 자식 #32770윈도우를 모두 찾게 됩니다.

      static CWnd* FindWindowEx(
      HWND hwndParent,
      HWND hwndChildAfter,
      LPCTSTR lpszClass,
      LPCTSTR lpszWindow
      );

      MFC함수에는 NULL일 경우 어떻게 되는지 안나와 있더군요. API를 그대로 맵핑한 함수라서 둘다 똑같이 작동할꺼 생각했죠. 제 컴퓨터에서는 똑같이 작동하는데 Documents에 없는 상황이라 제대로 짠게 아니긴 하네요. 이렇게 하면 안된다고 수업시간에 배웠는데.. (내부 작동원리를 예측해서 Documents없는 기능을 쓰는것) 이건 생각 해봐야 겠네요.

      윈도우 크기로 창을 구분하는건 다른건 크게 중복될게 없는데 마지막 확인 윈도우 Child 윈도우가 "확인" 버튼 밖에 없는 저 창때문에 모두 크기로 찾는 방법을 썼죠.. 머리 조금 굴리면 될듯 하기도 하네요.. 댓글 정말로 감사합니다.

      Window 000208d4 "" #32770 (Dialog)
      -Window 000208d2 "" Edit
      -Window 000208d0 "멜론 프리클럽 가입하기" Button
      -Window 000208ce "찾아보기" Button
      -Window 000208cc "확인" Button
      -Window 000208ca "취소" Button

      Window 000308d4 "" #32770 (Dialog)
      -Window 000308ca "xxx" Edit
      -Window 000308cc "xxx" Edit
      -Window 000308ca "xxx" Edit
      -Window 000308d0 "xxx" Edit
      -Window 000308d2 "플레이리스트" ComboBox
      -Window 000609ae "" ComboBox
      -Window 0003098e "자동전송" Button
      -Window 00030992 "리스트 추가" Button
      -Window 0005096e "확인" Button
      -Window 000509a4 "취소" Button

      Window 000408d4 "" #32770 (Dialog)
      -Window 000408d2 "확인" Button

  • 굼벵이 2007.07.15 02:23

    HWND ff;
    HWND dd;

    ff = ::FindWindowEx(NULL, NULL, "#32770","");
    do
    {
    if(ff != NULL)
    {
    dd = ::FindWindowEx(ff,NULL,"Button", "멜론 프리클럽 가입하기");
    if(dd != NULL)
    {
    break;
    }
    }

    ff = ::FindWindowEx(NULL, ff, "#32770","");
    }while(ff != NULL);

    요렇게 찾으시라고 말씀 드린건데.. 제가 말주변이 부족해서..
    구지 CWnd를 쓸 필요도 없고..
    걍 핸들만 구하면 됩니다.
    나중에 확인 버튼을 찾을 때도..
    ff의 자식들에서 확인이라는 캡션으로 찾으시면 정확한 핸들을 구할 수가 있습니다...^^;
    사실 원래 소스에서도 왜 윈도우를 제대로 못찾는지는잘 모르겠네요.
    지금 2005깔고 있으니.. 디버깅 해보면 알겠죠..

    수정이 되면 고맙게 잘 쓰겠습니당.. 지금은 못쓰고 있네요..^^;

    • 영재 2007.07.16 14:40

      Window 000408d4 "" #32770 (Dialog)
      -Window 000408d2 "확인" Button

      위와 같은 창이 떴을 경우는 VBR오류 메세지박스, 네트워크 오류 메시지 박스, 성공적으로 변환하였음을 알리는 메세지 박스 모두 똑같아서 구분 할 방법을 못찾고 있습니다.. Child Window만 가지고는 구분이 안되더군요.. 뭐 좀더 좋은 방법이 없을까요??

      싸이즈를 사용한 이유가 되겠습니다..

  • 굼벵이 2007.07.16 13:06

    //DCF변환하기 버튼 누르기
    void CMelOnSniperMacro::commandDCFConverting(void)
    {
    CWnd * wMelon = getMainWindow();
    wMelon->SendMessage(WM_COMMAND,0x8026,0x0);
    delete wMelon;
    }
    여기서 죽어 버리네요..
    위에서 말한데 까지 가지도 못하고..
    SendMessage한뒤 정지해 버리는데.. 이유는 잘 모르겠네요..떱..
    이거 쓰고 싶은데....^^;

    • 영재 2007.07.16 13:52

      아하~ 혹시 유료가입자아닙니까??

      sendMessage(WM_COMMAND~~)이부분은 메뉴에서 DCF변환 메뉴를 선택하는 부분입니다..

      SendMessage를 보내면 저 메세지가 처리 될때까지 블럭되겠죠??

      PostMessage를 바꿔야 하겠네요.. 그리고~~ IE핸들 찾아서.. 웹버튼 클릭하는 부분 생략하도록 바꿔야 겠네요..

  • 곰양 2007.07.16 23:57

    플레이어 실행하고 있는데
    계속 플레이어 실행하라고 에러가 뜨네요
    어떻하죠?ㅜㅜ