您尚未登录。

楼主 #1 2020-03-14 23:35:26

malasy
会员
注册时间: 2020-03-14
已发帖子: 8
积分: 38

Windows裸机程序烧录工具,烧录到SD卡

Window下烧录裸机程序到tf卡的小工具,功能就是dd if=xxx of=xxx bs=xxx seek=xxx
截图

链接:https://github.com/malasy/SDCardWriter/releases
-------------------------
刚入坑嵌入式开发,跟着网上的的视频一起学,昨天跑通了第一个裸机程序,想着改善下开发环境,因为要windows和ubuntu来回切换,非常麻烦。就想到了用Win10的WSL,对于学习裸机开发应该够了,问题是WSL不支持dd到TF卡,百度了也没找到windows下可用的工具,有大佬知道了给我推荐一下。然后就参考win32DiskImager的代码写了个小工具,暂时够用,先分享一下。












以下由 @哇酷小二 2020-09-27 添加:
------------------------------------------
感谢楼主分享, 不方便github的朋友可以本站下载: SDCardWriter.7z

最近编辑记录 malasy (2020-03-14 23:37:16)

离线

#2 2020-03-15 00:08:19

晕哥
管理员
注册时间: 2017-09-06
已发帖子: 9,350
积分: 9202

Re: Windows裸机程序烧录工具,烧录到SD卡

强大!





离线

#3 2020-03-15 06:58:35

chengjia535
会员
注册时间: 2020-03-15
已发帖子: 15
积分: 0

Re: Windows裸机程序烧录工具,烧录到SD卡

666

离线

#4 2020-03-15 07:14:03

迪卡
会员
所在地: 河北
注册时间: 2018-11-02
已发帖子: 916
积分: 903
个人网站

Re: Windows裸机程序烧录工具,烧录到SD卡

思路不错

离线

#5 2020-03-15 07:32:02

小智
会员
注册时间: 2019-10-16
已发帖子: 112
积分: 84

Re: Windows裸机程序烧录工具,烧录到SD卡

学习

离线

#6 2020-03-15 08:07:10

john78
会员
注册时间: 2018-07-19
已发帖子: 222
积分: 160

Re: Windows裸机程序烧录工具,烧录到SD卡

功能和Win32DiskImager类似?

离线

#7 2020-03-15 08:54:06

异乡是故乡
会员
注册时间: 2019-11-15
已发帖子: 74
积分: 73.5

Re: Windows裸机程序烧录工具,烧录到SD卡

给力给力, 核心就是这个了:

https://github.com/malasy/SDCardWriter/blob/master/SDCardWriter/SDCardWriterDlg.cpp#L396

https://github.com/malasy/SDCardWriter/blob/master/SDCardWriter/SDCardWriterDlg.cpp#L594

// SDCardWriterDlg.cpp: 实现文件
//

#include "pch.h"
#include "framework.h"
#include "SDCardWriter.h"
#include "SDCardWriterDlg.h"
#include "afxdialogex.h"
#include <Dbt.h>
#include "winioctl.h"
#include "ioapiset.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

#define SECTION_NAME "SDCardWriter"
#define BLOCK_SIZE_KEY "block_size"
#define BLOCK_COUNT_KEY "block_count"
#define WINDOW_X "left"
#define WINDOW_Y "top"


// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// 对话框数据
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_ABOUTBOX };
#endif

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CSDCardWriterDlg 对话框


CSDCardWriterDlg::CSDCardWriterDlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_SDCARDWRITER_DIALOG, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDI_ICON_SD);
}

void CSDCardWriterDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_DEVICE_COMB, m_cbDevice);
}

