키워드 [Programming][VC++][Tip]
http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=51&MAEULNo=20&no=6499&ref=6499

질문글에 답변을 달다가.. 언뜻 스쳐지나간 MSDN 내용을 찾아서.. 올려봅니다.

현재 내가 실행시킨 프로그램이 스스로 떠 있는 상태에서 자기 자신의 실행파일을 다른 곳으로 이동하는 질문이
있어서.. 기억을 살려 보았습니다.

일반적으로 구동중인 실행파일이나.. 그런것을 지울 수는 없습니다.
공유 에러를 발생시키기 때문이죠.

근디, 윈도의 치명적인 버그인지는 몰라도 이동은 가능합니다.
(버그일까.. 아님 일부러 그렇게 가능하도록 만든 것일까.. ???? )

물론 다른 파티션이나 드라이브로의 이동은 불가능합니다.
하지만 동일한 드라이브 내에서의 이동은 가능하죠.

정확하게 확인한것은 아니지만, 메모리와 메핑되어 있는 파일의 영역은 그대로 살리고
NTFS의 링크만 이동하는것으로 짐작합니다.

즉, 탐색기 상에서는 파일이 이동한 것으로 보이지만, 링크만 바뀌었을 뿐 메핑된 파일 영역은 디스크상에
그 위치 그대로 존재하게 되는 것이겠죠.

위와 같은 동작을 하기위해서는 Window 2000 이상에서만 가능합니다...
파티션이 NTFS이어야만 하는 지는 잘 모르겠고, FAT16 or FAT32 는 실험해보지 않았습니다.

#define WINVER 0x0500
#define _WIN32_WINNT 0x0500

MoveFileEx(original path, move path, MOVEFILE_FAIL_IF_NOT_TRACKABLE);

PS. 참고로 이동할 경로에 동일한 이름을 가진 파일이 존재하면 에러 납니다..

----------------------------------------------------------------------------------------

정일호 (madness_kr)   정일호님께 메시지 보내기정일호님을 내 주소록에 추가합니다.정일호님의 개인게시판 가기 
Window 2000. FAT32 에서도 잘 되네요...

키워드 [Programming][VC++][API]
http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=51&MAEULNo=20&no=6761&ref=6761


디렉토리에 대한 변경이 발생하면, 발생한 이벤트와 경로를 큐에 저장
2. 큐 처리 전용스레드를 이용하여, 만약 부모 윈도 핸들을 주면, PostMessage로 정보 전송

조언을 듣고 코드 프로젝트에도 잘 꾸며진 소스를 살펴밨습니다만...
제가 사용하기에는 코드가 좀 크고 복잡해서 잘 분석이 않되네요.
그래서, 이전 버전을 좀더 업데이트 해봤습니다.
앞으로 필요에 의해 쭈욱 업데이트를 하겠지만, 제 본래 작업과는 거리가 먼 분야라..

짬짬이..  ^^;
참고로, 실행파일과 샘플 프로젝트를 올립니다.
샘플은 C:\와 D:\에 걸쳐 동작하도록 두개를 돌렸습니다.
대략.. 3개 드라이브에..  CD 한장 분량을 복사하고 해봐도.. 큰 문제는 없군요.
버그도 좀 있으면, 리플주세요

구조가 좀 지저분한데, 혹시나 정리하시는 분이 생기시면 업데이트 해주세요 ^^;

키워드 [Programming][VC++][Regsitry]
http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=51&MAEULNo=20&no=7471&ref=7471

// 레지스트리를 설정한 후 키이름을 변경할 만한 방법이 없어서 구현해봤습니다.
// 직접적으로 이름의 변경이 가능한건 아니고, 현재 열린 키를 포함 하위를 몽땅
// 파일로 백업한 다음에, 변경할 새 키로 몽땅 리스토어 한후, 기존 키를 지웁니다.

// 대상 키는 미리 만들어 주셔야 하며, 그게 귀찬을 경우
// 소스를 조금 수정하시면 없을 경우는 만들고 동작하도록 구성하시면 됩니다.

