Delphi 로 디스크 포멧 방법과 소스가 많이 알려지지 않아 이번 삽질의 결과물인 소스를 올린다.


이 소스는 이번에 만든 Freeware 인 Eagle Auto Downloader 에 사용된 코드이다.


상단에 형 정의

type
  CALLBACKCOMMAND = (PROGRESS, DONEWITHSTRUCTURE, UNKNOWN2, UNKNOWN3, UNKNOWN4,
  UNKNOWN5, INSUFFICIENTRIGHTS, WRITEPROTECTED, UNKNOWN8, UNKNOWN9, UNKNOWNA,
  DONE, UNKNOWNC, UNKNOWND, OUTPUT, STRUCTUREPROGRESS);
type
  PFMIFSCALLBAC = function (Command: CALLBACKCOMMAND; SubAction: DWORD;
  ActionInfo: Pointer): BOOL; stdcall;
type
  PFORMATEX = procedure (DriveRoot: PWCHAR; MediaFlag: DWORD; Format: PWCHAR;
  wLabel: PWCHAR; QuickFormat: BOOL; ClusterSize: DWORD; Callback: PFMIFSCALLBAC); stdcall


그리고 콜백 함수를 클래스가 아닌 전역이나 지역변수에 함수를 선언한다.

이부분은 사용자 본인 구미에 맞게 넣어주면 된다.

function FormatEXCallBack(Command: CALLBACKCOMMAND; SubAction: DWORD; ActionInfo: Pointer): BOOL; stdcall;


그리고 이 콜백 함수의 내용은 아래와 같다.

function FormatEXCallBack(Command: CALLBACKCOMMAND; SubAction: DWORD; ActionInfo: Pointer): BOOL; stdcall;
var
  piPrograss : PInteger;
  pwstrMessage : PWideString;
  pbState : PBoolean;
begin

  case (Command) of
    PROGRESS :
    begin
      piPrograss := ActionInfo;
      form1.progressbar1.Position := piPrograss^; // 프로그래스 바가 되었든 뭐가 되었든 piPrograss 포인터의 값을 다른곳에 쓰지 않으면 포멧이 되질 않는다.  덕분에 삽질좀 제대로 했다. 여기서는 form1 에 있는 PrograssBar 에 값을 넣었다.
    end;
    OUTPUT :
    begin
      pwstrMessage := ActionInfo;
      //메세지 출력부이지만 별로 쓰이지 않는 것 같다.
    end;
    WRITEPROTECTED:
    begin
      //쓰기 방지(SD 나 디스켓의 경우 쓰기방지 텝이 있다.)가 걸려있는 경우.
    end;
    DONE :
    begin
      pbState := ActionInfo;

      if (pbState^ = TRUE) then
      begin
        // 포멧이 성공했을 경우 처리.
      end else
      begin
        // 포멧이 실패했을 경우 처리.
      end;
    end;
  else

  end;
end;


그리고 이제 포멧 명령이다.

함수 상단에 아래와 같이 변수 선언을 한다.

var
  pwcDrive : Array[0..5] of WideChar;
  pwcDriveLabel : Array[0..49] of WideChar;
  pwcFormatType : Array[0..5] of WideChar;
  DllHandle : THandle;
  FormatEx: PFORMATEX;


함수 내부에 아래와 같이 코딩한다.

StringToWideChar({드라이버 명, 예를 들어 e:\ 일 경우 e: 만 넣는다.}, pwcDrive, 5);
StringToWideChar({포멧 후 설정될 레이블 명}, pwcDriveLabel, 49);
StringToWideChar('FAT', pwcFormatType, 5); //FAT 나 FAT32 나 NTFS 를 쓰면된다. 여기서는 FAT 를 사용했다.

DllHandle := LoadLibrary('fmifs.dll');
FormatEx := GetProcAddress(DllHandle, 'FormatEx');
FormatEx(pwcDrive, DWORD($C), pwcFormatType, pwcDriveLabel, false, 512, FormatEXCallBack);