BEGIN_MESSAGE_MAP(CSDCardWriterDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_WM_DEVICECHANGE()
	ON_BN_CLICKED(IDC_INPUT_BTN, &CSDCardWriterDlg::OnBnClickedInputBtn)
	ON_CBN_SELCHANGE(IDC_DEVICE_COMB, &CSDCardWriterDlg::OnCbnSelchangeDeviceComb)
	ON_BN_CLICKED(IDC_BTN_BURN, &CSDCardWriterDlg::OnBnClickedBtnBurn)
	ON_STN_CLICKED(IDC_STATIC_LINK, &CSDCardWriterDlg::OnStnClickedStaticLink)
END_MESSAGE_MAP()


// CSDCardWriterDlg 消息处理程序

BOOL CSDCardWriterDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 将“关于...”菜单项添加到系统菜单中。

	// IDM_ABOUTBOX 必须在系统命令范围内。
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != nullptr)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	// TODO: 在此添加额外的初始化代码
	initCombobox();
	
	//读取配置文件
	CString blockSize = AfxGetApp()->GetProfileString(_T(SECTION_NAME), _T(BLOCK_SIZE_KEY));
	CString blockCount = AfxGetApp()->GetProfileString(_T(SECTION_NAME), _T(BLOCK_COUNT_KEY));
	GetDlgItem(IDC_EDIT_BLOCK_SIZE)->SetWindowTextW(blockSize);
	GetDlgItem(IDC_EDIT_OFFSET)->SetWindowTextW(blockCount);

	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

void CSDCardWriterDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void CSDCardWriterDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使图标在工作区矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CSDCardWriterDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

//监听USB设备的插入和移除
BOOL CSDCardWriterDlg::OnDeviceChange(UINT nEventType, DWORD dwData)
{
	if (nEventType == DBT_DEVICEREMOVECOMPLETE) {
		initCombobox();
	}

	if (nEventType == DBT_DEVICEARRIVAL) {
		initCombobox();
	}
	
	return false;
}


//打开资源管理器选择文件
void CSDCardWriterDlg::OnBnClickedInputBtn()
{
	filePath = _T("");
	CFileDialog dlgFile(TRUE, NULL, NULL, OFN_HIDEREADONLY, _T("Bin文件(*.bin)|*.bin|All Files(*.*)|*.*||"), NULL);
	if (dlgFile.DoModal()) {
		filePath = dlgFile.GetPathName();
		if (!filePath.IsEmpty()) {
			GetDlgItem(IDC_INPUT_ET)->SetWindowTextW(filePath);
		}
	}
}

//获取所有的USB设备盘符(一个字母)
int CSDCardWriterDlg::get_usb_disk(char usb_paths[])
{
	DWORD all_disk = GetLogicalDrives();
	int usb_cnt = 0;
	int i = 0;
	char disk_path[5] = { 0 };
	char device_path[10] = { 0 };
	char device_name[100] = {0};
	while (all_disk && usb_cnt < 5) {
		if ((all_disk & 0x1) == 1) {
			sprintf_s(device_path, "%c:\\", 'A' + i);
			if (GetDriveType(CString(device_path)) == DRIVE_REMOVABLE) {
				usb_paths[usb_cnt++] = 'A' + i;
			}
		}
		all_disk = all_disk >> 1;
		i++;
	}
	return usb_cnt;
}

//重新填充下拉列表数据
void CSDCardWriterDlg::initCombobox()
{
	//清空下拉列表
	m_cbDevice.ResetContent();
	int count = get_usb_disk(devicePaths);
	if (count == 0) {
		m_cbDevice.AddString(_T(""));
		m_cbDevice.SetCurSel(0);
		deviceLabel = '#';
		return;
	}
	CString strInfo;
	for (int i = 0; i < count; i++) {
		strInfo.Format(_T("%c:"), devicePaths[i]);
		m_cbDevice.InsertString(i, strInfo);
	}
	//默认选中第一个
	m_cbDevice.SetCurSel(0);
	deviceLabel = devicePaths[0];
}

HANDLE CSDCardWriterDlg::getHandleOnFile(LPCWSTR filelocation, DWORD access)
{
	HANDLE hFile;
	hFile = CreateFileW(filelocation, access, (access == GENERIC_READ) ? FILE_SHARE_READ : 0, NULL, (access == GENERIC_READ) ? OPEN_EXISTING : CREATE_ALWAYS, 0, NULL);
	if (hFile == INVALID_HANDLE_VALUE)
	{
		wchar_t* errormessage = NULL;
		FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, GetLastError(), 0, (LPWSTR)&errormessage, 0, NULL);
		CString errInfo;
		errInfo.Format(_T("An error occurred when attempting to get a handle on the file.  Error:%d  %s"), GetLastError(), errormessage);
		MessageBox(errInfo);
		LocalFree(errormessage);
	}
	return hFile;
}