BOOL SetPrivilege(LPCTSTR lpszPrivilege, BOOL bEnablePrivilege = TRUE)
{
    HANDLE hToken;
 
    if(!::OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
  return FALSE;
 
    TOKEN_PRIVILEGES tp;
    LUID luid;
 
    if (!LookupPrivilegeValue(NULL, lpszPrivilege, &luid )) {
        TRACE("LookupPrivilegeValue error: %u\n", GetLastError() );
        return FALSE;
    }
 
    tp.PrivilegeCount = 1;
    tp.Privileges[0].Luid = luid;
    if (bEnablePrivilege)
  tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
 else
  tp.Privileges[0].Attributes = 0;
 
 if ( !AdjustTokenPrivileges(hToken, FALSE,  &tp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES) NULL, (PDWORD) NULL) ) {
  TRACE("AdjustTokenPrivileges error: %u\n", GetLastError() );
  return FALSE;
 }
 
 if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) {
  TRACE("The token does not have the specified privilege. \n");
  return FALSE;
 }
 
 return TRUE;
}

#define TEMP_BACK_FILE  "_#temp"

BOOL RegRenameKey(HKEY srcROOT, const char* srcSUB, HKEY dstROOT, const char* dstSUB)
{
 HKEY hKeySrc=0, hKeyDst=0;
 DWORD Ret;
 
 // 저장할 때는 SeBackupPrivilege, 복구할 때는 SeRestorePrivilege 권한이 필요하다. msdn 발췌
 if( !SetPrivilege("SeBackupPrivilege") || !SetPrivilege("SeRestorePrivilege") )
  return FALSE;
 
 if( RegOpenKeyEx(srcROOT, srcSUB, 0, KEY_ALL_ACCESS, &hKeySrc) != ERROR_SUCCESS ||
  RegOpenKeyEx(dstROOT, dstSUB, 0, KEY_ALL_ACCESS, &hKeyDst) != ERROR_SUCCESS )
  return FALSE;
 
 Ret = RegSaveKey(hKeySrc, TEMP_BACK_FILE, NULL);
 if(ERROR_SUCCESS != Ret)
 {
  RegCloseKey(hKeySrc);
  DeleteFile(TEMP_BACK_FILE);
  return FALSE;
 }
 RegCloseKey(hKeySrc);
 hKeySrc = 0;
 
 Ret = RegRestoreKey(hKeyDst, TEMP_BACK_FILE, REG_FORCE_RESTORE | REG_NO_LAZY_FLUSH);
 if(ERROR_SUCCESS != Ret)
 {
  RegCloseKey(hKeyDst);
  DeleteFile(TEMP_BACK_FILE);
  return FALSE;
    }
 
    RegCloseKey(hKeyDst);
    SHDeleteKey(srcROOT, srcSUB);
    return TRUE;
}

----------------------------------------------------------------------------------------------

오승우 (Ċhobits)   오승우님께 메시지 보내기오승우님을 내 주소록에 추가합니다.오승우님의 개인게시판 가기  61.75.68.12
참고로 XP이상에선 NtDll.dll에 native API NtRenameKey가 있습니다.
http://www.codeproject.com/system/NtRegistry.asp

키워드 [Programming][VC++][Multimedia]
http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=51&MAEULNo=20&no=7518&ref=7518

전에도 한번 올라왔던 내용인데..
요즘 중복되는 질문 내용이 자주 보여 간단하게 정리해서 올립니다.

PlaySound()는 아주 간단하게 리소스나 파일의 wav폼 파일을 읽어서 재생할 수 있는 함수입니다.
단점이 싱크모드와 어싱크 모드로 재생이 가능한데.. 싱크모드로 돌리면 제어가 불가능하고..
어싱크모드로 돌리면 종료시 점을 알수 없다는데 있습니다.

아래의 기법을 이용하면 어싱크모드로 재생하면서 종료 시점을 알수 있고요..
Sleep에 의한 오차 100ms가 있긴 하지만.. 어쨋든...

원하는 소리를 원하는 시점에서 재생 및 중지를 시킬 수 있다는게 장점입니다.

// 소리를 재생하는 스레드입니다.
DWORD CALLBACK AAA(void* param)
{
   // 임시로 aaa.wav란 넘을 어싱크모드로 플레이 합니다.
    PlaySound("aaa.wav", NULL, SND_FILENAME | SND_ASYNC);

    while(1)
    {
        Sleep(100);

        // 재생이 끝날 때 까지 대기 합니다.
        // SND_NOSTOP 옵션이 있어서 현재 재생중일 때는 아래의 함수가 FALSE를 리턴함다.
        if(PlaySound(NULL, NULL, SND_PURGE | SND_NOSTOP | SND_NOWAIT | SND_SYNC))
            break;
    }

    return 0;
}