FreeLibrary(DllHandle);


Vista 에서는 사용가능한지 모르겠는데 2000/XP는 확실히 된다.

이올린에 북마크하기(0) 이올린에 추천하기(0)
2008/12/20 00:03 2008/12/20 00:03
Posted by TylorSTYLE™

볼랜드 포럼이였나 개인 블로그였나 기억이 나진 않는데 하위 디렉토리 포함 복사 코드라고 나와있는걸 아주 약간 수정을 본 코드다.

실제 이 코드는 복사뿐만 아니라 삭제, 이동도 가능하며, 이름 바꾸기도 가능하다.


Using 에 다음 라이브러리를 추가한다.

ShellApi


이 함수를 코드 상단에 선언한다.

Function File_DirOperations_Datail(
Action            : String;  {COPY, DELETE, MOVE, RENAME}
RenameOnCollision : Boolean; {Renames if directory exists}
NoConfirmation    : Boolean; {Responds "Yes to All" to any dialogs}
Silent            : Boolean; {No progress dialog is shown}
ShowProgress      : Boolean; {displays progress dialog but no file
                              names}
FromDir           : String;  {From directory}
ToDir             : String   {To directory}
): Boolean;


그리고 아래 함수를 소스 아무곳이나 맘에 드는 곳에 넣어둔다.

Function File_DirOperations_Datail(
  Action            : String;  {COPY, DELETE, MOVE, RENAME}
  RenameOnCollision : Boolean; {Renames if directory exists}
  NoConfirmation    : Boolean; {Responds "Yes to All" to any dialogs}
  Silent            : Boolean; {No progress dialog is shown}
  ShowProgress      : Boolean; {displays progress dialog but no file
                                names}
  FromDir           : String;  {From directory}
  ToDir             : String   {To directory}
  ): Boolean;
var
  SHFileOpStruct : TSHFileOpStruct;
  FromBuf, ToBuf: Array [0..255] of Char;
begin
  Try
    Fillchar(SHFileOpStruct, Sizeof(SHFileOpStruct), 0 );
    FillChar(FromBuf,        Sizeof(FromBuf),        0 );
    FillChar(ToBuf,          Sizeof(ToBuf),          0 );
    StrPCopy(FromBuf,        FromDir);
    StrPCopy(ToBuf,          ToDir);
    With SHFileOpStruct Do
    Begin
      Wnd    := 0;
      If UpperCase(Action) = 'COPY'   Then wFunc := FO_COPY;
      If UpperCase(Action) = 'DELETE' Then wFunc := FO_DELETE;
      If UpperCase(Action) = 'MOVE'   Then wFunc := FO_MOVE;
      If UpperCase(Action) = 'RENAME' Then wFunc := FO_RENAME;
      pFrom  := @FromBuf;
      pTo    := @ToBuf;
      fFlags := FOF_ALLOWUNDO;
      If RenameOnCollision Then fFlags := fFlags or FOF_RENAMEONCOLLISION;
      If NoConfirmation    Then fFlags := fFlags or FOF_NOCONFIRMATION;
      If Silent            Then fFlags := fFlags or FOF_SILENT;
      If ShowProgress      Then fFlags := fFlags or FOF_SIMPLEPROGRESS;
    End;
    Result := (SHFileOperation(SHFileOpStruct) = 0);
  Except
    Result := False;
  End;
end;


이 함수의 파라미터는 다음과 같다.

1. 문자형으로 복사인지 삭제인지 이동인지 이름 바꾸기인지 넣는다.

2. 만약 파일이 이미 존재할 경우 이름바꾸기를 할 것인지 결정한다.

3. 작업도중 같은 파일이 있거나, 읽기전용 파일을 삭제할꺼냐는 다이얼 로그가 뜨면 무조건 Yes 나 All 을 선택하는지 결정한다.

4. 작업 상황을 안보여주고 조용히 백그라운드에서 복사할 것인지 결정한다.