HANDLE CSDCardWriterDlg::getHandleOnVolume(char volume, DWORD access)
{
	HANDLE hVolume;
	char volumename[] = "\\\\.\\A:";
	volumename[4] = volume;
	hVolume = CreateFile(CString(volumename), access, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
	if (hVolume == INVALID_HANDLE_VALUE)
	{
		wchar_t* errormessage = NULL;
		FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, GetLastError(), 0, (LPWSTR)&errormessage, 0, NULL);
		CString errInfo;
		errInfo.Format(_T("An error occurred when attempting to get handle on volume.  Error:%d  %s"), GetLastError(), errormessage);
		MessageBox(errInfo);
	}
	return hVolume;
}

bool CSDCardWriterDlg::getLockOnVolume(HANDLE handle)
{
	DWORD bytesreturned;
	BOOL bResult;
	bResult = DeviceIoControl(handle, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &bytesreturned, NULL);
	if (!bResult)
	{
		wchar_t* errormessage = NULL;
		FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, GetLastError(), 0, (LPWSTR)&errormessage, 0, NULL);
		CString errInfo;
		errInfo.Format(_T("An error occurred when attempting to lock the volume.  Error:%d  %s"), GetLastError(), errormessage);
		MessageBox(errInfo);
	}
	return (bResult);
}

bool CSDCardWriterDlg::removeLockOnVolume(HANDLE handle)
{
	DWORD junk;
	BOOL bResult;
	bResult = DeviceIoControl(handle, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &junk, NULL);
	if (!bResult)
	{
		wchar_t* errormessage = NULL;
		FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, GetLastError(), 0, (LPWSTR)&errormessage, 0, NULL);
		CString errInfo;
		errInfo.Format(_T("An error occurred when attempting to unlock the volume.  Error:%d  %s"), GetLastError(), errormessage);
		MessageBox(errInfo);
	}
	return (bResult);
}

bool CSDCardWriterDlg::unmountVolume(HANDLE handle)
{
	DWORD junk;
	BOOL bResult;
	bResult = DeviceIoControl(handle, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &junk, NULL);
	if (!bResult)
	{
		wchar_t* errormessage = NULL;
		FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, GetLastError(), 0, (LPWSTR)&errormessage, 0, NULL);
		CString errInfo;
		errInfo.Format(_T("An error occurred when attempting to dismount the volume.  Error:%d  %s"), GetLastError(), errormessage);
		MessageBox(errInfo);
	}
	return (bResult);
}

bool CSDCardWriterDlg::isVolumeUnmounted(HANDLE handle)
{
	DWORD junk;
	BOOL bResult;
	bResult = DeviceIoControl(handle, FSCTL_IS_VOLUME_MOUNTED, NULL, 0, NULL, 0, &junk, NULL);
	return (!bResult);
}

DWORD CSDCardWriterDlg::getDeviceID(HANDLE hVolume)
{
	VOLUME_DISK_EXTENTS sd;
	DWORD bytesreturned;
	if (!DeviceIoControl(hVolume, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL, 0, &sd, sizeof(sd), &bytesreturned, NULL))
	{
		wchar_t* errormessage = NULL;
		FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, GetLastError(), 0, (LPWSTR)&errormessage, 0, NULL);
		CString errInfo;
		errInfo.Format(_T("An error occurred when attempting to get information on volume.  Error:%d  %s"), GetLastError(), errormessage);
		MessageBox(errInfo);
	}
	return sd.Extents[0].DiskNumber;
}