// 아무 곳에서나 현재 재생중인 음악을 중지 하시고 싶으시면.
// 음악을 중지시키면 당연히 위의 스레드도 바로 종료하게 됩니다.
PlaySound(NULL, NULL, SND_PURGE | SND_NOWAIT | SND_ASYNC);

키워드 [Programming][VC++][String]
http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=51&MAEULNo=20&no=7534&ref=7534

질문글을 보다가 문득 예전 자료가 생각나서.. 잠시 올려봅니다.
보통 문자열을 파싱할 때, 많이 쓰이는게 구분자를 문자열중에 찾는 겁니다.
만약 구분자가 여러개라면?


아이디어는 strtok 소스를 보면서 따온겁니다.
현재 고속으로 문자열을 처리할 때 지금도 사용중이며, 좀더 좋은 아이디어나 자료가 있으신분들은
공유해 주시면 감사~~ ^^;


아래의 예제는 간단하게, 주어진 문자열에서 숫자, 대문자, 소문자의 갯수를 출력하는 루틴입니다.
응용은 본인이 필요한 형식에 따라 하시면 되겠죠.
(한글이 포함되었을 경우는 별도 처리가 필요하지만 생략...)
 
문자열 고속 처리에 관심이 많은데, 좋은 자료를 구할 수 있는 곳이나..
숨겨놓은 보석이 있으시면 공개좀.. ^^;

#define CHECK_MAP(map, arg) ((map[arg >> 3] & (1 << (arg & 7))) && arg)
 
unsigned char map_num[32];
unsigned char map_so[32];
unsigned char map_dae[32];

void init()
{
    int i;
    char* ctrl_num = "1234567890";
    for (i = 0; i < 32; ++i)
        map_num[i] = 0;
    do
    {
        map_num[*ctrl_num >> 3] |= (1 << (*ctrl_num & 7));
    } while (*ctrl_num++);

    char* ctrl_so = "abcdefghijklmnopqrstuvwxyz";
    for (i = 0; i < 32; ++i)
        map_so[i] = 0;
    do
    {
        map_so[*ctrl_so >> 3] |= (1 << (*ctrl_so & 7));
    } while (*ctrl_so++);

    char* ctrl_dae = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    for (i = 0; i < 32; ++i)
        map_dae[i] = 0;
    do
    {
        map_dae[*ctrl_dae >> 3] |= (1 << (*ctrl_dae & 7));
    } while (*ctrl_dae++);
}

void getsome(const char* str, int& num, int& so, int& dae)
{
    if(str == NULL || str[0] == 0)
        return;

    num = so = dae = 0;
    while(*str)
    {
        if(CHECK_MAP(map_num, *str))
            num++;
        else if(CHECK_MAP(map_so, *str))
            so++;
        else if(CHECK_MAP(map_dae, *str))
            dae++;
        ++str;
    }
}

int main()
{
    const char* p = "12341441srsfafAAFSaf";
    int num, so, dae;
    init();
    getsome(p, num, so, dae);
    return 0;
}

------------------------------------------
num = 8, so = 8, dae = 4;

키워드 [Programming][VC++][File][Security]
http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=51&MAEULNo=20&no=7537&ref=7537

MSSQL2005는 참.. 쓰기가 까다롭군요. (드럽다는 표현이.. -_-);
DB를 다루다 보면 DB파일을 여러가지 이유 때문에 Attach or Detach 할경우가 많이 있습니다.
근디, 2005 이놈이 파일을 Detach하면 보안 속성을 어드민 전용, 혹은 심할 경우 시스템 전용으로
보안 속성을 싹 바까버립니다.
 

사람이 손까락으로 할 경우는 눈으로 확인하고, 이것 저것 건드려서 보안 속성을 풀면 되지만
어플리케이션에서 할 경우는 돌아버립니다. --^;
Detach한 파일에 대한 접근이 차단되어 버리기 때문에 다시 Attach할 수도 혹은 복사도 불가능해지죠.
 
그래서, 어플리케이션에서 파일의 보안 속성을 필요한 형태로 변경할 수 있도록 구성해 봤습니다.
삽질하시는데 도움이 되시기를...
 
#include <windows.h>
#include <aclapi.h>
 