5. 프로그래스바(PrograssBar) 를 표시할 것인지 결정한다.

6. 원본 경로를 넣는다.

파일 전체 경로를 넣을 경우 하나의 파일만을 대상으로 할 것이고, 파일명 대신 *.* 이 들어가면 폴더내 전체 파일과 서브 디렉토리가 Source 가 된다. (Dos 에서 copy 명령의 경로 작성법과 같다고 보면 된다.)

7. 대상 경로를 넣는다.

파일명을 바꾼다면 바뀐 파일명이 들어가면 되겠다. 디렉토리 경로만 들어간다면 해당 디렉토리에 복사, 이동 등의 작업이 된다.


다이얼 로그는 우리가 탐색기에서 파일 복사를 할 때 나오는 다이얼 로그와 같다.

이 코드는 쉽고 간편하게 쓸 수 있다는 장점이 있다.

이올린에 북마크하기(0) 이올린에 추천하기(0)
2008/12/20 00:02 2008/12/20 00:02
Posted by TylorSTYLE™

필요한 부분은 주석으로 달아놓았고, 파일을 읽고 쓰는 방법에 대해 대략적인 이해는 할 수 있을 것으로 생각된다.


먼저 변수 선언부이다.

var
  NandBC : TFileStream;
  RAMBC : TFileStream;
  MergeBC : TFileStream;
  Buffer : Char;
  iForLoop : integer;


소스코드 내용이다.

NandBootcodeMerger 에서는 두 파일을 합치는데 낸드 부트 코드는 2 Kbyte 이하이기때문에 파일 크기를 검사한다.

그리고 낸드 부트 코드가 0번 블럭에 쓰여지고 램 부트가 1 번 블럭에 쓰여져야 하는데 한 블럭이 16 KByte 이고, 낸드 부트코드는 16KByte 가 안되기 때문에 강제로 0xFF값을 채워 16 KByte 를 만든다.

Jtag 으로 합쳐진 파일을 낸드플래시에 0 번 블럭을 라이팅 시작 번지로 지정하여  라이팅하면 2 KByte 가 약간 안되는 낸드부트코드 들어간 뒤 자연히 0xFF 값이 1 번 블럭 직전까지 쓰이고, 1 번 블럭이 시작하는 부분부터 램 부트코드가 자연히 라이팅이 되는 것이다.