HANDLE CSDCardWriterDlg::getHandleOnDevice(int device, DWORD access)
{
	HANDLE hDevice;
	CString devicename;
	devicename.Format(_T("\\\\.\\PhysicalDrive%d"), device);

	hDevice = CreateFile(devicename, access, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
	if (hDevice == INVALID_HANDLE_VALUE)
	{
		wchar_t* errormessage = NULL;
		FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, GetLastError(), 0, (LPWSTR)&errormessage, 0, NULL);
		CString errInfo;
		errInfo.Format(_T("An error occurred when attempting to get a handle on the device.  Error:%d  %s"), GetLastError(), errormessage);
		MessageBox(errInfo);
		LocalFree(errormessage);
	}
	return hDevice;
}

char* CSDCardWriterDlg::readSectorDataFromHandle(HANDLE handle, unsigned long long startsector, unsigned long long numsectors, unsigned long long sectorsize)
{
	unsigned long bytesread;
	char* data = new char[sectorsize * numsectors];
	LARGE_INTEGER li;
	li.QuadPart = startsector * sectorsize;
	SetFilePointer(handle, li.LowPart, &li.HighPart, FILE_BEGIN);
	if (!ReadFile(handle, data, sectorsize * numsectors, &bytesread, NULL))
	{
		wchar_t* errormessage = NULL;
		FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, GetLastError(), 0, (LPWSTR)&errormessage, 0, NULL);
		CString errInfo;
		errInfo.Format(_T("An error occurred when attempting to read data from handle.  Error:%d  %s"), GetLastError(), errormessage);
		MessageBox(errInfo);
		delete[] data;
		data = NULL;
	}
	if (data && bytesread < (sectorsize * numsectors))
	{
		memset(data + bytesread, 0, (sectorsize * numsectors) - bytesread);
	}
	return data;
}

bool CSDCardWriterDlg::writeSectorDataToHandle(HANDLE handle, char* data, unsigned long long startsector, unsigned long long numsectors, unsigned long long sectorsize)
{
	unsigned long byteswritten;
	BOOL bResult;
	LARGE_INTEGER li;
	li.QuadPart = startsector * sectorsize;
	SetFilePointer(handle, li.LowPart, &li.HighPart, FILE_BEGIN);
	bResult = WriteFile(handle, data, sectorsize * numsectors, &byteswritten, NULL);
	if (!bResult)
	{
		wchar_t* errormessage = NULL;
		FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, GetLastError(), 0, (LPWSTR)&errormessage, 0, NULL);
		CString errInfo;
		errInfo.Format(_T("An error occurred when attempting to write data to handle.  Error:%d  %s"), GetLastError(), errormessage);
		MessageBox(errInfo);
	}
	return (bResult);
}

unsigned long long CSDCardWriterDlg::getFileSizeInSectors(HANDLE handle, unsigned long long sectorsize)
{
	unsigned long long retVal = 0;
	if (sectorsize) // avoid divide by 0
	{
		LARGE_INTEGER filesize;
		if (GetFileSizeEx(handle, &filesize) == 0)
		{
			wchar_t* errormessage = NULL;
			FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, GetLastError(), 0, (LPWSTR)&errormessage, 0, NULL);
			CString errInfo;
			errInfo.Format(_T("An error occurred while getting the file size.  Error:%d  %s"), GetLastError(), errormessage);
			MessageBox(errInfo);
			retVal = 0;
		}
		else
		{
			retVal = ((unsigned long long)filesize.QuadPart / sectorsize) + (((unsigned long long)filesize.QuadPart % sectorsize) ? 1 : 0);
		}
	}
	return(retVal);
}

unsigned long long CSDCardWriterDlg::getNumberOfSectors(HANDLE handle, unsigned long long* sectorsize)
{
	DWORD junk;
	DISK_GEOMETRY_EX diskgeometry;
	BOOL bResult;
	bResult = DeviceIoControl(handle, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, &diskgeometry, sizeof(diskgeometry), &junk, NULL);
	if (!bResult)
	{
		wchar_t* errormessage = NULL;
		FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, GetLastError(), 0, (LPWSTR)&errormessage, 0, NULL);
		CString errInfo;
		errInfo.Format(_T("An error occurred when attempting to get the device's geometry.  Error:%d  %s"), GetLastError(), errormessage);
		MessageBox(errInfo);
		return 0;
	}
	if (sectorsize != NULL)
	{
		*sectorsize = (unsigned long long)diskgeometry.Geometry.BytesPerSector;
	}
	return (unsigned long long)diskgeometry.DiskSize.QuadPart / (unsigned long long)diskgeometry.Geometry.BytesPerSector;
}