BOOL SetPrivilege(LPCTSTR lpszPrivilege, BOOL bEnablePrivilege = TRUE)
{
    HANDLE hToken;
    if(!::OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
        return FALSE;

    TOKEN_PRIVILEGES tp;
    LUID luid;   

    if (!LookupPrivilegeValue(NULL, lpszPrivilege, &luid ))
        return FALSE;

    tp.PrivilegeCount = 1;
    tp.Privileges[0].Luid = luid;
    if (bEnablePrivilege)
        tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    else
        tp.Privileges[0].Attributes = 0;
   
    if ( !AdjustTokenPrivileges(hToken, FALSE,  &tp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES) NULL, (PDWORD) NULL) )
        return FALSE;

    if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
        return FALSE;

    return TRUE;
}

BOOL AddToACL(PACL pACL, const char* AccountName)
{
    BYTE SidBuffer[100] = {0};
    PSID ptr_sid;
    DWORD SidBufSz;
    char DomainNameBuf[256] = {0};
    DWORD DomainNameBufSz;
    SID_NAME_USE SNU;

    ptr_sid = SidBuffer;
    SidBufSz = 100;
    DomainNameBufSz = 256;
 
    if(!LookupAccountName(NULL, AccountName, ptr_sid, &SidBufSz, DomainNameBuf, &DomainNameBufSz, &SNU))
        return FALSE;   

    return AddAccessAllowedAce(pACL, ACL_REVISION,
        GENERIC_ALL+GENERIC_READ+GENERIC_WRITE+GENERIC_EXECUTE,
        ptr_sid);
}

BOOL ChangeFileSecurity(const char* path)
{
    // 권한이 없을 경우는 생성해야 한다.
    // 보통은 어드민이므로 생략 가능하다.
    // SetPrivilege("SeSecurityPrivilege");
 
    SECURITY_DESCRIPTOR SD;
    SECURITY_ATTRIBUTES SA;
    BYTE AclBuf[100] = {0};
    PACL pACL;   

    if(!InitializeSecurityDescriptor(&SD, SECURITY_DESCRIPTOR_REVISION))
        return FALSE;
 
    pACL = (PACL)AclBuf;
    if(!InitializeAcl(pACL, 100, ACL_REVISION))
        return FALSE;

     AddToACL(pACL, "Everyone");
    AddToACL(pACL, "Administrator");
    AddToACL(pACL, "SYSTEM");   

    if(!SetSecurityDescriptorDacl(&SD, TRUE, pACL, FALSE))
        return FALSE;

    SA.nLength = sizeof(SECURITY_ATTRIBUTES);
    SA.bInheritHandle = FALSE;
    SA.lpSecurityDescriptor = &SD;

    LocalFree(pACL);
    return SetFileSecurity(path, DACL_SECURITY_INFORMATION, &SD);
}


 

키워드 [Programming][VC++][Certfication][PFX]
http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=51&MAEULNo=20&no=7598&ref=7598

윈도에서 OpenSSL을 사용할경우 인증서를 익스포트 시켜서
PEM 파일로 변환한 후 로드하는 과정이 필요하죠.

보통 제어판에서 인증서를 열어가지고 마우스로 콕콕 찍어서..
프라이빗 키 설정한 후 익스포트 하여 사용하곤 하는데..

귀찬죠.. 가끔 까먹기도 하죠.. 설명할라믄 메뉴얼 작성해야죠.. -_-

윈도 크립토 API를 사용하여 간단하게 샘플을 만들어 보았습니다.

첨부된 클래스의 헤더는 아래와 같습니다.

//////////////////////////////////////////////////////////
#include <windows.h>
#include <wincrypt.h>
#include <cryptuiapi.h>

class CCertToPFX  
{
public:
    CCertToPFX();
    virtual ~CCertToPFX();

    void SetStoreName(CHAR* name);
    void SetCertName(CHAR* name);
    void SetSaveName(CHAR* name);
    void SetPrivatePassword(CHAR* name);

    BOOL Export();
    DWORD GetLastError();

protected:
    HCERTSTORE  m_hCertStore;        
    HCERTSTORE  m_hCertTemp;        
    CHAR        m_pszStoreName[256];
    CHAR        m_pszCertName[256];
    CHAR        m_pszSaveName[MAX_PATH];
    CHAR        m_pszPrivatePass[256];

    DWORD       m_dwLastError;
};

샘플 코드는 아래와 같습니다.
////////////////////////////////////////////////////
    CCertToPFX con;
    con.SetStoreName("MY");
    con.SetCertName("my_ssl");
    con.SetSaveName("C:\\test.pfx");
    con.SetPrivatePassword("my_password");

    if(!con.Export())
        con.GetLastError();


+ Recent posts