NandBC := TFileStream.Create([낸드 부트 파일의 경로], fmOpenRead); // 읽기 모드로 파일을 연다.
if (NandBC.Size > 2048) then // 2048 Byte = 2 KByte 이다. 2 KByte 이하인지 확인한다.
begin
  ShowMessage('Size Error.' + #13#10#13#10+ 'NandBootCode Size is 2048 Byte and less.');
  MergeBC.Free;
  exit;
end;

if not (FileExists([램 부트  파일의 경로])) then // 이 파트가 낸드 부트 파일을 열기 전에 있어야 하는데 빠졌다. 파일이 존재하는지 검사한다.
begin
  ShowMessage('Check Ram Bootcode Path!');
  MergeBC.Free;
  exit;
end;

RAMBC := TFileStream.Create([램 부트 파일의 경로], fmOpenRead); //위와 동일하게 파일을 읽기 모드로 연다.
MergeBC := TFileStream.Create([합쳐질 파일의 경로], fmCreate);  // 합쳐진 파일을 저장할 경로(파일명 포함)를 넣으며 새로 만들어지는 파일이므로 생성모드로 연다.

while (NandBC.Read(Buffer, 1) = 1) do // 1 바이트씩 읽어 1 바이트씩 쓴다. 리턴값이 읽은 바이트 수이므로 0 일 경우는 파일 끝에 도달했다고 보면 된다. 만약 10 바이트씩 읽고싶다면 Read 함수의 두번째 파라미터를 10 으로 수정하면 된다.
begin
  MergeBC.Write(Buffer, 1); // 읽은 데이터를 쓴다.
end;

Buffer := Chr(255);
for iForLoop := 0 to (16384 - NandBC.Size - 1) do // 낸드 부트가 들어간 위치 이후로 16KByte 직전 위치까지 0xFF 로 채운다.
begin
  MergeBC.Write(Buffer, 1);
end;

while (RAMBC.Read(Buffer, 1) = 1) do // 램 부트 코드를 채운다.
begin
  MergeBC.Write(Buffer, 1);
end;

MergeBC.Free; // 작업이 끝났으니 파일 스트림을 모두 닫는다.
NandBC.Free;
RAMBC.Free;


여기서 쓰인 함수들은 F1 키로 도움말을 열어 참고하기 바란다.

그리고 파일 제어에 대해서는 C 언어 책에서 파일 I/O 파트를 보면 큰 도움이 될 것이다.

이올린에 북마크하기(0) 이올린에 추천하기(0)
2008/12/20 00:02 2008/12/20 00:02
Posted by TylorSTYLE™
일단 형변환에서 경고가 뜬다는건 매우 유쾌하지 않은 일이다.

String 을 PWideChar(PWChar) 로 변환할 때.. 특히 Windows API 를 사용할 때 PWideChar 를 많이 보게 되는데, 다음의 과정을 거치닌 경고가 사라졌다.

참고로 이 방법은 에디트박스와 같은 델파이 기본 컴포넌트의 값인 TCaption 형도 경고를 없애기가 가능하다.

1. String -> WideString 형의 변수에 값을 넣는다.
2. PWideChar 를 사용하여야 하는 부분에서 PWChar(WideString 형 변수) 또는 PWideChar(WideString 형 변수) 로 형 변환을 한다.
3. 경고가 사라진다.

다른 좋은 방법이 있겠지만, 일단 나의 삽질 결과는 이정도다... ---;;
이올린에 북마크하기(0) 이올린에 추천하기(0)
2008/12/12 11:25 2008/12/12 11:25
Posted by TylorSTYLE™

소수점을 제거하는 연산이 필요할 때 Floor(), Ceiling() [일부 언어에서는 Ceil() 로 제공하기도 한다.] 이렇게 두 함수가 존재한다.

결과를 보면 모든 설명이 될 것으로 보인다.
귀찮아서 MSDN 결과 긁었다. (-_-;;)

Ceiling:
Ceiling(0.00) = 0
Ceiling(0.10) = 1
Ceiling(0.20) = 1
Ceiling(0.30) = 1
Ceiling(0.40) = 1
Ceiling(0.50) = 1
Ceiling(0.60) = 1
Ceiling(0.70) = 1
Ceiling(0.80) = 1
Ceiling(0.90) = 1
Ceiling(1.00) = 1
Ceiling(1.10) = 2

Floor:
Floor(2.10) = 2
Floor(2.00) = 2
Floor(1.90) = 1
Floor(1.80) = 1
Floor(1.70) = 1
Floor(1.60) = 1
Floor(1.50) = 1
Floor(1.40) = 1
Floor(1.30) = 1
Floor(1.20) = 1
Floor(1.10) = 1
Floor(1.00) = 0

Ceiling 은 보통 웹에서 게시물이 몇 페이지인지 연산할 때 쓰인다고 한다.

지금은 주파수 영역 분석 알고리즘에 쓰고 있지만.... 이건 특수한거니 패스~

이올린에 북마크하기(0) 이올린에 추천하기(0)
2008/09/18 16:18 2008/09/18 16:18
Posted by TylorSTYLE™

BLOG main image

카테고리

전체 (119)
Freeware (2)
SAMSUNG MCU (14)
Embedded Linux (10)
AE32000(EAGLE) (2)
Mac OS X (5)
신변잡기 (48)
디지털 회로 (1)
Programming (12)
무선 네트워크 (15)
Computer (5)
사용기 (5)

글 보관함

124

87

-35 days

today : 9

Daum 블로거뉴스
믹시