//下拉选中列表中的另外一项
void CSDCardWriterDlg::OnCbnSelchangeDeviceComb()
{
	int sel = m_cbDevice.GetCurSel();
	deviceLabel = devicePaths[sel];
}


//点击烧录按钮
void CSDCardWriterDlg::OnBnClickedBtnBurn()
{
	//获取必须数据:烧录的文件,烧录的设备,偏移,块大小
	if (filePath.IsEmpty() || deviceLabel == '#') {
		MessageBox(_T("请选择设备和烧录的文件"));
		return;
	}
	CString blockSizeStr;
	CString blockCountStr;
	GetDlgItem(IDC_EDIT_BLOCK_SIZE)->GetWindowTextW(blockSizeStr);
	GetDlgItem(IDC_EDIT_OFFSET)->GetWindowTextW(blockCountStr);
	if (blockSizeStr.IsEmpty() || blockCountStr.IsEmpty()) {
		MessageBox(_T("请输入块大小和偏移量"));
		return;
	}
	//保存数据
	AfxGetApp()->WriteProfileStringW(_T(SECTION_NAME), _T(BLOCK_SIZE_KEY), blockSizeStr);
	AfxGetApp()->WriteProfileStringW(_T(SECTION_NAME), _T(BLOCK_COUNT_KEY), blockCountStr);

	//字符串-->数字
	unsigned long long blockSize = _ttoi(blockSizeStr);
	unsigned int blockCount = _ttoi(blockCountStr);

	int status = STATUS_WRITING;
	//获取卷句柄
	HANDLE hVolume = getHandleOnVolume(deviceLabel, GENERIC_WRITE);
	if (hVolume == INVALID_HANDLE_VALUE) { 
		status = STATUS_IDLE;
		return; 
	}
	//获取设备ID
	DWORD deviceID = getDeviceID(hVolume);
	if (!getLockOnVolume(hVolume))
	{
		CloseHandle(hVolume);
		hVolume = INVALID_HANDLE_VALUE;
		status = STATUS_IDLE;
		return;
	}
	//卸载卷(不懂为什么要这样,猜测应该是需要卸载设备,解除系统对该设备的占用,然后我们才能直接操作该设备)
	if (!unmountVolume(hVolume))
	{
		removeLockOnVolume(hVolume);
		CloseHandle(hVolume);
		hVolume = INVALID_HANDLE_VALUE;
		status = STATUS_IDLE;
		return;
	}

	//获取文件句柄
	HANDLE hFile = getHandleOnFile(filePath, GENERIC_READ);
	if (hFile == INVALID_HANDLE_VALUE)
	{
		removeLockOnVolume(hVolume);
		CloseHandle(hVolume);
		hVolume = INVALID_HANDLE_VALUE;
		status = STATUS_IDLE;
		return;
	}

	//得到设备的物理地址。hVolume是应用层使用的地址,hRawDisk是驱动层使用的地址(不太确定)
	HANDLE hRawDisk = getHandleOnDevice(deviceID, GENERIC_WRITE);
	if (hRawDisk == INVALID_HANDLE_VALUE)
	{
		removeLockOnVolume(hVolume);
		CloseHandle(hFile);
		CloseHandle(hVolume);
		hVolume = INVALID_HANDLE_VALUE;
		hFile = INVALID_HANDLE_VALUE;
		status = STATUS_IDLE;
		return;
	}
	unsigned long long numsectors,sectorsize, availablesectors, lasti,i;

	//获取可用空间(以扇区为单位)和扇区大小,一般扇区大小为512Byte
	availablesectors = getNumberOfSectors(hRawDisk, &sectorsize);
	if (!availablesectors) { 
		removeLockOnVolume(hVolume);
		CloseHandle(hRawDisk);
		CloseHandle(hFile);
		CloseHandle(hVolume);
		hRawDisk = INVALID_HANDLE_VALUE;
		hFile = INVALID_HANDLE_VALUE;
		hVolume = INVALID_HANDLE_VALUE;
		status = STATUS_IDLE;
		return; 
	}

	//获取文件大小(以扇区为单位)
	numsectors = getFileSizeInSectors(hFile, sectorsize);
	if (!numsectors)
	{
		removeLockOnVolume(hVolume);
		CloseHandle(hRawDisk);
		CloseHandle(hFile);
		CloseHandle(hVolume);
		hRawDisk = INVALID_HANDLE_VALUE;
		hFile = INVALID_HANDLE_VALUE;
		hVolume = INVALID_HANDLE_VALUE;
		status = STATUS_IDLE;
		return;
	}

	if (numsectors > availablesectors) {
		MessageBox(_T("More space required than is available"));
	}
	lasti = 0ul;
	char* sectorData;

	//计算需要偏移的扇区数
	unsigned long long offsetSector = (blockSize * blockCount)/sectorsize;
	for (i = 0ul; i < numsectors && status == STATUS_WRITING; i += 1024ul) {
		sectorData = readSectorDataFromHandle(hFile, i, (numsectors - i >= 1024ul) ? 1024ul : (numsectors - i), sectorsize);
		if (sectorData == NULL)
		{
			removeLockOnVolume(hVolume);
			CloseHandle(hRawDisk);
			CloseHandle(hFile);
			CloseHandle(hVolume);
			status = STATUS_IDLE;
			hRawDisk = INVALID_HANDLE_VALUE;
			hFile = INVALID_HANDLE_VALUE;
			hVolume = INVALID_HANDLE_VALUE;
			return;
		}
		if (!writeSectorDataToHandle(hRawDisk, sectorData, offsetSector + i, (numsectors - i >= 1024ul) ? 1024ul : (numsectors - i), sectorsize))
		{
			delete[] sectorData;
			removeLockOnVolume(hVolume);
			CloseHandle(hRawDisk);
			CloseHandle(hFile);
			CloseHandle(hVolume);
			status = STATUS_IDLE;
			sectorData = NULL;
			hRawDisk = INVALID_HANDLE_VALUE;
			hFile = INVALID_HANDLE_VALUE;
			hVolume = INVALID_HANDLE_VALUE;
			return;
		}
		delete[] sectorData;
		sectorData = NULL;
	}
	removeLockOnVolume(hVolume);
	CloseHandle(hRawDisk);
	CloseHandle(hFile);
	CloseHandle(hVolume);
	hRawDisk = INVALID_HANDLE_VALUE;
	hFile = INVALID_HANDLE_VALUE;
	hVolume = INVALID_HANDLE_VALUE;
	MessageBox(_T("烧录成功!"));
}


