PICO_INTERNAL int Load_ISO(const char *iso_name, int is_bin) { int i, j, num_track, Cur_LBA, index, ret, iso_name_len; _scd_track *Tracks = Pico_mcd->TOC.Tracks; char tmp_name[1024], tmp_ext[10]; pm_file *pmf; static char *exts[] = { "%02d.mp3", " %02d.mp3", "-%02d.mp3", "_%02d.mp3", " - %02d.mp3", "%d.mp3", " %d.mp3", "-%d.mp3", "_%d.mp3", " - %d.mp3", #if CASE_SENSITIVE_FS "%02d.MP3", " %02d.MP3", "-%02d.MP3", "_%02d.MP3", " - %02d.MP3", #endif }; if (PicoCDLoadProgressCB != NULL) PicoCDLoadProgressCB(1); Unload_ISO(); Tracks[0].ftype = is_bin ? TYPE_BIN : TYPE_ISO; Tracks[0].F = pmf = pm_open(iso_name); if (Tracks[0].F == NULL) { Tracks[0].ftype = 0; Tracks[0].Length = 0; return -1; } if (Tracks[0].ftype == TYPE_ISO) Tracks[0].Length = pmf->size >>= 11; // size in sectors else Tracks[0].Length = pmf->size /= 2352;
PICO_INTERNAL int Load_CD_Image(const char *cd_img_name, cd_img_type type) { int i, j, num_track, Cur_LBA, index, ret; int iso_name_len, missed, cd_img_sectors; _scd_track *Tracks = Pico_mcd->TOC.Tracks; char tmp_name[256], tmp_ext[10], tmp_ext_u[10]; cue_data_t *cue_data = NULL; pm_file *pmf; static const char *exts[] = { "%02d.mp3", " %02d.mp3", "-%02d.mp3", "_%02d.mp3", " - %02d.mp3", "%d.mp3", " %d.mp3", "-%d.mp3", "_%d.mp3", " - %d.mp3", }; if (PicoCDLoadProgressCB != NULL) PicoCDLoadProgressCB(cd_img_name, 1); Unload_ISO(); /* is this a .cue? */ cue_data = cue_parse(cd_img_name); if (cue_data != NULL) { cd_img_name = cue_data->tracks[1].fname; Tracks[0].ftype = cue_data->tracks[1].type; } else Tracks[0].ftype = type == CIT_BIN ? CT_BIN : CT_ISO; Tracks[0].F = pmf = pm_open(cd_img_name); if (Tracks[0].F == NULL) { Tracks[0].ftype = 0; Tracks[0].Length = 0; if (cue_data != NULL) cue_destroy(cue_data); return -1; } if (Tracks[0].ftype == CT_ISO) cd_img_sectors = pmf->size >>= 11; // size in sectors else cd_img_sectors = pmf->size /= 2352;
/* checks if romFileName points to valid MegaCD image * if so, checks for suitable BIOS */ int emu_cdCheck(int *pregion) { unsigned char buf[32]; pm_file *cd_f; int type = 0, region = 4; // 1: Japan, 4: US, 8: Europe cd_f = pm_open(romFileName); if (!cd_f) return 0; // let the upper level handle this if (pm_read(buf, 32, cd_f) != 32) { pm_close(cd_f); return 0; } if (!strncasecmp("SEGADISCSYSTEM", (char *)buf+0x00, 14)) type = 1; // Sega CD (ISO) if (!strncasecmp("SEGADISCSYSTEM", (char *)buf+0x10, 14)) type = 2; // Sega CD (BIN) if (type == 0) { pm_close(cd_f); return 0; } /* it seems we have a CD image here. Try to detect region now.. */ pm_seek(cd_f, (type == 1) ? 0x100+0x10B : 0x110+0x10B, SEEK_SET); pm_read(buf, 1, cd_f); pm_close(cd_f); if (buf[0] == 0x64) region = 8; // EU if (buf[0] == 0xa1) region = 1; // JAP lprintf("detected %s Sega/Mega CD image with %s region\n", type == 2 ? "BIN" : "ISO", region != 4 ? (region == 8 ? "EU" : "JAP") : "USA"); if (pregion != NULL) *pregion = region; return type; }
int emu_ReloadRom(void) { unsigned int rom_size = 0; char *used_rom_name = romFileName; char ext[5]; pm_file *rom; int ret, cd_state, cd_region, cfg_loaded = 0; lprintf("emu_ReloadRom(%s)\n", romFileName); get_ext(romFileName, ext); // detect wrong extensions if(!strcmp(ext, ".srm") || !strcmp(ext, "s.gz") || !strcmp(ext, ".mds")) { // s.gz ~ .mds.gz sprintf(menuErrorMsg, "Not a ROM selected."); return 0; } PicoPatchUnload(); // check for movie file if(movie_data) { free(movie_data); movie_data = 0; } #if 0 if(!strcmp(ext, ".gmv")) { // check for both gmv and rom int dummy; FILE *movie_file = fopen(romFileName, "rb"); if(!movie_file) { sprintf(menuErrorMsg, "Failed to open movie."); return 0; } fseek(movie_file, 0, SEEK_END); movie_size = ftell(movie_file); fseek(movie_file, 0, SEEK_SET); if(movie_size < 64+3) { sprintf(menuErrorMsg, "Invalid GMV file."); fclose(movie_file); return 0; } movie_data = malloc(movie_size); if(movie_data == NULL) { sprintf(menuErrorMsg, "low memory."); fclose(movie_file); return 0; } fread(movie_data, 1, movie_size, movie_file); fclose(movie_file); if (strncmp((char *)movie_data, "Gens Movie TEST", 15) != 0) { sprintf(menuErrorMsg, "Invalid GMV file."); return 0; } dummy = try_rfn_cut() || try_rfn_cut(); if (!dummy) { sprintf(menuErrorMsg, "Could't find a ROM for movie."); return 0; } get_ext(romFileName, ext); } else if (!strcmp(ext, ".pat")) { int dummy; PicoPatchLoad(romFileName); dummy = try_rfn_cut() || try_rfn_cut(); if (!dummy) { sprintf(menuErrorMsg, "Could't find a ROM to patch."); return 0; } get_ext(romFileName, ext); } #else // load GG patches list char ggFname[512]; romfname_ext(ggFname, NULL, ".cht"); PicoPatchLoad(ggFname); #endif if ((PicoMCD & 1) && Pico_mcd != NULL) Stop_CD(); // check for MegaCD image cd_state = emu_cdCheck(&cd_region); if (cd_state > 0) { // valid CD image, check for BIOS.. #if 0 // we need to have config loaded at this point ret = emu_ReadConfig(READ_CONFIG_FOR_GAME, READ_CONFIG_SKIP_DEF); if (!ret) emu_ReadConfig(READ_CONFIG_GLOBAL, READ_CONFIG_SKIP_DEF); #endif cfg_loaded = 1; if (PicoRegionOverride) { cd_region = PicoRegionOverride; lprintf("overrided region to %s\n", cd_region != 4 ? (cd_region == 8 ? "EU" : "JAP") : "USA"); } if (!emu_findBios(cd_region, &used_rom_name)) { // bios_help() ? return 0; } PicoMCD |= 1; get_ext(used_rom_name, ext); } else { if (PicoMCD & 1) Stop_CD(); PicoMCD &= ~1; } ips_define(ipsFileName); rom = pm_open(used_rom_name); if(!rom) { sprintf(menuErrorMsg, "Failed to open rom."); return 0; } menu_romload_prepare(used_rom_name); // also CD load if(rom_data) { free(rom_data); rom_data = 0; rom_size = 0; } if( (ret = PicoCartLoad(rom, &rom_data, &rom_size)) ) { sprintf(menuErrorMsg, "PicoCartLoad() failed."); lprintf("%s\n", menuErrorMsg); pm_close(rom); menu_romload_end(); return 0; } pm_close(rom); // detect wrong files (Pico crashes on very small files), also see if ROM EP is good if(rom_size <= 0x200 || strncmp((char *)rom_data, "Pico", 4) == 0 || ((*(unsigned char *)(rom_data+4)<<16)|(*(unsigned short *)(rom_data+6))) >= (int)rom_size) { if (rom_data) free(rom_data); rom_data = 0; sprintf(menuErrorMsg, "Not a ROM selected."); menu_romload_end(); return 0; } #if 0 // load config for this ROM (do this before insert to get correct region) if (!cfg_loaded) { ret = emu_ReadConfig(READ_CONFIG_FOR_GAME, READ_CONFIG_SKIP_DEF); if (!ret) emu_ReadConfig(READ_CONFIG_GLOBAL, READ_CONFIG_SKIP_DEF); } #endif lprintf("PicoCartInsert(%p, %d);\n", rom_data, rom_size); if(PicoCartInsert(rom_data, rom_size)) { sprintf(menuErrorMsg, "Failed to load ROM."); menu_romload_end(); return 0; } Pico.m.frame_count = 0; // insert CD if it was detected if (cd_state > 0) { ret = Insert_CD(romFileName, cd_state == 2); if (ret != 0) { sprintf(menuErrorMsg, "Insert_CD() failed, invalid CD image?"); lprintf("%s\n", menuErrorMsg); menu_romload_end(); return 0; } } menu_romload_end(); #if 0 if (!emu_isBios(romFileName)) { // emu_ReadConfig() might have messed currentConfig.lastRomFile strncpy(currentConfig.lastRomFile, romFileName, sizeof(currentConfig.lastRomFile)-1); currentConfig.lastRomFile[sizeof(currentConfig.lastRomFile)-1] = 0; } #endif if (PicoPatches) { PicoPatchPrepare(); PicoPatchApply(); } // additional movie stuff if (movie_data) { if(movie_data[0x14] == '6') PicoOpt |= PicoOpt_6button_gamepad; // 6 button pad else PicoOpt &= ~PicoOpt_6button_gamepad; PicoOpt |= (PicoOpt_accurate_timing | PicoOpt_disable_vdp_fifo); // accurate timing, no VDP fifo timing if(movie_data[0xF] >= 'A') { if(movie_data[0x16] & 0x80) { PicoRegionOverride = 8; } else { PicoRegionOverride = 4; } PicoReset(0); // TODO: bits 6 & 5 } movie_data[0x18+30] = 0; sprintf(noticeMsg, "MOVIE: %s", (char *) &movie_data[0x18]); } else { PicoOpt &= ~PicoOpt_disable_vdp_fifo; if(Pico.m.pal) { strcpy(noticeMsg, "PAL SYSTEM / 50 FPS"); } else { strcpy(noticeMsg, "NTSC SYSTEM / 60 FPS"); } } emu_noticeMsgUpdated(); // load SRAM for this ROM emu_SaveLoadSRAM(1); return 1; }
static int detect_media(const char *fname) { static const short sms_offsets[] = { 0x7ff0, 0x3ff0, 0x1ff0 }; static const char *sms_exts[] = { "sms", "gg", "sg" }; static const char *md_exts[] = { "gen", "bin", "smd" }; char buff0[32], buff[32]; unsigned short *d16; pm_file *pmf; char ext[5]; int i; get_ext(fname, ext); // detect wrong extensions if (!strcmp(ext, ".srm") || !strcmp(ext, "s.gz") || !strcmp(ext, ".mds")) // s.gz ~ .mds.gz return PM_BAD_DETECT; /* don't believe in extensions, except .cue */ if (strcasecmp(ext, ".cue") == 0) return PM_CD; pmf = pm_open(fname); if (pmf == NULL) return PM_BAD_DETECT; if (pm_read(buff0, 32, pmf) != 32) { pm_close(pmf); return PM_BAD_DETECT; } if (strncasecmp("SEGADISCSYSTEM", buff0 + 0x00, 14) == 0 || strncasecmp("SEGADISCSYSTEM", buff0 + 0x10, 14) == 0) { pm_close(pmf); return PM_CD; } /* check for SMD evil */ if (pmf->size >= 0x4200 && (pmf->size & 0x3fff) == 0x200) { if (pm_seek(pmf, sms_offsets[0] + 0x200, SEEK_SET) == sms_offsets[0] + 0x200 && pm_read(buff, 16, pmf) == 16 && strncmp("TMR SEGA", buff, 8) == 0) goto looks_like_sms; /* could parse further but don't bother */ goto extension_check; } /* MD header? Act as TMSS BIOS here */ if (pm_seek(pmf, 0x100, SEEK_SET) == 0x100 && pm_read(buff, 16, pmf) == 16) { if (strncmp(buff, "SEGA", 4) == 0 || strncmp(buff, " SEG", 4) == 0) goto looks_like_md; } for (i = 0; i < ARRAY_SIZE(sms_offsets); i++) { if (pm_seek(pmf, sms_offsets[i], SEEK_SET) != sms_offsets[i]) continue; if (pm_read(buff, 16, pmf) != 16) continue; if (strncmp("TMR SEGA", buff, 8) == 0) goto looks_like_sms; } extension_check: /* probably some headerless thing. Maybe check the extension after all. */ for (i = 0; i < ARRAY_SIZE(md_exts); i++) if (strcasecmp(pmf->ext, md_exts[i]) == 0) goto looks_like_md; for (i = 0; i < ARRAY_SIZE(sms_exts); i++) if (strcasecmp(pmf->ext, sms_exts[i]) == 0) goto looks_like_sms; /* If everything else fails, make a guess on the reset vector */ d16 = (unsigned short *)(buff0 + 4); if ((((d16[0] << 16) | d16[1]) & 0xffffff) >= pmf->size) { lprintf("bad MD reset vector, assuming SMS\n"); goto looks_like_sms; } looks_like_md: pm_close(pmf); return PM_MD_CART; looks_like_sms: pm_close(pmf); return PM_MARK3; }
enum media_type_e PicoLoadMedia(const char *filename, const char *carthw_cfg_fname, const char *(*get_bios_filename)(int *region, const char *cd_fname), void (*do_region_override)(const char *media_filename)) { const char *rom_fname = filename; enum media_type_e media_type; enum cd_img_type cd_img_type = CIT_NOT_CD; unsigned char *rom_data = NULL; unsigned int rom_size = 0; pm_file *rom = NULL; int cd_region = 0; int ret; media_type = detect_media(filename); if (media_type == PM_BAD_DETECT) goto out; if ((PicoAHW & PAHW_MCD) && Pico_mcd != NULL) cdd_unload(); PicoCartUnload(); PicoAHW = 0; PicoQuirks = 0; if (media_type == PM_CD) { // check for MegaCD image cd_img_type = PicoCdCheck(filename, &cd_region); if ((int)cd_img_type >= 0 && cd_img_type != CIT_NOT_CD) { // valid CD image, ask frontend for BIOS.. rom_fname = NULL; if (get_bios_filename != NULL) rom_fname = get_bios_filename(&cd_region, filename); if (rom_fname == NULL) { media_type = PM_BAD_CD_NO_BIOS; goto out; } PicoAHW |= PAHW_MCD; } else { media_type = PM_BAD_CD; goto out; } } else if (media_type == PM_MARK3) { lprintf("detected SMS ROM\n"); PicoAHW = PAHW_SMS; } rom = pm_open(rom_fname); if (rom == NULL) { lprintf("Failed to open ROM\n"); media_type = PM_ERROR; goto out; } ret = PicoCartLoad(rom, &rom_data, &rom_size, (PicoAHW & PAHW_SMS) ? 1 : 0); pm_close(rom); if (ret != 0) { if (ret == 2) lprintf("Out of memory\n"); else if (ret == 3) lprintf("Read failed\n"); else lprintf("PicoCartLoad() failed.\n"); media_type = PM_ERROR; goto out; } // detect wrong files if (strncmp((char *)rom_data, "Pico", 4) == 0) { lprintf("savestate selected?\n"); media_type = PM_BAD_DETECT; goto out; } if (!(PicoAHW & PAHW_SMS)) { unsigned short *d = (unsigned short *)(rom_data + 4); if ((((d[0] << 16) | d[1]) & 0xffffff) >= (int)rom_size) { lprintf("bad reset vector\n"); media_type = PM_BAD_DETECT; goto out; } } // load config for this ROM (do this before insert to get correct region) if (!(PicoAHW & PAHW_MCD)) { memcpy(media_id_header, rom_data + 0x100, sizeof(media_id_header)); if (do_region_override != NULL) do_region_override(filename); } if (PicoCartInsert(rom_data, rom_size, carthw_cfg_fname)) { media_type = PM_ERROR; goto out; } rom_data = NULL; // now belongs to PicoCart Pico.m.ncart_in = 0; // insert CD if it was detected if (cd_img_type != CIT_NOT_CD) { ret = cdd_load(filename, cd_img_type); if (ret != 0) { PicoCartUnload(); media_type = PM_BAD_CD; goto out; } Pico.m.ncart_in = 1; } if (PicoQuirks & PQUIRK_FORCE_6BTN) PicoSetInputDevice(0, PICO_INPUT_PAD_6BTN); out: if (rom_data) free(rom_data); return media_type; }
/* checks if fname points to valid MegaCD image */ int PicoCdCheck(const char *fname_in, int *pregion) { const char *fname = fname_in; unsigned char buf[32]; pm_file *cd_f; int region = 4; // 1: Japan, 4: US, 8: Europe char ext[5]; cue_track_type type = CT_UNKNOWN; cue_data_t *cue_data = NULL; // opens a cue, or searches for one cue_data = cue_parse(fname_in); if (cue_data != NULL) { fname = cue_data->tracks[1].fname; type = cue_data->tracks[1].type; } else { get_ext(fname_in, ext); if (strcasecmp(ext, ".cue") == 0) return -1; } cd_f = pm_open(fname); if (cue_data != NULL) cue_destroy(cue_data); if (cd_f == NULL) return 0; // let the upper level handle this if (pm_read(buf, 32, cd_f) != 32) { pm_close(cd_f); return -1; } if (!strncasecmp("SEGADISCSYSTEM", (char *)buf+0x00, 14)) { if (type && type != CT_ISO) elprintf(EL_STATUS, ".cue has wrong type: %i", type); type = CT_ISO; // Sega CD (ISO) } if (!strncasecmp("SEGADISCSYSTEM", (char *)buf+0x10, 14)) { if (type && type != CT_BIN) elprintf(EL_STATUS, ".cue has wrong type: %i", type); type = CT_BIN; // Sega CD (BIN) } if (type == CT_UNKNOWN) { pm_close(cd_f); return 0; } pm_seek(cd_f, (type == CT_ISO) ? 0x100 : 0x110, SEEK_SET); pm_read(media_id_header, sizeof(media_id_header), cd_f); /* it seems we have a CD image here. Try to detect region now.. */ pm_seek(cd_f, (type == CT_ISO) ? 0x100+0x10B : 0x110+0x10B, SEEK_SET); pm_read(buf, 1, cd_f); pm_close(cd_f); if (buf[0] == 0x64) region = 8; // EU if (buf[0] == 0xa1) region = 1; // JAP lprintf("detected %s Sega/Mega CD image with %s region\n", type == CT_BIN ? "BIN" : "ISO", region != 4 ? (region == 8 ? "EU" : "JAP") : "USA"); if (pregion != NULL) *pregion = region; return type; }
int main(void) { struct pm_context pm; float power; int ret; printf("Example program for libpm600x %s\n", pm_library_version()); printf("-----------------------------------\n\n"); // initialise the pm_context we want to use ret = pm_init(&pm); // find all power meter probes on the bus struct pm_list *list, *curdev; ret = pm_find_all(&pm, TYPE_PM_ALL, &list); if (!list) { printf("No powermeter probes found\n"); return -1; } // list all probes that we found for (curdev = list; curdev != NULL ;) { if (curdev->type == TYPE_PM_6006) printf("found PM 6006 with serial number %lu\n", curdev->serial); else if (curdev->type == TYPE_PM_6003) printf("found PM 6003 with serial number %lu\n", curdev->serial); curdev = curdev->next; } // open the first power meter that was found ret = pm_open(&pm, list->serial); if (ret < 0) { printf("Error %i, \"%s\"\n", ret, pm_get_error_string(&pm)); return -1; } // set frequency to 1 GHz ret = pm_set_frequency(&pm, 1000000000ULL); if (ret < 0) { printf("Error %i, \"%s\"\n", ret, pm_get_error_string(&pm)); return -1; } // set amount of averaging measurements to 255 ret = pm_set_averages(&pm, 255); if (ret < 0) { printf("Error %i, \"%s\"\n", ret, pm_get_error_string(&pm)); return -1; } // measure the power ret = pm_measure(&pm, &power); if (ret < 0) { printf("Error %i, \"%s\"\n", ret, pm_get_error_string(&pm)); return -1; } printf("Power: %.2f dBm\n", power); // close the device pm_close(&pm); // we do not need the device list anymore pm_list_free(&list); return 0; }
int main (void) { struct pm_context pm; struct pm_list *list, *curdev; int ret; /* A pointer to a function */ pm_init_func pm_init; pm_find_all_func pm_find_all; pm_list_free_func pm_list_free; pm_reset_func pm_reset; pm_identify_func pm_identify; pm_type_func pm_type; pm_open_func pm_open; pm_close_func pm_close; pm_measure_func pm_measure; pm_set_frequency_func pm_set_frequency; pm_set_averages_func pm_set_averages; pm_get_error_string_func pm_get_error_string; pm_library_version_func pm_library_version; pm_blink_func pm_blink; /* Windows handle */ HANDLE handle; /* Load the library */ handle = LoadLibrary("libpm600x.dll"); if (!handle) { printf("Error: can not load library libpm600x.dll\n"); return -1; } /* Get the proc addresses of the library */ pm_init = (pm_init_func)GetProcAddress(handle, "pm_init"); pm_find_all = (pm_find_all_func)GetProcAddress(handle, "pm_find_all"); pm_list_free = (pm_list_free_func)GetProcAddress(handle, "pm_list_free"); pm_reset = (pm_reset_func)GetProcAddress(handle, "pm_reset"); pm_identify = (pm_identify_func)GetProcAddress(handle, "pm_identify"); pm_type = (pm_type_func)GetProcAddress(handle, "pm_type"); pm_open = (pm_open_func)GetProcAddress(handle, "pm_open"); pm_close = (pm_close_func)GetProcAddress(handle, "pm_close"); pm_measure = (pm_measure_func)GetProcAddress(handle, "pm_measure"); pm_set_frequency = (pm_set_frequency_func)GetProcAddress(handle, "pm_set_frequency"); pm_set_averages = (pm_set_averages_func)GetProcAddress(handle, "pm_set_averages"); pm_get_error_string = (pm_get_error_string_func)GetProcAddress(handle, "pm_get_error_string"); pm_library_version = (pm_library_version_func)GetProcAddress(handle, "pm_library_version"); pm_blink = (pm_blink_func)GetProcAddress(handle, "pm_blink"); if (!pm_init || !pm_find_all || !pm_list_free || !pm_reset || !pm_identify || !pm_type || !pm_open || !pm_close || !pm_measure || !pm_set_frequency || !pm_set_averages || !pm_get_error_string || !pm_library_version || !pm_blink) { FreeLibrary(handle); printf ("Error: Can not get Proc Addesses!"); return -1; } printf("Example program for libpm600x %s\n", pm_library_version()); printf("-----------------------------------\n\n"); // initialise our pm_context pm_init(&pm); // find all power meter probes on the bus ret = pm_find_all(&pm, TYPE_PM_ALL, &list); if (!list) { printf("Error: No powermeter probes found\n"); FreeLibrary(handle); return -1; } // list all probes that we have found for (curdev = list; curdev != NULL ;) { if (curdev->type == TYPE_PM_6006) printf("found PM 6006 with serial number %lu\n", curdev->serial); else if (curdev->type == TYPE_PM_6003) printf("found PM 6003 with serial number %lu\n", curdev->serial); curdev = curdev->next; } // open the first power meter that was found ret = pm_open(&pm, list->serial); if (ret < 0) { printf("Error: %i \"%s\"\n", ret, pm_get_error_string(&pm)); pm_list_free(&list); FreeLibrary(handle); return -1; } // blink the probes green led ret = pm_blink(&pm); if (ret < 0) { printf("Error %i, \"%s\"\n", ret, pm_get_error_string(&pm)); pm_list_free(&list); FreeLibrary(handle); return -1; } // set frequency ret = pm_set_frequency(&pm, 1000000000ULL); if (ret < 0) { printf("Error %i, \"%s\"\n", ret, pm_get_error_string(&pm)); pm_list_free(&list); FreeLibrary(handle); return -1; } // set amount of averaging measurements to 255 ret = pm_set_averages(&pm, 255); if (ret < 0) { printf("Error %i, \"%s\"\n", ret, pm_get_error_string(&pm)); pm_list_free(&list); FreeLibrary(handle); return -1; } // measure float power = 0; ret = pm_measure(&pm, &power); if (ret < 0) { printf("Error %i, \"%s\"\n", ret, pm_get_error_string(&pm)); pm_list_free(&list); FreeLibrary(handle); return -1; } printf("Power: %.2f dBm\n", power); // clean up pm_close(&pm); pm_list_free(&list); FreeLibrary(handle); return 0; }