void CSDCardWriterDlg::OnStnClickedStaticLink()
{
	ShellExecute(0, NULL, _T("https://github.com/malasy/SDCardWriter"), NULL, NULL, SW_NORMAL);
}

离线

楼主 #8 2020-03-15 16:44:44

malasy
会员
注册时间: 2020-03-14
已发帖子: 8
积分: 38

Re: Windows裸机程序烧录工具,烧录到SD卡

john78 说:

功能和Win32DiskImager类似?

实现方法类似。功能不一样,我这个主要是为了偏移量。

离线

#9 2020-09-27 18:54:29

我思故我在
会员
注册时间: 2019-09-03
已发帖子: 244
积分: 243.5

Re: Windows裸机程序烧录工具,烧录到SD卡

这个给力!

离线

#10 2020-09-27 18:57:51

马前卒
会员
注册时间: 2020-08-08
已发帖子: 60
积分: 57

Re: Windows裸机程序烧录工具,烧录到SD卡

QQ截图20200927185730.png

dd if=fel-sdboot.sunxi of=fel-sdboot.img bs=1024 seek=8

然后用 win32diskimager 烧录 fel-sdboot.img 就可以了.

插入SD0然后上电, 强制进入USB烧录模式。

本站下载: fel-sdboot.zip

离线

#11 2020-09-28 12:34:13

vip888888
会员
注册时间: 2020-07-16
已发帖子: 141
积分: 138

Re: Windows裸机程序烧录工具,烧录到SD卡

就烧录来说还是比较方便不用连接到虚拟机去。整好了image直接下载就行了。

离线

#12 2020-10-15 14:37:10

路漫漫
会员
注册时间: 2019-07-22
已发帖子: 65
积分: 54

Re: Windows裸机程序烧录工具,烧录到SD卡

马前卒 说:

https://whycan.com/files/members/4986/QQ截图20200927185730.png

dd if=fel-sdboot.sunxi of=fel-sdboot.img bs=1024 seek=8

然后用 win32diskimager 烧录 fel-sdboot.img 就可以了.

本站下载: fel-sdboot.zip

感谢, 学到了新知识。

离线

#13 2020-10-16 09:16:52

shawn.d
会员
注册时间: 2020-09-12
已发帖子: 164
积分: 95

Re: Windows裸机程序烧录工具,烧录到SD卡

厉害

离线

#14 2020-10-17 11:42:41

不会飞的渡渡鸟
会员
注册时间: 2020-10-17
已发帖子: 1
积分: 1

Re: Windows裸机程序烧录工具,烧录到SD卡

666

离线

#15 2022-01-18 17:36:55

表慌张
会员
注册时间: 2020-09-03
已发帖子: 18
积分: 22.5

Re: Windows裸机程序烧录工具,烧录到SD卡

这个漂亮,可以吧msys2丢掉了

离线

#16 2022-01-19 10:16:19

dykxjh
会员
注册时间: 2020-03-25
已发帖子: 171
积分: 166

Re: Windows裸机程序烧录工具,烧录到SD卡

偏移要是直接支持地址就好了。我一直在找一个直接支持指定地址烧录的软件。比如我想把一个镜像直接写入sd卡8MByte的地方,但是Win32DiskImager只能写入0地址,没办法我只能先把sd卡的镜像读回来,然后裁剪拼接,然后再整体写入。

离线

#18 2022-05-27 13:11:39

hameyou
会员
注册时间: 2018-04-15
已发帖子: 200
积分: 7.5

Re: Windows裸机程序烧录工具,烧录到SD卡

来的正好,就缺这么一个工具了,方便了很多,之前每次都在Linux有些麻烦

离线

#19 2022-11-25 02:36:17

Simn
会员
注册时间: 2021-12-16
已发帖子: 33
积分: 3

Re: Windows裸机程序烧录工具,烧录到SD卡

我使用 cfimager.exe + *.BAT 实用程 但是你的实用程序更有趣

cfimager.exe tool is used to flash boot images and create FAT partition on SD/MMC cards
on the host PC
- To flash the uboot, use the following command:
cfimager -raw -offset 0x400 -skip 0x400 -f u-boot.bin -d
cfimager.exe -raw -offset 0x2000 -f boot.bin -d F
Note if changing -offset 0xXXXX, other image can be flashed to SD card "F".

Exemple bat file:
rem cfimager.exe -raw -offset 0x2000 -f boot.bin -d Disk F
cfimager.exe -raw -offset 0x2000 -f boot.bin -d F
pause

https://gitlab.com/my-imx6/mfgtools/tree/master/Utils/cfimager
https://github.com/NXPmicro/cfimager

离线

#21 2023-01-16 10:43:44

lzw
会员
注册时间: 2022-07-31
已发帖子: 20
积分: -7

Re: Windows裸机程序烧录工具,烧录到SD卡

.bin的程序可以烧录吗

离线

#23 2024-04-08 16:28:16

酱爸
会员
注册时间: 2024-01-06
已发帖子: 6
积分: 1

Re: Windows裸机程序烧录工具,烧录到SD卡

感谢大佬的无私分享,太方便了,不用每次都切换到虚拟机里面去敲指令了

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn